std :: string :: c_str&空终止

时间:2017-01-05 13:00:50

标签: c++ string c-str

我已经阅读了std::string::c_str的各种描述,包括多年来/几十年来提出的问题,

我喜欢这个描述的清晰度:

  

返回指向包含以null结尾的序列的数组的指针   表示当前值的字符(即,C字符串)   字符串对象。该数组包含相同的字符序列   构成字符串对象的值加上一个额外的   最后终止空字符(' \ 0')。

然而,有关此功能目的的一些事情仍不清楚。

您可能原谅认为调用c_str可能会在字符串末尾添加\0字符,该字符串存储在主机对象的内部char数组中(std::string) :

s[s.size+1] = '\0'

但是,即使在调用std::string之前,默认情况下c_str对象仍然是Null终止: enter image description here

查看定义后:

const _Elem *c_str() const _NOEXCEPT
{   // return pointer to null-terminated nonmutable array
    return (this->_Myptr());
}

我没有看到任何将\0添加到char数组末尾的代码。据我所知c_str只返回一个指向存储在数组第一个元素中的字符的指针,就像begin()一样。我甚至看不到代码检查内部数组是否被\0

终止

或者我错过了什么?

3 个答案:

答案 0 :(得分:6)

您没有看到将'\0'添加到序列末尾的代码,因为空字符已存在。 c_str的实现无法返回指向新数组的指针,因此数组必须存储在std::string对象本身上。

因此,您有两种有效的方法来实现它:

  1. 始终将'\0'存储在构造中_Myptr()字符数组的末尾,或
  2. 根据需要制作字符串的副本,在调用'\0'时添加c_str(),并在析构函数中删除副本。
  3. 第一种方法允许您为_Myptr()返回c_str(),代价是为每个字符串存储一个额外字符。第二种方法需要每个std::string对象有一个额外的指针,因此第一种方法更便宜。

答案 1 :(得分:5)

在C ++ 11之前,没有要求std::string(或模板化的类std::basic_string - 其中std :: string是实例化)存储尾随'\0'。这反映在data()c_str()成员函数的不同规范中 - data()返回指向基础数据的指针(不需要以'\0'终止, c_str()返回了一个带有终止'\0'的副本。但是,同样地,没有要求不在内部存储尾随'\0'(访问存储数据末尾的字符是未定义的行为) .....并且,为简单起见,一些实现选择追加尾随'\0'

使用C ++ 11,这改变了。实质上,data()成员函数被指定为与c_str()具有相同的效果(即返回的指针指向具有尾随'\0'的数组的第一个字符)。这导致要求'\0'返回的数组上跟踪data(),因此要求内部表示。

因此,您所看到的行为与C ++ 11一致 - 该类的一个不变量是尾随'\0'(即构造函数确保是这种情况,修改字符串的成员函数确保它仍然是真实的,并且所有公共成员职能都可以依赖它是真实的。)

您看到的行为与C ++ 11之前的C ++标准并不矛盾。严格地说,在C ++ 11之前std::string不需要保持尾随'\0',但同样地,实施者可以选择这样做。

答案 2 :(得分:1)

要求是c_str必须返回空终止的cstring。没有什么可以说函数必须添加null终止符。大多数实现(我认为所有想要符合标准的实现)都将null终止符存储在字符串本身使用的底层缓冲区中。其中一个原因是

std::string s;
assert(s[0] == '\0');

必须工作,因为现在需要字符串返回string[string.size()]处的空终止符。如果string没有在底层缓冲区中存储空终止符,那么[]必须进行边界检查以查看它是否在size()并且需要返回\0

相关问题