int *p[10] → [](优先级高于 *)先结合 → p 是数组(指针数组)int (*p)[10] → * 先结合 → p 是指针(数组指针)一句话:"[] 优先级高,没括号 p 是数组;括号护住 *,p 才是指针。"
C 声明结合优先级:[](下标)比 *(解引用)高。判断身份 = 看变量名先跟谁结合——跟 [] 先结合是数组,被括号包住先跟 * 结合是指针。数组指针配 &a 或二维数组传参;指针数组就是"数组里装指针"。
int *p[10] —— 指针数组。p 先和 [10] 结合 → p 是数组,每个元素是 int *。用法:p[0] 是一个指针,指向别处的 intint (*p)[10] —— 数组指针。(p) 括号先和 * 结合 → p 是指针,指向 int[10] 整块。用法:int a[10]; int (*p)[10] = &a; (*p)[i] 取元素int m[3][4]; → 形参 int (*p)[4](指向一行的指针),退化成"指向第一行的指针"int *p[10] 是"指向数组的指针" → 错,[] 优先级高,p 先是数组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] 取元素,指向一整块 |
int a[2][3]; 传参 → 退化成指向第一行的指针,形参写 int (*p)[3]int *p[3]; 的 sizeof(p) = 12(3 个指针);int (*q)[3]; 的 sizeof(q) = 4(1 个指针)——身份不同,sizeof 立刻露馅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+1 要跨一整行);行数能省,因为退化成指针后只指向第一行,单个指针的步长跟有几行无关p+1 跨一整行 / &a+1 跨一整块——"指向什么类型,+1 就跨多大"p[1][2](p 是 int(*)[4])= 指向二维数组的第 1 行第 2 列(即 m[1][2]),不是报错| 相邻概念 | 和本主题的关系 | 孤立理解会犯的错 |
|---|---|---|
| 数组名 vs 指针 | &a 的类型就是 int(*)[N]——数组指针正好接 &a;a 退化成 int* |
把&a 和 a 混用,步长全错 |
| 二维数组传参 | int m[3][4] 传参退化 → int (*)[4](行指针),行数可省列数不可省 |
以为传二维数组要传int ** |
| 声明优先级 | [] > *,括号改结合 |
靠背名字而不是看结合 |
| 函数指针 | int (*fp)(int) 同款括号思想——括号护住 * 让 fp 先是指针 |
以为括号可有可无 |
2026-08-03
每主题一页,复习时只翻本目录。