C 語言教科書的附錄裡,總少不了一張「運算子優先序與結合性」的表格。許多初學者以為背熟這張表就萬事大吉,但在實際寫代碼或閱讀代碼時,卻常常在 a = *p++; 這類表達式上栽跟頭。本文將從運算子優先序與結合性的基本概念出發,層層剖析,帶你搞懂背後的核心邏輯,避開經典陷阱。
在 C 語言中,一個表達式的求值順序遵循兩大鐵律:
* 和 ++ 的優先序高於 =,所以 a = *p++ 等價於 a = (*p++),而非 (a = *p)++。= 為右結合,所以 a = b = c = 0 實際上是 a = (b = (c = 0)),從右向左依次執行。很多書上寫 *(間接取值)和 ++(前綴/後綴)同屬第 2 級優先序,結合方向自右向左。照此邏輯,*p++ 應解析為 *(p++) —— 這其實是正確的!但為什麼初學者會困惑?關鍵在於對「後綴 ++ 運算語義」的誤解。
「後綴 ++ 是先用值,再加 1。」
這句話聽起來合理,實則極不嚴謹。它誤導初學者以為 int j = i++; 是「先賦值給 j,再將 i 加 1」。但賦值運算子 = 優先序遠低於後綴 ++,若真按「先賦值」執行,違背了優先序規則。
前綴 ++ 與後綴 ++ 都是「先將變數加 1」,差別在於「運算表達式的結果值」不同:
從效果上看,i++ 等價於逗號表達式 (tmp = i, ++i, tmp)(其中 tmp 為臨時變數)。
回到 a = *p++;:
++ 優先序高於 *,故結合為 *(p++)。p++:先取出 p 當前值(舊地址)參與 * 運算,然後將 p 本身加 1(指向下一個元素)。* 運算,取出該地址的內容。結果:a 獲得的是 p 遞增前所指向的元素值,而 p 已指向下一個元素。 這正是 C 語言處理字串、陣列遍歷的標準慣用法。
掌握這些核心細節,你就能輕鬆駕馭 C 語言中最靈活也最危險的指標運算表達式了。