在 C 語言中,指標運算子 * 與自增 ++/自減 -- 結合時,運算順序極易混淆。本文系統分析六種經典組合,透過實測程式碼與輸出結果,徹底釐清運算邏輯。
| 編號 | 表達式 | 運算順序 | 返回值 | 副作用 |
|---|---|---|---|---|
| 1 | *p++ | 先取值 *p,再 p++ | 原 *p 值 | 指標後移 |
| 2 | (*p)++ | 先取值 *p,再 *p++ | 原 *p 值 | 所指資料遞增 |
| 3 | *(p++) | 先取值 *p,再 p++ | 原 *p 值 | 指標後移(同 #1) |
| 4 | ++*p | 先 *p++,再取值 | 新 *p 值 | 所指資料遞增 |
| 5 | ++(*p) | 先 *p++,再取值 | 新 *p 值 | 所指資料遞增(同 #4) |
| 6 | *(++p) | 先 p++,再取值 *p | 新位置 *p 值 | 指標前移 |
#includeint main() { int a[3] = {1, 3, 5}; int *p = a; int i; // --- Case 1: *p++ --- printf("----------------1----------------\n"); printf("%d ", *p++); // 輸出 1 printf("%d ", *p); // 輸出 3 (p 已後移) for(i=0;i<3;i++) printf("%d ", a[i]); // 陣列未變: 1 3 5 printf("\n"); // --- Case 2: (*p)++ --- p = a; // 重置 printf("----------------2----------------\n"); printf("%d ", (*p)++); // 輸出 1 printf("%d ", *p); // 輸出 2 (a[0] 已變 2) for(i=0;i<3;i++) printf("%d ", a[i]); // 陣列變: 2 3 5 printf("\n"); // --- Case 3: *(p++) --- a[0] = 1; p = a; // 重置 printf("----------------3----------------\n"); printf("%d ", *(p++)); // 輸出 1 printf("%d ", *p); // 輸出 3 (p 已後移) for(i=0;i<3;i++) printf("%d ", a[i]); // 陣列未變: 1 3 5 printf("\n"); // --- Case 4: ++*p --- p = a; // 重置 printf("----------------4----------------\n"); printf("%d ", ++*p); // 輸出 2 (a[0] 先變 2) printf("%d ", *p); // 輸出 2 for(i=0;i<3;i++) printf("%d ", a[i]); // 陣列變: 2 3 5 printf("\n"); // --- Case 5: ++(*p) --- p = a; a[0] = 1; // 重置 printf("----------------5----------------\n"); printf("%d ", ++(*p)); // 輸出 2 printf("%d ", *p); // 輸出 2 for(i=0;i<3;i++) printf("%d ", a[i]); // 陣列變: 2 3 5 printf("\n"); // --- Case 6: *(++p) --- p = a; a[0] = 1; // 重置 printf("----------------6----------------\n"); printf("%d ", *(++p)); // 輸出 3 (p 先移到 a[1]) printf("%d ", *p); // 輸出 3 for(i=0;i<3;i++) printf("%d ", a[i]); // 陣列未變: 1 3 5 printf("\n"); return 0; }
p++、(*p)++ 先取值再副作用++*p、++(*p) 先副作用再取值* 與前綴 ++ 同級,右結合:++*p ≡ ++(*p),*(++p) 先遞增指標(*p)++ 強制先解參考再遞增資料
a[i++] 而非指標運算,可讀性更高指標與自增運算子的結合是 C 語言最經典的「陷阱題」之一。透過理解運算子優先級、結合方向與副作用時機三大核心,配合實測驗證,即可徹底掌握這六種組合的行為差異,寫出無歧義、可維護的程式碼。