字符串c_str()与data()


102

我看了几个地方那之间的区别c_str(),并data()(在STL和其他实现)是c_str()始终是NULL终止,而data()不是。据我在实际实现中看到的,它们要么执行相同的操作,要么data()调用c_str()

我在这里想念什么?在哪种情况下使用哪个更正确?

Answers:


105

该文档是正确的。使用c_str(),如果你想有一个空结束的字符串。

如果实现者恰好实现data()c_str()您不必担心的实现,则仍然可以使用,data()如果您不需要以null结尾的字符串,那么在某些实现中,它可能会比c_str()更好。

字符串不一定必须由字符数据组成,它们可以由任何类型的元素组成。在那些情况下data()更有意义。c_str()在我看来,仅当字符串的元素基于字符时才真正有用。

附加:从C ++ 11开始,两个函数必须相同。即data现在需要为空终止。根据cppreference的描述:“返回的数组以null结尾,即data()和c_str()执行相同的功能。”


4
附加2:从C ++ 17开始,现在还存在的非常量重载.data(),因此它们不再等效于非常量字符串。
Deduplicator

29

C ++ 11 / C ++ 0x中data()并且c_str()不再不同。因此,data()还需要在末尾具有空终止。

21.4.7.1 basic_string访问器[string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1返回:指针p,这样in 中p + i == &operator[](i)的每个指针。i[0,size()]


21.4.5 basic_string元素访问[string.access]

const_reference operator[](size_type pos) const noexcept;

1要求:pos <= size()。2返回:*(begin() + pos) if pos < size(),否则charT();将不修改对值为T的T类型对象的引用。


如果字符串由非字符数据组成(对于字符串数据AFAIK合法,包括null),该怎么办?
taz

3
@taz即使存储二进制数据,C ++ 11也要求为尾随std::string分配额外char的空间'\0'。当你这样做std::string s("\0");,既s.data()[0]s.data()[1]保证,以评估为0
bcrist

19

甚至知道您已经看到它们执行相同的操作,或者.data()调用.c_str()时,假设其他编译器也是如此是不正确的。您的编译器也可能会在将来的版本中进行更改。

使用std :: string的2个理由:

std :: string可以用于文本和任意二进制数据。

//Example 1
//Plain text:
std::string s1;
s1 = "abc";

//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);

在将字符串用作示例1时,应使用.c_str()方法。

在使用字符串作为示例2时,应使用.data()方法。这不是因为在这种情况下使用.c_str()是危险的,而是因为更明确的是您正在使用二进制数据供其他人查看您的代码。

使用.data()可能的陷阱

以下代码是错误的,可能会在您的程序中导致段错误:

std::string s;
s = "abc";   
char sz[512]; 
strcpy(sz, s.data());//This could crash depending on the implementation of .data()

为什么实现者使.data()和.c_str()做相同的事情很常见?

因为这样做更有效。使.data()返回不以null结尾的东西的唯一方法是使.c_str()或.data()复制其内部缓冲区,或者仅使用2个缓冲区。拥有单个以null终止的缓冲区总是意味着在实现std :: string时,您始终只能使用一个内部缓冲区。


6
实际上,.data()的要点是它不应复制内部缓冲区。这意味着在不需要之前,实现不必浪费\ 0上的char。您永远不需要两个缓冲区:如果要调用.c_str(),请在缓冲区后面附加\ 0。.data()仍可以返回该缓冲区。
MSalters

2
完全同意使用2个缓冲区是荒谬的。您怎么知道这就是为什么要使用.data的原因?
Brian R. Bondy

@ BrianR.Bondy我尝试了以下代码:.. auto str = string {“测试\ 0String!” }; cout <<“ DATA:” << str.data()<< endl; 输出是“ Test”而不是整个字符串,我做错了什么?
程序员

最后一部分是错误的,数据和c_str可以使用相同的缓冲区而不用0终止-c_str可以在第一次调用时简单地添加0。
记得莫妮卡

注意,c ++ 11将.data()用作.c_str()的别名
hanshenrik

3

它已经得到答复,并有以下目的说明:执行自由。

std::string操作(例如迭代,串联和元素突变)不需要零终止符。除非将传递string给期望终止字符串为零的函数,否则可以将其省略。

这将允许实现使子字符串共享实际的字符串数据:string::substr可以在内部保存对共享字符串数据的引用以及起始/结束范围,从而避免了实际字符串数据的复制(和其他分配)。该实现将推迟副本,直到您调用c_str或修改任何字符串为止。如果仅阅读所涉及的信息,将不会复制任何内容。

(在多线程环境中,写时复制实现不是很有趣,再加上今天节省的内存/分配并不值得更复杂的代码,因此很少这样做)。


同样,string::data允许使用不同的内部表示形式,例如,绳索(字符串段的链接列表)。这可以显着改善插入/替换操作。同样,当您调用c_str或时,必须将细分列表折叠到单个细分中data


2

引用自ANSI ISO IEC 14882 2003(C ++ 03 Standard):

    21.3.6 basic_string string operations [lib.string.ops]

    const charT* c_str() const;

    Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements
equal the corresponding elements of the string controlled by *this and whose last element is a
null character specified by charT().
    Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the
returned value as a valid pointer value after any subsequent call to a non-const member function of the
class basic_string that designates the same object as this.

    const charT* data() const;

    Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first
size() elements equal the corresponding elements of the string controlled by *this. If size() is
zero, the member returns a non-null pointer that is copyable and can have zero added to it.
    Requires: The program shall not alter any of the values stored in the character array. Nor shall the program
treat the returned value as a valid pointer value after any subsequent call to a non- const member
function of basic_string that designates the same object as this.

2

先前所有的评论都是一致的,但我还要补充一点,从c ++ 17开始,str.data()返回一个char *而不是const char *


1
两个constnon-const重载可自C ++ 17。
Gupta
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.