Sizeof 和 strlen() 的概念,联系和区别,应用总结

来源:互联网 发布:关于网络点赞的作文 编辑:程序博客网 时间:2024/05/16 04:40

Sizeof 和strlen() 的概念,联系和区别,应用总结

0.说明


根据编程语言来讲:intC语言中是占用2个字节;在C++中占用4个字节;在Java中占用2个字节。

1.sizeof简介


sizeof(...)C语言的一个特殊的编译预处理不是单目运算符不是函数在头文件中typedef为unsignedint,其值在编译时计算好了,参数可以是数组、指针、类型、对象、函数等。

它的功能是:获得保证能容纳实现所建立的最大对象字节大小sizeof操作符以字节形式给出了其操作数的存储大小,所以用sizeof就可以测出不能数据类型在所在系统上占用几个字节的空间大小。

由于sizeof的值编译时已经计算好因此sizeof不能用来返回动态分配内存空间大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。

具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:

数组——编译时分配的数组空间大小

[]

charstr[20]="0123456789"; 
int a=sizeof(str); //a=20

[]

char str[ ]="0123456789"; 

int a=sizeof(str); //a=11

Sizeof以字节的形式返回字符串内存占用实际长度字符串以‘\0’结尾,所以\0’的长度也要算上,所以a=10 + 1 = 11;

指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);

Const char *ptr = “abc better winner”;

Int a = sizeof(ptr); // a = 4;

Int b = sizeof(*ptr); //b = 1;

[] ptr 是指向字符串常量的字符指针,sizeof获得的是ptr指针的地址长度,是长整型,所以a = 4; *ptr 是第一个字符,其实就获得了字符串的第一位’a’所占的内存空间,’a’char类型,占了1位,所以b =1;

类型——该类型所占的空间大小

Int a = Sizeof(int); //a = 4; 32位机上int 长度为4个字节

[] sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。

对象——对象的实际占用空间大小

Union u{

      Char str[2];

      Int num[2];

}u;

Int a = sizeof(u); // a = 8; 因为 num[2] 实际占用了4X2 = 8 字节内存大于char str[2] 2字节内存, 所以union 的最终占用内存为4 8字节。

 

函数——函数的返回类型所占的空间大小。函数的返回类型不能是void

IntcheckCPU()

{

       //do something

}

Int a = sizeof(checkCPU());// a =4;  返回类型为int 型故a = 4;

Sizeof另解


程序存储分布有三个区域:栈、静态动态所有能够从代码直接操作的对象,包括任何类型的变量、指针,都是在栈上的;动态和静态存储区是靠栈上的指针间接操作的。sizeof操作符,计算的是对象在栈上的投影体积;除了栈上的char数组这一个特殊情况之外。

sizeof计算的都是类型的长度。如果是对象,则转换成类型,再计算类型的长度。 

在32位系统中。指针类型是32位,4个字节。所以对任何指针用sizeof结果都是4;  

1.   数组用sizeof = 数组的步长(类型的长度)* 数组的长度。  

2.   复合结构sizeof= 各个数据成员的类型长度 * 声明的个数之和。(要考虑到字节对齐)  

    typedef struct student

    {

        int data;

        staticint number;

    } node1;

    typedef struct teacher

    {

        int data;

        charname;

} node2;

//静态变量是放在全局数据区,sizeof计算栈分配的大小,不会计算静态变量的,所以sizeof(node1)为4个字节

sizeof(node1)=4个字节

    sizeof(node2)=8个字节。//字节对齐

 

Sizeof特别说明


Sizeof()括号内的内容在编译过程中是不被编译的而是被替代类型!

int a=8; sizeof(a)。在编译过程中,不管a的值是什么,都被替换成类型sizeof(int),结果为4。如果sizeof(a=6)呢?也是一样地转换成a的类型,但是要注意,因为a=6是不被编译的,所以执行sizeof(a=6)后,a的值还是8,是不变的!

Sizeof 针对变量而言 只计算其数据类型所占的字节大小 并不管它本身是什么注:这里是针对变量而言没有说数组什么的也适应这条规则!

[]

int a =0;

 cout<<sizeof(a = 6)<<endl;

  cout<<a<<endl;

输出结果为:4

            0

