崔 玲,張榮茜,鄭小靜
(北京工業(yè)大學(xué) 信息學(xué)部,北京 100124)
C 語言程序設(shè)計課程實踐性較強(qiáng),是最能體現(xiàn)計算思維的一門課程,對于非計算機(jī)專業(yè)的學(xué)生來說有一定難度。語法點多、內(nèi)容抽象,即使掌握了語法,學(xué)生在分析問題和解決問題時仍會感到無從下手,久而久之,一些同學(xué)喪失學(xué)習(xí)積極性,一些同學(xué)雖然很努力,但是因為初次接觸程序設(shè)計,顯得非常吃力。課堂教學(xué)如何引導(dǎo)學(xué)生快速接受程序設(shè)計理論,是一線教師著重思考的問題。
建構(gòu)主義學(xué)習(xí)理論[1-2]強(qiáng)調(diào)要以學(xué)生為中心,在學(xué)習(xí)過程中充分發(fā)揮學(xué)生的主動性,能夠讓學(xué)生在原有知識和經(jīng)驗的基礎(chǔ)上主動學(xué)習(xí)、構(gòu)建新的知識。建構(gòu)主義學(xué)習(xí)理論的主要教學(xué)方法有3種:支架式教學(xué)、拋錨式教學(xué)、隨機(jī)進(jìn)入教學(xué)。
支架式教學(xué)指的是為學(xué)習(xí)者建構(gòu)知識的概念框架,該思想來源于心理學(xué)家維果斯基的“最近發(fā)展區(qū)”理論[3-4]。維果斯基認(rèn)為,學(xué)習(xí)者對于所要解決的問題和原有能力之間存在差異,這個差異就是“最近發(fā)展區(qū)”,而教育就是要消除這個差異,同時引導(dǎo)學(xué)習(xí)者進(jìn)入更高水平的“最近發(fā)展區(qū)”。支架式教學(xué)主要由以下環(huán)節(jié)組成。
(1)搭建腳手架。圍繞知識點,按照“最近發(fā)展區(qū)”的要求建立概念框架。
(2)進(jìn)入情境。將學(xué)生引入一定的問題情境。
(3)獨立探索。教師給予適時提示,讓學(xué)生獨立探索,在概念框架中不斷提升自己。
(4)協(xié)作學(xué)習(xí)。學(xué)生進(jìn)行協(xié)商討論,在集體討論的基礎(chǔ)上完成對知識的意義建構(gòu)。
(5)學(xué)習(xí)效果評價。對學(xué)習(xí)效果的自我評價和相互評價。
建構(gòu)主義認(rèn)為,學(xué)習(xí)者獲取知識應(yīng)該主動去學(xué)習(xí)、體驗,而不是由教師傳授。該方法也被稱為案例教學(xué),或者基于問題的教學(xué)。
拋錨式教學(xué)主要由以下環(huán)節(jié)組成:①創(chuàng)設(shè)情境。為學(xué)生提供與實際情況類似的問題情境。②確定問題。為學(xué)生選擇與當(dāng)前學(xué)習(xí)主題相關(guān)的問題作為學(xué)習(xí)的主要內(nèi)容。③自主學(xué)習(xí)。為學(xué)生提供求解問題線索,讓學(xué)生主動搜集信息、思考方案來解決問題。④協(xié)作學(xué)習(xí)。⑤學(xué)習(xí)效果評價。
對于復(fù)雜問題,學(xué)生可選擇不同途徑、不同方式進(jìn)入同樣教學(xué)內(nèi)容的學(xué)習(xí),這就是“隨機(jī)進(jìn)入教學(xué)”。隨機(jī)進(jìn)入教學(xué)主要由以下環(huán)節(jié)組成:①呈現(xiàn)基本情境。②隨機(jī)進(jìn)入學(xué)習(xí)。③思維發(fā)展訓(xùn)練。教師提出的問題要有利于促進(jìn)學(xué)生認(rèn)知能力的發(fā)展,要有利于建立學(xué)生的思維模型。同時還可提出一些延伸問題培養(yǎng)學(xué)生發(fā)散性思維。④協(xié)作學(xué)習(xí)。⑤學(xué)習(xí)效果評價。
在建構(gòu)主義學(xué)習(xí)理論的指導(dǎo)下,結(jié)合程序設(shè)計課程的特點,進(jìn)行課堂教學(xué)設(shè)計,引導(dǎo)學(xué)生在原有知識基礎(chǔ)上快速構(gòu)建新知識。
學(xué)習(xí)循環(huán)之前,學(xué)生已經(jīng)學(xué)會如何輸出1 行“Happy New Year!”,接下來讓學(xué)生思考:如何輸出10 行“Happy New Year!”?學(xué)生可能回答:復(fù)制、粘貼,那么可以再問:如果輸入1 000 行呢?
在給出對應(yīng)的for 循環(huán)代碼之后,可以讓學(xué)生繼續(xù)思考:
如何輸出1 到10?
如何輸出1、3、5、7、9 的序列?
編寫程序驗證學(xué)生的想法,最后讓學(xué)生總結(jié)語句的執(zhí)行順序,以及影響輸出結(jié)果的語句都有哪些。
通過以上實例,教師可以自然地引出for 循環(huán)的語法格式,并指出for 循環(huán)的四要素:循環(huán)變量初值、循環(huán)條件、循環(huán)變量變化規(guī)律和循環(huán)體。
再比如,講解例題“輸入n 個學(xué)生成績,計算平均分”之后,讓學(xué)生思考如何編程實現(xiàn)“輸入班級學(xué)生成績,計算平均分(其中班級人數(shù)未知,可用-1 表示輸入結(jié)束)”。學(xué)生根據(jù)已經(jīng)學(xué)習(xí)過的for 語句可以編程實現(xiàn),但是會發(fā)現(xiàn)循環(huán)條件與循環(huán)變量無關(guān)。此時教師可引出while 語句,并通過比較,分析for 語句和while 語句的相似和不同之處。最后進(jìn)行總結(jié):雖然for 語句、while 語句均可實現(xiàn)循環(huán)問題的求解,但由語法形式可知,for 語句更適合循環(huán)次數(shù)已知的問題,而while 語句則適合循環(huán)次數(shù)未知的問題。
不僅例題講解要由淺入深,而且實踐練習(xí)也要由易到難,如掌握了for 語句的基本語法格式之后,教師可以設(shè)計與例題相似的題目,讓學(xué)生進(jìn)行編程練習(xí)。
練習(xí)1:輸出A 到Z;
練習(xí)2:輸出AaBb……Zz;
練習(xí)3:輸出100 到1 000 之間的偶數(shù)。
對于練習(xí)1,可以提示學(xué)生,利用已學(xué)知識解決問題:①字符類型可以參與算術(shù)運算,如ch=ch+1;②語法中未規(guī)定循環(huán)變量必須是整型。
練習(xí)2 有一定難度,雖然與練習(xí)1 相似,但是多數(shù)學(xué)生無法一下總結(jié)出AaBb……Zz 的規(guī)律。此時教師可以提醒:在已學(xué)過的分支語句中,執(zhí)行的語句可以是復(fù)合語句,那么循環(huán)語句中的循環(huán)體也可以是復(fù)合語句,將Aa、Bb、Cc 視為一組即可找到規(guī)律:
練習(xí)3 難度再次增加,循環(huán)體是分支語句,這是循環(huán)語句與分支語句的簡單混合應(yīng)用。
再比如,循環(huán)嵌套是學(xué)習(xí)的一個難點,通過對已有案例的升級改造,可以讓學(xué)生在已有知識基礎(chǔ)上,輕松接受循環(huán)嵌套。
案例1:已知如何輸出1 到10,思考如何輸出10 行的1 到10。
由該案例引出雙重循環(huán),此處要重點分析內(nèi)層循環(huán)變量和外層循環(huán)變量的變化規(guī)律。同時可讓學(xué)生練習(xí)如何輸出九九乘法表、三角圖形等。
案例2:已知如何計算n!,思考如何計算1+2!+3!+…+n!。
在該案例中,要著重注意變量初值及其所在位置問題。存儲求和結(jié)果的變量初值應(yīng)為0,放在外層循環(huán)之前。內(nèi)層循環(huán)用于求階乘,那么存儲求階乘的結(jié)果,初值為1,應(yīng)放在內(nèi)層循環(huán)之前外層循環(huán)之內(nèi)。素數(shù)問題是循環(huán)結(jié)構(gòu)的典型問題,也是枚舉算法的一個典型應(yīng)用。在講解素數(shù)問題之后,可給出以下兩個案例,繼續(xù)學(xué)習(xí)循環(huán)的嵌套用法,也可讓學(xué)生進(jìn)一步了解枚舉算法的基本思想。
案例3:已知如何判斷一個數(shù)是否是素數(shù),思考如何輸出100 到1 000 之間的素數(shù)。
案例4:通過講解雞兔同籠問題,讓學(xué)生練習(xí)百錢買百雞、搬磚等問題。同時,還可讓學(xué)生思考有無多種解法,如雞兔同籠問題的常規(guī)解法是二重循環(huán),思考是否可用一重循環(huán)解決。
素數(shù)問題對于非計算機(jī)專業(yè)的學(xué)生來說,問題簡單,但實現(xiàn)時容易出錯。關(guān)鍵點在于什么時候給出判定結(jié)果,很多同學(xué)往往在循環(huán)中直接給出判定結(jié)果,如:
教師在講解時不用立即否定學(xué)生想法,可運行程序進(jìn)行測試,通過運行結(jié)果學(xué)生會逐漸意識到問題所在。這時教師和學(xué)生再一起思考解決方法,在這樣不斷嘗試不斷修改的過程中逐步理清思路,達(dá)到求解問題的目的。這個過程會讓學(xué)生有種成就感。
同一問題往往有多種解法,在練習(xí)素數(shù)問題時,會有不少學(xué)生的解法思路都很巧妙。教師可讓學(xué)生展示給大家,然后一起分析其優(yōu)劣。
方法一:
該方法定義了變量flag,表示能整除n 的個數(shù),循環(huán)結(jié)束后,如果flag 為零,表示n 為素數(shù),否則n 不是素數(shù)。
容易理解大于n/2 的數(shù)不會整除n,程序中循環(huán)條件為i<n/2,比i<n 減少了循環(huán)次數(shù),提高了運行效率。
方法二:
方法二較方法一有3 點變化:①變量flag 的含義。flag 為1 表示n 是素數(shù),flag 為0 表示n不是素數(shù)。這種變量稱為邏輯型變量,常用于邏輯判斷問題,一般取值為1 或0,表示是或否、真或假。②可以證明,一個素數(shù)的兩個因數(shù),至少有一個小于等于根號n。sqrt(n)是判斷素數(shù)的最小臨界條件。因此該方法中循環(huán)條件是i<=sqrt(n),進(jìn)一步減少了循環(huán)次數(shù)。③break的應(yīng)用。只要某個i 可以整除n,則執(zhí)行break,跳出循環(huán),再次減少循環(huán)次數(shù)。對于復(fù)雜程序來說,減少循環(huán)次數(shù)會極大提高程序運行效率,教師可以借此向?qū)W生介紹一下算法復(fù)雜度問題,讓學(xué)生認(rèn)識到算法在程序設(shè)計中的重要性。
方法三:
該程序非常簡練,但不易理解,該程序思路可由方法二推出。方法二中使用了break 語句,如果滿足n%i==0,則結(jié)束循環(huán),也就是說n%i!=0 是循環(huán)條件之一。因此循環(huán)條件是n%i!=0&&i<=sqrt(n),循環(huán)結(jié)束表示這兩個條件至少有一個不滿足。如果不滿足n%i!=0,表示存在一個數(shù)可以整除n,則n 不是素數(shù)。
2.4.1 將應(yīng)用問題分類,提高學(xué)生求解問題能力
編程的難點不在于語法格式,而是如何將實際問題的求解方法轉(zhuǎn)化為符合語法格式的程序語句。教師可以將應(yīng)用問題進(jìn)行分類,為學(xué)生求解問題提供思路,幫助學(xué)生逐步提高利用程序求解問題的能力。一般來說,可用循環(huán)結(jié)構(gòu)解決的應(yīng)用問題有如下幾種:①有規(guī)律輸出問題,如輸出Fibonacci 序列。②累加累乘問題,如求n!。③連續(xù)輸入并進(jìn)行計算的問題,如輸入班級學(xué)生成績并求平均分、最高分。④枚舉問題,如素數(shù)、雞兔同籠問題。
每類問題可講解1~2 個案例,然后讓學(xué)生獨立求解類似問題加以練習(xí)。也可對案例進(jìn)行改編,如將問題:“根據(jù)公式,計算前n 項之和,求解π 的近似值”,改編為“根據(jù)公式,求解π 的近似值,直到最后一項的絕對值小于10-6”。
2.4.2 將求解步驟模式化,重復(fù)訓(xùn)練,培養(yǎng)學(xué)生計算思維能力
思維能力的培養(yǎng)離不開大量重復(fù)的訓(xùn)練。對每一個案例,均按照“問題描述、問題分析、算法描述、程序?qū)崿F(xiàn)、運行結(jié)果、程序分析”6 個步驟[5],進(jìn)行問題求解,逐步引導(dǎo)學(xué)生掌握程序設(shè)計的基本方法,培養(yǎng)學(xué)生計算思維能力。
以位數(shù)分解問題為例。
(1)問題描述。
輸出1 至10 000 之間每位數(shù)的乘積小于每位數(shù)的和的數(shù)。
(2)問題分析。
類似解數(shù)學(xué)題,首先分析題意。該題最終要求輸出一些數(shù),這些數(shù)的范圍是1 到10 000。由此可知輸出是一個循環(huán),循環(huán)范圍是1 到10 000。該部分算法可描述如下:
再分析,輸出的數(shù)是要滿足一定條件的,即每位數(shù)的乘積小于每位數(shù)的和。算法修改如下:
最后分析如何求和、求乘積,題目要求的是i 的每位數(shù)的乘積與每位數(shù)的和。因此要求和與積,首先要分解i,得到它的每個位數(shù)。
如何分解一個數(shù)呢?在學(xué)習(xí)算術(shù)運算時,已經(jīng)學(xué)過如何分解位數(shù)確定的數(shù),如i 是三位數(shù),則i%10 即個位數(shù),(i/10)%10 即十位數(shù),(i/100)%10 即百位數(shù)。但是該題目中位數(shù)可能是1、2、3、4、5,該如何分解出它的每位數(shù)呢?分解操作何時結(jié)束呢?我們只能嘗試尋找有無規(guī)律可循。先用實際的數(shù)進(jìn)行嘗試,然后試著總結(jié)規(guī)律,見表1。
通過實例分析可知,分解位數(shù)可由循環(huán)實現(xiàn),重復(fù)的操作是:
什么時候停止重復(fù)操作?當(dāng)m 為0 時。
分解位數(shù)的目的是求其和與積,因此在分解的同時計算和與積。該部分算法描述如下:
表1 分解位數(shù)實例分析
(1)算法描述。
根據(jù)問題分析,求解問題的完整算法如下:
(2)程序?qū)崿F(xiàn)。
類似中英文翻譯,將算法轉(zhuǎn)換為C 語言代碼。
(3)程序分析。
該例的難點在于如何分解一個不確定位數(shù)的數(shù)。已知確定位數(shù)的分解方法,那么可以嘗試總結(jié)不定位數(shù)的求法是否與之有相同之處。容易知道,個位數(shù)為m%10,十位數(shù)對于m/10 來說也是個位數(shù),百位數(shù)對于(m/10)/10 也是個位數(shù),因此可以把問題歸結(jié)為求個位數(shù),問題就變得簡單且有規(guī)律,通過幾個實例分析可得出求解規(guī)律。
另外要注意,該例程序中的m=i,為什么不直接用i 呢?原因在于m 是變化的,最終的m 會為0,而i 則是要輸出的數(shù),而且i 是外層循環(huán)的循環(huán)變量,不能輕易改變。初學(xué)者容易犯的錯誤就是在循環(huán)中不小心改變了循環(huán)變量的值,而這種錯誤屬于邏輯錯誤,難于察覺,很難找到錯誤所在。由此還可以給學(xué)生介紹一些調(diào)試程序的方法,比如在可疑語句前后加入輸出語句查看變量變化,或者直接使用編譯軟件提供的調(diào)試工具。
do-while 語句較為簡單,可對比while 語句學(xué)習(xí)。與while 語句不同,do-while 語句是至少執(zhí)行一次循環(huán)體,而while 語句則可能一次都不執(zhí)行。
上述程序段中while 循環(huán)條件不滿足,不會進(jìn)入循環(huán),執(zhí)行之后,s=0,n=3。而下面程序段中do-while 語句會先執(zhí)行一次循環(huán)體,再退出循環(huán),執(zhí)行之后,s=3,n=4。
同樣,可以對比學(xué)習(xí)break 和continue。在循環(huán)中,break 是結(jié)束循環(huán),類似于游戲中的“Game over!”;continue 是結(jié)束本次循環(huán),類似于游戲中的“Try again!”。
上述程序段輸出1、2、3、4,隨后跳出循環(huán)。而下面的程序則會進(jìn)入死循環(huán),因為x 會一直停留在5,循環(huán)條件一直未能打破。
對于實踐性較強(qiáng)的課程來說,課堂教學(xué)安排在教室上課,非常不利于學(xué)生實踐能力的培養(yǎng)。我校從2010 年開始,將C 語言程序設(shè)計等計算機(jī)公共基礎(chǔ)課程安排在機(jī)房上課,授課模式由講練分離變?yōu)檫呏v邊練,在學(xué)習(xí)一個知識點之后即刻讓學(xué)生進(jìn)行練習(xí)。由近幾年的教學(xué)評價來看,這種模式有助于激發(fā)學(xué)生學(xué)習(xí)興趣,培養(yǎng)學(xué)生實踐能力,提高教學(xué)效果。
循環(huán)結(jié)構(gòu)是C 語言程序設(shè)計的重點和難點內(nèi)容,基于建構(gòu)主義的教學(xué)方法可以讓學(xué)生在原有知識基礎(chǔ)上,由易到難、由淺入深逐步引導(dǎo)學(xué)生主動去分析問題、解決問題。多年教學(xué)實踐證明,該方法有助于培養(yǎng)學(xué)生的計算思維能力,有助于激發(fā)學(xué)生的學(xué)習(xí)興趣,培養(yǎng)學(xué)生的自主學(xué)習(xí)能力。