| 概念 | 定義 | 可作為 | 範例 |
| 左值 | 代表記憶體位置的表達式,可出現在賦值號左側 | 賦值目標 | 變數 a、解參考 *p、陣列元素 arr[0] |
| 右值 | 代表資料值的表達式,可出現在賦值號右側 | 賦值來源 | 常數 10、變數值 a、運算結果 a+b、函數回傳 |
關鍵:某些表達式兼具兩者 (如 *p 既可讀值也可寫值)
基礎宣告環境
char ch = 'a'; // 位址假設 0x23
char *cp = &ch; // cp 位址假設 0x12,內容 0x23
經典指標表達式完整分析
| # | 表達式 | 右值意義 (讀取值) | 左值合法性 | 左值意義 (寫入位置) | 優先級解析 |
| 1 | &ch | ch 位址 (0x23) | ❌ 非法 | — | 取址運算子結果非左值 |
| 2 | cp | cp 內容 (0x23,即 ch 位址) | ✅ 合法 | cp 變數本身儲存空間 | 單一識別碼 |
| 3 | &cp | cp 位址 (0x12) | ❌ 非法 | — | 取址運算子結果非左值 |
| 4 | *cp | ch 的值 ('a') | ✅ 合法 | ch 的儲存空間 (0x23) | 解參考優先級高 |
| 5 | *cp + 1 | ch 值 + 1 ('b') | ❌ 非法 | — | * 高於 +,結果為暫時值 |
| 6 | *(cp + 1) | ch 下一個位址的值 | ✅ 合法 | ch 下一個位址空間 | 括號改變結合:先 cp+1 再 * |
| 7 | ++cp / cp++ | 前綴:新值(0x24);後綴:舊值(0x23) | ❌ 非法 | — | 運算結果為暫時值 (prvalue) |
| 8 | *++cp / *cp++ | 前綴:新位址值;後綴:舊位址值 | ✅ 合法 | 對應位址的儲存空間 | ++ 高於 *,右結合 |
運算子優先級與結合方向關鍵
優先級 (高→低):
1. 後綴: () [] -> . ++ --
2. 前綴: ++ -- * & sizeof (type) ~ !
3. 乘除: * / %
4. 加減: + -
5. 位移: << >>
6. 關係: < <= > >=
7. 相等: == !=
8. 位元 AND: &
9. 位元 XOR: ^
10. 位元 OR: |
11. 邏輯 AND: &&
12. 邏輯 OR: ||
13. 條件: ?:
14. 賦值: = += -= *= /= %= &= ^= |= <<= >>=
15. 逗號: ,
結合方向:多為左→右,賦值/前綴/條件為右→左
指標運算子優先級陷阱
*p++ // ≡ *(p++) : 取值後指標後移
(*p)++ // : 取值後所指資料遞增
*p++ // ≡ *(p++) : 同上
++*p // ≡ ++(*p) : 所指資料遞增後取值
++(*p) // : 同上
*++p // ≡ *(++p) : 指標前移後取值
實戰除錯技巧
- 加括號消除歧義:
*(p+1) 比 *p+1 明確
- 拆分複雜表達式:
// 難讀
*dst++ = *src++;
// 清晰
*dst = *src;
dst++;
src++;
- 編譯器警告:啟用
-Wsequence-point 偵測未定義行為
- 靜態分析:Clang Static Analyzer、Cppcheck 可捕獲指標誤用
為什麼要掌握這些「怪異」表達式?
- 閱讀舊代碼/開源庫:K&R 風格、系統級代碼大量使用
- 面試考題高頻:指標運算是 C 語言核心考點
- 深度理解指標本質:從語法糖透視記憶體操作本質
- 編寫高效底層代碼:編譯器優化提示、手動向量化前奏
結語
指標表達式是 C 語言威力與危險並存的雙面刃。精通左值/右值判定、運算子優先級與結合方向、解參考與遞增組合語意,配合括號明確意圖、拆分複雜鏈的防禦性編程習慣,即能安全駕馭指標威力,寫出高效、正確、可維護的系統級代碼。
- 上一篇文章: Objective-C 多執行緒建立兩大經典方法:initWithTarget 與 detachNewThreadSelector
- 下一篇文章: C 語言實作克魯斯克爾演算法:最小生成樹完整程式碼與邊界標記法優化
Copyright ©
程式碼之家 All Rights Reserved