sizeof和strlen的区别
2026/5/15 4:01:07 网站建设 项目流程

sizeof和strlen的区别

  • 一、本质不同:运算符 vs 库函数
  • 二、求值时机:编译期常量 vs 运行时计算
  • 三、测量核心:总内存大小 vs 有效字符长度
    • 32 位系统输出
  • 四、职责分离:`sizeof` 问结构,`strlen` 问内容
  • 五、常见陷阱:函数参数中的数组退化
  • 六、安全性差异
  • 七、全面对照总结表

一、本质不同:运算符 vs 库函数

  • sizeof是 C/C++ 语言内置的运算符(关键字),由编译器直接处理,无需包含任何头文件
  • strlen是 C 标准库提供的函数,声明在<string.h>中,使用时必须包含该头文件。
维度sizeofstrlen
本质运算符(关键字)函数
所需头文件<string.h>(C++ 中为<cstring>
作用对象类型名、变量名、表达式const char*(以'\0'结尾的字符串)

二、求值时机:编译期常量 vs 运行时计算

  • sizeof:在编译阶段计算结果,等价于一个常量,不依赖程序实际运行。
  • strlen:在程序运行时从传入地址逐个扫描内存,直到遇见'\0'才停止。
#include<stdio.h>#include<string.h>intmain(void){chars[]="abc";// 编译器分配 4 字节:'a','b','c','\0'printf("sizeof(s) = %zu\n",sizeof(s));// 编译时已知printf("strlen(s) = %zu\n",strlen(s));// 运行时遍历return0;}

输出

sizeof(s) = 4 strlen(s) = 3

讲解

  • 数组s被初始化为"abc",编译器分配 4 个字节(含结尾'\0')。sizeof(s)在编译时就被替换为常数4
  • strlen(s)在运行时s的首地址向后扫描,数到'\0'前一共 3 个字符,返回3

三、测量核心:总内存大小 vs 有效字符长度

  • sizeof:测量类型或对象占用的总内存字节数。若对象是字符数组,会包含结尾的'\0'
  • strlen:测量字符串中有效字符的个数绝不包含结尾的'\0'
#include<stdio.h>#include<string.h>intmain(void){charstr[]="hello";// 数组 —— 实际占据 6 字节char*p="hello";// 指针 —— p 只存一个地址printf("=== 对字符数组 str ===\n");printf("sizeof(str) = %zu\n",sizeof(str));// 整个数组大小printf("strlen(str) = %zu\n",strlen(str));// 有效字符数printf("\n=== 对指针 p ===\n");printf("sizeof(p) = %zu\n",sizeof(p));// 指针变量自身大小printf("strlen(p) = %zu\n",strlen(p));// 指针所指字符串长度return0;}

输出(64 位系统)

=== 对字符数组 str === sizeof(str) = 6 strlen(str) = 5 === 对指针 p === sizeof(p) = 8 strlen(p) = 5

32 位系统输出

=== 对字符数组 str === sizeof(str) = 6 strlen(str) = 5 === 对指针 p === sizeof(p) = 4 strlen(p) = 5

讲解

  • 数组strsizeof(str)返回6(5 个字母 + 1 个'\0'),32 位与 64 位系统结果完全相同。strlen(str)返回5(遇'\0'停止,不计入结束符)。
  • 指针psizeof(p)64 位系统下返回 8,在32 位系统下返回 4,只与系统位数有关,p指向什么内容完全无关strlen(p)始终返回5,因为它沿着指针地址计算有效字符长度,至'\0'停止,不受系统位数影响。

四、职责分离:sizeof问结构,strlen问内容

  • sizeof只关心“这个变量 / 类型本身占多大空间”。不读取内存,不关心里面存的是什么。
  • strlen只关心“从这个地址开始,存放着一个多长的字符串”。必须读取内存,以'\0'为唯一终止标记。
    因此:
  • 数组名sizeof→ 得到整个数组的字节数。
  • 指针变量sizeof→ 得到指针变量自身的大小(4 或 8 字节)。
  • strlen对数组名和指针一视同仁,都是从给定地址向后数非'\0'字符。

五、常见陷阱:函数参数中的数组退化

数组作为函数参数传递时,会退化为指针。此时在函数内部使用sizeof(形参名)将无法获得原数组大小,只能得到指针大小。而strlen可以继续正常工作。

#include<stdio.h>#include<string.h>voidexamine(chararr[]){// 形参等价于 char *arrprintf("在函数内部:\n");printf(" sizeof(arr) = %zu <-- 这是指针的大小,不是数组的大小\n",sizeof(arr));printf(" strlen(arr) = %zu <-- 这才是字符串的真正长度\n",strlen(arr));}intmain(void){charstr[]="hello";printf("在 main 中 sizeof(str) = %zu\n\n",sizeof(str));examine(str);return0;}

输出(64 位系统)

在 main 中 sizeof(str) = 6 在函数内部: sizeof(arr) = 8 <-- 这是指针的大小,不是数组的大小 strlen(arr) = 5 <-- 这才是字符串的真正长度

讲解

  • mainsizeof(str)正确反映数组总大小6
  • 传入函数后,形参arr虽写作数组形式,但本质是指针sizeof(arr)返回指针变量的大小8,丢失了原数组的长度。
  • strlen(arr)不受影响,依然从地址扫描,得到正确长度5

🔑编程铁律:函数内处理字符串时,要长度请用strlen,或显式传入长度参数,不可依赖sizeof


六、安全性差异

  • strlen有越界风险:必须扫描到'\0'才停止。若传入的指针不是指向以'\0'结尾的有效字符串,将导致未定义行为,可能读取非法内存甚至崩溃。
  • sizeof不访问内存:仅根据类型信息在编译期推算大小,没有越界风险,极其安全。
char*dangerous=(char*)0x100;// 任意地址// strlen(dangerous); // 未定义行为,极可能崩溃// sizeof(*dangerous); // 等价于 sizeof(char),安全得到 1

七、全面对照总结表

比较维度sizeofstrlen
是什么运算符(关键字)函数
头文件<string.h>/<cstring>
计算时机编译时(VLA 除外)运行时
计算对象类型、变量、表达式'\0'结尾的字符串(const char*
测量内容内存占用总字节数有效字符个数(不含'\0'
是否包含'\0'数组:包含;
指针:与内容无关
不包含
对数组返回整个数组大小返回内部字符串长度
对指针返回指针变量自身大小(4/8 字节)返回指针所指字符串长度
在函数参数中数组退化 → 返回指针大小仍可正确求字符串长度
安全性不访问内存,无越界依赖正确的'\0',否则可能越界
结果是否为编译期常量多数情况,运行时值

记忆口诀

  • sizeof:问 “变量 / 类型 占多大坑” ——编译时定,不读数据。
  • strlen:问 “坑里字符串有多长 (别把末尾\0当字符)” ——运行时数,认\0为止。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询