字符串字面量 "hello" 存在静态区,类型是 char[6]——5 个字符 + 隐式结尾 '\0'。一切 str 函数都靠找 '\0' 判断结束,所以 '\0' 丢了就一路读到天边:
size_t my_strlen(const char *s) /* strlen 的典型实现思路 */
{
const char *start = s;
while (*s != '\0')
s++;
return (size_t)(s - start); /* 指针相减 = 元素个数 */
}
/* 返回类型 size_t:无符号!strlen(a) - strlen(b) 结果永不为负 */| 函数 | 签名要点 | 行为 / 陷阱 |
|---|---|---|
| strcpy(dst, src) | 返回 dst | 连 '\0' 一起拷;不检查 dst 空间,src 过长即溢出 |
| strncpy(dst, src, n) | 最多拷 n 字节 | src 短则补 0 凑满 n;src 长则不写 '\0'——必须手工补 |
| strcat(dst, src) | 返回 dst | 把 src 接到 dst 尾部;dst 空间不足即溢出 |
| strncat(dst, src, n) | 最多追加 n 字符 | 好消息:它总会补 '\0',比 strncpy 规矩 |
| strcmp(a, b) | 按字典序逐字符比 | 返回 <0 / 0 / >0;判断相等必须 == 0,strcmp 返回的不是布尔 |
| strncmp(a, b, n) | 最多比 n 字符 | 前缀比较用 |
char buf[16];
strncpy(buf, src, sizeof buf - 1); /* 留 1 字节给 '\0' */
buf[sizeof buf - 1] = '\0'; /* 手工保险:strncpy 可能不补 */
if (strcmp(cmd, "quit") == 0) /* 正确的相等判断 */
quit();| 函数 | 找什么 | 返回 |
|---|---|---|
| strchr(s, c) | 单个字符(含 '\0') | 首次出现处的指针,找不到 NULL |
| strrchr(s, c) | 单个字符,从右找 | 最后一次出现处 |
| strstr(s, sub) | 子串 | 首次出现处,找不到 NULL |
| strpbrk(s, set) | set 中任意一个字符 | 首个命中处 |
| strspn / strcspn(s, set) | 前缀连续匹配/不匹配 set | 长度(size_t) |
| strtok(s, delim) | 按分隔符切 token | 逐次调用返回各 token,完了 NULL |
/* strtok 的状态机用法:第一次传串,之后传 NULL */
char line[] = "a,b,,c";
for (char *t = strtok(line, ","); t; t = strtok(NULL, ","))
printf("[%s]\n", t); /* [a] [b] [c] —— 空字段被跳过 */ctype.h:isalpha / isdigit / isspace / isupper / islower / iscntrl...,转换 tolower / toupper——非字母原样返回,参数必须是 unsigned char 值或 EOF(传负的 char 值是未定义行为)。
mem 家族:不认 '\0'、按字节数干活,因此能处理任意二进制数据:
memcpy(dst, src, n); /* 快速拷贝 n 字节——两块内存不得重叠! */ memmove(dst, src, n); /* 允许重叠:先当 src 整体读出再写,慢一点但安全 */ memset(buf, 0, n); /* 清零 n 字节:结构体/缓冲区初始化标配 */ memcmp(a, b, n); /* 按字节比较,返回 <0/0/>0 */