版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第7章
函數(shù)——模塊化程序設計方法的實現(xiàn)7.1模塊化程序設計方法與函數(shù)7.2函數(shù)的定義7.3函數(shù)的調(diào)用7.4函數(shù)調(diào)用的條件與函數(shù)聲明7.5函數(shù)的嵌套調(diào)用和遞歸調(diào)用7.6變量的作用域與函數(shù)間的數(shù)據(jù)傳遞7.7用函數(shù)實現(xiàn)模塊化程序設計實訓任務十三
熟悉函數(shù)的功能及其使用方法實訓任務十四
學習模塊化程序設計的方法
7.1模塊化程序設計方法與函數(shù)
程序模塊與函數(shù)有何關(guān)系?怎樣根據(jù)問題功能模塊設計函數(shù)?
結(jié)構(gòu)化程序設計由迪克斯特拉(E.W.Dijkstra)在1969年提出,是以模塊化設計為中心,將待開發(fā)的軟件系統(tǒng)劃分為若干個相互獨立的模塊,這樣使完成每一個模塊的工作變得單純而明確,為設計一些較大的軟件打下了良好的基礎(chǔ)。模塊化程序設計的基本要點是貫徹“自頂向下,逐步細化”的思想方法,即將一個復雜功能的編程問題,劃分成若干個功能相對簡單的子問題。這種劃分可以逐層進行,直到便于編程為止。在C語言中,一個模塊的功能由一個函數(shù)來實現(xiàn)。頂層函數(shù)是主函數(shù)main()。功能模塊與C語言函數(shù)的關(guān)系如圖7.1所示。
圖7.1模塊與函數(shù)分析問題,劃分出模塊之后,C程序設計的工作就是函數(shù)的定義了。一般來說,底層模塊函數(shù)的定義主要是某種功能的實現(xiàn),上層模塊函數(shù)的定義主要考慮對下層模塊函數(shù)的調(diào)用與數(shù)據(jù)傳遞。
C語言中包含多種函數(shù)類型。從用戶使用的角度可分為標準庫函數(shù)和用戶自定義函數(shù);從函數(shù)接口可分為有參函數(shù)和無參函數(shù)。標準庫函數(shù)是由系統(tǒng)提供的,用戶只需按要求調(diào)用即可。
7.2函
數(shù)
的
定
義
怎樣定義函數(shù)?定義函數(shù)要考慮哪些問題?
定義函數(shù)要解決兩個方面的問題:一是函數(shù)間的接口問題,二是功能實現(xiàn)問題。接口問題包括如何被上層函數(shù)調(diào)用,調(diào)用時需傳遞什么數(shù)據(jù),調(diào)用返回時需傳帶什么數(shù)據(jù)。功能實現(xiàn)問題就是如何實現(xiàn)模塊的過程算法。
函數(shù)定義的一般形式為
第一種形式是C語言ANSI的標準形式,VC++6.0系統(tǒng)中只允許這種形式;第二種形式是TurboC編譯系統(tǒng)允許的擴展形式。
下面對函數(shù)定義的各組成部分作一說明。
(1)基類型符可以是基本數(shù)據(jù)類型中任一種類型的標識符,如int、char、float、double等。其作用是定義函數(shù)返回值的類型。當函數(shù)執(zhí)行后不需要返回值或不允許返回值時,函數(shù)類型標識符用void表示。函數(shù)類型標識符可以缺省,系統(tǒng)默認為int型。當缺省時,在TurboC系統(tǒng)中編譯可以完全通過,而在VC++6.0系統(tǒng)中會出現(xiàn)警告。標準C語言中不建議省略函數(shù)類型。
(2)函數(shù)名是函數(shù)調(diào)用的名稱。其命名規(guī)則同變量名、數(shù)組名一樣。實質(zhì)上,函數(shù)名表示函數(shù)存儲的首地址,將在“指針”一章詳細介紹。
(3)形式參數(shù),簡稱形參,用于接收函數(shù)調(diào)用時所傳遞的數(shù)據(jù),可以是變量名、數(shù)組名等。因為在函數(shù)定義時,不表示具體數(shù)據(jù),只表示虛設的數(shù)據(jù)對象,所以稱為形式參數(shù)。當形參多于1個時,形參之間要用逗號分隔,就構(gòu)成了形參表。在第一種定義形式中,每一個形參前要說明其類型。在第二種定義形式中,只列出形參名,但在其后對形參的類型逐一進行說明。如果形式參數(shù)表中沒有參數(shù),但括號必須保留,就成為無參函數(shù)定義?!盎愋头?/p>
函數(shù)名(形參表)”構(gòu)成函數(shù)的頭部,是函數(shù)調(diào)用的接口。
(4)用一對花括號括起來的內(nèi)容稱為函數(shù)體。函數(shù)體一般包含三個部分:
①函數(shù)體內(nèi)數(shù)據(jù)對象定義或聲明部分,是對在函數(shù)體內(nèi)使用的數(shù)據(jù)對象(如變量、數(shù)組等)的定義,或有些數(shù)據(jù)對象在函數(shù)外已經(jīng)定義,在被定義的函數(shù)中使用,需要進行聲明。
②函數(shù)功能實現(xiàn)部分,是一個程序段,要依據(jù)實現(xiàn)某種功能的算法進行設計。③函數(shù)體最后使用一個“return(返回值);”語句,括號中的返回值是一個需傳帶給主調(diào)函數(shù)的數(shù)據(jù)對象。如果沒有返回值,可以不要這個語句。VC++6.0系統(tǒng)中提倡在main()函數(shù)體后使用一個“return0;”語句,表示正常返回系統(tǒng),否則會出現(xiàn)警告。如果函數(shù)體僅是一對花括號,沒有任何語句,就是空函數(shù)??蘸瘮?shù)一般是無參函數(shù)。
例7.1
編程實現(xiàn)從鍵盤輸入三角形三條邊的長度,并判定是否構(gòu)成三角形。
編程思路:問題雖簡單,為了說明模塊化程序設計方法,可將問題劃分為三個模塊,如圖7.2所示,每一個模塊用函數(shù)實現(xiàn)。輸入、輸出使用系統(tǒng)提供的庫函數(shù),只需自行定義判定函數(shù)。
圖7.2例7.1的模塊與函數(shù)運行結(jié)果:
分析:在process中,定義了3個整型形參x、y、z,表示三角形三邊數(shù)據(jù)。根據(jù)三角形的構(gòu)成條件,在if語句中判定,若能構(gòu)成三角形,返回值為“1”,否則,返回值為“0”。在主函數(shù)中調(diào)用process,根據(jù)返回值輸出判定結(jié)果。
7.3函
數(shù)
的
調(diào)
用
7.3.1函數(shù)調(diào)用方法與過程
在main函數(shù)中調(diào)用其他函數(shù),在其他函數(shù)中還可以調(diào)用別的函數(shù)。C語言函數(shù)調(diào)用有多種方式,可以是程序中獨立的調(diào)用語句,也可以在表達式中調(diào)用函數(shù),還可以在函數(shù)參數(shù)位置調(diào)用函數(shù)。函數(shù)調(diào)用的一般形式為
函數(shù)名(實參表)
其中,函數(shù)名是被調(diào)用的函數(shù)名稱。實參表與被調(diào)用函數(shù)的形參表相對應,即參數(shù)個數(shù)和類型要保持一致。實參是具體的數(shù)據(jù),所以稱之為實參。通過實參向被調(diào)函數(shù)的形參傳遞數(shù)據(jù)。
C語言函數(shù)調(diào)用相當于其他語言中的子程序調(diào)用,不論哪種方式的調(diào)用,都使程序的執(zhí)行流從調(diào)用處轉(zhuǎn)向被調(diào)函數(shù),當被調(diào)函數(shù)執(zhí)行結(jié)束時又返回到調(diào)用處繼續(xù)執(zhí)行。函數(shù)調(diào)用過程如圖7.3所示。
圖7.3函數(shù)調(diào)用過程
例7.2
編寫一個求階乘的函數(shù),在主函數(shù)中輸入求階乘的數(shù),調(diào)用函數(shù)求出階乘值并輸出。
運行結(jié)果:
分析:在主函數(shù)中輸入10并賦給變量n,n作為實參調(diào)用factorial函數(shù),將n的值傳給形參x,此時,x具有值10,factorial函數(shù)求出10的階乘并置于變量c中,c是返回值。返回后,將c的值賦給變量fact。
例7.3
編寫一個函數(shù),求兩數(shù)中的最小數(shù)。在主函數(shù)中輸入兩個數(shù),調(diào)用函數(shù)求出最小數(shù),再求最小數(shù)的平方根并輸出。
編程思路:定義一個求兩數(shù)中最小數(shù)的函數(shù),在主函數(shù)中調(diào)用該函數(shù),再調(diào)用求平方根的庫函數(shù),最后輸出結(jié)果。運行結(jié)果:
分析:sqrt是求平方根庫函數(shù),在程序開頭用預處理命令包含頭文件“math.h”。在庫函數(shù)sqrt和printf的參數(shù)位置調(diào)用min函數(shù),其實是調(diào)用后的返回值作參數(shù)。
7.3.2參數(shù)傳遞
從函數(shù)的調(diào)用過程可知,函數(shù)調(diào)用時,實參把數(shù)據(jù)傳遞給形參,形參接收實參數(shù)據(jù),在函數(shù)中進行特定處理。C語言與其他一些高級語言有所不同,函數(shù)的參數(shù)傳遞是單向的,即只能將實參數(shù)據(jù)傳遞給形參,形參數(shù)據(jù)不能傳遞給實參。也就是說,函數(shù)調(diào)用返回后,對形參數(shù)據(jù)引用是無效的。
函數(shù)參數(shù)傳遞的單向性的實質(zhì)在于:在函數(shù)中定義的形參,函數(shù)未被調(diào)用時,系統(tǒng)并不給它們分配存儲單元,只有調(diào)用發(fā)生時,系統(tǒng)才給形參分配存儲單元。調(diào)用結(jié)束后,形參所占的存儲單元即被釋放(不存在了),亦即,形參中的數(shù)據(jù)也就無效了。函數(shù)的參數(shù)傳遞還要求類型一致,即實參與形參要保持類型的匹配。如整型形參只能接收整型或字符型實參數(shù)據(jù),不能接收其他類型的實參數(shù)據(jù),否則,將發(fā)生“類型不匹配”錯誤。
例7.4
下面的程序是在一函數(shù)中交換兩個變量的值,并輸出交換后形參的值,在主函數(shù)中提供兩數(shù),調(diào)用函數(shù)后輸出實參的值。
運行結(jié)果:
分析:exchange中實現(xiàn)對兩形參值的交換,輸出形參值交換后的結(jié)果;主函數(shù)中給變量a、b分別賦值5和10,調(diào)用exchange,使形參a、b的值交換,輸出結(jié)果是a=10,b=5。調(diào)用返回輸出實參的值a=5,b=10。函數(shù)調(diào)用參數(shù)傳遞及變化情況如圖7.4所示。圖7.4例7.4函數(shù)調(diào)用參數(shù)傳遞及變化情況由圖可知,雖然實參和形參定義了相同的變量名,但它們是不同的變量,系統(tǒng)分別分配不同的存儲單元。實參編譯時就分配存儲單元,而且在程序執(zhí)行的全過程有效。形參在調(diào)用時才分配存儲單元,調(diào)用結(jié)束就不復存在了。調(diào)用時,實參把數(shù)據(jù)傳遞給形參,在函數(shù)中對形參進行交換,不影響實參。函數(shù)調(diào)用返回后,輸出實參變量仍是原值(單向傳遞)。
7.3.3函數(shù)的返回值
函數(shù)的返回值是函數(shù)調(diào)用后帶回的主調(diào)函數(shù)的一個確定值,用return語句帶回。
return語句有3種形式:
形式一:
return表達式;
形式二:
return(表達式);
形式三:
return;形式一和形式二作用完全相同,表達式的意義是結(jié)束函數(shù)的運行并帶回表達式的值;形式三中無表達式,其作用是結(jié)束函數(shù)的運行且無返回值。return中表達式的值就是函數(shù)的返回值,其值的類型由函數(shù)類型決定。如果表達式值的類型與函數(shù)類型不一致,則以函數(shù)類型為準,由系統(tǒng)自動轉(zhuǎn)換。
根據(jù)return語句的意義,可以得出的結(jié)論是:一個非void類型函數(shù)有且僅有一個返回值。當函數(shù)體中出現(xiàn)return語句時,函數(shù)的類型就不能是void類型,反之亦然。如果一個函數(shù)體中有幾個返回語句,執(zhí)行第1個返回語句就返回,所以其后的語句不起作用。
運行結(jié)果:
分析:本例說明,在一個函數(shù)中,如果有多種可能的運行方式,根據(jù)情況選擇一種方式運行,每一種方式可以用不同的return語句返回不同的結(jié)果。
7.4函數(shù)調(diào)用的條件與函數(shù)聲明
7.4.1調(diào)用后定義的函數(shù)
在前面的例子中,我們把定義函數(shù)放在程序的前面,主函數(shù)放在后面,也就是說,函數(shù)定義在前、調(diào)用在后。所以直接按基本調(diào)用方法調(diào)用,沒有提及調(diào)用函數(shù)的附加條件。如果被調(diào)函數(shù)的定義在調(diào)用之后,直接調(diào)用,VC系統(tǒng)將會出現(xiàn)對被調(diào)函數(shù)不能辨識的錯誤。如果主調(diào)函數(shù)與被調(diào)函數(shù)在一個程序文件中,被調(diào)函數(shù)定義在后,主調(diào)函數(shù)在前,要求在主調(diào)函數(shù)的前面對被調(diào)函數(shù)作“聲明”。函數(shù)聲明的一般形式為
基類型符
函數(shù)名(類型符
形式參數(shù)1,類型符
形式參數(shù)2,…);
還可以采用簡化形式:
基類型符
函數(shù)名(類型符,類型符,…);
在TC系統(tǒng)中還可以為
基類型符
函數(shù)名();
函數(shù)聲明是用函數(shù)定義的頭部或簡化形式,對函數(shù)返回值類型、函數(shù)名、參數(shù)的類型的說明,不包含函數(shù)體。
例7.6
用簡單的函數(shù)調(diào)用實現(xiàn)兩數(shù)相加程序來說明函數(shù)聲明。
運行結(jié)果:
分析:定義add函數(shù)在主函數(shù)之后,所以在主函數(shù)前面作了函數(shù)聲明。讀者可自行驗證函數(shù)聲明的簡化形式。7.4.2調(diào)用庫函數(shù)
C語言提供了豐富的庫函數(shù)。為方便用戶使用,庫函數(shù)劃分為了不同的類。每一類庫函數(shù)有一個擴展名為“.h”的頭文件。頭文件中包含了相關(guān)函數(shù)的聲明、宏定義和數(shù)據(jù)結(jié)構(gòu)的定義。在程序中要調(diào)用庫函數(shù),需要在程序開頭使用預處理命令將該庫函數(shù)所在類的頭文件包含在程序中,否則,會出現(xiàn)庫函數(shù)不能辨識的錯誤。庫函數(shù)的分類及其頭文件可查閱附件D。例如,stdio.h、math.h、string.h、stdlib.h分別是輸入/輸出庫函數(shù)、數(shù)學庫函數(shù)、字符及字符串函數(shù)、動態(tài)存儲器分配庫函數(shù)的頭文件。預處理命令的使用有兩種形式:
#include<頭文件名>
或
#include"頭文件名"
這兩種形式稍有區(qū)別,尖括號表示在包含文件目錄中查找(包含目錄是由用戶在設置環(huán)境時設置的),而不在源文件目錄中查找;雙引號則表示首先在當前的源文件目錄中查找,若未找到,再到包含目錄中查找。用戶編程時可根據(jù)自己文件所在的目錄來選擇某一種命令形式。
7.4.3調(diào)用外部函數(shù)
C語言中,根據(jù)函數(shù)能否被不同的源程序文件調(diào)用,將函數(shù)區(qū)分為內(nèi)部函數(shù)和外部函數(shù)。
如果一個函數(shù)只能在同一文件中被調(diào)用,則稱之為內(nèi)部函數(shù)。在定義內(nèi)部函數(shù)時,需要在“基類型符”前加“static”。其定義的形式為
static基類型符函數(shù)名(形參表)
{
}內(nèi)部函數(shù)又稱為靜態(tài)函數(shù)。因為內(nèi)部函數(shù)只限于本文件使用,所以,在不同的程序文件中可以使用同名的內(nèi)部函數(shù),而不會產(chǎn)生干擾。這樣在開發(fā)大型軟件時,不同的人可分別編寫不同的函數(shù),而不必擔心與其他程序文件中的函數(shù)同名。
外部函數(shù)可以在不同文件中被調(diào)用。定義時,可以在“基類型符”前加“extern”,表示外部函數(shù)。其定義的形式為
extern基類型符函數(shù)名(形參表)
{
}如果不加“extern”,系統(tǒng)也隱含為外部函數(shù)。在此之前所用的函數(shù)都可作為外部函數(shù)。
調(diào)用外部函數(shù)時,一般要在調(diào)用函數(shù)的文件中作外部函數(shù)的聲明。聲明的一般形式為
extern函數(shù)名();
例7.7
通過4個文件來實現(xiàn):輸入一個字符串,刪除其中指定的一個字符,然后輸出字符串。
運行結(jié)果:
分析:三個函數(shù)分別在3個文件中定義,雖然函數(shù)前未加“extern”說明,但系統(tǒng)默認為外部函數(shù)。在主函數(shù)中對3個函數(shù)進行了外部函數(shù)聲明,分別調(diào)用了3個文件中的函數(shù)。
7.5函數(shù)的嵌套調(diào)用和遞歸調(diào)用
7.5.1函數(shù)的嵌套調(diào)用
何謂函數(shù)的嵌套調(diào)用?函數(shù)的嵌套調(diào)用有何特點?
C語言允許一個函數(shù)在調(diào)用另一個函數(shù)的過程中再調(diào)用其他函數(shù),形成多層調(diào)用關(guān)系。這種調(diào)用關(guān)系稱為嵌套調(diào)用。嵌套調(diào)用可以實現(xiàn)多層模塊結(jié)構(gòu)的程序設計。
例7.8
編程實現(xiàn)求2|x|+1的值。
編程思路:為了說明嵌套調(diào)用,求絕對值用一個函數(shù)實現(xiàn),求表達式的值用另一個函數(shù)實現(xiàn),通過3層嵌套調(diào)用得以求解。
運行結(jié)果:
分析:嵌套調(diào)用關(guān)系及其執(zhí)行過程如圖7.5所示。圖7.5例7.8程序嵌套調(diào)用關(guān)系及其執(zhí)行過程程序的執(zhí)行步驟:
(1)程序進入main函數(shù),給變量f賦初值-1.5。
(2)?main函數(shù)的printf語句中調(diào)用了func,將實際參數(shù)-1.5傳遞給func的形式參數(shù)r。
(3)程序進入func函數(shù),在func里調(diào)用了fabs函數(shù),將-1.5傳遞給fabs的形參x。
(4)程序進入fabs,計算x的絕對值,將1.5返回到func函數(shù)中的調(diào)用fabs函數(shù)處,繼續(xù)func函數(shù)的執(zhí)行。
(5)在func函數(shù)中計算表達式2*fabs(r)+1的值,將結(jié)果4.0返回到main函數(shù)中調(diào)用func函數(shù)處。
(6)?main函數(shù)的printf函數(shù)輸出func的返回值4.0。7.5.2函數(shù)的遞歸調(diào)用
何謂函數(shù)的遞歸調(diào)用?函數(shù)的遞歸調(diào)用有何特點?
一個函數(shù)在它的函數(shù)體內(nèi)直接或間接調(diào)用自身稱為遞歸調(diào)用,這種函數(shù)稱為遞歸函數(shù)或自調(diào)用函數(shù),如圖7.6所示。C語言中允許函數(shù)的遞歸調(diào)用。
圖7.6函數(shù)遞歸調(diào)用關(guān)系函數(shù)遞歸調(diào)用特別適合遞推問題的求解。利用遞歸算法,需對問題進行以下三個方面的分析:
(1)分析出遞推公式。
(2)確定問題的邊界條件或邊界值,即遞推的終結(jié)條件,否則問題求解將進入死圈。
(3)利用遞歸函數(shù)調(diào)用實現(xiàn)遞推公式求解。
例7.9
用遞歸方法求解n!。
編程思路:由n!=n(n-1)(n-2)…1可得遞推公式n!=n*(n-1)!,終結(jié)條件是0或1的階乘值為1。利用函數(shù)遞歸調(diào)用可以很容易地實現(xiàn)。
運行結(jié)果:
分析:在主函數(shù)中輸入5,從fac(5)開始函數(shù)的遞歸調(diào)用,調(diào)用過程如圖7.7所示。圖7.7例7.9函數(shù)遞歸調(diào)用示意圖由圖可知,遞歸調(diào)用過程可分成兩個階段。第一階段是“遞推”,n的階乘表示為n-1的階乘,而n-1的階乘仍未知,進而表示為n-2的階乘,如此推到1的階乘為1,就不必再推了。然后開始第2階段的“反推”。由1的階乘推算出2的階乘,由2的階乘推算出3的階乘,如此反推到第一次調(diào)用,算出5的階乘,最后返回到主程序的調(diào)用處。
從上述分析易知,遞歸調(diào)用程序結(jié)構(gòu)簡潔,但函數(shù)的調(diào)用次數(shù)、參數(shù)傳遞并沒有節(jié)省內(nèi)存資源的使用、程序的執(zhí)行時間。因遞歸調(diào)用很容易解決遞推算法問題,從而成為了C程序設計中的一種重要方法。
例7.10
用遞歸方法求一個等差數(shù)列第n項an的值,其中首項a1的值是1,公差d為3。
編程思路:由等差數(shù)列通項公式an=a1+(n-1)d可知,求第n項的值是一個遞推問題,即an=an-1+d,終結(jié)條件是首項已知。
運行結(jié)果:
分析:考慮程序的通用性,getan函數(shù)的形參設置為3個,分別是首項、公差和項數(shù)。主程序中輸入首項值和項數(shù),如果公差也輸入,則程序成為求等差數(shù)列任一項的通用程序。在主函數(shù)中得到實參值后調(diào)用getan函數(shù),進入遞歸調(diào)用過程,共調(diào)用10次,再經(jīng)過“反推”過程,回到主函數(shù),輸出結(jié)果。
7.6變量的作用域與函數(shù)間的數(shù)據(jù)傳遞
7.6.1局部變量和全局變量
C程序中的變量,按照作用域可分為兩種:局部變量和全局變量。
1.局部變量
在一個函數(shù)內(nèi)部定義的變量,稱為內(nèi)部變量。內(nèi)部變量只能在所定義的函數(shù)范圍內(nèi)使用(有效),在其外就不能使用了,或者說在其外就無效了,所以內(nèi)部變量是局部變量。關(guān)于局部變量的幾點說明:
(1)?main()函數(shù)中定義的變量也只能在主函數(shù)中使用,不能在其他函數(shù)中使用。同時,主函數(shù)中也不能使用其他函數(shù)中定義的變量。
(2)形參變量屬于局部變量。函數(shù)調(diào)用結(jié)束后,形參變量就不復存在了。
(3)在不同的函數(shù)中可以使用同名變量,因為它們僅在所屬的函數(shù)內(nèi)有效,系統(tǒng)分配給不同的單元,代表不同的數(shù)據(jù)對象,互不干擾,也不會發(fā)生混淆。
(4)一個函數(shù)內(nèi)部的復合語句中定義的變量,其作用范圍是從定義處到復合語句尾部,如圖7.8所示。
圖7.8局部變量作用范圍示意
2.全局變量
一個源程序文件中可以包含多個函數(shù),在每一個函數(shù)外定義的變量統(tǒng)稱為外部變量。外部變量是全局變量。外部變量的有效范圍是從定義變量處到源程序文件結(jié)束。源文件中變量的作用范圍如圖7.9所示。
關(guān)于全局變量的幾點說明:
(1)在一個程序文件中若存在局部變量和全局變量的共同有效區(qū)域,則既可使用局部變量,又可使用全局變量。定義局部變量和全局變量時應避免同名。若有同名變量,則在局部變量的作用范圍內(nèi),外部變量不起作用。
圖7.9源文件中的變量使用范圍示意運行結(jié)果:
分析:在主函數(shù)中,a既在局部變量的作用范圍,又在全局變量的作用范圍,此時a用局部變量的值,b用全局變量的值,所以函數(shù)調(diào)用是max(8,5)。實參值傳遞給形參a,b,在max函數(shù)中形參起作用,全局變量a,b不起作用,調(diào)用返回值為8。
(2)如果想在定義點之前的函數(shù)中使用外部變量,C語言是允許的,但要在該函數(shù)中用“extern”作外部變量說明,表示該變量在函數(shù)外部定義,在本函數(shù)內(nèi)部使用。聲明的一般形式為
extern類型說明符
變量列表;
這樣就擴大了外部變量的作用范圍。外部變量說明和外部變量定義的作用意義是不一樣的。外部變量定義在函數(shù)之外,只能有一次。而外部變量說明是在要使用的函數(shù)之內(nèi),可以有多次說明。系統(tǒng)根據(jù)外部變量定義給變量分配存儲單元,而不是根據(jù)外部變量說明。
運行結(jié)果:
分析:在main函數(shù)中,x既是局部變量又是全局變量,應取局部變量的值5,y是全局變量,在main函數(shù)中有效,所以函數(shù)調(diào)用為mul(5,4)。在mul中,對外部變量z作了說明,可以引用z的值。因此函數(shù)返回值為x*y*z=5*4*5=100。
(3)由于全局變量能被一個文件中的各個函數(shù)引用,因而在一個函數(shù)中改變?nèi)值闹?,在其他函?shù)中可以引用改變后的值,相當于將一個函數(shù)中的值傳遞到其他函數(shù)中。所以,利用全局變量就增加了函數(shù)間數(shù)據(jù)傳遞的通道。利用外部變量提高函數(shù)間數(shù)據(jù)傳遞能力的同時,也會給程序設計帶來一些負面影響:
(1)會使程序的通用性降低。因為如果將一個函數(shù)移植到另一文件中,還需要將相關(guān)的外部變量及其值一并移植。若所移植的外部變量與文件中的變量同名,就會出現(xiàn)問題,從而降低程序的通用性和可靠性。
(2)使用全局變量會使程序清晰性變差。因為在分析程序時,很難把握全局變量的動態(tài)值。
(3)全局變量在程序運行的全過程中一直占據(jù)存儲單元,過多使用全局變量,不利于存儲器資源的有效利用。
綜上所述,在程序設計中,只有非用不可時才定義全局變量,應盡量減少全局變量的數(shù)目。
例7.13
從鍵盤輸入0~4000范圍內(nèi)的整數(shù),以輸入負數(shù)作為結(jié)束標志,并通過一個函數(shù)實現(xiàn)最大值、最小值和平均值的計算。
編程思路:一個函數(shù)通過return語句只能返回一個值,現(xiàn)在要求計算最大值、最小值和平均值,都需要返回輸出??衫萌肿兞總鬟f值。
運行結(jié)果:
分析:由于數(shù)據(jù)個數(shù)不限,通過負數(shù)來結(jié)束輸入,定義全局變量max、min、sum,compute函數(shù)定義為無返回值函數(shù),是通過全局變量傳遞最大值、最小值和累加和的。在循環(huán)外輸入一個數(shù),作為max、min、sum的初值,在循環(huán)中再輸入數(shù),調(diào)用compute()進行判斷及求和,循環(huán)控制變量i記錄循環(huán)輸入數(shù)據(jù)的個數(shù),因在循環(huán)外還輸入了一個數(shù),所以求平均值的除數(shù)為(i+1)。
7.6.2變量的存儲類型
在C語言中,每個變量都有兩個屬性:數(shù)據(jù)類型和存儲類型。數(shù)據(jù)的存儲類型是指程序執(zhí)行時數(shù)據(jù)在內(nèi)存中的存儲方式。了解變量的存儲類型,能指導我們在程序設計中合理地定義數(shù)據(jù)對象,有效地利用存儲器資源。
程序在執(zhí)行時,系統(tǒng)為程序的執(zhí)行劃分了3個內(nèi)存區(qū)域:程序區(qū)、靜態(tài)存儲區(qū)和動態(tài)存儲區(qū)。
分配在動態(tài)存儲區(qū)的數(shù)據(jù)對象,在程序執(zhí)行過程中對存儲單元的占用情況是動態(tài)變化的。函數(shù)調(diào)用時系統(tǒng)分配存儲單元,返回時自動釋放??稍趧討B(tài)存儲區(qū)中存儲的數(shù)據(jù)有函數(shù)的形參、自動局部變量、函數(shù)調(diào)用的現(xiàn)場保護和返回地址等。分配在靜態(tài)存儲區(qū)的數(shù)據(jù)對象,在程序執(zhí)行過程中對存儲單元的占用是固定的。程序執(zhí)行時分配存儲單元,直到結(jié)束時才釋放。靜態(tài)存儲區(qū)一般存儲全局數(shù)據(jù)對象和被定義的靜態(tài)局部變量。
從系統(tǒng)對存儲區(qū)的劃分可以看出,數(shù)據(jù)對象的存儲方式有兩大類:動態(tài)存儲類和靜態(tài)存儲類。程序中定義的全局變量按靜態(tài)存儲方式存儲,局部變量一般按動態(tài)存儲方式存儲。
把變量對存儲單元的占用期稱為生存期。動態(tài)存儲變量的生存期是函數(shù)調(diào)用的期限。靜態(tài)存儲變量的生存期是程序執(zhí)行的期限。系統(tǒng)對局部變量一般自動地按動態(tài)方式存儲,但也允許把局部變量改變?yōu)殪o態(tài)存儲類。為了和CPU內(nèi)部寄存器相聯(lián)系,局部變量可專門定義為寄存器變量。如此,局部變量又可劃分為三個存儲類型:自動變量、靜態(tài)變量和寄存器變量。
1.自動變量
函數(shù)中的局部變量,如沒有專門的定義,都存儲在動態(tài)存儲區(qū)中,動態(tài)分配存儲空間。分配和釋放存儲空間的工作是由系統(tǒng)自動處理的。因此,這類局部變量稱為自動變量。自動變量可以使用關(guān)鍵字“auto”來顯式定義。例如:
在局部變量定義的類型符前再加存儲類關(guān)鍵字“auto”,就形成了完整的自動變量的定義。在局部變量定義的類型符前不加任何存儲類關(guān)鍵字,系統(tǒng)默認為自動變量。所以上面函數(shù)中的變量x、y、a和k都是自動變量。
2.靜態(tài)變量
局部變量也可以定義為靜態(tài)變量,按靜態(tài)方式存儲。靜態(tài)變量定義的一般形式為
static基本類型符變量列表;
即在局部變量的定義前增加靜態(tài)存儲類關(guān)鍵字“static”就定義了靜態(tài)變量。在函數(shù)中定義的靜態(tài)局部變量,函數(shù)調(diào)用結(jié)束后,所占用的存儲單元不釋放,仍保留變量的值。靜態(tài)存儲類雖然改變了局部變量的生存期,但不改變其作用域。也就是說,函數(shù)調(diào)用結(jié)束后,保留的值不能被其他函數(shù)引用,只能在下一次調(diào)用時,在本函數(shù)中使用。
例7.14
計算1+2+3+…+100的和,并分析程序的運行結(jié)果和靜態(tài)變量的使用。
編程思路:編寫一個每次累加一個數(shù)的函數(shù),在函數(shù)中循環(huán)調(diào)用,實現(xiàn)多數(shù)累加??衫渺o態(tài)局部變量保持前一次的累加值。
運行結(jié)果:
分析:函數(shù)add_one中的靜態(tài)變量s默認初始化為0,每次被調(diào)用時,在保留上一次的結(jié)果上累加本次實參傳遞的值。主函數(shù)每次調(diào)用只得到本次返回值,最終的輸出get_sum是最后一次調(diào)用的返回值。輸出s的值不是最后一次累加的值,而是一個系統(tǒng)隨機數(shù)。這就說明,靜態(tài)局部變量只能在所屬的函數(shù)內(nèi)使用,不能在其他函數(shù)中引用。
3.寄存器變量
寄存器變量是與CPU內(nèi)部寄存器相關(guān)聯(lián)的局部變量。CPU內(nèi)部寄存器的功能是暫存操作數(shù)或中間運算結(jié)果,直接向運算器傳送數(shù)據(jù),以提高運算速度。把局部變量定義成寄存器變量即為了此目的。寄存器變量定義的一般形式是在定義變量的前面加上寄存器關(guān)鍵字“register”。例如,“registerinti;”就定義了i為寄存器變量。在有些情況下,如果一些變量在程序中要多次使用,將這些變量定義成寄存器變量,可縮短程序的執(zhí)行時間。比如本書中多處所舉的求累加和程序例子,程序中的累加數(shù)變量及累加和變量,在每次累加時都要使用,定義成寄存器變量,可提高程序的執(zhí)行速度。有關(guān)局部變量存儲方式使用的幾點說明:
(1)對局部靜態(tài)變量賦初值是在編譯時進行的,即只賦初值一次,程序運行中保留當前的操作結(jié)果。對自動變量賦初值不是在編譯時進行的,而是在函數(shù)調(diào)用時賦初值,因為每次調(diào)用函數(shù)時,會給自動變量重新分配存儲單元。
(2)如果在定義局部靜態(tài)變量時不賦初值,編譯時自動賦初值0(數(shù)值型變量)或空字符(字符型變量)。如果在定義自動變量時不賦初值,則變量是一個不確定的值(所分配單元的當時值)。
(3)雖然局部靜態(tài)變量在函數(shù)調(diào)用結(jié)束后仍然存在,但只能在下次調(diào)用時的本函數(shù)內(nèi)使用,不能被其他函數(shù)引用。
7.7用函數(shù)實現(xiàn)模塊化程序設計
怎樣利用函數(shù)實現(xiàn)模塊化程序設計?
C語言函數(shù)是實現(xiàn)模塊化程序設計中的模塊功能的,是程序中功能相對獨立的一個基本單元。模塊化程序設計貫徹“自頂向下,逐步細化,逐層分解”的基本思想,最后形成一個模塊結(jié)構(gòu)的樹形圖,如圖7.1所示。圖中最頂層模塊稱為樹根模塊,沒有下層模塊的模塊稱為樹葉模塊,中間層模塊稱為樹枝模塊。逐層分解是一個抽象到具體的思維過程。在頂層先抓住問題實質(zhì),暫時忽略細節(jié),只注重解決問題的大過程。越到下層模塊,越要接近模塊問題處理的方法過程。直到樹葉模塊,需要考慮問題的細節(jié)。模塊分解要遵循“強內(nèi)聚,弱耦合”的原則。這個原則的內(nèi)涵意義是:模塊功能應盡量具有完整性和獨立性,減少對其他模塊的依附性,避免模塊之間傳遞冗余數(shù)據(jù),盡量減少模塊之間所傳遞數(shù)據(jù)的數(shù)量和復雜的數(shù)據(jù)結(jié)構(gòu)。問題的功能模塊設計完后,就可以針對模塊設計C語言函數(shù)了。設計C函數(shù)時,一般從樹葉模塊開始,逐層向上進行。也就是說模塊設計是自頂向下,函數(shù)實現(xiàn)是自底向上的。樹葉模塊的函數(shù)設計要考慮解決問題的算法、數(shù)據(jù)及數(shù)據(jù)結(jié)構(gòu)。樹枝層和樹根層模塊主要考慮調(diào)用函數(shù)的接口問題。一般包含調(diào)用函數(shù)時需傳遞哪些數(shù)據(jù),是什么類型的數(shù)據(jù),調(diào)用返回需帶什么數(shù)據(jù),通過什么方式傳回數(shù)據(jù)等。在C語言程序中,模塊之間的數(shù)據(jù)傳遞主要有兩種方式:一是通過調(diào)用函數(shù)傳遞,傳入數(shù)據(jù)是通過實參與形參的結(jié)合方式,傳出數(shù)據(jù)是函數(shù)的返回值,只能返回一個數(shù)據(jù);二是通過全局變量來傳遞數(shù)據(jù),這種傳遞方式是雙向的,既可傳入也可傳出。利用全局變量傳遞數(shù)據(jù)會降低程序的移植性、可靠性和易懂性,會使模塊間的耦合性增強。所以,要盡可能地減少全局變量傳遞數(shù)據(jù)。
下面通過一個設計例子,說明用函數(shù)實現(xiàn)模塊化程序設計的方法及過程,請認真體會。
例7.15
設計程序,實現(xiàn)用弦截法求方程的根。
(1)算法分析。
①取兩個不同點x1、x2,如果f(x1)和f(x2)符號相反,則(x1,x2)區(qū)間必有一個根。如果f(x1)和f(x2)同號,則改變x1、x2,直到f(x1)和f(x2)異號。注意x1、x2的值不宜相差太大,以保證(x1,x2)區(qū)間只有一個根。
②連接f(x1)和f(x2)對應的兩點,連線(即弦)交于x,如圖7.10所示。x點坐標可由下式求出,再從x求出f(x)。
圖7.10弦截法求根示意圖
③若f(x)與f(x1)同符號,則根必在(x,x2)區(qū)間,此時將x作為x1。如果f(x)與f(x2)同符號,則根必在(x1,x)區(qū)間,此時將x作為x2。
④重復步驟②和③,直到|f(x)|<ε,ε是一很小的數(shù),說明|f(x)|接近于0,此時的x即為方程的近似根。
(2)模塊設計。
根據(jù)上述迭代算法,從頂層看,應包含輸入初始x坐標點x1,x2模塊、求根模塊和根輸出模塊。輸入和輸出模塊可調(diào)用庫函數(shù)實現(xiàn)。關(guān)鍵是求根模塊的實現(xiàn)。
求根模塊從算法分析可知,求根是一個迭代過程。在迭代過程中求根是目的,但需求出弦交點,求弦交點又需求函數(shù)值。在迭代過程中這三個模塊需反復調(diào)用。為了程序的可讀性、通用性、可靠性,可將求根、求弦交點、求函數(shù)值劃分為3個模塊。模塊劃分如圖7.11所示。
圖7.11弦截法求根模塊運行結(jié)果:
分析:程序從main函數(shù)開始執(zhí)行。先執(zhí)行d0_while循環(huán),輸入x1和x2,判斷f(x1)和f(x2)是否異號。如果非異號,則重新輸入x1和x2的值,直到滿
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025民辦幼兒園教師聘用合同書范本
- 2025監(jiān)理工程師《合同管理》考點合同生效時間的規(guī)定
- 二零二五年度醫(yī)療項目項目經(jīng)理委托合同3篇
- 二零二五年度互聯(lián)網(wǎng)金融服務公司股權(quán)及業(yè)務轉(zhuǎn)讓合同3篇
- 2025年度紙裝修設計創(chuàng)新技術(shù)應用合同3篇
- 2025年度企業(yè)財務分析與稅務籌劃咨詢服務合同2篇
- 2025年度醫(yī)療機構(gòu)與執(zhí)業(yè)藥師簽訂的藥品質(zhì)量追溯體系合作協(xié)議3篇
- 2025年度展臺搭建與展會現(xiàn)場布置合同3篇
- 二零二五年度軌道交通設備維修保養(yǎng)協(xié)議3篇
- 2025年度養(yǎng)殖技術(shù)培訓與推廣合作合同3篇
- 一監(jiān)區(qū)服裝生產(chǎn)管理問題
- 人教PEP版英語四年級上冊單詞表默寫(英譯漢、漢譯英)
- 職業(yè)健康監(jiān)護技術(shù)規(guī)范
- 水不同溫度的熱焓值
- 小品劇本《超級招聘》
- 空氣壓縮機檢驗原始記錄表
- 叉車部件的涂裝工藝及體系
- DB32∕T 3261-2017 水利工程預拌混凝土應用技術(shù)規(guī)范
- 物理學習的8種思考方式
- 閱讀題賒小雞
- 中國風圍棋對弈雅致文藝教育培訓活動策劃版
評論
0/150
提交評論