字符数组中'\ 0'的意义是什么?

时间:2013-01-13 20:30:13

标签: c

我知道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!

我无法理解其中的差异。任何解释?

9 个答案:

答案 0 :(得分: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循环将永远继续,直到程序崩溃或强制终止它。可能在屏幕上打印垃圾。

答案 1 :(得分:2)

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

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

使用:

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

终止零字符的目的是终止字符串,即间接编码字符串本身的字符串长度信息。如果你以某种方式已经知道字符串的长度,你可以编写正确工作的代码而不依赖于终止零字符。这基本上都是。

现在,在您的代码示例中,第一个循环执行的操作没有多大意义。它从一个实际长度为6的字符串打印7个字符。它也试图打印终止零。

答案 4 :(得分:1)

如果要从第一个字符打印字符串直到结束。当字符串以\0结尾时(在\0之前打印字符),不需要知道该字符串的长度。 所以你不需要任何额外的变量来存储字符串的长度

实际上,字符串可以有许多不同的表示,但最小化消耗的内存(这对C设计者来说很重要)会导致设计人员定义零终止字符串。

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

答案 5 :(得分:0)

我无法理解它在打印字符串和打印字符串时的用法

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

答案 6 :(得分:0)

终止零字符的目的是终止字符串,即间接编码字符串本身中的字符串 length 信息。如果你以某种方式已经知道字符串的长度,你可以编写正确工作的代码而不依赖于终止零字符。这基本上都是。

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

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

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

答案 7 :(得分:0)

打印可变长度的字符串时,必须有一些“信号”表示您已到达终点。通常,这是'\ 0'字符。大多数C标准调用,如strcpy,strcat,printf等,都取决于字符串是否为零终止,因此以'\ 0'字符结尾。这对应于你的第二个例子。

第一个例子是打印一个固定长度的字符串,这是一个不太常见的事件。

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

答案 8 :(得分: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输出没有“run-on”。有时周围的“垃圾”可能已经是零。