在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会进行自动转换,但请详细说明一下。
答案 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::ostream
和char 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*
和其他几种基本数据类型。实际上每个函数的功能略有不同,并且您打印的任何不是原始类型的函数都必须具有已定义的转换为。