检查 std::string.c_str() 的返回值

Nic*_*rey 0 c++ c-strings

在 C++ Primer 第五版中,它说:

c_str 返回的数组不保证无限期有效。

于是我做了一个测试:

//  c_str exploration
std::string strTest = "This is a test";
const char* s1 = strTest.c_str();
strTest = "This is b test";
std::cout << s1 << std::endl;
Run Code Online (Sandbox Code Playgroud)

由于 s1 是一个指针,因此它肯定会显示新值。但是,当我将值更改为不同长度的字符串时,它通常会显示一些垃圾:

//  c_str exploration
std::string strTest = "This is a test";
const char* s1 = strTest.c_str();
strTest = "This is b testsssssssssssssssssssssssssss";
std::cout << s1 << std::endl;
Run Code Online (Sandbox Code Playgroud)

我认为这是因为返回的 C String 已经固定了结束空字符的位置,所以当长度改变时,它会使所有内容无效。令我惊讶的是,有时即使我将字符串更改为新长度,它仍然有效:

//  c_str exploration
std::string strTest = "This is a test";
const char* s1 = strTest.c_str();
strTest = "This is b tests";     // Note the extra s at the end
std::cout << s1 << std::endl;
Run Code Online (Sandbox Code Playgroud)

第二个问题:

我也不确定为什么std::cout << s1打印内容而不是 C 字符串的地址。虽然以下代码按我的预期打印了整数的地址:

int dim = 42;
int* pdim = &dim;
std::cout << pdim << std::endl;
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,打印出字符“T”:

std::cout << *s1 << std::endl;
Run Code Online (Sandbox Code Playgroud)

我的假设是 std::cout 会自动转换,但请更多地讲授我这一点。

R S*_*ahu 5

第一个问题

std::c_str()如果字符串未被修改,则返回的指针保持有效。来自cppreference.com

通过以下方式获得的指针c_str()可能会失效:

  • 将对字符串的非常量引用传递给任何标准库函数,或者
  • 对字符串调用非常量成员函数,不包括operator[]at()front()back()begin()rbegin()end()rend()

在您发布的代码中,

std::string strTest = "This is a test";
const char* s1 = strTest.c_str();
strTest = "This is b tests";  // This line makes the pointer invalid.
Run Code Online (Sandbox Code Playgroud)

然后使用指针访问字符串是未定义的行为。

std::cout << s1 << std::endl; // Undefined behavior.
Run Code Online (Sandbox Code Playgroud)

之后,尝试理解代码的作用是毫无意义的。

第二个问题

标准库提供了 之间的运算符重载函数std::ostreamchar const*因此可以以合理的方式打印 C 样式字符串。当您使用:

std::cout << "Hello, World.";
Run Code Online (Sandbox Code Playgroud)

您希望看到Hello, World.的是输出,而不是指向该字符串的指针的值。

由于超出本答案范围的原因,该函数重载被实现为非成员函数。

template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os, 
                                         const CharT* s );
Run Code Online (Sandbox Code Playgroud)

替换所有与模板相关的标记后,该行将转换为:

std::ostream& operator<<(std::ostream& os, const char* s );
Run Code Online (Sandbox Code Playgroud)

您可以在cppreference.com上查看非成员重载函数的列表。