zoukankan      html  css  js  c++  java
  • sizeof, strlen区别

    strlen与sizeof的区别
    1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。 
    该类型保证能容纳实现所建立的最大对象的字节大小。
    2.sizeof是算符,strlen是函数。
    3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''0''结尾的。
    4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
    5.大部分编译程序在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因 
    char str[20]="0123456789";//str是编译期大小已经固定的数组 
    int a=strlen(str); //a=10;//strlen()在运行起确定 
    int b=sizeof(str); //而b=20;//sizeof()在编译期确定
    6.strlen的结果要在运行的时候才能计算出来,是用来计算字符串的实际长度,不是类型占内存的大小。
    7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。 
    char c; 
    sizeof c;//变量名可以不加括弧 
    8.当适用了于一个结构类型时或变量, sizeof 返回实际的大小, 
    当适用一静态地空间数组, sizeof 归还全部数组的尺寸。 
    sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
    
    笔者的感悟:
    我的误解是sizeof和strlen都是返回字符串的长度,其实其中真的有很多的幼稚的地方,相信很多的程序员一开始也会有所困惑。
    char * test = “daoluan”;
    sizeof的结果是4,很明显是类型的大小;而strlen调用的结果是6,在这里strlen聪明多了。
    char test[10] = “daoluan”;
    sizeof的结果是10(编译期间已经准备好了),而strlen的结果是6,在这里strlen也很聪明。
    这样的结果就很明朗了。
    
    2011-12-10的补充:
    
    声明一个字符数组比如:char str[9]一并对其进行赋值的时候,有些人这样:
    char str[9] = "abcdefghi";//9个字符,没错啊
    可惜编译器不允许,字符数组规定,数组的最后一个值应该为0(也就是空格),所以上面的语句是错误的。
    应该改为:
    char str[9] = "abcdefgh"
    ZeroMemory和memset 
    两者的功能是一样的,将一段内存的内容置为0,当然前者要memset(&valiable,0,sizeof(valiable))才是置0。
    所以比起来的话,还是memset的功能强大一点,毕竟还可以不是置0,
    
    memset(&valiable,1,sizeof(valiable))。
    
    memset函数是C Run-time Library也就是我们熟悉的C运行时库,而后者ZeroMemory是win32 api的版本,如果需要跨平台的话用memset,如果是在win下工作,那用ZeroMemory也不为过。
    
    ZeroMemory是在win32下是一个宏,而不是一个函数,这点要清楚。
    1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
    
      2.sizeof是算符,strlen是函数。
    
      3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''0''结尾的。sizeof还可以用函数做参数,比如: short f();printf("%d
    ", sizeof(f()));输出的结果是sizeof(short),即2。
    
      4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
    
      5.大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因 char str[20]="0123456789";int a=strlen(str); //a=10;int b=sizeof(str); //而b=20;
    
      6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
    
      7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
    
      8.当适用了于一个结构类型时或变量, sizeof 返回实际的大小,当适用一静态地空间数组, sizeof 归还全部数组的尺寸。sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
    
      9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如: fun(char [8])fun(char [])都等价于 fun(char *) 在C++里参数传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小如果想在函数内知道数组的大小,需要这样做:进入函数后用memcpy拷贝出来,长度由另一个形参传进去 fun(unsiged char *p1, int len){  unsigned char* buf = new unsigned char[len+1]  memcpy(buf, p1, len);}
    
      我们能常在用到 sizeof 和 strlen 的时候,通常是计算字符串数组的长度看了上面的详细解释,发现两者的使用还是有区别的,从这个例子可以看得很清楚:
    
      char str[20]="0123456789";int a=strlen(str); //a=10; >>>> strlen 计算字符串的长度,以结束符 0x00 为字符串结束。int b=sizeof(str); //而b=20; >>>> sizeof 计算的则是分配的数组 str[20] 所占的内存空间的大小,不受里面存储的内容改变。
    
      上面是对静态数组处理的结果,如果是对指针,结果就不一样了
    
      char* ss = "0123456789";sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针,sizeof 获得的是一个指针的之所占的空间,应该是
    
      长整型的,所以是4sizeof(*ss) 结果 1 ===》*ss是第一个字符 其实就是获得了字符串的第一位'0' 所占的内存空间,是char类
    
      型的,占了 1 位
    
      strlen(ss)= 10 >>>> 如果要获得这个字符串的长度,则一定要使用 strlen。
        
    //sizeof与strlen的区别? 
    //(1)sizeof是运算符,strlen是函数 
    //(2)sizeof可以用类型做参数;strlen只能用char *做参数,且必须是以''结尾 
    //(3)sizeof大多在编译时已计算出结果;strlen的结果要在运行的时候才能计算出来 
    //即:sizeof是计算范围有多大;strlen是计算''之前有多少 
    #include<iostream>
    using namespace std; 
      
    int main()
    {
        char ss1[]="0123456789";
        cout<<sizeof(ss1)<<endl;//11
        cout<<strlen(ss1)<<endl;//10 
      
        char ss2[100]="0123456789";
        cout<<sizeof(ss2)<<endl;//100
        cout<<strlen(ss2)<<endl;//10 
        
        char ss3[100]={'h','e','l','l','o','','c','+','+'};
        cout<<sizeof(ss3)<<endl;//100
        cout<<strlen(ss3)<<endl;//5 
        
        char *ss4="0123456789";
        cout<<sizeof(ss4)<<endl;//4
        cout<<strlen(ss4)<<endl;//10 
        
        //void Func(char str[100])
        //{
        //    sizeof(str);//4
        //}
        
        return 0;
    }
    已知 char *str1="absde";
         char str2[]="absde";
         char str3[8]={'a',};
         char ss[] = "0123456789";
    
    为什么sizeof(str1)=4
          sizeof(str2)=6;
           sizeof(str3)=8;
           sizeof(ss)=11
    
    首先说明一点,char类型占一个字节,所以sizeof(char)是1,这点要理解
    
    str1是一个指针,只是指向了字符串"absde"而已。所以sizeof(str1)不是字符串占的空间也不是字符数组占的空间,而是一个字符型指针占的空间。所以sizeof(str1)=sizeof(char*)=4,在C/C++中一个指针占4个字节
    
    str2是一个字符型数组。C/C++规定,对于一个数组,返回这个数组占的总空间,所以sizeof(str2)取得的是字符串"absde"占的总空间。"absde"中,共有a b s d e 六个字符,所以str2数组的长度是6,所以sizeof(str2)=6*sizeof(char)=6
    
    str3已经定义成了长度是8的数组,所以sizeof(str3)为8
    
    str4和str2类似,'0' '1' ... '9'加上''共11个字符,所以ss占的空间是8
    
    总之,对于指针,sizeof操作符返回这个指针占的空间,一般是4个字节;而对于一个数组,sizeof返回这个数组所有元素占的总空间。char*与char[]容易混淆,一定要分清,而且char*="aaa"的写法现在不被提倡,应予以避免
    而strlen不区分是数组还是指针,就读到为止返回长度。而且strlen是不把计入字符串的长度的。
    前几天学习一维数组的赋值的时候遇到这样一个问题,程序如下:
    
    char a[]="hello";
            char b[5]={'h','e','l','l','o'};
            char c[]={'h','e','l','l','o',''};
            char *d="hello";
            printf("%d,%d
    ",sizeof(a),strlen(a));
            printf("%d,%d
    ",sizeof(b),strlen(b));
            printf("%d,%d
    ",sizeof(c),strlen(c));
            printf("%d,%d
    ",sizeof(d),strlen(d));
            运行结果如下:
            65
            538
            65
            45
    
    在分析结果之前,我们先来看下sizeof和strlen的区别。
    
    本质上而言,sizeof是一个运算符,它用类型作为参数,而strlen只是C库提供的一个函数,他用来计算以’0’结果的字符串的长度,即它的参数只能是char*。它们相同的地点就只是返回值,都是一个size_t类型的值。
    
    其实还有其他不同的地方,我们来通过这个程序分析下。
    
    1)分析第一行第二行,同样是给数组赋值了hello,为什么结果却不一样。
    strlen的结果要在运行的时候才能计算出来,是用来计算字符串的实际长度,而sizeof的结果是在编译的时候就计算过的,是类型或变量占内存的大小。Strlen是计算以’0’结束的字符串的长度,故如果b的长度就不是我们所想的我们给它赋值的字符串的长度了。如果你对b进行了如下的赋值:char b[5]={'h','e','l',‘0’,'l'};那么b的长度也只有3了。
    
    2)sizeof是我们给字符串赋值时系统分配给数组所用空间的值。比较a和c,这个时候我们对它俩的赋值其实是一样的,b区别于c,内存给a、c分配的都是6个字节,而b只分配给5个字节。
    
    3)分析第一行第四行,为什么同样给a、d赋值了一个字符串,用strlen求出的值相同而用sizeof求出的不一样?
    
    原因就是:数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。sizeof(d) 结果 4 ,这个时候,d是指向字符串常量的字符指针,sizeof 获得的是一个指针的之所占的空间,应该是长整型的,所以是4。而sizeof(a)中a表示的是分配的数组 a 所占的内存空间的大小,不受里面存储的内容改变。
    
    所以通常当我们来计算字符串数组的长度,到底用到的是 sizeof 和 strlen ,是需要考虑的,应注意它们的区别。
    VC6.0下的sizeof和strlen  
    
             在win32下,intfloatint *、float  *、char* 大小全部是4个字节,char大小是1。这个只要是用C在VC6.0下编过程的人都知道。但是在数组的时候,就需要注意一下了。我们定义一个整形的数组int array[10] = {1,2,3,4,5},求数组array的大小sizeof(array),是40,而不是10,这个数据的长度是10,每个元素占4个字节,所以它总共占40 个字节。虽然在初始化的时候我们只赋了5个值,但是编译器在编译的时候已经将地址预留下来了,所以,不管我们初始值赋了多少个,算大小的时候,总是算10个int的大小。而且,整形数组是不能用strlen来计算长度的。
    
            而对于字符数组来说,它的长度和大小跟计算整形数组的一样,定义字符数组char ch[10] = {'A','B','C','D','E'},大小是10,长度是10,每个元素占1个字节,总共10个字节,它可以用strlen来计算长度,计算出来长度是5。
    
            对于字符串指针,同样需要注意,我们定义一个字符串指针,并且赋初始值“ABCDE”,char *str = "ABCDE",计算它的大小,是4,长度是5,再定义char *str1 = "ABC" ,大小同样是4,长度是3。两个字符串指针所指内存空间的内容有所区别,但是由于都是字符串指针,所以它们的大小一样。
    
           有人会问,字符串是以0来结束,长度是不是要加1?在这里,我告诉大家,这个是不需要的,这个是编译器决定的,没有为什么。只是需要注意一点,在定义字符数组时,要给结束符0预留空间,定义一个8个字符的数组,数组大小最小必须是9,如果定义成8,编译运行不会报错,但是结果都会是错误的。
    
          经常有人问我关于这些知识的问题,有时候因头脑发热会说错,今天有时间来整理一下,在在让我更加清晰掌握的同时,也希望对你有用。关于编译器方面的知识,我知之甚少,希望技术界的大牛们,能说给我们讲一下关于编译器工作的原理。
    char chTest[] = "love";
        char *pchTest = "love";
        
        int nA1 = sizeof(chTest) / sizeof(chTest[0]);
        int nA2 = strlen(pchTest);
        int nA3 = strlen(chTest);
        
        nA1 = 11 // sizeof(chTest) = 11, 因为chTest的值为 "love", 包含字符串结束标志''
        nA2 = 10 // strlen(pchTest)  =  10, strlen不包含字符串结束标志。
        nA3 = 10 // strlen()不包含结束标志
    有关内容见: C++ RIMER? 
    10.计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。MS VC++中的对齐设定,有时候sizeof得到的与实际不等。一般在VC++中加上#pragma pack(n)的设定即可.或者如果要按字节存储,而不进行数据对齐,可以在Options对话框中修改Advanced compiler页中的Data alignment为按字节对齐。 
    11.sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式 
    四、结束语
    
    sizeof使用场合。 
    1.sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如:    void *malloc(size_t size), 
      size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
    
    2.用它可以看看一类型的对象在内存中所占的单元字节。 void * memset(void * s,int c,sizeof(s))
    
    3.在动态分配一对象时,可以让系统知道要分配多少内存。 
    4.便于一些类型的扩充,在windows中就有很多结构内型就有一个专用的字段是用来放该类型的字节大小。 
    5.由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。 
    6.如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。 
     
     
    第一个例子: char* ss = "0123456789";
    sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针
    sizeof(*ss) 结果 1 ===》*ss是第一个字符
    
    char ss[] = "0123456789";
    sizeof(ss) 结果 11 ===》ss是数组,计算到位置,因此是10+1
    sizeof(*ss) 结果 1 ===》*ss是第一个字符
    
    char ss[100] = "0123456789";
    sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
    strlen(ss) 结果是10 ===》strlen是个函数内部实现是用一个循环计算到为止之前
    
    int ss[100] = "0123456789";
    sizeof(ss) 结果 400 ===》ss表示再内存中的大小 100×4
    strlen(ss) 错误 ===》strlen的参数只能是char* 且必须是以''0''结尾的
    
    char q[]="abc";
    char p[]="a
    ";
    sizeof(q),sizeof(p),strlen(q),strlen(p);
    结果是 4 3 3 2      
    第二个例子:class X
    {
    int i;
    int j;
    char k;
    };
    X x;
    cout<<sizeof(X)<<endl; 结果 12 ===》内存补齐
    cout<<sizeof(x)<<endl; 结果 12 同上
    
    第三个例子:char szPath[MAX_PATH]
    
      如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小) 
    由几个例子开始说:
        
        第一个例子:
        
        char* s = "0123456789″;
        
        sizeof(s) 结果 4  s是指向字符串常量的字符指针
        
        sizeof(*s) 结果 1 *s是第一个字符
        
        char s[] = "0123456789″;
        
        sizeof(s) 结果 11  s是数组,计算到位置,因此是10+1
        
        sizeof(*s) 结果 1 *s是第一个字符
        
        char s[100] = "0123456789″;
        
        sizeof(s) 结果是100 s表示在内存中的大小 100×1
        
        strlen(s) 结果是10  strlen是个函数内部实现是用一个循环计算到为止之前
        
        int s[100] = "0123456789″;
        
        sizeof(s) 结果 400  s表示再内存中的大小 100×4
        
        strlen(s) 错误 strlen的参数只能是char* 且必须是以""结尾的
        
        第二个例子:
        
        class X
        
        {
        
        int i;
        
        int j;
        
        char k;
        
        };
        
        X x;
        
        cout《sizeof(X)《endl; 结果 12 内存补齐
        
        cout《sizeof(x)《endl; 结果 12 同上
        
        第三个例子:
        
        char szPath[MAX_PATH]
        
        如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小)
        
        sizeof深入理解
        
        sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
        
        sizeof是运算符,strlen是函数。
        
        sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以""结尾的。sizeof还可以用函数做参数,比如:
        
        short f();
        
        printf("%d
    ", sizeof(f()));
        
        输出的结果是sizeof(short),即2.
        
        数组做sizeof的参数不退化,传递给strlen就退化为指针了。
        
        大部分编译程序在编译的时候就把sizeof计算过了,是类型或是变量的长度,这就是sizeof(x)可以用来定义数组维数的原因。
        
        char str[20]="0123456789″;
        
        int a=strlen(str); //a=10;
        
        int b=sizeof(str); //而b=20;
        
        strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
        
        sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
        
        当适用了于一个结构类型时或变量, sizeof 返回实际的大小, 当适用一静态地空间数组, sizeof 归还全部数组的尺寸。 sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸。
        
        数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
        
        fun(char [8])
        
        fun(char [])
        
        都等价于 fun(char *)
        
        在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小 如果想在函数内知道数组的大小, 需要这样做: 进入函数后用memcpy拷贝出来,长度由另一个形参传进去。
        
        fun(unsiged char *p1, int len)
        
        {
        
        unsigned char* buf = new unsigned char[len+1]
        
        memcpy(buf, p1, len);
        
        }
        
        计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。MS VC++中的对齐设定,有时候sizeof得到的与实际不等。一般在VC++中加上#pragma pack(n)的设定即可。或者如果要按字节存储,而不进行数据对齐,可以在Options对话框中修改Advanced compiler页中的Data alignment为按字节对齐。
        
        sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。 如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeofvoid)都不是正确形式。
        
        sizeof使用场合
        
        sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。 例如:
        
        void *malloc(size_t size),
        
        size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
        
        用它可以看看一类型的对象在内存中所占的单元字节。
        
        void * memset(void * s,int c,sizeof(s))
        
        在动态分配一对象时,可以让系统知道要分配多少内存。
        
        便于一些类型的扩充,在windows中就有很多结构内型就有一个专用的字段是用来放该类型的字节大小。
        
        由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。
        
        如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
    char str[] = "abc";  实际的数据存储: a b c 0,也就是增加了一个终结符0 其类型为char[4]   VS: sizeof(str)=4     strlen(str) = 3
    GCC: sizeof(str)=4     strlen(str) = 3
    char str[]   = "abc"; 实际的数据存储: a b c 0,也就是增加了一个终结符0 其类型为char[4]   VS: sizeof(str)=4     strlen(str) = 3
    GCC: sizeof(str)=4     strlen(str) = 3
    char str[] = {'a','b','c'}; 实际的数据存储: a b c,并没有在最后添加终结符 其类型为char[3]   VS: sizeof(str)=3     strlen(str) = 15
    GCC: sizeof(str)=3     strlen(str) = 6
    char str[3] = {'a','b','c'}; 实际的数据存储: a b c,并没有在最后添加终结符 其类型为char[3]   VS: sizeof(str)=3     strlen(str) = 15
    GCC: sizeof(str)=3     strlen(str) = 6
    char str[5] = {'a','b','c','d','e'};  实际的数据存储: a b c d e ,并没有在最后添加终结符 其类型为char[5]   VS: sizeof(str)=5     strlen(str) = 19
    GCC: sizeof(str)=5     strlen(str) = 8
    char str[5] = {'a','b','c','d'};
    实际的数据存储: a b c d 0(默认填充字符0) 其类型为char[5]   VS: sizeof(str)=5     strlen(str) = 4
    GCC: sizeof(str)=5     strlen(str) = 4
    char *pstr = "abcde"; 实际的数据存储: a b c d e 0 pstr的类型为char* sizeof(pstr) = 4 ( 指针的数据存储空间,4个字节),strlen(pstr) = 5
    总结一下:
    1). sizeof的结果是类型的大小,区分类型之后,sizeof的结果也就命了,sizeof的结果是在编译期决定的,计算的占据的内存大小。
         srelen的结果是在运行期间决定,计算的是实际长度,strlen只能以char*作参数,以作为结束符, 以上的例子中,红色部分的strlen计算是错误的,
         因为在str的数据存储中并没有 一个字符,所以strlen的结果看似有点异常。
    2). 注意在计算sizeof的时候:
         char str[] = "abc";  类型为char[4],   sizeof(str) = 4*sizeof(char) = 4.
    3). sizeof(express),其中的express在编译过程中是不会被编译的,而是被替代类型。
         例如: int a = 1; sizeof(a=2);
         此时的express为a=2,在编译过程中被替换为sizeof(int),所以在执行完之后,a仍然是等于1.
    4). 对函数使用sizeof,在编译阶段会被替换为函数的返回值的类型取代
         例如: int f(){return 0;}  sizeof(f());的结果为4.
                 void f(){}            sizeof(f());编译过程中会出现错误,替换之后的sizoeof(void)编译无法通过.
    sizeof、strlen计算字符数组、字符指针空间
     
    char str[] = "abc";     实际的数据存储: a b c 0,也就是增加了一个终结符0    其类型为char[4]      VS: sizeof(str)=4     strlen(str) = 3 
    GCC: sizeof(str)=4     strlen(str) = 3
    char str[]   = "abc";    实际的数据存储: a b c 0,也就是增加了一个终结符0    其类型为char[4]      VS: sizeof(str)=4     strlen(str) = 3 
    GCC: sizeof(str)=4     strlen(str) = 3
    char str[] = {'a','b','c'};    实际的数据存储: a b c,并没有在最后添加终结符    其类型为char[3]      VS: sizeof(str)=3     strlen(str) = 15 
    GCC: sizeof(str)=3     strlen(str) = 6
    char str[3] = {'a','b','c'};    实际的数据存储: a b c,并没有在最后添加终结符    其类型为char[3]      VS: sizeof(str)=3     strlen(str) = 15 
    GCC: sizeof(str)=3     strlen(str) = 6
    char str[5] = {'a','b','c','d','e'};     实际的数据存储: a b c d e ,并没有在最后添加终结符    其类型为char[5]      VS: sizeof(str)=5     strlen(str) = 19 
    GCC: sizeof(str)=5     strlen(str) = 8
    char str[5] = {'a','b','c','d'};
    实际的数据存储: a b c d 0(默认填充字符0)    其类型为char[5]      VS: sizeof(str)=5     strlen(str) = 4 
    GCC: sizeof(str)=5     strlen(str) = 4
    char *pstr = "abcde";    实际的数据存储: a b c d e 0    pstr的类型为char*    sizeof(pstr) = 4 ( 指针的数据存储空间,4个字节),strlen(pstr) = 5
    总结一下:
    1). sizeof的结果是类型的大小,区分类型之后,sizeof的结果也就命了,sizeof的结果是在编译期决定的,计算的占据的内存大小。
         srelen的结果是在运行期间决定,计算的是实际长度,strlen只能以char*作参数,以作为结束符, 以上的例子中,红色部分的strlen计算是错误的,
         因为在str的数据存储中并没有 一个字符,所以strlen的结果看似有点异常。
    2). 注意在计算sizeof的时候:
         char str[] = "abc";  类型为char[4],   sizeof(str) = 4*sizeof(char) = 4.
    3). sizeof(express),其中的express在编译过程中是不会被编译的,而是被替代类型。
         例如: int a = 1; sizeof(a=2);
         此时的express为a=2,在编译过程中被替换为sizeof(int),所以在执行完之后,a仍然是等于1.
    4). 对函数使用sizeof,在编译阶段会被替换为函数的返回值的类型取代
         例如: int f(){return 0;}  sizeof(f());的结果为4.
                 void f(){}            sizeof(f());编译过程中会出现错误,替换之后的sizoeof(void)编译无法通过.
     考虑下面的问题:
    
      char a[] = "abcdef";
    
      char b[20] = "abcdef";
    
      string s = "abcdef";
    
      cout<<strlen(a)<<endl; // 6,字符串长度
    
      cout<<sizeof(a)<<endl; // 7,字符串容量
    
      cout<<strlen(b)<<endl; // 6,字符串长度
    
      cout<<strlen(b)<<endl; // 20,字符串容量
    
      cout<<sizeof(s)<<endl; // 12, 这里不代表字符串的长度,而是string类的大小
    
      cout<<strlen(s)<<endl; // 错误!s不是一个字符指针。
    
      a[1] = '';
    
      cout<<strlen(a)<<endl; // 1
    
      cout<<sizeof(a)<<endl; // 7,sizeof是恒定的
    
      strlen是寻找从指定地址开始,到出现的第一个0之间的字符个数,他是在运行阶段执行的,而sizeof是得到数据的大小,在这里是得到字符串的容量。所以对同一个对象而言,sizeof的值是恒定的。string是C++类型的字符串,他是一个类,所以sizeof(s)表示的并不是字符串的长度,而是类string的大小。strlen(s)根本就是错误的,因为strlen的参数是一个字符指针,如果想用strlen得到s字符串的长度,应该使用sizeof(s.c_str()),因为string的成员函数c_str()返回的是字符串的首地址。实际上,string类提供了自己的成员函数来得到字符串的容量和长度,分别是Capacity()和Length()。string封装了常用了字符串操作,所以在C++开发过程中,最好使用string代替C类型的字符串。
    char *str_1 = "12345";
    char str_2[ ] = "12345";
    char str_3[5] = { '1' };
    char str_4[5] = { '1', '2', '3', '4', '5' };
    
    1sizeof(str1)  = sizeof(char*)
    2sizeof(*str1)  = sizeof(char)
    3、strlen(str1)   =  字符个数
    4sizeof(str2) = sizeof(char) * (字符个数 + 1)
    5、strlen(str2) = 字符个数(字符尾部的0不计在内)
    6sizeof(str3) = sizeof(char) * (申请的字符个数)
    7、strlen(str3) =  实际字符的个数
    89、str4的字符空间申请时忘了计算结尾的'',按正确的写法应该是char str4[6]...
    10、strlen只接受const char*类型的参数
    楼主的想法不错,如果能成系列的话,应该让斑竹至顶,以便于大家讨论学习,这样可以节省资源,免得新手就同一个问题反复提问。关于这些类型的题目,其实用编译器说话最贴切。
    #pragma pack的基本用法为:#pragma pack( n ),n为字节对齐数,其取值为1、2、4、8、16,默认是8,如果这个值比结构体成员的sizeof值小,那么 该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,
    公式如下:
    offsetof( item ) = min( n, sizeof( item ) )
    再看示例:
    #pragma pack(push) // 将当前pack设置压栈保存
    #pragma pack(2) // 必须在结构体定义之前使用
    struct S1
    {
    char c;
    int i;
    };
    struct S3
    {
    char c1;
    S1 s;
    char c2;
    }; #pragma pack(pop) // 恢复先前的pack设置
    计算sizeof(S1)时,min(2, sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)等于6,能够被2整除,所以整个S1的大小为6。同样,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,加上sizeof(c2)等于9,不能被2整除,添加一个填充字节,所以sizeof(S3)等于10。struct S5 { }; sizeof( S5 ); // 结果为1
     
    9. 联合体的sizeof
    结构体在内存组织上是顺序式的,联合体则是重叠式,各成员共享一段内存,所以整个联合体的sizeof也就是每个成员sizeof的最大值。结构体的成员也可以是复合类型,这里,复合类型成员是被作为整体考虑的。
    所以,下面例子中,U的sizeof值等于sizeof(s)。
    union U
    {
    int i;
    char c;
    S1 s;
    };
     
    ---------------------补充---------------------
    参数为结构或类。Sizeof应用在类和结构的处理情况是相同的。但有三点需要注意:
    第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。
    第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。
    第三、类中含有虚函数的情况,虚函数表指针占用4个字节大小,并且放在类的开头。即虚函数在类中的位置对类的大小无影响,其始终是在最前面的。
    下面举例说明,
    1、Class Test{int a; static double c}; //sizeof(Test)=4.
    2、Test *s; //sizeof(s)=4,s为一个指针。
    3、Class test1{ }; //sizeof(test1)=1;
    4class A
    {
    double a;
    char b;
    virtual p(){};
    };//sizeof(A)=24,因为类中有虚函数,所以等价于下面:
    class A
    *p; //虚函数表指针
    double a;
    char b;
    };
     
     
     
    三、sizeof深入理解。
     
    1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
    2.sizeof是算符,strlen是函数。
    3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''''"0''''结尾的。sizeof还可以用函数做参数,比如:
    short f();printf("%d"n", sizeof(f()));
    输出的结果是sizeof(short),即2。
    4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
    5.大部分编译程序 在编译的时候就把sizeof计算过了,是类型或是变量的长度,这就是sizeof(x)可以用来定义数组维数的原因
    char str[20]="0123456789";
    int a=strlen(str); //a=10;
    int b=sizeof(str); //而b=20;
    6.strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,不是类型占内存的大小。
    7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
    8.当适用了于一个结构类型时或变量, sizeof 返回实际的大小, 当适用一静态地空间数组, sizeof 归还全部数组的尺寸。 sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
    9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
    fun(char [8]) fun(char [])
    都等价于 fun(char *)
    在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小 如果想在函数内知道数组的大小,需要这样做,进入函数后用memcpy拷贝出来,长度由另一个形参传进去
     
     
    四、结束语
     
    sizeof使用场合。
    1.sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。
    如void *malloc(size_t size), size_t fread(void* ptr,size_t size,size_t nmemb,FILE * stream)。
    2.用它可以看看一类型的对象在内存中所占的单元字节。
    void * memset(void * s,int c,sizeof(s))
    3.在动态分配一对象时,可以让系统知道要分配多少内存。
    4.便于一些类型的扩充,在windows中就有很多结构内型就有一个专用的字段是用来放该类型的字节大小。
    5.由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。
    6.如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
    内存初始化函数memset()
    #include
    内存初始化函数memset()用法详解
    作用:在一段内存中填充某个给定的值,注意填充时是按照字节顺序填充的,而不是按照元素填充。
    此方法是对较大的结构体和数组进行清零操作的一种有效方法。
    函数形式:memset(void *buffer,int c,size_t n)
    buffer是需要设置的内存的开始地址;c是期望填充值;n是需要填充的字节数。
    例1:一个int a[10]型变量,则memset(a,100,sizeof(int))此操作后,元素a[0]的每个字节的值都是100,即0x64,二进制表示: 01100100,所以元素a[0]为0x64646464,二进制表示:01100100 01100100 01100100 01100100
    void main()
    {
    int i,a[20];
    memset( a, 10, 5*sizeof(int) );
    for(i=0;i<20;i++)
    函数输出的10个元素并非10,而是每个字节都是00001010组成的int型数。
    例2:
    #include
    #include
    void main( void )
    {
    char buffer[] = "This is a test of the memset function";
    printf( "Before: %s"n", buffer );
    memset( buffer, ''*'', 4 );
    printf( "After: %s"n", buffer );
    }
    Output
    Before: This is a test of the memset function
    After: **** is a test of the memset function 
    Memset用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为'' ''''"0'';
     例:char a[100];
    memset(a, ''"0'', sizeof(a));
    memset可以方便地清空一个结构体类型的变量或数组。
    如:
    struct sample_struct
    {
    char csName[16];
    int iSeq;
    int iType;
    };
    对于变量
    struct sample_strcut stTest;
    一般情况下,-清空stTest的方法:
    stTest.csName[0]=''"0'';
    stTest.iSeq=0;
    stTest.iType=0;
    用memset就非常方便:
    memset(&stTest,0,sizeof(struct sample_struct));
    如果是数组:
    struct sample_struct TEST[10];
    则
    memset(TEST,0,sizeof(struct sample_struct)*10);
     
    memcpy 用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度。
    例:char a[100],b[50]; memcpy(b, a, sizeof(b));
    注意如果用memcpy(b,a,sizeof(a)),很可能会造成b的内存地址溢出。
     
    Strcpy就只能拷贝字符串了,它遇到''"0''就结束拷贝。
    例:char a[100],b[50];
    strcpy(a,b);
    如用strcpy(b,a),要注意a中的字符串长度(第一个‘"0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。
     C++中strlen()用法 
    int main( )
    
    {      
       char str0[8]={'a','b','c','d','e','f','i','g'};
       char str1[]="abcdefig";
       char str2[]="0123456789" ;
       char str3[]="abcsefgkij";
       printf("strlen(str0)=%d
    ",strlen(str0));
       printf("strlen(str1)=%d
    ",strlen(str1));
       printf("strlen(str2)=%d
    ",strlen(str2));  
       printf("strlen(str3)=%d
    ",strlen(str3));
    }
    请问输出什么?
    我用vc++6.0运行结果为:
    strlen(str0)=11
    strlen(str1)=8
    strlen(str2)=9
    strlen(str3)=5
    str0为什么会是11,和str1输出有什么区别?str2和str3同样的'',输出的效果却不同,请问这是什么原因造成的
    ||
    需要明确的第一点,strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符''为止,然后返回计数器值。
    
    例如以下代码片断理论上也是可以编译通过的:
    char str[]="abcdefg";
    printf("%d
    ",strlen(&str[5]));
    
    结果应当为2。
    该例中,strlen从字符str[5]即'f'开始计数,当到达'g'之后遇到''并停止计数。因此结果为2。
    
    ||
    str2和str3的主要区别就在于C/C++字符串中,允许形如“056”这样的所谓转义字符存在,它们仅表示一个字节位(byte),一般用于输出无法直接通过键盘输入的字符。
    ||
    str0的sizeof为8,导致没有结束,因此strlen的返回是不可预期的。
    str1的sizeof实际上是9,会自动加结束。
    str2的56会被解释成8进制数056表示的字符,因此strlen是9
    str3的会被解释为结束符 
  • 相关阅读:
    LintCode "Maximum Gap"
    LintCode "Wood Cut"
    LintCode "Expression Evaluation"
    LintCode "Find Peak Element II"
    LintCode "Remove Node in Binary Search Tree"
    LintCode "Delete Digits"
    LintCode "Binary Representation"
    LeetCode "Game of Life"
    LintCode "Coins in a Line"
    LintCode "Word Break"
  • 原文地址:https://www.cnblogs.com/timssd/p/4080312.html
Copyright © 2011-2022 走看看