指針解引用*與自增++/自減--組合時,優先級與結合性極易混淆。本文通過代碼實測,徹底釐清6種組合的求值順序與副作用差異。
#include <stdio.h>
int main() {
int a[3] = {1,3,5};
int *p, i;
// 1. *p++
p = a; printf("-----1: *p++ -----\n");
printf("return: %d, *p after: %d\n", *p++, *p);
for(i=0;i<3;i++) printf("%d ", a[i]); puts("");
// 2. (*p)++
p = a; printf("-----2: (*p)++ -----\n");
printf("return: %d, *p after: %d\n", (*p)++, *p);
for(i=0;i<3;i++) printf("%d ", a[i]); puts("");
// 3. *(p++)
p = a; printf("-----3: *(p++) -----\n");
printf("return: %d, *p after: %d\n", *(p++), *p);
for(i=0;i<3;i++) printf("%d ", a[i]); puts("");
// 4. ++*p
p = a; printf("-----4: ++*p -----\n");
printf("return: %d, *p after: %d\n", ++*p, *p);
for(i=0;i<3;i++) printf("%d ", a[i]); puts("");
// 5. ++(*p)
p = a; a[0]=1; printf("-----5: ++(*p) -----\n");
printf("return: %d, *p after: %d\n", ++(*p), *p);
for(i=0;i<3;i++) printf("%d ", a[i]); puts("");
// 6. *(++p)
p = a; a[0]=1; printf("-----6: *(++p) -----\n");
printf("return: %d, *p after: %d\n", *(++p), *p);
for(i=0;i<3;i++) printf("%d ", a[i]); puts("");
return 0;
}
輸出結果:
-----1: *p++ ----- return: 1, *p after: 3 1 3 5 -----2: (*p)++ ----- return: 1, *p after: 2 2 3 5 -----3: *(p++) ----- return: 1, *p after: 3 1 3 5 -----4: ++*p ----- return: 2, *p after: 2 2 3 5 -----5: ++(*p) ----- return: 2, *p after: 2 2 3 5 -----6: *(++p) ----- return: 3, *p after: 3 1 3 5
| 表達式 | 運算順序 | 返回值 | 副作用 | 等價寫法 |
|---|---|---|---|---|
*p++ | ①取*p值 ②p++ | 舊*p值 | 指針後移 | *(p++) |
(*p)++ | ①取*p值 ②*p值++ | 舊*p值 | 所指對象值+1 | — |
*(p++) | ①取*p值 ②p++ | 舊*p值 | 指針後移 | *p++ |
++*p | ①*p值++ ②取新*p值 | 新*p值 | 所指對象值+1 | ++(*p) |
++(*p) | ①*p值++ ②取新*p值 | 新*p值 | 所指對象值+1 | ++*p |
*(++p) | ①p++ ②取新*p值 | 新位置的值 | 指針後移 | *++p |
p++、(*p)++):先取值,後副作用。返回舊值。++*p、++p):先副作用,後取值。返回新值。*p++ ≡ *(p++):++綁定p(指針移動)。(*p)++:++綁定*p(對象值修改)。++*p ≡ ++(*p):++綁定*p(對象值修改)。*(++p):++綁定p(指針移動)。// 易讀、無歧義
int val = *p;
p++;
// 或
(*p)++;
// 或
p++;
int val = *p;
(*p)++、*(p++)、++(*p)、*(++p)。理解運算符優先級(++/-- > *(解引用)> *(乘法))與結合性,配合括號顯式分組,是寫出無歧義指針代碼的鑰匙。