1.sizeof操作符来得到字符数组(字符串)的大小
(1)sizeof所代表的意义和用法
int main()
{
int a=1;
printf("%d\n",sizeof(a)); 4
printf("%d\n",sizeof a); 4
printf("%d\n",sizeof 10); 4
printf("%d\n",sizeof(10)); 4
printf("%d\n",sizeof(int)); 4
// printf("%d\n",sizeof int); // 错误
return 0;
}
如上述所示,很多人都以为sizeof是一个函数,但是sizeof是一个操作符,和+-=&!一样,所以它既可以像函数一样sizeof(a),也可以直接 sizeof a。
当然不可以直接用sizeofa,这样的话编译器就不认识了。它可以用来返回一个数据或者类型所占的内存大小空间。当判断类型大小时,不能用sizeof int的方式。
2.sizeof和strlen的区别
(1)当字符数组不设定大小下标时
int main()
{
char str[]="Hello World";
printf("strlen=%d\n",strlen(str)); // 11
printf("sizeof=%d\n",sizeof(str)); // 12
return 0;
}
这种情况下,strlen得到字符数组str的是他的有效长度,也就是字符串的长度也就是11bytes。
sizeof表示数组名str所占内存的空间(系统默认开辟栈空间),包括str的长度大小和字符串的结尾标志'\0'(编译器自动添加),故11+1=12bytes。
(2)当字符数组固定大小下标时
int main()
{
char str[15]="Hello World";
printf("strlen=%d\n",strlen(str)); // 11
printf("sizeof=%d\n",sizeof(str)); // 15
return 0;
}
此时,strlen同样是得到字符串有效长度,通过'\0'来判断结尾11bytes。
而对于sizeof而言str[15]相当于在内存入口地址为str的地方开辟了15bytes的大小空间。所以sizeof返回str大小就是数组大小15。
当然,不同编译器对于未初始化的非法内存和合法堆栈空间的填充值都不同,稍后再讨论这个问题。
(3)当字符串以数组初始化的方式存储到字符数组时
int main()
{
char str1[]={'H','e','l','l','o',' ','W','o','r','l','d'};
char str2[]={'H','e',0,'l','l','o',' ','W','o','r','l','d'}; // 0等价于'\0',但不为'0',转义字符相当于0
printf("strlen=%d\n",strlen(str1)); // 随机值
printf("sizeof=%d\n",sizeof(str1)); // 11
printf("strlen=%d\n",strlen(str2)); // 2
printf("sizeof=%d\n",sizeof(str2)); // 12
return 0;
}
如果以这种方式来初始化字符数组的时候,他不会在字符串的末尾自动添加'\0'。所以他不能判断字符串什么时候结束,很容易就会访问到非法空间。
用strlen来测试str1随机值了(大于或等于字符串实际长度)。而str2的数组成员中有一个0等价于'\0'而不是'0',转义字符相当于结束标志为2bytes。
sizeof测试的是数组的大小,这时候不加'\0',str1就是11,str2为12。
(4)当字符数组未被初始化值时
int main()
{
char str[15];
printf("strlen=%d\n",strlen(str));
printf("sizeof=%d\n",sizeof(str)); // 15
return 0;
}
这种情况下没有初始化字符数组,由于str是局部变量,分配在栈区。一般的编译器对于分配给栈区未被化空间都设置随机初始值。
在32bitsMSVC环境下分配的初始值是0xCCCCCCCC,所以没有结束标志,无法确定strlen(str)的长度。sizeof(str)的大小是15bytes。
char str[10];
int main()
{
printf("strlen=%d\n",strlen(str)); // 0
printf("sizeof=%d\n",sizeof(str)); // 15
return 0;
}
当str[10]作为外部全局变量时,这个时候作为静态变量,str存储在常量区,编译器初始化数据为0对应字符'\0',所以strlen为0,sizeof为15bytes。
(5)当使用字符指针来存储字符串时
int main()
{
char * str = "hello World";
printf("strlen=%d\n",strlen(str)); // 11
printf("sizeof=%d\n",sizeof(str)); // 4
return 0;
}
strlen求得的str长度和字符数组没什么区别,同样是字符串自动添加'\0',strlen(str)=11bytes。而sizeof(str)则是得到的指针str大小4bytes。
sizeof求得任意指针类型在32bits环境下都是4bytes。
(6)字符串作为函数参数时
void fun(char str[])
{
printf("strlen=%d\n",strlen(str)); // 11
printf("sizeof=%d\n",sizeof(str)); // 4
}
int main()
{
char str[15]="Hello World";
printf("strlen=%d\n",strlen(str)); // 11
printf("sizeof=%d\n",sizeof(str)); // 15
printf("\n");
fun(str);
return 0;
}
这种情况下,在main函数中strlen(str)长度为11,sizeof(str)=15bytes。而如果将这个数组str作为参数传入fun函数时。
实参的数组会在调用函数内部转换成一个指针(注意不要把数组和指针混为一谈)。编译器的这种做法是为了提高效率和节省空间。
所以此时fun中的strlen的长度依然是11bytes。但是sizeof的大小变成了4bytes。
3.总结
(1)sizeof和strlen
sizeof是C语言提供的用于返回变量或者类型所占内存大小的一个运算符。而strlen是用于返回字符串长度的一个函数。
函数原型为size_t strlen(const char *); 他的参数只允许一个字符串,而且以'\0'作为结束判断标志。
(2)关于内存的初始化和释放的问题
在32bits MSVC Debug模式下,在操作系统分配给程序的内存中,编译器会把未初始化的栈空间指针全部填充0xcccccccc,
会把未初始化的堆空间指针全部填充0xcdcdcdcd,避免随机值造成debug程序出错。在中文windows下GB2312编码可以看到"烫烫烫烫"和"屯屯屯屯"。
在Release模式下自然就是随机值了。
而当我们malloc动态开辟了一片内存时,他就会在堆空间开辟一片合法空间供我们使用。当我们使用结束时,使用free来释放这片空间。
编译器会自动帮我们在堆空间的数据进行扰乱,填充0xfeeefeee进去表示内存已经被释放。