sizeof是一个运算符,在编译时计算,用于获取数据类型或变量所占的内存字节数。strlen是一个库函数,在运行时计算,用于获取以'\0'结尾的字符串的长度(字符个数)。
sizeof 运算符
sizeof 是 C 语言的一个单目运算符,就像 , , 一样,它返回一个 size_t 类型的值,表示对象或类型所占的内存字节数。

(图片来源网络,侵删)
主要特点和用法:
- 编译时计算:
sizeof的值在程序编译时就已经确定了,而不是在运行时才计算,它不会带来任何运行时开销。 - 作用于类型和变量:
sizeof(type):计算一个类型所占的字节数。sizeof variable:计算一个变量所占的字节数。sizeof(variable):加上括号也可以,但通常不加更简洁。
- 计算的是总大小:它会计算整个数组、结构体等所占用的空间,直到遇到边界。
示例代码:
#include <stdio.h>
int main() {
// 1. 基本数据类型
int a = 10;
printf("sizeof(int): %zu\n", sizeof(int)); // 输出 4 (在大多数现代系统上)
printf("sizeof(a): %zu\n", sizeof(a)); // 输出 4
printf("sizeof(double): %zu\n", sizeof(double)); // 输出 8
// 2. 数组
// 数组名 'arr' 在这里会“退化”为指向首元素的指针,但 sizeof(arr) 仍然计算整个数组的大小
char arr[] = "hello"; // 等价于 char arr[] = {'h', 'e', 'l', 'l', 'o', '\0'};
printf("sizeof(arr): %zu\n", sizeof(arr)); // 输出 6 (5个字符 + 1个'\0')
int arr_int[10];
printf("sizeof(arr_int): %zu\n", sizeof(arr_int)); // 输出 40 (10 * 4)
// 3. 指针
char *ptr = "hello"; // ptr 是一个指针,它只存储一个地址
printf("sizeof(ptr): %zu\n", sizeof(ptr)); // 输出 8 (在64位系统上,地址是8字节)
// 4. 字符串字面量 (String Literal)
// "hello" 也是一个字符数组,存储在程序的只读数据段
printf("sizeof(\"hello\"): %zu\n", sizeof("hello")); // 输出 6
return 0;
}
strlen 函数
strlen 是 C 标准库 <string.h> 中的一个函数,它的作用是计算字符串的长度。
函数原型:
size_t strlen(const char *str);
主要特点和用法:
- 运行时计算:
strlen必须在程序运行时才能知道结果,它会从传入的地址开始,逐个字节检查,直到遇到第一个空字符'\0'为止,这个过程需要时间,因此有运行时开销。 - 参数必须是
'\0'结尾的字符串:如果传入的字符数组没有'\0',strlen会一直向后读,直到它偶然在内存中找到一个'\0',这会导致未定义行为,通常表现为程序崩溃或得到一个完全错误的长度。 - 返回值不包括
'\0':strlen只计算字符的个数,不计算结尾的空字符。
示例代码:
#include <stdio.h>
#include <string.h> // 必须包含这个头文件
int main() {
char str[] = "hello";
// strlen 从 str 的地址开始,直到遇到 '\0'
// 'h' 'e' 'l' 'l' 'o' '\0'
// 1 2 3 4 5 (长度)
size_t len = strlen(str);
printf("strlen(str): %zu\n", len); // 输出 5
// 对比 sizeof 和 strlen 的关键区别
printf("sizeof(str): %zu\n", sizeof(str)); // 输出 6 (包括 '\0')
printf("strlen(str): %zu\n", strlen(str)); // 输出 5 (不包括 '\0')
// 危险示例:没有 '\0' 结尾的字符数组
char str_no_null[] = {'h', 'e', 'l', 'l', 'o'}; // 没有 '\0'
// 下面的调用是错误的,会导致未定义行为!
// printf("strlen(str_no_null): %zu\n", strlen(str_no_null));
// 指针和数组名的区别
char *ptr = "hello";
// 对于字符串字面量,sizeof 计算的是整个字面量的大小(包括'\0')
// strlen 计算的是字符串的长度
printf("sizeof(\"hello\"): %zu\n", sizeof("hello")); // 输出 6
printf("strlen(\"hello\"): %zu\n", strlen("hello")); // 输出 5
// 对于指针变量,sizeof 计算的是指针本身的大小
// strlen 解引用指针,从指针指向的内存开始计算长度
printf("sizeof(ptr): %zu\n", sizeof(ptr)); // 输出 8 (64位系统)
printf("strlen(ptr): %zu\n", strlen(ptr)); // 输出 5
return 0;
}
核心区别对比表
| 特性 | sizeof |
strlen |
|---|---|---|
| 本质 | 运算符 (Operator) | 库函数 (Function) |
| 执行时机 | 编译时 (Compile-time) | 运行时 (Run-time) |
| 功能 | 计算类型或变量占用的内存字节数 | 计算字符串的长度(字符个数) |
| 参数 | 类型 (int) 或 变量 (my_var) |
必须是 const char* (指向 '\0' 结尾的字符串) |
包含 '\0' |
是 (计算总大小) | 否 (遇到 '\0' 停止,但不计入结果) |
| 对数组 | 返回整个数组的总大小 | 只计算有效字符的长度,直到 '\0' |
| 对指针 | 返回指针变量本身的大小 (通常是 4 或 8 字节) | 从指针指向的地址开始,计算字符串长度 |
| 头文件 | 无需包含任何头文件 | 必须包含 <string.h> |
经典面试题
这是一个非常经典的面试题,能完美考察你对这两个概念的理解。
问题: 下面的代码会输出什么?
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "hello";
char *ptr = "hello";
printf("sizeof(str) = %zu\n", sizeof(str));
printf("strlen(str) = %zu\n", strlen(str));
printf("sizeof(ptr) = %zu\n", sizeof(ptr));
printf("strlen(ptr) = %zu\n", strlen(ptr));
printf("sizeof(\"hello\") = %zu\n", sizeof("hello"));
printf("strlen(\"hello\") = %zu\n", strlen("hello"));
return 0;
}
答案分析 (在64位系统上运行):

(图片来源网络,侵删)
-
char str[] = "hello";str是一个字符数组,在栈上分配。- 内容是
{'h', 'e', 'l', 'l', 'o', '\0'}。 sizeof(str):计算整个数组的大小,即6 * 1字节。 输出 6。strlen(str):从str开始数,直到'\0',数了5个字符。 输出 5。
-
char *ptr = "hello";ptr是一个指针变量,在栈上分配,它存储一个地址(指向字符串字面量)。sizeof(ptr):计算指针变量本身的大小,在64位系统上是8字节。 输出 8。strlen(ptr):解引用ptr,从它指向的地址(即字符串"hello"的地址)开始数,直到'\0',数了5个字符。 输出 5。
-
sizeof("hello")和strlen("hello")"hello"是一个字符串字面量,它本质上是一个匿名的字符数组。sizeof("hello"):计算这个匿名数组的大小,包括'\0'。 输出 6。strlen("hello"):从这个匿名数组的地址开始计算长度。 输出 5。
完整输出:

(图片来源网络,侵删)
sizeof(str) = 6
strlen(str) = 5
sizeof(ptr) = 8
strlen(ptr) = 5
sizeof("hello") = 6
strlen("hello") = 5
通过这个例子,你应该能深刻理解 sizeof 和 strlen 在不同场景下的行为差异了。sizeof 问的是“占多大地方?”,strlen 问的是“字符串有多长?”。
