检查 std::string.c_str() 的返回值
Inspect the returning value of std::string.c_str()
在C++入门第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 字符串已经固定了结尾空字符的位置,因此当长度更改时,它会使所有内容无效。令我惊讶的是,有时即使我将字符串更改为新长度,它仍然有效:
// 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 字符串的地址。虽然下面的代码按我的预期打印整数的地址:
int dim = 42;
int* pdim = &dim;
std::cout << pdim << std::endl;
这将打印出字符"T",正如预期的那样:
std::cout << *s1 << std::endl;
我的假设是 std::cout 会进行自动转换,但请给我更多关于这一点的讲座。
第一个问题
如果不修改字符串,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.
然后使用指针访问字符串是未定义的行为。
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 上看到非成员重载函数的列表。
保证从c_str()
返回的指针在修改string
之前有效。修改它时(通过调用非 const 成员函数(,string
可能必须在内部分配新的内存缓冲区,从而使指针无效。没有具体说明何时以及如何发生这种情况。
对于第二个问题:operator <<
有不同的重载,string
打印其内容。
第一个问题:
c_str文档指出以下内容,这比书中所说的更清楚一些,因为它说明了何时可能无效:
返回的指针可能会因进一步调用其他指针而失效 修改对象的成员函数。
我做了一个快速测试:当您更新地址 s1 指向的字符串时,该字符串将失效(即strTest.c_str()
返回不同的值(。
从文档中不太清楚哪些成员函数使指针无效,但可以肯定地说,如果要使用c_str
指针,则不应对原始字符串变量进行操作。
第二个问题:
cout
从空字符推断字符数组的结尾。当它是您测试过的整数指针时,这不起作用。
第二个问题
std::ostream::operator<<
被重载以接收整数、const char*
和其他几种基本数据类型。实际上,它们中的每一个都有一个略有不同的功能,并且您打印的任何非基元类型的内容都必须具有定义的转换为原始类型的原始类型。
- 从python中调用C++函数并获取返回值
- 为什么模板类中的对象不能返回值
- 返回值优化:显式移动还是隐式
- lock_guard是否保护返回值
- 调用CreateProcess()并获取字符串的返回值
- 如何使 windows 命令提示符在C++可执行文件上显示返回值?
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 查找 GCD:并非所有控制路径都返回值
- 在 Arduino 上使用 sscanf 会导致与 const char * 不匹配,并且返回值始终相同,尽管输入值不同
- 将返回值存储在函数指针数组的指针中是如何工作的?
- 如何从 std::thread 返回值
- 将返回值从 exe 传递到 bat,并将其传递给 C# 中的进程
- 方法错误"not all control paths return a value"和方法不返回值
- 如何读取 C++ SAFEARRAY**,该 SAFEARRAY** 是 COM 互操作的结果,其中 C# 返回值为
- 对fread的返回值感到困惑
- 程序不向函数返回值
- 如何在另一个函数中使用返回值作为参数?
- 如何使用 uint64_t 键类型从 std::map<int, std::string> 返回值?
- 使用 std::p air 进行返回值优化
- C++输出参数与返回值