解析:
这是一道关于 C 语言中**二维数组与指针数组/行指针**关系的经典题目。我们需要分析定义、初始化以及各个选项的语法和语义合法性。
### 1. 代码分析与修正
题目中的定义语句存在排版缺失,根据上下文 `pt=a` 和选项用法,完整的定义应为:
```c
int a[2][3], (*pt)[3];
pt = a;
```
* `int a[2][3]`:定义了一个 2 行 3 列的二维整型数组。
* `(*pt)[3]`:定义了一个**行指针**(或称数组指针),它指向包含 3 个整数的一维数组。
* `pt = a`:将二维数组 `a` 的首地址赋给 `pt`。此时,`pt` 指向 `a` 的第 0 行,`pt+1` 指向 `a` 的第 1 行。
**关键点:**
* `pt` 的类型是 `int (*)[3]`。
* `pt[i]` 等价于 `*(pt + i)`,其结果是一个一维数组名(即指向该行第 0 个元素的指针,类型为 `int *`)。
* `pt[i][j]` 等价于 `*(*(pt + i) + j)`,访问的是具体的 `int` 元素。
---
### 2. 选项逐一解析
#### A. `pt[0][0]`
* **分析**:
* `pt[0]` 等价于 `*(pt + 0)`,即指向第 0 行首元素的指针(类型为 `int *`)。
* `pt[0][0]` 等价于 `*(pt[0] + 0)`,即取第 0 行第 0 列的元素值。
* **结论**:这是合法的引用,对应 `a[0][0]`。
#### B. `*(pt+1)[2]`
* **分析**:
* 这里涉及运算符优先级。**下标运算符 `[]` 的优先级高于间接寻址运算符 `*`**。
* 因此,表达式 `*(pt+1)[2]` 被解析为 `* ( ((pt+1)[2]) )`。
* 让我们拆解 `(pt+1)[2]`:
* `pt+1` 指向数组 `a` 的第 1 行。
* `(pt+1)[2]` 等价于 `*((pt+1) + 2)`,即 `*(pt + 3)`。
* 这意味着它试图访问数组 `a` 的**第 3 行**(索引为 3)。
* 然而,数组 `a` 只有 2 行(索引为 0 和 1)。访问 `a[3]` 属于**数组越界**。
* 即使不考虑越界,从类型上看,`(pt+1)[2]` 的结果是一个 `int *` 类型的指针(指向第 3 行的首地址),最外层的 `*` 对其进行解引用得到 `int`。虽然语法上可能通过编译(取决于编译器对越界的检查),但在逻辑上它是**非法的内存访问**,因为它超出了数组定义的边界。
* **更常见的错误理解对比**:如果意图是访问第 1 行第 2 列,应该写成 `(*(pt+1))[2]` 或者 `pt[1][2]`。原写法因优先级问题导致了指针移动到了错误的位置(第 3 行)。
* **结论**:这是**非法引用**(数组越界)。
#### C. `*(pt[1]+2)`
* **分析**:
* `pt[1]` 等价于 `*(pt + 1)`,指向第 1 行第 0 个元素的地址(类型为 `int *`)。
* `pt[1] + 2` 将指针向后移动 2 个 `int` 位置,指向第 1 行第 2 个元素。
* `*(pt[1] + 2)` 对该地址解引用,获取该元素的值。
* 这等价于 `a[1][2]`。
* **结论**:这是合法的引用。
#### D. `*(a[0]+2)`
* **分析**:
* `a[0]` 是二维数组第 0 行的数组名,在表达式中退化为指向第 0 行第 0 个元素的指针(类型为 `int *`)。
* `a[0] + 2` 指向第 0 行第 2 个元素。
* `*(a[0] + 2)` 解引用获取该元素的值。
* 这等价于 `a[0][2]`。
* *(注:原题选项 D 缺少右括号 `)`,但这通常是印刷错误,从语义上看 `*(a[0]+2)` 是完全合法的)*。
* **结论**:这是合法的引用。
---
### 3. 最终结论
选项 **B** 由于运算符优先级的问题,导致指针偏移量计算错误,访问了超出数组边界的空间(第 3 行),因此是非法引用。
**正确答案:B**