为什么/何时为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

非常广泛的,如果你有一个字符串存储在一个数组中,那么你必须知道字符串结束的位置。两个最明显的方法是(1)保留单独的字符数,或(2)用一些唯一字符(例如''\ 0'')终止字符串。选项2似乎是今天最常用的方法,C自动终止带有''\ 0'的字符串常量。标准的C库也会显示''\ 0''终止的字符串。 –

+0

@TomKarzes:“* C自动终止字符串常量'\ 0'*”好吧,只是字符串* *文字*。 – alk

+0

不要试图通过Trial&Error学习C,因为这已知会导致萧条。 – alk

在情况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; 

是一样的。

但是你不能依靠它为零。由于操作系统的工作以及安全原因,动态分配的内存可能具有零作为默认值。有关更多信息,请参阅herehere

如果您需要动态分配内存的默认值为零,则可以使用calloc()

情况6最后有\0,其他位置有字符。打印时应显示正确的字符串。

+3

*“在情况5 ...我认为这是因为malloc()分配的内存邻近的内存为零”* - 可以说/不可能是真的。这是因为你已经调用了*未定义的行为* - 如果内存中的下一个字节恰好是'0',那么它可以工作,但是不能保证会发生什么 - *和*'malloc'不初始化内存。但是,如果你修正了这个声明,那么所有的考虑,当然值得投票,会更好。 –

+1

@ DavidC.Rankin感谢您纠正我。我编辑它。 –

+1

这对我的理解非常有帮助,非常感谢你@J ... S!如果我没有明确添加'stack6 [5] ='\ 0'这一行,情况6会发生什么;'因为它不是字符串文字,它会添加'\ 0'字符吗?我认为这不会因为我明确添加字符。因此,如果我使用'malloc'而不是'calloc',是否会导致终止字符的未定义行为(即依赖于以前的内存使用情况)? – Coach

任何地方存储的字符串必须始终留有余地,终止空字符的好说教的解释。在你的一些例子中,你不这样做,明确地给出5的长度。在这些情况下,你会得到未定义的行为。

字符串文字总是自动获得空终止符。尽管strlen返回长度为5,但它确实需要6个字节。

你的情况5只工作,因为undefined有时意味着看起来像它的工作。你可能在内存中的字符串后面有一个零值 - 但你不能依赖它。