C++ 常用字符串函数详解:cstring.h 核心 API 与注意事项
C++ 中的 cstring(兼容 C 语言 string.h)提供了大量处理字符数组的标准函数。掌握这些函数是进行底层数据处理的基础,但也伴随着较高的安全隐患。本文梳理了最常用的字符串长度、拼接、复制和比较函数,特别是针对 strcpy 等函数的缓冲区溢出风险给出具体解决方案,并深度解析了 memset 在不同类型数组初始化中的特殊表现。
准备工作与头文件引入
cstring 库是 C 语言遗留的标准库在 C++ 中的存在形式,主要用于操作原生字符数组(char*)。在使用前需包含对应头文件:
#include <cstring>
#include <iostream>
using namespace std;
strlen:获取真实字符串长度
由于 C++ 编译器依赖终止符 \0 来识别字符串结束位置,因此字符数组的实际容量往往大于其内部存储的有效字符串长度。strlen 函数能精准返回不包含 \0 的字符个数。
char name[100] = "hello world";
cout << strlen(name) << endl; // 输出: 11
即使分配了 char name[100],只要内容是 "hello world",其长度依然只计算为 11。
字符串拼接函数:strcat 与 strncat
第 1 步:理解 strcat 拼接机制
strcat(char *dest, const char *src) 会将 src 追加到 dest 的末尾,并返回 dest 指针。原 dest 末尾的 \0 会被 src 的第一个字符覆盖。
char name[100] = "hello world";
char level[100] = " concat test";
// dest必须预留足够空间容纳拼接后的新字符串
char *ret = strcat(name, level);
cout << ret << endl; // 输出: hello world concat test
第 2 步:使用 strncat 限制拷贝长度
为防止越界或仅需部分拼接,推荐使用 strncat。第三个参数 n 指定从 src 最多拷贝的字符数(不含自动添加的 \0)。
char name[100] = "hello world";
char level[100] = "concat test";
// 仅拼接 level 的前4个字符
char *ret = strncat(name, level, 4);
cout << name << endl; // 输出: hello worldconc
字符串复制函数:strcpy 的安全陷阱
第 3 步:警惕缓冲区溢出
strcpy(char *dest, const char *src) 将 src 完整复制到 dest。此函数不会检查目标空间是否足够,极易引发运行时崩溃或内存损坏。
char name[10] = "";
char level[100] = "concat test";
// 编译通过,但运行时会发生栈溢出错误
strcpy(name, level);

上图展示了典型的内存访问违规报错。在实际开发中,务必确保 dest 有足够空间,或者直接使用更安全的方式(如 std::string 或手动截断)。
第 4 步:覆盖行为
如果 dest 原有内容被完全覆盖,原数据将丢失:
char name[15] = "abc";
strcpy(name, "concat test");
cout << name << endl; // abc 被清空,输出 concat test
第 5 步:使用 strncpy 增加安全性
strncpy 增加了长度控制参数 n。它最多拷贝 n 个字符;若 src 不足 n 位,剩余部分填充 \0。
char name[15] = "abc";
char level[100] = "concat test";
strncpy(name, level, 4);
cout << name << endl; // 输出: conc (注意后续可能有随机乱码,取决于未处理的内存)
提示:strncpy 并不保证结果一定以 \0 结尾(除非 src 长度小于 n),使用时需小心。
批量填充函数:memset 的深度解析
第 6 步:理解 memset 字节级操作
memset(void *str, int c, size_t n) 逐字节地设置内存。常用于清零数组或填充特定字符。
char name[15] = "abc";
memset(name, 'c', 10);
cout << name << endl; // 前10个字节变为'c'
第 7 步:整型数组初始化的误区
当对 int 数组调用 memset 时,因为一个 int 占 4 个字节,传入的值会被重复填充 4 次。例如 memset(a, 1, sizeof a) 会将每个字节填为 0x01,最终整数变为 0x01010101(十进制约 1680 万),而非 1。
对于整型数组,memset 仅推荐用于以下三种情况:
// 1. 置零 (最常用)
memset(a, 0, sizeof a);
// 2. 全 -1 (二进制补码全1)
memset(a, -1, sizeof a);
// 3. 大数值初始化 (如贪心算法初始化距离)
memset(a, 0x3f, sizeof a); // 0x3f3f3f3f ≈ 1e9
字符串比较函数:strcmp 与 strncmp
第 8 步:字典序比较
strcmp(const char *s1, const char *s2) 从左向右逐个对比 ASCII 值:
- 返回值 < 0:s1 小于 s2
- 返回值 = 0:两字符串相等
- 返回值 > 0:s1 大于 s2
cout << strcmp("abc", "abcd") << endl; // 输出负数 (如-100),说明 abc 排在 abcd 前面
第 9 步:限定长度的比较
同前文逻辑,strncmp 可额外指定最大比较字符数,适用于协议头部分析或部分匹配场景。
查找子串:strstr
strstr(char *haystack, char *needle) 在 haystack 中查找 needle 第一次出现的位置,并返回该位置的指针。若未找到则返回 NULL。
char name[15] = "search-test";
char *ret = strstr(name, "-");
cout << ret << endl; // 输出: -test (直接打印从此位置开始的后缀)

简要总结
以上关于 C++ cstring.h 常用函数的详细内容,更多关于 C++ 标准库操作与内存安全的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









