数组指针、指针数组与二级指针
概念说明
这一节最容易混淆的不是概念本身,而是声明语法太像。 可以先用一句话区分三类写法:
int (*p)[3]:p是“指向数组的指针”,常叫数组指针。int *p[3]:p是“由 3 个指针组成的数组”,常叫指针数组。int **pp:pp是“指向一级指针的指针”,也就是二级指针。
真正读懂这些写法的关键,是记住 [] 的优先级高于 *。
所以很多时候,括号不是装饰,而是决定类型含义的必要部分。
这些类型都不是为了“故意刁难语法”。 它们在字符串列表、二维数组、命令行参数和需要间接修改指针本身的场景里都非常常见。
语法/规则
int (*p)[3]表示p指向一个包含 3 个int的数组。int *p[3]表示p是一个数组,其中每个元素都是int *。int **pp表示pp指向一个int *类型对象。char *argv[]本质上就是一个指针数组,因此命令行参数天然和这部分知识有关。- 二维数组常和数组指针配合,例如
int (*row)[4] = matrix;。 int **不能直接替代二维数组指针,因为它们期望的内存布局不同。- 读复杂声明时,可以从变量名开始向外看,优先判断它是“数组”还是“指针”。
示例
指针数组
| |
输出结果:
| |
数组指针和二级指针
| |
输出结果:
| |
常见错误
- 忘记
[]的优先级高于*,结果把数组指针和指针数组完全看反。 - 在二维数组场景里误用
int **,导致类型不匹配或访问方式错误。 - 看见两个星号就只记“更复杂的指针”,却没弄清它到底指向的是什么类型。
- 复杂指针声明里省略必要括号,结果声明含义和自己想的完全不同。
- 没把“变量名往外读”的习惯建立起来,导致每次遇到复杂声明都只能硬背。