接下來,通過示例徹底理解自增運算符的兩種用法(自減的用法與之類似,只不過是加1變成了減1)。 1、++i和i++的區別 如清單1(注意代碼中的注釋): [cpp] #include <stdio.h> int main(void) { int a, b, i = 7; i++; //等價於i = i + 1; ++i; //等價於i = i + 1; a = i++; //等價於a = i; i = i + 1; b = ++i; //等價於i = i + 1; b = i; printf("a = %d, b = %d\n", a, b); return 0; } 例子輸出結果: [cpp] a = 9, b = 11 在例子中,第7和第8行的作用一樣,僅僅是為變量i加1,這時i的值已經增加為9,接下來第10行變量a先獲得i的值(即9),然後i加1,第11行變量i先再加1,然後把得到的值賦給b,所以b的值為11。 稍微復雜的例子,如清單2: [cpp] #include <stdio.h> int main(void) { int a = 5; int *p = &a; int b = (*p)++; //等價於b = a++; 即b = a; a = a + 1; int c = ++(*p); //等價於c = ++a; 即a = a + 1; c = a; printf("b = %d, c = %d\n", b, c); printf("(*p)++ = %d, ++(*p) = %d\n", (*p)++, ++(*p)); return 0; } 例子輸出結果: [cpp] b = 5, c = 7 (*p)++ = 8, ++(*p) = 8 在這個例子中,只不過是通過*p來間接地操作a,其他關於自增運算符的用法與清單1類似。第9行的*p一定要用小括號括起來,否則含義就不一樣了。而第11行的++(*p)也可以寫成++*p(用GCC驗證過),那是因為對操作數p來說它只有一個運算符*在計算它,所以無關乎運算符優先級和結合性的問題。 值得注意的是,由於C語言沒有指定函數各參數的求值順序,所以第15行的代碼是不可移植的,用不同的編譯器可能會產生不同的結果(對於這個例子,GCC是先計算++(*p),後計算(*p)++,所以兩者都等於8)。 知識點: (1)、副作用 在對表達式求值的同時,修改了某些變量的值,其中修改值的行為在C語言中被叫作副作用,那是因為對C語言而言,計算的目的就是對表達式求值,如語句int a = 5,它的含義是先求值得到5,然後把5賦值給變量a,後一步的賦值就是此表達式的副作用。自增和自減運算符就是因為副作用而被使用,除了加1或減1之外,還給自身賦值。 (2)、運算符的優先級 在C語言中,把運算符的優先級分為15級,如下表,從上到下,依次為從最高優先級到最低優先級(為了方便記憶,將15級分成11類,並對每類進行了命名)。 初等運算符 包括小括號 ()、中括號 [] 、成員訪問運算符 . 和 -> 。 一元運算符 包括自增++和自減--、正負號+ 和-、間接運算*和取址運算& 、類型轉換(type)、 sizeof 、邏輯反! 、位取反~等。 算術運算符 包括兩級,先乘除(*、/、%)後加減(+、-)。 位移運算符 包括左移 << 和右移 >> 。 關系運算符 包括小於 < 、小於等於 <= 、大於 > 、大於等於 >= 。 判等運算符 包括相等 == 和不相等 != 。 位邏輯運算符 分三級,依次為位與 &、位異或 ^ 和位或 | 。 邏輯運算符 分兩級,依次為邏輯與 && 和邏輯或 || 。 條件運算符 ? : 賦值運算符 包括= 、+= 、-=、 *=、 /=、 %= 、&= 、^=、 |= 、<<= 、>>= 。 逗號運算符 , (3)、結合性 對於同一操作數,在具有兩個相同優先級的操作符時決定先執行哪個操作符的問題就是由結合性決定的。 相同優先級的操作符具有同樣的結合性。右結合性就是說表達式中最右邊的操作最先執行,然後從右到左依次執行。在C語言中,具有右結合性的操作符只有相應的三類,分別為一元運算符、條件運算符和賦值運算符。 注意:C語言中的優先級和結合性都是針對同一操作數而言的。如表達式24/8*2,對於操作數8而言,/ 和*的優先級相同,所以再根據它們的左結合性可知,表達式是先計算24/8得到3,然後計算3*2得到6。 C語言並沒有規定同一運算符相關的多個操作數的計算順序(&&、|| 、? : 和 , 運算符除外),如式子a = 8 * 9 + 20 * 4,對操作數9和20而言,根據優先級就可判斷先乘後加,但表達式中的兩個*並不共享同一操作數,所以從左到右的結合性並不適用它,8 * 9 和20 * 4的計算順序是不定的,到底先計算8 * 9還是20 * 4由編譯器決定。 在上面例子中,8 * 9和20 * 4誰先執行都不影響最後結果的一致,但有些情況下就未必了,如“ b = 3; a = (b++) * (b++); ”這樣的例子,對於不同的編譯器最後a的值可能等於9,也可能等於12,甚至可能等於16。因此,在實際應用中不能出現這樣的未確定性,根據自己的需要,可以把它改成類似“b = 3; c = b++; a = c * c;”這樣的形式。 2、*p++和*++p的區別 舉例,如清單3: [cpp] #include <stdio.h> int main(void) { int arr[] = {1, 2, 3, 4}; int *p = arr; int a = *p++; //等價於a = *(p++); 即a = *p; p = p + 1; int b = *++p; //等價於b = *(++p); 即p = p + 1; b = *p; printf("a = %d, b = %d\n", a, b); return 0; } 例子輸出結果: [cpp] a = 1, b = 3 對於第8行的操作數p而言,*和++的優先級相同,但根據它們的右結合性可知,在這個表達式裡可認為++的優先級高於*,即*p++等價於*(p++)。 而對於第10行的操作數p而言,它只有一個運算符++,所以先計算++p得出結果,然後間接運算。