C++ 怎么实现字符串拷贝 C++ strcpy与strncpy安全版本【C风格】

10次阅读

c++中不应直接使用strcpy和strncpy,因二者均不检查缓冲区大小且strncpy不保证NULL终止,易致缓冲区溢出或未定义行为;应优先使用std::String,必要时用snprintf封装安全函数。

C++ 怎么实现字符串拷贝 C++ strcpy与strncpy安全版本【C风格】

为什么不能直接用 strcpystrncpy

这两个函数在 C++ 中仍可调用(来自 ),但它们不检查目标缓冲区大小,也不保证结果字符串'' 结尾——strcpy 可能越界写入,strncpy 在源串长度 ≥ 目标大小时不会补 '',后续用 strlenprintf 就会读越界。常见错误现象是程序崩溃、输出乱码或破坏。

典型误用:

char dst[5]; strcpy(dst, "hello"); // 写入 6 字节(含 ''),dst 只有 5 字节 → 缓冲区溢出
char dst[5]; strncpy(dst, "hello", sizeof(dst)); // 拷贝前 5 字节 "hello",不加 '' → dst 不是合法 C 字符串

strlcpy 是更安全的替代,但不是标准 C/C++ 函数

strlcpy 在 BSD 系统和部分 linux 发行版(如 glibc 2.39+)中可用,它明确要求目标缓冲区大小,并始终以 '' 结尾(除非 size == 0)。但它**不是 ISO C++ 标准函数**,跨平台项目中需谨慎:

  • windows 默认不提供,需自行实现或引入兼容层
  • 旧版 glibc(如 centos 7)不支持
  • 参数顺序是 strlcpy(dst, src, size),与 strncpy 一致,但语义更清晰

简易自实现(仅作示意,生产环境建议用 std::string 或已验证的库):

立即学习C++免费学习笔记(深入)”;

size_t strlcpy(char* dst, const char* src, size_t size) {     if (size == 0) return strlen(src);     size_t len = strlen(src);     size_t copy_len = (len < size - 1) ? len : size - 1;     memcpy(dst, src, copy_len);     dst[copy_len] = '';     return len; }

真正推荐的 C 风格安全做法:用 snprintf

snprintf 是 ISO C99 起就标准化的函数,C++11 及以后可直接用(包含 ),它天然带长度限制且保证末尾 ''

  • 总是返回「若缓冲区足够大时本应写入的字符数」,可用于判断是否截断
  • 即使 size == 0 也安全(只计算长度,不写内存)
  • 支持格式化,但单纯拷贝字符串时用 "%s" 即可

示例:

char dst[10]; int ret = snprintf(dst, sizeof(dst), "%s", "hello world"); // ret == 11 → 实际写入了 "hello wor" + ''(共 10 字节),说明被截断 if (ret >= (int)sizeof(dst)) {     // 拷贝不完整,需处理 }

C++ 项目里其实不该用这些 C 风格函数

除非你明确在写系统层、嵌入式驱动或与 C ABI 交互的接口,否则在普通 C++ 代码中坚持用 strcpy 类函数,等于主动放弃类型安全和 RaiI。真正该做的:

  • std::string 存储和传递文本,拷贝就是 std::string s2 = s1;,无缓冲区管理负担
  • 需要 C 兼容接口时,用 s.c_str() 获取只读指针;必须写入 C 缓冲区时,先确认大小,再用 snprintfstd::copy_n + 手动置 ''
  • 若必须用 C 风格字符串操作,至少封装一层检查:比如写个 safe_strcpy(dst, sizeof(dst), src) 并在 debug 版本做断言

最常被忽略的一点:很多开发者以为「用了 strncpy 就安全了」,却忘了它不自动补 '',而这个缺失的空字符,在后续任意一次 strcmpstrcat 中都可能引发未定义行为。

text=ZqhQzanResources