C 字符串函数
更新时间:2026-08-26。本文是
languages/c/主题入门层第 29 篇。字符串的增删查改,标准库都备好了函数(<string.h>)。这一篇把它们分组讲清:哪组做什么、返回值代表什么、以及为什么"安全变体"几乎总是更好的选择。
本文要回答的问题
strcpy和strncpy差在哪?什么时候用哪个?strcmp的返回值是什么语义?能当布尔用吗?- 怎么在字符串里找字符/子串?
一、复制:strcpy 与 strncpy
c
char dst[16];
strcpy(dst, "hello"); // 复制,目标必须够大!
strncpy(dst, "hello", sizeof(dst) - 1); // 最多写 15 字节,留 \0
dst[15] = '\0'; // strncpy 不保证结尾 \0,自己补| 函数 | 行为 | 风险 |
|---|---|---|
strcpy(dst, src) | 无条件复制到 \0 | 目标小就溢出 |
strncpy(dst, src, n) | 最多写 n 字节 | n 用完不补 \0(巨坑) |
snprintf(dst, n, "%s", src) | 最多 n-1 字节 + \0 | 推荐:最稳 |
结论:strncpy 并非"安全版"——它会在源字符串太长时丢 \0,产生一个"没有终点"的字符串。工程上很多人直接用 snprintf 或手写循环。至少记住:用 strncpy 必须手动保证结尾。
二、拼接:strcat 与 strncat
c
char buf[32] = "Hello, ";
strcat(buf, "world"); // buf 变 "Hello, world"(目标要够大)
strncat(buf, "!!!", sizeof(buf) - strlen(buf) - 1); // 限长拼接strcat 从目标串的 \0 开始追加,目标必须留有足够剩余空间——strlen(buf) + strlen(src) + 1 ≤ 容量。strncat 的 n 是"最多追加几个字符",注意它会补 \0(和 strncpy 不同)。
三、比较:strcmp 与 strncmp
c
if (strcmp(a, b) == 0) { // 相等判断
printf("相同\n");
}
if (strcmp(a, b) < 0) { // 按字典序,a 在 b 前
printf("a 小\n");
}strcmp 返回的是"差值符号",不是布尔:
| 返回值 | 含义 |
|---|---|
== 0 | 相等 |
< 0 | a 字典序小于 b |
> 0 | a 大于 b |
所以 strcmp(a, b) 本身不能当"是否相等"用(非 0 可能是"a 大于 b")——必须显式比较 == 0。这是新手常错的一行。
四、查找:strchr 与 strstr
c
char *p = strchr("hello world", 'o'); // 找字符,返回指向它的指针
if (p != NULL) {
printf("%ld\n", p - "hello world"); // 4:位置(指针减法)
}
char *q = strstr("hello world", "world"); // 找子串
if (q != NULL) {
printf("找到:%s\n", q); // "world":从找到处到结尾
}| 函数 | 功能 | 找不到时返回 |
|---|---|---|
strchr(s, c) | 找字符 | NULL |
strrchr(s, c) | 从右找字符 | NULL |
strstr(s, sub) | 找子串 | NULL |
strspn/strcspn | 扫描字符集合 | 见高手层 |
找到后拿位置:指针相减 p - s 得到下标(同数组内的指针才合法)。
五、安全变体怎么选(决策表)
| 需求 | 推荐 | 理由 |
|---|---|---|
| 复制到缓冲区 | snprintf(dst, sizeof(dst), "%s", src) | 自动截断 + 补 \0 |
| 限长拼接 | strncat | 会补 \0 |
| 比较 | strcmp/strncmp | 无安全问题 |
| 找字符/子串 | strchr/strstr | 无安全问题 |
| 复制(且能保证长度) | strcpy | 明确够大时更快 |
总原则:凡是"往缓冲区写",优先带长度限制的版本,宁可截断不可溢出。
六、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| strcpy 目标太小 | 缓冲区溢出 | 用 snprintf |
strncpy 后没补 \0 | 字符串没终点 | 手动 dst[n-1] = '\0' |
strcmp 结果当布尔 | 判断反了 | == 0 判断相等 |
| strcat 剩余空间不够 | 溢出 | 先算剩余容量 |
| 字符串太长被截断 | 数据丢失(但安全) | 检查返回值/剩余 |
七、与本站主线衔接
- glibc 字符串函数的实现(SIMD 优化 strlen/strcmp),见高手层字符串函数实现与性能;
- 缓冲区溢出的完整攻防,见缓冲区溢出与安全;
- 自己实现字符串函数(练习),见文本文件统计工具。
一句话总结
strcpy/strcat 不安全(目标够大才用)、strncpy 会丢 \0(要手动补)、snprintf 最稳;strcmp 返回差值符号要 == 0 判相等、strchr/strstr 找不到返回 NULL——六函数三组记忆,字符串增删查改全覆盖。