使用字符串字面量初始化std::strings时,它们是否以'\0'结尾?

9

我知道字符串对象没有以null结尾,但为什么这样也可以工作呢?

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

那么构造函数也会复制空终止符,但不会增加长度?它为什么要这样做呢?

std::string 不像 C 一样有异味。 - Sourav Ghosh
请查看此链接:https://dev59.com/6FkS5IYBdhLWcg3wiXMj#39725242 - Michał Walenciak
3
我重新打开了这个问题,因为提问者已经知道std::string不是以空字符结尾的,但对于std::string::operator[]的行为感到困惑。 - songyuanyao
3个回答

10
所以构造函数也会将空终止符复制,但不会增加长度吗?
正如您所知,std::string 不包含空字符 (并且此处不会复制空字符)。
关键是您正在使用 std::basic_string::operator[]。根据 C++11,std::basic_string::operator[] 将在指定的索引等于 size() 时返回一个空字符。
如果 pos == size(),则返回值为值为 CharT()(即空字符)的字符的引用。对于第一个(非 const)版本,如果将此字符修改为任何值而不是 charT(),则其行为未定义。

10
"

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 起,要求字符串必须包含空终止字符以支持该功能。
P.S. 虽然不是严格属于你的问题,但应指出,如果您的字符串包括 null 字符,则来自您的问题的循环可能不会返回完整的字符串:
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!

0
  • std::string 重载:std::string 类有一种特殊的方式来存储其长度,因此不需要像 C 风格字符串那样使用空字符结尾。您可以使用 S[i] 直接访问字符,并且循环可以在没有 '\0' 的情况下工作。

  • 高效处理:std::string 构造函数在创建字符串时不会添加空字符结尾,因为它使用了更智能的长度管理方法。这种方法对于处理和操作字符串更高效。


你的回答可以通过提供更多支持性信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人能够确认你的回答是否正确。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接