系统梳理 C++ 数组、指针的类型表示
...大约 3 分钟
一、分类
1.1. 已知大小的数组(位于栈上)
一维 | 二维 | 三维 | |
---|---|---|---|
变量声明 | int a[5] | int b[3][4] | int c[2][3][4] |
类型名 | int[5] | int[3][4] | int[2][3][4] |
占用空间 | 5 * sizeof(int) | 3 * 4 * sizeof(int) | 2 * 3 * 4 * sizeof(int) |
1.2. 动态数组(位于堆上)
一维 | 二维 | 三维 | |
---|---|---|---|
变量声明 | int* a | int** b | int*** c |
类型名 | int* | int** | int*** |
占用空间 | sizeof(size_t) | sizeof(size_t) | sizeof(size_t) |
描述 | 指向 {int, int, ...} 的第一个元素的指针 | 指向 {int*, int*, ...} 的第一个元素的指针 | 指向 {int**, int**, ...} 的第一个元素的指针 |
释放内存 | delete[] a; | for (i) delete[] b[i]; | for (i) for (j) delete[] c[i][j]; |
省略号表示仅靠类型名无法确定数组的长度
1.3. 复合
二维
变量声明 | int (*p)[5] | int *p[5] |
---|---|---|
类型名 | int (*)[5] | int *[5] |
本质 | 指针 | 数组 (大小: 5) |
占用空间 | 1 * sizeof(size_t) | 5 * sizeof(size_t) |
描述 | 指向 {int[5], int[5], ...} 的第一个元素的指针 | 指向{int*, int*, int*, int*, int*} 的第一个元素的指针 |
三维
变量声明 | int (*p)[2][3] | int *p[2][3] |
---|---|---|
类型名 | int (*)[2][3] | int *[2][3] |
本质 | 指针 | 数组 (大小: 2 * 3) |
占用空间 | 1 * sizeof(size_t) | 2 * 3 * sizeof(size_t) |
描述 | 指向 {int[2][3], int[2][3], ...} 的第一个元素的指针 | 指向{{int*, int*, int*}, {int*, int*, int*}, ...} 的第一个元素的指针 |
隐式转换
由于数组可以看作是指针的一种特例, 因此数组可以隐式转换为指针 例如:
int [5]
可以隐式转换为int*
int [3][5]
可以隐式转换为int*[5]
- 但
int [3][5]
不能隐式转换为int(*)[5]
int [5][2][3]
可以隐式转换为int*[2][3]
二、规则与理解
2.1. 拆解规则
foo [n] bar
相当于有 n 个foo bar
组成的数组foo * bar
相当于指向foo bar
构成的数组的指针
2.2. 运算规则
- 小括号 包围的有限拆解
- 方括号 优先级高于 星号
- 相同运算优先级, 则从中间向外拆解
2.3. 实例解析
按照此规则, 就可以用置换原理来很容易地理解数组的类型表示:
int[2][3]
(中间向外拆解)
=(int) [2] ([3])
={ int[3], int[3] }
int**
(中间向外拆解)
=(int) * (*)
={int*, int*, ...}
int(*)[5]
(小括号改变运算顺序, 先拆解星号)
={ int[5], int[5], ... }
int*[5]
(原有顺序, 先拆解方括号)
={ int*, int*, int*, int*, int* }
int (*)[2][3]
(小括号改变运算顺序, 先拆解星号)
={ int[2][3], int[2][3], ... }
int *[2][3]
(原有顺序, 先拆解方括号, 中间向外拆解)
={ int*[3], int*[3] }
(原有顺序, 先拆解方括号)
={ {int*, int*, int*}, {int*, int*, int*} }
int *(*)[3]
(小括号改变运算顺序, 先拆解星号)
={ int *[3], int *[3], ... }
(原有顺序, 先拆解方括号)
={ {int*, int*, int*}, {int*, int*, int*}, ... }
注意
可以观察到 int *[2][3]
其实是 int *(*)[3]
的一个特例。
换句话说 int *[2][3]
可以隐式转换为 int *(*)[3]
。
Powered by Waline v3.4.3