用字符串文字初始化时,std::strings 是不是以 '\0' 结尾?

Posted

技术标签:

【中文标题】用字符串文字初始化时,std::strings 是不是以 \'\\0\' 结尾?【英文标题】:Do std::strings end in '\0' when initialized with a string literal?用字符串文字初始化时,std::strings 是否以 '\0' 结尾? 【发布时间】:2016-11-21 09:17:34 【问题描述】:

我知道字符串对象不是以 null 结尾的,但为什么会这样呢?

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

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

【问题讨论】:

std::string 闻起来不像 C。 检查这个:***.com/questions/39725183/… 我重新打开了这个问题,因为 OP 知道 std::string 不是空终止的,而是对 std::string::operator[] 的行为感到困惑。 【参考方案1】:

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

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

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

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

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

【讨论】:

【参考方案2】:

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 开始,要求字符串包含空终止符来支持这一点。

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

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!

【讨论】:

以上是关于用字符串文字初始化时,std::strings 是不是以 '\0' 结尾?的主要内容,如果未能解决你的问题,请参考以下文章

是否有任何可能的方法来强制使用字符串文字进行隐式构造函数初始化

c ++如何创建包含未初始化字节大小的std :: string?

比较两个 std::strings 以查看它们是不是匹配 c++ [关闭]

std::strings 有啥问题

C++ 字符串声明

VS中R转义字符处理