陳松
摘要:自增、自減語句是C語言初學(xué)者使用時最容易出錯的運算符類語句。在VC平臺上,自增、自減運算符出現(xiàn)在printf輸出語句中時,有些例題執(zhí)行結(jié)果較難理解。這是因為VC平臺下語句編譯處理的順序有其自身的特點,需要了解這些特點,才能更好地分析自增、自減運算符的使用方法。
關(guān)鍵詞:自增(自減)語句;VC平臺;編譯順序
中圖分類號:TP311 文獻(xiàn)標(biāo)識碼:A 文章編號:1009-3044(2016)15-0072-02
Abstract: Self increment and decrement statementis C language beginners use the most error prone operator. On the platform of VC, self increment and decrement operators in printf output statements, some examples of results difficult to understand. This is because the VC platform compiler processing sequence has its own characteristics, the need to understand these characteristics, in order to better analysis of the self increasing, the use of the reduction operator.
Key words: Self increment(decrement) statemente; VC platform; Compile order
自1972年投入使用之后,C語言成為Unix和Xenix操作系統(tǒng)的主要語言,是當(dāng)今最為廣泛使用的程序設(shè)計語言。目前各大高校的計算機及理工類專業(yè)的本、??拼蠖鄶?shù)都開設(shè)了C語言。C語言教學(xué)內(nèi)容主要包括概論,數(shù)據(jù)類型、運算和輸入輸出,順序、選擇、循環(huán)結(jié)構(gòu)程序設(shè)計、數(shù)組、函數(shù)、指針、結(jié)構(gòu)體和共用體等內(nèi)容[1]。學(xué)生在剛開始接觸C語言時,往往會被C語言的數(shù)據(jù)類型、基本語法規(guī)則、輸入輸出格式等弄得煩不勝煩。不過這些知識點本身難度都不大,隨著后續(xù)使用的增多,學(xué)生都會慢慢熟悉并掌握。而在C語言教學(xué)的開始階段,學(xué)生普遍覺得較難理解的問題中主要集中在自增、自減運算語句。特別是與輸出語句結(jié)合在一起使用時,有些問題的出現(xiàn),一些年輕老師都不太好理解,因為這涉及了C語言在不同運行平臺上編譯順序的問題。由于現(xiàn)在很多高校C語言上機環(huán)境采用更易于操作的VC++,本文就此平臺下對自增、自減語句的教學(xué)方法及在應(yīng)用舉例中出現(xiàn)的一些問題,進(jìn)行了研究和討論,希望對C語言的教學(xué)能夠起到有益補充,方便解答學(xué)生提出的一些疑問。
1 自增、自減語句簡介
自增(++)、自減(--)語句在C語言教學(xué)中屬于算術(shù)運算語句,從用法上可以分為兩種,即先用后加(減)和先加(減)后用,如i++(i--),++i(--i)[2]。學(xué)生在學(xué)習(xí)時,一開始往往不明白“用”指的是什么,也容易疏忽不論是先用還是后用,最終變量i的值都會加1 這點。我們可以通過這樣一個小例子幫助學(xué)生理解:
#include
void main()
{ int i=3,j=3,k=3,m=3;
int p,s,r,q;
p=i+++i++;
s=++j+(++j);
r=k+++(++k);
q=++m+m++;
printf("p=%d,s=%d,r=%d,q=%d\n",p,s,r,q);
printf("i=%d,j=%d,k=%d,m=%d\n",i,j,k,m); }
運行結(jié)果如圖:
分析以上程序可知p的值是由3+3計算得來,求和賦值也就是對i使用后,i的值做了兩次加1操作,先用后加,最終值為5。S的值是由5+5計算得來,是先對j的值做了兩次加1,再求和賦值,先加后用。r和q都是由4+4計算得來,k和m先加后用了1次,變成4,求和賦值后,再做一次先用后加變成5。在分析完此例后,可將例子中的自增改為自減,讓學(xué)生來分析下執(zhí)行結(jié)果。
2 自增、自減語句教學(xué)重點
自增、增加語句在編程時常用于循環(huán)結(jié)構(gòu)中修改循環(huán)變量[3],當(dāng)然也可用于賦值語句、邏輯表達(dá)式、指針等[4]。對于初學(xué)者首先應(yīng)該熟練掌握自增、自減語句與if…goto…、while、do…while、for等語句的連用。如下面兩個小例子:
#include
void main()
{ int i;
for(i=1;i<4;i++) ;
printf("%d\n",i); } /*i的值為4*/
#include
void main()
{ int i;
for(i=1;i++<4; ) ;
printf("%d\n",i); } /*i的值為5*/
這兩個例子中由于i++語句位置不同,循環(huán)次數(shù)不同,i的值也不同,此例也可用于幫助學(xué)生理解空語句,for語句的執(zhí)行等。很顯然學(xué)生自己在編程時,按第一種用法的情況更常見,但考慮學(xué)生有計算機考證方面的需求,還是應(yīng)該提高學(xué)習(xí)要求,對自增、自減語句不僅會自己編程使用,也要能看懂他人編寫的程序中的用法,因此可以把這個知識點理解得更深入一點。
3 學(xué)生在Printf函數(shù)中使用出現(xiàn)的疑問
在中國水利水電出版社的《新編C語言程序設(shè)計教程》教材中第2章課后習(xí)題中有這樣一個程序閱讀題:
#include
void main()
{ int i;
i=8;
printf("%d,%o,%x\n",i++,i++,i++); }
上機運行的結(jié)果是:
按十進(jìn)制、八進(jìn)制、十六進(jìn)制顯示i++的值是8、10、8,即3次i++的顯示結(jié)果值大小是一樣的,都是8。學(xué)生會提這樣一個問題:i++是先用后加,那么第一次i++顯示后,i的值加1,則第二個i++的值顯示應(yīng)該是11(換算成十進(jìn)制,即為9),第三值應(yīng)該顯示為a(換算成十進(jìn)制,即為10)。如果此例改為:
#include
void main()
{ int i;
i=8;
printf("%d \n",i);
i++;
printf("%o \n",i);
i++;
printf("%x \n",i); }
顯示結(jié)果如學(xué)生期望的,按十進(jìn)制看,三次顯示結(jié)果為8,9,10。為什么自增語句放到printf語句中顯示結(jié)果就不同呢?有的教師是這樣解釋的:在printf語句中,自增、自減語句只計算不存儲。就是說計算機只是顯示了運算結(jié)果,而沒有把運算結(jié)果都存放到對應(yīng)的變量中。從剛剛的例子表象看,似乎可以解釋得通。但筆者仍存在疑問,如果在printf語句中自增、自減的結(jié)果沒有存儲,而只有賦值語句才存儲結(jié)果,那么為什么在其他語句中使用自增、自減,結(jié)果都存儲了呢?真的是printf語句比較特殊嗎?
4 問題分析與原因探究
為了進(jìn)一步分析這個問題,筆者上機運行了下例:
#include
void main()
{ int i=5;
i++;
printf("%d\n",i);
printf("%d,%d\n",i,++i);
printf("%d\n",i);
printf("%d,%d\n",i,i++);
printf("%d\n",i); }
此例中可以看出第一條printf語句中顯示的是i(初值為5)增1之后的結(jié)果,第二條printf語句中有一個先加后用的自增運算,如果沒有存儲的話,第三條printf語句顯示的結(jié)果是6,而實際情況是第三條printf語句顯示結(jié)果是7,這說明變量i的值完成了第二次的增1操作。第四條、第五條printf語句的顯示結(jié)果,也說明了先用后加的自增語句也得到了存儲。這說明printf中的自增語句并不是不存儲,先加后用、先用后加中的“用”在printf語句中指的是顯示輸出,顯示輸出后最終還是執(zhí)行加1操作并存儲的。不過此例中又出現(xiàn)一個奇怪的現(xiàn)象,第二條printf("%d,%d\n",i,++i);語句中,先顯示i的值,再顯示i++的值,如果按照我們書寫的順序,即從左到右的順序來理解,則第一個i的值為6,第二個++i的值先加后用值為7。但結(jié)果顯示的卻是7,7。這又是為什么呢?筆者將上例改為:
#include
void main()
{ int i=5;
i++;
printf("%d\n",i);
printf("%d,%d\n",++i,i);
printf("%d\n",i);
printf("%d,%d\n",i++,i);
printf("%d\n",i); }
顯示結(jié)果如圖4所示:
在將++i與i交換顯示位置,i++與i也交換顯示位置后,結(jié)果發(fā)生了一點變化。printf("%d,%d\n",++i,i);顯示結(jié)果變成了7,6。按由左向右的順序看,i的值既然已經(jīng)加1變成7了,為什么第二個i的值反倒是6呢?貌似如果兩次結(jié)果顛倒過來了。這個問題,如果我們換個方向去理解就能說通了。我們從右向左看,printf("%d,%d\n",i,++i);中首先執(zhí)行顯示++i,i賦值為7,再執(zhí)行顯示i,也為7。printf("%d,%d\n",i,i++);中首先執(zhí)行顯示i++,由于是先用后加,值依然為7,再執(zhí)行顯示i,i的值仍為7(因為顯示操作還沒結(jié)束,可以認(rèn)為先用后加中的“用”還沒執(zhí)行完,這里的“用”是printf)。printf("%d,%d\n",++i,i);中首先執(zhí)行顯示i的值,i為6,再顯示++i的值,先加后顯示,則值為7。printf("%d,%d\n",i++,i);中先顯示i的值,此時已為7,再顯示i++的值,先用后加,結(jié)果仍為7。
5 總結(jié)
VC平臺下,printf語句在編譯時是從左往右的,讀取的內(nèi)容放入堆棧中,執(zhí)行時從棧頂開始,由于堆棧是后進(jìn)先出的,實際執(zhí)行順序是從右往左的。因此學(xué)生在遇到出現(xiàn)在printf語句中自增、自減運算時,判斷輸出結(jié)果應(yīng)該先從左到右去除多余變量,如在printf("%d,%d\n",i++,i,i+3);語句中,最后一個i+3不顯示其值,再從右到左的判斷各表達(dá)式或變量的值。由于不同平臺語句編譯順序不同,建議學(xué)生不要使用容易產(chǎn)生歧義的自增、自減語句,以免因平臺不同而造成執(zhí)行結(jié)果不同。
參考文獻(xiàn):
[1] 孫家啟,萬家華.新編C語言程序設(shè)計教程[M].北京:水利水電出版社,2013.
[2] 董衛(wèi)紅.淺談自增自減運算符在C語言中的應(yīng)用[J].微型電腦應(yīng)用,2012,28(1):49-50.
[3] 周偉.C語言中自增自減運算符教學(xué)探究[J].軟件導(dǎo)刊,2012,11(12):188-190.
[4] 李彩玲.C語言中自增自減運算符的應(yīng)用與解析[J].晉城職業(yè)技術(shù)學(xué)院學(xué)報,2013,6(3):78-80.