这段C代码主要演示了sizeof运算符在指针数组中的行为。理解的关键在于分析int *a[2][3]的类型和sizeof在不同解引用层级下的计算方式。以下是逐行解析:
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
//int a[2][3]={0};
int *a[2][3];
printf("sizeof(a) =%d \n",sizeof(a));
printf("sizeof(*a) =%d\n",sizeof(*a));
printf("sizeof(**a) =%d\n",sizeof(**a));
printf("sizeof(***a) =%d\n",sizeof(***a));
//printf("szieof(a) = %d,szieof(*a) = %d,szieof(**a) = %d,szieof(***a) = %d",szieof(a),szieof(*a),szieof(**a),szieof(***a));
return 0;
}
1. 变量声明
int *a[2][3];
- 声明了一个2行3列的二维数组
a - 每个元素都是
int*类型(指向整数的指针) - 内存结构:6个连续的指针元素(2×3)
2. sizeof运算解析
| 表达式 | 实际类型 | 计算方式 | 32位系统 | 64位系统 |
|---|---|---|---|---|
sizeof(a) | int*[2][3] | 整个数组大小 = 2×3×指针大小 | 24字节 | 48字节 |
sizeof(*a) | int*[3] | 单行大小 = 3×指针大小 | 12字节 | 24字节 |
sizeof(**a) | int* | 单个元素大小 = 指针大小 | 4字节 | 8字节 |
sizeof(***a) | int | 指针解引用后的大小 = sizeof(int) | 4字节 | 4字节 |
3. 关键概念图解
a → [ ptr00 ] → (可能的int数据)
| [ ptr01 ] → ...
| [ ptr02 ] → ...
| [ ptr10 ] → ...
| [ ptr11 ] → ...
| [ ptr12 ] → ...
- a:整个二维数组(6个指针)
- *a:第一行(3个指针)
- **a:第一行第一个元素(单个指针)
- a*:指针指向的整数数据
4. 输出结果说明
sizeof(a):计算整个二维数组的空间占用sizeof(*a):计算单行(子数组)的空间占用sizeof(**a):计算单个指针元素的大小sizeof(***a):计算指针解引用后的整数大小
5. 系统差异
- 32位系统:指针占4字节,int占4字节
- 64位系统:指针占8字节,int仍占4字节
- 输出差异主要来自指针大小的不同
总结
这段代码展示了指针数组在内存中的层级结构:
- 二维数组 → 2. 行数组 → 3. 单个指针 → 4. 实际数据
通过sizeof运算符可以清晰地观察到:
- 数组整体与部分的空间关系
- 指针与数据的本质区别
- 系统架构对指针大小的直接影响
理解核心:sizeof在编译时静态计算类型大小,与实际存储的值无关。这种分析方式对于理解复杂指针结构和内存管理至关重要。
理解 int *a[2][3] 及其相关表达式,关键是拆解变量类型和指针运算的关系,一步步来会很清晰 👇
第一步:明确 int *a[2][3] 是什么?
· 优先级规则:[] 比 * 优先级高,所以这是一个 二维数组,而非指针。
· 数组类型:数组的每个元素是 int*(指向 int 的指针)。
·维度:2 行 × 3 列,共 2×3=6 个元素,每个元素都是一个 int* 指针。
简单说:a 是一个「存储指针的二维数组」,像个 2 行 3 列的表格,每个格子里放着一个指向整数的地址。
第二步:关键表达式解析
1. a
· 类型:int* (*)[3](指向「包含 3 个 int* 元素的数组」的指针)。
· 含义:数组名 a 代表数组首元素的地址。由于 a 是二维数组,其首元素是第一行(一个包含 3 个 int* 的一维数组),所以 a 是指向「行数组」的指针。
2. *a
· 类型:int* [3](包含 3 个 int* 元素的一维数组)。
· 含义:对 a 解引用,得到二维数组的第一行(完整的一维数组)。此时 *a 等价于 a[0](第一行的数组名)。
3. **a
· 类型:int*(指向 int 的指针)。
· 含义:先 *a 得到第一行数组,再对其解引用,得到该行的第一个元素(即 a[0][0],一个 int* 指针)。
4. a[0][0](补充:和 **a 等价)
· 直接通过数组下标访问第一行第一列的 int* 指针,与 **a 完全相同。
5. *a[0][0](补充:访问最终的 int 值)
· 如果想获取 a[0][0] 指针指向的整数,需要再解引用一次:*a[0][0](或 ***a,但不推荐这么写,可读性差)。
总结:从 a 到具体值的路径
a → 指向第一行的指针(行指针)
*a → 第一行数组(a[0])
**a → 第一行第一个指针(a[0][0],int* 类型)
***a → a[0][0] 指向的整数(int 类型)
可以类比成:
a 是「书架」的地址 → *a 是第一层书架 → **a 是第一层第一个格子里的「书签」(指向某页)→ ***a 是书签指向的「具体内容」。
避坑提醒
· 区分 int *a[2][3](指针数组的二维数组)和 int (*a)[2][3](指向二维数组的指针),前者数组元素是指针,后者本身是指针。
· 多维数组的指针运算容易绕,建议多结合下标(如 a[i][j])理解,少用多层解引用(如 ***a)。
如果觉得抽象,画个内存布局图会更直观哦!需要的话可以告诉我,帮你补充~ 😊