




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、1第4章 函數(shù)2第4章 函數(shù)4.1 函數(shù)定義4.2 函數(shù)參數(shù)4.3 函數(shù)原型與調(diào)用4.4 內(nèi)聯(lián)函數(shù)4.5 函數(shù)調(diào)用形式4.6 作用域和生命期4.7 對象初始化4.8 聲明與定義3第4章 函數(shù)4.9 變量修飾小結(jié)4.10 程序組織結(jié)構(gòu)4.11 函數(shù)應(yīng)用程序舉例使用函數(shù)的最大好處:舉例說明1.結(jié)構(gòu)化程序設(shè)計:模塊分割,由上而下,逐步細(xì)化,功能模塊用函數(shù)實現(xiàn);2.相同功能的代碼段復(fù)用;使用函數(shù)減少重復(fù)勞動:把要重復(fù)使用的功能包裝成函數(shù);44.1 函數(shù)定義函數(shù)定義的一般形式為:函數(shù)定義本質(zhì)上就是抽象功能代碼的函數(shù)實現(xiàn),包括:確定函數(shù)名;確定形式參數(shù)列表;確定返回類型;編寫函數(shù)體代碼。 返回類型 函數(shù)名
2、(形式參數(shù)列表)函數(shù)體聲明部分函數(shù)體執(zhí)行語句 54.1.1 函數(shù)定義的一般形式1函數(shù)名 實現(xiàn)函數(shù)需要確定函數(shù)名,以便使用函數(shù)時能夠按名引用。2形式參數(shù)列表 實現(xiàn)函數(shù)需要確定有無形式參數(shù)、有多少形式參數(shù)、有什么類型的形式參數(shù)。形式參數(shù)列表是函數(shù)與調(diào)用者進(jìn)行數(shù)據(jù)交換的途徑,一般形式為:類型類型1 參數(shù)名參數(shù)名1,類型類型2 參數(shù)名參數(shù)名2, 類型類型3 參數(shù)名參數(shù)名3 , 64.1.1 函數(shù)定義的一般形式 多個參數(shù)用逗號(,)分隔,且每個參數(shù)都要有自己的類型說明,即使類型相同的參數(shù)也是如此。例如:int fun(int x, int y, double m) return m12.5 ? x :
3、y;74.1.1 函數(shù)定義的一般形式 函數(shù)可以沒有形式參數(shù),定義形式為: 返回類型 函數(shù)名()函數(shù)體聲明部分函數(shù)體執(zhí)行語句 返回類型 函數(shù)名(void)函數(shù)體聲明部分函數(shù)體執(zhí)行語句 84.1.1 函數(shù)定義的一般形式3返回類型 實現(xiàn)函數(shù)需要確定有無返回數(shù)據(jù)、返回什么類型的數(shù)據(jù)。返回值是函數(shù)向調(diào)用者返回數(shù)據(jù)的途徑之一,本質(zhì)上函數(shù)返回值也起到與調(diào)用者進(jìn)行數(shù)據(jù)交換的作用,只不過它是單向的,即從函數(shù)向調(diào)用者傳遞,故稱返回。 返回類型可以是C語言除數(shù)組之外的內(nèi)置數(shù)據(jù)類型或自定義類型。C語言規(guī)定一個函數(shù)如果沒有給出返回類型,則默認(rèn)是int型94.1.1 函數(shù)定義的一般形式 函數(shù)可以不返回數(shù)據(jù),此時返回類型應(yīng)
4、寫成void,表示沒有返回值,其形式為: void 函數(shù)名(形式參數(shù)列表)函數(shù)體聲明部分函數(shù)體執(zhí)行語句 104.1.1 函數(shù)定義的一般形式4函數(shù)體 實現(xiàn)函數(shù)最重要的是編寫函數(shù)體。函數(shù)體(function body)包含聲明部分和執(zhí)行語句,是一組能實現(xiàn)特定功能的語句序列的集合。 編寫函數(shù)體是為了實現(xiàn)函數(shù)功能。故稱函數(shù)定義為函數(shù)實現(xiàn),簡稱實現(xiàn)。 而函數(shù)頭簡稱接口。114.1.1 函數(shù)定義的一般形式例4.1 1 #include 2 int IsPrime(int m) /求素數(shù)函數(shù)求素數(shù)函數(shù) 3 /枚舉法求枚舉法求m是否素數(shù)是否素數(shù) 4 int i; 5 for (i=2 ; ib ? a : b
5、; 4 第1行a和b就是形參。 204.2.1 形式參數(shù)函數(shù)定義時指定的形參,在未進(jìn)行函數(shù)調(diào)用前,并不實際占用內(nèi)存中的存儲單元,這也是稱它為形式參數(shù)的原因,即它們不是實際存在的。只有在發(fā)生函數(shù)調(diào)用時,形參才分配實際的內(nèi)存單元,接受從主調(diào)函數(shù)傳來的數(shù)據(jù),此刻形參是真實存在的,因而可以對它們進(jìn)行各種操作。當(dāng)函數(shù)調(diào)用結(jié)束后,形參占用的內(nèi)存單元被自動釋放。此后,形參又是未實際存在的。214.2.1 形式參數(shù)形參的類型可以是任意數(shù)據(jù)類型,換言之,函數(shù)允許任意類型的數(shù)據(jù)傳遞到函數(shù)中。形參類型的設(shè)計一是依據(jù)實際需求,二是確保高效的數(shù)據(jù)傳遞。224.2.2 實際參數(shù)實際參數(shù)函數(shù)調(diào)用時提供給被調(diào)函數(shù)的參數(shù)稱為實
6、際參數(shù)(arguments),簡稱實參。實參必須有確定的值,因為調(diào)用函數(shù)會將它們傳遞給形參。實參可以是常量、變量或表達(dá)式,還可以是函數(shù)的返回值。例如:x = max(a,b); /max函數(shù)調(diào)用,實參為函數(shù)調(diào)用,實參為a,by = max(a+3,128); /max函數(shù)調(diào)用,實參為函數(shù)調(diào)用,實參為a+3,128z = max(max(a,b),c); /max函數(shù)調(diào)用,實參為函數(shù)調(diào)用,實參為max(a,b),c234.2.2 實際參數(shù)實參數(shù)據(jù)傳遞給形參,必須滿足語法和應(yīng)用兩方面的要求。實參是以形參為依據(jù)的,即實參的類型、次序和數(shù)目要與形參一致。如果參數(shù)數(shù)目不一致,則出現(xiàn)編譯錯誤;如果參數(shù)次序
7、不一致,則傳遞到被調(diào)函數(shù)中的數(shù)據(jù)就不合邏輯,難有正確的程序結(jié)果;244.2.2 實際參數(shù)如果參數(shù)類型不一致時,則函數(shù)調(diào)用時按形參類型隱式類型轉(zhuǎn)換實參;如果是不能進(jìn)行隱式類型轉(zhuǎn)換的類型,就會出現(xiàn)編譯錯誤。更重要的是,實參的數(shù)據(jù)應(yīng)與函數(shù)接口要求的數(shù)據(jù)物理意義是一致的,否則即使語法正確,程序的運行結(jié)果也是錯的。例如調(diào)用數(shù)學(xué)庫函數(shù)中的sin函數(shù)求正弦時,函數(shù)接口就要求實參必須是弧度的數(shù)據(jù)。254.2.3 參數(shù)傳遞機(jī)制程序通常有兩種函數(shù)參數(shù)傳遞機(jī)制:值傳遞和引用傳遞。值傳遞(pass-by-value)過程中,形參作為被調(diào)函數(shù)的內(nèi)部變量來處理,即開辟內(nèi)存空間以存放由主調(diào)函數(shù)復(fù)制過來的實參的值,從而成為實
8、參的一個副本。264.2.3 參數(shù)傳遞機(jī)制值傳遞的特點是被調(diào)函數(shù)對形參的任何操作都是對內(nèi)部變量進(jìn)行,不會影響到主調(diào)函數(shù)的實參變量的值。void fun(int x, int y, int m) m = xy ? x : y; /僅修改函數(shù)內(nèi)部的僅修改函數(shù)內(nèi)部的mvoid caller() /主調(diào)函數(shù),調(diào)用者主調(diào)函數(shù),調(diào)用者 int a=10, b=5, k=1; fun(a,b,k); /實參值傳遞實參值傳遞274.2.3 參數(shù)傳遞機(jī)制引用傳遞(pass-by-reference)過程中,被調(diào)函數(shù)的形參雖然也作為內(nèi)部變量開辟了內(nèi)存空間,但是這時存放的是由主調(diào)函數(shù)復(fù)制過來的實參的內(nèi)存地址,從而使
9、得形參為實參的一個別名(形參和實參內(nèi)存地址相同,則它們實為同一個對象的兩個名稱)。被調(diào)函數(shù)對形參的任何操作實際上都是對主調(diào)函數(shù)的實參進(jìn)行操作。C語言中,值傳遞是唯一的參數(shù)傳遞方式。C語言的后續(xù)C+,支持引用傳遞。284.2.3 參數(shù)傳遞機(jī)制值傳遞時,實參數(shù)據(jù)傳遞給形參是單向傳遞,即只能由實參傳遞給形參,而不能由形參傳回給實參,這也是實參可以是常量和表達(dá)式的原因(這些數(shù)據(jù)不是左值)。294.2.4 函數(shù)調(diào)用棧函數(shù)調(diào)用時,為了能將參數(shù)傳遞到函數(shù)中、準(zhǔn)確返回到調(diào)用點以及返回函數(shù)值,使用了“棧”來管理存儲器存儲函數(shù)的形參和局部變量。棧是內(nèi)存管理中的一種數(shù)據(jù)結(jié)構(gòu),是一種先進(jìn)后出的數(shù)據(jù)表,即先進(jìn)去的數(shù)據(jù)后
10、出來。棧最常見操作有兩種:進(jìn)棧(push)和出棧(pop)。304.2.4 函數(shù)調(diào)用棧系統(tǒng)為每次函數(shù)調(diào)用在“棧”中建立獨立的??蚣?,稱為函數(shù)調(diào)用棧幀(stack frame),其建立和撤銷是自動維護(hù)的。314.2.4 函數(shù)調(diào)用棧int fun(int a, int b) /被調(diào)函數(shù)被調(diào)函數(shù) int x = 8, y=2, z; z = (a+b)*x +(a-b)*y; return z;void caller() /主調(diào)函數(shù),調(diào)用者主調(diào)函數(shù),調(diào)用者 int m=2 , n=3 , k; k = fun(m,n); /函數(shù)調(diào)用函數(shù)調(diào)用324.2.4 函數(shù)調(diào)用棧圖4.1 函數(shù)調(diào)用棧334.2.5
11、 const參數(shù)const參數(shù)函數(shù)定義時,允許在形參的類型前面加上const限定,語法形式為:返回類型 函數(shù)名(const 類型 形式參數(shù),)函數(shù)體 344.2.5 const參數(shù)函數(shù)參數(shù)使用const限定的目的是確保形參對應(yīng)的實參對象在函數(shù)體中不會被修改。通常,基本類型的參數(shù),因為形參和實參本來就不是同一個內(nèi)存單元,即使修改形參也不會影響到實參,因此沒有必要加const限定。但如果是數(shù)組參數(shù)、指針參數(shù),希望在函數(shù)中不修改數(shù)組元素或者指針值就有必要了。354.2.6 可變參數(shù)函數(shù)可變參數(shù)函數(shù)C語言支持可變參數(shù)的函數(shù),允許函數(shù)參數(shù)數(shù)目是不確定的??勺儏?shù)函數(shù)的定義形式為:返回類型 函數(shù)名(類型1
12、 形參1,類型2 形參2,)函數(shù)體 364.2.6 可變參數(shù)函數(shù)在函數(shù)體中可以使用stdarg.h頭文件定義的幾個va_*的宏來引用可變參數(shù):(1)va_list arg_ptr:定義一個指向個數(shù)可變的參數(shù)列表指針;374.2.6 可變參數(shù)函數(shù)(2)va_start(arg_ptr, argN):使參數(shù)列表指針arg_ptr指向函數(shù)參數(shù)列表中第一個可選參數(shù),argN是位于第一個可選參數(shù)之前的固定參數(shù),即最后一個固定參數(shù)。例如有一個函數(shù)是int fun(char a,char b,char c,.),則它的固定參數(shù)依次是a、b、c,最后一個固定參數(shù)argN即為c,因此就是va_start(arg
13、_ptr ,c)。384.2.6 可變參數(shù)函數(shù)(3)va_arg(arg_ptr, type):返回參數(shù)列表中指針arg_ptr所指的參數(shù),返回類型由type指定,并使指針arg_ptr指向參數(shù)列表中下一個參數(shù)。(4)va_end(arg_ptr):清空參數(shù)列表,并置參數(shù)指針arg_ptr無效。指針arg_ptr被置無效后,可以通過調(diào)用va_start恢復(fù)arg_ptr。每次調(diào)用va_start后,必須有相應(yīng)的va_end與之匹配。參數(shù)指針可以在參數(shù)列表中隨意地來回移動,但必須在va_startva_end之間。394.2.6 可變參數(shù)函數(shù)例4.2 1 #include 2 #include
14、/可變參數(shù)函數(shù)需要用到可變參數(shù)函數(shù)需要用到va_*的宏定義的宏定義 3 double avg(int first, .) /返回若干個整數(shù)平均值的函數(shù)返回若干個整數(shù)平均值的函數(shù) 4 5 int count=0 ,sum=0, i; 6 va_list arg_ptr; /定義變參數(shù)列表指針定義變參數(shù)列表指針 7 va_start(arg_ptr, first); /初始化初始化 8 i=first; /取第取第1個參數(shù)個參數(shù) 404.2.6 可變參數(shù)函數(shù)例4.2 9 while( i!=-1 ) /調(diào)用時最后一個參數(shù)必須是調(diào)用時最后一個參數(shù)必須是-1,作為結(jié)束標(biāo)記,作為結(jié)束標(biāo)記 10 11 s
15、um += i; /累加多個整數(shù)值累加多個整數(shù)值 12 count+; /計數(shù)計數(shù) 13 i = va_arg(arg_ptr, int); /取下一個參數(shù)取下一個參數(shù) 14 15 va_end(arg_ptr); /清空參數(shù)列表清空參數(shù)列表 16 return (count0?(double)sum/count:0); 17 414.2.6 可變參數(shù)函數(shù)例4.2 18 int main() 19 20 printf(%lfn, avg(1,2,3,-1); /返回返回1-3的平均值的平均值 21 printf(%lfn, avg(7,8,9,10,-1); /返回返回7-10的平均值的平均值
16、 22 printf(%lfn, avg(-1); /沒有計算返回沒有計算返回0 23 return 0; 24 424.3 函數(shù)原型與調(diào)用1函數(shù)聲明 當(dāng)要調(diào)用函數(shù)時,C語言規(guī)定在調(diào)用一個函數(shù)之前必須有該函數(shù)的聲明。 編譯器在編譯函數(shù)調(diào)用時,需要檢查函數(shù)接口,即返回類型、參數(shù)類型、參數(shù)次序、參數(shù)數(shù)目是否正確,這樣就能避免參數(shù)類型、參數(shù)數(shù)目不一致而引發(fā)的錯誤。保證正確的函數(shù)調(diào)用棧。而編譯器之所以能夠發(fā)現(xiàn)這些錯誤,原因就在于它事先有了該函數(shù)的聲明,進(jìn)而知道函數(shù)接口是如何規(guī)定的。434.3.1 函數(shù)聲明和函數(shù)原型一個函數(shù)只能定義一次,但是可以聲明多次。定義是函數(shù)實現(xiàn),函數(shù)代碼一經(jīng)實現(xiàn),就不能再來一次
17、。聲明的作用是程序向編譯器提供函數(shù)的接口信息,因而多次提供接口信息是允許的,但不能提供相互矛盾、語義不一致的接口信息。444.3.1 函數(shù)聲明和函數(shù)原型C語言規(guī)定函數(shù)定義語法既是函數(shù)定義,也是函數(shù)聲明。換言之,只要函數(shù)調(diào)用是寫在函數(shù)定義的后面,就自然有了函數(shù)聲明。 但這種方式與C語言允許函數(shù)定義可放在任意位置的規(guī)定矛盾了,而且使用起來也不方便。顯然,將函數(shù)調(diào)用均寫在函數(shù)定義的后面不是現(xiàn)實的方法。454.3.1 函數(shù)聲明和函數(shù)原型 一般情況下,將函數(shù)聲明放在頭文件(.h)中,將函數(shù)實現(xiàn)放在源程序文件中。凡是要調(diào)用這個函數(shù)的地方,通過#include將頭文件包含即可。 另一方面,C語言允許調(diào)用庫函
18、數(shù),所謂庫函數(shù)是指事先由程序員編制好的函數(shù)。多數(shù)情況下,基于各種理由,如保護(hù)知識產(chǎn)權(quán),這些庫函數(shù)僅提供二進(jìn)制形式的目標(biāo)代碼給調(diào)用者鏈接,卻沒有提供源碼形式的函數(shù)定義。這種情況下,又如何讓調(diào)用者有函數(shù)聲明呢?方法是使用函數(shù)原型。464.3.1 函數(shù)聲明和函數(shù)原型2函數(shù)原型函數(shù)原型(function prototype)的作用是提供函數(shù)調(diào)用所必須的接口信息,使編譯器能夠檢查函數(shù)調(diào)用中可能存在的問題,有兩種形式:第一種形式:第二種形式:返回類型 函數(shù)名(類型1 形參1,類型2 形參2,);返回類型 函數(shù)名(類型1 ,類型2 ,);474.3.1 函數(shù)聲明和函數(shù)原型標(biāo)準(zhǔn)庫求平方根的函數(shù)原型,表示調(diào)用它
19、需要:包含頭文件math.h,因為sqrt函數(shù)原型在math.h中。sqrt函數(shù)須提供一個double型的實參,返回值也是double型。 #include double sqrt(double x);484.3.1 函數(shù)聲明和函數(shù)原型例4.3 1 #include 2 int gcd(int m,int n);/gcd函數(shù)原型,聲明在前函數(shù)原型,聲明在前 3 int main() 4 5 int m,n; 6 scanf(%d%d,&m,&n); 7 printf(%dn,gcd(m,n); /調(diào)用調(diào)用 8 return 0; 9 494.3.1 函數(shù)聲明和函數(shù)原型例4.3
20、10 int gcd(int m, int n) /gcd函數(shù)實現(xiàn)在后函數(shù)實現(xiàn)在后 11 12 int r; 13 while (n!=0) /歐幾里德算法,原理是:歐幾里德算法,原理是: 14 r = m % n ; /r為為m/n的余數(shù)的余數(shù) 15 m = n ; /則則gcd(m,n)=gcd(n,r)=. 16 n = r ; /r=0時時n即是即是gcd 17 18 return m; 19 504.3.1 函數(shù)聲明和函數(shù)原型函數(shù)原型通常出現(xiàn)在函數(shù)定義的前面,也允許在函數(shù)定義的后面,只不過意義不大。編譯器在編譯時,無論它們哪個在前,均以第一次“看到”的函數(shù)接口為準(zhǔn),,如果后面的與這個
21、函數(shù)接口不一致,就會出現(xiàn)編譯錯誤,所以函數(shù)原型要與函數(shù)定義匹配。514.3.1 函數(shù)聲明和函數(shù)原型3函數(shù)調(diào)用有了函數(shù)聲明,就可以調(diào)用函數(shù),有參數(shù)函數(shù)調(diào)用的形式為:實參可以是常量、變量、表達(dá)式和函數(shù)調(diào)用,各實參之間用逗號(,)分隔。實參的類型、次序、個數(shù)應(yīng)與形參一致。函數(shù)名(實參列表)524.3.1 函數(shù)聲明和函數(shù)原型無參數(shù)函數(shù)調(diào)用的形式為:函數(shù)名后面的括號()必須有,括號內(nèi)不能有任何參數(shù)。函數(shù)名()534.3.1 函數(shù)聲明和函數(shù)原型在C語言中,可以用以下幾種方式調(diào)用函數(shù)。(1)函數(shù)表達(dá)式。(2)函數(shù)調(diào)用語句。(3)函數(shù)實參z = max(x,y)printf(area=%lf,s);print
22、f(%d,max(x,y);544.3.1 函數(shù)聲明和函數(shù)原型前面述及,函數(shù)調(diào)用時實參的運算是有方向的,即函數(shù)調(diào)用對實參的計算是有求值順序的。運算方向由不同的函數(shù)調(diào)用約定決定,C語言默認(rèn)使用C調(diào)用約定,求值順序是自右向左。與此相反的是PASCAL調(diào)用約定,求值順序是自左向右。C程序需要經(jīng)過特別的設(shè)定才能是PASCAL調(diào)用約定。554.3.1 函數(shù)聲明和函數(shù)原型int i=1,j=2;printf(%d,%d,%dn,i=i+j,j=j+i,i=i+j);/從右向左計算實參從右向左計算實參程序輸出結(jié)果為:8,5,3。因為在調(diào)用printf函數(shù)時,先處理最右邊的i=i+j,這個實參值是3,再處理中
23、間的j=j+i,這個實參值是5,最后處理左邊的i=i+j,這個實參值是8。 564.3.2 庫函數(shù)的調(diào)用方法(1)在程序中添加庫函數(shù)聲明 多數(shù)庫函數(shù)將自己的函數(shù)原型和特殊數(shù)據(jù)等放在頭文件(.h)中,所以應(yīng)首先使用文件包含命令將這些頭文件包含到程序中。例如欲使用數(shù)學(xué)庫函數(shù),文件包含命令為: #include 574.3.2 庫函數(shù)的調(diào)用方法(1)在程序中添加庫函數(shù)聲明 多數(shù)庫函數(shù)將自己的函數(shù)原型和特殊數(shù)據(jù)等放在頭文件(.h)中,所以應(yīng)首先使用文件包含命令將這些頭文件包含到程序中。例如欲使用數(shù)學(xué)庫函數(shù),文件包含命令為: #include 從而使得程序有函數(shù)聲明,例如: y=sin(x); 調(diào)用就能
24、夠通過編譯。584.3.2 庫函數(shù)的調(diào)用方法(2)將庫函數(shù)目標(biāo)代碼連接到程序中。 在連接時,例如使用了sin函數(shù),就必須要有sin函數(shù)的實現(xiàn)代碼才能生成可執(zhí)行文件,否則連接出錯。要將庫函數(shù)的目標(biāo)代碼能夠連接到程序中,主要是配置好開發(fā)環(huán)境的相關(guān)參數(shù),然后由連接器處理。 標(biāo)準(zhǔn)庫函數(shù)的連接在開發(fā)環(huán)境中是默認(rèn)的,一般可以不用特別設(shè)置。 594.3.2 庫函數(shù)的調(diào)用方法604.3.2 庫函數(shù)的調(diào)用方法614.3.3 標(biāo)準(zhǔn)庫函數(shù)表4-1 標(biāo)準(zhǔn)庫函數(shù)索引標(biāo)準(zhǔn)庫名稱標(biāo)準(zhǔn)庫名稱頭文件名頭文件名標(biāo)準(zhǔn)庫名稱標(biāo)準(zhǔn)庫名稱頭文件名頭文件名斷言驗證斷言驗證復(fù)數(shù)算術(shù)運算復(fù)數(shù)算術(shù)運算字符類型字符類型出錯碼出錯碼浮點環(huán)境浮點環(huán)境
25、浮點常量浮點常量整型格式轉(zhuǎn)換整型格式轉(zhuǎn)換替代記號替代記號整型大小整型大小本地化本地化數(shù)學(xué)數(shù)學(xué)非局部跳轉(zhuǎn)非局部跳轉(zhuǎn)信號量處理信號量處理可變參數(shù)可變參數(shù)布爾類型布爾類型標(biāo)準(zhǔn)定義標(biāo)準(zhǔn)定義整型類型整型類型標(biāo)準(zhǔn)輸入輸出標(biāo)準(zhǔn)輸入輸出實用函數(shù)實用函數(shù)字符串字符串624.3.3 標(biāo)準(zhǔn)庫函數(shù)續(xù)表4-1 標(biāo)準(zhǔn)庫函數(shù)索引標(biāo)準(zhǔn)庫名稱標(biāo)準(zhǔn)庫名稱頭文件名頭文件名標(biāo)準(zhǔn)庫名稱標(biāo)準(zhǔn)庫名稱頭文件名頭文件名通用類型數(shù)學(xué)通用類型數(shù)學(xué)宏宏時間日期時間日期擴(kuò)展多字節(jié)和擴(kuò)展多字節(jié)和寬字符寬字符寬字符分類和寬字符分類和映射映射在調(diào)用標(biāo)準(zhǔn)庫函數(shù)時,需要在源文件中包含相應(yīng)的頭文件,形式如下:#include 634.3.3 標(biāo)準(zhǔn)庫函數(shù)例4.4
26、1 #include 2 #include /使用數(shù)學(xué)庫使用數(shù)學(xué)庫 3 int main() 4 5 double d; 6 int i,j; 7 for(i=0;i90;i+) 8 printf(%2d ,i); 9 for(j=0;j10;j+) 10 d=(i+j/10.0)*3.1415926535/180; 11 printf(%.4lf ,sin(d); 12 13 printf(n); 14 15 return 0; 16 644.3.3 標(biāo)準(zhǔn)庫函數(shù)例4.5 1 #include 2 #include /使用實用函數(shù)使用實用函數(shù) 3 #include /使用時間函數(shù)使用時間函數(shù)
27、4 int main() 5 6 double d; 7 int i,n,seed; 8 seed=time(0); /以系統(tǒng)流逝時間為隨機(jī)數(shù)發(fā)生器種子以系統(tǒng)流逝時間為隨機(jī)數(shù)發(fā)生器種子 9 srand(unsigned int)seed); 654.3.3 標(biāo)準(zhǔn)庫函數(shù)例4.5 10 for(i=0;i10;i+) 11 n=rand()%20; /產(chǎn)生產(chǎn)生0,20)區(qū)間的隨機(jī)整數(shù)區(qū)間的隨機(jī)整數(shù) 12 d=rand()/(double)RAND_MAX; /產(chǎn)生產(chǎn)生(0,1)區(qū)間的隨機(jī)小數(shù)區(qū)間的隨機(jī)小數(shù) 13 printf(%d %lfn,n,d); 14 15 return 0; 16 664
28、.4 內(nèi)聯(lián)函數(shù)C語言提供一種提高函數(shù)效率的方法,即在編譯時將被調(diào)函數(shù)的代碼直接嵌入到主調(diào)函數(shù)中,取消調(diào)用這個環(huán)節(jié)。這種嵌入到主調(diào)函數(shù)中的函數(shù)稱為內(nèi)聯(lián)函數(shù)(inline function)。 請注意,一些早期編譯器,如Visual C+ 6.0不支持這個新特性。674.4 內(nèi)聯(lián)函數(shù)內(nèi)聯(lián)函數(shù)的聲明是在函數(shù)定義的類型前加上inline修飾符,定義形式為:inline 返回類型 函數(shù)名(形式參數(shù)列表)函數(shù)體 684.4 內(nèi)聯(lián)函數(shù)圖4.2 普通函數(shù)和內(nèi)聯(lián)函數(shù)調(diào)用示意694.4 內(nèi)聯(lián)函數(shù)例4.6 1 #include 2 inline int fun(int a,int b) /內(nèi)聯(lián)函數(shù)內(nèi)聯(lián)函數(shù) 3 4
29、return a*a+b*b; 5 6 int main() 7 8 int n=5,m=8,k; 9 k = fun(n,m); /調(diào)用點嵌入調(diào)用點嵌入 a*a+b*b 代碼代碼 10 printf(k=%dn,k); 11 return 0; 12 704.4 內(nèi)聯(lián)函數(shù)內(nèi)聯(lián)函數(shù)中不允許用循環(huán)語句和switch語句,遞歸函數(shù)也不能被用來做內(nèi)聯(lián)函數(shù)。當(dāng)編譯器無法對代碼進(jìn)行嵌入時,就會忽略inline聲明,此時內(nèi)聯(lián)失效,這些函數(shù)將按普通函數(shù)處理。一般情況下,只是將規(guī)模較小、語句不多(15個)、頻繁使用的函數(shù)聲明為內(nèi)聯(lián)函數(shù)。對一個含有許多語句的函數(shù),函數(shù)調(diào)用的開銷相對來說微不足道,所以也沒有必要用
30、內(nèi)聯(lián)函數(shù)實現(xiàn)。 714.5 函數(shù)調(diào)用形式嵌套調(diào)用在調(diào)用一個函數(shù)的過程中,又調(diào)用另一個函數(shù),稱為函數(shù)嵌套調(diào)用,C語言允許函數(shù)多層嵌套調(diào)用,只要在函數(shù)調(diào)用前有函數(shù)聲明即可。724.5.1 嵌套調(diào)用例4.7 1 #include 2 int fa(int a,int b); /fa函數(shù)原型函數(shù)原型 3 int fb(int x); / fb函數(shù)原型函數(shù)原型 4 int main() 5 6 int a=5,b=10,c; 7 c = fa(a,b); 8 printf(%dn,c); 9 c = fb(a+b); 10 printf(%dn,c); 11 return 0; 12 734.5.1 嵌
31、套調(diào)用例4.7 13 int fa(int a,int b) 14 15 int z; 16 z= fb(a*b); 17 return z; 18 19 int fb(int x) 20 21 int a=15,b=20,c; 22 c=a+b+x; 23 return c; 24 744.5.1 嵌套調(diào)用圖4.3 嵌套調(diào)用示意754.5.1 嵌套調(diào)用圖4.4 嵌套調(diào)用函數(shù)調(diào)用棧(1)函數(shù)每調(diào)用一次就會有新的函數(shù)調(diào)用棧建立,返回時函數(shù)調(diào)用棧釋放;(2)每個函數(shù)調(diào)用棧都是獨立的,相互不影響;764.5.1 嵌套調(diào)用圖4.4 嵌套調(diào)用函數(shù)調(diào)用棧(3)盡管main函數(shù)和fb函數(shù)都有局部變量a、b、
32、c,但明顯的是它們是在不同區(qū)域的存儲單元,各自獨立,互不相干。774.5.1 嵌套調(diào)用【例4.8】 用弦截法求方程的根,精度 。 32( )51680f xxxx610784.5.1 嵌套調(diào)用例4.8 1 #include 2 #include 3 double f(double x) 4 /所要求解的函數(shù)公式,可改為其他公式所要求解的函數(shù)公式,可改為其他公式 5 return x*x*x-3*x-1; 6 7 double point(double a,double b) 8 /求解弦與求解弦與x軸的交點軸的交點 9 return (a*f(b)-b*f(a)/(f(b)-f(a); 10
33、794.5.1 嵌套調(diào)用例4.8 11 double root(double a, double b) 12 /弦截法求方程弦截法求方程a,b區(qū)間的根區(qū)間的根 13 double x,y,y1; 14 y1=f(a); 15 do 16 x=point(a,b); /求交點求交點x坐標(biāo)坐標(biāo) 17 y=f(x); /求求y 18 if (y*y10) y1=y, a=x; 19 else b=x; 20 while (fabs(y)=0.00001); /計算精度計算精度E 21 return x; 22 804.5.1 嵌套調(diào)用例4.8 23 int main() 24 25 double a
34、,b; 26 scanf(%lf%lf,&a,&b); 27 printf(root=%lfn,root(a,b); 28 return 0; 29 814.5.2 遞歸調(diào)用4.5.2 遞歸調(diào)用函數(shù)直接或間接調(diào)用自己稱為遞歸調(diào)用。C語言允許函數(shù)遞歸調(diào)用,如圖4.6(a)所示為直接遞歸調(diào)用,如圖4.6(b)所示為間接遞歸調(diào)用。圖4.6 遞歸調(diào)用示意824.5.2 遞歸調(diào)用例4.9 1 #include 2 int f(int n) 3 4 if (n1) return f(n-1)*n; /遞歸調(diào)用遞歸調(diào)用 5 return 1; 6 7 int main() 8 9 print
35、f(%dn,f(5); 10 return 0; 11 834.5.2 遞歸調(diào)用圖4.7 遞歸調(diào)用過程844.5.2 遞歸調(diào)用表4-2 f函數(shù)的執(zhí)行跟蹤nreturn5f(4)*54f(3)*43f(2)*32f(1)*211854.5.2 遞歸調(diào)用圖4.8 遞歸調(diào)用函數(shù)調(diào)用棧864.6 作用域和生命期本節(jié)討論(設(shè)計函數(shù)的重要內(nèi)容)作用域(scope)生命期(lifetimes)874.6.1 局部變量局部變量在函數(shù)內(nèi)部或復(fù)合語句中(簡稱區(qū)域)定義的變量,稱為局部變量(local variable),又稱為內(nèi)部變量。884.6.1 局部變量894.6.1 局部變量局部變量的說明。(1)局部變量
36、只能在定義它的區(qū)域及其子區(qū)域中使用。 例如main函數(shù)可以使用第38行的a、b、c、n,f1函數(shù)可以使用第1行的x、y(形參)和第3行的a、b、m,if分支的復(fù)合語句可以使用f1函數(shù)定義的變量和第5行的a、t;另一方面,main函數(shù)就不能使用f1函數(shù)的變量,f1函數(shù)不能使用main函數(shù)的變量。904.6.1 局部變量局部變量的說明。(2)在同一個區(qū)域中不能定義相同名字的變量。 例如第1行有了x、y,那么在f1函數(shù)內(nèi)部就不能再使用x和y的名字了。(3)在不同區(qū)域中允許定義相同名字的變量,但本質(zhì)上它們是不同的變量 例如main函數(shù)的a、b和f1函數(shù)的a、b完全不相干。914.6.1 局部變量(4)
37、如果一個變量所處區(qū)域的子區(qū)域中有同名的變量,則該變量在子區(qū)域無效,有效的是子區(qū)域的變量,稱為定義屏蔽。 例如第3行的a在f1函數(shù)中,而if分支的復(fù)合語句是f1函數(shù)的子區(qū)域,并且第5行也有a定義,所以第3行的a在復(fù)合語句不可見,復(fù)合語句的a是第5行定義的。924.6.2 全局變量全局變量在源文件中,但在函數(shù)外部定義的變量,稱為全局變量(global variable),全局變量的有效區(qū)域是從定義變量的位置開始到源文件結(jié)束。934.6.2 全局變量944.6.2 全局變量函數(shù)之間數(shù)據(jù)傳遞盡管可以利用全局變量,但這樣一來也導(dǎo)致兩個函數(shù)彼此分不開,違背模塊化的原則,所以結(jié)構(gòu)化程序設(shè)計提倡少用或不用全局
38、變量。954.6.3 作用域C語言的實體通常有三類:變量或?qū)ο?,例如基本類型變量、?shù)組對象、指針對象、結(jié)構(gòu)體對象等;函數(shù);類型。包含結(jié)構(gòu)體類型、共用體類型。作用域是程序中的一段區(qū)域。在同一個作用域上,C程序中每個名字都與唯一的實體對應(yīng);只要在不同的作用域上,那么在程序中就可以多次使用同一個名字,對應(yīng)不同作用域中的不同實體。964.6.3 作用域(1)文件作用域(file scope)(2)函數(shù)作用域(function scope)(3)塊作用域(block scope)(4)類型聲明作用域(declaration scope)(5)函數(shù)原型作用域(function prototype scop
39、e)974.6.3 作用域?qū)嶓w在作用域內(nèi)可以使用稱為可見(visible),又稱有效。可見的含義是指實體在作用域上處處可以使用下面給出C語言實體可見規(guī)則。(1)規(guī)則一。同一個作用域內(nèi)不允許有相同名字的實體,不同的作用域的實體互不可見,可以有相同名字。984.6.3 作用域C語言實體可見規(guī)則。(2)規(guī)則二。實體在包含它的作用域內(nèi),從定義或聲明的位置開始,按文件行的順序往后(往下)直到該作用域結(jié)束均是可見的,包含作用域內(nèi)的所有子區(qū)域及其嵌套,但往前(往上)不可見,同時包含該作用域的上一級區(qū)域也不可見。994.6.3 作用域C語言實體可見規(guī)則。(3)規(guī)則三。若實體A在包含它的作用域內(nèi)的子區(qū)域中出現(xiàn)了
40、相同名字的實體B,則實體A被屏蔽(hide),即實體A在子區(qū)域不可見,在子區(qū)域中可見的是實體B。(4)規(guī)則四??梢允褂胑xtern聲明將全局變量或函數(shù)實體的可見區(qū)域往前延伸,稱為前置聲明(forward declaration)。(5)規(guī)則五。在全局作用域中,變量或函數(shù)實體若使用static修飾,則該實體對于其他源文件是屏蔽的,稱為私有的(private)。1004.6.3 作用域extern聲明變量實體的形式為:extern聲明函數(shù)原型的形式為:extern 類型 變量名, .extern 返回類型 函數(shù)名(類型1 參數(shù)名1, .);extern 返回類型 函數(shù)名(類型1,.);1014.6
41、.3 作用域static修飾變量實體的形式為:static修飾函數(shù)原型的形式為:static 類型 變量名=初值, .static 返回類型 函數(shù)名(類型1 參數(shù)名1, .);static 返回類型 函數(shù)名(類型1, .) ;1024.6.3 作用域 1 / FILE1.C 全局作用域全局作用域 2 int a=1 , b=2; /全局變量全局變量 3 int c=10 , d=11; /全局變量全局變量 4 void f1(int n,int m) /f1函數(shù)作用域函數(shù)作用域 5 6 int x=21, y=22,z=23; /f1局部變量局部變量 7 extern int h,k;/正確,
42、正確,h=60 k=61 規(guī)則四規(guī)則四 8 n = n + t ; /錯誤,錯誤,t 違反規(guī)則二違反規(guī)則二 9 if (n100) /塊作用域塊作用域 10 int x=31,t=20; /復(fù)合語句局部變量復(fù)合語句局部變量 11 n=x+y;/正確,正確,n=31+22 規(guī)則二規(guī)則二 規(guī)則三規(guī)則三 12 if (m10) /嵌套塊作用域嵌套塊作用域 13 int y=41;/嵌套的復(fù)合語句局部變量嵌套的復(fù)合語句局部變量 14 n=x+y;/正確,規(guī)則二正確,規(guī)則二 規(guī)則三規(guī)則三 1034.6.3 作用域 15 16 17 n = a + x ; /正確,正確,n=1+21 規(guī)則二規(guī)則二 18
43、m = e + f ; /錯誤,錯誤,e,f 違反規(guī)則二違反規(guī)則二 19 n = h + k ; /正確,正確,n=60+61 規(guī)則四規(guī)則四 20 21 int e=50 , f=51; /全局變量全局變量 22 int h=60 , k=61; /全局變量全局變量 23 void f2(int n,int m) /f2函數(shù)作用域函數(shù)作用域 24 25 n=a+b+e+f; /正確,正確,n=1+2+50+51 規(guī)則二規(guī)則二 26 m=z; /錯誤,錯誤,z 違反規(guī)則一違反規(guī)則一 27 1044.6.3 作用域 28 int f3(int n,int m) /f3函數(shù)作用域函數(shù)作用域 29 3
44、0 return n+m; /正確,規(guī)則二正確,規(guī)則二 31 32 int f4(int n,int m) /f4函數(shù)作用域函數(shù)作用域 33 34 return n-m; /正確,規(guī)則二正確,規(guī)則二 35 36 / FILE1.C 文件結(jié)束文件結(jié)束1054.6.3 作用域 1 / FILE2.C 全局作用域全局作用域 2 int a=201 , b=202; /錯誤,連接時與錯誤,連接時與FILE1.C的同名的同名 違反規(guī)則一違反規(guī)則一 3 void f1(int n,int m) /錯誤,連接時與錯誤,連接時與FILE1.C的同名的同名 違反規(guī)則一違反規(guī)則一 4 5 n=n*m; 6 7 s
45、tatic int c=210 , d=212; /正確,規(guī)則五正確,規(guī)則五 8 static void f2(int n,int m) /正確,規(guī)則五正確,規(guī)則五 9 10 n=n/m; 11 1064.6.3 作用域 12 extern int h , k; /正確,規(guī)則四正確,規(guī)則四 13 extern int f4(int n,int m); /正確,規(guī)則四正確,規(guī)則四 14 int main() 15 16 int p,q,r; /main函數(shù)局部變量函數(shù)局部變量 17 p = c + d; /正確,正確,p=210+212 規(guī)則二規(guī)則二 18 f2(-1,-2); /正確,不是正確
46、,不是FILE1.C的的 規(guī)則二規(guī)則二 19 q = e + f; /錯誤,試圖使用錯誤,試圖使用FILE1.C的的 違反規(guī)則一違反規(guī)則一 20 f3(-10,-12); /錯誤,試圖使用錯誤,試圖使用FILE1.C的的 違反規(guī)則一違反規(guī)則一 21 r = h + k; /正確,正確,r=60+61 規(guī)則四規(guī)則四 22 f4(-20,-22); /正確,規(guī)則四正確,規(guī)則四 23 return 0; 24 1074.6.4 程序映像和內(nèi)存布局C源程序經(jīng)過編譯、連接后,成為二進(jìn)制形式的可執(zhí)行文件,稱為程序映像??蓤?zhí)行文件采用ELF格式(可執(zhí)行連接格式)存儲,內(nèi)容包含程序指令、已初始化的靜態(tài)數(shù)據(jù)和其
47、他一些重要信息,例如未初始化的靜態(tài)數(shù)據(jù)空間大小、符號表(symbol table),調(diào)試信息(debugging information)、動態(tài)共享庫的鏈接表(linkage tables for dynamic shared libraries)等。1084.6.4 程序映像和內(nèi)存布局運行程序時,由操作系統(tǒng)將可執(zhí)行文件載入到計算機(jī)內(nèi)存中,成為一個進(jìn)程(process)。程序在內(nèi)存中的布局由5個段(segment)組成。 1094.6.4 程序映像和內(nèi)存布局圖4.9 可執(zhí)行文件映像與內(nèi)存映像1104.6.4 程序映像和內(nèi)存布局1代碼段代碼段(text segment)存放程序執(zhí)行的機(jī)器指令(m
48、achine instructions)。通常情況下,text段是可共享的,使其可共享的目的是對于頻繁被執(zhí)行的程序,只需要在內(nèi)存中有一份副本即可。text段通常也是只讀的,使其只讀的原因是防止一個程序意外地修改了它的指令。1114.6.4 程序映像和內(nèi)存布局2已初始化數(shù)據(jù)段已初始化數(shù)據(jù)段(data segment)用來存放C程序中所有已賦初值的全局和靜態(tài)變量、對象,也包括字符串、數(shù)組等常量,但基本類型的常量不包含其中,因為這些常量被編譯成指令的一部分存放于text段。1124.6.4 程序映像和內(nèi)存布局2已初始化數(shù)據(jù)段程序運行時由操作系統(tǒng)從程序映像中取出data段,布局在程序內(nèi)存地址較低的區(qū)域
49、。程序結(jié)束后由操作系統(tǒng)收回這段內(nèi)存區(qū)域,即釋放data段。顯然,data段的存儲單元有與程序代碼相同的生命期,它們的初始值實際在編譯時就已經(jīng)確定了。即使程序沒有運行,這些存儲單元的初始值也固定下來了,當(dāng)程序開始運行時,這些存儲單元是沒有初始化的動作。在程序運行中,data段的存儲單元數(shù)據(jù)會一直保持到改變?yōu)橹?,或保持到程序結(jié)束為止。1134.6.4 程序映像和內(nèi)存布局3未初始化數(shù)據(jù)段未初始化數(shù)據(jù)段(bss segment)用來存放C程序中所有未賦初值的全局和靜態(tài)變量。在程序映像中沒有存儲bss段,只有它的空間大小信息;程序運行前由操作系統(tǒng)根據(jù)這個大小信息分配bss段,且數(shù)據(jù)值全都初始化為0,布局
50、在與data段相鄰的區(qū)域。程序結(jié)束后由操作系統(tǒng)收回這段內(nèi)存區(qū)域,即釋放bss段。1144.6.4 程序映像和內(nèi)存布局3未初始化數(shù)據(jù)段顯然,bss段的存儲單元也有與程序代碼相同的生命期,但與data段不同的是如果程序沒有運行,bss段的存儲空間是不存在的,因而也就不會有初始值。當(dāng)程序運行前,這些存儲單元會初始化為0。此后,bss段的存儲單元的性質(zhì)與data段完全相同。1154.6.4 程序映像和內(nèi)存布局data段和bss段的存儲特點,決定了C程序中所有全局和靜態(tài)變量、對象的存儲空間在main函數(shù)運行前就已經(jīng)存在,就有了初始值。程序運行到這些變量和對象的定義處時,是不會再有初始化動作的。在程序運行
51、中這些變量和對象的存儲空間不會被釋放,一直保持到程序運行結(jié)束。期間如果數(shù)據(jù)被修改,則修改會一直保持。1164.6.4 程序映像和內(nèi)存布局4棧棧(stack)用來存放C程序中所有局部的非靜態(tài)型變量、臨時變量,包含函數(shù)形參和函數(shù)返回值。1174.6.4 程序映像和內(nèi)存布局4棧程序映像中沒有棧,在程序開始運行時也不會分配棧。每當(dāng)一個函數(shù)被調(diào)用,程序在棧段中按函數(shù)棧框架入棧,就分配了局部變量存儲空間。如果這些變量有初始化,就會有賦值指令給這些變量送初值,否則變量的值就呈現(xiàn)隨機(jī)性。當(dāng)函數(shù)調(diào)用結(jié)束時,函數(shù)??蚣艹鰲#瘮?shù)局部變量釋放存儲空間。棧的存儲特點,決定了C程序中所有局部的非靜態(tài)型變量,其存儲方式是
52、動態(tài)的。函數(shù)調(diào)用開始時得到分配,賦予初值,函數(shù)調(diào)用結(jié)束時釋放空間,變量不存在。下次函數(shù)調(diào)用時再重復(fù)。1184.6.4 程序映像和內(nèi)存布局5堆堆(heap)用來存放C程序中動態(tài)分配的存儲空間。1194.6.4 程序映像和內(nèi)存布局5堆程序映像中沒有堆,在程序開始運行時不會分配堆,函數(shù)調(diào)用時也不會分配堆。堆的存儲空間分配和釋放是通過指定的程序方式來進(jìn)行的,即由程序員使用指令分配和釋放,若程序員不釋放,程序結(jié)束可能由操作系統(tǒng)回收。C語言中可以通過使用指針、動態(tài)內(nèi)存分配和釋放函數(shù)來實現(xiàn)堆的分配和釋放,詳見第7章。程序可以通過動態(tài)內(nèi)存分配和釋放來使用堆區(qū),堆區(qū)有比棧更大的存儲空間、更自由的使用方式。120
53、4.6.4 程序映像和內(nèi)存布局堆和棧的共同點是動態(tài)存儲,處于這兩個區(qū)域的存儲單元可以隨時分配和釋放,所以這些存儲單元的使用特點呈現(xiàn)臨時性的特點。data段的特點是靜態(tài)存儲,處于這個區(qū)域的存儲單元隨程序運行而存在,隨程序結(jié)束才釋放,相對程序生命期,data段存儲單元的使用特點呈現(xiàn)持久性的特點。data段由于持久占有存儲空間,因此大小會被操作系統(tǒng)限定,而堆可以達(dá)到空閑空間的最大值。1214.6.4 程序映像和內(nèi)存布局堆和棧的區(qū)別是分配方式的不同,棧是編譯器根據(jù)程序代碼自動確定大小,到函數(shù)調(diào)用時有指令自動完成分配和釋放的;堆則完全由程序員指定分配大小、何時分配、何時釋放。堆的優(yōu)點是分配和釋放是自由的
54、,缺點是需要程序員自行掌握分配和釋放時機(jī),特別是釋放時機(jī),假如已經(jīng)釋放了還要使用堆會產(chǎn)生引用錯誤,或者始終沒有釋放產(chǎn)生內(nèi)存泄漏(memory leak)。1224.6.5 生命期C語言中,每個名字都有作用域,即可以使用名字的區(qū)域,而每個對象都有生命期(lifetimes),即在程序執(zhí)行過程中對象存在的時間。1234.6.5 生命期1動態(tài)存儲動態(tài)存儲(dynamic storage duration)是指在程序運行期間,系統(tǒng)為對象動態(tài)地分配存儲空間。動態(tài)存儲的特點是存儲空間的分配和釋放是動態(tài)的,要么由函數(shù)調(diào)用來自動分配釋放,要么由程序指令來人工分配釋放,在分配至釋放之間就是對象的生命期,這個生命
55、期是整個程序運行期的一部分。從前一節(jié)可知動態(tài)存儲是在內(nèi)存布局中的棧和堆兩個段實現(xiàn)的。1244.6.5 生命期1動態(tài)存儲動態(tài)存儲的優(yōu)點是對象不持久地占有存儲空間,釋放后讓出空閑空間給其他對象的分配。程序中多數(shù)對象應(yīng)該是動態(tài)存儲方式的,因為程序的執(zhí)行在一段時期往往局限于 部分對象,而不會是所有對象,這樣未起作用的對象持久占有內(nèi)存空間,只會導(dǎo)致內(nèi)存越來越少,多進(jìn)程、多任務(wù)無從談起。1254.6.5 生命期動態(tài)存儲在分配和釋放的形式有兩種,一種是由函數(shù)調(diào)用來自動完成的,稱為自動存儲(automatic storage),一種是由程序員通過指令的方式來人工完成的,稱為自由存儲(free storage)
56、。1264.6.5 生命期自動存儲的優(yōu)點是程序員不用理會對象何時分配、分配多大、何時釋放,其生命期完全與函數(shù)調(diào)用相同,自由存儲的優(yōu)點是生命期由程序員的意愿來決定,因此即使函數(shù)已經(jīng)運行完也可以繼續(xù)存在,直到釋放指令發(fā)生。自由存儲的缺點是程序員需要操心釋放時機(jī),多數(shù)情況下程序員會忘記釋放,或者忘記已經(jīng)釋放。1274.6.5 生命期2靜態(tài)存儲靜態(tài)存儲(static storage duration)是指對象在整個程序運行期持久占有存儲空間,其生命期與程序運行期相同。靜態(tài)存儲的特點是對象的數(shù)據(jù)可以在程序運行期始終保持直到修改為止,或者程序結(jié)束為止,靜態(tài)存儲的分配和釋放在編譯完成時就決定好了。從前一節(jié)可
57、知靜態(tài)存儲是在內(nèi)存布局中的數(shù)據(jù)段實現(xiàn)的。現(xiàn)代程序設(shè)計的觀點是,除非有必要盡量少地使用靜態(tài)存儲。1284.6.5 生命期圖4.10 存儲類別的生命期1294.6.5 生命期3自動對象默認(rèn)情況下,函數(shù)或復(fù)合語句中的對象(包含形參)稱為自動對象(automatic objects),其存儲方式是自動存儲,程序中大多數(shù)對象是自動存儲。auto 類型類型 變量名變量名=初值初值, .1304.6.5 生命期4寄存器變量C語言允許用CPU的寄存器來存放局部變量,稱為寄存器變量。在局部變量前加上register存儲類別修飾來定義的,其形式為:register 類型類型 變量名變量名=初值初值, .1314.
58、6.5 生命期5靜態(tài)局部對象在局部對象的前面加上static存儲類別修飾用來指明對象是靜態(tài)局部對象(static local object),一般形式為:static 類型類型 變量名變量名=初值初值 , .1324.6.5 生命期1334.6.5 生命期例4.10 1 #include 2 int fun() 3 4 static int cnt=0;/靜態(tài)局部變量會保持其值靜態(tài)局部變量會保持其值 5 cnt+; 6 return cnt; 7 8 int main() 9 10 int i,c; 11 for (i=1;i=10;i+) c=fun(); 12 printf(%dn,c);
59、 13 return 0; 14 1344.7 對象初始化1初始化概念對象定義時指定了變量的類型和標(biāo)識符,也可以為對象提供初始值,定義時指定了初始值的對象被稱為是“已初始化的(initialized)”,而創(chuàng)建對象并給它初始值就稱為初始化(initialization)。初始化不是賦值,賦值的含義是擦除對象的當(dāng)前值并用新值代替,而初始化除了給初值外,之前還創(chuàng)建了對象。1354.7 對象初始化1初始化概念對象定義時指定了變量的類型和標(biāo)識符,也可以為對象提供初始值,定義時指定了初始值的對象被稱為是“已初始化的(initialized)”,而創(chuàng)建對象并給它初始值就稱為初始化(initializati
60、on)。初始化不是賦值,賦值的含義是擦除對象的當(dāng)前值并用新值代替,而初始化除了給初值外,之前還創(chuàng)建了對象。1364.7 對象初始化 1 #include 2 int m=100; /全局變量已初始化全局變量已初始化 3 int n; /全局變量未初始化全局變量未初始化 4 int main() 5 6 int a; 7 a=10+m+n; /a=10+100+0 8 return 0; 9 第7行是賦值運算,執(zhí)行此語句后變量a得到賦值,可是這個程序執(zhí)行main函數(shù),并沒有從第2、3行執(zhí)行過去,那m、n有值是如何來的呢?顯然,“賦”的說法不通。1374.7 對象初始化例4.11 1 #include 2 int fun()
溫馨提示
- 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 掌握項目時間管理技巧試題及答案
- 注冊會計師考試專題試題及答案
- 真人圖書執(zhí)行方案范本
- 2024項目管理項目實施方案試題及答案
- 2024年項目管理考試實踐試題及答案
- 項目管理中的溝通與反饋機(jī)制試題及答案
- 2024年項目評估的標(biāo)準(zhǔn)題目及答案
- 地鐵拱蓋法施工方案
- 知識點全面覆蓋園藝師試題及答案
- 園林金屬工具生產(chǎn)工藝流程優(yōu)化考核試卷
- 2025年合肥高新美城物業(yè)有限公司招聘30人筆試參考題庫附帶答案詳解
- 2025內(nèi)蒙古中煤鄂爾多斯能源化工有限公司招聘98人筆試參考題庫附帶答案詳解
- 三年級西師大語文下學(xué)期期末知識點歸納復(fù)習(xí)知識點鞏固練習(xí)
- 河南省駐馬店市汝南縣2024-2025學(xué)年七年級下學(xué)期期中生物試題(含答案)
- 23G409先張法預(yù)應(yīng)力混凝土管樁
- 人教PEP版(一起)(2024)一年級上冊英語全冊教案(單元整體教學(xué)設(shè)計)
- DZ∕T 0219-2006 滑坡防治工程設(shè)計與施工技術(shù)規(guī)范(正式版)
- MOOC 大學(xué)體育-華中科技大學(xué) 中國大學(xué)慕課答案
- 《光伏發(fā)電工程工程量清單計價規(guī)范》
- 人工智能與知識產(chǎn)權(quán)保護(hù)的關(guān)系
- 三年級下冊口算天天100題(A4打印版)
評論
0/150
提交評論