19.sizeof-vs-strlen.md 3.8 KB

sizeof vs strlen

判别规则(核心,唯一要记的)

  • sizeof → 编译期,按类型算字节,含 \0(数组得整块大小、指针得 4/8)
  • strlen → 运行期,数到 \0 前,不含 \0
  • 陷阱:数组名传参退化成指针后,sizeof 得指针大小——函数里算数组长度要靠参数传入

一句话:"sizeof 问多大(含\0,编译期),strlen 问多长(不含\0,运行期)。"

抽象描述(一句话本质)

sizeof = 编译期算"这个类型占多少字节";strlen = 运行期 O(n) 扫到 \0 前数"有几个字符"。strlen 依赖 \0 结尾,没 \0 会越界读。

正反例(建立直觉)

  • 正例1char s[] = "hello";sizeof(s) = 6(5 字符+\0),strlen(s) = 5(数到 \0 前)
  • 正例2char *p = "hello";sizeof(p) = 4/8(指针大小),strlen(p) = 5
  • 正例3void f(char s[]) { sizeof(s); }4/8!形参是退化指针;strlen(s) 照样对
  • 正例4char s[100] = "hi";sizeof(s) = 100(声明的大小),strlen(s) = 2(实际字符数)
  • 反例1:以为 strlen 含 \0 → 错,不含
  • 反例2:以为 sizeof 数"有效字符数" → 错,是类型占多少字节

易混对比

sizeof strlen
时机 编译期(编完就定死) 运行期(跑起来才数)
算什么 类型占多少字节 \0几个字符
\0 ✅ 含(按类型大小) ❌ 不含
对数组 整块大小(6/100) 长度(5/2)
对指针 指针大小(4/8) 照样数

变体验证(3 题,全过=学会)

  1. char s[100] = "hi";sizeof(s) = 100(声明的大小),strlen(s) = 2(实际字符数)
  2. 陷阱题:void f(char s[]) {...}f("hello") → 打印 sizeof = 4/8(退化指针)、strlen = 5
  3. 陷阱题:int a[5];sizeof(a) = 20strlen(a) 不能用(strlen 只认 char* 字符串,int 数组没有 \0 语义)

口述要点(面试怎么讲)

  • 结论先行:sizeof 编译期按类型算字节(含\0),strlen 运行期数到\0前(不含\0)
  • 为什么 strlen 必须运行期:设计上必须 O(n) 扫描 \0 才能知道长度,编译期做不到(除非字面量可静态计算)
  • 函数里怎么拿数组长度:函数参数显式传入数组长度;封装容器/宏在声明处算好。函数内对退化指针 sizeof 拿不到长度
  • 为什么嵌入式推崇 sizeof:编译器按当前平台算,跨平台自动适配(int 在 16 位机是 2 字节、32 位是 4 字节),手写常量换平台就错;数组改大小时只改一处,防越界
  • 易错点:传参后 sizeof 失灵;strlen 对没 \0 的缓冲区会越界读

关系网络

相邻概念 和本主题的关系 孤立理解会犯的错
数组名 vs 指针 sizeof 失灵的根源 = 数组名传参退化 传参后还 sizeof 想拿数组长度
字符串 strlen 依赖 \0 结尾——没 \0 的缓冲区会数出界 以为 strlen 自动安全
结构体对齐 sizeof(结构体) 含填充字节,可用于算偏移 以为 sizeof 结构体 = 成员和
内存安全 strlen 对未初始化/无 \0 内存会越界读 忘了检查缓冲区是否以 \0 结尾

学习日期

2026-08-03


每主题一页,复习时只翻本目录。