涂小琴
(云南師范大學(xué)文理學(xué)院,昆明650222)
C語言結(jié)構(gòu)化編程教學(xué)案例過程設(shè)計
涂小琴
(云南師范大學(xué)文理學(xué)院,昆明650222)
為了讓學(xué)生更快速地掌握結(jié)構(gòu)化編程方法,特設(shè)計此案例。利用自頂向下,逐步細(xì)化的方法將案例一步步推進(jìn),從問題的提出,分析問題,給出解決問題的基本框架,設(shè)計算法,任務(wù)分解,函數(shù)定義等幾個方面進(jìn)行詳細(xì)的描述,最終解決問題。結(jié)構(gòu)化程序設(shè)計思想是現(xiàn)代編程技術(shù)的基礎(chǔ),甚至是基礎(chǔ)當(dāng)中的基礎(chǔ),從提出問題、分析問題著手,給出解決問題的基本框架,再在框架上進(jìn)行進(jìn)一步的分析與細(xì)化,給出解決問題的全過程。將如何分析問題及解決問題表現(xiàn)得淋漓盡致。
C語言;結(jié)構(gòu)化編程;教學(xué)過程;案例
人類進(jìn)行程序設(shè)計只有幾十年的歷史,在最初進(jìn)行軟件生產(chǎn)的年代,軟件的生產(chǎn)并沒有什么章法可循,生產(chǎn)效率十分低下,失敗的項目比比皆是。大約從有科學(xué)家反對goto語句開始,人類才開始認(rèn)真思考軟件應(yīng)該如何編寫,在這方面有限的若干成果之一就是結(jié)構(gòu)化程序設(shè)計思想。
結(jié)構(gòu)化程序設(shè)計思想是現(xiàn)代編程技術(shù)的基礎(chǔ),甚至是基礎(chǔ)當(dāng)中的基礎(chǔ),這個思想大體是20世紀(jì)的60年代末期和70年代,斷斷續(xù)續(xù)地由若干人提出并互相補(bǔ)充匯集而成的,目標(biāo)是使程序的結(jié)構(gòu)更清晰,更容易理解(可讀性通常是衡量代碼質(zhì)量時僅次于正確性的一個指標(biāo),除了在對性能要求特別高的地方)、易于修改,易于調(diào)試,減少錯誤從而達(dá)到提高軟件開發(fā)效率和成功率的目的。
自頂向下(top-down),逐步細(xì)化(stepwise refinement)是結(jié)構(gòu)化程序設(shè)計思想的主要內(nèi)容之一,而函數(shù)是實現(xiàn)這個思路的一種強(qiáng)有力的主要的技術(shù)支持手段。
要完成一個較大的任務(wù),首先把它分解成若干個小問題;要完成一個復(fù)雜的問題,首先把它解析為若干個簡單的問題。這就是自頂向下,逐步細(xì)化(或稱之為“逐步求精”)的方法,先考慮整體,再考慮局部,最后考慮細(xì)節(jié),下面以一個程序從構(gòu)思到完成的完整過程來說明這種思路以及如何通過函數(shù)達(dá)到程序的實現(xiàn)。
題目分析:由于題目要求給出精確的結(jié)果,所以double,float這些數(shù)據(jù)類型顯然不可能加以考慮,結(jié)果只可能以分?jǐn)?shù)形式給出,然而C語言沒有分?jǐn)?shù)這種類型,那么就只能自已創(chuàng)造出這種類型——這就是所謂數(shù)據(jù)結(jié)構(gòu)的含義??梢钥紤]以兩個int類型的量來分別表示一個分?jǐn)?shù)的分子和分母,這雖然是一種很初級、很粗糙的數(shù)據(jù)結(jié)構(gòu),但依據(jù)目前大一學(xué)生所學(xué)的內(nèi)容,只能如此來表示。
程序的功能應(yīng)該是輸入一個整數(shù)n的值,然后輸出H(n)的分子和分母,此外應(yīng)該注意到輸入非正整數(shù)是沒有意義的,而且輸入的n不可以太大。
前面描述了程序的輸入也輸出,實際上完成了對程序功能的定義,現(xiàn)在可以寫代碼了。/*程序功能:
輸入:一個整數(shù)n的值。
輸出:
n<=0時,輸出“對于輸入數(shù)值H(n)無定義”;
n太大的時候輸出“數(shù)值太大無法計算”;
n>0且不是很大時輸出H(n)的分子和分母。*/
結(jié)構(gòu)化程序設(shè)計強(qiáng)調(diào)的是計劃的正確性,然后逐步地漸進(jìn)??梢杂脗未a(Pseudocode),來描述程序員的思路并幫助程序員進(jìn)行構(gòu)思??梢栽谠创a編輯器中寫成注釋的形式,也可以作為程序的一個文檔。偽代碼或流程圖,對于比較復(fù)雜的程序,能夠明確程序所要完成的功能。
在確定程序的基本框架之前,首先需要確定程序涉及的數(shù)據(jù)對象的數(shù)據(jù)結(jié)構(gòu)。由于程序的數(shù)據(jù)結(jié)構(gòu)(用兩個int類型分別表示和的分子與分母)已經(jīng)確定,程序的基本功能已經(jīng)明確,所以可以進(jìn)一步勾勒出程序的基本結(jié)構(gòu)和框架。
現(xiàn)在考慮n的值的界限問題。由于:
所以暫時把n!取值在int表示的范圍內(nèi)做評估n的上限的臨界條件。由于12!=479001600,13!=6227020800,后者超出了int類型的表示范圍,所以n的上限可以暫定為12。盡管離全部完成尚早,但是這段代碼已經(jīng)可以運(yùn)行并接受程序測試了,編譯完成后,運(yùn)行并輸入,-1,0,可以確信,程序的部分功能已經(jīng)實現(xiàn)。/*程序功能:
輸入:一個整數(shù)n的值。
輸出:n<=0時,輸出“對于輸入數(shù)值 H(n)無定義”;n太大的時候輸出“數(shù)值太大無法計算”;n>0且不是很大時輸出H(n)的分子和分母。*/
這個程序只是完成了初步框架的搭建,程序并無語法錯誤,可以運(yùn)行,結(jié)果如圖1所示。
圖1 運(yùn)行結(jié)果圖1
測試正確后,接下來專心考慮程序的核心算法。為了總結(jié)算法,一個切實可行的方法是自己用手工的方式把題目試著做幾次(對于初學(xué)者尤其必要),如果使用紙張、筆都無法完成,就絕對不可能編程了。
假設(shè)n的值為6,計算的步驟如下:
可以看到當(dāng)n為6時整個計算過程是分6次完成的,而每次進(jìn)行的計算步驟是相同的。這顯然可以用循環(huán)來描述。而且從上面可以看到,為了使計算的過程統(tǒng)一,和的分子的初值應(yīng)該設(shè)為0,和的分母的初值應(yīng)該設(shè)為1。在計算的過程中,每一項的符號都在發(fā)生變化,初始符號為正,接著為負(fù),所以可以設(shè),初始符號變量,fh=1,當(dāng)進(jìn)行下一項時,可以設(shè)定fh=-fh,這樣可以對每一項做正負(fù)符號的改變。下面的代碼再向前推進(jìn)一步,完成變量hfz,hfm的定義,循環(huán)語句及輸出的功能。
將第6行更新為:inthfz=0,hfm=1,fh=1;//int和的分子,和的分母;
將第19,20行更新為:
inti;
for(i=1;i<=n;i++)
//計算和的分子,和的分母;
{
//計算
}
//輸出和的分子,和的分母;
printf("H(%d)為%d/%d ",n,hfz,hfm);
計算部分沒法有完成,但是已經(jīng)可以測試輸出格式是否合乎要求了??梢詧?zhí)行printf(“H(%d)為%d/%d “,hfz,hfm);語句,但并沒有完成計算,程序運(yùn)行的結(jié)果也不正確,運(yùn)行結(jié)果如圖2。
圖2 運(yùn)行結(jié)果圖2
這部分的計算是求兩個分?jǐn)?shù)的和(“1/i”與”和的分子/和的分母”)。計算的第一步是通分,而通分的本質(zhì)是求兩個分母(“i”與“和的分母”)的最小公倍數(shù)。在求得最小公倍數(shù)之后,可以利用最小公倍數(shù)求得通分后兩個分?jǐn)?shù)的新的分子(“最小公倍數(shù)/i”及“最小公倍數(shù)/和的分母*和的分子”)及它們的和,這個和就是“和的分子/和的分母”加上“1/i”后得到的新的“和的分子”。此時,可以把新的“和的分母”確定為剛剛求得的最小公倍數(shù)。最后對新得到的“和的分子/和的分母”還要進(jìn)行約分(如果它們的最大公倍數(shù)不為1的話)。這樣“//計算”部分的算法可以進(jìn)一步細(xì)化為:
//(1)求“i”與“和的分母”的最小公倍數(shù)
//(2)用最小公倍數(shù)、“和的分子”、“i”、“和的分母”求新的“和的分子”;
//(3)新的“和的分母”=“最小公倍數(shù)”;
//(4)求“和的分子”、“和的分母”的最大公約數(shù);
//(5)如果最大公約數(shù)不為1則進(jìn)行約分。
以上的各個任務(wù)中,(3)可以簡單的實現(xiàn),(5)在目前還做不到用一個函數(shù)完成(因為要改變兩個變量的值,而函數(shù)只能求得一個值),其余的都可以用一個函數(shù)來完成。
由于完成(1)需要兩個 int類型的量(“i”與“和的分母”),求得一個int類型的量(最小公倍數(shù)),因而函數(shù)原型可寫為:
int qiuzxgbs(int,int);
完成(2)需要5個int類型的量(“最小公倍數(shù)”、“和的分子”、“i”、“和的分母”、“符號位”),求得的新的“和的分子”是一個int類型的量,因而函數(shù)原型可以寫為:
int qiuhe(int,int,int,int,int);
同理,(4)的函數(shù)原型如下:
int qiuzdgys(int,int);
函數(shù)定義及函數(shù)調(diào)用聞分在些不再詳述,下面是完成后的代碼。此外n的上限經(jīng)過計算驗證可以達(dá)到
23。
將第15行更新為:if(n>=24)
//求正整數(shù)m,n的最大公約數(shù)
intqiuzdgys(intm,intn)
{
inttemp;
while((temp=m%n)!=0)
{
m=n;n=temp;
}
return n;
}
//求正整數(shù)m,n的最小公倍數(shù)
intqiuzxgbs(intm,intn)
{
return m*n/qiuzdgys(m,n);
}
//求通分后分子之和
intqiuhe(intgbs,intfz,inti,intfm,intfh)
{
returngbs/fm*fz+fh*gbs/i;
}
重新將第19至20行更新為:
inti;
fh=-fh;
for(i=1;i<=n;i++)//計算和的分子,和的分母;
{
fh=-fh;
intzxgbs,zdgys;//存放最小公倍數(shù),最大公約數(shù)
//求"i"與"和的分母"的最小公倍數(shù)(1)
zxgbs=qiuzxgbs(hfm,i);
//用最小公倍數(shù)、"和的分子"、"i"、"和的分母"求新的"和的分子"(2);
hfz=qiuhe(zxgbs,hfz,i,hfm,fh);
//新的"和的分母"="最小公倍數(shù)";(3)
hfm=zxgbs;
//求"和的分子"、"和的分母"的最大公約數(shù)(4);zdgys=qiuzdgys(hfz,hfm);
//如果最大公約數(shù)不為1則進(jìn)行約分(5)。
if(zdgys>1)
{
hfz/=zdgys;
hfm/=zdgys;
}
}
之后的任務(wù)就是程序的測試與調(diào)試了,程序運(yùn)行正確,運(yùn)行結(jié)果如圖3所示。
圖3 結(jié)果運(yùn)行圖3
從以上的過程可以知道,要解決好一個問題,需明確以下幾點:
(1)明確定義程序的總體目標(biāo)或功能,而且越明確越好??梢园堰@種目標(biāo)作為注釋寫在代碼中或其他文檔中,這是編程總的依據(jù)。
(2)將程序的目標(biāo)粗略地分解為若干比較簡單的問題,這時可以在保證程序結(jié)構(gòu)正確性的前提下勾勒出main()在大致框架。
(3)審視main()的結(jié)構(gòu)和框架,確保無誤之后可以開始逐個考慮(1)中有沒有具體完成的各個函數(shù)定義。這些函數(shù)本身可能依然是比較大或比較復(fù)雜的任務(wù),同樣按照(1)的方式明確這些函數(shù)的功能,然后繼續(xù)把這些函數(shù)解析成更小或更簡單的任務(wù)。
(4)在進(jìn)行(1)、(2)時盡量作到每個步驟都保證代碼在語法上的正確性,可以用空函數(shù)、空語句、假設(shè)的數(shù)據(jù)以及注釋來達(dá)到這個目的。這樣便于在程序編寫過程中進(jìn)行不斷測試以保證程序在總的大框架范圍內(nèi)的正確性。同時使得編程以“一步一個腳印”的方式進(jìn)行,有利于編程者對程序的正確性和進(jìn)度增強(qiáng)信心。
(5)對各個功能模塊進(jìn)行透徹的分析并且明確地寫出來,這樣才能在進(jìn)行完每個步驟之后都能進(jìn)行程序測試,而這種測試對于編程有極大的好處。從前面的例子可以看到,結(jié)構(gòu)化程序設(shè)計有些像繪畫時先打個草圖或先畫個輪廓,然后再逐步把各個部分繪制好一樣。實際上生活中到處都可以看到top-down這種思想的影子,結(jié)構(gòu)化程序設(shè)計不僅使得程序本身變得有條理、層次清晰,每個部分的結(jié)構(gòu)和意圖都清晰可見,實際上也使得編程過程本身變得很有條理,具有可規(guī)劃性。在這種思想的指導(dǎo)下,編程的步驟本身也變得井井有條。
[1]王敬華.C語言程序設(shè)計.第二版[M],2009.
[2]黑馬.C語言程序設(shè)計案例式教程[M],2017.
涂小琴(1981-),女,講師,研究方向為程序設(shè)計方法
Teaching Case Process Design of C Language Structured Programming
TU Xiao-qin
(College ofArts And Sciences,Yunnan NormalUniversity,Kunming 650222)
Design this case,in order to let students more quickly master structured programming method,the top-down method is used to push the case forward step by step,from the pointofview ofthe problem,describes the analysis ofthe problem,the basic framework for solving the problem,the design algorithm,the task decomposition,function definition and other aspects in detail,finally solves the problem.The idea ofstructured programming is the basis ofmodern programming techniques.Starts with asking questions and analyzing problems,and gives the basic frame ofsolving the problems,further carries outthe analysis and refinementon the framework,gives the whole process ofsolving the problem.
C Language;Structured Programming;Teaching Process;Case Study
1007-1423(2017)30-0072-05
10.3969/j.issn.1007-1423.2017.30.016
2017-09-05
2017-10-20