何时/为啥需要 '\0' 来标记 (char) 数组的结尾?

Posted

技术标签:

【中文标题】何时/为啥需要 \'\\0\' 来标记 (char) 数组的结尾?【英文标题】:When/Why is '\0' necessary to mark end of an (char) array?何时/为什么需要 '\0' 来标记 (char) 数组的结尾? 【发布时间】:2017-04-10 19:47:25 【问题描述】:

所以我刚刚阅读了一个关于如何创建表示字符串的字符数组的示例。

将空字符\0放在数组的末尾以标记数组的末尾。这是必要的吗?

如果我创建了一个 char 数组:

char line[100]; 

并输入单词:

"hello\n"

在其中,字符将被放置在前六个索引line[0] - line[6],所以数组的其余部分无论如何都会被空字符填充?

这本书说,这是一个约定,例如将字符串常量"hello\n" 放入字符数组并以\0 终止。

也许我没有完全理解这个话题,希望能得到启发。

【问题讨论】:

\0 用于在 C 中标记字符串的结尾。大多数 C 标准库函数要求字符串以这种方式终止才能工作。 由于 C 不知道你的字符串有多长,你必须用 \0 标记结尾,这样它就知道它已经到达了你的字符串的结尾。 您也可以在 C 中使用 Pascal 字符串。当然,现有的函数不会期望这样,所以它们不会一起工作。 What's the rationale for null terminated strings?的可能重复 Is it necessary to supply the null character when declaring an character's array?的可能重复 【参考方案1】:

\0 字符不标记“数组的结尾”。 \0 字符标记存储在 char 数组中的 string 的结尾,如果(且仅当)该 char 数组旨在存储字符串。

char 数组只是一个 char 数组。它存储独立的整数值(char 只是一个小整数类型)。 char 数组不必以 \0 结尾。 \0 在 char 数组中没有特殊含义。它只是一个零值。

但有时 char 数组用于存储 字符串。字符串是以\0 结尾的字符序列。所以,如果你想使用你的字符数组作为一个字符串你必须用\0来终止你的字符串。

因此,关于\0 是“必要”的问题的答案取决于您在 char 数组中存储的内容。如果您正在存储一个字符串,那么您必须使用\0 来终止它。如果你存储的不是字符串,那么\0 就没有任何特殊意义。

【讨论】:

【参考方案2】: 如果您将其用作字符数组,则不需要

'\0'。但是如果你使用字符数组作为字符串,你需要放'\0'。 C 中没有单独的字符串类型。

有多种方式来声明字符数组。

例如:

char str1[]    = "my string";
char str2[64]  = "my string";
char str3[]    = 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g', '\0';
char str4[64]  = 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g', '\0';

所有这些数组都有相同的字符串“my string”。在 str1 和 str2 中,'\0' 字符是自动添加的,但在其他两个中,您需要显式添加。

【讨论】:

【参考方案3】:

何时/为什么需要 '\0' 来标记 (char) 数组的结尾?

如果字符数组包含字符串,则需要终止零。这允许找到字符串结束的点。

至于你的例子,我认为如下所示

char line[100] = "hello\n";

那么对于初学者来说,字符串文字有7 字符。它是一个字符串,包括终止零。此字符串文字的类型为char[7]。你可以想象它像

char no_name[] =  'h', 'e', 'l', 'l', 'o', '\n', '\0' ;

当使用字符串字面量初始化字符数组时,其所有字符都将用作初始化器。因此,相对于示例,字符串文字的七个字符用于初始化数组的前 7 个元素。数组中所有其他未由字符串文字的字符初始化的元素将被隐式初始化为零。

如果要确定字符串在字符数组中存储多长时间,可以使用标头 <string.h> 中声明的标准 C 函数 strlen。它返回终止零之前数组中的字符数。

考虑以下示例

#include <stdio.h>
#include <string.h>

int main(void) 

    char line[100] = "hello\n";

    printf( "The size of the array is %zu"
            "\nand the length of the stored string \n%s is %zu\n",
            sizeof( line ), line, strlen( line ) );

    return 0;

它的输出是

The size of the array is 100
and the length of the stored string 
hello
 is 6

在 C 中,您可以使用字符串文字来初始化字符数组,不包括字符串文字的终止零。例如

char line[6] = "hello\n";

在这种情况下,您可能不会说数组包含字符串,因为存储在数组中的符号序列没有终止零。

【讨论】:

【参考方案4】:

您需要空字符来标记字符串的结尾。 C 不存储有关字符数组长度或字符串长度的任何内部信息,因此空字符/字节\0 标记它的结束位置。

这仅对 字符串 是必需的,但是 - 您可以拥有任何不代表字符串的普通字符数组。

例如,试试这段代码:

#include <stdio.h>

int main(void) 
    char string[1];
    string[0] = 'a';
    printf("%s", string);

请注意,字符数组已完全填充了数据。因此,没有空字节来标记结束。现在,printf 将继续打印,直到遇到一个空字节——这将在数组末尾之后的某个位置,因此除了“a”之外,您还会打印出很多垃圾。

现在,试试这个:

#include <stdio.h>

int main(void) 
    char string[2];
    string[0] = 'a';
    string[1] = '\0';
    printf("%s", string);

它只会打印“a”,因为字符串的结尾是明确标记的。

【讨论】:

【参考方案5】:

通过搜索(第一个)NUL 字节来找到 C 字符串(包含字符并以 '\0' 字符结尾的数组)的长度。 \0 是零字符。在 C 中,它主要用于指示字符串的终止。 我给你举个例子:

假设您已将一个单词写入文件:

word = malloc(sizeof(cahr) * 6);
word = "Hello";
fwrite(word, sizeof(char), 6, fp);

word 中,我们为“Hello”的第 5 个字符分配空间,并为其终止的 '\0' 分配一个空间。 fp 是文件。 现在,我们在最后一个词之后再写一个词:

word2 = malloc(sizeof(cahr) * 7);
word2 = "world!";
fwrite(word2, sizeof(char), 7, fp);

那么现在,让我们读一下这两个词:

char buff = malloc(sizeof(char)*1000); // See that we can store as much space as we want, it won't change the final result
/* 13 = (5 chacater from 'Hello')+(1 character of the \0)+(6 characters from 'world!')+(1 character from the \0) */
fread(buff, sizeof(char), 13, fp); // We read the words 'Hello\0' and 'world!\0'
printf("the content of buff is: %s", buff); // This would print 'Hello world!'

这最后是由于结尾的\0 字符,所以C 知道缓冲区中有两个单独的字符串。如果我们没有将 \0 字符放在两个单词的末尾,并重复相同的示例,则输出将是 "Helloworld!" 这可以用于许多字符串方法和函数!。

【讨论】:

以上是关于何时/为啥需要 '\0' 来标记 (char) 数组的结尾?的主要内容,如果未能解决你的问题,请参考以下文章

char类型为啥只能存储0-255

为啥 main(int argc, char* argv[]) 需要两个参数? [复制]

iOS——使用工具来标记何时调用方法[或函数]?

为啥/何时我必须点击两次才能触发 iOS 上的点击

为啥以及何时需要提供我自己的删除器?

为啥以及何时使用 Django mark_safe() 函数