2

我知道 C 中的每个字符串都以 '\0' 字符结尾。当我们需要知道字符串何时结束时,它非常有用。但是,我无法理解它在打印字符串和没有它的情况下打印字符串的用途。我有以下代码: -

/* Printing out an array of characters */
#include<stdio.h>
#include<conio.h>
int main()
{
    char a[7]={'h','e','l','l','o','!','\0'};
    int i;
    /* Loop where we do not care about the '\0' */ 
    for(i=0;i<7;i++)
    {
        printf("%c",a[i]);
    }
    printf("\n");
    /* Part which prints the entire character array as string */
    printf("%s",a);
    printf("\n");
    /* Loop where we care about the '\0' */
    for(i=0;i<7&&a[i]!='\0';i++)
    {
        printf("%c",a[i]);
    }
}

输出是: -

hello!
hello!
hello!

我无法理解其中的区别。有什么解释吗?

4

9 回答 9

3

在这种情况下:

for(i=0;i<7;i++)
{
    printf("%c",a[i]);
}

您循环数次 (7) 然后退出。那是循环的结束条件。它终止,不管别的。

在另一种情况下,您还循环了 7 次,不再循环,您只是添加了另一个条件,这实际上没有任何作用,因为您已经记录了一些事情。如果您执行了以下操作:

 int index = 0;
 while (a[index] != '\0') { printf("%c", a[index]); index++; } 

现在你将依赖那里的零终止字符,如果它不在字符串中,你的while循环将永远持续下去,直到程序崩溃或强制终止它。可能在屏幕上打印垃圾。

于 2013-01-13T20:33:36.170 回答
2

\0不是字符串中数据的一部分。它是字符串结束的指示器。如果不知道字符串的长度,请查找此指示符。在它的帮助下,您可以更换您的循环:

for(i=0;i<7&&a[i]!='\0';i++) { ...

和:

for(int i=0; a[i]; ++i) { ...

因此,for-loops 和 printf 显示的是相同的字符串。唯一的区别是你如何打印它。

于 2013-01-13T20:34:05.843 回答
1

'\0'不对应于可显示的字符;这就是为什么第一个和最后一个版本看起来是一样的。

第二个版本是相同的,因为在引擎盖下,printf它只是迭代直到它到达'\0'.

于 2013-01-13T20:31:35.043 回答
1

终止零字符的目的是终止字符串,即在字符串本身中间接编码字符串长度信息。如果您以某种方式已经知道字符串的长度,则可以编写可以正常工作的代码,而无需依赖终止的零字符。基本上就是这样。

现在,在您的代码示例中,第一个循环做了一些没有多大意义的事情。它从实际长度为 6 的字符串中打印 7 个字符。即它也尝试打印终止零。

于 2013-01-13T20:35:29.840 回答
1

当您想从第一个字符到结尾打印字符串时。\0当字符串以(Print characters until \0)结尾时,不需要知道该字符串的长度。所以你不需要任何额外的变量来存储 string 的长度

事实上,一个字符串可以有许多不同的表示,但最小化消耗的内存(这对 C 设计人员很重要)导致设计人员定义以零结尾的字符串。

每个字符串表示在速度、内存和灵活性之间都有它的权衡。例如,您可以让您的字符串定义与 Pascal 字符串相同,它在数组的第一个元素处存储字符串的长度,但它会导致该字符串的长度有限,但检索字符串的长度比以零结尾的字符串更快(计算每个字符直到\0)。

于 2013-01-13T20:40:21.837 回答
0

我无法理解它在打印字符串和没有它的情况下打印字符串的用途

通常,您不会像这样逐个字符地打印字符串。您打印整个字符串。在这种情况下,您的 C 库将一直打印到找到零为止。

于 2013-01-13T20:32:50.103 回答
0

终止零字符的目的是终止字符串,即在字符串本身中间接编码字符串长度信息。如果您以某种方式已经知道字符串的长度,则可以编写可以正常工作的代码,而无需依赖终止的零字符。基本上就是这样。

现在,在您的代码示例中,第一个循环做了一些没有多大意义的事情。它从实际长度为 6 的字符串中打印 7 个字符。即它也尝试打印终止零。为什么会这样——我不知道。换句话说,您的代码生成的第一个输出在形式上与其他输出不同,因为它包括在!符号后立即打印零字符的效果。在您的平台上,这种效果恰好在屏幕上“不可见”,这就是为什么您可能认为第一个输出与其他输出相同的原因。但是,如果您将输出重定向到一个文件,您将能够看到它实际上是完全不同的。

代码中的其他输出方法只是将字符串输出到(但不包括)终止零字符。最后一个循环具有冗余条件检查,因为您知道循环将在零字符处停止,之前i将有机会达到 7。

除此之外,我不知道您可能会问什么“差异”。请澄清你的问题,如果这不能回答它。

于 2013-01-13T20:36:41.867 回答
0

当打印一个可变长度的字符串时,必须有一些“信号”来表明你已经到了结尾。通常,这是 '\0' 字符。大多数 C 标准调用,如 strcpy、strcat、printf 等,都依赖于以零结尾的字符串,因此以 '\0' 字符结尾。这对应于您的第二个示例。

第一个例子是打印一个固定长度的字符串,这种情况很少见。

第三个示例结合了两者,它查找零终止符('\0' 字符)或最多 7 个字符。例如,这对应于 str n cpy 之类的调用。

于 2013-01-13T20:36:43.353 回答
0

在您的循环中,您实际上打印了 nul 字符。通常这不起作用,因为它是非打印、非控制字符。但是printf("%s",a);根本不会输出 nul - 它使用它作为哨兵值。所以你循环不等于 %s 格式化输出。

如果您尝试说:

char a[] = "123456" ;
char b[]={'h','e','l','l','o','!' } ;  // No terminator
char c[] = "ABCDEF" ;

printf( "%s", a ) ;
printf( "%s", b ) ;
printf( "%s", c ) ;

可能清楚地看到为什么 nul 终止符是必不可少的。就我而言,它输出:

123456
hello!╠╠╠╠╠╠╠╠╠╠123456
ABCDEF

您的里程可能会有所不同 - 结果是未定义的行为,但在这种情况下,输出正在运行到相邻的字符串,但编译器在它们之间插入了一些未使用的空间,其中包含“垃圾”。我在未终止的字符串的两侧打包了一个字符串,因为无法知道特定编译器如何在内存中排序数据。顺便说一句,当我将字符串声明为字符串static时,字符串 b 的输出没有“运行”。有时周围的“垃圾”可能恰好已经为零。

于 2013-01-13T23:04:12.977 回答