7.数组指针-vs-指针数组.md 4.2 KB

数组指针 vs 指针数组

判别规则(核心,唯一要记的)

  • 看变量名先跟谁结合:无括号 int *p[10][](优先级高于 *)先结合 → p 是数组(指针数组)
  • 有括号 int (*p)[10]* 先结合 → p 是指针(数组指针)

一句话:"[] 优先级高,没括号 p 是数组;括号护住 *,p 才是指针。"

抽象描述(一句话本质)

C 声明结合优先级:[](下标)比 *(解引用)高。判断身份 = 看变量名先跟谁结合——跟 [] 先结合是数组,被括号包住先跟 * 结合是指针。数组指针配 &a 或二维数组传参;指针数组就是"数组里装指针"。

正反例(建立直觉)

  • 正例1int *p[10] —— 指针数组。p 先和 [10] 结合 → p 是数组,每个元素是 int *。用法:p[0] 是一个指针,指向别处的 int
  • 正例2int (*p)[10] —— 数组指针。(p) 括号先和 * 结合 → p 是指针,指向 int[10] 整块。用法:int a[10]; int (*p)[10] = &a; (*p)[i] 取元素
  • 正例3:二维数组传参 int m[3][4]; → 形参 int (*p)[4](指向一行的指针),退化成"指向第一行的指针"
  • 反例1:背反——以为 int *p[10] 是"指向数组的指针" → 错,[] 优先级高,p 先是数组
  • 反例2:以为 int (*p)[10] 能指向任意 int → 错,只能指向 int[10]int x; int (*p)[10] = &x; 类型不匹配报错

易混对比

int *p[10] int (*p)[10]
p 是什么 数组(10 个指针) 指针(指向 int[10])
名字 指针数组 数组指针
为什么 无括号,[] 优先级高先结合 (p) 括号先和 * 结合
怎么用 p[0] 是指针,指向单个 int (*p)[i] 取元素,指向一整块

变体验证(3 题,全过=学会)

  1. int a[2][3]; 传参 → 退化成指向第一行的指针,形参写 int (*p)[3]
  2. 陷阱题:32 位平台上 int *p[3];sizeof(p) = 12(3 个指针);int (*q)[3];sizeof(q) = 4(1 个指针)——身份不同,sizeof 立刻露馅
  3. int arr[5]; int (*pa)[5] = &arr;(*pa)[2]pa[0][2]arr[2] 三者完全相等,不报错pa[0] 解引用出 arr 本身);真正越界的是 pa[1][2]——pa+1 跨过整整一块 int[5]

口述要点(面试怎么讲)

  • 结论先行:看变量名先跟谁结合——无括号 [] 优先 = 数组;括号护 * = 指针
  • 为什么一个括号改变一切[] 优先级高于 *,括号强制改变结合顺序,类型就完全不同
  • 二维数组传参为什么列数不能省:列数决定"一行多大",指针运算步长需要它, 这样才能运算p[i][j](p+1 要跨一整行);行数能省,因为退化成指针后只指向第一行,单个指针的步长跟有几行无关
  • 步长思想p+1 跨一整行 / &a+1 跨一整块——"指向什么类型,+1 就跨多大"
  • 易错点p[1][2](p 是 int(*)[4])= 指向二维数组的第 1 行第 2 列(即 m[1][2]),不是报错

关系网络

相邻概念 和本主题的关系 孤立理解会犯的错
数组名 vs 指针 &a 的类型就是 int(*)[N]——数组指针正好接 &aa 退化成 int* &aa 混用,步长全错
二维数组传参 int m[3][4] 传参退化 → int (*)[4](行指针),行数可省列数不可省 以为传二维数组要传int **
声明优先级 [] > *,括号改结合 靠背名字而不是看结合
函数指针 int (*fp)(int) 同款括号思想——括号护住 * 让 fp 先是指针 以为括号可有可无

学习日期

2026-08-03


每主题一页,复习时只翻本目录。