17370845950

C++ char*和string互转 C++ C风格字符串与对象转换大全【代码】
结论:std::string转const char优先用c_str(),char转std::string需防nullptr和非空终止;非C字符串必须显式传长度构造。

直接说结论: std::stringconst char*c_str()data()char*(C 风格字符串)转 std::string 直接构造即可。但「能用」不等于「安全」,关键在生命周期和 const 正确性。

std::string → const char*:c_str() 和 data() 到底怎么选?

c_str() 返回以 \0 结尾的 C 风格字符串指针,保证兼容所有 C 函数;data() 在 C++11 中行为同 c_str(),但 C++17 起不再保证末尾有 \0(除非显式调用 c_str() 或字符串含空字符)。实际项目中,只要传给 C API(如 fopenprintfsqlite3_exec),一律用 c_str()

注意:c_str() 返回的指针仅在原 std::string 对象未被修改/析构前有效:

  • 不要保存该指针长期使用(比如存*局 const char*
  • 不要在 string 被 move 后继续用其 c_str()
  • 若需持久化,必须拷贝:用 strdup(s.c_str())(记得 free)或构造新 std::string

char* → std::string:哪些情况会出问题?

最简方式是直接构造:std::string s(p)pconst char*char*)。但隐含风险:

  • pnullptr → 构造抛 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 数组 / 字节数组怎么转 string?

当你的 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 的小字符

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