为什么/何时为C字符串包含终止'\ 0'字符?
我对C非常陌生,对于什么时候需要手动添加字符串的终止'\ 0'字符有点困惑。给出这个函数来计算字符串长度(为了清楚起见):为什么/何时为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(也是为什么e情况2的规则行为,并且不需要在1和3中指定空终止字符。另外,3和4的工作方式是否相同?)以及5和6如何分配相同的内容,即使分配的内存不足情况5为空终止字符(因为只有5个字符分配给每个字母在“松弛”中,它是如何检测'\ 0'字符的,即第6个字符?)
我很抱歉这个荒谬长的问题,它只是我找不到这些具体事例还有
在情况1中,您正在创建一个字符串文字(一个将在只读存储器上的常量),该文字将隐含地添加到该字符串中\0
。
由于\0
的位置依赖于找到字符串的结尾,所以您的stringLength()
函数会打印5
。
在情况2中,您试图用5个字符的字符串初始化大小为5的字符数组,而不会为\0
分隔符留下空间。与该字符串相邻的内存可以是任何内容,并且可能在某处存在\0
。这个\0
被认为是字符串的结尾,它解释了你得到的那些奇怪的字符。看起来,对于你输出的结果,这个\0
只有在计算字符串长度时也考虑了3个字符后才被发现。由于内存内容随时间而改变,因此输出可能并不总是相同的。
在情况3中,您正在使用大小为5的字符串初始化大小为6的字符数组,留下足够的空间来存储将被隐式存储的\0
。因此,它会正常工作。
案例4类似于通过
char stack4[5] = '\0';
来区分3.无修改完成,因为stack4
大小为6,因此其最后指数是5,您将要覆盖其旧值本身就是一个变量。 stack4[5]
甚至在你重写它之前就已经有了\0
。
在情况5中,您已经完整地填充了字符数组,并且没有留下空间来存放\0
。但是,当您打印字符串时,它会正确打印。我认为这是因为与malloc()
分配的内存相邻的内存恰好为0,这是\0
的值。但这是不确定的行为,不应该依赖。真正发生的事情取决于实施。
应该注意的是,与calloc()
不同,malloc()
不会初始化其分配的内存。
两个
char str[2]='\0';
和
char str[2]=0;
是一样的。
但是你不能依靠它为零。由于操作系统的工作以及安全原因,动态分配的内存可能具有零作为默认值。有关更多信息,请参阅here和here。
如果您需要动态分配内存的默认值为零,则可以使用calloc()
。
情况6最后有\0
,其他位置有字符。打印时应显示正确的字符串。
*“在情况5 ...我认为这是因为malloc()分配的内存邻近的内存为零”* - 可以说/不可能是真的。这是因为你已经调用了*未定义的行为* - 如果内存中的下一个字节恰好是'0',那么它可以工作,但是不能保证会发生什么 - *和*'malloc'不初始化内存。但是,如果你修正了这个声明,那么所有的考虑,当然值得投票,会更好。 –
@ DavidC.Rankin感谢您纠正我。我编辑它。 –
这对我的理解非常有帮助,非常感谢你@J ... S!如果我没有明确添加'stack6 [5] ='\ 0'这一行,情况6会发生什么;'因为它不是字符串文字,它会添加'\ 0'字符吗?我认为这不会因为我明确添加字符。因此,如果我使用'malloc'而不是'calloc',是否会导致终止字符的未定义行为(即依赖于以前的内存使用情况)? – Coach
任何地方存储的字符串必须始终留有余地,终止空字符的好说教的解释。在你的一些例子中,你不这样做,明确地给出5的长度。在这些情况下,你会得到未定义的行为。
字符串文字总是自动获得空终止符。尽管strlen
返回长度为5,但它确实需要6个字节。
你的情况5只工作,因为undefined有时意味着看起来像它的工作。你可能在内存中的字符串后面有一个零值 - 但你不能依赖它。
非常广泛的,如果你有一个字符串存储在一个数组中,那么你必须知道字符串结束的位置。两个最明显的方法是(1)保留单独的字符数,或(2)用一些唯一字符(例如''\ 0'')终止字符串。选项2似乎是今天最常用的方法,C自动终止带有''\ 0'的字符串常量。标准的C库也会显示''\ 0''终止的字符串。 –
@TomKarzes:“* C自动终止字符串常量'\ 0'*”好吧,只是字符串* *文字*。 – alk
不要试图通过Trial&Error学习C,因为这已知会导致萧条。 – alk