为何/何时包含终止' \ 0' C字符串的字符?

时间:2017-09-17 05:33:43

标签: c string c-strings null-terminated

我对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个字符?)

对于这个荒谬冗长的问题,我感到非常抱歉,只是我无法在其他任何地方找到关于这些特定实例的良好教学解释

2 个答案:

答案 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';

是一样的。

但你不能依赖它为零。由于操作系统的工作和出于安全原因,动态分配的内存可能具有零作为默认值。有关详情,请参阅herehere

如果您需要动态分配的内存的默认值为零,则可以使用char str[2]=0;

案例6最后有calloc(),其他位置有字符。打印时应显示正确的字符串。