c_str() 返回以\0结尾的只读C字符串指针,data()在C++17前不保证结尾有\0;二者均不可写,需显式分配内存并确保足够空间(≥长度+1)后复制,必要时手动补\0。
string.c_str() 和 string.data() 的区别与选择
直接用
获取 C 风格字符串指针是最常见做法,但它返回的是
,不能用于写入;若你确实需要可修改的
数组(比如传给老式 C API 做输入输出),必须自己分配内存并复制内容。
在 C++11 中也返回
(C++17 起才保证结尾有
),所以它和
此时行为一致,**不能替代 strcpy 目标缓冲区**。
常见错误是这样写:
要写入,必须用
或栈数组(如
)显式分配空间
目标缓冲区大小必须 ≥
,否则复制会越界
复制后记得手动加
(如果用
且源长度 ≥ 缓冲区长度)
strcpy 复制 string 到 char 数组的正确步骤
本身不检查目标空间大小,依赖程序员确保目标足够大。从
复制时,必须先确认容量再调用:
永远不要对未知长度的
直接调用
只对数组名有效,对指针(如
)无效
若目标是堆分配内存,记得
,避免泄漏
strncpy 更安全?但要注意三个陷阱
看似安全,实则容易埋坑:它不保证目标以
结尾,也不自动补满整个缓冲区,还可能掩盖越界问题。
参数三(最大拷贝数)应为
,留一位给
如果
,
不会写
—— 必须手动补
如果
会用
填满剩余位置,浪费性能
现代 C++ 更推荐
+ 手动置
,或直接用
更现代、更少出错的替代方案
绕过 C 风格函数,用
标准库
能避开大多数缓冲区问题:
C函数速查手册(CHM版)
C函数速查手册(CHM版)
下载
立即学习
“
C++免费学习笔记(深入)
”;
需要临时 C 字符串只读?直接传
,无需复制
需要可修改副本且长度已知?用
需要固定大小栈缓冲区?用
对接旧 API 必须传
?优先封装成 RAII 类管理生命周期,而不是裸指针 +
真正麻烦的从来不是“怎么转”,而是“谁负责释放”“是否会被改写”“下次读取前有没有被覆盖”——这些逻辑比一行
重得多。
string.c_str()const char*charstring.data()const char*'\0'c_str()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'strncpystrcpystd::stringstd::string s = "test";
char buf[32];
if (s.length() < sizeof(buf)) {
strcpy(buf, s.c_str());
} else {
// 处理截断或报错
}stringstrcpy(buf, s.c_str())sizeof(buf)char* buf = new char[32]delete[] bufstrncpy'\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::vectors.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*strcpystrcpy