c_str() 返回以\0结尾的只读C字符串指针,data()在C++17前不保证结尾有\0;二者均不可写,需显式分配内存并确保足够空间(≥长度+1)后复制,必要时手动补\0。
直接

string.c_str() 获取 C 风格字符串指针是最常见做法,但它返回的是 const char*,不能用于写入;若你确实需要可修改的 char 数组(比如传给老式 C API 做输入输出),必须自己分配内存并复制内容。string.data() 在 C++11 中也返回 const char*(C++17 起才保证结尾有 '\0'),所以它和 c_str() 此时行为一致,**不能替代 strcpy 目标缓冲区**。
常见错误是这样写:
std::string s = "hello"; char* buf = const_cast(s.c_str()); // 危险!底层内存不可写 strcpy(buf, "world"); // 未定义行为
new char[n+1] 或栈数组(如 char buf[256])显式分配空间s.length() + 1,否则复制会越界'\0'(如果用 strncpy 且源长度 ≥ 缓冲区长度)strcpy 本身不检查目标空间大小,依赖程序员确保目标足够大。从 std::string 复制时,必须先确认容量再调用:
std::string s = "test";
char buf[32];
if (s.length() < sizeof(buf)) {
strcpy(buf, s.c_str());
} else {
// 处理截断或报错
}string 直接调用 strcpy(buf, s.c_str())
sizeof(buf) 只对数组名有效,对指针(如 char* buf = new char[32])无效delete[] buf,避免泄漏strncpy 看似安全,实则容易埋坑:它不保证目标以 ' 结尾,也不自动补满整个缓冲区,还可能掩盖越界问题。strncpy 看似安全,实则容易埋坑:它不保证目标以 '\0' 结尾,也不自动补满整个缓冲区,还可能掩盖越界问题。
std::string s = "hello world"; char buf[5]; strncpy(buf, s.c_str(), sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; // 必须手动补 '\0'
sizeof(buf) - 1,留一位给 '\0'
s.length() >= sizeof(buf),strncpy 不会写 '\0' —— 必须手动补s.length() ,strncpy 会用 '\0' 填满剩余位置,浪费性能
std::copy_n + 手动置 '\0',或直接用 std::vector
绕过 C 风格函数,用标准库能避开大多数缓冲区问题:
s.c_str(),无需复制std::vector v(s.begin(), s.end()); v.push_back('\0');
std::array buf{}; std::copy_n(s.begin(), std::min(s.size(), buf.size()-1), buf.begin()); buf.back() = '\0';
char*?优先封装成 RAII 类管理生命周期,而不是裸指针 + strcpy
真正麻烦的从来不是“怎么转”,而是“谁负责释放”“是否会被改写”“下次读取前有没有被覆盖”——这些逻辑比一行 strcpy 重得多。