【问题标题】: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。
  • 我重新打开了这个问题,因为 OP 知道 std::string 不是空终止的,而是对 std::string::operator[] 的行为感到困惑。

标签: c++ string null-terminated subscript-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!
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-18
      • 2011-06-06
      • 1970-01-01
      • 1970-01-01
      • 2020-09-26
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多