C 语言的字符串处理是每个 C 开发者必须掌握的基本功。不同于高级语言,C 字符串本质上是字符数组,需要手动管理内存。本文详解常用字符串函数的原理、常见陷阱与安全用法。
一、字符串基础与存储模型
C 语言中没有专门的"字符串类型",字符串以字符数组形式存储,以空字符 \0 结尾:
char s[6] = {'h', 'e', 'l', 'l', 'o', '\0'}; char s2[] = "hello"; /* 简化写法,自动添加 \0 */
字符串长度不包括结尾的 \0,strlen("hello") 返回 5,但存储需要 6 字节。
二、常用字符串函数详解
1. 复制函数
/* strcpy - 不安全,有缓冲区溢出风险 */ char dest[20]; strcpy(dest, src); /* 如果 src > 20 会崩溃 */ /* strncpy - 指定长度复制,但可能不添加 \0 */ strncpy(dest, src, 19); dest[19] = '\0'; /* 必须手动添加结尾符 */ /* snprintf - 安全版本,推荐使用 */ snprintf(dest, sizeof(dest), "%s", src);
2. 连接函数
/* strcat - 连接两个字符串 */ char buf[100] = "Hello"; strcat(buf, " World"); /* buf 变为 "Hello World" */ /* strncat - 安全版本,自动确保 \0 */ strncat(buf, src, 99 - strlen(buf));
3. 比较函数
/* strcmp - 按字典序比较,返回值:<0/0/>0 */ if (strcmp(s1, s2) == 0) { printf("相同\n"); } /* strncmp - 比较前 n 个字符 */ strncmp(s1, s2, 3); /* 只比较前 3 个字符 */ /* strcasecmp - 不区分大小写比较(Linux 特有) */ strcasecmp("ABC", "abc"); /* 返回 0 */
4. 搜索函数
/* strchr - 查找字符首次出现位置 */ char *p = strchr("hello", 'l'); /* 指向第二个 'l' */ /* strrchr - 查找字符最后一次出现 */ char *p2 = strrchr("hello", 'l'); /* 指向第三个 'l' */ /* strstr - 子串查找 */ char *p3 = strstr("hello world", "world");
三、字符串转换函数
/* 字符串转数值 */ int i = atoi("123"); /* 不推荐,无错误检测 */ long l = strtol(s, &end, 10); /* 推荐,可检测错误 */ double d = strtod(s, &end); /* 数值转字符串 */ char buf[32]; snprintf(buf, sizeof(buf), "%d", 123);
四、常见安全问题
缓冲区溢出是 C 语言中最常见的安全漏洞之一。攻击者通过溢出覆盖返回地址,可以执行任意代码。
- 始终使用有界限的函数:用
snprintf替代sprintf,用strncpy替代strcpy - 检查返回值:函数返回 NULL 时要妥善处理
- 预留空间:确保目标缓冲区足够大,考虑最坏情况
- 使用静态分析工具:如 Coverity、cppcheck 可检测潜在问题
五、字符串操作技巧
/* 去除字符串首尾空白 */ char *trim(char *s) { while (isspace(*s)) s++; /* 跳过开头空白 */ char *end = s + strlen(s) - 1; while (end > s && isspace(*end)) end--; *(end + 1) = '\0'; return s; } /* 字符串分割 */ char s[] = "a,b,c,d"; char *token; char *saveptr; for (token = strtok_r(s, ",", &saveptr); token; token = strtok_r(NULL, ",", &saveptr)) { printf("%s\n", token); /* 线程安全版本 */ }
六、总结
- 牢记
\0是字符串的一部分,计算长度时要考虑 - 优先使用有边界检查的函数(snprintf、strncpy、strncat)
- 处理用户输入时务必验证长度与内容
- 使用
strtol、strtod等带错误检测的转换函数
进阶阅读:《C 陷阱与缺陷》《Expert C Programming》中有更多字符串处理的最佳实践。