结论:std::string转const char优先用c_str(),char转std::string需防nullptr和非空终止;非C字符串必须显式传长度构造。
直接说结论: std::string 转 const char* 用 c_str() 或 data();char*(C 风格字符串)转 std::string 直接构造即可。但「能用」不等于「安全」,关键在生命周期和 const 正确性。
c_str() 返回以 \0 结尾的 C 风格字符串指针,保证兼容所有 C 函数;data() 在 C++11 中行为同 c_str(),但 C++17 起不再保证末尾有 \0(除非显式调用 c_str() 或字符串含空字符)。实际项目中,只要传给 C API(如 fopen、printf、sqlite3_exec),一律用 c_str()。
注意:c_str() 返回的指针仅在原 std::string 对象未被修改/析构前有效:
const char*)string 被 move 后继续用其 c_str()
strdup(s.c_str())(记得 free)或构造新 std::string
最简方式是直接构造:std::string s(p)(p 为 const char* 或 char*)。但隐含风险:
p 为 nullptr → 构造抛 std::logic_error(GCC/Clang 下常见,MSVC 可能崩溃)p 指向未以 \0 结尾的内存 → 行为未定义(读越界)p 指向栈上临时缓冲(如 char buf[32]; sprintf(buf, "%d", x); std::string s(buf);)→ 安全,只要 buf 生命周期覆盖 s 构造std::string s(p, len),避免依赖 \0
当你的 当你的 char 数据不是 C 字符串(例如网络包、加密结果、含 的中间数据),绝不能用无参构造函数。必须显式传入长度:char 数据不是 C 字符串(例如网络包、加密结果、含 \0 的中间数据),绝不能用无参构造函数。必须显式传入长度:
char raw_data[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x77, 0x6f, 0x72, 0x6c, 0x64}; // "Hello\0world"
std::string s(raw_data, sizeof(raw_data)); // 包含 \0 和后续字节
这样得到的 std::string 是完整 11 字节,s.length() == 11,且可安全遍历每个字节。若误用 std::string s(raw_data),则只取到第一个 \0 前的 "Hello"(5 字节)。
标准库已足够,无需封装通用转换函数。但以下场景值得加一层检查:
char*(如 C API 回调参数)→ 先判 nullptr 再构造std::string 交给 C 函数且该函数会修改内容 → 不能用 c_str()(它是 const),应另分配可写内存:std::vector buf(s.begin(), s.end()); buf.push_back('\0'); some_c_func(buf.data());
c_str() 不安全,必须深拷贝内容(如用 std::string 值传递,或 std::shared_ptr<:string>)最易被忽略的一点:std::string 的小字符

c_str() 指向内部缓冲,看似“免费”,但一旦字符串变长触发堆分配,指针就变了——别对指针值做任何假设。