[]sizeof(a = 6)相当于sizeof(int)  sizeof() 括号内的内容a = 6不被编译,而是被替代为变量a的数据类型,所以这条语句过后,a的值还是0不是 6

Sizeof 小结



1.unsigned影响的只是最高位bit的意义(正负),数据长度不会被改变的。所以sizeof(unsignedint) == sizeof(int);
2.自定义类型的sizeof取值等同于它的类型原形。如typedefshort WORD;sizeof(short) == sizeof(WORD)。
3.对函数使用sizeof,在编译阶段会被函数返回值的类型取代。如intf1(){return 0;};
cout < <sizeof(f1()) < <endl; // f1()返回值为int,因此被认为是int
4. 32位机器上,只要是指针,大小就是4。如cout< <sizeof(string*) < <endl; // 4
5.数组的大小是各维数的乘积*数组元素的大小。如 char a[] = “abcdef “;
int b[20] = {3, 4};
char c[2][3] = { “aa “, “bb “};
cout < <sizeof(a) < <endl; // 7
cout < <sizeof(b) < <endl; // 20*4
cout < <sizeof(c) < <endl; // 2*3*1 = 6
数组a的大小在定义时未指定,编译时给它分配的空间是按照初始化的值确定的,也就是7,包括‘\0’

[]

这里有一个陷阱:

int *d = newint[10];

cout<<sizeof(d)<<endl;// 4

d是我们常说的动态数组,但是他实质上还是一个指针,所以sizeof(d)的值是4。

再考虑下面的问题:

double* (*a)[3][6];

cout<<sizeof(a)<<endl;  // 4

cout<<sizeof(*a)<<endl;  // 72

cout<<sizeof(**a)<<endl;// 24

cout<<sizeof(***a)<<endl;// 4

cout<<sizeof(****a)<<endl;// 8

a是一个很奇怪的定义,他表示一个指向 double*[3][6]类型数组的指针。既然是指针,所以sizeof(a)就是4

既然a是执行double*[3][6]类型的指针,*a就表示一个double*[3][6]的多维数组类型,因此sizeof(*a)=3*6*sizeof(double*)=72。同样的,**a表示一个double*[6]类型的数组,所以sizeof(**a)=6*sizeof(double*)=24***a就表示其中的一个元素,也就是double*了,所以sizeof(***a)=4。至于****a,就是一个double了,所以sizeof(****a)=sizeof(double)=8

2.Strlen简介


原型:externunsigned int strlen(char *s);

用法: #include<cstring>

格式:strlen (字符数组名)

功能计算字符串s长度不包括'\0'在内!

说明:返回s的长度,不包括结束符NULL。

strlen(...)函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。

strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度(不包括'\0'在内),不是类型占内存的大小

 

自定义函数实现strlen()函数的功能


-------------------------------------------------1:start------------------------------------

  #include<stdio.h>

  #include<assert.h>

  typedefunsigned int u_int;

  u_intMystrlen(const char *str)

  {

  u_inti;

  assert(str!= NULL);

  for (i= 0; str[i]!= '\0'; i++);

  returni;

  }

------------------------------------------------1:end--------------------------------------

-------------------------------------------------2:start--------------------------------------

  int strlen(const char *str)

  {

  assert(str!= NULL);

  intlen = 0;

  while((*str++)!= '\0')

  len++;

  returnlen;

  }

------------------------------------------------2:end------------------------------------------

------------------------------------------------3:start------------------------------------------

  int strlen(const char *str)

  {

  assert(str);

  constchar *p = str;

  while(*p++!=NULL);

  returnp - str - 1;

  }

-------------------------------------------------3:end-----------------------------------------

-------------------------------------------------4:start----------------------------------------

  int strlen(const char *str)

  {

  assert(str);

  if(*str==NULL)

  return0;

  else

  return(1 + strlen(++str));

  }

-----------------------------------------------4:end----------------------------------------

以上各种实现的方式都是大同小异的,有的用的是变量,有的用的是指针。

其中,最后一个用的是递归的方式。而在实现库函数的时候,规定不可以用递归

 

3.Sizeof和 strlen的区别与联系



1.sizeof是算符,strlen是函数 

2.sizeof
可以用类型做参数,strlen只能用char*做参数且必须是以''\0''结尾的。 
sizeof还可以用函数做参数,比如: 
short f(); 
printf("%d\n", sizeof(f())); 
输出的结果是sizeof(short),即2。 

