使用 strcat 拼接前必须确保目标缓冲区空间足够,否则会导致栈溢出或未定义行为;推荐用 snprintf 或 std::string 替代以提升安全性。

用 strcat 拼接字符数组前必须确保空间足够
strcat 不检查目标缓冲区大小,直接从 dest 的末尾(第一个 '\0')开始拷贝 src,如果 dest 没预留足够空间,就会越界写入 —— 这是典型的栈溢出或未定义行为。常见现象是程序崩溃、变量被意外覆盖、甚至看似正常但后续逻辑出错。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 声明
dest时,长度至少为strlen(dest) + strlen(src) + 1(+1 是结尾'\0') - 拼接前用
strlen确认当前已用长度,再判断剩余空间是否够用 - 避免对字面量字符串(如
"hello")调用strcat—— 它们通常存于只读段,写入会触发Segmentation fault
示例:
char buf[32] = "Hello"; // 初始化含 '\0' strcat(buf, " world"); // OK:buf 剩余空间 25 字节 > " world" 长度 7
用 snprintf 更安全地拼接并控制长度
snprintf 允许指定最大写入字节数,天然防溢出,适合拼接多个片段或带格式的字符串。它返回实际需要的字符数(不含 '\0'),可用于判断是否截断。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 始终传入缓冲区总长度(不是剩余空间),
snprintf自动留出'\0'位置 - 若返回值 ≥ 缓冲区长度,说明内容被截断,需扩容重试
- 相比
strcat,snprintf开销略高,但安全性提升显著
示例:
char buf[32]; int n = snprintf(buf, sizeof(buf), "%s%s", "Hello", " world"); // n == 12 → 成功;若 sizeof(buf) 为 10,则 n == 12,buf 中只有 "Hello worl"
C++ 中优先用 std::string 替代字符数组拼接
原生字符数组拼接本质是 C 风格操作,C++ 标准库提供 std::string 后,绝大多数场景下应直接用 + 或 +=。它自动管理内存、无溢出风险、支持移动语义,且可随时通过 c_str() 获取 C 兼容指针。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 除非对接 C API 或性能敏感的嵌入式场景,否则不要手动管理字符数组长度
-
std::string拼接后若需传给 C 函数,用str.c_str(),注意该指针在str修改或析构后失效 - 频繁拼接大量小字符串时,可预先
reserve()避免多次内存重分配
示例:
std::string s = "Hello"; s += " world"; // 安全、简洁 const char* cstr = s.c_str(); // 仅在 s 生命周期内有效
遇到 buffer overflow 报错时先查三点
编译器(如 GCC/Clang)开启 -D_FORTIFY_SOURCE=2 或 ASan 时,常在运行时报 buffer overflow。这不是语法错误,而是运行时检测到非法写入。
排查重点:
-
dest是否为栈上固定数组?长度是否硬编码且小于拼接后总长? - 是否误把
sizeof(arr)当作可用空间?对指针参数调用sizeof会得到指针大小(通常是 8),而非数组长度 - 是否在循环中反复
strcat却没重置起始位置或检查剩余空间?
最容易被忽略的是:char arr[10] = "abc" 实际只占 4 字节(含 '\0'),但剩余空间只有 6 字节,不是 10 字节 —— 每次拼接都得拿当前 strlen(arr) 加新字符串长度来算,不能凭初始声明长度估算


















