检查std :: string.c_str()

时间:2018-06-08 15:50:28

标签: c++ c-strings

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

  

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;

由于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;

我认为这是因为返回的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;

第二个问题:

我也不确定为什么std::cout << s1打印内容而不是C String的地址。以下代码按预期打印Integer的地址:

int dim = 42;
int* pdim = &dim;
std::cout << pdim << std::endl;

按预期打印出字符“T”:

std::cout << *s1 << std::endl;

我的假设是std :: cout会进行自动转换,但请详细说明一下。

4 个答案:

答案 0 :(得分:4)

第一个问题

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

  

c_str()获得的指针可能会失效:

     
      
  • 将对字符串的非const引用传递给任何标准库函数,或
  •   
  • 在字符串上调用非const成员函数,不包括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.

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

std::cout << s1 << std::endl; // Undefined behavior.

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

第二个问题

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

std::cout << "Hello, World.";

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

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

template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os, 
                                         const CharT* s );

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

std::ostream& operator<<(std::ostream& os, const char* s );

您可以在cppreference.com看到非成员超载功能列表。

答案 1 :(得分:3)

c_str()返回的指针在string被修改之前保证有效。当它被修改时(通过调用非const成员函数),string可能必须在内部分配一个新的内存缓冲区,这会使指针无效。何时以及如何确切地发生这种情况。

对于第二个问题:operator <<存在不同的重载,string的重载会打印其内容。

答案 2 :(得分:2)

第一个问题:

c_str文档说明了以下内容,这比本书所说的要清楚得多,因为它说明了它可能会失效的时间:

  

通过进一步调用其他指针,可能会使返回的指针无效   修改对象的成员函数。

我做了一个快速测试:当您更新字符串时,地址s1指向无效(即strTest.c_str()返回不同的值)。

从文档中可以清楚地看出哪些成员函数使指针无效,但是如果要使用c_str指针,则可以安全地说不应该对原始字符串变量进行操作。 / p>

第二个问题:

cout从空字符推断出字符数组的结尾。当你测试它是一个整数指针时,这不起作用。

答案 3 :(得分:0)

第二个问题

重载

std::ostream::operator<<以接受整数,const char*和其他几种基本数据类型。实际上每个函数的功能略有不同,并且您打印的任何不是原始类型的函数都必须具有已定义的转换为。