在许多代码示例中,人们通常'\0'
在创建新的 char 数组后使用如下:
string s = "JustAString";
char* array = new char[s.size() + 1];
strncpy(array, s.c_str(), s.size());
array[s.size()] = '\0';
为什么要'\0'
在这里使用?
您的问题标题引用了 C 字符串。C++std::string
对象的处理方式与标准 C字符串不同。\0
在使用 C 字符串时很重要,当我在string
这里使用该术语时,我指的是标准 C 字符串。
\0
在 C 中充当字符串终止符。它被称为空字符或NUL。它表示处理字符串的代码——标准库,还有你自己的代码——字符串的结尾在哪里。一个很好的例子是strlen
返回字符串的长度。
当您声明一个常量字符串时:
const char *str = "JustAString";
然后\0
自动为您附加。在其他情况下,您将像数组示例一样管理非常量字符串,有时您需要自己处理它。您的示例中使用的 strncpy的文档是一个很好的说明:strncpy
复制空终止字符,除非在复制整个字符串之前达到指定长度的情况。因此,您经常会看到strncpy
与空终止符的可能冗余分配相结合。strlcpy
并strcpy_s
旨在解决因疏忽处理此案而引起的潜在问题。
在您的特定示例中,array[s.size()] = '\0';
就是这样一种冗余:由于array
是 size s.size() + 1
,并且strncpy
正在复制s.size()
字符,因此该函数将附加\0
.
标准 C 字符串实用程序的文档将指出您何时需要小心包含此类空终止符。但请仔细阅读文档:因为strncpy
细节很容易被忽略,导致潜在的缓冲区溢出。
为什么 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
终止字符串的情况有两种:
\0
到字符串。在您的情况下,您已经有第二种情况适合您。
array[s.size()] = '\0';
上面的代码语句在您的示例中是多余的。
对于您的示例 usingstrncpy()
使其无用。strncpy()
将字符复制s.size()
到您的array
,请注意,如果在复制字符串后还有剩余空间,它会附加一个空终止符。由于array
大小s.size() + 1
为 a\0
是自动添加的。
'\0' 是空终止字符。如果您的字符数组没有它并且您尝试执行 strcpy 您将有缓冲区溢出。许多函数依靠它来知道何时需要停止读取或写入内存。
strncpy(array, s.c_str(), s.size());
array[s.size()] = '\0';
为什么我们应该在这里使用'\0'?
你不应该,第二行是浪费空间。如果您知道如何使用它,strncpy 已经添加了一个空终止。代码可以重写为:
strncpy(array, s.c_str(), s.size()+1);
strncpy 是一个奇怪的函数,它假设第一个参数是第三个参数大小的数组。因此,如果在复制字符串后还有剩余空间,它只会复制空终止。
在这种情况下,您也可以使用 memcpy(),它的效率会稍高一些,但可能会使代码阅读起来不那么直观。
在 C 中,我们用一个 char(或 w_char)数组来表示字符串,并使用特殊字符来表示字符串的结束。与 Pascal 不同,Pascal 将字符串的长度存储在数组的索引 0 中(因此字符串对字符数有硬性限制),理论上对字符串的字符数没有限制(表示为字符数组)可以在 C 中具有。
在 C 中的默认库以及其他库中的所有函数中,特殊字符都应为 NUL。如果要使用依赖于字符串确切长度的库函数,则必须使用 NUL 终止字符串。您可以完全定义自己的终止字符,但您必须了解涉及字符串(作为字符数组)的库函数可能无法按您预期的那样工作,并且会导致各种错误。
在给出的代码片段中,需要将终止字符显式设置为 NUL,因为您不知道分配的数组中是否有垃圾数据。这也是一个很好的做法,因为在大型代码中,您可能看不到字符数组的初始化。