以自增運算符為例,當自增運算符++作用於一個變量時,例如:當i=3時++i這個算術表達式的值為4,同時變量i的值也由原來的3改變為4。一般情況下,計算表達式后不改變變量本身的值,而++運算符和--運算符組成的表達式計算后,則改變變量的值,這稱為運算符的副作用。這類運算符在計算表達式時,一定要注意區分表達式的值和變量的值。
2 注意前綴運算和后綴運算的區別
仍以自增運算符為例,該運算符可作用在變量之前,例如前面所講的++i,稱為前綴運算;也可作用在變量之后,例如i++,稱為后綴運算。在這兩種運算中,表達式的值不同:前綴運算后,表達式的值為原變量值加1;后綴運算后,表達式的值仍為原變量值;而變量值不論前綴運算還是后綴運算都加1。自減運算符與自增運算符類似,只要將加1改為減1即可。即前綴運算是“先變后用”,而后綴運算是“先用后變”。
3 注意運算符的運算對象
自增、自減運算符只能作用於變量,而不能作用於常量或表達式。因為自增、自減運算符具有對運算量重新賦值的功能,而常量、表達式無存儲單元可言,當然不能做自增、自減運算。只要是標准類型的變量,不管是整型、實型,還是字符型、枚舉型都可以作為這兩個運算符的運算對象。如以下四個表達式都是合法的:i+++j++、++i+(++j)、++a+b++、++array[--j];而++6、(i+j)++、‘A’++、++i+++j、(&p)++這五個表達式卻是不合法的。為什么i+++j++合法,而++i+++j卻不合法?C的編譯器對程序編譯時,從左到右盡可能多地將字符組合成一個運算符或標識符,因此i+++j++等效於(i++)+(j++),兩個“++”作用的對象都是變量,這是合法的;而++i+++j等效於++(i++)+j,第1個“++”作用的對象是表達式“i++”,這是不允許的。
4 注意運算符的結合方向
表達式k=-i++等效於k=(-i)++還是k=-(i++)?因為負號運算符和自增運算符優先級相同,哪一個正確就得看結合方向。自增、自減運算符及負號運算符的結合方向是從右向左。因此,上式等效於k=-(i++);若i=5,則表達式k=-i++運算之后k的值為-5,i的值為6。此賦值表達式的值即為所賦的值-5。不要因為k=-i++等效於k=-(i++)就先做“++”運算!這里采用的是“先用后變”,即先拿出i的值做負號“-”運算,把這個值賦給變量k之后變量i才自增。(PS:
二、 ++和--運算級別:
++和--的運算級別在我們當前所接觸的運算符號中低於圓擴弧(),與正(+)和負(-)同級別,高於其它所有的算術符號和賦值符號。如下:
最高級別:()
次高級別:++ -- +(正) -(負) (同級別自右向左運算)
第三級別: * / % (同級別自左向右運算)
第四級別: +(加) -(減) (同級別自左向右運算)
最低級別: = += -= *= /= %= (同級別自右向左運算)
注意:只有同級別運算符號結合在一起時,才有運算方向問題,不同級別只有先高后低的概念。
在程序設計中,經常遇到“i=i+1”和“i=i-1”這兩種極為常用的操作。變量i被稱為“計數器”,用來記錄完成某一操作的次數。C語言為這種計數器操作提供了兩個更為簡潔的運算符,即++和--,分別叫做自增運算符和自減運算符。它們是從右向左結合的一元算術運算符,優先級為2。學習和應用這兩個運算符時應注意以下幾點:
1 注意表達式的值和變量值的區別
)
5 注意運算符的副作用
C語言允許在一個表達式中使用一個以上的賦值類運算,包括賦值運算符、自增運算符、自減運算符等。這種靈活性使程序簡潔,但同時也會引起副作用。這種副作用主要表現在:使程序費解,並易於發生誤解或錯誤。例如,當i=3時,表達式(i++)+(i++)+(i++)的值為多少,各種教材說法不統一:有的認為是9(3+3+3,如譚浩強的《C程序設計》,清華大學出版社,1991);也有的認為是12(3+4+5,如王森的《C語言程序設計》,電子工業出版社,1995)。到底哪一個說法正確呢?不妨看看下面這個程序的運行情況:
main( )
{int i,j;
i=3; j=(i++)+(i++)+(i++); printf(“\nj=%d,”j);
i=3; printf(“j=%d”,(i++)+(i++)+(i++));
}
在TC3.0上運行,其結果則是:j=9,j=12,究其原因,“先用后變,先變后用“中的“先”和“后”是一個模糊的概念,很難給出順序或時間上的准確定論。“先”到什么時候,“后”到什么程度?沒有此方面的詳細資料可供查詢。
為此,筆者用各種表達式上機測試,結果發現當表達式的值作為printf函數的直接輸出對象時,“先變后用”和“先用后變”中的“后”就是指++i和i++這一小項運算完之后,如上面程序中最后一個語句中的輸出對象:第一個(i++)取出i的值3以后i立即變為4,第二個(i++)取出i的值4以后i立即變為5,第三個(i++)取出i的值5以后i立即變為6,這樣輸出的結果便是3+4+5這個表達式的值,即12。而在其它一些表達式或語句中,“變”或“用”的時機卻很難掌握。下列各式中變量j的值都是在i=3,k=1的前提下求出的:
后綴運算:
(1)j=(5,6,(i++)+(i++)+(i++)): j=9(3+3+3)
(2)j=(k++,6,(i++)+(i++)+(i++)): j=9(3+3+3)
(3)j=1?(i++)+(i++)+(i++): 0: j=9(3+3+3)
(4)j=i?(i++)+(i++)+(i++): 0: j=12(3+4+5)
(5)j=k++?(i++)+(i++)+(i++): 0: j=12(3+4+5)
前綴運算:
(6)j=(5,i,(++i)+(++i)+(++i)): j=18(6+6+6)
(7)j=(5,k++,(++i)+(++i)+(++i)): j=15(4+5+6)
(8)j=1?(++i)+(++i)+(++i): 0: j=18(6+6+6)
(9)j=1?(k++,(+i)+(++i)+++i)): 0: j=15(4+5+6)
(10)j=k++?(++i)+(++i)+(++i): 0: j=15(4+5+6)
其中(3)和(4)、(6)和(7)、(8)和(10)等這幾對類型相同的表達式卻得到完全不同的運算結果,令人費解!由此可見,在一般表達式中,就i++來說,“先用后變”中何時“變”很難說得清楚;對++i來說,“先變后用”中何時“用”也不易道白(自減運算符與此類似)。因此,讀者在使用這類運算符時一定要特別注意。
克服這類副作用的方法是,盡量把程序寫得易懂一些,即將費解處分解成若干個語句。如:k=i+++j:可寫成k=i+j:i++:而類似(i++)+(i++)+(i++)這類連續自增、自減的運算最好不要使用,以避免疑團的出現,同時也可減少程序出錯的可性能。
在程序設計中,效率和易讀性是一對主要矛盾。為了提高程序的效率,需要用技巧把程序寫得盡可能簡潔一些,但這樣有可能降低程序的可讀性和可理解性。可讀性差的程序容易隱藏錯誤且難於糾正,不易維護,降低了程序的可靠性。鑒於“軟件危機”的教訓,人們在程序設計時遵守的基本規范是:可靠性第一,效率第二。為了保證可靠性,程序必須清晰易讀,而表達式的清晰易讀是十分重要的方面。因此,在C程序設計中,要慎重使用自增、自減運算符,特別是在一個表達式中不要多處出現變量的自增、自減等運算。
