1、sizeof
1)、编译时计算运算符sizeof,可用类型或变量做参数,计算占用内存的大小。sizeof后若是类型必须加括弧,若是变量名可不加括弧。即sizeof的三种使用格式为
1:sizeof(对象)
2:sizeof 对象
3:sizeof(类型)
sizeof(x)可用来定义数组维数如:
代码如下:
printf("%d\n", sizeof(short));
输出的结果为短整型的长度2(以32位编译器计算)。
用结构类型或变量做参数时,sizeof 返回实际的大小,当用于静态数组时,sizeof 返回全部数组的尺寸。sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
2、strlen
1)、运行时计算strlen,只能用char*做参数,且必须是以”\0”结尾的(不包含”\0”)。计算的是字符串的长度。如:
代码如下:
char str[20]="0123456789";
int a=strlen(str); // 结果为a=10
int b=sizeof(str); // 结果b=20;
3、处理静态数组:
数组:数组的sizeof值等于数组所占用的内存字节数,注意char数组里面可能包含‘\0’
char s[] = "abc" ;//这是定义时即为"abc\0"四个字符。
char s1[3] ="abc" ;//其中"abc"也实际上是"abc\0",但是s1[3] 只有三个,所以最后的'\0'被舍去了
比方说
char s[] = "abcdef"; //sizeof(s) :7
char s1[3] ="abcdef"; //sizeof(s1):3
int a2[3]; //sizeof( a2 ): 3*4=12(int在32位和64位编译器时占内存4字节)
char str[20]="0123456789";
//一维数组和二位数组都是数组,所有的数组如果没有初始化,其位置虽然已经确定,但是其位置上对应的内容都是之前残留的,所以,输出的内容都是不确定的未知内容;但是在全局区定义的数组数据都默认为0;
int a=strlen(str); //a=10;
int b=sizeof(str); //而b=20;
char str[20]="0123456789";
int a=strlen(str); // a=10; strlen 计算字符串的长度,以\0'为字符串结束标记。
int b=sizeof(str); // b=20; sizeof 计算的则是分配的数组str[20] 所占的内存空间的大小,不受里面存储的内容影响。
4、处理指针
指针:记录了另一个对象的地址。既然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中,一个指针变量的返回值必定是4(注意结果是以字节为单位),在64位系统中指针变量的sizeof结果为8。
代码如下:
char* ss = "0123456789";
int* pi;
sizeof(ss); // 结果4(以32位编译器计算)
sizeof( pc ); // 结果为4
sizeof(*ss); //结果1,*ss是第一个字符 其实就是获得了字符串的第一位'0' 所占的内存空间,是char类型的,占用1字节
strlen(ss)= 10; //若要获得这个字符串的长度,则一定要使用 strlen
ss是指向字符串常量的字符指针,sizeof 获得的是一个指针所占的空间。
记住一句话:指针变量的sizeof值与指针所指的对象没有任何关系,
5、sizeof计算对象的大小是转换成对象类型计算的
sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象其sizeof值都是一致的。这里,对象可以进一步延伸至表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。
sizeof( 2 ); // 2的类型为int,所以等价于 sizeof( int );
sizeof( 2 + 3.14 ); // 3.14的类型为double,2也会被提升成double类型,所以等价于 sizeof( double );5、同种类型的不同对象其sizeof值都是一致的
6、sizeof的常量性
sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用,如:
char ary[ sizeof( int ) * 10 ]; // ok
7、注意移植性,
基本数据类型:short、int、long、float、double这样的简单内置数据类型,由于它们都是和系统相关的,所以在不同的系统下取值可能不同,这务必引起我们的注意,尽量不要在这方面给自己程序的移植造成麻烦。
下表为16、32、64位编译器中各类型所占内存情况
编译器 | 16位 | 32位 | 64位 |
---|---|---|---|
char | 1(字节) | 1 | 1 |
char*(指针) | 2 | 4 | 8 |
short int | 2 | 2 | 2 |
int | 2 | 4 | 4 |
unsigned int | 2 | 4 | 4 |
float | 4 | 4 | 4 |
double | 8 | 8 | 8 |
long | 4 | 4 | 8 |
long long | 8 | 8 | 8 |
unsigned long | 4 | 4 | 8 |
8、 结构体的sizeof
先看一个结构体:
struct S1
{
char c;
int i;
};
此处可能占用5个字节,也可能不是5个,因为有字节对齐原则。
When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment.
字节对齐有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了
字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
讲解一下:结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:
#define offsetof(s,m) (size_t)&(((s *)0)->m)
例如,想要获得S2中c的偏移量,方法为
size_t pos = offsetof(S2, c);// pos等于4
基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。
struct S3
{
char c1;
int s;
char c2;
};
按照准则1,此结构体的变量的首地址应该能够被int类型所占的字节数整除。
按照准则2,由于此c1位于最前,且占用字节为1,不用偏移,而s占用4个字节,需要偏移整数倍4个字节,加上本身占有的字节数,c2占一个字节和s之间不需要偏移,所以总共占有1+4(偏移)+4+1总共10个字节,
再根据准则3,则需要为s占有大小的整数倍,与10最接近的就是12,所以占用字节数为12。
注:Strlen与sizeof()的区别
strlen(char*)函数求的是字符串的实际长度,它求得方法是从开始到遇到第一个’\0’,如果你只定义没有给它赋初值,这个结果是不定的,它会从aa首地址一直找下去,直到遇到’\0’停止。
而sizeof()返回的是变量声明后所占的内存数,不是实际长度,此外sizeof不是函数,仅仅是一个操作符,strlen是函数。
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就退化为指针了。
对于以数组为形参的函数,传过去之后实参都变成数组首地址。也就是退化。
因为sizeof不是一个函数,所以不退化。
strlen只能用char* 做参数,且必须是以'\0'结尾
数组退化的问题可以用以下例子来说明
char str[20]="1234";
int a=strlen(str); //a=4;a的结果是从str这个char*指针开始一直到'\0'结束符之间的长度
5.strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小。
6.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
8.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,
如:
fun(char [8]);
fun(char []);//都等价于 fun(char *)
int ss[100] = "0123456789";
sizeof(ss); // 结果 400 ===》ss表示再内存中的大小 100×4
strlen(ss); // 错误 ===》strlen的参数只能是char* 且必须是以'\0'结尾的
char q[]="abc";
char p[]="a\n";
sizeof(q),sizeof(p),strlen(q),strlen(p);//结果是 4 3 3 2
参考自
http://www.jb51.net/article/61506.htm
http://blog.csdn.net/zhangjixin/article/details/7542122