劉 鵬,趙仁慶,鄧燕林
(楚雄師范學(xué)院數(shù)學(xué)系,云南 楚雄 675000)
C語言是一種國際上廣泛流行的計算機高級語言,具有用途廣泛、功能強大、使用靈活的特點?!禖語言程序設(shè)計》是高等學(xué)校的一門基本的計算機課程,在計算機教育和計算機應(yīng)用中發(fā)揮著重要的作用。通過學(xué)習(xí)程序設(shè)計,學(xué)生進一步了解計算機的工作原理,更好地理解和應(yīng)用計算機;掌握用計算機處理問題的方法,能培養(yǎng)分析問題和解決問題的能力,具備編制程序的初步能力[1]。
C語言是大學(xué)階段第一門程序設(shè)計的課程,有了C語言的基礎(chǔ),在以后學(xué)習(xí)高級語言編程就會很容易。在該課程的教學(xué)中,如何來培養(yǎng)學(xué)生的編程能力呢?
結(jié)構(gòu)化程序設(shè)計的思想是自頂向下,逐步細化,模塊化設(shè)計,結(jié)構(gòu)化編碼。核心的理念就是層次。良好的代碼要有層次感,先做好“頂層設(shè)計”,然后一步一步細化,這樣做可使編碼工作有條不紊地進行。
在教材第291頁有這樣的題目[1]:有n個人圍成一圈,順序排號。從第1個人開始報數(shù) (從1到3報數(shù)),凡報到3的人退出圈子,問最后留下的是原來第幾號的那位。文獻[2]在第104頁給出如下的參考解答[2]:
這段代碼從頭到尾只有一個main()函數(shù),根本就不符合結(jié)構(gòu)化程序設(shè)計的思想要求。
把所有的代碼都堆在main()函數(shù)中,就如同在一個硬盤中存放了很多文件,卻沒有使用任何文件夾來進行管理一樣;也如同買了一套房子,并沒有用墻把房子分隔成臥室、客廳、廚房、餐廳、衛(wèi)生間,而是將一切生活用品都堆放在房子的地上,吃喝拉撒都在一個大房間里進行。
一個源程序由若干個函數(shù)組成,猶如用墻把房子分隔成一個個房間一樣。模塊化設(shè)計就是把一個大任務(wù)分為若干個相對簡單的子任務(wù),每個子任務(wù)用函數(shù)來實現(xiàn)。
解決一個問題首先要從大處著手,做好“頂層設(shè)計”。站在高處來看,解決這個問題需要四個步驟[3]:輸入人數(shù);數(shù)組初始化;“從1到3報數(shù)”n-1次;輸出最后剩下的那個人的編號。而每一步都可以簡單地用函數(shù)或基本的控制語句來實現(xiàn)。在向下一層展開之前應(yīng)檢查本層設(shè)計是否正確,只有上一層設(shè)計是正確的才能向下細化。良好的程序設(shè)計應(yīng)該是把復(fù)雜的問題分解為簡單的問題,然后各個擊破,一件一件有條不紊地完成。
“自頂向下,逐步求精”的層次理念是每個編程人員時刻都要堅持的,就像做人要守好自己的“底線”一樣,不能輕易發(fā)生動搖。
在教學(xué)的過程中,可以總結(jié)出一個編程的標準模板。利用這個模板,可幫助學(xué)生快速搭建程序框架,讓學(xué)生能集中精力于數(shù)據(jù)的處理、問題的解決方面。這個模板為:
下面就以求兩個正整數(shù)的最大值為例進行說明:
第一:預(yù)處理命令#include<stdio.h>必不可少,另外可能用到的有#include<math.h>、#include<string.h>。若程序中有一些常數(shù),建議用預(yù)處理命令將其定義為符號常量:#define N 10,另外要注意預(yù)處理命令后面沒有標點符號。
第二:函數(shù)聲明由函數(shù)定義中的首行,再加一個分號“;”形成,此時形參名可省略不寫。形參名是什么都無所謂,特別注意函數(shù)聲明是以分號“;”結(jié)束的。
第三:根據(jù)問題的需要,定義有關(guān)的變量,在使用的過程中一定要注意與定義時的變量類型要保持一致。全局變量一般是在不同的地方進行傳遞數(shù)值的。
第四:數(shù)據(jù)的輸入主要有以下幾種方式:①賦值:在定義時進行賦值即為初始化,如數(shù)組的初始化;②鍵盤輸入:特別注意做好數(shù)據(jù)輸入 (出)時的提示設(shè)計,如:
③加入數(shù)據(jù)的合法性檢查:數(shù)據(jù)的合法性檢查是數(shù)據(jù)輸入時要做的事,當(dāng)用戶輸入不合法的數(shù)據(jù),程序提示用戶重新輸入,如:
第五:數(shù)據(jù)處理是程序設(shè)計編寫的核心,一般使用函數(shù)來完成,這樣一來使設(shè)計者的精力放在后面的函數(shù)定義上即可:c=max(a,b);。
第六:數(shù)據(jù)的輸出主要用函數(shù)printf()實現(xiàn):
字符數(shù)據(jù)的輸入輸出函數(shù)有:putchar,getchar,puts,gets。
第七:函數(shù)定義就是程序設(shè)計者要花時間精力去做的事情,如:
有了模板后,要寫好程序就需要寫好函數(shù),而要寫好函數(shù)就必須熟悉一些基本的算法和常見問題的求解方法。
第一個問題:用輾轉(zhuǎn)相除法,求解整數(shù)x和y的最大公約數(shù)的算法如下[4]:
步驟1:變量r是x除以y的余數(shù);
步驟2:變量r不是0的時候,反復(fù)執(zhí)行步驟3~5;
步驟3:變量x代入變量y的值;
步驟4:變量y代入變量r的值;
步驟5:變量r是x除以y的余數(shù);
步驟6:變量y的值即為最大公約數(shù);
使用基本語句:
一般來說,只要能得到問題的解法,就很容易把它寫成函數(shù)的形式。該問題從使用窮舉法、基本語句到使用函數(shù)、遞歸函數(shù)的過程,體現(xiàn)了編程中精益求精的思想,極能體現(xiàn)編程思維的抽象性和深刻性。
第二個問題:判斷鍵盤輸入的整數(shù) (用n來表示)是否是素數(shù):
根據(jù)數(shù)學(xué)上的結(jié)論,循環(huán)只需到n的算術(shù)平方根就可以了。但此時不能簡單地用sqrt(n)來求n的平方根或整數(shù)部分,由1=12,1+3=22,1+3+5=32,…,1+3+…+(2k-1)=k2,可求出n的整數(shù)部分。整個程序如下[3]:
素數(shù)問題本身就是初等數(shù)論中的重要問題,解決該問題的程序效率與所掌握的有關(guān)數(shù)學(xué)理論知識密切相關(guān),這里給出的求n的整數(shù)部分的方法值得程序設(shè)計者深思。
第三個問題:級數(shù)求和中典型的例子是[1]:用π/4≈1-1/3+1/5-1/7+…公式求π的近似值,直到某一項的絕對值小于106為止 (該項不累加)[1]。
該問題之所以重要是因為涉及到循環(huán)累加求和基本方法、交錯數(shù)列符號處理技巧,真正掌握該編程思想就能處理許多求和的問題。
這類問題還很多,需要在學(xué)習(xí)過程中不斷地歸納總結(jié)。通過對這些問題的解決,可訓(xùn)練學(xué)生的編程思維,進一步提高學(xué)生的編程能力。
現(xiàn)在介紹IT行業(yè)優(yōu)秀工程師的經(jīng)驗方面的書籍很多,里面有許多值得在教學(xué)中推廣的做法。當(dāng)然,在以往教學(xué)中也存在許多錯誤的觀念,會嚴重影響教學(xué)的質(zhì)量。
一些正確的觀念,在教學(xué)之初就要強調(diào):①浮點數(shù)是實數(shù)在計算機上的近似表示,只能表示一部分實數(shù);②程序設(shè)計中,遇到常數(shù)一般定義為符號常數(shù),避免魔法數(shù)問題 (程序中的常數(shù)與問題沒有直接關(guān)系);③寫循環(huán)時一定要檢查邊界條件,避免造成失之毫厘,差之千里的錯誤;④指針是某個對象存儲時占用若干連續(xù)存儲單元中首個存儲單元的地址。這方面的問題建議大家好好讀讀參考文獻[3]、[4]~[8]。
許多初學(xué)者都會有這樣的想法:只要編寫出程序,運行結(jié)果也沒有問題就萬事大吉了。實際上這是一個很嚴重的錯誤觀念!比如求100~200間的全部素數(shù)的程序如下[1]:
該程序編譯、連接都沒問題,執(zhí)行結(jié)果如下
從數(shù)學(xué)的角度上來說結(jié)果也沒有錯誤。但該程序隱藏著一個很難發(fā)現(xiàn)的錯誤[3]:語句if(m%10==0)printf(" ");的正確位置是在m=m+1;之后 (應(yīng)與前面的花括號互換位置)!程序中if(m%10==0)printf(" ");語句的意思是前面輸出了10,20,30,……個素數(shù)時就換行,即只要前面輸出的素數(shù)個數(shù)是10的倍數(shù)就換行。該問題中第10個素數(shù)與第11個素數(shù)以及第20個素數(shù)與第21個素數(shù)恰好相鄰,掩蓋了這個錯誤。將語句中的10改為其他正整數(shù)如3、4等,錯誤馬上就凸顯出來。
實際上這里使用該語句是想每行輸出10個素數(shù),只有語句if(m%10==0)printf(" ");緊隨語句m=m+1;之后,才能真正實現(xiàn)這一目的。
教師平時都會告誡學(xué)生:看懂學(xué)會書上的理論知識,學(xué)習(xí)只成功了30%;動手編程,親自上機調(diào)試運行,可達60%;善于利用所得到的知識解決實際問題,才能達到90%以上。學(xué)習(xí)C語言程序設(shè)計,必須重視實踐環(huán)節(jié),既會編寫程序,又會上機實踐,另外還要舉一反三。
《C語言程序設(shè)計》課程只是程序設(shè)計學(xué)習(xí)過程中的起點,在今后的學(xué)習(xí)過程中,還需要進一步學(xué)習(xí)其他高級程序語言,遇到許多實際問題時要有編程解決的意識。只有養(yǎng)成用程序設(shè)計來解決實際問題的良好習(xí)慣,才能使程序設(shè)計的學(xué)習(xí)得到深化,程序設(shè)計能力才可能會得到提高。
如學(xué)生在后續(xù)課程《信息論與編碼》中需要計算信息熵:
其中p1,p2,…,pn為概率分布:p1+p2+…+pn=1,pi〉0。
C語言數(shù)學(xué)庫中沒有l(wèi)og2(x)函數(shù),可用換底公式來計算:log2(x)=log(x)/log(2)。函數(shù)的參數(shù)個數(shù)是變化的,C語言中沒有專門的函數(shù),參考程序為:
《C語言程序設(shè)計》課程教學(xué)中學(xué)生編程能力的培養(yǎng)問題是一個系統(tǒng)工程,只有堅持不懈地努力,才能收到良好的效果。
[1]譚浩強.C程序設(shè)計 (第四版)[M].北京:清華大學(xué)出版社,2010:9,131-132,137-138,291.
[2]譚浩強.C程序設(shè)計 (第四版)學(xué)習(xí)輔導(dǎo)[M].北京:清華大學(xué)出版社,2010:104.
[3]薛非.拋棄C程序設(shè)計中的謬誤與惡習(xí)[M].北京:清華大學(xué)出版社,2012:86-87,255.
[4]李克秋譯.算法解讀[M].北京:科學(xué)出版社,2012:100.
[5]尹哲,鄭秀雯譯.編寫可讀代碼的藝術(shù)[M].北京:機械工業(yè)出版社,2012.
[6]陳正沖.C語言深度解剖——解開程序員面試筆試的秘密[M].北京:航空航天大學(xué)出版社,2010.
[7]崔康譯.程序員的思維修煉開發(fā)認知潛能的九堂課[M].北京:人民郵電出版社,2011.
[8]何海濤.劍指Offer名企面試官精講典型編程題[M].北京:電子工業(yè)出版社,2012.