C語言點運算子和箭頭運算子

2020-07-16 10:04:22
二元運算子 . 和 -> 常常被稱為點運算子(dot operator)和箭頭運算子(arrow operator),借助於這兩個運算子,可以選擇結構或聯合中的成員。

例 1 展示了點運算子的左運算元必須是一個結構或者一個聯合,而右運算元必須是該型別(結構或聯合)成員的名字。

【例1】
struct Article {  long number;      // 物品編號
                  char name[32];    // 物品名字
                  long price;       // 物品單價(精確到美分)
                  /* ... */
                };
struct Article sw = { 102030L, "Heroes", 5995L };
sw.price = 4995L;                   // 將價格改為49.95

點運算結果的型別,與所選擇成員的型別是一樣的。如果左運算元是一個左值,那麼該運算也會產生左值。如果左運算元的型別有限定符(例如被宣告為 const),那麼結果型別也有該限定符。

點運算子的左運算元並非一定是左值,如下例所示:
struct Article getArticle();                      // 函數原型
printf( "name: %sn", getArticle().name );

函數 getArticle()返回一個 struct Article 型別的物件。按此結果,getArticle().name 是一個有效的表示式,但不是一個左值,因為函數的返回值不是一個左值。

運算子 -> 也可用於選擇結構或聯合的成員,但是箭頭運算子的左運算元必須是一個指標,它指向一個結構或聯合型別右運算元是該結構或聯合成員的名字。例 2 展示了運算子->的用法,同樣使用例 1 所定義的結構 Article。

【例2】
struct Article *pArticle = &sw,     // 一個指向struct Article的指標
       const *pcArticle = &sw;      // 一個指向struct Article的唯讀指標

++(pArticle->number);                    // 增加編號
if ( pcArticle->number == 102031L ) // 正確:獲取唯讀指標
  pcArticle->price += 50;        // 錯誤:不能使用限定符const的指標來修改物件

箭頭運算子的結果總是一個左值。它具有被選取成員的型別,也同樣包括了其指標運算元的任何型別限定符。在例 2 中,pcArticle 是一個指向 const struct Article 的指標。其結果是,表示式 pcArticle->price 是一個常數。

包含箭頭運算子的任何表示式,都可以利用點運算子進行重寫,做法是先將指標解參考,然後使用點運算子:表示式 p->m 等效於(*p).m;相反地,如果 x 是左值的話,表示式 x.m 等效於(&x)->m。

和運算子 [] 一樣,點運算子 . 和箭頭運算子 -> 都具有最高的優先順序,並且組合方式都是從左到右。因此,表示式 ++p->m 等同於 ++(p->m),表示式 p->m++ 等同於(p->m)++。

然而,表示式(*p).m 中的括號是有必要的,因為復參照運算子 * 的優先順序比較低。表示式 *p.m 等效於 *(p.m),這種等效僅當在成員 m 是指標時才有意義。

我們通過結合下標運算子、點運算子和箭頭運算子,對一個元素為結構的陣列進行操作,來總結本文講述的問題:
struct Article arrArticle[10];       // 一個具有10個元素的陣列
                                                // 每個元素為結構型別
arrArticle[2].price = 990L;             // 設定陣列元素arrArticle[2]的成員price
arrArticle->number = 10100L;         // 設定陣列元素arrArticle[0]的成員number

一個陣列名稱,例如本例中的 arrArticle,是一個指向第一個陣列元素的常數指標。所以 arrArticle->number 指向第一個陣列元素的成員 number。簡單地說,對於任一的索引值 i,下面 3 個表示式是等價的:
arrArticle[i].number
(arrArticle+i)->number
(*(arrArticle+i)).number
它們都指向陣列中索引值為 i 的元素的成員 number。