Sizeof 和strlen() 的概念,联系和区别,应用总结
0.说明
根据编程语言来讲:int型在C语言中是占用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的值是恒定的。string是C++类型的字符串,它是一个类,所以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