C 語言提供四種自增/自減運算符,核心差異在於「值的計算時機」與「副作用發生時機」:
| 運算符 | 名稱 | 語義 |
|---|---|---|
++i | 前綴自增 | 先自增 1,再參與運算,值為新值 |
--i | 前綴自減 | 先自減 1,再參與運算,值為新值 |
i++ | 後綴自增 | 先參與運算(值為舊值),再自增 1 |
i-- | 後綴自減 | 先參與運算(值為舊值),再自減 1 |
++iint i = 8;
printf("%d\n", ++i); // 輸出 9
// 說明:i 先自增為 9,再輸出
i++int i = 8;
printf("%d\n", i++); // 輸出 8
printf("%d\n", i); // 輸出 9
// 說明:先用舊值 8 參與運算,輸出後 i 變為 9
--iint i = 8;
printf("%d\n", --i); // 輸出 7
i--int i = 8;
printf("%d\n", i--); // 輸出 8
printf("%d\n", i); // 輸出 7
-i++ 與 -i--int i = 8;
printf("%d\n", -i++); // 輸出 -8,i 變 9
// 解析:等價於 -(i++),先取 i 舊值 8 加負號得 -8,再 i 自增
int i = 8;
printf("%d\n", -i--); // 輸出 -8,i 變 7
// 解析:等價於 -(i--),先取舊值 8 加負號,再 i 自減
-(++i) 與 -(--i)int i = 8;
printf("%d\n", -(++i)); // 輸出 -9,i 變 9
// 解析:先自增得 9,再加負號
int i = 8;
printf("%d\n", -(--i)); // 輸出 -7,i 變 7
// 解析:先自減得 7,再加負號
警告:單一表達式中對同一變數多次修改屬於未定義行為(UB),不同編譯器結果可能不同。以下僅供理解運算符結合性,實際編程中嚴禁使用。
(i++) + (i++) + (i++)int i = 5, p = (i++) + (i++) + (i++);
// 可能結果:p = 5+5+5 = 15,i = 8
// 實際取決於編譯器求值順序
(++i) + (++i) + (++i)int i = 5, p = (++i) + (++i) + (++i);
// 可能結果:i 先增至 7,前兩項 7+7=14,第三項增至 8,總和 22,i=8
| 表達式 | 結合順序 | 語義 |
|---|---|---|
*p++ | *(p++) | 先取 *p 值,再將指標 p 遞增 |
*p-- | *(p--) | 先取 *p 值,再將指標 p 遞減 |
(*p)++ | 先取 *p 值參與運算,再將所指值自增 | 值為舊值,所指記憶體內容 +1 |
(*p)-- | 先取 *p 值參與運算,再將所指值自減 | 值為舊值,所指記憶體內容 -1 |
*++p | *(++p) | 先將指標 p 遞增,再取新位置的值 |
*--p | *(--p) | 先將指標 p 遞減,再取新位置的值 |
++*p | ++(*p) | 先取值,再將所指值自增,值為新值 |
--*p | --(*p) | 先取值,再將所指值自減,值為新值 |
*(p++) | 同 *p++ | 括號僅為強調結合性 |
*(p--) | 同 *p-- | 括號僅為強調結合性 |
int a[5] = {1,8,10,5,2};
int *p = a;
printf("%d\n", *p++); // 輸出 1,p 指向 a[1]
printf("%d\n", *p); // 輸出 8
p = &a[1];
printf("%d\n", *p--); // 輸出 8,p 指向 a[0]
printf("%d\n", *p); // 輸出 1
p = a;
printf("%d\n", (*p)++); // 輸出 1,a[0] 變 2
printf("%d\n", *p); // 輸出 2
p = a;
printf("%d\n", (*p)--); // 輸出 1,a[0] 變 0
printf("%d\n", *p); // 輸出 0
p = a;
printf("%d\n", *++p); // p 先指向 a[1],輸出 8
p = &a[1];
printf("%d\n", *--p); // p 先指向 a[0],輸出 1
[] 優先級高於 *,*p++ 等價 *(p++)-Wall -Wextra -Wsequence-point 可捕捉多數 UB