7

我知道字符串对象不是空终止的,但为什么要这样做呢?

std::string S("Hey");
for(int i = 0; S[i] != '\0'; ++i)
   std::cout << S[i];

所以构造函数也复制空终止符,但不增加长度?为什么会打扰?

4

2 回答 2

8

std::string以空终止 C 字符串的形式在内部存储其数据,但在正常使用中不允许您访问空终止符。

例如,如果我分配值“Hello, World!” 对于一个字符串,内部缓冲区将如下所示:

std::string myString("Hello, World!");

// Internal Buffer...
// [ H | e | l | l | o | , |   | W | o | r | d | ! | \0 ]
//                                                   ^ Null terminator.

在此示例中,空终止符不是从字符串文字的末尾复制的,而是在内部由std::string.

正如@songyuanyao 在他的回答中提到的那样,结果是myString[myString.size()];返回'\0'

那么为什么std::string要在字符串的末尾分配一个空终止符呢?它当然不必支持一个,因为您可以添加'\0'到字符串中并且它包含在字符串中:

std::string myString;
myString.size();              // 0
myString.push_back('\0');
myString.size();              // 1

这种行为的原因是为了支持该std::string::c_str()功能。该c_str()函数需要返回一个以 null 结尾的const char *。最有效的方法是简单地返回一个指向内部缓冲区的指针,但为了做到这一点,内部缓冲区必须在字符串的末尾包含一个空终止符。从 C++11 开始,字符串需要包含空终止符来支持这一点。

PS虽然严格来说不是您问题的一部分,但应该指出,如果您的字符串包含空字符,您的问题中的循环可能不会返回完整的字符串:

std::string S("Hey");
S.push_back('\0');
S.append("Jude");

for(int i = 0; S[i] != '\0'; ++i)
    std::cout << S[i];

// Only "Hey" is printed!
于 2016-11-21T09:53:03.757 回答
8

所以构造函数也复制空终止符,但不增加长度?

如您所知,std::string它不包含空字符(并且它不会在此处复制空字符)。

关键是您正在使用std::basic_string::operator[]. 根据 C++11,std::basic_string::operator[]当指定索引等于 . 时,将返回一个空字符size()

如果pos == size(),则返回对具有值的字符CharT()(空字符)的引用。

对于第一个(非常量)版本,如果将此字符修改为除 之外的任何值,则行为未定义charT()

于 2016-11-21T09:20:34.177 回答