c_str()返回const char*只读指针,不可修改或释放;需可写数组时应拷贝到自有缓冲区,注意目标大小;优先用string_view替代c_str()以避免生命周期和安全性问题。

string转char数组必须用c_str(),但不能直接赋值给char*
很多人写 char* p = s.c_str() 然后就去改 p[0],结果程序崩溃或行为未定义。因为 c_str() 返回的是 const char*,指向 string 内部只读缓冲区;强行转成非 const 指针再写入,属于未定义行为。
真正需要可修改的 char 数组时,得自己分配空间并拷贝:
-
c_str()只提供只读视图,生命周期绑定原string对象 - 若原
string被移动、销毁或重新赋值,c_str()返回的指针立即失效 - 要写入内容,必须用
strcpy或std::copy拷到你自己的char[]或std::vector<char></char>中
示例:
std::string s = "hello"; char buf[256]; strcpy(buf, s.c_str()); // ✅ 安全:拷贝到自有缓冲区 buf[0] = 'H'; // ✅ 可修改
strcpy目标缓冲区必须足够大,否则溢出风险极高
strcpy 不检查目标空间大小,只按源字符串的 \0 结束。如果目标 char[] 太小,就会写越界 —— 这是 C 风格字符串最常见 crash 根源之一。
- 目标数组长度至少为
s.length() + 1(+1 是给结尾\0) - 用
strncpy也不安全:它不保证目标以\0结尾,除非源比目标短 - 更稳妥的做法是用
snprintf(buf, sizeof(buf), "%s", s.c_str()),自动截断并补\0
错误示范:
char small[3]; strcpy(small, "hello"); // ❌ 越界:"hello" 需要 6 字节
不要对c_str()返回值做free/delete,也不要用它初始化std::string_view以外的非常量指针
c_str() 返回的指针不是 malloc 出来的,也不是 new 出来的,它只是 string 内部数据的“快照”。调用 free() 或 delete[] 会直接导致段错误。
- 绝不能写
delete[] s.c_str()或free(const_cast<char>(s.c_str()))</char> - 若需长期持有,应复制内容(如用
std::vector<char>(s.begin(), s.end())</char>) -
std::string_view是少数能安全接受c_str()的类型,因为它明确承诺只读且不拥有内存
典型误用:
const char* p = s.c_str(); // ... 后续某处: delete[] p; // ❌ UB!
现代C++中优先用string_view替代c_str() + char*场景
如果你只是要把字符串传给一个只读函数(比如日志、查找、解析),根本不需要转成 char*。用 std::string_view 更轻量、零拷贝、类型安全。
-
string_view构造开销为 O(1),且能隐式转换自std::string和字面量 - 避免了
c_str()生命周期管理问题:只要原string活着,string_view就安全 - 很多新 API(如
std::format、std::regex)已原生支持string_view
对比:
// 老写法(多此一举)
void log(const char* msg) { /* ... */ }
log(s.c_str());
<p>// 新写法(推荐)
void log(std::string_view msg) { /<em> ... </em>/ }
log(s); // ✅ 自动转换,无拷贝,无生命周期焦虑</p>
最常被忽略的一点:c_str() 的有效性完全依赖原 string 对象的生存期和稳定性。哪怕只是在另一线程里对同一个 string 做了 push_back,当前线程里正在用的 c_str() 指针也可能已失效。别把它当“稳定地址”来用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










