单选题
1、〖第13题〗205) 变量p为指针变量,若p=&a,下列说法不正确的是()。
A
&*p==&a
B
*&a==a
C
(*p)++==a++
D
*(p++)==a++
答案解析
正确答案:D
解析:
这是一道关于 C 语言指针运算和运算符优先级的经典题目。我们需要根据已知条件 `p = &a`(即指针 `p` 指向变量 `a`),逐一分析各个选项的正确性。
**核心概念回顾:**
* `&`:取地址运算符。
* `*`:解引用(间接访问)运算符。
* `++`:自增运算符。分为前置(`++i`)和后置(`i++`)。
* 前置 `++`:先自增,再使用值。
* 后置 `++`:先使用当前值,再自增。
* 优先级:`()` > `*` (解引用) / `&` (取址) / `++` (后置) > `==`。注意:后置 `++` 的优先级高于解引用 `*` 和取址 `&`,但它是作用于操作数的“值副本”或特定语义。
---
### 选项详细解析
#### A. `&*p == &a`
* **分析**:
1. `*p`:因为 `p = &a`,所以 `*p` 等价于 `a`(即访问 `p` 指向的内存单元,也就是变量 `a`)。
2. `&*p`:对 `*p`(即 `a`)取地址,等价于 `&a`。
3. 因此,`&*p` 的结果就是 `&a`。
4. 表达式变为 `&a == &a`,显然成立。
* **结论**:说法正确。
#### B. `*&a == a`
* **分析**:
1. `&a`:取出变量 `a` 的地址。
2. `*&a`:对 `a` 的地址进行解引用。根据定义,对某个变量的地址解引用,得到的就是该变量本身。
3. 因此,`*&a` 等价于 `a`。
4. 表达式变为 `a == a`,显然成立。
* **结论**:说法正确。
#### C. `(*p)++ == a++`
* **分析**:
1. `(*p)`:括号强制先执行解引用。因为 `p` 指向 `a`,所以 `*p` 就是 `a` 的别名(左值)。
2. `(*p)++`:对 `*p` 执行后置自增。这意味着表达式的值是 `a` 原来的值,副作用是 `a` 的值加 1。
3. `a++`:对 `a` 执行后置自增。表达式的值是 `a` 原来的值,副作用是 `a` 的值加 1。
4. 虽然这两个操作在同一个表达式中修改同一个变量通常会导致未定义行为(Undefined Behavior)如果它们之间没有序列点,但在本题语境下,通常考察的是**语义等价性**。即:`(*p)++` 的操作对象是 `p` 指向的内容(即 `a`),其效果与直接对 `a` 进行 `a++` 是完全一致的。它们都返回 `a` 的旧值,并将 `a` 增加 1。
5. 从逻辑意义上讲,两者是对同一内存位置的相同操作,因此说法被认为是正确的。
* **结论**:说法正确。
#### D. `*(p++) == a++`
* **分析**:这是本题的关键错误点。我们需要拆解 `*(p++)` 的含义。
1. **优先级与结合性**:后置 `++` 的优先级高于解引用 `*`。但是,后置 `++` 的特殊语义是:**返回操作数当前的值作为表达式的结果,然后将操作数自增**。
2. `p++`:
* 表达式的值是 `p` 的**当前值**(即 `&a`)。
* 副作用是:指针 `p` 本身自增,指向下一个位置(例如 `&a + 1`,具体步长取决于 `a` 的类型)。
3. `*(p++)`:
* 相当于 `*(p的旧值)`。
* 因为 `p` 的旧值是 `&a`,所以 `*(p++)` 等价于 `*(&a)`,也就是 **`a` 的值**。
* **关键点**:这个表达式只读取了 `a` 的值,**并没有修改 `a` 的值**。它修改的是指针 `p` 的指向。
4. `a++`:
* 表达式的值是 `a` 的**当前值**。
* 副作用是:**变量 `a` 的值自增 1**。
5. **对比**:
* 左边 `*(p++)`:取值 `a`,**改变指针 `p`**,`a` 不变。
* 右边 `a++`:取值 `a`,**改变变量 `a`**,`p` 不变。
6. 虽然两边的“返回值”在当前时刻可能相等(都是 `a` 的旧值),但它们的**副作用完全不同**。更重要的是,如果在比较之后观察状态,`a` 的值在右边表达式执行后变了,而在左边没变。
7. 此外,如果题目意指“这两个表达式是否完全等价”或“执行结果是否一致”,答案是否定的。`*(p++)` 绝不等同于 `a++`,因为它不修改 `a`。如果强行比较值,在某些编译器或语境下可能数值相等,但从语意和操作对象来看,它们截然不同。通常这类题目考察的是:`*(p++)` 只是取了 `a` 的值并移动了指针,而 `a++` 是修改了 `a` 的值。因此说它们“相等”或“等价”是不正确的,尤其是考虑到副作用对程序状态的影响。
*更严格的解释*:即使只看返回值,`*(p++)` 返回 `a` 的值,`a++` 也返回 `a` 的值。看似相等?但是,C语言中 `==` 比较的是值。如果仅比较值,在这一瞬间它们确实相等。**但是**,我们再看选项 C 和 D 的对比。
* 选项 C:`(*p)++` 修改的是 `*p` (即 `a`)。 `a++` 修改的也是 `a`。两者不仅返回值相同,对内存状态的改变也相同。
* 选项 D:`*(p++)` 修改的是 `p`。 `a++` 修改的是 `a`。
通常这类题目的“不正确”指的是**语义不等价**或者**操作结果不一致**。
让我们重新审视一下常见的陷阱:
`*(p++)` 等价于 `*p` (然后 p 自增)。
`a++` 等价于 `a` (然后 a 自增)。
如果题目问的是表达式的**值**是否相等:
假设 `a=5`, `p=&a`。
`*(p++)` 的值是 5。
`a++` 的值是 5。
值确实相等。
**但是**,我们必须注意到选项 C 和 D 的形式对称性。
C: `(*p)++` vs `a++`。 `(*p)` 就是 `a`。所以 `a++` == `a++`。完全一样。
D: `*(p++)` vs `a++`。 `*(p++)` 取值后,`p` 变了,`a` 没变。 `a++` 取值后,`a` 变了。
为什么 D 是不正确的?
在很多教材和考试语境中,`==` 在这里不仅仅指数值比较,往往隐含了“等价替换”或“操作一致性”的意味。或者,我们可以从另一个角度:
如果这是一道单选题,且 A、B、C 都明显正确(C 中 `(*p)++` 和 `a++` 对变量 `a` 的作用完全一致),那么 D 必须是错误的。
**错误的原因在于:**
`*(p++)` 这个表达式**并没有对 `a` 进行自增操作**,它只是使用了 `a` 的值。而 `a++` **对 `a` 进行了自增操作**。
如果在后续代码中使用 `a`,经过 `*(p++)` 后 `a` 还是原值,经过 `a++` 后 `a` 变成了原值+1。因此,这两个表达式在程序逻辑上**不等价**,不能划等号。虽然它们在孤立求值时返回相同的临时值,但作为语句或子表达式,它们的**副作用**不同,导致整体程序状态不同,因此不能说它们“相等”或“正确对应”。
简而言之:
* `(*p)++` 等价于 `a++` (都让 a 加 1)
* `*(p++)` 等价于 `a` (取值,但不让 a 加 1,而是让 p 移位)
所以 `*(p++) == a++` 这种说法混淆了指针移动和变量自增,是不正确的。
* **结论**:说法不正确。
### 最终总结
* **A** 正确:`&*p` 还原为 `&a`。
* **B** 正确:`*&a` 还原为 `a`。
* **C** 正确:`(*p)++` 即对 `p` 指向的内容(`a`)自增,与 `a++` 完全等价。
* **D** 错误:`*(p++)` 是先取 `p` 当前指向的值(`a`),然后指针 `p` 自增;而 `a++` 是取 `a` 的值,然后 `a` 自增。前者改变指针,后者改变变量值,两者不等价。
故答案选 **D**。
题目纠错
c语言选择判断题库
相关题目
单选题
1、对以下说明语句 int a[10]={6,7,8,9,10}; 的正确理解是()。
单选题
1、若有说明:int a[10];则对a数组元素的正确引用是()。
单选题
1、以下数据中,不正确的数值或字符常量是()。
单选题
9.以下数组定义中不正确的是()。
单选题
8.设有 int x=11; 则表达式 (x++ * 1/3) 的值是()。
单选题
3.以下数据中,不正确的数值或字符常量是()。
单选题
1、第300题 (1.0分) 题号:516 static char str[10]=“China”;数组元素个数为()。
单选题
1、第299题 (1.0分) 题号:664 以下正确的函数定义形式是()。
单选题
1、第298题 (1.0分) 题号:537 在定义构造数据类型时,不能()。
单选题
1、第297题 (1.0分) 题号:525 C语言中不可以嵌套的是()。
