核心定义
sizeof 是C语言中的一个关键字,而不是一个函数,它的作用是返回一个变量、数据类型或数组所占用的内存字节数。

(图片来源网络,侵删)
sizeof 就是一个“内存尺子”,用来测量在内存中,某个东西占了多大地方。
基本语法和用法
sizeof 有两种主要的用法形式:
sizeof(数据类型)
直接在 sizeof 后面跟一个数据类型(如 int, char, double 等),需要用括号括起来。
#include <stdio.h>
int main() {
// 测基本数据类型的大小
printf("char 的大小: %zu 字节\n", sizeof(char)); // 通常输出 1
printf("int 的大小: %zu 字节\n", sizeof(int)); // 通常输出 4
printf("float 的大小: %zu 字节\n", sizeof(float)); // 通常输出 4
printf("double 的大小: %zu 字节\n", sizeof(double)); // 通常输出 8
printf("long 的大小: %zu 字节\n", sizeof(long)); // 通常输出 4 或 8
return 0;
}
注意:这里的 %zu 是 size_t 类型的正确格式说明符。size_t 是一个无符号整数类型,专门用于表示大小和计数,是 sizeof 返回值的类型。
sizeof(变量名)
在 sizeof 后面跟一个已经定义好的变量名,括号可以省略(但加上更清晰、更安全)。
#include <stdio.h>
int main() {
int a = 10;
double b = 3.14;
char c = 'A';
// 测变量的大小
printf("变量 a 的大小: %zu 字节\n", sizeof(a)); // 输出 4
printf("变量 b 的大小: %zu 字节\n", sizeof(b)); // 输出 8
printf("变量 c 的大小: %zu 字节\n", sizeof(c)); // 输出 1
// 使用括号也是可以的,推荐这种方式,特别是当变量名是复杂表达式时
printf("变量 a 的大小 (带括号): %zu 字节\n", sizeof(a));
return 0;
}
重要特性和高级用法
sizeof 在编译时计算
sizeof 是一个编译时操作,而不是运行时操作,这意味着它的值在程序编译时就已经确定了,不会给程序运行增加任何开销。
示例:
int arr[10]; int size = sizeof(arr); // 在编译时,编译器就知道 arr 占 10 * sizeof(int) 个字节
这行代码在运行时并不会去数 arr 数组里有多少个元素,而是在编译阶段就计算好了。
sizeof 用于数组
sizeof 在计算数组大小时非常有用,可以轻松得到整个数组占用的总字节数。
#include <stdio.h>
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
// 计算整个数组的大小
int total_size = sizeof(numbers); // 5 * sizeof(int) = 5 * 4 = 20 字节
// 计算数组元素的个数
int element_count = total_size / sizeof(numbers[0]); // 20 / 4 = 5 个元素
printf("数组 numbers 的总大小: %d 字节\n", total_size); // 输出 20
printf("数组 numbers 的元素个数: %d\n", element_count); // 输出 5
return 0;
}
注意:当数组作为函数参数传递时,它会“退化”为指向其首元素的指针,此时在函数内部使用 sizeof 得到的是指针的大小,而不是数组的大小。
void print_size(int arr[]) { // arr 实际上是一个 int* 指针
printf("在函数内部,arr 的大小是: %zu\n", sizeof(arr)); // 输出的是指针的大小 (如 4 或 8),而不是数组的大小
}
int main() {
int numbers[10];
printf("在 main 函数中,numbers 的大小是: %zu\n", sizeof(numbers)); // 输出 40
print_size(numbers); // 输出 4 或 8
return 0;
}
这是C语言初学者一个非常容易混淆的点。
sizeof 用于结构体
sizeof 也可以计算结构体的大小,但这里有一个非常重要的概念:内存对齐。
结构体的大小不一定是其所有成员大小之和,编译器为了提高内存访问效率,会在成员之间插入“填充字节”(Padding)。
#include <stdio.h>
// 定义一个结构体
struct MyStruct {
char c; // 1 字节
int i; // 4 字节
double d; // 8 字节
};
int main() {
printf("结构体 MyStruct 的大小: %zu 字节\n", sizeof(struct MyStruct));
// 手动计算一下(假设编译器按4字节对齐):
// char c: 占 1 字节
// [填充 3 字节],使得下一个 int 能从 4 的倍数地址开始
// int i: 占 4 字节
// [填充 4 字节],使得下一个 double 能从 8 的倍数地址开始
// double d: 占 8 字节
// 总计 = 1 + 3 + 4 + 4 + 8 = 20 字节
// 但实际输出可能是 24,因为整个结构体的总大小也必须是最大成员(double, 8字节)的整数倍。
// 20 不是 8 的倍数,所以最后再填充 4 字节,总共 24 字节。
return 0;
}
运行结果通常是 24,而不是 1+4+8=13,这就是内存对齐的影响。
sizeof 用于字符串字面量
字符串字面量(如 "hello")在C语言中会被存储在内存的只读区域,并且会自动在末尾添加一个 \0 (空字符) 作为结束符。
#include <stdio.h>
int main() {
char str[] = "hello"; // 这是一个字符数组
char *ptr = "hello"; // 这是一个指向字符串字面量的指针
printf("字符数组 str 的大小: %zu\n", sizeof(str)); // 输出 6 ('h','e','l','l','o','\0')
printf("指针 ptr 的大小: %zu\n", sizeof(ptr)); // 输出指针的大小 (如 4 或 8)
return 0;
}
总结表格
| 用法 | 描述 | 示例 | 结果 (典型值) |
|---|---|---|---|
sizeof(类型) |
获取数据类型占用的字节数 | sizeof(int) |
4 |
sizeof(变量) |
获取变量占用的字节数 | int x; sizeof(x) |
4 |
sizeof(数组名) |
获取整个数组占用的总字节数 | int arr[5]; sizeof(arr) |
20 |
sizeof(结构体) |
获取结构体占用的字节数(考虑对齐) | struct S{char c; int i;}; sizeof(S) |
8 |
sizeof(指针) |
获取指针本身占用的字节数 | int *p; sizeof(p) |
4 或 8 |
sizeof("字符串") |
获取字符串字面量(含'\0')的总字节数 | sizeof("abc") |
4 |
为什么 sizeof 很重要?
- 内存管理:知道数据占多大内存,才能正确地分配和释放内存(如
malloc和free)。 - 数据序列化:在将数据写入文件或通过网络传输时,需要知道数据块的准确大小。
- 避免缓冲区溢出:在处理数组时,用
sizeof计算元素个数,可以防止数组越界访问。 - 跨平台开发:不同平台下,
int、long等类型的大小可能不同,使用sizeof可以让你的代码更具可移植性。
希望这个详细的解释能帮助你彻底理解 sizeof 的含义和用法!
