C 语言 strlen 与 sizeof 深度解析:核心差异、陷阱避坑与最佳实践
strlen():运行时计算字符串长度
strlen() 定义于 <string.h>,返回以空字符 '\0' 结尾的字符串中字符数(不含终止符)。它从指针开始逐字节扫描,直到遇到 '\0',因此时间复杂度为 O(n)。
size_t strlen(const char *str);
sizeof:编译期/运行期获取对象占用字节数
sizeof 是一元运算符(非函数),用于获取类型或表达式的存储大小(字节数)。对静态类型在编译期求值;对变长数组(VLA)在运行期求值。不求值表达式(不执行副作用)。
sizeof(type) // 类型大小
sizeof expression // 表达式结果类型大小,不计算表达式
sizeof variable // 变量占用字节数
核心差异对比表
| 特性 | strlen() | sizeof |
|---|---|---|
| 头文件 | string.h | 内置运算符,无需头文件 |
| 作用对象 | 仅以 '\0' 结尾的字符数组/指针 | 任意类型、变量、表达式 |
| 计算内容 | 字符串逻辑长度(不含 '\0') | 对象占用内存字节数(含 '\0'、填充字节) |
| 求值时机 | 运行时(遍历字符串) | 编译期(VLA 除外) |
| 返回类型 | size_t | size_t |
| 空指针行为 | 未定义行为(崩溃) | 不适用(作用于类型/变量) |
| 数组退化 | 参数退化为指针,仅见首元素地址 | 作用于数组对象本身,得完整大小 |
语法与示例
strlen() 示例
#include <stdio.h>
#include <string.h>
int main(void) {
char str[] = "January";
printf("Length: %zu\n", strlen(str)); // 7
return 0;
}
sizeof 示例
1) sizeof(类型)
printf("%zu\n", sizeof(double)); // 8(64 位系统)
2) sizeof(变量)
char c = 'S';
double d = 4.65;
printf("%zu %zu\n", sizeof(c), sizeof(d)); // 1 8
3) sizeof(表达式) —— 不求值
int a = 5;
printf("%zu\n", sizeof(a++)); // 4(int 大小),a 不变仍为 5
经典陷阱:数组退化导致的 sizeof 误用
void func(char arr[]) { // 参数退化为 char*
printf("%zu\n", sizeof(arr)); // 8(指针大小),非数组长度!
}
int main() {
char str[] = "Hello";
printf("%zu\n", sizeof(str)); // 6(含 '\0')
func(str); // 传入后退化
return 0;
}
对策:函数参数若需数组大小,必须显式传递长度参数,或用结构体封装 { char *data; size_t len; }。
字符串字面量的 sizeof 与 strlen
sizeof("hello") // 6(5 字符 + '\0')
strlen("hello") // 5
sizeof("") // 1(仅 '\0')
strlen("") // 0
实战决策指南:何时用哪个?
| 场景 | 推荐 | 理由 |
|---|---|---|
| 获取字符串逻辑长度(如截取、拼接、校验) | strlen() | 语义精确,不含终止符 |
| 分配内存存储字符串副本 | strlen(s) + 1 | 含终止符 |
| 用 memcpy/memmove 拷贝字符串 | strlen(src) + 1 | 拷贝含终止符的完整内容 |
| 获取数组/结构体/基本类型占用字节 | sizeof | 编译期常量,零开销 |
| 计算结构体数组元素个数 | sizeof(arr)/sizeof(arr[0]) | 仅对数组对象有效,指针无效 |
| 格式化输出大小 | %zu 对应 size_t | 跨平台可移植 |
进阶:嵌入空字符的字符串
C 字符串约定以首个 '\0' 为结束。若数据本身包含 '\0'(如二进制协议、UTF-16),不能用 strlen,必须显式维护长度字段(struct { void *data; size_t len; }),并用 memcmp/memcpy 等内存函数处理。
性能考量
strlen为 O(n),频繁调用于长字符串会成为热点。缓存长度或使用带长度的字符串结构(如struct Str { char *p; size_t len; })可优化。sizeof编译期常量,零运行时开销。- 现代编译器对字符串字面量的
strlen可在编译期优化为常量。
跨平台注意:size_t 打印格式
// 正确:C99 标准
printf("len = %zu\n", strlen(s));
printf("size = %zu\n", sizeof(arr));
// 旧标准兼容(不推荐)
printf("len = %lu\n", (unsigned long)strlen(s));
总结
- strlen = 运行时字符串逻辑长度(不含
'\0'),仅限 C 字符串 - sizeof = 编译期对象存储大小(含
'\0'/填充),任意类型通用 - 数组作函数参数退化为指针,
sizeof失效 → 必须显式传长度 - 字符串字面量:
sizeof = strlen + 1 - 含嵌入
'\0'数据 → 弃用 C 字符串函数,改用显式长度 + 内存函数
C语言