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

Kin*_*uoc 17 c c++ string

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

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

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

pb2*_*b2q 42

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

\0在C中充当字符串终止符.它被称为空字符NUL.它表示处理字符串的代码 - 标准库以及您自己的代码 - 字符串结尾处.一个很好的例子是strlen返回字符串的长度.

使用以下方法声明常量字符串时:

const char *str = "JustAString";
Run Code Online (Sandbox Code Playgroud)

然后\0会自动为您添加.在其他情况下,您将使用数组示例管理非常量字符串,有时您需要自己处理它.该对函数strncpy文档,这是在实施例中使用,是一个很好的例子:strncpy在空终止字符拷贝除了在整个字符串被复制之前达到指定的长度的情况.因此,您经常会看到strncpy与null终止符的可能冗余分配相结合.strlcpystrcpy_s旨在解决因忽略了处理这种情况出现的潜在问题.

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

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


Alo*_*ave 13

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

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

在C中,字符串是字符集合.这个集合通常以a结尾\0.
除非使用类似特殊字符,否则\0无法知道字符串何时结束.
它也恰如其分地称为字符串null终止符.

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

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

请注意,这\0是必需的,因为大多数标准C库函数在字符串上运行,假设它们已\0终止.
例如:
在使用时,printf()如果你有一个没有\0终止的字符串,那么printf()一直写字符stdout直到\0遇到它,简而言之它甚至可能打印垃圾.

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

当您不需要\0终止字符串时,有两种情况:

  • 在任何用法中,如果您明确记录字符串的长度和
  • 如果您使用的是某些标准库api,则会隐式添加一个\0字符串.

在您的情况下,您已经有第二个方案适合您.

array[s.size()] = '\0';
Run Code Online (Sandbox Code Playgroud)

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

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

  • @evanmcdonnal更多的开销,是的,但是空指针"没有开销"的想法是不真实的 - 它是一个额外的字符(1-4个字节).如果您使用UTF32(由于某种原因),那么它们的大小完全相同.在需要查找长度的任何情况下,存储长度也要快得多(因为使用空终止符,您需要一直遍历字符串以确定其长度).我只是想指出,这不是"一种方式显然更好".值得注意的是,C++存储了字符串和向量的长度. (2认同)

eva*_*nal 6

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