版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、6.1 概 述6.2 函數(shù)的定義6.3 函數(shù)的調(diào)用6.4 函數(shù)的嵌套及遞歸調(diào)用6.5 數(shù)組作為函數(shù)參數(shù)6.6 局部變量和全局變量6.7 變量的存儲(chǔ)類別6.8 內(nèi)部函數(shù)和外部函數(shù)6.9 編譯預(yù)處理6.10 程序舉例第6章 函 數(shù)安徽工程科技學(xué)院6.1 概 述6.1.1 模塊化程序設(shè)計(jì)思想 面對(duì)一項(xiàng)復(fù)雜任務(wù),通常采取模塊化的解決方法。首先,分解該復(fù)雜任務(wù)成幾個(gè)大的功能模塊,根據(jù)需要還可以繼續(xù)細(xì)分,直到分解成一個(gè)個(gè)功能獨(dú)立的模塊為止。分解的結(jié)果可以描述為一棵倒立的大樹,如圖6.1所示。 圖6.1 模塊化程序設(shè)計(jì) 在程序設(shè)計(jì)中,常將一些常用的功能模塊編寫成函數(shù),放在函數(shù)庫(kù)中供公共選用。要善于利用函數(shù)庫(kù)
2、中的函數(shù),以減少重復(fù)編寫程序段的工作量。先舉一個(gè)簡(jiǎn)單的函數(shù)調(diào)用的例子?!纠?.1】main( )printstar( ); /* 調(diào)用printstar函數(shù)*/ print_message( );/*調(diào)用print_message*/ printstar( );/*調(diào)用printstar函數(shù)*/ printstar( )/*printstar 函數(shù)* printf(*n); print_message( ) /*print_message函數(shù)*/ printf(“How do you do!n”); 運(yùn)行結(jié)果如下:*How do you do!* printstart( )和print_mes
3、sage( )都是用戶定義的函數(shù),分別用來輸出一排“*”號(hào)和一行信息。說明:(1)一個(gè)源程序文件由一個(gè)或多個(gè)函數(shù)組成。一個(gè)源程序文件是一編譯單位,即以源程序?yàn)閱挝贿M(jìn)行編譯,而不以函數(shù)為單位進(jìn)行編譯。(2)一個(gè)C程序由一個(gè)或多個(gè)源程序文件組成。對(duì)較大的程序,一般不希望全放在一個(gè)文件中,而將函數(shù)和其他內(nèi)容(如預(yù)處理)分別放在若干個(gè)源文件中,再由若干源文件組成一個(gè)C程序。這樣可以分別編寫、分別編譯,提高調(diào)度效率。一個(gè)源文件可以為多個(gè)C程序公用。(3)C程序的執(zhí)行從main函數(shù)開始,調(diào)用其他函數(shù)后流程返回到main函數(shù),在main函數(shù)中結(jié)束整個(gè)程序的運(yùn)行,main函數(shù)是系統(tǒng)定義的。(4)所有函數(shù)都是平
4、行的,即在定義函數(shù)時(shí)是互相獨(dú)立的,一個(gè)函數(shù)并不從屬于另一個(gè)函數(shù),即函數(shù)不能嵌套定義(這和其他的高級(jí)語(yǔ)言可能不同)。函數(shù)間可以互相調(diào)用,但不能調(diào)用main函數(shù)。(5)從用戶使用的角度看,函數(shù)有兩種;標(biāo)準(zhǔn)函數(shù),即庫(kù)函數(shù)。這是由系統(tǒng)提供的,用戶不必自己定義這些函數(shù),可以直接使用它們。應(yīng)該說明,不同的C系統(tǒng)提供的庫(kù)函數(shù)的數(shù)量和功能不同,當(dāng)然有一些基本的函數(shù)是相同的。用戶自己定義的函數(shù),用戶自己編寫的用以解決特定問題。(6)從函數(shù)的形式看,函數(shù)分兩類:無參函數(shù)。如例6.1中printstar( )和 print_message( )就是無參函數(shù)。在調(diào)用無參函數(shù)時(shí),主調(diào)函數(shù)并不將數(shù)據(jù)傳送給被調(diào)用函數(shù),一般
5、用來執(zhí)行指定的一組操作,printstar( )函數(shù)的作用是輸出18個(gè)星號(hào)。無參函數(shù)可以帶回或不帶回函數(shù)值。有參函數(shù)。在調(diào)用函數(shù)時(shí),在主調(diào)函數(shù)和被調(diào)用函數(shù)之間有數(shù)據(jù)傳遞。也就是說,主調(diào)函數(shù)可以將數(shù)據(jù)傳給被調(diào)用函數(shù)使用,被調(diào)用函數(shù)中的數(shù)據(jù)也可以帶回來供主調(diào)函數(shù)使用。6.1.2 C語(yǔ)言程序結(jié)構(gòu) 函數(shù)是構(gòu)成C語(yǔ)言程序的基本功能模塊,它完成一項(xiàng)相對(duì)獨(dú)立的任務(wù)。一個(gè)C語(yǔ)言程序是若干函數(shù)構(gòu)成的,在構(gòu)成C程序的諸多函數(shù)中有而且只有一個(gè)主函數(shù)。函數(shù)是程序的最小組成單位。 所有函數(shù)之間的關(guān)系是平行的,沒有從屬的概念。函數(shù)的平行關(guān)系使得函數(shù)的編寫相對(duì)獨(dú)立,便于模塊化程序設(shè)計(jì)的實(shí)現(xiàn)。C程序的執(zhí)行總是從主函數(shù)開始,又
6、從主函數(shù)結(jié)束,其他函數(shù)只有通過調(diào)用關(guān)系發(fā)生作用。 6.1.4 函數(shù)的分類1從用戶角度分從用戶角度,函數(shù)可分為以下兩類。(1)庫(kù)函數(shù)(2)自定義函數(shù) 定義函數(shù); 聲明函數(shù); 調(diào)用函數(shù)。具體使用方法將在本章中詳細(xì)介紹。2從函數(shù)形式分從函數(shù)形式角度,函數(shù)可分為以下兩類。(1)無參函數(shù),函數(shù)不帶參數(shù)。(2)有參函數(shù),函數(shù)帶有至少一個(gè)參數(shù)。3從函數(shù)的返回值分從函數(shù)是否有返回值,函數(shù)可分為以下兩類。(1)有值函數(shù),調(diào)用該函數(shù)后可以得到返回值。(2)無值函數(shù),調(diào)用該函數(shù)后沒有返回值。無值函數(shù)類似于其他高級(jí)語(yǔ)言中的過程。6.2 函數(shù)的定義 函數(shù)由兩部分構(gòu)成:函數(shù)頭和函數(shù)體。 函數(shù)頭給出函數(shù)相關(guān)信息(類似“黑盒
7、子”中的入口和出口),而函數(shù)體具體實(shí)現(xiàn)函數(shù)的功能。6.2.1 函數(shù)的定義形式函數(shù)定義的一般形式是: 類型標(biāo)識(shí)符 函數(shù)名(形式參數(shù)表列)形式參數(shù)類型說明 數(shù)據(jù)描述部分 算法實(shí)現(xiàn)部分 前兩行是函數(shù)頭。形式參數(shù)(又簡(jiǎn)稱形參)表列和形式參數(shù)類型說明部分體現(xiàn)的是一個(gè)函數(shù)的入口參數(shù)的個(gè)數(shù)及其類型。 類型標(biāo)識(shí)符說明了函數(shù)返回值的類型,也簡(jiǎn)稱函數(shù)類型。 函數(shù)體用一對(duì)花括號(hào)括起來。函數(shù)體中不僅可以使用數(shù)據(jù)描述部分描述的變量,而且還可以使用形式參數(shù)。 例6.1 函數(shù)定義示例。float max(x, y)float x, y; float temp; if (xy) temp=x; else temp=y; re
8、turn (temp);6.2.2 函數(shù)的返回值 在函數(shù)定義時(shí)需要描述函數(shù)類型,但沒有給出函數(shù)如何得到返回值。調(diào)用有值函數(shù)時(shí),要求被調(diào)函數(shù)返回?cái)?shù)據(jù)給主調(diào)函數(shù),返回的數(shù)據(jù)稱為函數(shù)返回值,簡(jiǎn)稱函數(shù)值。得到函數(shù)返回值的方法是使用return語(yǔ)句。 return語(yǔ)句的功能有3個(gè)。(1)返回一個(gè)值給主調(diào)函數(shù)。(2)釋放在函數(shù)的執(zhí)行過程中分配的所有內(nèi)存空間。(3)結(jié)束被調(diào)函數(shù)的運(yùn)行,將流程控制權(quán)交給主調(diào)函數(shù)。return語(yǔ)句使用的一般形式為:return(表達(dá)式) return語(yǔ)句應(yīng)書寫在函數(shù)體的算法實(shí)現(xiàn)部分,圓括號(hào)可以省略。6.2.3 形參和返回值的設(shè)定 編寫函數(shù)時(shí),應(yīng)分析該函數(shù)中哪些量是函數(shù)的已知量,
9、那些是函數(shù)需要得到的結(jié)果。設(shè)計(jì)時(shí)將已知數(shù)據(jù)作為函數(shù)的形參,已知數(shù)據(jù)有幾個(gè),形參就有幾個(gè)。未知數(shù)據(jù)正是函數(shù)需要得到的結(jié)果。除需要分析已知和未知外,還需要確定已知和未知的數(shù)據(jù)類型,從而完成對(duì)函數(shù)頭的設(shè)計(jì)。 6.3 函數(shù)的調(diào)用 當(dāng)函數(shù)被調(diào)用時(shí),函數(shù)對(duì)應(yīng)的程序代碼才開始執(zhí)行,才能實(shí)現(xiàn)相應(yīng)的函數(shù)功能。6.3.1 對(duì)被調(diào)用函數(shù)的聲明 對(duì)被調(diào)用函數(shù)的聲明有兩種方式:外部聲明和內(nèi)部聲明。在主調(diào)函數(shù)內(nèi)對(duì)被調(diào)函數(shù)所作的聲明稱為內(nèi)部聲明,也稱為局部聲明;在函數(shù)外進(jìn)行的函數(shù)聲明稱為外部聲明,如果聲明在程序最前端,外部聲明又稱為全局聲明。 內(nèi)部聲明過的函數(shù)只能在聲明它的主調(diào)函數(shù)內(nèi)調(diào)用。外部聲明過的函數(shù),從聲明處到本程序
10、文件結(jié)束都可以被調(diào)用。內(nèi)部聲明應(yīng)放在主調(diào)函數(shù)的數(shù)據(jù)描述部分,外部聲明可以出現(xiàn)在程序中任何函數(shù)外。對(duì)被調(diào)用函數(shù)的聲明具體形式為:函數(shù)類型 函數(shù)名( );例6.5 函數(shù)聲明示例。main() int m; float c; float sum();/*在主函數(shù)main()內(nèi)對(duì)被調(diào)函數(shù)sum()作局部聲明,*/ scanf(%d,&m); /*只能在主函數(shù)內(nèi)調(diào)用聲明過的函數(shù)max()*/ c=sum(m); printf(c=%fn,c);float sum(int n) /*功能是計(jì)算數(shù)列1/2,2/3,3/5,5/8的前n項(xiàng)之和*/ float a,b,t,s; int k; a=1,b=2;s
11、=0.5; for(k=2;k=n;k+) t=a,a=b,b=a+t; s=s+a/b; return (s);6.3.2 函數(shù)調(diào)用的一般形式1函數(shù)調(diào)用的一般形式函數(shù)名(實(shí)際參數(shù)表列) 實(shí)際參數(shù)表列是函數(shù)入口參數(shù)的實(shí)際值。如例6.5中的csum(m)中的m就是有確定值的實(shí)際參數(shù),sum(m)是對(duì)函數(shù)的調(diào)用,調(diào)用結(jié)束后得到返回值賦值給變量c。2形式參數(shù)和實(shí)際參數(shù) 有參函數(shù)在調(diào)用時(shí),主調(diào)函數(shù)和被調(diào)函數(shù)之間有數(shù)據(jù)傳遞,主調(diào)函數(shù)傳遞數(shù)據(jù)給被調(diào)函數(shù)。主調(diào)函數(shù)傳遞來的數(shù)據(jù)稱為實(shí)際參數(shù),簡(jiǎn)稱實(shí)參。函數(shù)定義時(shí)形式參數(shù)僅僅是數(shù)據(jù)的抽象代表,沒有具體值,稱為形參。 (1)形式參數(shù) 定義函數(shù)時(shí),函數(shù)名后的參數(shù)稱作
12、形式參數(shù),簡(jiǎn)稱形參。 在定義函數(shù)時(shí),系統(tǒng)并不給形參分配存儲(chǔ)單元,當(dāng)然形參也沒有具體的數(shù)值,所以稱它是形參,也叫作虛參。 形參在函數(shù)調(diào)用時(shí),系統(tǒng)暫時(shí)給它分配存儲(chǔ)單元,以便存儲(chǔ)調(diào)用函數(shù)時(shí)傳來的實(shí)參。一旦函數(shù)結(jié)束運(yùn)行,系統(tǒng)馬上釋放相應(yīng)的存儲(chǔ)單元。(2)實(shí)際參數(shù) 在調(diào)用函數(shù)時(shí),函數(shù)名后的參數(shù)稱作實(shí)際參數(shù),簡(jiǎn)稱實(shí)參。 調(diào)用函數(shù)時(shí),實(shí)參有確定的值,所以稱它是實(shí)際參數(shù)。它可以是變量、常量、表達(dá)式等任意“確定的值”。(3)實(shí)參和形參之間的關(guān)系 實(shí)參的個(gè)數(shù)、類型應(yīng)該和形參的個(gè)數(shù)、類型一致。調(diào)用函數(shù)時(shí),系統(tǒng)給形參分配存儲(chǔ)單元,并且把實(shí)參的數(shù)值傳遞給形參。 實(shí)參和形參分別屬于主調(diào)函數(shù)和被調(diào)函數(shù),具有不同的內(nèi)存單元。
13、所以,在函數(shù)調(diào)用時(shí)形參發(fā)生改變,不會(huì)影響到實(shí)參。3實(shí)參和形參的結(jié)合方式 C語(yǔ)言中實(shí)參和形參的結(jié)合采取的是“單向值傳遞”方式,只有實(shí)參傳遞參數(shù)給形參,形參不回傳參數(shù)給實(shí)參。下面用例6.7講述實(shí)參和形參的具體結(jié)合方式。例6.7 實(shí)參和形參的結(jié)合方式示例。main( ) float a,b,sum; float add(); scanf(%f,%f,&a,&b); sum=add(a,b); printf(sum=%fn,sum);float add( x, y) float x,y; float z; z=x+y; return(z); 程序從主函數(shù)開始執(zhí)行,首先輸入a,b的數(shù)值(假如輸入3,5)
14、,接下來調(diào)用函數(shù)add(a,b)。具體調(diào)用過程如下。(1)給形參x,y分配內(nèi)存空間。(2)將實(shí)參b的值傳遞給形參y,a的值傳遞給形參x,于是y的值為5,x的值為3。(3)執(zhí)行函數(shù)體。 給函數(shù)體內(nèi)的變量分配存儲(chǔ)空間。即給z分配存儲(chǔ)空間。 執(zhí)行算法實(shí)現(xiàn)部分,得到z的值為8。 執(zhí)行return語(yǔ)句,完成以下功能。 將返回值返回主調(diào)函數(shù),即將z的值返回給main()。 釋放函數(shù)調(diào)用過程中分配的所有內(nèi)存空間,即釋放x,y,z的內(nèi)存空間。 結(jié)束函數(shù)調(diào)用,將流程控制權(quán)交給主調(diào)函數(shù)。調(diào)用結(jié)束后繼續(xù)執(zhí)行main()函數(shù)直至結(jié)束。函數(shù)調(diào)用前后實(shí)參、形參的變化情況如圖6.4所示。圖6.4 例6.7實(shí)參和形參變化示意
15、圖6.3.3 函數(shù)調(diào)用的具體形式 有些函數(shù)有返回值,有些沒有返回值,這兩種函數(shù)的調(diào)用形式不同。1有值函數(shù)的調(diào)用形式(1)函數(shù)調(diào)用作為表達(dá)式的一部分。即函數(shù)返回值參與表達(dá)式的運(yùn)算。(2)作為函數(shù)參數(shù)。即函數(shù)返回值又作為另一個(gè)函數(shù)的實(shí)參。2無值函數(shù)的調(diào)用形式 無值函數(shù)調(diào)用是作為獨(dú)立的函數(shù)調(diào)用語(yǔ)句出現(xiàn)的語(yǔ)句,其功能類似于一個(gè)過程。(1)實(shí)參的類型應(yīng)和形參的類型匹配。(2)實(shí)參和形參的結(jié)合方向是自右向左的。(3)實(shí)參的個(gè)數(shù)和形參應(yīng)該一致。(4)實(shí)參可以是任意能夠代表“確定的值”的內(nèi)容。(5)有值函數(shù)才可以參于表達(dá)式的運(yùn)算。 6.4 函數(shù)的嵌套及遞歸調(diào)用6.4.1 函數(shù)的嵌套調(diào)用 嵌套調(diào)用指的是在函數(shù)的
16、調(diào)用過程中又出現(xiàn)了另外一種函數(shù)調(diào)用,稱為函數(shù)的嵌套調(diào)用。 例6.8 函數(shù)嵌套示例。 以下程序的功能是計(jì)算x2sinx在區(qū)間0,5的定積分。程序由3個(gè)函數(shù)構(gòu)成,分別是主函數(shù)main()、函數(shù)f1()、函數(shù)f2()。main()調(diào)用函數(shù)f2(),在函數(shù)f2()的執(zhí)行過程中又調(diào)用了函數(shù)f1(), main()嵌套調(diào)用了函數(shù)f1()。圖6.5 例6.10函數(shù)嵌套調(diào)用過程#include math.h main() float f2(); float s=0, h=0.00005,x; for(x=0;xy) return x; else return y;main() float m,a=34.2,1
17、00,12.3,50,67,65,78,98,89,-20; int k; m=a0; for(k=1;k10;k+) m=max(m,ak); printf(.2fn,m);程序運(yùn)行的結(jié)果為:100.00 6.5.2 數(shù)組名作函數(shù)的參數(shù) 數(shù)組名代表數(shù)組的首地址,在數(shù)組名作為函數(shù)的參數(shù)時(shí),形參和實(shí)參都應(yīng)該是數(shù)組名。在函數(shù)調(diào)用時(shí),實(shí)參給形參傳遞的數(shù)據(jù)是實(shí)參數(shù)組的首地址,即實(shí)參數(shù)組和形參數(shù)組完全等同,是存放在同一存儲(chǔ)空間的同一個(gè)數(shù)組,形參數(shù)組和實(shí)參數(shù)組共享存儲(chǔ)單元。如果在函數(shù)調(diào)用過程中形參數(shù)組的內(nèi)容被修改了,實(shí)際上也是修改了實(shí)參數(shù)組的內(nèi)容。例6.11 編寫函數(shù)實(shí)現(xiàn)數(shù)組的逆序存放。程序如下。void
18、 change(x)int x; temp=x0;x0=x1;x1=temp;main() void change(); int a2=12,24; printf(before:a0=d,a1=dn,a0,a1); change(a); printf(after:a0=d,a1=dn,a0,a1);程序運(yùn)行的結(jié)果為:before:a0=12,a1=24after:a0=24,a1=12 顯然,用數(shù)組名作函數(shù)的參數(shù),才能真正實(shí)現(xiàn)兩個(gè)數(shù)據(jù)的交換。因?yàn)椋瑪?shù)組名作函數(shù)的形參和實(shí)參時(shí),調(diào)用函數(shù)把實(shí)參數(shù)組的首地址傳遞給形參數(shù)組,這樣兩個(gè)數(shù)組共享存儲(chǔ)單元,在函數(shù)調(diào)用時(shí)對(duì)形參數(shù)組元素值的交換,實(shí)質(zhì)上也是對(duì)實(shí)參
19、數(shù)組元素值的交換。用數(shù)組名作為函數(shù)參數(shù)應(yīng)注意以下幾點(diǎn)。 (1)數(shù)組名作函數(shù)參數(shù)時(shí),可省略數(shù)組的長(zhǎng)度。 (2)形參數(shù)組可以和實(shí)參數(shù)組同名。 (3)實(shí)參數(shù)組應(yīng)足夠大,即實(shí)參數(shù)組提供的內(nèi)存空間應(yīng)大于或等于形參數(shù)組需要的內(nèi)存空間。 (4)數(shù)組名作函數(shù)參數(shù)時(shí),應(yīng)將數(shù)組的長(zhǎng)度也作為函數(shù)的參數(shù),這樣編寫的函數(shù)具備通用性。例6.12 編寫函數(shù)用“起泡法”排序?!捌鹋莘ā钡幕舅枷胧菍?duì)N個(gè)數(shù)構(gòu)成的序列兩兩比較求出最大值。假設(shè)有5個(gè)數(shù)8,3,9,4,1,存儲(chǔ)到a數(shù)組中,采用“起泡法”從大到小排序的過程如下。(1)對(duì)5個(gè)數(shù)兩兩比較,如果相臨的兩個(gè)數(shù)不是從小到大排列的,則交換使之變?yōu)閺男〉酱笈帕校容^結(jié)束后最大值在序
20、列底部,于是得到序列(3,8,4,1,9)。(2)對(duì)前個(gè)數(shù)兩兩比較得到序列(3,4,1,8,9)。(3)對(duì)前3個(gè)數(shù)兩兩比較得到序列(3,1,4,8,9)。(4)對(duì)前2個(gè)數(shù)兩兩比較得到序列(1,3,4,8,9)。排序工作結(jié)束。從分析編寫程序如下。#define N 10main() void sort(); int aN,i; for(i=0;iN;i+) scanf(d,&ai); sort(a,N); for(i=0;iN;i+) printf(8d,ai); printf(n); sort(a,5); for(i=0;i0;i-) for(j=0;jarrayj+1) t=arrayj;
21、arrayj=arrayj+1; arrayj+1=t; 運(yùn)行程序,輸入:123 456 -123 -456 1 23 5885 34 101 10則輸出:-456 -123 1 10 23 34 101 123 456 5885-456 -123 1 10 236.6 變量的作用域6.6.1 局部變量 在一個(gè)函數(shù)內(nèi)定義的變量稱為局部變量。局部變量的作用范圍是定義它的函數(shù)。 關(guān)于局部變量的作用域需要說明以下幾點(diǎn)。(1)主函數(shù)中定義的變量也只能在主函數(shù)中使用,不能在其他函數(shù)中使用。 (2)形參屬于被調(diào)函數(shù)的局部變量,實(shí)參屬于主調(diào)函數(shù)的局部變量。(3)允許在不同的函數(shù)中使用相同的變量名,它們代表不
22、同的對(duì)象,分配不同的單元,互不干擾。(4)在復(fù)合語(yǔ)句中也可定義變量,其作用域只在本復(fù)合語(yǔ)句范圍內(nèi)。6.6.2 全局變量 函數(shù)外定義的變量稱作全局變量。全局變量可以被定義它的文件中的所有函數(shù)使用。全局變量的作用范圍是從定義變量的位置開始到它所在源文件的結(jié)束。6.7 變量的存儲(chǔ)方式 C語(yǔ)言中的變量不僅有類型屬性,而且還有存儲(chǔ)類別的屬性。 完整的變量定義應(yīng)該確定它的兩種屬性:存儲(chǔ)類型和數(shù)據(jù)類型。變量定義的完整形式為:存儲(chǔ)類型 類型說明符 變量名表列; C語(yǔ)言中,變量有4種存儲(chǔ)類型,分別為自動(dòng)類型、靜態(tài)類型、外部類型和寄存器類型。 變量在計(jì)算機(jī)內(nèi)存的存儲(chǔ)情況分為靜態(tài)存儲(chǔ)和動(dòng)態(tài)存儲(chǔ)兩種。6.7.1 自動(dòng)
23、存儲(chǔ)類型 關(guān)鍵字auto表示變量是自動(dòng)存儲(chǔ)類型。 自動(dòng)存儲(chǔ)類型的變量具有動(dòng)態(tài)性。自動(dòng)存儲(chǔ)類型變量的作用范圍僅局限于定義它的函數(shù)。自動(dòng)存儲(chǔ)類型變量的存儲(chǔ)單元分配在動(dòng)態(tài)數(shù)據(jù)區(qū)。 6.7.2 寄存器存儲(chǔ)類型 關(guān)鍵字register表示變量是寄存器存儲(chǔ)類型。例如,register int a,b; 表示定義變量a,b是整型并且是寄存器存儲(chǔ)類型。 寄存器型變量具有動(dòng)態(tài)性。寄存器存儲(chǔ)類型變量的作用范圍也是僅局限于定義它的函數(shù)。 6.7.3 外部存儲(chǔ)類型關(guān)鍵字extern表示變量是外部存儲(chǔ)類型。例如,extern double x,y; 表示定義變量x,y是雙精度浮點(diǎn)型并且是外部存儲(chǔ)類型。 外部存儲(chǔ)類型變量
24、具有靜態(tài)性。外部存儲(chǔ)類型變量定義在函數(shù)外部,它的作用域?yàn)閺淖兞康亩x處開始,到本程序文件的末尾。 6.7.4 靜態(tài)存儲(chǔ)類型 關(guān)鍵字static表示變量是靜態(tài)存儲(chǔ)類型。例如,static double x,y; 表示定義變量x,y是雙精度浮點(diǎn)型并且是靜態(tài)存儲(chǔ)類型。 靜態(tài)存儲(chǔ)類型變量具有靜態(tài)性。靜態(tài)存儲(chǔ)類型變量可以定義在函數(shù)內(nèi)部,也可以定義在函數(shù)外部。在整個(gè)程序運(yùn)行期間,靜態(tài)型變量都占據(jù)存儲(chǔ)單元。 68 內(nèi)部函數(shù)和外部函數(shù) 同一個(gè)源程序文件中的函數(shù)之間是可以互相調(diào)用的,不同源程序文件中的函數(shù)之間也是可以互相調(diào)用的,根據(jù)需要我們也可以指定函數(shù)不能被其他文件調(diào)用。根據(jù)函數(shù)能否被其他源程序文件調(diào)用,將函
25、數(shù)分為內(nèi)部函數(shù)和外部函數(shù)。6.8.1內(nèi)部函數(shù) 如果一個(gè)函數(shù)只能被本文件中其他函數(shù)所調(diào)用,它稱為內(nèi)部函數(shù)。在定義內(nèi)部函數(shù)時(shí),在函數(shù)名和函數(shù)類型的前面加static。即 static類型標(biāo)識(shí)符 函數(shù)名(形參表)如 static int fun(int a,int b ) 內(nèi)部函數(shù)又稱靜態(tài)函數(shù)。使用內(nèi)部函數(shù),可以使函數(shù)只局限于所在文件,如果在不同的文件中有同名的內(nèi)部函數(shù),互不干擾。這樣不同的人可以分別編寫不同的函數(shù),而不必?fù)?dān)心所用函數(shù)是否會(huì)與其他文件中函數(shù)同名,通常把只能由同一文件使用的函數(shù)和外部變量放在一個(gè)文件中,在它們前面都冠以static使之局部化,其他文件不能引用。6.8.2外部函數(shù)(1)在
26、定義函數(shù)時(shí),如果在函數(shù)首部的最左端冠以關(guān)鍵字extern,則表示此函數(shù)是外部函數(shù),可供其他文件調(diào)用。如函數(shù)首部可以寫為extern int fun (int a,int b)這樣,函數(shù)fun 就可以為其他文件調(diào)用。C語(yǔ)言規(guī)定,如果在定義函數(shù)時(shí)省略extern,則隱含為外部函數(shù)。本書前面所用的函數(shù)都是外部函數(shù)。(2)在需要調(diào)用此函數(shù)的文件中,用extern聲明所用的函數(shù)是外部函數(shù)?!纠?.14】有一個(gè)字符串,內(nèi)有若干個(gè)字符,今輸入一個(gè)字符,要求程序?qū)⒆址性撟址麆h去。用外部函數(shù)實(shí)現(xiàn)。file1.c(文件1)main()extern enter_string ( char str 80);ext
27、ern delete_string (char str ,char ch);extern print_string (char str );/*以上3行聲明在本函數(shù)中將要調(diào)用的在其他文件中定義的3個(gè)函數(shù) char c;char str80;enter_strng(str);scanf(%c,&c);delete_string(str,c);print_string(str);file2.c(文件2)#includeenter_string(char str80) /*定義外部函數(shù)enter_srting*/gets(str); /*向字符數(shù)組輸入字符串*/file3.c(文件3)delete_
28、string(char str ,char ch) /*定義外部函數(shù)delete_string*/int i,j;for(i=j=0;stri!=0 ;i+)if(stri!=ch)strj+=stri;strj= 0 ; file4.c(文件4)print_string(char str ) /*定義外部函數(shù)print_string*/printf(%s ,str);運(yùn)行情況如下:abcdefgc (輸入str)c (輸入要?jiǎng)h去的字符)abdefg (輸出已刪去指定字符的字符串) 整個(gè)程序由4個(gè)文件組成。每個(gè)文件包含一個(gè)函數(shù)。主函數(shù)是主控函數(shù),除聲明部分外,由4個(gè)函數(shù)調(diào)用語(yǔ)句組成。其中sca
29、nf是庫(kù)函數(shù),另外3個(gè)是用戶自己定義的函數(shù)。函數(shù)delete_string的作用是根據(jù)給定的字符串和要?jiǎng)h除的字符ch,對(duì)字符串作刪除處理。算法是這樣的:對(duì)str數(shù)組的字符逐個(gè)檢查,如果不是被刪除的字符就將它存放在數(shù)組中,見圖6.21(設(shè)刪除空格)。從str0開始逐個(gè)檢查數(shù)組元素值是否等于指定要?jiǎng)h除的字符,若不是就留在數(shù)組中,若是就不保留。從圖中可以看到,應(yīng)該使str0賦給str0,str1str1,str2str2,str3str3,然后,str5str4,請(qǐng)讀者注意分析如何控制i和j的變化,以便使被刪除的字符不保留在原數(shù)組中。這個(gè)題目當(dāng)然可以設(shè)兩個(gè)數(shù)組,把不刪除的字符賦給新數(shù)組。但我們只用一
30、個(gè)數(shù)組,只把不被刪除的字符保留下來。由于I總是二于或等于j,因此最后保留下來的字符不會(huì)覆蓋未被檢測(cè)處理的字符。最后將結(jié)束符o也復(fù)制到被保留的字符后面。程序中3個(gè)函數(shù)都定義為外部函數(shù)。在main函數(shù)中用extern聲明在main函數(shù)中用到的enter_string、delete_string、print_string是在其他文件中定義的外部函數(shù)。通過此例可知:使用extern聲明就能夠在一個(gè)文件中調(diào)用其他文件中定義的函數(shù),或者說把該函數(shù)的作用域擴(kuò)展到本文件。Extern聲明的形式就是在函數(shù)原型基礎(chǔ)上加關(guān)鍵字extern(見本例main函數(shù)中的聲明形式)。由于函數(shù)在本質(zhì)上是外部的,在程序中經(jīng)常要調(diào)
31、用外部函數(shù),耿方便編程,C語(yǔ)言允許在聲明函數(shù)時(shí)省寫extern。例8.21程序main函數(shù)中對(duì)power函數(shù)的聲明就沒有用extern,但作用相同,一般都省寫extern,例如例8.22程序main函數(shù)中的第一個(gè)函數(shù)聲明可寫成 enter_string(char str80) 這就是我們多次用過的函數(shù)原型。由此可以進(jìn)一步理解函數(shù)原型的作用。用函數(shù)原型也能夠把函數(shù)的作用域擴(kuò)展到定義該函數(shù)的文件之外(不必使用extern)。只要在使用該函數(shù)的每一個(gè)文件中包含該函數(shù)的函數(shù)原型即可。函數(shù)原型通知編譯系統(tǒng):該函數(shù)在本文件中稍后定義,或在另一文件中定義。利用函數(shù)原型擴(kuò)展函數(shù)作用域最常見的例子是includ
32、e命令的應(yīng)用。在前面幾章中曾多次使用過include命令,并提到過:include命令所指定的“頭文件”中包含有調(diào)用庫(kù)函數(shù)時(shí)所需的信息。例如,在程序中需要調(diào)用sin函數(shù),但三角函數(shù)并不是由用戶在本文件中定義的,而是存放在數(shù)學(xué)函數(shù)庫(kù)中的。按以上的介紹,必須在本文件中寫出sin函數(shù)的原型,否則無法調(diào)用sin函數(shù)。Sin函數(shù)的原型是 double sin(double x)顯然,要求程序設(shè)計(jì)者在調(diào)用庫(kù)函數(shù)時(shí)先從手冊(cè)可查出所用的庫(kù)函數(shù)的原型,并在程序中一一寫出來是麻煩而困難的。為減少程序設(shè)計(jì)者的困難,在頭文件math.h中包括了所有數(shù)學(xué)函數(shù)的原型和其他有關(guān)信息,用戶只需用以下#include命令:#i
33、ncludemath.h這樣,在該文件中就能合法地調(diào)用各數(shù)學(xué)庫(kù)函數(shù)了。69 編譯預(yù)處理 ANSI C標(biāo)準(zhǔn)規(guī)定可以在C源程序中加入一些“預(yù)處理命令”(preprocessor directives),以改進(jìn)程序設(shè)計(jì)環(huán)境,提高編程效率。這些預(yù)處理命令是由ANSI C統(tǒng)一規(guī)定的,但是它不是C語(yǔ)言本身的組成部分,不能直接對(duì)它們進(jìn)行編譯(因?yàn)榫幾g程序不能識(shí)別它們。)必須在對(duì)程序進(jìn)行通常的編譯(包括詞法和語(yǔ)法分析、代碼生成、優(yōu)化等)之前,先對(duì)程序中這些特殊的命令進(jìn)行“預(yù)處理”,即根據(jù)預(yù)處理命令對(duì)程序作相應(yīng)的處理(例如,若程序中用define命令定義了一個(gè)符號(hào)常量A,則在預(yù)處理時(shí)將程序中所有的A都置換為指定
34、的字符串。若程序中用include命令包含一個(gè)文件“stdio.h”,則在預(yù)處理時(shí)將stdio.h文件中的實(shí)際內(nèi)容代替該命令)。 經(jīng)過預(yù)處理后程序不再包括預(yù)處理命令了,最后再由編譯程序?qū)︻A(yù)處理后的源程序進(jìn)行通常的編譯處理,得到可供執(zhí)行的目標(biāo)代碼。現(xiàn)在使用的許多C編譯系統(tǒng)都包括了預(yù)處理、編譯和連接等部分,在進(jìn)行編譯時(shí)一氣呵成。因此不少用戶誤認(rèn)為預(yù)處理命令是C語(yǔ)言的一部分,甚至以為它們是C語(yǔ)句,這是不對(duì)的。必須正確區(qū)別預(yù)處理命令和C語(yǔ)句、區(qū)別預(yù)處理和編譯,才能正確使用預(yù)處理命令。C語(yǔ)言與其他高級(jí)語(yǔ)言的一個(gè)重要區(qū)別是可以使用預(yù)處理命令和具有預(yù)處理的功能。C提供的預(yù)處理功能主要有以下三種:1.宏定義2
35、.文件包含3.條件編譯分別用宏定義命令、文件包含命令、條件編譯命令來實(shí)現(xiàn)。為了與一般C語(yǔ)句相區(qū)別,這些命令以符號(hào)“”開頭。6.8.1 宏定義1.不帶參數(shù)的宏定義 用一個(gè)指定的標(biāo)識(shí)符(即名子)來代表一個(gè)字符串,它的一般形式為define 標(biāo)識(shí)符 字符串 這就是已經(jīng)介紹過的定義符號(hào)常量。如:define PI 3.1415926 它的作用是指定用標(biāo)識(shí)符PI來代替“3.1415926”這個(gè)字符串,在編譯預(yù)處理時(shí),將程序中在該命令以后出現(xiàn)的所有的PI都用“3.1415926”代替。這種方法使用戶能以一個(gè)簡(jiǎn)單的名字代替一個(gè)長(zhǎng)的字符串,因此把這個(gè)標(biāo)識(shí)符(名字)稱為“宏名”,在預(yù)編譯時(shí)將宏名替換成字符串的過
36、程稱為“宏展開”。define是宏定義命令?!纠?.17】define PI 3.1415926main( ) float l,s,r,v;printf(input radius:);scanf(%f,&r);l2.0*PI*r;s=PI*r*r;v=4.0/3*PI*r*r*r;printf(i=%10.4fns=%10.4fnv=%10.4fn,l,s,v);運(yùn)行情況如下:input radius:4l=25.1328s=50.2655v=150.7966說明:(1)宏名一般習(xí)慣用大寫字母表示,以便與變量名相區(qū)別。但這并非規(guī)定,也可用小寫字母。(2)使用宏名代替一個(gè)字符串,可以減少程序中重
37、復(fù)寫某些字符串的工作量。例如,如果不定義PI代表3.1415926則在程序中要多處出現(xiàn)3.1415926,不僅麻煩,而且容易寫錯(cuò)(或敲錯(cuò)),用宏名代替,簡(jiǎn)單不易出錯(cuò),因?yàn)橛涀∫粋€(gè)宏名(它的名字往往用容易理解的單詞表示)要比記住一個(gè)無規(guī)律的字符串容易,而且在讀程序時(shí)能立即知道它的含義,當(dāng)需要改變某一個(gè)常量時(shí),可以只改變define命令行,一改全改。 例如,定義數(shù)組大小,可以用: define array_size 1000int arrayarray_size; 先指定array_size代表常量1000,因此數(shù)組array大小為1000,如果需要改變數(shù)組大小,只需改define行:define
38、 array_size 500使用宏定義,可以提高程序的通用性。(3)宏定義是用宏名代替一個(gè)字符串,也就是作簡(jiǎn)單的置換,不作正確性檢查。如果寫成#define PI 3.l459即把數(shù)字1寫成小寫字母l,預(yù)處理時(shí)也照樣代人,不管含義是否正確。也就是說預(yù)編譯時(shí)不作任何語(yǔ)示檢查。只有在編譯已被宏展開后的源程序時(shí)才會(huì)發(fā)現(xiàn)錯(cuò)誤并報(bào)錯(cuò)。(4)宏定義不是C語(yǔ)句,不必在行末加分號(hào)。如果加了分號(hào)則會(huì)連分號(hào)一起進(jìn)行置換。如:#define PI 3.1415926;area=PI*r*r;經(jīng)過宏展開后,該語(yǔ)句為area=3.1415926*r*r;顯然出現(xiàn)語(yǔ)法錯(cuò)誤。(5)#define命令出現(xiàn)在程序中函數(shù)的外面
39、,宏名的有效范圍為定義命令之后到本源文件結(jié)束。通常,#define命令寫在文件開頭,函數(shù)之前,作為文件一部分,在此文件范圍內(nèi)有效。(6)可以用#undef命令終止宏定義的作用域。例如:#define G 9.8 main( ) | G的有效范圍 #undef G f1( ) 由于#undef的作用,使G的作用范圍在#undef行處終止,因此在f1函數(shù)中,G不再代表9.8。這樣可以靈活控制宏定義的作用范圍。(7)在進(jìn)行宏定義時(shí),可以引用已定義的宏名,可以層層置換?!纠?.18】# define R 3.0# define PI 3.1415926# define L 2*PI*R# define
40、 S PI*R*Rmain( )printf(”L=%fnS=%fn”,L,S);運(yùn)行情況如下:L=18.849556S=28.274333經(jīng)過宏展開后,printf函數(shù)中的輸出項(xiàng)L被展開為2*3.1415926*3.0,S展開為3.1415926*3.0*3.0,printf函數(shù)調(diào)用語(yǔ)句展開為printf(”L=%fnS=%fn”,2*3.1415926*3.0,3.1415926*3.0*3.0);(8)對(duì)程序中用雙撇號(hào)括起來的字符串內(nèi)的字符,即使與宏名相同,也不進(jìn)行置換。如例9.2中的printf函數(shù)內(nèi)有兩個(gè)L字符,一個(gè)在雙撇號(hào)內(nèi),它不被宏置換,另一個(gè)在雙撇號(hào)外,被宏置換展開。(9)宏定
41、義是專門用于預(yù)處理命令的一個(gè)專用名詞,它與定義變量的含義不同,只作字符替換,不分配內(nèi)存空間。2.帶參數(shù)的宏定義 不是進(jìn)行簡(jiǎn)單的字符串替換,還要進(jìn)行參數(shù)替換。其定義的一般形式為 #define宏名(參數(shù)表)字符串 字符串中包含在括弧中所指定的參數(shù)。如: #define S(a,b) a*b area=S(3,2); 定義矩形面積S,a是b是邊長(zhǎng)。在程序中用了S(3,2),把3、2分別代替宏定義中的形式參數(shù)a、b,即用3*2代替S(3,2),因此賦值語(yǔ)句展開為 area=S(3,2); 對(duì)帶參的宏定義是這樣展開置換的:在程序中如果有帶實(shí)參的宏(如S(3,2),則按#define命令行中指定的字符串
42、從左到右進(jìn)行置換。如果串中包含宏中的形參(如a、b),則將程序語(yǔ)句中相應(yīng)的實(shí)參(可以是常量、變量或表達(dá)式)代替形參。如果宏定義中的字符串中的字符不是參數(shù)字符(如a*b中的*號(hào)),則保留。這樣就形成了置換的字符串,見圖6.22。 【例6.19】#define PI 3.1415926#define S(r) PI*r*rmain( )float a, area;a=3.6;area=S(a);printf(”r=%fnarea=%fn”,a,area);運(yùn)行結(jié)果如下:r=3.600000area=40.715038賦值語(yǔ)句“area=S(a)”;經(jīng)宏展開后為area=3.1415926*a*a;
43、說明:(1)對(duì)帶參數(shù)的宏的展開只是將語(yǔ)句中的宏名后面括號(hào)內(nèi)的實(shí)參字符串代替#define命令行中的形參。例9.3中語(yǔ)句中有S(a),在展開時(shí),找到#define命令行中的S(r),將S(a)中的實(shí)參a代替宏定義中的字符串“PI*r*r”中的形參r,得到PI*a*a。這是容易理解而且不會(huì)發(fā)生什么問題。但是,如果有以下語(yǔ)句:area=S(a+b);這時(shí)把實(shí)參a+b代替PI*r*r中的形參r,成為area=PI*a+b*a+b; 請(qǐng)注意在a+b外面沒有括弧,顯然這與程序設(shè)計(jì)得的原意不符。原意希望得到area=PI*(a+b)*(a+b); 為了得到這個(gè)結(jié)果,應(yīng)當(dāng)在定義時(shí),在字符串中的形式參數(shù)外面加一
44、個(gè)括弧。即#define S(r)PI*(r)*(r)在對(duì)S(a+b)進(jìn)行宏展開時(shí),將a+b代替r,就成了PI*(a+b)*(a+b)這就達(dá)到了目的。(2)在宏定義時(shí),在宏名與帶參數(shù)的括弧之間不應(yīng)加空格,否則將空格以后的字符都作為替代字符串的一部分。例如,如果有 #define S(r) PI*r*r 被認(rèn)為S是符號(hào)常量(不帶參的宏名),它代表字符串“(r)PI*r*r”。如果在語(yǔ)句中有 area=S(a); 則被展開為 area=(r) PI*r*r(a); 顯然不對(duì)了。 有些讀者容易把帶參數(shù)的宏和函數(shù)混淆。的確,它們之間有一定類似之處,在調(diào)用函數(shù)時(shí)也是在函數(shù)名后的括弧內(nèi)寫實(shí)參,也要求實(shí)參與
45、形參的數(shù)目相等。但是帶參的宏定義與函數(shù)是不同的。 主要有: (1)函數(shù)調(diào)用時(shí),先求出實(shí)參表達(dá)式的值,然后代入形參。而使用帶參的宏只是進(jìn)行簡(jiǎn)單的字符替換。例如上面的S(a+b),在宏開展時(shí)并不求a+b的值,而只將實(shí)參字符“a+b”代替形參r。(2)函數(shù)調(diào)用是在程序運(yùn)行時(shí)處理的,為形參分配臨時(shí)的內(nèi)存單元。而宏展開則是在編譯前進(jìn)行的,在展開時(shí)并不分配內(nèi)存單元,不進(jìn)行值的傳遞處理,也沒有“返回值”的概念。(3)對(duì)函數(shù)中的實(shí)參和形參都要定義類型,二者的類型要求一致,如不一致,應(yīng)進(jìn)行類型轉(zhuǎn)換。而宏不存在的類型問題,宏名無類型,它的參數(shù)也無類型,只是一個(gè)符號(hào)代表,展開時(shí)代入指定的字符串即可。宏定義時(shí),字符串
46、可以是任何類型的數(shù)據(jù)。 例如:#define CHARI CHINA (字符)#define a 3.6 (數(shù)值) CHARI和a不需要定義類型,它們不是變量,在程序中凡遇CHARI均以CHINA代之;凡遇a均以3.6代之,顯然不需定義類型。同樣,對(duì)帶參的宏。#define s(r) PI*r*r r也不是變量,如果在語(yǔ)句中有S(3.6),則展開后為PI*3.6*3.6,語(yǔ)句中并不出現(xiàn)r。當(dāng)然也不必定義r的類型。(4)調(diào)用函數(shù)只可得到一個(gè)返回值,而用宏可以設(shè)法得到幾個(gè)結(jié)果?!纠?.20】 #define PI 3.1415926 #define CIRCLE(R,L,S,V) L=2*PI*R
47、;S=PI*R*R;V=4.0/3.0*PI*R*R*R main( ) float r,l,s,v;scanf(%f,&r);CIRCLE(r,l,s,v);printf(r=%6.2f,s=%6.2f,v=%6.2fn,r,l,s,v);經(jīng)預(yù)編譯宏展開后的程序如下:main( ) float r,l,s,v;scanf(%f,&r);l=2*3.1415926*r;s=3.1415926*r*r;v=4.0/3.0*3.1415926*r*r*r;printf(r=%6.2f,l=%6.2f,s=%6.2f,v=%6.2fn,r,l,s,v);運(yùn)行情況如下:3.5r=3.50,1=21.9
48、9,s=38.48,v=179.59請(qǐng)注意,實(shí)參r的值已知,可以從宏帶回3個(gè)值(l,s,v)。其實(shí),只不過是字符代表而已,將字符r代表R,l代表L,s代表S,v代表V,而并未在宏展開時(shí)求出l、s、v的值。(5)使用宏次數(shù)多時(shí),宏展開后源程序長(zhǎng),因?yàn)槊空归_一次都使程序增長(zhǎng),而函數(shù)調(diào)用不使原程序變長(zhǎng)。(6)宏替換不占運(yùn)行時(shí)間,只占編譯時(shí)間,而函數(shù)調(diào)用則占運(yùn)行時(shí)間(分配單元、保留現(xiàn)場(chǎng)、值傳遞、返回)。 一般用宏來代表簡(jiǎn)短的表達(dá)式比較合適。有些問題,用宏和函數(shù)都可以。如:#define MAX(x,y) (x)(y)?(x) :(y)main( ) int a,b,c,d,t;t=MAX(a+b,c+
49、d);賦值語(yǔ)句展開后為t=(a+b)(c+d)?(a+b):(c+d); 注意:MAX不是函數(shù),這里只有一個(gè)main函數(shù),在main函數(shù)中就能求出t的值。 這個(gè)問題也可用函數(shù)來求:int max(int x,int y)return(xy?x:y);main( )int a,b,c,d,t;t=max(a+b,x+d); max是函數(shù),在main函數(shù)中調(diào)用max函數(shù)才能求出t的值。 請(qǐng)仔細(xì)分析以上兩種方法。 如果善于利用宏定義,可以實(shí)現(xiàn)程序的簡(jiǎn)化,如事先將程序中的“輸出格式”定義好,以減少在輸出語(yǔ)句中每次都要寫出具體的輸出格式的麻煩。【例6.21】#define PR printf#defin
50、e NL n#define D %d#define D1 D NL#define D2 D D NL#define D3 D D D NL#define D4 D D D D NL#define S %smain( ) int a,b,c,d;char string =CHINA;a=1;b=2;c=3;d=4;PR(D1,a);PR(D2,a,b);PR(D3,a,b,c);PR(D4,a,b,c,d);PR(S,string);運(yùn)行時(shí)輸出以下結(jié)果:1121231234CHINA程序中用PR代表printf。以NL代表執(zhí)行一次“換行”操作。以D代表輸出一個(gè)整型數(shù)據(jù)的格式符。以D1代表輸出完1
51、個(gè)整數(shù)后換行,D2代表輸出2個(gè)整數(shù)后換行,D3代表輸出3個(gè)整數(shù)后換行,D4代表輸出4個(gè)整數(shù)后換行。以S代表輸出一個(gè)字符串的格式符??梢钥吹?,程序中寫輸出語(yǔ)句就比較簡(jiǎn)單了,只要根據(jù)需要選擇已定義的輸出格式即可。連printf都可以簡(jiǎn)寫為PR。寫出各種輸入輸出的格式(例如實(shí)型、長(zhǎng)整型、十六進(jìn)制整數(shù)、八進(jìn)制整數(shù)、字符型等),把它們單獨(dú)編成一個(gè)文件,它相當(dāng)一個(gè)“格式庫(kù)”,用#include合令把它“包括”到自己所編的程序中,用戶就可以根據(jù)情況各取所需了。顯然在寫大程序時(shí),這樣做是很方便的。6.8.2 “文件包含”處理 所謂“文件包含”處理是指一個(gè)源文件可以將另外一個(gè)源文件的全部?jī)?nèi)容包含進(jìn)來。即將另外的
52、文件包含到本文件之中。C語(yǔ)言提供了#include命令用來實(shí)現(xiàn)“文件包含”的操作。其一般形式為#include”文件名”或#include 圖6.23表示“文件包含”的含意。圖6.23(a)為文件file1.c,它有一個(gè)#include命令,然后還有其他內(nèi)容(以A表示)。圖6.23(b)為另一文件file2.c,文件內(nèi)容以B表示。經(jīng)編譯預(yù)處理時(shí),要對(duì)#include命令進(jìn)行“文件包含”處理:將file2.c的全部?jī)?nèi)容復(fù)制插入到#include命令處,即file2.c被包含到file1.c中,得到圖6.23(c)所示的結(jié)果。在編譯中,將“包含”以后的file1.c(即圖6.23(c)所示)作為一
53、個(gè)源文件單位進(jìn)行編譯?!拔募泵钍呛苡杏玫?,它可以節(jié)省程序設(shè)計(jì)人員的重復(fù)勞動(dòng)。例如,某一單位的人員往往使用一組固定的符號(hào)常量(如g=9.81,pi=3.1415926,e=2.718,c=),可以把這些宏定義命令組成一個(gè)文件,然后各人都可以用#include命令將這些符號(hào)常量包含到自己所寫的源文件中。這樣每個(gè)人就可以不必重復(fù)定義這些符號(hào)常量。相當(dāng)于工業(yè)上的標(biāo)準(zhǔn)零件,拿來就用?!纠?.22】可以將例6.21程序改為:(1)文件format.h#define PR printf#define NL n#define D %d#define D1 D NL#define D2 D D NL#d
54、efine D3 D D D NL#define D4 D D D D NL#define S %s(2)文件file1.c#include format.hmain( ) int a,b,c,d;char string =CHINA;a=1;b=2;c=3;d=4;PR(D1,a);PR(D2,a,b);PR(D3,a,b,c);PR(D4,a,b,c,d);PR(S,string); 注意:在編譯時(shí)并不是作為兩個(gè)文件進(jìn)行連接的,而是作為一個(gè)源程序編譯,得到一個(gè)目標(biāo)(.obj)文件。因此被包含的文件也應(yīng)該是源文件而不應(yīng)該是目標(biāo)文件。 這種常用在文件頭部的被包含的文件為“標(biāo)題文件”或“頭部文件
55、”,常以“.h”為后綴(h為head(頭)的縮寫),如“format.h”文件。當(dāng)然不用“.h”為后綴,而用“.c”為后綴或者沒有后綴也是可以的,但用“.h”作后綴更能表示此文件的性質(zhì)。 如果需要修改一些常數(shù),不必修改每個(gè)程序,只需修改一個(gè)文件(頭部文件)即可。但是應(yīng)當(dāng)注意,被包含文件修改后,凡包含此文件的所有文件都要全部重新編譯。 頭文件除了可以包括函數(shù)原型和宏定義外,也可以包括結(jié)構(gòu)體類型定義(見第11章)和全局變量定義等。說明:(1)一個(gè)#include命令只能指定一個(gè)被包含文件,如果要包含n個(gè)文件,要用n個(gè)#include命令。(2)如果文件1包含文件2,而文件2中要用到文件3的內(nèi)容,則
56、可在文件1中用兩個(gè)include命令分別包含文件2和文件3,而且文件3應(yīng)出現(xiàn)在文件2之前,即在file1.c中定義:#include “file3.h”#include “file2.h” 這樣,file1和file2都可以用 file3的內(nèi)容。在file2中不必再用#include了(以上是假設(shè)file2.h在本程序中只被file1.c包含,而不出現(xiàn)在其他場(chǎng)合)。(3)在一個(gè)被包含文件中又可以包含另一個(gè)被包含文件,即文件包含是可以嵌套的。例如,上面的問題也可以這樣處理,見圖6.24。它的作用與圖6.25所示相同。(4)#include 命令中,文件名可以用雙撇號(hào)或尖括號(hào)括起來,如可以在fil
57、e1.c中用#include 或#include “flie2.h” 都是合法的。二者的區(qū)別是用尖括?。葱问剑r(shí),系統(tǒng)到存放C庫(kù)函數(shù)頭文件所在的目錄中尋找要包含的文件,這稱為標(biāo)準(zhǔn)方式。用雙撇號(hào)(即“file2.h”形式)時(shí),系統(tǒng)先在用戶當(dāng)前目錄中尋找要包含的文件,若找不到,再按標(biāo)準(zhǔn)方式查找(即再按尖括號(hào)的方式查找)。一般說,如果為調(diào)用庫(kù)函數(shù)而用#include命令來包含相關(guān)的頭文件,則用尖括號(hào),以節(jié)省查找時(shí)間。如果要包含的是用戶自己編寫的文件(這種文件一般都在當(dāng)前目錄中),一般用雙撇號(hào),若文件不在當(dāng)前目錄中,雙撇號(hào)內(nèi)可給出文件路徑。(5)被包含文件(file2.h)與其所在的文件(即用#in
58、clude命令的源文件file1.c),在預(yù)編譯后已成為同一文件(而不是兩個(gè)文件)。因此,如果file2.h中有全局靜態(tài)變量,它也在file1.c文件中有效,不必用extern聲明。6.8.3 條件編譯 一般情況下,源程序中所有的行都參加編譯。但是有時(shí)希望對(duì)其中一部分內(nèi)容只在滿足一定條件才進(jìn)行編譯,也就是對(duì)一部分內(nèi)容指定編譯的條件,這就是“條件編譯”。有時(shí),希望當(dāng)滿足某條件時(shí)對(duì)一組語(yǔ)句進(jìn)行編譯,而當(dāng)條件不滿足時(shí)則編譯另一組語(yǔ)句。條件編譯命令有以下幾種形式:(1)#ifdef 標(biāo)識(shí)符程序段1#else程序段2#endif 它的作用是當(dāng)所指定的標(biāo)識(shí)符已經(jīng)被define命令定義過,則在程序編譯階段只
59、編譯程序段1,否則編譯程序段2。其中#else部分可以沒有,即#ifdef 標(biāo)識(shí)符程序段1#endif 這里的“程序段”可以是語(yǔ)句組,也可以是命令行。這種條件編譯對(duì)于提高C源程序的通用性是很有好處的。如果一個(gè)C源程序在不同計(jì)算機(jī)系統(tǒng)上運(yùn)行,而不同的計(jì)算機(jī)又有一定的差異(例如,有的機(jī)器以16位(2個(gè)字節(jié))來存放一個(gè)整數(shù),而有的則以32位存放一個(gè)整數(shù)),這樣往往需要對(duì)源程序作必要的修改,這就降低了程序的通用性??梢杂靡韵碌臈l件編譯來處理:#ifdef CMPUTER_A#define INTEGRE_SIZE 16#else#define INTEGER_SIZE 32#endif即如果COMPU
60、TER_A在前面已被定義過,則編譯下面的命令行:#define INTEGER_SIZE 16否則,編譯下面的命令行:#define INTEGER_SIZE 32如果在這組條件編譯命令之前曾出現(xiàn)以下命令行:#define COMPUTER_A 0或?qū)OMPUTER_A定義為任何字符串,甚至是#define COMPUTER_A 則預(yù)編譯后程序中的INTEGER_SIZE都用16代替,否則都用32代替。 這樣,源程序可以不必作任何修改就可以用于不同類型的計(jì)算機(jī)系統(tǒng)。當(dāng)然以上介紹的只是一種簡(jiǎn)單的情況,讀者可以根據(jù)此思路設(shè)計(jì)出其他的條件編譯。 例如,在調(diào)試程序時(shí),常常希望輸出一些所需的信息,而在
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 齊魯工業(yè)大學(xué)《C++面向?qū)ο蠹夹g(shù)》2022-2023學(xué)年期末試卷
- 公司人力資源實(shí)施計(jì)劃
- 2024年車輛使用權(quán)益無償讓渡協(xié)議
- 免稅品質(zhì)量管理工作計(jì)劃
- 健康教育年初計(jì)劃
- 短期勞務(wù)合作協(xié)議樣本2024年
- 2024年果酒區(qū)域代理銷售協(xié)議條款
- 2024年中介服務(wù)協(xié)議常見特征精解
- 選礦裝備及耐磨備件智能化技術(shù)改造項(xiàng)目可行性研究報(bào)告模板-立項(xiàng)備案
- 新能源汽車技術(shù)電動(dòng)汽車與充電設(shè)施考核試卷
- 青少年數(shù)獨(dú)智力運(yùn)動(dòng)會(huì)U12組數(shù)獨(dú)賽前集訓(xùn)題
- 醫(yī)院健康教育培訓(xùn)課件
- GH/T 1419-2023野生食用菌保育促繁技術(shù)規(guī)程灰肉紅菇
- 鼻咽癌的放射治療課件
- 明孝端皇后九龍九鳳冠
- 注塑車間規(guī)劃方案
- 營(yíng)養(yǎng)不良五階梯治療
- 標(biāo)本運(yùn)送培訓(xùn)課件
- 護(hù)士與醫(yī)生的合作與溝通
- GB 42295-2022電動(dòng)自行車電氣安全要求
- 產(chǎn)品系統(tǒng)設(shè)計(jì)開發(fā) 課件 第4、5章 產(chǎn)品系統(tǒng)設(shè)計(jì)類型、產(chǎn)品系統(tǒng)設(shè)計(jì)開發(fā)綜合案例
評(píng)論
0/150
提交評(píng)論