我对C很陌生,对于何时我们需要手动添加终止' \ 0'而言我感到有点困惑。字符串到字符串。鉴于这个函数来计算字符串长度(为了清楚起见):
int stringLength(char string[])
{
int i = 0;
while (string[i] != '\0') {
i++;
}
return i;
}
根据空终止字符计算字符串的长度。因此,使用以下案例,' \ 0'的作用是什么?角色,如果有的话?
案例1:
char * stack1 = "stack";
printf("WORD %s\n", stack1);
printf("Length %d\n", stringLength(stack1));
打印:
WORD stack
Length 5
案例2:
char stack2[5] = "stack";
printf("WORD %s\n", stack2);
printf("Length %d\n", stringLength(stack2));
打印:
WORD stack���
Length 8
(这些结果每次都有所不同,但永远不正确)。
案例3:
char stack3[6] = "stack";
printf("WORD %s\n", stack3);
printf("Length %d\n", stringLength(stack3));
打印:
WORD stack
Length 5
案例4:
char stack4[6] = "stack";
stack4[5] = '\0';
printf("WORD %s\n", stack4);
printf("Length %d\n", stringLength(stack4));
打印:
WORD stack
Length 5
案例5:
char * stack5 = malloc(sizeof(char) * 5);
if (stack5 != NULL) {
stack5[0] = 's';
stack5[1] = 't';
stack5[2] = 'a';
stack5[3] = 'c';
stack5[4] = 'k';
printf("WORD %s\n", stack5);
printf("Length %d\n", stringLength(stack5));
}
free(stack5);
打印:
WORD stack
Length 5
案例6:
char * stack6 = malloc(sizeof(char) * 6);
if (stack6 != NULL) {
stack6[0] = 's';
stack6[1] = 't';
stack6[2] = 'a';
stack6[3] = 'c';
stack6[4] = 'k';
stack6[5] = '\0';
printf("WORD %s\n", stack6);
printf("Length %d\n", stringLength(stack6));
}
free(stack6);
打印:
WORD stack
Length 5
即,我想知道案例1,2,3和4之间的区别(也是为什么案例2的不稳定行为,而不需要在1和3中指定空终止字符。另外,如何3即使在案例5中没有为空终止字符分配足够的内存,因此5和6两者的工作方式相同?)以及5和6如何打印出相同的内容(因为在&#34中每个字母只分配了5个字符槽;松弛",如何检测' \ 0'字符,即第6个字符?)
对于这个荒谬冗长的问题,我感到非常抱歉,只是我无法在其他任何地方找到关于这些特定实例的良好教学解释
答案 0 :(得分:5)
字符串的 storage 必须始终为终止空字符留出空间。在你的一些例子中,你不要这样做,明确给出长度为5.在这些情况下,你将得到未定义的行为。
String literals 始终自动获取null终结符。即使strlen
返回的长度为5,它实际上也需要6个字节。
你的案例5才有效,因为 undefined 有时意味着它看起来像是有效的。在内存中的字符串之后,你的值可能为零 - 但你不能依赖它。
答案 1 :(得分:3)
在案例1中,您正在创建一个字符串文字(一个将在只读内存上的常量),它将隐式添加\0
。
由于依靠\0
的位置来查找字符串的结尾,因此stringLength()
函数会打印5
。
在第2种情况下,您尝试使用5个字符的字符串初始化大小为5的字符数组,而\0
分隔符没有空格。字符串旁边的内存可以是任何内容,并且某处可能有\0
。这个\0
被认为是字符串的结尾,这解释了你得到的那些奇怪的字符。似乎对于您给出的输出,只有在计算字符串长度时还考虑了3个字符之后才发现此\0
。由于存储器的内容随时间而变化,因此输出可能并不总是相同。
在第3种情况下,您正在使用大小为5的字符串初始化大小为6的字符数组,留下足够的空间来存储将隐式存储的\0
。因此,它将正常工作。
案例4与案例3类似。
未进行任何修改char stack4[5] = '\0';
因为stack4
的大小为6,因此它的最后一个索引是5.您将使用旧值本身覆盖变量。 <{1}}甚至在你覆盖它之前就已经stack4[5]
了。
在第5种情况下,您已使用字符完全填充字符数组,而不为\0
留出空间。然而,当你打印字符串时,它打印正确。我认为这是因为\0
分配的内存旁边的内存恰好是零,这是malloc()
的值。但这是不明确的行为,不应该依赖。真正发生的事情取决于实施情况
应该注意的是\0
不会初始化它分配的内存而不像malloc()
。
两个
calloc()
和
char str[2]='\0';
是一样的。
但你不能依赖它为零。由于操作系统的工作和出于安全原因,动态分配的内存可能具有零作为默认值。有关详情,请参阅here和here。
如果您需要动态分配的内存的默认值为零,则可以使用char str[2]=0;
。
案例6最后有calloc()
,其他位置有字符。打印时应显示正确的字符串。