# sizeof 和 strlen 的区别
# 简要回答
一句话概括:sizeof 是编译期运算符,计算的是类型或变量占用的内存字节数;strlen 是运行时函数,计算的是字符串中 \0 之前的字符个数。两者都能作用于字符串,但结果不同,含义也不同。
# 详细回答
理解这两者的本质区别,要从它们各自"看"字符串的角度出发。
两者的核心差异对比:
| 对比维度 | sizeof | strlen |
|---|---|---|
| 本质 | 运算符(operator) | 标准库函数(<cstring>) |
| 执行时机 | 编译期(compile-time) | 运行时(runtime) |
| 计算内容 | 类型/变量占用的字节数 | \0 前的字符个数 |
包含 '\0'? | 包含 | 不包含 |
| 适用类型 | 任意类型(int、struct…) | 仅限 char* / char[] |
# 代码示范
#include <iostream>
#include <cstring>
using namespace std;
int main() {
// ── 情况1:字符数组 ──────────────────────────
char s1[] = "hello";
cout << sizeof(s1) << endl; // 6,数组大小 = 5字符 + 1个'\0'
cout << strlen(s1) << endl; // 5,不含'\0'
// ── 情况2:字符指针 ──────────────────────────
const char* s2 = "hello";
cout << sizeof(s2) << endl; // 8(64位系统指针大小),不是字符串长度!
cout << strlen(s2) << endl; // 5,正常计算
// ── 情况3:手动指定大小的数组 ──────────────────
char s3[20] = "hello";
cout << sizeof(s3) << endl; // 20,数组声明的总大小
cout << strlen(s3) << endl; // 5,只看'\0'之前
// ── 情况4:sizeof 用于非字符串类型 ─────────────
cout << sizeof(int) << endl; // 4
cout << sizeof(double) << endl; // 8
// strlen(42); // ❌ 编译错误:strlen 只接受 char*
// ── 情况5:含中间'\0'的字符数组(经典陷阱)──────
char s4[] = {'a', '\0', 'b', 'c'};
cout << sizeof(s4) << endl; // 4,数组真实大小
cout << strlen(s4) << endl; // 1,碰到第一个'\0'就停了!
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
输出结果:
6
5
8
5
20
5
4
8
4
1
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
情况5是最容易踩坑的地方:
sizeof如实返回4,但strlen只返回1,因为它在第二个字节就遇到了\0并停止了遍历。
# 知识拓展:面试官的追问
# 追问1:sizeof 对指针和数组有什么区别?
这是最高频的追问,也是最容易答错的。
char arr[] = "hello"; // 栈上的数组
char* ptr = "hello"; // 指向字符串字面量的指针
sizeof(arr); // 6 —— sizeof 看到的是整个数组 char[6]
sizeof(ptr); // 8 —— 指针本身的大小,与字符串长度无关
1
2
3
4
5
2
3
4
5
核心原因:sizeof 是编译期运算符,直接查看类型信息。arr 的类型是 char[6],返回6;ptr 的类型是 char*,返回指针大小(64位系统为8字节)。
# 追问2:数组作为函数参数传递时,sizeof 还准确吗?
不准确,这是一个经典陷阱:
void foo(char arr[]) {
cout << sizeof(arr) << endl; // 输出 8!不是数组大小
// char arr[] 作为参数等价于 char* arr,数组退化成了指针
}
int main() {
char s[] = "hello";
cout << sizeof(s) << endl; // 6,正确
foo(s); // 传进去就退化了
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
数组一旦作为函数参数传递,就退化为指针,sizeof 只能得到指针大小。如果需要在函数内知道数组长度,必须额外传一个 len 参数。
# 追问3:strlen 的时间复杂度是多少?能优化吗?
strlen 是 O(n) 的,本质上是从头遍历到 \0:
// strlen 的等价实现
size_t my_strlen(const char* s) {
const char* p = s;
while (*p != '\0') p++;
return p - s;
}
1
2
3
4
5
6
2
3
4
5
6
如果在循环中反复调用 strlen,要把结果缓存起来:
// ❌ 差写法:每次循环都重新遍历
for (int i = 0; i < strlen(s); i++) { ... }
// ✓ 好写法:提前缓存长度
size_t len = strlen(s);
for (int i = 0; i < len; i++) { ... }
1
2
3
4
5
6
2
3
4
5
6
# 追问4:sizeof 的结果一定是编译期常量吗?
在标准 C++ 中,是的。但 C99 引入了变长数组(VLA),在 C 语言中 sizeof 会退化为运行时计算:
// C语言(不是C++)
void foo(int n) {
int arr[n]; // VLA,大小运行时才确定
printf("%zu\n", sizeof(arr)); // 运行时求值,不是编译期常量
}
1
2
3
4
5
2
3
4
5
C++ 标准不支持 VLA,所以在标准 C++ 中 sizeof 的结果始终是编译期常量。
评论
验证登录状态...