std :: strings的结尾是' \ 0'什么时候用字符串文字初始化?

时间:2016-11-21 09:17:34

标签: c++ string null-terminated subscript-operator

我知道字符串对象没有被终止,但为什么这样做呢?

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

所以构造函数也复制了null终止符,但是不增加长度?为什么这么麻烦?

2 个答案:

答案 0 :(得分:6)

  

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

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

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

  

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

     

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

答案 1 :(得分:4)

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

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

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

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

在此示例中,null终止符未从字符串文字的末尾复制,而是由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开始,字符串 required 包含null终止符以支持它。

P.S。虽然不是严格意义上的一部分问题,但应该指出,如果您的字符串包含空字符,那么您问题的循环可能不会返回完整的字符串:

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!