3.数组做sizeof的参数不退化,传递给strlen就退化为指针了。 

4.大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因 
char str[20]="0123456789"; 
int a=strlen(str);//a=10; 
int b=sizeof(str);//而b=20; 

5.strlen的结果要在运行候才能计算出来,是用来计算字符串的长度不是类型占内存的大小。 

6.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。 

7.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址, 
如: 
fun(char[8]) 
fun(char []) 

都等价于 fun(char *) 
在C++里参数传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小 
如果想在函数内知道数组的大小, 需要这样做: 
进入函数后用memcpy拷贝出来,长度由另一个形参传进去 
fun(unsigedchar *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 获得的是一个指针的之所占的空间,应该是 长整型的,所以是4 
sizeof(*ss) 结果 为1 //*ss是第一个字符 其实就是获得了字符串的第一位'0' 所占的内存空间,是char类型的,占了1 位 

strlen(ss)= 10 //如果要获得这个字符串的长度,则一定要使用 strlen

字符串中sizeof 和 strlen的区别


[]

char a[] = “abcdef “;
char b[20] = “abcdef “;
string s = “abcdef “;
cout < <strlen(a) < <endl; // 6,字符串长度
cout < <sizeof(a) < <endl; // 7,字符串容量 包括了’\0’字符这个长度
cout < <strlen(b) < <endl; // 6,字符串长度
cout < <sizeof(b) < <endl; // 20,字符串容量
cout < <sizeof(s) < <endl; // 4,这里不代表字符串的长度,而是string类的大小
cout < <strlen(s) < <endl; // 错误s不是一个字符指针strlen的参数只能是char*,且必须是以'\0'结尾的!
将上面的char a[] 中的a[1]做如下修改:

a[1] = ‘\0 ‘;
cout < <strlen(a) < <endl; // 1

// strlen(char*)函数求的是字符串的实际长度,它求得方法是从开始到遇到第一个'\0'为止。
对strlen()函数 如下例:如果你只定义没有给它赋初值,这个结果是不定的,它会从aa首地址一直找下去,直到遇到'\0'停止。

charaa[10];cout<<strlen(aa)<<endl; //结果是不定的

charaa[10]={'\0'}; cout<<strlen(aa)<<endl; //结果为0 //strlen()遇到第一个’\0’但不返回这个’\0’的长度。

charaa[10]="jun"; cout<<strlen(aa)<<endl; //结果为3

sizeof()返回的是变量声明后所占的内存数,不是实际长度

换句话说,sizeof返回对象所占用的字节大小。而strlen返回字符个数

针对本例小结


strlen是寻找从指定地址开始,到出现的第一个’\0’之间的字符个数,它是在运行阶段执行的,而sizeof是得到数据的大小,在这里是得到字符串的容量。所以对同一个对象而言,sizeof的值是恒定的stringC++类型的字符串,它是一个类,所以sizeof(s)表示的并不是字符串的长度,而是类string的大小strlen(s)根本就是错误的,因为strlen的参数是一个字符指针char*,如果想用strlen得到s字符串的长度,应该使用sizeof(s.c_str()),因为string的成员函数c_str()返回的是字符串的首地址。实际上,string类提供了自己的成员函数来得到字符串的容量和长度,分别是Capacity()Length()string封装了常用了字符串操作,所以在C++开发过程中,最好使用string代替C类型的字符串


参考来源


[01] http://www.cnblogs.com/carekee/articles/1630789.html

[02] http://mazhijing.blog.51cto.com/215535/68644/

[03] http://blog.chinaunix.net/uid-21411227-id-1826864.html

[04] http://baike.baidu.com/view/736226.htm

[05] http://www.zhiwenweb.cn/Category/Learning/sizeof-and-strlen.html

[06] http://blog.csdn.net/sooolo/article/details/7669813

[07] http://blog.chinaunix.net/uid-20621895-id-196623.html

[08] http://blog.csdn.net/wangg0717/article/details/4818416

[09] http://www.cnblogs.com/wanghetao/archive/2012/04/04/2431760.html

[10] http://dev.yesky.com/143/2563643.shtml

[11] http://blog.chinaunix.net/uid-20621895-id-196622.html