版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
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 對(duì)象初始化4.8 聲明與定義3第4章 函數(shù)4.9 變量修飾小結(jié)4.10 程序組織結(jié)構(gòu)4.11 函數(shù)應(yīng)用程序舉例使用函數(shù)的最大好處:舉例說(shuō)明1.結(jié)構(gòu)化程序設(shè)計(jì):模塊分割,由上而下,逐步細(xì)化,功能模塊用函數(shù)實(shí)現(xiàn);2.相同功能的代碼段復(fù)用;使用函數(shù)減少重復(fù)勞動(dòng):把要重復(fù)使用的功能包裝成函數(shù);44.1 函數(shù)定義函數(shù)定義的一般形式為:函數(shù)定義本質(zhì)上就是抽象功能代碼的函數(shù)實(shí)現(xiàn),包括:確定函數(shù)名;確定形式參數(shù)列表;確定返回類(lèi)型;編寫(xiě)函數(shù)體代碼。 返回類(lèi)型 函數(shù)名
2、(形式參數(shù)列表)函數(shù)體聲明部分函數(shù)體執(zhí)行語(yǔ)句 54.1.1 函數(shù)定義的一般形式1函數(shù)名 實(shí)現(xiàn)函數(shù)需要確定函數(shù)名,以便使用函數(shù)時(shí)能夠按名引用。2形式參數(shù)列表 實(shí)現(xiàn)函數(shù)需要確定有無(wú)形式參數(shù)、有多少形式參數(shù)、有什么類(lèi)型的形式參數(shù)。形式參數(shù)列表是函數(shù)與調(diào)用者進(jìn)行數(shù)據(jù)交換的途徑,一般形式為:類(lèi)型類(lèi)型1 參數(shù)名參數(shù)名1,類(lèi)型類(lèi)型2 參數(shù)名參數(shù)名2, 類(lèi)型類(lèi)型3 參數(shù)名參數(shù)名3 , 64.1.1 函數(shù)定義的一般形式 多個(gè)參數(shù)用逗號(hào)(,)分隔,且每個(gè)參數(shù)都要有自己的類(lèi)型說(shuō)明,即使類(lèi)型相同的參數(shù)也是如此。例如:int fun(int x, int y, double m) return m12.5 ? x :
3、y;74.1.1 函數(shù)定義的一般形式 函數(shù)可以沒(méi)有形式參數(shù),定義形式為: 返回類(lèi)型 函數(shù)名()函數(shù)體聲明部分函數(shù)體執(zhí)行語(yǔ)句 返回類(lèi)型 函數(shù)名(void)函數(shù)體聲明部分函數(shù)體執(zhí)行語(yǔ)句 84.1.1 函數(shù)定義的一般形式3返回類(lèi)型 實(shí)現(xiàn)函數(shù)需要確定有無(wú)返回?cái)?shù)據(jù)、返回什么類(lèi)型的數(shù)據(jù)。返回值是函數(shù)向調(diào)用者返回?cái)?shù)據(jù)的途徑之一,本質(zhì)上函數(shù)返回值也起到與調(diào)用者進(jìn)行數(shù)據(jù)交換的作用,只不過(guò)它是單向的,即從函數(shù)向調(diào)用者傳遞,故稱(chēng)返回。 返回類(lèi)型可以是C語(yǔ)言除數(shù)組之外的內(nèi)置數(shù)據(jù)類(lèi)型或自定義類(lèi)型。C語(yǔ)言規(guī)定一個(gè)函數(shù)如果沒(méi)有給出返回類(lèi)型,則默認(rèn)是int型94.1.1 函數(shù)定義的一般形式 函數(shù)可以不返回?cái)?shù)據(jù),此時(shí)返回類(lèi)型應(yīng)
4、寫(xiě)成void,表示沒(méi)有返回值,其形式為: void 函數(shù)名(形式參數(shù)列表)函數(shù)體聲明部分函數(shù)體執(zhí)行語(yǔ)句 104.1.1 函數(shù)定義的一般形式4函數(shù)體 實(shí)現(xiàn)函數(shù)最重要的是編寫(xiě)函數(shù)體。函數(shù)體(function body)包含聲明部分和執(zhí)行語(yǔ)句,是一組能實(shí)現(xiàn)特定功能的語(yǔ)句序列的集合。 編寫(xiě)函數(shù)體是為了實(shí)現(xiàn)函數(shù)功能。故稱(chēng)函數(shù)定義為函數(shù)實(shí)現(xiàn),簡(jiǎn)稱(chēng)實(shí)現(xiàn)。 而函數(shù)頭簡(jiǎn)稱(chēng)接口。114.1.1 函數(shù)定義的一般形式例4.1 1 #include 2 int IsPrime(int m) /求素?cái)?shù)函數(shù)求素?cái)?shù)函數(shù) 3 /枚舉法求枚舉法求m是否素?cái)?shù)是否素?cái)?shù) 4 int i; 5 for (i=2 ; ib ? a : b
5、; 4 第1行a和b就是形參。 204.2.1 形式參數(shù)函數(shù)定義時(shí)指定的形參,在未進(jìn)行函數(shù)調(diào)用前,并不實(shí)際占用內(nèi)存中的存儲(chǔ)單元,這也是稱(chēng)它為形式參數(shù)的原因,即它們不是實(shí)際存在的。只有在發(fā)生函數(shù)調(diào)用時(shí),形參才分配實(shí)際的內(nèi)存單元,接受從主調(diào)函數(shù)傳來(lái)的數(shù)據(jù),此刻形參是真實(shí)存在的,因而可以對(duì)它們進(jìn)行各種操作。當(dāng)函數(shù)調(diào)用結(jié)束后,形參占用的內(nèi)存單元被自動(dòng)釋放。此后,形參又是未實(shí)際存在的。214.2.1 形式參數(shù)形參的類(lèi)型可以是任意數(shù)據(jù)類(lèi)型,換言之,函數(shù)允許任意類(lèi)型的數(shù)據(jù)傳遞到函數(shù)中。形參類(lèi)型的設(shè)計(jì)一是依據(jù)實(shí)際需求,二是確保高效的數(shù)據(jù)傳遞。224.2.2 實(shí)際參數(shù)實(shí)際參數(shù)函數(shù)調(diào)用時(shí)提供給被調(diào)函數(shù)的參數(shù)稱(chēng)為實(shí)
6、際參數(shù)(arguments),簡(jiǎn)稱(chēng)實(shí)參。實(shí)參必須有確定的值,因?yàn)檎{(diào)用函數(shù)會(huì)將它們傳遞給形參。實(shí)參可以是常量、變量或表達(dá)式,還可以是函數(shù)的返回值。例如:x = max(a,b); /max函數(shù)調(diào)用,實(shí)參為函數(shù)調(diào)用,實(shí)參為a,by = max(a+3,128); /max函數(shù)調(diào)用,實(shí)參為函數(shù)調(diào)用,實(shí)參為a+3,128z = max(max(a,b),c); /max函數(shù)調(diào)用,實(shí)參為函數(shù)調(diào)用,實(shí)參為max(a,b),c234.2.2 實(shí)際參數(shù)實(shí)參數(shù)據(jù)傳遞給形參,必須滿足語(yǔ)法和應(yīng)用兩方面的要求。實(shí)參是以形參為依據(jù)的,即實(shí)參的類(lèi)型、次序和數(shù)目要與形參一致。如果參數(shù)數(shù)目不一致,則出現(xiàn)編譯錯(cuò)誤;如果參數(shù)次序
7、不一致,則傳遞到被調(diào)函數(shù)中的數(shù)據(jù)就不合邏輯,難有正確的程序結(jié)果;244.2.2 實(shí)際參數(shù)如果參數(shù)類(lèi)型不一致時(shí),則函數(shù)調(diào)用時(shí)按形參類(lèi)型隱式類(lèi)型轉(zhuǎn)換實(shí)參;如果是不能進(jìn)行隱式類(lèi)型轉(zhuǎn)換的類(lèi)型,就會(huì)出現(xiàn)編譯錯(cuò)誤。更重要的是,實(shí)參的數(shù)據(jù)應(yīng)與函數(shù)接口要求的數(shù)據(jù)物理意義是一致的,否則即使語(yǔ)法正確,程序的運(yùn)行結(jié)果也是錯(cuò)的。例如調(diào)用數(shù)學(xué)庫(kù)函數(shù)中的sin函數(shù)求正弦時(shí),函數(shù)接口就要求實(shí)參必須是弧度的數(shù)據(jù)。254.2.3 參數(shù)傳遞機(jī)制程序通常有兩種函數(shù)參數(shù)傳遞機(jī)制:值傳遞和引用傳遞。值傳遞(pass-by-value)過(guò)程中,形參作為被調(diào)函數(shù)的內(nèi)部變量來(lái)處理,即開(kāi)辟內(nèi)存空間以存放由主調(diào)函數(shù)復(fù)制過(guò)來(lái)的實(shí)參的值,從而成為實(shí)
8、參的一個(gè)副本。264.2.3 參數(shù)傳遞機(jī)制值傳遞的特點(diǎn)是被調(diào)函數(shù)對(duì)形參的任何操作都是對(duì)內(nèi)部變量進(jìn)行,不會(huì)影響到主調(diào)函數(shù)的實(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); /實(shí)參值傳遞實(shí)參值傳遞274.2.3 參數(shù)傳遞機(jī)制引用傳遞(pass-by-reference)過(guò)程中,被調(diào)函數(shù)的形參雖然也作為內(nèi)部變量開(kāi)辟了內(nèi)存空間,但是這時(shí)存放的是由主調(diào)函數(shù)復(fù)制過(guò)來(lái)的實(shí)參的內(nèi)存地址,從而使
9、得形參為實(shí)參的一個(gè)別名(形參和實(shí)參內(nèi)存地址相同,則它們實(shí)為同一個(gè)對(duì)象的兩個(gè)名稱(chēng))。被調(diào)函數(shù)對(duì)形參的任何操作實(shí)際上都是對(duì)主調(diào)函數(shù)的實(shí)參進(jìn)行操作。C語(yǔ)言中,值傳遞是唯一的參數(shù)傳遞方式。C語(yǔ)言的后續(xù)C+,支持引用傳遞。284.2.3 參數(shù)傳遞機(jī)制值傳遞時(shí),實(shí)參數(shù)據(jù)傳遞給形參是單向傳遞,即只能由實(shí)參傳遞給形參,而不能由形參傳回給實(shí)參,這也是實(shí)參可以是常量和表達(dá)式的原因(這些數(shù)據(jù)不是左值)。294.2.4 函數(shù)調(diào)用棧函數(shù)調(diào)用時(shí),為了能將參數(shù)傳遞到函數(shù)中、準(zhǔn)確返回到調(diào)用點(diǎn)以及返回函數(shù)值,使用了“?!眮?lái)管理存儲(chǔ)器存儲(chǔ)函數(shù)的形參和局部變量。棧是內(nèi)存管理中的一種數(shù)據(jù)結(jié)構(gòu),是一種先進(jìn)后出的數(shù)據(jù)表,即先進(jìn)去的數(shù)據(jù)后
10、出來(lái)。棧最常見(jiàn)操作有兩種:進(jìn)棧(push)和出棧(pop)。304.2.4 函數(shù)調(diào)用棧系統(tǒng)為每次函數(shù)調(diào)用在“?!敝薪ⅹ?dú)立的棧框架,稱(chēng)為函數(shù)調(diào)用棧幀(stack frame),其建立和撤銷(xiāo)是自動(dòng)維護(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ù)定義時(shí),允許在形參的類(lèi)型前面加上const限定,語(yǔ)法形式為:返回類(lèi)型 函數(shù)名(const 類(lèi)型 形式參數(shù),)函數(shù)體 344.2.5 const參數(shù)函數(shù)參數(shù)使用const限定的目的是確保形參對(duì)應(yīng)的實(shí)參對(duì)象在函數(shù)體中不會(huì)被修改。通常,基本類(lèi)型的參數(shù),因?yàn)樾螀⒑蛯?shí)參本來(lái)就不是同一個(gè)內(nèi)存單元,即使修改形參也不會(huì)影響到實(shí)參,因此沒(méi)有必要加const限定。但如果是數(shù)組參數(shù)、指針參數(shù),希望在函數(shù)中不修改數(shù)組元素或者指針值就有必要了。354.2.6 可變參數(shù)函數(shù)可變參數(shù)函數(shù)C語(yǔ)言支持可變參數(shù)的函數(shù),允許函數(shù)參數(shù)數(shù)目是不確定的??勺儏?shù)函數(shù)的定義形式為:返回類(lèi)型 函數(shù)名(類(lèi)型1
12、 形參1,類(lèi)型2 形參2,)函數(shù)體 364.2.6 可變參數(shù)函數(shù)在函數(shù)體中可以使用stdarg.h頭文件定義的幾個(gè)va_*的宏來(lái)引用可變參數(shù):(1)va_list arg_ptr:定義一個(gè)指向個(gè)數(shù)可變的參數(shù)列表指針;374.2.6 可變參數(shù)函數(shù)(2)va_start(arg_ptr, argN):使參數(shù)列表指針arg_ptr指向函數(shù)參數(shù)列表中第一個(gè)可選參數(shù),argN是位于第一個(gè)可選參數(shù)之前的固定參數(shù),即最后一個(gè)固定參數(shù)。例如有一個(gè)函數(shù)是int fun(char a,char b,char c,.),則它的固定參數(shù)依次是a、b、c,最后一個(gè)固定參數(shù)argN即為c,因此就是va_start(arg
13、_ptr ,c)。384.2.6 可變參數(shù)函數(shù)(3)va_arg(arg_ptr, type):返回參數(shù)列表中指針arg_ptr所指的參數(shù),返回類(lèi)型由type指定,并使指針arg_ptr指向參數(shù)列表中下一個(gè)參數(shù)。(4)va_end(arg_ptr):清空參數(shù)列表,并置參數(shù)指針arg_ptr無(wú)效。指針arg_ptr被置無(wú)效后,可以通過(guò)調(diào)用va_start恢復(fù)arg_ptr。每次調(diào)用va_start后,必須有相應(yīng)的va_end與之匹配。參數(shù)指針可以在參數(shù)列表中隨意地來(lái)回移動(dòng),但必須在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, .) /返回若干個(gè)整數(shù)平均值的函數(shù)返回若干個(gè)整數(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個(gè)參數(shù)個(gè)參數(shù) 404.2.6 可變參數(shù)函數(shù)例4.2 9 while( i!=-1 ) /調(diào)用時(shí)最后一個(gè)參數(shù)必須是調(diào)用時(shí)最后一個(gè)參數(shù)必須是-1,作為結(jié)束標(biāo)記,作為結(jié)束標(biāo)記 10 11 s
15、um += i; /累加多個(gè)整數(shù)值累加多個(gè)整數(shù)值 12 count+; /計(jì)數(shù)計(jì)數(shù) 13 i = va_arg(arg_ptr, int); /取下一個(gè)參數(shù)取下一個(gè)參數(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); /沒(méi)有計(jì)算返回沒(méi)有計(jì)算返回0 23 return 0; 24 424.3 函數(shù)原型與調(diào)用1函數(shù)聲明 當(dāng)要調(diào)用函數(shù)時(shí),C語(yǔ)言規(guī)定在調(diào)用一個(gè)函數(shù)之前必須有該函數(shù)的聲明。 編譯器在編譯函數(shù)調(diào)用時(shí),需要檢查函數(shù)接口,即返回類(lèi)型、參數(shù)類(lèi)型、參數(shù)次序、參數(shù)數(shù)目是否正確,這樣就能避免參數(shù)類(lèi)型、參數(shù)數(shù)目不一致而引發(fā)的錯(cuò)誤。保證正確的函數(shù)調(diào)用棧。而編譯器之所以能夠發(fā)現(xiàn)這些錯(cuò)誤,原因就在于它事先有了該函數(shù)的聲明,進(jìn)而知道函數(shù)接口是如何規(guī)定的。434.3.1 函數(shù)聲明和函數(shù)原型一個(gè)函數(shù)只能定義一次,但是可以聲明多次。定義是函數(shù)實(shí)現(xiàn),函數(shù)代碼一經(jīng)實(shí)現(xiàn),就不能再來(lái)一次
17、。聲明的作用是程序向編譯器提供函數(shù)的接口信息,因而多次提供接口信息是允許的,但不能提供相互矛盾、語(yǔ)義不一致的接口信息。444.3.1 函數(shù)聲明和函數(shù)原型C語(yǔ)言規(guī)定函數(shù)定義語(yǔ)法既是函數(shù)定義,也是函數(shù)聲明。換言之,只要函數(shù)調(diào)用是寫(xiě)在函數(shù)定義的后面,就自然有了函數(shù)聲明。 但這種方式與C語(yǔ)言允許函數(shù)定義可放在任意位置的規(guī)定矛盾了,而且使用起來(lái)也不方便。顯然,將函數(shù)調(diào)用均寫(xiě)在函數(shù)定義的后面不是現(xiàn)實(shí)的方法。454.3.1 函數(shù)聲明和函數(shù)原型 一般情況下,將函數(shù)聲明放在頭文件(.h)中,將函數(shù)實(shí)現(xiàn)放在源程序文件中。凡是要調(diào)用這個(gè)函數(shù)的地方,通過(guò)#include將頭文件包含即可。 另一方面,C語(yǔ)言允許調(diào)用庫(kù)函
18、數(shù),所謂庫(kù)函數(shù)是指事先由程序員編制好的函數(shù)。多數(shù)情況下,基于各種理由,如保護(hù)知識(shí)產(chǎn)權(quán),這些庫(kù)函數(shù)僅提供二進(jìn)制形式的目標(biāo)代碼給調(diào)用者鏈接,卻沒(méi)有提供源碼形式的函數(shù)定義。這種情況下,又如何讓調(diào)用者有函數(shù)聲明呢?方法是使用函數(shù)原型。464.3.1 函數(shù)聲明和函數(shù)原型2函數(shù)原型函數(shù)原型(function prototype)的作用是提供函數(shù)調(diào)用所必須的接口信息,使編譯器能夠檢查函數(shù)調(diào)用中可能存在的問(wèn)題,有兩種形式:第一種形式:第二種形式:返回類(lèi)型 函數(shù)名(類(lèi)型1 形參1,類(lèi)型2 形參2,);返回類(lèi)型 函數(shù)名(類(lèi)型1 ,類(lèi)型2 ,);474.3.1 函數(shù)聲明和函數(shù)原型標(biāo)準(zhǔn)庫(kù)求平方根的函數(shù)原型,表示調(diào)用它
19、需要:包含頭文件math.h,因?yàn)閟qrt函數(shù)原型在math.h中。sqrt函數(shù)須提供一個(gè)double型的實(shí)參,返回值也是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ù)實(shí)現(xiàn)在后函數(shù)實(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時(shí)時(shí)n即是即是gcd 17 18 return m; 19 504.3.1 函數(shù)聲明和函數(shù)原型函數(shù)原型通常出現(xiàn)在函數(shù)定義的前面,也允許在函數(shù)定義的后面,只不過(guò)意義不大。編譯器在編譯時(shí),無(wú)論它們哪個(gè)在前,均以第一次“看到”的函數(shù)接口為準(zhǔn),,如果后面的與這個(gè)
21、函數(shù)接口不一致,就會(huì)出現(xiàn)編譯錯(cuò)誤,所以函數(shù)原型要與函數(shù)定義匹配。514.3.1 函數(shù)聲明和函數(shù)原型3函數(shù)調(diào)用有了函數(shù)聲明,就可以調(diào)用函數(shù),有參數(shù)函數(shù)調(diào)用的形式為:實(shí)參可以是常量、變量、表達(dá)式和函數(shù)調(diào)用,各實(shí)參之間用逗號(hào)(,)分隔。實(shí)參的類(lèi)型、次序、個(gè)數(shù)應(yīng)與形參一致。函數(shù)名(實(shí)參列表)524.3.1 函數(shù)聲明和函數(shù)原型無(wú)參數(shù)函數(shù)調(diào)用的形式為:函數(shù)名后面的括號(hào)()必須有,括號(hào)內(nèi)不能有任何參數(shù)。函數(shù)名()534.3.1 函數(shù)聲明和函數(shù)原型在C語(yǔ)言中,可以用以下幾種方式調(diào)用函數(shù)。(1)函數(shù)表達(dá)式。(2)函數(shù)調(diào)用語(yǔ)句。(3)函數(shù)實(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í)實(shí)參的運(yùn)算是有方向的,即函數(shù)調(diào)用對(duì)實(shí)參的計(jì)算是有求值順序的。運(yùn)算方向由不同的函數(shù)調(diào)用約定決定,C語(yǔ)言默認(rèn)使用C調(diào)用約定,求值順序是自右向左。與此相反的是PASCAL調(diào)用約定,求值順序是自左向右。C程序需要經(jīng)過(guò)特別的設(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);/從右向左計(jì)算實(shí)參從右向左計(jì)算實(shí)參程序輸出結(jié)果為:8,5,3。因?yàn)樵谡{(diào)用printf函數(shù)時(shí),先處理最右邊的i=i+j,這個(gè)實(shí)參值是3,再處理中
23、間的j=j+i,這個(gè)實(shí)參值是5,最后處理左邊的i=i+j,這個(gè)實(shí)參值是8。 564.3.2 庫(kù)函數(shù)的調(diào)用方法(1)在程序中添加庫(kù)函數(shù)聲明 多數(shù)庫(kù)函數(shù)將自己的函數(shù)原型和特殊數(shù)據(jù)等放在頭文件(.h)中,所以應(yīng)首先使用文件包含命令將這些頭文件包含到程序中。例如欲使用數(shù)學(xué)庫(kù)函數(shù),文件包含命令為: #include 574.3.2 庫(kù)函數(shù)的調(diào)用方法(1)在程序中添加庫(kù)函數(shù)聲明 多數(shù)庫(kù)函數(shù)將自己的函數(shù)原型和特殊數(shù)據(jù)等放在頭文件(.h)中,所以應(yīng)首先使用文件包含命令將這些頭文件包含到程序中。例如欲使用數(shù)學(xué)庫(kù)函數(shù),文件包含命令為: #include 從而使得程序有函數(shù)聲明,例如: y=sin(x); 調(diào)用就能
24、夠通過(guò)編譯。584.3.2 庫(kù)函數(shù)的調(diào)用方法(2)將庫(kù)函數(shù)目標(biāo)代碼連接到程序中。 在連接時(shí),例如使用了sin函數(shù),就必須要有sin函數(shù)的實(shí)現(xiàn)代碼才能生成可執(zhí)行文件,否則連接出錯(cuò)。要將庫(kù)函數(shù)的目標(biāo)代碼能夠連接到程序中,主要是配置好開(kāi)發(fā)環(huán)境的相關(guān)參數(shù),然后由連接器處理。 標(biāo)準(zhǔn)庫(kù)函數(shù)的連接在開(kāi)發(fā)環(huán)境中是默認(rèn)的,一般可以不用特別設(shè)置。 594.3.2 庫(kù)函數(shù)的調(diào)用方法604.3.2 庫(kù)函數(shù)的調(diào)用方法614.3.3 標(biāo)準(zhǔn)庫(kù)函數(shù)表4-1 標(biāo)準(zhǔn)庫(kù)函數(shù)索引標(biāo)準(zhǔn)庫(kù)名稱(chēng)標(biāo)準(zhǔn)庫(kù)名稱(chēng)頭文件名頭文件名標(biāo)準(zhǔn)庫(kù)名稱(chēng)標(biāo)準(zhǔn)庫(kù)名稱(chēng)頭文件名頭文件名斷言驗(yàn)證斷言驗(yàn)證復(fù)數(shù)算術(shù)運(yùn)算復(fù)數(shù)算術(shù)運(yùn)算字符類(lèi)型字符類(lèi)型出錯(cuò)碼出錯(cuò)碼浮點(diǎn)環(huán)境浮點(diǎn)環(huán)境
25、浮點(diǎn)常量浮點(diǎn)常量整型格式轉(zhuǎn)換整型格式轉(zhuǎn)換替代記號(hào)替代記號(hào)整型大小整型大小本地化本地化數(shù)學(xué)數(shù)學(xué)非局部跳轉(zhuǎn)非局部跳轉(zhuǎn)信號(hào)量處理信號(hào)量處理可變參數(shù)可變參數(shù)布爾類(lèi)型布爾類(lèi)型標(biāo)準(zhǔn)定義標(biāo)準(zhǔn)定義整型類(lèi)型整型類(lèi)型標(biāo)準(zhǔn)輸入輸出標(biāo)準(zhǔn)輸入輸出實(shí)用函數(shù)實(shí)用函數(shù)字符串字符串624.3.3 標(biāo)準(zhǔn)庫(kù)函數(shù)續(xù)表4-1 標(biāo)準(zhǔn)庫(kù)函數(shù)索引標(biāo)準(zhǔn)庫(kù)名稱(chēng)標(biāo)準(zhǔn)庫(kù)名稱(chēng)頭文件名頭文件名標(biāo)準(zhǔn)庫(kù)名稱(chēng)標(biāo)準(zhǔn)庫(kù)名稱(chēng)頭文件名頭文件名通用類(lèi)型數(shù)學(xué)通用類(lèi)型數(shù)學(xué)宏宏時(shí)間日期時(shí)間日期擴(kuò)展多字節(jié)和擴(kuò)展多字節(jié)和寬字符寬字符寬字符分類(lèi)和寬字符分類(lèi)和映射映射在調(diào)用標(biāo)準(zhǔn)庫(kù)函數(shù)時(shí),需要在源文件中包含相應(yīng)的頭文件,形式如下:#include 634.3.3 標(biāo)準(zhǔn)庫(kù)函數(shù)例4.4
26、1 #include 2 #include /使用數(shù)學(xué)庫(kù)使用數(shù)學(xué)庫(kù) 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)庫(kù)函數(shù)例4.5 1 #include 2 #include /使用實(shí)用函數(shù)使用實(shí)用函數(shù) 3 #include /使用時(shí)間函數(shù)使用時(shí)間函數(shù)
27、4 int main() 5 6 double d; 7 int i,n,seed; 8 seed=time(0); /以系統(tǒng)流逝時(shí)間為隨機(jī)數(shù)發(fā)生器種子以系統(tǒng)流逝時(shí)間為隨機(jī)數(shù)發(fā)生器種子 9 srand(unsigned int)seed); 654.3.3 標(biāo)準(zhǔn)庫(kù)函數(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語(yǔ)言提供一種提高函數(shù)效率的方法,即在編譯時(shí)將被調(diào)函數(shù)的代碼直接嵌入到主調(diào)函數(shù)中,取消調(diào)用這個(gè)環(huán)節(jié)。這種嵌入到主調(diào)函數(shù)中的函數(shù)稱(chēng)為內(nèi)聯(lián)函數(shù)(inline function)。 請(qǐng)注意,一些早期編譯器,如Visual C+ 6.0不支持這個(gè)新特性。674.4 內(nèi)聯(lián)函數(shù)內(nèi)聯(lián)函數(shù)的聲明是在函數(shù)定義的類(lèi)型前加上inline修飾符,定義形式為:inline 返回類(lèi)型 函數(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ǎn)嵌入調(diào)用點(diǎn)嵌入 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)語(yǔ)句和switch語(yǔ)句,遞歸函數(shù)也不能被用來(lái)做內(nèi)聯(lián)函數(shù)。當(dāng)編譯器無(wú)法對(duì)代碼進(jìn)行嵌入時(shí),就會(huì)忽略inline聲明,此時(shí)內(nèi)聯(lián)失效,這些函數(shù)將按普通函數(shù)處理。一般情況下,只是將規(guī)模較小、語(yǔ)句不多(15個(gè))、頻繁使用的函數(shù)聲明為內(nèi)聯(lián)函數(shù)。對(duì)一個(gè)含有許多語(yǔ)句的函數(shù),函數(shù)調(diào)用的開(kāi)銷(xiāo)相對(duì)來(lái)說(shuō)微不足道,所以也沒(méi)有必要用
30、內(nèi)聯(lián)函數(shù)實(shí)現(xiàn)。 714.5 函數(shù)調(diào)用形式嵌套調(diào)用在調(diào)用一個(gè)函數(shù)的過(guò)程中,又調(diào)用另一個(gè)函數(shù),稱(chēng)為函數(shù)嵌套調(diào)用,C語(yǔ)言允許函數(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)用一次就會(huì)有新的函數(shù)調(diào)用棧建立,返回時(shí)函數(shù)調(diào)用棧釋放;(2)每個(gè)函數(shù)調(diào)用棧都是獨(dú)立的,相互不影響;764.5.1 嵌套調(diào)用圖4.4 嵌套調(diào)用函數(shù)調(diào)用棧(3)盡管main函數(shù)和fb函數(shù)都有局部變量a、b、
32、c,但明顯的是它們是在不同區(qū)域的存儲(chǔ)單元,各自獨(dú)立,互不相干。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軸的交點(diǎn)軸的交點(diǎn) 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); /求交點(diǎn)求交點(diǎn)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); /計(jì)算精度計(jì)算精度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)用自己稱(chēng)為遞歸調(diào)用。C語(yǔ)言允許函數(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)用過(guò)程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è)計(jì)函數(shù)的重要內(nèi)容)作用域(scope)生命期(lifetimes)874.6.1 局部變量局部變量在函數(shù)內(nèi)部或復(fù)合語(yǔ)句中(簡(jiǎn)稱(chēng)區(qū)域)定義的變量,稱(chēng)為局部變量(local variable),又稱(chēng)為內(nèi)部變量。884.6.1 局部變量894.6.1 局部變量局部變量的說(shuō)明。(1)局部變量
36、只能在定義它的區(qū)域及其子區(qū)域中使用。 例如main函數(shù)可以使用第38行的a、b、c、n,f1函數(shù)可以使用第1行的x、y(形參)和第3行的a、b、m,if分支的復(fù)合語(yǔ)句可以使用f1函數(shù)定義的變量和第5行的a、t;另一方面,main函數(shù)就不能使用f1函數(shù)的變量,f1函數(shù)不能使用main函數(shù)的變量。904.6.1 局部變量局部變量的說(shuō)明。(2)在同一個(gè)區(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、如果一個(gè)變量所處區(qū)域的子區(qū)域中有同名的變量,則該變量在子區(qū)域無(wú)效,有效的是子區(qū)域的變量,稱(chēng)為定義屏蔽。 例如第3行的a在f1函數(shù)中,而if分支的復(fù)合語(yǔ)句是f1函數(shù)的子區(qū)域,并且第5行也有a定義,所以第3行的a在復(fù)合語(yǔ)句不可見(jiàn),復(fù)合語(yǔ)句的a是第5行定義的。924.6.2 全局變量全局變量在源文件中,但在函數(shù)外部定義的變量,稱(chēng)為全局變量(global variable),全局變量的有效區(qū)域是從定義變量的位置開(kāi)始到源文件結(jié)束。934.6.2 全局變量944.6.2 全局變量函數(shù)之間數(shù)據(jù)傳遞盡管可以利用全局變量,但這樣一來(lái)也導(dǎo)致兩個(gè)函數(shù)彼此分不開(kāi),違背模塊化的原則,所以結(jié)構(gòu)化程序設(shè)計(jì)提倡少用或不用全局
38、變量。954.6.3 作用域C語(yǔ)言的實(shí)體通常有三類(lèi):變量或?qū)ο?,例如基本?lèi)型變量、數(shù)組對(duì)象、指針對(duì)象、結(jié)構(gòu)體對(duì)象等;函數(shù);類(lèi)型。包含結(jié)構(gòu)體類(lèi)型、共用體類(lèi)型。作用域是程序中的一段區(qū)域。在同一個(gè)作用域上,C程序中每個(gè)名字都與唯一的實(shí)體對(duì)應(yīng);只要在不同的作用域上,那么在程序中就可以多次使用同一個(gè)名字,對(duì)應(yīng)不同作用域中的不同實(shí)體。964.6.3 作用域(1)文件作用域(file scope)(2)函數(shù)作用域(function scope)(3)塊作用域(block scope)(4)類(lèi)型聲明作用域(declaration scope)(5)函數(shù)原型作用域(function prototype scop
39、e)974.6.3 作用域?qū)嶓w在作用域內(nèi)可以使用稱(chēng)為可見(jiàn)(visible),又稱(chēng)有效??梢?jiàn)的含義是指實(shí)體在作用域上處處可以使用下面給出C語(yǔ)言實(shí)體可見(jiàn)規(guī)則。(1)規(guī)則一。同一個(gè)作用域內(nèi)不允許有相同名字的實(shí)體,不同的作用域的實(shí)體互不可見(jiàn),可以有相同名字。984.6.3 作用域C語(yǔ)言實(shí)體可見(jiàn)規(guī)則。(2)規(guī)則二。實(shí)體在包含它的作用域內(nèi),從定義或聲明的位置開(kāi)始,按文件行的順序往后(往下)直到該作用域結(jié)束均是可見(jiàn)的,包含作用域內(nèi)的所有子區(qū)域及其嵌套,但往前(往上)不可見(jiàn),同時(shí)包含該作用域的上一級(jí)區(qū)域也不可見(jiàn)。994.6.3 作用域C語(yǔ)言實(shí)體可見(jiàn)規(guī)則。(3)規(guī)則三。若實(shí)體A在包含它的作用域內(nèi)的子區(qū)域中出現(xiàn)了
40、相同名字的實(shí)體B,則實(shí)體A被屏蔽(hide),即實(shí)體A在子區(qū)域不可見(jiàn),在子區(qū)域中可見(jiàn)的是實(shí)體B。(4)規(guī)則四??梢允褂胑xtern聲明將全局變量或函數(shù)實(shí)體的可見(jiàn)區(qū)域往前延伸,稱(chēng)為前置聲明(forward declaration)。(5)規(guī)則五。在全局作用域中,變量或函數(shù)實(shí)體若使用static修飾,則該實(shí)體對(duì)于其他源文件是屏蔽的,稱(chēng)為私有的(private)。1004.6.3 作用域extern聲明變量實(shí)體的形式為:extern聲明函數(shù)原型的形式為:extern 類(lèi)型 變量名, .extern 返回類(lèi)型 函數(shù)名(類(lèi)型1 參數(shù)名1, .);extern 返回類(lèi)型 函數(shù)名(類(lèi)型1,.);1014.6
41、.3 作用域static修飾變量實(shí)體的形式為:static修飾函數(shù)原型的形式為:static 類(lèi)型 變量名=初值, .static 返回類(lèi)型 函數(shù)名(類(lèi)型1 參數(shù)名1, .);static 返回類(lèi)型 函數(shù)名(類(lèi)型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 ; /錯(cuò)誤,錯(cuò)誤,t 違反規(guī)則二違反規(guī)則二 9 if (n100) /塊作用域塊作用域 10 int x=31,t=20; /復(fù)合語(yǔ)句局部變量復(fù)合語(yǔ)句局部變量 11 n=x+y;/正確,正確,n=31+22 規(guī)則二規(guī)則二 規(guī)則三規(guī)則三 12 if (m10) /嵌套塊作用域嵌套塊作用域 13 int y=41;/嵌套的復(fù)合語(yǔ)句局部變量嵌套的復(fù)合語(yǔ)句局部變量 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 ; /錯(cuò)誤,錯(cuò)誤,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; /錯(cuò)誤,錯(cuò)誤,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; /錯(cuò)誤,連接時(shí)與錯(cuò)誤,連接時(shí)與FILE1.C的同名的同名 違反規(guī)則一違反規(guī)則一 3 void f1(int n,int m) /錯(cuò)誤,連接時(shí)與錯(cuò)誤,連接時(shí)與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; /錯(cuò)誤,試圖使用錯(cuò)誤,試圖使用FILE1.C的的 違反規(guī)則一違反規(guī)則一 20 f3(-10,-12); /錯(cuò)誤,試圖使用錯(cuò)誤,試圖使用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)過(guò)編譯、連接后,成為二進(jìn)制形式的可執(zhí)行文件,稱(chēng)為程序映像??蓤?zhí)行文件采用ELF格式(可執(zhí)行連接格式)存儲(chǔ),內(nèi)容包含程序指令、已初始化的靜態(tài)數(shù)據(jù)和其
47、他一些重要信息,例如未初始化的靜態(tài)數(shù)據(jù)空間大小、符號(hào)表(symbol table),調(diào)試信息(debugging information)、動(dòng)態(tài)共享庫(kù)的鏈接表(linkage tables for dynamic shared libraries)等。1084.6.4 程序映像和內(nèi)存布局運(yùn)行程序時(shí),由操作系統(tǒng)將可執(zhí)行文件載入到計(jì)算機(jī)內(nèi)存中,成為一個(gè)進(jìn)程(process)。程序在內(nèi)存中的布局由5個(gè)段(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段是可共享的,使其可共享的目的是對(duì)于頻繁被執(zhí)行的程序,只需要在內(nèi)存中有一份副本即可。text段通常也是只讀的,使其只讀的原因是防止一個(gè)程序意外地修改了它的指令。1114.6.4 程序映像和內(nèi)存布局2已初始化數(shù)據(jù)段已初始化數(shù)據(jù)段(data segment)用來(lái)存放C程序中所有已賦初值的全局和靜態(tài)變量、對(duì)象,也包括字符串、數(shù)組等常量,但基本類(lèi)型的常量不包含其中,因?yàn)檫@些常量被編譯成指令的一部分存放于text段。1124.6.4 程序映像和內(nèi)存布局2已初始化數(shù)據(jù)段程序運(yùn)行時(shí)由操作系統(tǒng)從程序映像中取出data段,布局在程序內(nèi)存地址較低的區(qū)域
49、。程序結(jié)束后由操作系統(tǒng)收回這段內(nèi)存區(qū)域,即釋放data段。顯然,data段的存儲(chǔ)單元有與程序代碼相同的生命期,它們的初始值實(shí)際在編譯時(shí)就已經(jīng)確定了。即使程序沒(méi)有運(yùn)行,這些存儲(chǔ)單元的初始值也固定下來(lái)了,當(dāng)程序開(kāi)始運(yùn)行時(shí),這些存儲(chǔ)單元是沒(méi)有初始化的動(dòng)作。在程序運(yùn)行中,data段的存儲(chǔ)單元數(shù)據(jù)會(huì)一直保持到改變?yōu)橹?,或保持到程序結(jié)束為止。1134.6.4 程序映像和內(nèi)存布局3未初始化數(shù)據(jù)段未初始化數(shù)據(jù)段(bss segment)用來(lái)存放C程序中所有未賦初值的全局和靜態(tài)變量。在程序映像中沒(méi)有存儲(chǔ)bss段,只有它的空間大小信息;程序運(yùn)行前由操作系統(tǒng)根據(jù)這個(gè)大小信息分配bss段,且數(shù)據(jù)值全都初始化為0,布局
50、在與data段相鄰的區(qū)域。程序結(jié)束后由操作系統(tǒng)收回這段內(nèi)存區(qū)域,即釋放bss段。1144.6.4 程序映像和內(nèi)存布局3未初始化數(shù)據(jù)段顯然,bss段的存儲(chǔ)單元也有與程序代碼相同的生命期,但與data段不同的是如果程序沒(méi)有運(yùn)行,bss段的存儲(chǔ)空間是不存在的,因而也就不會(huì)有初始值。當(dāng)程序運(yùn)行前,這些存儲(chǔ)單元會(huì)初始化為0。此后,bss段的存儲(chǔ)單元的性質(zhì)與data段完全相同。1154.6.4 程序映像和內(nèi)存布局data段和bss段的存儲(chǔ)特點(diǎn),決定了C程序中所有全局和靜態(tài)變量、對(duì)象的存儲(chǔ)空間在main函數(shù)運(yùn)行前就已經(jīng)存在,就有了初始值。程序運(yùn)行到這些變量和對(duì)象的定義處時(shí),是不會(huì)再有初始化動(dòng)作的。在程序運(yùn)行
51、中這些變量和對(duì)象的存儲(chǔ)空間不會(huì)被釋放,一直保持到程序運(yùn)行結(jié)束。期間如果數(shù)據(jù)被修改,則修改會(huì)一直保持。1164.6.4 程序映像和內(nèi)存布局4棧棧(stack)用來(lái)存放C程序中所有局部的非靜態(tài)型變量、臨時(shí)變量,包含函數(shù)形參和函數(shù)返回值。1174.6.4 程序映像和內(nèi)存布局4棧程序映像中沒(méi)有棧,在程序開(kāi)始運(yùn)行時(shí)也不會(huì)分配棧。每當(dāng)一個(gè)函數(shù)被調(diào)用,程序在棧段中按函數(shù)??蚣苋霔?,就分配了局部變量存儲(chǔ)空間。如果這些變量有初始化,就會(huì)有賦值指令給這些變量送初值,否則變量的值就呈現(xiàn)隨機(jī)性。當(dāng)函數(shù)調(diào)用結(jié)束時(shí),函數(shù)??蚣艹鰲?,函數(shù)局部變量釋放存儲(chǔ)空間。棧的存儲(chǔ)特點(diǎn),決定了C程序中所有局部的非靜態(tài)型變量,其存儲(chǔ)方式是
52、動(dòng)態(tài)的。函數(shù)調(diào)用開(kāi)始時(shí)得到分配,賦予初值,函數(shù)調(diào)用結(jié)束時(shí)釋放空間,變量不存在。下次函數(shù)調(diào)用時(shí)再重復(fù)。1184.6.4 程序映像和內(nèi)存布局5堆堆(heap)用來(lái)存放C程序中動(dòng)態(tài)分配的存儲(chǔ)空間。1194.6.4 程序映像和內(nèi)存布局5堆程序映像中沒(méi)有堆,在程序開(kāi)始運(yùn)行時(shí)不會(huì)分配堆,函數(shù)調(diào)用時(shí)也不會(huì)分配堆。堆的存儲(chǔ)空間分配和釋放是通過(guò)指定的程序方式來(lái)進(jìn)行的,即由程序員使用指令分配和釋放,若程序員不釋放,程序結(jié)束可能由操作系統(tǒng)回收。C語(yǔ)言中可以通過(guò)使用指針、動(dòng)態(tài)內(nèi)存分配和釋放函數(shù)來(lái)實(shí)現(xiàn)堆的分配和釋放,詳見(jiàn)第7章。程序可以通過(guò)動(dòng)態(tài)內(nèi)存分配和釋放來(lái)使用堆區(qū),堆區(qū)有比棧更大的存儲(chǔ)空間、更自由的使用方式。120
53、4.6.4 程序映像和內(nèi)存布局堆和棧的共同點(diǎn)是動(dòng)態(tài)存儲(chǔ),處于這兩個(gè)區(qū)域的存儲(chǔ)單元可以隨時(shí)分配和釋放,所以這些存儲(chǔ)單元的使用特點(diǎn)呈現(xiàn)臨時(shí)性的特點(diǎn)。data段的特點(diǎn)是靜態(tài)存儲(chǔ),處于這個(gè)區(qū)域的存儲(chǔ)單元隨程序運(yùn)行而存在,隨程序結(jié)束才釋放,相對(duì)程序生命期,data段存儲(chǔ)單元的使用特點(diǎn)呈現(xiàn)持久性的特點(diǎn)。data段由于持久占有存儲(chǔ)空間,因此大小會(huì)被操作系統(tǒng)限定,而堆可以達(dá)到空閑空間的最大值。1214.6.4 程序映像和內(nèi)存布局堆和棧的區(qū)別是分配方式的不同,棧是編譯器根據(jù)程序代碼自動(dòng)確定大小,到函數(shù)調(diào)用時(shí)有指令自動(dòng)完成分配和釋放的;堆則完全由程序員指定分配大小、何時(shí)分配、何時(shí)釋放。堆的優(yōu)點(diǎn)是分配和釋放是自由的
54、,缺點(diǎn)是需要程序員自行掌握分配和釋放時(shí)機(jī),特別是釋放時(shí)機(jī),假如已經(jīng)釋放了還要使用堆會(huì)產(chǎn)生引用錯(cuò)誤,或者始終沒(méi)有釋放產(chǎn)生內(nèi)存泄漏(memory leak)。1224.6.5 生命期C語(yǔ)言中,每個(gè)名字都有作用域,即可以使用名字的區(qū)域,而每個(gè)對(duì)象都有生命期(lifetimes),即在程序執(zhí)行過(guò)程中對(duì)象存在的時(shí)間。1234.6.5 生命期1動(dòng)態(tài)存儲(chǔ)動(dòng)態(tài)存儲(chǔ)(dynamic storage duration)是指在程序運(yùn)行期間,系統(tǒng)為對(duì)象動(dòng)態(tài)地分配存儲(chǔ)空間。動(dòng)態(tài)存儲(chǔ)的特點(diǎn)是存儲(chǔ)空間的分配和釋放是動(dòng)態(tài)的,要么由函數(shù)調(diào)用來(lái)自動(dòng)分配釋放,要么由程序指令來(lái)人工分配釋放,在分配至釋放之間就是對(duì)象的生命期,這個(gè)生命
55、期是整個(gè)程序運(yùn)行期的一部分。從前一節(jié)可知?jiǎng)討B(tài)存儲(chǔ)是在內(nèi)存布局中的棧和堆兩個(gè)段實(shí)現(xiàn)的。1244.6.5 生命期1動(dòng)態(tài)存儲(chǔ)動(dòng)態(tài)存儲(chǔ)的優(yōu)點(diǎn)是對(duì)象不持久地占有存儲(chǔ)空間,釋放后讓出空閑空間給其他對(duì)象的分配。程序中多數(shù)對(duì)象應(yīng)該是動(dòng)態(tài)存儲(chǔ)方式的,因?yàn)槌绦虻膱?zhí)行在一段時(shí)期往往局限于 部分對(duì)象,而不會(huì)是所有對(duì)象,這樣未起作用的對(duì)象持久占有內(nèi)存空間,只會(huì)導(dǎo)致內(nèi)存越來(lái)越少,多進(jìn)程、多任務(wù)無(wú)從談起。1254.6.5 生命期動(dòng)態(tài)存儲(chǔ)在分配和釋放的形式有兩種,一種是由函數(shù)調(diào)用來(lái)自動(dòng)完成的,稱(chēng)為自動(dòng)存儲(chǔ)(automatic storage),一種是由程序員通過(guò)指令的方式來(lái)人工完成的,稱(chēng)為自由存儲(chǔ)(free storage)
56、。1264.6.5 生命期自動(dòng)存儲(chǔ)的優(yōu)點(diǎn)是程序員不用理會(huì)對(duì)象何時(shí)分配、分配多大、何時(shí)釋放,其生命期完全與函數(shù)調(diào)用相同,自由存儲(chǔ)的優(yōu)點(diǎn)是生命期由程序員的意愿來(lái)決定,因此即使函數(shù)已經(jīng)運(yùn)行完也可以繼續(xù)存在,直到釋放指令發(fā)生。自由存儲(chǔ)的缺點(diǎn)是程序員需要操心釋放時(shí)機(jī),多數(shù)情況下程序員會(huì)忘記釋放,或者忘記已經(jīng)釋放。1274.6.5 生命期2靜態(tài)存儲(chǔ)靜態(tài)存儲(chǔ)(static storage duration)是指對(duì)象在整個(gè)程序運(yùn)行期持久占有存儲(chǔ)空間,其生命期與程序運(yùn)行期相同。靜態(tài)存儲(chǔ)的特點(diǎn)是對(duì)象的數(shù)據(jù)可以在程序運(yùn)行期始終保持直到修改為止,或者程序結(jié)束為止,靜態(tài)存儲(chǔ)的分配和釋放在編譯完成時(shí)就決定好了。從前一節(jié)可
57、知靜態(tài)存儲(chǔ)是在內(nèi)存布局中的數(shù)據(jù)段實(shí)現(xiàn)的?,F(xiàn)代程序設(shè)計(jì)的觀點(diǎn)是,除非有必要盡量少地使用靜態(tài)存儲(chǔ)。1284.6.5 生命期圖4.10 存儲(chǔ)類(lèi)別的生命期1294.6.5 生命期3自動(dòng)對(duì)象默認(rèn)情況下,函數(shù)或復(fù)合語(yǔ)句中的對(duì)象(包含形參)稱(chēng)為自動(dòng)對(duì)象(automatic objects),其存儲(chǔ)方式是自動(dòng)存儲(chǔ),程序中大多數(shù)對(duì)象是自動(dòng)存儲(chǔ)。auto 類(lèi)型類(lèi)型 變量名變量名=初值初值, .1304.6.5 生命期4寄存器變量C語(yǔ)言允許用CPU的寄存器來(lái)存放局部變量,稱(chēng)為寄存器變量。在局部變量前加上register存儲(chǔ)類(lèi)別修飾來(lái)定義的,其形式為:register 類(lèi)型類(lèi)型 變量名變量名=初值初值, .1314.
58、6.5 生命期5靜態(tài)局部對(duì)象在局部對(duì)象的前面加上static存儲(chǔ)類(lèi)別修飾用來(lái)指明對(duì)象是靜態(tài)局部對(duì)象(static local object),一般形式為:static 類(lèi)型類(lèi)型 變量名變量名=初值初值 , .1324.6.5 生命期1334.6.5 生命期例4.10 1 #include 2 int fun() 3 4 static int cnt=0;/靜態(tài)局部變量會(huì)保持其值靜態(tài)局部變量會(huì)保持其值 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 對(duì)象初始化1初始化概念對(duì)象定義時(shí)指定了變量的類(lèi)型和標(biāo)識(shí)符,也可以為對(duì)象提供初始值,定義時(shí)指定了初始值的對(duì)象被稱(chēng)為是“已初始化的(initialized)”,而創(chuàng)建對(duì)象并給它初始值就稱(chēng)為初始化(initialization)。初始化不是賦值,賦值的含義是擦除對(duì)象的當(dāng)前值并用新值代替,而初始化除了給初值外,之前還創(chuàng)建了對(duì)象。1354.7 對(duì)象初始化1初始化概念對(duì)象定義時(shí)指定了變量的類(lèi)型和標(biāo)識(shí)符,也可以為對(duì)象提供初始值,定義時(shí)指定了初始值的對(duì)象被稱(chēng)為是“已初始化的(initialized)”,而創(chuàng)建對(duì)象并給它初始值就稱(chēng)為初始化(initializati
60、on)。初始化不是賦值,賦值的含義是擦除對(duì)象的當(dāng)前值并用新值代替,而初始化除了給初值外,之前還創(chuàng)建了對(duì)象。1364.7 對(duì)象初始化 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行是賦值運(yùn)算,執(zhí)行此語(yǔ)句后變量a得到賦值,可是這個(gè)程序執(zhí)行main函數(shù),并沒(méi)有從第2、3行執(zhí)行過(guò)去,那m、n有值是如何來(lái)的呢?顯然,“賦”的說(shuō)法不通。1374.7 對(duì)象初始化例4.11 1 #include 2 int fun()
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 遠(yuǎn)程教育中如何培養(yǎng)學(xué)生的自我約束力
- 運(yùn)動(dòng)療法在醫(yī)療領(lǐng)域的新突破
- 教學(xué)創(chuàng)新與科研突破的相互關(guān)系研究
- 數(shù)據(jù)安全保衛(wèi)戰(zhàn)網(wǎng)絡(luò)安全教育專(zhuān)題研討與執(zhí)行總結(jié)
- 二零二五年度網(wǎng)絡(luò)安全技術(shù)支持與服務(wù)合同6篇
- 2025年度綠色建筑項(xiàng)目投資借款合同樣本4篇
- 深圳廣東深圳市光明區(qū)區(qū)屬公辦幼兒園招聘園長(zhǎng)副園長(zhǎng)財(cái)務(wù)人員筆試歷年參考題庫(kù)附帶答案詳解
- 2025年度個(gè)人養(yǎng)老護(hù)理借款合同及服務(wù)內(nèi)容3篇
- 河北2024年河北工藝美術(shù)職業(yè)學(xué)院第二次選聘工作人員筆試歷年參考題庫(kù)附帶答案詳解
- 武漢2025年湖北武漢科技大學(xué)招聘專(zhuān)任教師和引進(jìn)高層次人才100人筆試歷年參考題庫(kù)附帶答案詳解
- 2024年全國(guó)職業(yè)院校技能大賽高職組(研學(xué)旅行賽項(xiàng))考試題庫(kù)(含答案)
- 2025年溫州市城發(fā)集團(tuán)招聘筆試參考題庫(kù)含答案解析
- 2025年中小學(xué)春節(jié)安全教育主題班會(huì)課件
- 2025版高考物理復(fù)習(xí)知識(shí)清單
- 除數(shù)是兩位數(shù)的除法練習(xí)題(84道)
- 2025年度安全檢查計(jì)劃
- 2024年度工作總結(jié)與計(jì)劃標(biāo)準(zhǔn)版本(2篇)
- 全球半導(dǎo)體測(cè)試探針行業(yè)市場(chǎng)研究報(bào)告2024
- 反走私課件完整版本
- 2024年注冊(cè)計(jì)量師-一級(jí)注冊(cè)計(jì)量師考試近5年真題附答案
- 四年級(jí)下冊(cè)數(shù)學(xué)知識(shí)點(diǎn)總結(jié)
評(píng)論
0/150
提交評(píng)論