20

在许多代码示例中,人们通常'\0'在创建新的 char 数组后使用如下:

string s = "JustAString";
char* array = new char[s.size() + 1];
strncpy(array, s.c_str(), s.size());
array[s.size()] = '\0';

为什么要'\0'在这里使用?

4

5 回答 5

45

您的问题标题引用了 C 字符串。C++std::string对象的处理方式与标准 C字符串不同。\0在使用 C 字符串时很重要,当我在string这里使用该术语时,我指的是标准 C 字符串

\0在 C 中充当字符串终止符。它被称为空字符NUL。它表示处理字符串的代码——标准库,还有你自己的代码——字符串的结尾在哪里。一个很好的例子是strlen返回字符串的长度。

当您声明一个常量字符串时:

const char *str = "JustAString";

然后\0自动为您附加。在其他情况下,您将像数组示例一样管理非常量字符串,有时您需要自己处理它。您的示例中使用的 strncpy的文档是一个很好的说明:strncpy复制空终止字符,除非在复制整个字符串之前达到指定长度的情况。因此,您经常会看到strncpy与空终止符的可能冗余分配相结合。strlcpystrcpy_s旨在解决因疏忽处理此案而引起的潜在问题。

在您的特定示例中,array[s.size()] = '\0';就是这样一种冗余:由于array是 size s.size() + 1,并且strncpy正在复制s.size()字符,因此该函数将附加\0.

标准 C 字符串实用程序的文档将指出您何时需要小心包含此类空终止符。但请仔细阅读文档:因为strncpy细节很容易被忽略,导致潜在的缓冲区溢出。

于 2012-06-08T04:23:13.190 回答
15

为什么 C++ 中的字符串通常以'\0'?

请注意,C++ 字符串和 C 字符串并不相同。
在 C++ 中,string 指的是std::string,它是一个模板类,提供了很多直观的函数来处理字符串。
请注意,C++ std::string 没有终止,但该类提供了将底层字符串数据作为终止的 c 样式字符串\0获取的函数。\0

在 C 中,字符串是字符的集合。此集合通常以\0.
除非使用特殊字符 like ,否则\0无法知道字符串何时结束。
它也被恰当地称为字符串空终止符。

当然,可能还有其他记账方式来跟踪字符串的长度,但是使用特殊字符有两个直接的优点:

  • 它更直观和
  • 没有额外的开销

请注意,这\0是必需的,因为大多数标准 C 库函数都在假设它们被\0终止的情况下对字符串进行操作。
例如:
在使用printf()时,如果您有一个未\0终止的字符串,则printf()继续写入字符stdout直到\0遇到 a ,简而言之,它甚至可能打印垃圾。

为什么要'\0'在这里使用?

不需要\0终止字符串的情况有两种:

  • 在任何用法中,如果您明确记账字符串的长度并且
  • 如果您使用一些标准库 api 将隐式添加 a\0到字符串。

在您的情况下,您已经有第二种情况适合您。

array[s.size()] = '\0';

上面的代码语句在您的示例中是多余的。

对于您的示例 usingstrncpy()使其无用。strncpy()将字符复制s.size()到您的array,请注意,如果在复制字符串后还有剩余空间,它会附加一个空终止符。由于array大小s.size() + 1为 a\0是自动添加的。

于 2012-06-08T04:23:33.093 回答
6

'\0' 是空终止字符。如果您的字符数组没有它并且您尝试执行 strcpy 您将有缓冲区溢出。许多函数依靠它来知道何时需要停止读取或写入内存。

于 2012-06-08T04:27:50.973 回答
4
strncpy(array, s.c_str(), s.size());
array[s.size()] = '\0';

为什么我们应该在这里使用'\0'?

你不应该,第二行是浪费空间。如果您知道如何使用它,strncpy 已经添加了一个空终止。代码可以重写为:

strncpy(array, s.c_str(), s.size()+1);

strncpy 是一个奇怪的函数,它假设第一个参数是第三个参数大小的数组。因此,如果在复制字符串后还有剩余空间,它只会复制空终止。

在这种情况下,您也可以使用 memcpy(),它的效率会稍高一些,但可能会使代码阅读起来不那么直观。

于 2012-06-08T06:28:45.270 回答
2

在 C 中,我们用一个 char(或 w_char)数组来表示字符串,并使用特殊字符来表示字符串的结束。与 Pascal 不同,Pascal 将字符串的长度存储在数组的索引 0 中(因此字符串对字符数有硬性限制),理论上对字符串的字符数没有限制(表示为字符数组)可以在 C 中具有。

在 C 中的默认库以及其他库中的所有函数中,特殊字符都应为 NUL。如果要使用依赖于字符串确切长度的库函数,则必须使用 NUL 终止字符串。您可以完全定义自己的终止字符,但您必须了解涉及字符串(作为字符数组)的库函数可能无法按您预期的那样工作,并且会导致各种错误。

在给出的代码片段中,需要将终止字符显式设置为 NUL,因为您不知道分配的数组中是否有垃圾数据。这也是一个很好的做法,因为在大型代码中,您可能看不到字符数组的初始化。

于 2012-06-08T04:40:22.710 回答