版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第5章函數(shù)5.1由程序規(guī)模增加引發(fā)的問題5.2模塊化的設(shè)計思想5.3函數(shù)在程序中的三種形式5.4主函數(shù)與子函數(shù)的比較5.5函數(shù)框架設(shè)計要素第5章函數(shù)5.6函數(shù)間信息如何傳遞5.7函數(shù)設(shè)計的綜合例子5.8函數(shù)的嵌套調(diào)用5.9函數(shù)的遞歸調(diào)用5.10作用域問題5.11本章小結(jié)
【主要內(nèi)容】
·揭示函數(shù)機(jī)制設(shè)置的原因和原理以及多個函數(shù)間相互關(guān)系的本質(zhì)含義;
·函數(shù)的聲明、定義、調(diào)用形式;
·函數(shù)參數(shù)的含義、使用規(guī)則;
·函數(shù)的設(shè)計要素及方法實例;
·讀程序的訓(xùn)練;
·自頂向下算法設(shè)計的訓(xùn)練;
·函數(shù)間信息傳遞調(diào)試要點的介紹。
【學(xué)習(xí)目標(biāo)】
·理解程序規(guī)模足夠大時分模塊(函數(shù))構(gòu)建程序的概念;
·理解并掌握在函數(shù)之間傳遞信息的機(jī)制;
·理解并掌握在函數(shù)之間信息屏蔽的機(jī)制;
·熟練掌握創(chuàng)建新函數(shù)的要素;
·理解如何編寫和使用能夠調(diào)用自身的函數(shù)。
解決現(xiàn)實問題的大多數(shù)程序,規(guī)模都比在前幾章中所介紹的程序要大得多,這樣的程序往往需要多人合作來完成,那么用什么樣的規(guī)則來把大的任務(wù)劃分成小的任務(wù)呢?按照我們?nèi)粘L幚韺嶋H問題的經(jīng)驗,按問題的功能來劃分是比較合適的,即把一個大的功能劃分成多個小的功能。像前面章節(jié)中,計算機(jī)處理數(shù)據(jù),一般分成數(shù)據(jù)的輸入、數(shù)據(jù)的處理和數(shù)據(jù)的輸出三部分,合起來就完成了指定的功能。5.1由程序規(guī)模增加引發(fā)的問題此外,有些功能我們需要重復(fù)使用,如前面已經(jīng)多次使用的數(shù)據(jù)的輸入/輸出功能。有效的做法,不應(yīng)該是每使用一次同樣的功能,都要重新編一次程序。
經(jīng)驗表明,開發(fā)和構(gòu)建大型程序的最好方法就是用較小的程序片段或模塊來構(gòu)建它,其中的模塊在必要時是可重復(fù)使用的。這就是“分而治之”這種很古老但很實用的策略在程序設(shè)計中的應(yīng)用。
模塊:能完成指定功能的子程序。
多模塊結(jié)構(gòu):將程序分為不同的模塊,每一模塊實現(xiàn)不同的功能。
模塊化程序設(shè)計的特點如下:
(1)各模塊相對獨立、功能單一,程序邏輯清晰,便于編寫和調(diào)試。
(2)降低了程序設(shè)計的復(fù)雜性,縮短了開發(fā)周期。
(3)提高了模塊的可靠性。
(4)避免了程序開發(fā)的重復(fù)勞動。
(5)易于維護(hù)和擴(kuò)充功能。
“模塊”這個詞有很多別名,如函數(shù)、子程序等。在結(jié)構(gòu)化分析和設(shè)計方法中人們常說的就是“模塊”;在面向?qū)ο蠓治龊驮O(shè)計中又把它說成是“類(class)”;在基于構(gòu)件的開發(fā)方法中的說法則是“構(gòu)件”。
一個程序只由一個模塊組成和由多個小模塊組成,除了模塊數(shù)量不同外,還有其他的區(qū)別嗎?
答:這正是我們下面要討論的問題。
下面先來看一個實際生活中做工程的分工合作的例子——鋪設(shè)瓷磚。
鋪設(shè)瓷磚的流程包括四個步驟:測量→計算→買料→鋪設(shè)。5.2模塊化的設(shè)計思想
問題一:鋪設(shè)瓷磚流程中的四個步驟,單人做和四個人分工完成,它們的區(qū)別有哪些?
答:可以從工作量、工作性質(zhì)和彼此間是否需要信息交流這幾個方面分項來看,內(nèi)容如表5.1所示。
表5.1鋪設(shè)瓷磚時單人做和多人分工完成的比較問題二:
(1)一段程序完成此功能與四段子程序完成此功能的不同點有哪些?
(2)如果用程序來實現(xiàn)上述功能,那么問題的關(guān)鍵點又在哪里呢?
答:程序無論是按各功能分段做,還是合起來一起做,對計算機(jī)而言,本質(zhì)是一樣的,都是由一個CPU完成,故表5.1中的“工作量”、“工作性質(zhì)”項都可以忽略,這樣,程序在一段里完成四個功能和分四段分別完成四個功能,其不同點就是模塊間必須要有信息交流,如“測量”模塊測量的結(jié)果,要如何交給“計算”模塊,“計算”的結(jié)果又如何傳遞給“買料”,等等。因此,在多模塊機(jī)制中,計算機(jī)解題的關(guān)鍵,就是解決程序按功能“分段”即模塊化后模塊間“信息交流”在機(jī)制上如何設(shè)置、如何實現(xiàn)的問題。
程序設(shè)計語言應(yīng)提供這樣的交流機(jī)制,才能真正在程序中實現(xiàn)多個子程序的構(gòu)建。
模塊:能夠單獨命名并獨立地完成一定功能的程序語句的集合。模塊內(nèi)部的實現(xiàn)細(xì)節(jié)和數(shù)據(jù)是外界不可見的,它與外界的聯(lián)系是通過信息接口進(jìn)行的。
信息接口:其他模塊或程序使用該模塊的約定方式,包括輸入/輸出信息等。
在C語言中,模塊的概念是用“函數(shù)”一詞來描述的。
函數(shù)的“信息交流”機(jī)制在設(shè)置時要考慮哪些因素,是怎樣設(shè)計出來的?5.2.1工程計劃
為了說明函數(shù)的信息交流機(jī)制,首先來看看瓷磚分工鋪設(shè)的實際流程。
在鋪設(shè)前,先要做計劃,即按照工種、需要的信息、完成的功能、提交的結(jié)果等項,填好表5.2。
表5.2函數(shù)的設(shè)計思想1——工程計劃
任何一個子工種都由三部分組成:需要的信息、要完成的功能和提交的結(jié)果。5.2.2工程施工
相對于計劃所需要的信息都是抽象的,并不涉及具體的數(shù)據(jù);實際施工時,需要的信息都是具體的,具體如表5.3所示。
表5.3函數(shù)的設(shè)計思想2——工程施工
計劃只需要抽象的概念;施工則要有實際的數(shù)據(jù)。5.2.3函數(shù)定義形式的設(shè)計
與實際的工程類比,我們可以從功能、信息輸入和信息輸出這三個方面考慮函數(shù)的形式設(shè)計。
(1)功能:
·功能描述:工種名稱←→函數(shù)名稱;
·功能實現(xiàn):施工步驟←→函數(shù)體語句。
(2)信息輸入:工種需要的信息←→函數(shù)的輸入信息。
(3)信息輸出:工種提交的結(jié)果←→函數(shù)的輸出信息。
上面三者的對應(yīng)關(guān)系如表5.4所示。
表5.4函數(shù)的設(shè)計思想——工程計劃與函數(shù)定義(1)
為使用的方便,函數(shù)要有名稱,且應(yīng)該設(shè)置有輸入信息的接收入口、提交信息的輸出口。函數(shù)的功能用語句實現(xiàn)。
綜上,與實際工作流程計劃的例子類比,函數(shù)的定義形式在結(jié)構(gòu)上要有三個要素:功能、輸入信息和輸出信息。函數(shù)的定義形式設(shè)計如下:
結(jié)果的類型函數(shù)名(輸入信息)
{
功能完成語句;
提交結(jié)果;/*輸出信息*/
}通常,我們把花括號括起來的部分稱做函數(shù)體。
“輸入信息”和“提交結(jié)果”具體的格式要求是怎樣的呢?這要從二者數(shù)據(jù)的種類和數(shù)量情形來分析,詳見表5.5。
表5.5函數(shù)的設(shè)計思想——工程計劃與函數(shù)定義(2)說明:
(1)輸入接口設(shè)置:由指定的輸入信息參數(shù)表接收。由實際的工種可以看到,需要處理的信息可以有0個或多個,它們可以分成數(shù)值和地址兩大類,因此參數(shù)表中需要處理的信息可以有不同類型的多個數(shù)據(jù)。
(2)輸出接口設(shè)置:有兩種方式。由實際的工種可以看到,提交的信息和需要處理的信息一樣,可以有0個或多個,也分成兩數(shù)值和地址大類,因此提交的結(jié)果也可以有不同類型的多個數(shù)據(jù)。對應(yīng)“提交結(jié)果”功能,C語言中專門設(shè)置了一個return語句來實現(xiàn)結(jié)果的返回。C語言中按提交結(jié)果的數(shù)目,設(shè)計了三種提交結(jié)果的方式:
(1)提交一個結(jié)果:使用return語句返回這個結(jié)果,特別規(guī)定函數(shù)的類型即是這個結(jié)果的類型。
(2)提交多個結(jié)果:把結(jié)果放在約定地址的存儲區(qū)域里。
方法一:使用語句return(約定地址)。使用return語句返回上述存儲區(qū)域的起始地址時有限定條件(具體的限定條件將在后續(xù)“局部量”的例子中給出。)
方法二:在形式參數(shù)表中約定放置提交結(jié)果的地址。特別提醒:此時return的功能仍可使用。
(3)無結(jié)果提交:函數(shù)只完成特定功能,而沒有“計算”出一個具體的數(shù)值,如完成定點報時的工作,這時無return語句提交結(jié)果,因此把函數(shù)類型設(shè)置為void型。
按照上述函數(shù)應(yīng)該有的關(guān)鍵要素,函數(shù)定義的一般形式如下:
函數(shù)類型函數(shù)名(形式參數(shù)表)
{
聲明部分;
語句部分;
}說明:
(1)函數(shù)類型:return語句提交結(jié)果的類型,可以是任何C語言允許的數(shù)據(jù)類型。
(2)函數(shù)名:標(biāo)識符。
(3)形式參數(shù)表:多個變量的定義形式,中間用逗號分開,其中的變量叫做形參。
(4)有時把函數(shù)中的變量聲明和語句部分合稱為“函數(shù)體”。
(5)return語句包含在函數(shù)體中。
函數(shù)設(shè)計三要素:
(1)功能描述:盡量用一個詞來描述函數(shù)的功能,以此做函數(shù)的名稱。
(2)輸入:列出所有的要提供給函數(shù)處理的信息,它們決定了函數(shù)形式參數(shù)表的內(nèi)容。
(3)輸出:輸出信息的類型決定了函數(shù)的類型。
【例5-1】函數(shù)定義形式設(shè)計的例子。寫出前面瓷磚鋪設(shè)流程中“測量”函數(shù)和“計算”函數(shù)的定義形式。
【解】(1)“計算”函數(shù):按照函數(shù)設(shè)計的三要素,列出相應(yīng)信息項如表5.6所示。
表5.6“計算”函數(shù)的設(shè)計形參表有房間長length、寬width和瓷磚尺寸size三個實型參數(shù)。輸出只有一個整型的瓷磚數(shù)量值,故用return返回它即可,函數(shù)的類型就是整型。
由此,可以給出“計算”函數(shù)的定義框架:
intcalculate(floatlength,floatwidth,floatsize)
{函數(shù)體
return(number);
}
(2)“測量”函數(shù):其三要素信息如表5.7所示。
表5.7測量函數(shù)的設(shè)計
·功能:測量給定房間的長、寬尺寸;
·輸入:房間地址;
·輸出:房間的長、寬尺寸。
這里的輸出有兩個,不能同時通過return提交,該如何處理?
答:由于這里的輸出信息多于一個,因此可以采用與輸入信息共用“地址”的方法,即通過在形式參數(shù)表里設(shè)置指針量(指針量中存放的是地址值)來提交房間的長、寬這兩個數(shù)據(jù),故形參表中就有三個參數(shù)了。這樣return的功能沒有用到,所以函數(shù)的類型為void?!皽y量”函數(shù)的定義框架如下:
voidsurvey(int*address,float*length,float*width)
{函數(shù)體}
說明:指針變量定義的一般形式為
數(shù)據(jù)類型*變量名;5.2.4函數(shù)調(diào)用形式的設(shè)計
實際工程的步驟是先按照工種、需要的信息、完成的功能、提交的結(jié)果等抽象信息做好計劃;然后在實際施工時,根據(jù)具體的信息進(jìn)行實際的處理。函數(shù)的具體執(zhí)行過程也是類似的,相對于形式參數(shù),也要提供有實際的操作數(shù)據(jù)——實際參數(shù),才能做具體的處理,它們的對應(yīng)關(guān)系見表5.8。
表5.8函數(shù)的設(shè)計思想——工程施工與函數(shù)調(diào)用
我們把函數(shù)的具體執(zhí)行稱為函數(shù)的調(diào)用,其格式為
函數(shù)名(實際參數(shù)表)
說明:
(1)實際參數(shù)表:實際參數(shù)可以是常數(shù)、變量或表達(dá)式。各實參之間用逗號分隔。
(2)對無參函數(shù)調(diào)用時則無實際參數(shù)表,但括號依然保留。
(3)有類型函數(shù)調(diào)用——只能出現(xiàn)在表達(dá)式右側(cè),如“計算”函數(shù),它會返回一個確定的值,這個值要有一個變量來接收它,這個變量的類型要和函數(shù)類型一致。
(4)無類型函數(shù)調(diào)用——當(dāng)做獨立的語句處理,如“測量”函數(shù),它不返回具體的
數(shù)值。
【例5-2】函數(shù)調(diào)用形式的例子。給出“測量”、“計算”函數(shù)的調(diào)用形式。設(shè)
floata,b; /*房間的長寬*/
intnum; /*瓷磚的數(shù)量*/
int*addr; /*房間地址*/
(1)“測量”函數(shù)的調(diào)用形式:
survey(addr,&a,&b);
(2)“計算”函數(shù)的調(diào)用形式:
num=calculate(a,b,0.36);
說明:函數(shù)調(diào)用時,實際參數(shù)的個數(shù)、類型和位置要與形參的相對應(yīng)。5.2.5函數(shù)間配合運行的機(jī)制設(shè)計
1.函數(shù)的聲明
函數(shù)聲明也稱函數(shù)原型,類似于變量的聲明。函數(shù)聲明里的形式參數(shù)可以只寫類型而省略名稱。
函數(shù)聲明形式如下:
返回值類型符函數(shù)名稱(形式參數(shù)列表);
瓷磚鋪設(shè)流程中各函數(shù)的聲明如下:
voidsurvey(int*address,float*length,float*width);
floatcalculate(floatlength,floatwidth,floatsize);
floatbuy(floatamount);
voidlay(void);
為什么需要函數(shù)原型?
在ANSIC新標(biāo)準(zhǔn)中,允許采用函數(shù)原型方式對被調(diào)用函數(shù)進(jìn)行說明。
函數(shù)原型能告訴編譯器此函數(shù)有多少個參數(shù),每個參數(shù)分別是什么類型,函數(shù)的返回類型又是什么。當(dāng)函數(shù)被調(diào)用時,編譯器可以根據(jù)這些信息判斷實參個數(shù)、類型是否正確等。函數(shù)原型能讓編譯器及時地發(fā)現(xiàn)函數(shù)調(diào)用時存在的語法錯誤。
一般習(xí)慣于在程序文件的開頭為程序中使用的每個函數(shù)編寫函數(shù)原型,這樣能提高編譯效率。
2.函數(shù)的定義
(1)“測量”函數(shù):
/**********
“測量”函數(shù)
功能:完成房間長寬尺寸的測量
輸入:房間地址address
輸出:房間長length、寬width
**********/
voidsurvey(int*address,float*length,float*width)
{函數(shù)體}
(2)“計算”函數(shù):
/**********
“計算”函數(shù)
功能:計算瓷磚數(shù)量
輸入:房間長length、寬width、瓷磚尺寸size
輸出:瓷磚數(shù)量
**********/
intcalculate(floatlength,floatwidth,floatsize)
{函數(shù)體}
(3)“買料”函數(shù)
/**********
“買料”函數(shù)
功能:瓷磚購買
輸入:瓷磚數(shù)量amount
輸出:無
**********/
voidbuy(intamount)
{函數(shù)體}
(4)“鋪設(shè)”函數(shù):
/**********
“鋪設(shè)”函數(shù)
功能:完成房間施工
輸入:無
輸出:無
**********/
voidlay(void)
{函數(shù)體}
3.函數(shù)的調(diào)用
1 #defineSIZE0.36
2 intmain()
3 {
4 int*address;/*房間的地址*/
5 floatlength1,length2;/*房間的長、寬*/
6 intnum;/*瓷磚數(shù)量*/
7
8survey(address,&length1,&length2);
9 num=calculate(length1,length2,SIZE);
10 buy(num);
11 lay();
12 return0;
13 }所有子函數(shù)的功能都在相應(yīng)的函數(shù)定義中給出,這些函數(shù)的運行要通過函數(shù)調(diào)用才能實現(xiàn)。在這個具體的例子中,按照各工種的先后順序在主函數(shù)中調(diào)用它們,這樣就完成了由多個子函數(shù)分工配合實現(xiàn)的復(fù)雜功能的總過程。
函數(shù)調(diào)用
所謂函數(shù)調(diào)用,就是使程序轉(zhuǎn)去執(zhí)行函數(shù)體。在C/C++中,除了主函數(shù)外,其他任何函數(shù)都不能單獨作為程序來運行,任何函數(shù)功能的實現(xiàn)都是通過被主函數(shù)直接或間接調(diào)用來進(jìn)行的。
函數(shù)在程序中有三種表現(xiàn)形式,具體見表5.9。5.3函數(shù)在程序中的三種形式
表5.9函數(shù)的三種形式
函數(shù)頭的格式:
函數(shù)類型函數(shù)名(形式參數(shù)表);
下面再介紹一下函數(shù)的三種形式的格式。
(1)函數(shù)聲明格式:
返回值類型符函數(shù)名稱(形式參數(shù)列表);
(2)函數(shù)定義格式:
/*************************
函數(shù)功能:實現(xiàn)××××功能
函數(shù)參數(shù):參數(shù)1,表示×××
參數(shù)2,表示×××
函數(shù)返回值:表示××
*****************************/
函數(shù)類型函數(shù)名(形式參數(shù)表)
{
聲明部分;
語句部分;
}
(3)函數(shù)調(diào)用格式:
函數(shù)名(實際參數(shù)表)
若站在數(shù)學(xué)的角度,我們可以這樣來解釋函數(shù)——關(guān)于函數(shù)的另一種說法。
當(dāng)我們把“函數(shù)”當(dāng)成一個剛畢業(yè)去找工作的學(xué)生時,可以有以下的故事演繹:
“函數(shù)”的故事
見面會上“函數(shù)”簡單說明了一下自己,
遞上厚厚的文本定義了自己的十八般武藝,
被領(lǐng)導(dǎo)看上調(diào)用來委心重任,
與同事信息交流工作同心協(xié)力,
合作完成大事業(yè)建立功績……函數(shù)在程序中出現(xiàn)的“面目”有三種:聲明形式(或稱說明形式)、定義形式和調(diào)用形式。函數(shù)在程序中通過信息交流,完成相互的配合,最終實現(xiàn)復(fù)雜的功能。
可以通過分別在主函數(shù)和子函數(shù)中實現(xiàn)同一功能來比較實現(xiàn)過程的差異和相同點。請看下面的例子。
【例5-3】在三個數(shù)a、b、c中,找其中的最大值max。
在主函數(shù)中實現(xiàn):
intmain()
{inta,b,c,max;
scanf("%d,%d,%d",&a,&b,&c);
max=a>b?a:b;5.4主函數(shù)與子函數(shù)的比較
max=max>c?max:c;
printf("max=%d",max);
return0;
}
在子函數(shù)中實現(xiàn):
intmax(inta,intb,intc)
{intmax;
max=a>b?a:b;
max=max>c?max:c;
return(max);
}在主函數(shù)main中實現(xiàn)此功能和由子函數(shù)max實現(xiàn)此功能的區(qū)別在于輸入信息的來源和輸出信息的渠道不一樣。主函數(shù)是通過鍵盤輸入要處理的數(shù)據(jù),子函數(shù)是通過信息接口———形參表得到它們;主函數(shù)直接把結(jié)果顯示出來,而子函數(shù)是把結(jié)果返回給調(diào)用者。當(dāng)然,子函數(shù)還要通過被調(diào)用,給它實際的參數(shù)才能運行。
形參和實參變量可以不同名嗎?
答:形參和實參同名或不同名,在語法上都沒有錯,但二者不同名有助于避免混淆,有利于調(diào)試。本章后面會在局部量與全局量的概念學(xué)習(xí)中再討論這個問題。
編寫子函數(shù),最重要的就是確定子函數(shù)的框架。子函數(shù)的框架要素有函數(shù)名、形參表和函數(shù)類型。我們通過實際的例子來學(xué)習(xí)函數(shù)的設(shè)計步驟。
5.5函數(shù)框架設(shè)計要素
【例5-4】函數(shù)設(shè)計的例子1。使用isPrime函數(shù)在屏幕上打印出20以內(nèi)的素數(shù)。
【解】程序設(shè)計思路:首先用子函數(shù)isPrime判斷一個整數(shù)是否為素數(shù);然后在主函數(shù)中調(diào)用isPrime,逐個判斷20以內(nèi)的整數(shù)是否為素數(shù),是則輸出。
isPrime的功能:判斷一個數(shù)是否為素數(shù),返回1代表是素數(shù),返回0代表不是素數(shù)。
如前所述,編寫子函數(shù),最重要的就是確定子函數(shù)的框架,確定了輸入、輸出和功能這三個要素,子函數(shù)的框架要素即函數(shù)名、形參表、函數(shù)類型也就相應(yīng)確定了。具體內(nèi)容如表5.10所示。
表5.10函數(shù)設(shè)計例子1之函數(shù)框架設(shè)計函數(shù)設(shè)計三要素的具體內(nèi)容如表5.11所示。
表5.11函數(shù)設(shè)計三要素說明:當(dāng)輸出信息多于一個時,可以采用以下兩種方法。
(1)與輸入信息共用“地址”;
(2)返回信息是“地址”。
isPrime子函數(shù)程序:
/*************************
函數(shù)isPrime判斷一個數(shù)是否為素數(shù)。
返回1代表是素數(shù);
返回0代表不是素數(shù)
************************/
intisPrime(intx)
{
intk;/*素數(shù)測試范圍*/
if(x==1)return0;/*x是1,不是素數(shù)*/
if(x==2)return1;/*x是1,不是素數(shù)*/
for(k=2;k<x/2;k++)
{
if(x%k==0)return0;/*檢查x是否為素數(shù)*/
}
return1;/*是素數(shù),返回1*/
}
完整的帶主函數(shù)的程序:
1/*創(chuàng)建并使用程序員定義的函數(shù)*/
2#include<stdio.h>
3intisPrime(intx);/*函數(shù)原型——函數(shù)的聲明形式*/
4
5intmain()
6{
7 inti;/*計數(shù)器*/
8
9 /*循環(huán)20次,從1-20逐個判斷其是否為素數(shù)*/
10 for(i=1;i<=20;i++)
11 {
12 if(isPrime(i))/*函數(shù)調(diào)用*/
13 {
14 printf("%d",i);
15 }
16 }/*結(jié)束for循環(huán)*/
17 printf("\n");
18 return0;
19 }/*結(jié)束main*/
20
21/*判斷一個數(shù)是否為素數(shù),返回1代表是素數(shù),返回0代表不是素數(shù)*/
22intisPrime(intx)
23{
24 intk;/*素數(shù)測試范圍*/
25
26 if(x==1)/*1不是素數(shù)*/
27 {
28 return0;
29 }
30 if(x==2)/*2是素數(shù)*/
31 {
32 return1;
33 }
34 for(k=2;k<x/2;k++)/*在2到x/2范圍內(nèi)檢查*/
35 {
36 if(x%k==0)/*檢查x是否為k的倍數(shù)*/
37 {
38 return0;/*不是素數(shù),返回0*/
39 }
40 }
41 return1;/*是素數(shù),返回1*/
42}
程序結(jié)果:
2345711131719
查看函數(shù)調(diào)用的運行軌跡。
圖5.1所示為調(diào)試步驟1,程序從主函數(shù)開始執(zhí)行。
圖5.1函數(shù)設(shè)計例子1之調(diào)試步驟1圖5.2顯示了i變量的情形:
CXX0069:Error:variableneedsstackframe
即變量需要堆棧幀(框架)。造成錯誤的原因是,要查看的變量i只有分配了存儲空間才能看到。圖5.2變量的查看1圖5.3中,將要調(diào)用子函數(shù)isPrinme之前,顯示i=1。
圖5.4所示為調(diào)試步驟3,按F11鍵跟蹤子函數(shù)。
此時,有一個現(xiàn)象值得注意,i的值顯示:
CXX0017:Error:symbol"i"notfound
即符號i未找到,如圖5.5所示。
圖5.3函數(shù)設(shè)計例子1之調(diào)試步驟2
圖5.4函數(shù)設(shè)計例子1之調(diào)試步驟3
圖5.5變量的查看2為什么會出現(xiàn)圖5.5所示的現(xiàn)象呢?剛剛在主函數(shù)中還看到了i,難道是程序執(zhí)行出錯了嗎?其實不是,C程序多函數(shù)機(jī)制設(shè)置就是這樣處理的,這涉及變量或數(shù)據(jù)的作用域問題,在后面有關(guān)作用域問題的討論中會給出相關(guān)的概念,在此只簡單解釋一下。多函數(shù)機(jī)制中規(guī)定每個函數(shù)只能使用自己本函數(shù)內(nèi)部定義的量(除此之外,當(dāng)然還有特例情形),因此,在進(jìn)行變量的查看時也就只能看到正在執(zhí)行的函數(shù)有權(quán)限使用的變量的值了。圖5.6所示為調(diào)試步驟4,圖中可以查看isPrime(i)作為if的表達(dá)式其取值的情況。
圖5.7所示為調(diào)試步驟5,可以看到,i值每增加一次,就調(diào)用一次isPrime函數(shù)。
圖5.8所示為調(diào)試步驟6,可以看到,i=3時,isPrime返回1,說明其是素數(shù)。
圖5.9所示為調(diào)試步驟7,當(dāng)i=6時,isPrime返回0,說明其不是素數(shù)。
圖5.10所示為調(diào)試步驟8,當(dāng)i=20時,for循環(huán)對isPrime做最后一次調(diào)用。
圖5.6函數(shù)設(shè)計例子1之調(diào)試步驟4
圖5.7函數(shù)設(shè)計例子1之調(diào)試步驟5
圖5.8函數(shù)設(shè)計例子1之調(diào)試步驟6
圖5.9函數(shù)設(shè)計例子1之調(diào)試步驟7
圖5.10函數(shù)設(shè)計例子1之調(diào)試步驟8圖5.11所示為調(diào)試步驟9,此時for循環(huán)結(jié)束,i=21。
圖5.11函數(shù)設(shè)計例子1之調(diào)試步驟9
函數(shù)運行順序為:主函數(shù)和子函數(shù)配合運行時,程序總是從主函數(shù)開始運行,遇到有子函數(shù)的調(diào)用時,進(jìn)入子函數(shù)運行,直至運行完畢,然后再回到主函數(shù),繼續(xù)運行。
例如,在main函數(shù)中,調(diào)用子函數(shù)a的流程如圖5.12所示。
圖5.12函數(shù)調(diào)用流程
有關(guān)函數(shù)的問題
(1)函數(shù)名結(jié)構(gòu):“動詞”或者“動詞+名詞”,如CalculateGetMax。
(2)變量名結(jié)構(gòu):“名詞”或者“形容詞+名詞”,如ValuenewValue。
(3)函數(shù)設(shè)計規(guī)則。表5.12中給出了在設(shè)計函數(shù)時應(yīng)該遵循的規(guī)則。
表5.12函數(shù)設(shè)計規(guī)則說明:
①一個函數(shù)一個功能。對函數(shù)的功能可以用一句話描述。
②函數(shù)不能過長。1986年IBM在OS/360的研究結(jié)果表明,大多數(shù)有錯誤的函數(shù)都大于500行。1991年對148000行代碼的研究表明,小于143行的函數(shù)比更長的函數(shù)更容易維護(hù)。
③檢查函數(shù)的輸入信息。輸入信息有問題時,要向調(diào)用者提出警示信息。函數(shù)的輸入主要有兩種:一種是參數(shù)輸入;另一種是全局變量、數(shù)據(jù)文件的輸入,即非參數(shù)輸入。函數(shù)在使用輸入之前,應(yīng)進(jìn)行必要的檢查。
選擇有意義的函數(shù)名和有意義的參數(shù)名,可以使程序具有更好的可讀性,并有助于避免過多使用注釋。
【例5-5】函數(shù)設(shè)計的例子2。用程序?qū)崿F(xiàn)從n個不同的元素中每次取k個元素的組合數(shù)目。計算公式如下:
【解】因為公式中要多次計算階乘,所以我們先設(shè)計一個計算階乘的子函數(shù)結(jié)構(gòu),如表5.13所示。
表5.13函數(shù)設(shè)計例子2之框架設(shè)計
表5.14函數(shù)設(shè)計例子2之函數(shù)實現(xiàn)設(shè)計
圖5.13函數(shù)的返回流程
(1)函數(shù)的返回值是int型,為什么函數(shù)類型要用Float?
(2)函數(shù)體中有兩個return語句,每次返回幾個值?
答:(1)求階乘的結(jié)果放到float型變量中,可以運算比int型更大的數(shù),而結(jié)果不會溢出。
(2)從流程圖5.13中可以清楚地看到,雖然流程中有多處返回,但每個返回執(zhí)行后,流程就結(jié)束了,所以每次只能返回一個值。
程序總流程:
1 #include<stdio.h>
2 floatfactorial(intx);
3 /*計算整數(shù)x的階乘*/
4 floatfactorial(intx)
5 {
6 inti;
7 floatt=1;
8 for(i=1;i<=x;i++)
9 t=t*i;
10 return(t);
11 }函數(shù)聲明函數(shù)定義
12
13 intmain()
14 {
15 floatc;
16 intm,n;
17
18 printf("inputm,n:");
19 scanf("%d%d",&m,&n);
20 c=factorial(m)/(factorial(n)*factorial(m-n));
函數(shù)調(diào)用
21 printf("Theresultis%8.1f",c);
22 return0;
23 }
函數(shù)的聲明出現(xiàn)在哪里比較好?
對于函數(shù)的聲明位置,C語言的規(guī)則是可以放在調(diào)用函數(shù)內(nèi),也可以放在函數(shù)外部。在調(diào)用一個函數(shù)時,如果前面的代碼沒有函數(shù)定義或聲明,將導(dǎo)致編譯出錯。
一般地,當(dāng)程序中有多個子函數(shù)時,它們的聲明最好都放在預(yù)編譯命令后,而不要放在調(diào)用函數(shù)內(nèi)。這樣聲明的特點是:當(dāng)前文件從函數(shù)的聲明位置開始到文件結(jié)束的任何函數(shù)中都可以調(diào)用該函數(shù)。簡單地說,函數(shù)聲明和變量說明是類似的,也是要“先聲明,后使用”。
子函數(shù)要處理的信息是通過實際參數(shù)傳遞給形式參數(shù)得到的,下面將通過實際例子觀察C函數(shù)間信息傳遞的方式。5.6函數(shù)間信息如何傳遞5.6.1C函數(shù)實際參數(shù)與形式參數(shù)的關(guān)系
形式參數(shù):簡稱“形參”,是在定義函數(shù)名和函數(shù)體的時候使用的參數(shù),目的是用來接收調(diào)用該函數(shù)時傳入的參數(shù)。
實際參數(shù):簡稱“實參”,是在調(diào)用時傳遞給該函數(shù)的參數(shù)。
表5.15形參與實參的關(guān)系要嚴(yán)格按照其語法格式的要求來使用函數(shù)的不同格式,初學(xué)者最容易犯的錯誤,就是不注意形式參數(shù)與實際參數(shù)的填寫,在此特別強調(diào)一下。
(1)形式參數(shù)表:在函數(shù)定義里,形式參數(shù)表中放參數(shù)的定義形式,即變量的定義形式。如果形參是數(shù)組,則在數(shù)組括號之間并不需要指定數(shù)組的大小,因為此時只傳遞數(shù)組的地址。函數(shù)定義形式:
函數(shù)類型函數(shù)名(形式參數(shù)表)
{
聲明部分;
語句部分;
}形式參數(shù)表中放參數(shù)的定義形式,如:基本變量:intx指針:int*ptr數(shù)組:一維inta[]二維intb[][6]。12
(2)實際參數(shù)表:在函數(shù)調(diào)用時,實際參數(shù)表中放參數(shù)的使用形式,即變量的使用形式(或稱變量引用形式);對數(shù)組則僅僅放置數(shù)組名。
函數(shù)調(diào)用形式:
函數(shù)名(實際參數(shù)表)實際參數(shù)表中放參數(shù)的使用形式,如:基本變量:x指針:ptr數(shù)組:一維a二維b
(3)函數(shù)返回return:括號里的參數(shù)可以是一個變量,也可以是一個常量,但一定只能是一個量,不能是多個。
函數(shù)返回形式:
Return(參數(shù))5.6.2函數(shù)間信息傳遞的實際例子
【例5-6】函數(shù)間信息傳遞的例子1。傳遞一個數(shù)組與傳遞一個變量給函數(shù)的區(qū)別。
【解】這里設(shè)計兩個子函數(shù)來觀察這種區(qū)別,函數(shù)的具體功能設(shè)計見表5.16。
表5.16函數(shù)間信息傳遞的例子1之函數(shù)功能設(shè)計
表5.17函數(shù)間信息傳遞的例子1之函數(shù)框架設(shè)計程序?qū)崿F(xiàn):
1/*傳遞一個數(shù)組與傳遞一個變量給函數(shù)的區(qū)別*/
2#include<stdio.h>
3#defineSIZE5
4
5/*函數(shù)聲明*/
6
voidmodify_array(inta[],intlength);/*修改整個數(shù)組元素的值*/
7voidmodify_value(intv);/*修改單個變量值*/
8
9intmain()
10{
11inta[SIZE]={1,3,5,7,9};/*初始化數(shù)組a*/
12intvalue;
13inti;/*計數(shù)器*/
14
15printf("以下結(jié)果均在main函數(shù)中觀察得到\n");
16printf("在modify_array函數(shù)中修改傳遞來的整個數(shù)組:\n");
17printf("modify_array調(diào)用前a數(shù)組=");
18/*輸出原始數(shù)組*/
19for(i=0;i<SIZE;i++)
20{
21printf("%3d",a[i]);
22}
23printf("\n");
24/*把數(shù)組傳遞給函數(shù),函數(shù)中傳入了數(shù)組a的地址*/
25modify_array(a,SIZE);
26printf("modify_array調(diào)用后a數(shù)組=");
27/*輸出修改后的數(shù)組*/
28for(i=0;i<SIZE;i++)
29{
30printf("%3d",a[i]);
31}
32
33/*把變量value的副本傳遞給函數(shù)*/
34value=6;
35printf("\n\n在modify_value函數(shù)中修改傳遞來的單個變量:\n");
36printf("modify_value調(diào)用前:value=%d\n",value);
37modify_value(value);
38printf("modify_value調(diào)用后:value=%d\n",value);
39
40/*把數(shù)組元素a[SIZE-1]的副本傳遞給函數(shù)*/
41printf("\n在modify_value函數(shù)中修改傳遞來的單個數(shù)組元素的值:\n");
42printf("modify_value調(diào)用前:a[%d]=%d\n",SIZE-1,a[SIZE-1]);
43modify_value(a[SIZE-1]);
44printf("modify_value調(diào)用后:a[%d]=%d\n",SIZE-1,a[SIZE-1]);
45
46return0;/*表示程序成功結(jié)束*/
47}/*main函數(shù)結(jié)束*/
48
49/*在函數(shù)modify_array中,數(shù)組的地址被傳入到函數(shù)中*/
50voidmodify_array(intb[],intsize)
51{
52intj;/*計數(shù)器*/
53/*將數(shù)組的每個元素都加1*/
54for(j=0;j<size;j++)
55{
56b[j]=b[j]+1;
57}
58}
59
60/*在函數(shù)modify_value中,變量v的副本被傳入到函數(shù)中*/
61voidmodify_value(intv)
62{
63v=v*2;/*將參數(shù)值乘以2*/
64}/*函數(shù)modify_int結(jié)束*/
程序結(jié)果(以下結(jié)果均在main函數(shù)中觀察得到):
在modify_array函數(shù)中修改傳遞來的整個數(shù)組:
modify_array調(diào)用前a數(shù)組=13579
modify_array調(diào)用后a數(shù)組=246810
在modify_value函數(shù)中修改傳遞來的單個變量:
modify_value調(diào)用前:value=6
modify_value調(diào)用后:value=6
在modify_value函數(shù)中修改傳遞來的單個數(shù)組元素的值:
modify_value調(diào)用前:a[4]=10
modify_value調(diào)用后:a[4]=10
為什么給子函數(shù)傳遞數(shù)組地址,就可以從同地址中得到被修改的值,而傳遞單個的變量值,就得不到被修改的結(jié)果?
答:上述問題,需要跟蹤函數(shù)的調(diào)用過程,查看實際參數(shù)與形式參數(shù)的空間分配使用狀況,才能清楚。
查看形參與實參單元分配及函數(shù)間信息如何傳遞。
(1)傳遞數(shù)組地址。
圖5.14所示為調(diào)試步驟1,modify_array被調(diào)用之前,實參a數(shù)組的地址為0x12ff6c。
圖5.14函數(shù)間信息傳遞的例子1之調(diào)試步驟1
圖5.15為調(diào)試步驟2,此時進(jìn)入子函數(shù)modify_array,將a數(shù)組的地址傳遞給b數(shù)組。
圖5.15函數(shù)間信息傳遞的例子1之調(diào)試步驟2
圖5.16所示為調(diào)試步驟3,可見在Watch窗口中,b數(shù)組的值只顯示了一個,要看到全部的信息,可以通過圖5.17所示的Memory窗口查看。
圖5.16函數(shù)間信息傳遞的例子1之調(diào)試步驟3圖5.17的Memory窗口顯示對b數(shù)組的內(nèi)容修改完畢,其值為2、4、6、8、10。
圖5.17Memory窗口圖5.18所示為調(diào)試步驟4,此時返回主函數(shù),因為a與b是同一地址,所以看到的數(shù)據(jù)依然是前面看到的那些。通過形參與實參“共用地址”的方法,可以把多個處理結(jié)果返回給調(diào)用者,這在返回值多于一個的場合是一種有效的方法。
圖5.18函數(shù)間信息傳遞的例子1之調(diào)試步驟4以上函數(shù)間通過共用地址傳遞信息,實參、形參單元及其中值的變化如圖5.19所示。圖5.19函數(shù)間通過共用地址傳遞信息
(2)傳遞一個變量值(值傳遞——傳值調(diào)用)。
圖5.20所示為調(diào)試步驟5,modify_value被調(diào)用之前,實參value的值為6,地址是0x12ff68。
圖5.21所示為調(diào)試步驟6,此時進(jìn)入modify_value函數(shù)執(zhí)行,實際參數(shù)的值被賦給形參v,v的地址為0x12ff14。
注意:此時形參、實參各分存儲單元,只是把實參值拷貝到了形參的空間,并不是像前面數(shù)組那樣共用地址。
圖5.22所示為調(diào)試步驟7,此時modify_value函數(shù)對形參進(jìn)行修改,v=12。
圖5.20函數(shù)間信息傳遞的例子1之調(diào)試步驟5
圖5.21函數(shù)間信息傳遞的例子1之調(diào)試步驟6
圖5.22函數(shù)間信息傳遞的例子1之調(diào)試步驟7圖5.23所示為調(diào)試步驟8,此時返回主函數(shù),實參value的值仍然是原來的6,即形參v的改變并不影響實參的值,因為它們的存儲空間是各自獨立的。
函數(shù)間通過單個變量給形參賦值傳遞信息,實參、形參單元及其中值的變化如圖5.24所示。
圖5.23函數(shù)間信息傳遞的例子1之調(diào)試步驟8
圖5.24函數(shù)間通過單個變量給形參賦值傳遞信息
(3)傳遞一個數(shù)組元素值。
圖5.25所示為調(diào)試步驟9,modify_value被調(diào)用之前,實參a[SIZE-1]的值為10(注:SIZE=5),地址是0x12ff7c。
圖5.26所示為調(diào)試步驟10,此時進(jìn)入modify_value函數(shù)執(zhí)行,實際參數(shù)的值被賦給形參v,v的地址為0x12ff14。
注意:此時形參、實參各分存儲單元,只是把實參值拷貝到了形參的空間。
圖5.27所示為調(diào)試步驟11,此時modify_value函數(shù)對形參進(jìn)行修改,v=20。
圖5.25函數(shù)間信息傳遞的例子1之調(diào)試步驟9
圖5.26函數(shù)間信息傳遞的例子1之調(diào)試步驟10
圖5.27函數(shù)間信息傳遞的例子1之調(diào)試步驟11圖5.28所示為調(diào)試步驟12,此時返回主函數(shù),實參a[SIZE-1]的值仍然是原來的10,即形參v的改變并不影響實參的值,因為它們的存儲空間是各自獨立的。
函數(shù)間通過單個變量給形參賦值傳遞信息,實參、形參單元及其中值的變化如圖5.29所示。
圖5.28函數(shù)間信息傳遞的例子1之調(diào)試步驟12
圖5.29函數(shù)間通過數(shù)組元素給形參賦值傳遞信息
關(guān)于形參與實參單元分配等
(1)數(shù)組名做參數(shù),實參、形參數(shù)組是共用地址的;
(2)普通變量做參數(shù),是各分單元的;
(3)在函數(shù)內(nèi)定義的量,只在本函數(shù)內(nèi)可見。
由此例可體會到通過參數(shù)傳遞地址即傳址調(diào)用(或稱引用調(diào)用reference)的好處,它可以減少函數(shù)間信息傳遞時需要復(fù)制的數(shù)量,從而提高信息傳遞效率。
關(guān)于值調(diào)用
(1)形參、實參有各自的存儲單元;
(2)函數(shù)調(diào)用時,將實參的值復(fù)制給形參。
(3)在函數(shù)中參加運算的是形參,形參單元值的改變不能影響實參單元。
“值調(diào)用”(callbyvalue)的方法是把實際參數(shù)的值復(fù)制到函數(shù)的形式參數(shù)中。這樣,函數(shù)中的形式參數(shù)的任何變化不會影響到調(diào)用時所使用的變量。傳值調(diào)用起到了數(shù)據(jù)隔離的作用,即不允許被調(diào)函數(shù)去修改元素變量的值。
關(guān)于引用調(diào)用
(1)形參與實參共用地址;
(2)調(diào)用函數(shù)可以修改原始變量的值。
“引用調(diào)用”(callbyreference)的方法是實際參數(shù)與形式參數(shù)共用地址,在函數(shù)中,這個地址用來訪問調(diào)用中所使用的實際參數(shù)。這意味著,形式參數(shù)的變化會影響調(diào)用時所使用的變量。
【例5-7】函數(shù)間信息傳遞的例子2。求數(shù)組intb[]中下標(biāo)為m到n項的和。主函數(shù)負(fù)責(zé)提供數(shù)組、m和n的值及結(jié)果的輸出,求和功能由子函數(shù)func完成。
【設(shè)計方案一】對函數(shù)結(jié)構(gòu)的設(shè)計如表5.18所示。
表5.18函數(shù)間信息傳遞的例子2之函數(shù)框架設(shè)計1把數(shù)組的信息通過傳址方式傳遞,m、n的值通過傳值方式傳遞,結(jié)果只有一個整型,可以通過return語句返回。表5.19給出了func函數(shù)的實現(xiàn)。
表5.19函數(shù)間信息傳遞的例子2之函數(shù)實現(xiàn)設(shè)計1程序?qū)崿F(xiàn):
1/*函數(shù)間信息傳遞的例子2——方案一*/
2#include"stdio.h"
3#defineSIZE10
4intfunc(intb[],intm,intn);
5
6/*求數(shù)組intb[]中下標(biāo)為m到n項的和*/
7intfunc(intb[],intm,intn)
8{inti,sum=0;
9
10 for(i=m;i<=n;i++)
11 {
12 sum=sum+b[i];
13 }
14returnsum;
15}
16
17intmain()
18{
19
intx;
20 inta[SIZE]={1,2,3,4,5,6,7,8,9,0};
21 intp=3,q=7;/*指定求和下標(biāo)的位置*/
22
23 printf("數(shù)組a下標(biāo)%d至%d項的元素為:",p,q);
24 for(inti=p;i<=q;i++)
25 {
26 printf("%d",a[i]);
27 }
28 printf("\n");
29
30 x=func(a,p,q);
31 printf("數(shù)組a下標(biāo)%d至%d項的元素和為:%d\n",p,q,x);
32 return0;
33}程序結(jié)果:
數(shù)組a下標(biāo)3~7項的元素為:45678
數(shù)組a下標(biāo)3~7項的元素和為:30
【設(shè)計方案二】我們?nèi)匀煌ㄟ^傳址方式傳遞數(shù)組的信息,既然是傳址,信息傳遞是雙向的,func的結(jié)果可以放在數(shù)組的約定位置,如數(shù)組的最后一個元素的位置,這樣就不用通過return語句返回了。采用這種方案,形參要增加一個“結(jié)果在b中存放的位置”,具體參見表5.20。
表5.20函數(shù)間信息傳遞的例子2之函數(shù)框架設(shè)計2
表5.21函數(shù)間信息傳遞的例子2之函數(shù)實現(xiàn)設(shè)計2程序?qū)崿F(xiàn):
1/*函數(shù)間信息傳遞的例子2——方案二*/
2#include"stdio.h"
3#defineSIZE10
4
5voidfunc(intb[],intm,intn,intsize);
6
7/*求數(shù)組intb[]中下標(biāo)為m到n項的和,結(jié)果放在下標(biāo)是size的位置*/
8 voidfunc(intb[],intm,intn,intsize)
9 {
10 inti,sum=0;
11
12 for(i=m;i<=n;i++)
13 {
14 sum=sum+b[i];
15 }
16 b[size]=sum;/*求和的結(jié)果放在b數(shù)組指定位置*/
17 }
18
19 intmain()
20 {
21 inta[SIZE]={1,2,3,4,5,6,7,8,9,0};
22 intp=3,q=7;/*指定求和下標(biāo)的位置*/
23
24 printf("數(shù)組a下標(biāo)%d至%d項的元素為:",p,q);
25 for(inti=p;i<=q;i++)
26 {
27 printf("%d",a[i]);
28 }
29 printf("\n");
30
31 func(a,p,q,SIZE-1);
32 printf("數(shù)組a下標(biāo)%d至%d項的元素和為:%d\n",p,q,a[SIZE-1]);
33 return0;
34 }
程序結(jié)果:
數(shù)組a下標(biāo)3~7項的元素為:45678
數(shù)組a下標(biāo)3~7項的元素和為:30
【例5-8】函數(shù)間信息傳遞的例子3。讀程序,分析結(jié)果。
1/*函數(shù)間信息傳遞的例子3*/
2#include"stdio.h"
3#include"string.h"
4voidi_s(charin[],charout[]);
5
6voidi_s(charin[],charout[])
7{
8
inti,j;
9
intl=strlen(in);
10
for(i=j=0;i<l;i++,j++)
11
{
12
out[j]=in[i]; /*步驟1*/
13 out[++j]='__'; /*步驟2*/
14 in[i]+=1; /*步驟3*/
15 }
16 out[j-1]='\0';
17}
18
19intmain()
20{
21
chars[]="1234";
22charg[20];
23
24i_s(s,g);
25printf("%s\n",g);
26return0;
27}通過上面函數(shù)間信息傳遞的規(guī)則,讀者可以自己分析例5-8,每個執(zhí)行步驟的中間結(jié)果項已經(jīng)列在表5.22中了,以方便讀程。
表5.22函數(shù)間信息傳遞的例子35.6.3函數(shù)間信息傳遞的總結(jié)
函數(shù)間信息傳遞的種類參見表5.23。
表5.23函數(shù)間信息傳遞的種類函數(shù)間信息傳遞的方式參見表5.24。
表5.24函數(shù)間信息傳遞的方式
表5.25函數(shù)間信息傳遞的途徑5.6.4共享數(shù)據(jù)的使用限制
通過前面的例子可知,函數(shù)間信息傳遞時有些數(shù)據(jù)往往是共享的,程序可以在不同的場合通過不同的途徑訪問同一個數(shù)據(jù)對象,有時在無意之中的誤操作會改變有關(guān)數(shù)據(jù)的狀況,而這是我們所不希望出現(xiàn)的。
既要使數(shù)據(jù)能在一定范圍內(nèi)共享,又要保證其不被任意修改,這時可以使用const,即把形參中有關(guān)數(shù)據(jù)定義為常量。
const是一個C語言的關(guān)鍵字,它限定一個變量不允許被改變。使用const在一定程度上可以提高程序的安全性和可靠性。
【例5-9】const的例子。使用const類型限定符來保護(hù)數(shù)組不被修改。
1/*const的例子*/
2#include<stdio.h>
3#defineSIZE3
4voidmodify(constinta[]);/*函數(shù)原型*/
5intb[SIZE];/*全局量,在函數(shù)之外定義的量,b數(shù)組用于保存修改后的數(shù)組*/
6
7/*程序從函數(shù)main開始執(zhí)行*/
8intmain()
9{
10inta[SIZE]={3,2,1};/*初始化*/
11inti;/*計數(shù)器*/
12
13modify(a);/*調(diào)用函數(shù)*/
14printf("\nmodify函數(shù)運行后的a數(shù)組為:");
15for(i=0;i<SIZE;i++)
16{
17printf("%3d",a[i]);/*打印出函數(shù)執(zhí)行后的數(shù)組*/
18}
19
20printf("\nmodify函數(shù)運行后的b數(shù)組為:");
21for(i=0;i<SIZE;i++)/*打印出修改后的數(shù)組*/
22{
23printf("%3d",b[i]);
24}
25return0;
26}
27
28/*取得數(shù)組a中的值,處理后保存在數(shù)組b中*/
29voidmodify(constinta[])
30{
31inti;/*計數(shù)器*/
32for(i=0;i<SIZE;i++)
33{
34/*a[i]=a[i]*2;試圖修改數(shù)組a的值,編譯將會報錯*/
35b[i]=a[i]*2;
36}
37}程序結(jié)果:
modify函數(shù)運行后的a數(shù)組為:321
modify函數(shù)運行后的b數(shù)組為:642
【題目】處理3位學(xué)生四門課程的成績:
(1)求所有成績中的最低、最高成績;
(2)每個學(xué)生的平均成績;
(3)輸出結(jié)果。5.7函數(shù)設(shè)計的綜合例子
【問題分析】
(1)數(shù)據(jù):把3位學(xué)生四門課程的成績存儲在表5.26所示的二維數(shù)組中。
studentGrades[學(xué)生數(shù)][課程門數(shù)]
表5.26函數(shù)設(shè)計的綜合例子(1)
(2)函數(shù)設(shè)計:參見表5.27。
表5.27函數(shù)設(shè)計的綜合例子(2)
(3)程序?qū)崿F(xiàn):
1 /*函數(shù)設(shè)計的綜合例子——多個函數(shù)對二維數(shù)組的處理*/
2 #include<stdio.h>
3 #defineSTUDENTS3
4 #defineEXAMS4
5
6 /*函數(shù)原型*/
7 intminimum(constintgrades[][EXAMS],intpupils,inttests);
8 intmaximum(constintgrades[][EXAMS],intpupils,inttests);
9 doubleaverage(constintsetOfGrades[],inttests);
10 voidprintArray(constintgrades[][EXAMS],intpupils,inttests);
11
12 /*程序從函數(shù)main開始執(zhí)行*/
13 intmain()
14 {
15 intstudent;/*學(xué)生計數(shù)器*/
16
17 /*初始化3個學(xué)生(行)的成績*/
18 intstudentGrades[STUDENTS][EXAMS]
19 ={{77,68,86,73},
20 {96,87,89,78},
21 {70,90,86,81}
22 };
23 /*輸出數(shù)組studentGrades*/
24 printf("Thearrayis:\n");
25 printArray(studentGrades,STUDENTS,EXAMS);
26
27 /*確定最高分?jǐn)?shù)與最低分?jǐn)?shù)*/
28 printf("\n\nLowestgrade:%d\nHighestgrade:%d\n",
29 minimum(studentGrades,STUDENTS,EXAMS),
30 maximum(studentGrades,STUDENTS,EXAMS));
31 /*計算每個學(xué)生的平均分?jǐn)?shù)*/
32 for(student=0;student<=STUDENTS-1;student++)
33
{
34 printf("Theaveragegradeforstudent%dis%.2f\n",
35 student,average(studentGrades[student],EXAMS));
36 }/*結(jié)束for*/
37
38 return0;/*表示程序成功結(jié)束*/
39
40 }/*結(jié)束main*/
41
42 /*找出最低分?jǐn)?shù)*/
43 intminimum(constintgrades[][EXAMS],intpupils,inttests)
44 {
45 inti;/*計數(shù)器*/
46 intj;/*計數(shù)器*/
47 intlowGrade=100;/*初始化為可能的最高分?jǐn)?shù)*/
48
49
for(i=0;i<pupils;i++)/*循環(huán)數(shù)組grades的行*/
50
{
51
for(j=0;j<tests;j++)/*循環(huán)數(shù)組grades的列*/
52
{
53 if(grades[i][j]<lowGrade)
54 {
55 lowGrade=grades[i][j];
56 }
57 }
58 }
59 returnlowGrade;/*返回最低分?jǐn)?shù)*/
60 }/*函數(shù)minimum結(jié)束*/
61
62 /*找出最高分?jǐn)?shù)*/
63 intmaximum(constintgrades[][EXAMS],intpupils,inttests)
64 {
65 inti;/*學(xué)生計數(shù)器*/
66 intj;/*考試計數(shù)器*/
67 inthighGrade=0;/*初始化為可能的最低分?jǐn)?shù)*/
68
69 for(i=0;i<pupils;i++)/*循環(huán)數(shù)組grades的行*/
70
{
71 f
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- YY/T 0581.2-2024輸液連接件第2部分:無針連接件
- 貴州大學(xué)《生物防治學(xué)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025年貴州省安全員《C證》考試題庫及答案
- 2025湖北建筑安全員《C證》考試題庫
- 2025山西建筑安全員《A證》考試題庫及答案
- 硅湖職業(yè)技術(shù)學(xué)院《唐詩宋詞賞析》2023-2024學(xué)年第一學(xué)期期末試卷
- 貴陽學(xué)院《物流英語》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025年河北建筑安全員C證(專職安全員)考試題庫
- 2025海南省安全員考試題庫及答案
- 2025年-黑龍江省安全員《A證》考試題庫及答案
- 三支一扶協(xié)議書模板
- 燙傷的防治與護(hù)理
- 2024年全國職業(yè)院校技能大賽高職組(護(hù)理技能賽項)備賽試題庫(含答案)
- 駕駛員三年內(nèi)工作總結(jié)
- 青年你為什么要入團(tuán)-團(tuán)員教育主題班會-熱點主題班會課件
- 司法鑒定工作應(yīng)急預(yù)案
- 《竹結(jié)構(gòu)建筑技術(shù)規(guī)程》
- 大一中國近代史綱要期末考試試題及答案
- (完整版)鋼筋加工棚驗算
- 安徽省合肥市廬陽區(qū)2023-2024學(xué)年三年級上學(xué)期期末數(shù)學(xué)試卷
- 概念方案模板
評論
0/150
提交評論