C strlen 与 sizeof 的区别
更新时间:2026-08-26。本文是
languages/c/主题入门层第 28 篇。strlen和sizeof看着都是"量一量",结果却经常不一样。这是 C 新手最经典的混淆之一,也是很多"字符串为什么出问题"的根源。
本文要回答的问题
strlen("hi")和sizeof("hi")各是多少?- 为什么数组传进函数后
sizeof就"失灵"了? - 什么时候该用哪个?
一、本质区别:数长度 vs 量大小
c
#include <stdio.h>
#include <string.h>
int main(void) {
char s[] = "hello";
printf("strlen = %zu\n", strlen(s)); // 5:有效字符数
printf("sizeof = %zu\n", sizeof(s)); // 6:整个数组大小(含 \0)
return 0;
}strlen | sizeof | |
|---|---|---|
| 含义 | 字符串长度 | 对象大小 |
| 运行时 | 运行时扫描,数到 \0 为止 | 编译期计算,不执行 |
| 单位 | 字符数 | 字节数 |
| 对象 | 必须是字符串(有 \0) | 任何东西 |
"hello" 的结果 | 5 | 6 |
关键认知:strlen 是函数,运行时逐字节找 \0;sizeof 是运算符,编译期就定好了。所以 sizeof 不需要变量"有值",strlen 要求字符串"有 \0"。
二、\0 的陷阱:没结尾会怎样
c
char bad[5] = {'h', 'e', 'l', 'l', 'o'}; // 没有 \0!
printf("%zu\n", strlen(bad)); // 灾难:越过数组边界找 \0bad 里没有 \0,strlen 会继续往后扫内存,直到撞见一个 0 字节——结果是垃圾长度,可能还读越界。这正是字符数组与字符串强调"必须留 \0"的原因。
三、数组传参:sizeof 的失效时刻
c
void print_size(char arr[]) {
printf("%zu\n", sizeof(arr)); // 8!不是数组大小,是指针大小
}
int main(void) {
char s[] = "hello";
printf("%zu\n", sizeof(s)); // 6:数组还在作用域内,正常
print_size(s); // 8:参数退化成指针
return 0;
}数组作为函数参数时退化成指针,sizeof(arr) 拿到的是指针大小(64 位下 8 字节)。所以:
数组传函数后,
strlen还能用(内容还在)、sizeof算不出数组大小了。
这就是为什么 C 函数签名里到处是"数组 + 长度"两个参数:
c
void process(char arr[], size_t n) { ... } // n 靠调用者传四、应用场景对照
| 场景 | 用谁 |
|---|---|
| 算字符串有几个字符 | strlen |
| 算数组能装多少字节(缓冲区大小) | sizeof |
给 snprintf/fgets 传缓冲区上限 | sizeof(永远是它) |
| 遍历字符串字符 | 先 strlen 存变量(别在循环条件里每次重算) |
| 比较两个字符串 | 都不是,用 strcmp |
性能小知识:strlen 在循环条件里反复调用很浪费:
c
for (size_t i = 0; i < strlen(s); i++) // 每轮都重扫一遍!O(n²)c
size_t len = strlen(s); // 存起来,O(n)
for (size_t i = 0; i < len; i++)现代编译器(-O2)会优化掉"无副作用的重复调用",但别依赖——显式存变量更稳。
五、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 用 sizeof 当字符串长度 | 多算一个 \0 | 用 strlen |
| 数组传参后 sizeof | 拿到指针大小 8 | 另传长度 |
无 \0 的数组跑 strlen | 越界扫描 | 保证 \0 结尾 |
| 循环条件里写 strlen | 慢(理论上 O(n²)) | 存变量 |
| 拿 sizeof 结果当长度去 memcpy | 多复制或越界 | 明确语义 |
六、与本站主线衔接
strlen的实现与性能(glibc 用 SIMD 加速),见高手层字符串函数实现与性能;- 指针衰减的底层机制,见指针与数组;
- 缓冲区大小计算的安全含义,见缓冲区溢出与安全。
一句话总结
strlen 运行时数到 \0(长度),sizeof 编译期量对象(大小),"hello" 分别是 5 和 6;数组传参后 sizeof 退化成指针大小,所以缓冲区上限用 sizeof、字符个数用 strlen——两个词,两个世界。