先问一个问题:如下字符串or字符数组,用strlen函数求长度各是多少?
/*01*/char * str1 = "abc"; /*02*/char * str2 = "ab\0c";/*03*/char * str3 = "ab\\0c";/*04*/char * str4 = "abc0c";/*05*/char arr0[5] = {'1', '2', '3', '4', '5'};/*06*/char arr1[5] = {'1', '2', '3', '4', '\0'};/*07*/char arr2[5] = {'1', '2', '3', '4', 0};/*08*/char arr3[5] = {'0', '0', '0'};/*09*/char arr4[5] = {0, 'a', 'b'};/*10*/char arr5[5] = {'a', '\0', 'b'};/*11*/char arr6[5] = {'a', 0, 'b'};
答案为:
01——302——2 03——504——505——未知06——407——408——309——010——111——1
首先明确一点,char * p = “abc” 与 char a[] = "abc"两种形式并不同。
(在VS中,你甚至写char * p = "abc"
都不会通过编译,而是必须写const char* p = "abc"
,表示他是个字符串常量)
再来看上面问题及结果,可以看到:
(1)sizeof(arrx[y]) 都为1.(其中arrx代表arr0\arr1\arr2\arr3…\arr6,y∈ (0,4))
(2)sizeof(strx) 都为4. (其中strx代表str1\str2\str3\str4,另在32位平台下,指针大小为4字节)
(3)这里先给出一个事实,后面说原理:sizeof(arrx) = 5
为什么呢? 首先,在字符串中‘\0’代表空字符,‘\0’ASCII值为0. 所以可认为‘\0’ == 0.
strlen函数工作机理:函数从第一个字符开始计算字符串中字符数,直到遇到空字符,然后返回空字符前字符总个数。
接下来分析:
01、char * str1 = “abc”;
strlen(…) = 3;
字符串"abc",没什么好说的,系统自动在该形式表达出的字符串末尾加上空字符。 所以为3.
02、char * str2 = “ab\0c”;
strlen(…) = 2;
提一下上面01中的字符串"abc"相当于 “abc\0”,即系统把 ‘\0’ 当成一个整体字符来识别成空字符,而不是按照 ‘\’ 与 ‘0’ 两个字符对待。 所以遇到第02个字符串 ‘ab’ 后的 ‘\0’ 时,strlen函数认为已经到了字符串的结尾。
03、char * str3 = “ab\\0c”;
strlen(…) = 5;
此时第二个斜杠被第一个斜杠转义,’\\0’ 相当于字符’\‘与字符’0’(第二个’\‘被第一个’\‘转义为独立字符 ‘\’, 而不是把第二个 ‘\’ 当成一个 转义字符 与 0 合为’\0’)。
04、char * str4 = "abc0c"
strlen(…) = 5;
虽然说过 ‘\0’ == 0,可是在字符串中的’0’, 代表字符’0’ 而不是数字0. 因此不终止strlen计算个数。
05、char arr0[5] = {‘1’, ‘2’, ‘3’, ‘4’, ‘5’};
strlen(…) = 不确定;
这是一个字符数组,他里面存放的并不是字符串 (因为无’\0’),只是一系列字符 因为最后无空字符,所以strlen一直寻找直到遇到第一个空字符,此时结果不可预知
比如我自己试了两次,一次strlen( arr0[5] ) = 15,一次16
06、char arr1[5] = {‘1’, ‘2’, ‘3’, ‘4’, ‘\0’};
strlen(…) = 4;
因为第五个元素为’\0’
07、char arr2[5] = {‘1’, ‘2’, ‘3’, ‘4’, 0};
strlen(…) = 4;
因为数字0 == ‘\0’
08、char arr3[5] ={‘0’, ‘0’, ‘0’};
strlen(…) = 3;
前三个元素为字符‘0’ != 数字0 (’\0’),因为部分初始化,数组剩下元素被设置为数字0,因此第四个元素为0 == ‘\0’。终止,所以为3.(数组声明后不初始化,里面值为随机值,部分初始化后,未被初始化部分自动被初始化为0)
09、char arr[4] = {0, ‘a’, ‘b’};
strlen(…) = 0
10、char arr[5] = {‘a’, ‘\0’, ‘b’}
strlen(…) = 1
11、char arr[6] = {‘a’, 0, ‘b’};
strlen(…) = 1
文末还有一个小练习
小小总结一下:
1.字符串和字符数组的区别和联系:
C语言中没有一个用于表示字符串的关键字;
C语言的字符串由C的字符数组变形而成,末尾加上’\0’,即字符串比字符数组多一个’\0’;
要从内存分配角度分析请看另一篇博文:
/yygsj/p/4996377.html
2.数字0,’\0’ ,字符0的关系:
在字符串中‘\0’代表空字符,‘\0’ASCII值为数字0. 所以可认为‘\0’ == 0.
注意只有数字0才会被当做空字符’\0’哦,字符0(即’0’)还是不会被当做空字符的。
比如char *str = “abc0”,char str1[] = “abc0”;这里字符串"abc0"中的0会被当做字符0(即’0’),strlen()不终止;
再比如char str2[] = {‘a’, ‘b’, ‘c’, ‘0’},这个字符数组str2就相当于字符串str,strlen()函数求长度都是4;
再比如char str3[] = {‘a’, ‘b’, ‘c’, ‘\0’},char str4[] = {‘a’, ‘b’, ‘c’, 0};这俩是求长度是一样的,原因就是上面的’\0’ 和 数字0均认为是空字符;
3.我们再来看看"abc\0d"这个字符串(而不是字符数组),系统在d字符后还加空字符吗? 它里面已经有空字符了啊!?
系统还是会加的,因为系统只负责在引号中最后一个字符结尾加一个空字符,然后根据你占用的空间大小以字节为单位给字符串开辟空间,它才不管你字符串里面有没有空字符
( 按照约定,空字符代表字符串结束,所以平时不要在字符串内部加空字符 )
我们可以通过sizeof关键字来验证,sizeof以字节为单位返回所占空间大小,包括空字符, 而strlen是计算长度直到遇到空字符停止,对他来说遇到空字符就停止工作。
如果系统在"abc\0d"末尾加空字符,那么sizeof(“abc\0d”)的返回值应该为6(‘\0’当一个字符对待),不加则为5。经验证为6,说明系统在最后是加空字符的(也说明了字符串中的空字符并不起终止字符串存储的作用,系统只是把’\0’当字符串中一个字符对待)。
sizeof(“abc\0”) == 5 ( 系统加了一个空字符’\0’,所以为5;另外strlen(“abc\0”)==3)
sizeof(“abc\0\0”) == 6(系统加了一个空字符’\0’,所以为6;另外strlen(“abc\0\0”)==3)
sizeof(“abc\0d”)== 6(系统加了一个空字符’\0’,所以为6;另外strlen(“abc\0d”)==3)
还想到一种验证方法(可看可不看),针对"abc\0d"实现一个函数,函数遇到第二个空字符返回包括第二个空字符在内的字符串字符总个数,即可以验证系统在这个字符串后还加没加空字符。(如果加程序返回6,如果不加则不是6,是一个随机值,or 程序直接出错)。
#include <stdio.h>int MyFun (const char * str);int main (void){int n = MyFun("abc\0d");printf ("%d\n", n);return 0;}int MyFun (const char * str){int i = 0;int flag = 0;while (1){i++;if ( *str++ == '\0' ){flag++;}if ( flag == 2 ){return i;}}}
最后贴一张私信回复题目的图,巩固和补充一些小细节。
部分摘自:/ssopp24/article/details/52893694