《C語(yǔ)言程序設(shè)計(jì)》課件第04章_第1頁(yè)
《C語(yǔ)言程序設(shè)計(jì)》課件第04章_第2頁(yè)
《C語(yǔ)言程序設(shè)計(jì)》課件第04章_第3頁(yè)
《C語(yǔ)言程序設(shè)計(jì)》課件第04章_第4頁(yè)
《C語(yǔ)言程序設(shè)計(jì)》課件第04章_第5頁(yè)
已閱讀5頁(yè),還剩102頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第4章函數(shù)與編譯預(yù)處理語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.1函數(shù)的概念及其分類(lèi)4.2函數(shù)的定義4.3函數(shù)的聲明與調(diào)用4.4變量的作用域和存儲(chǔ)類(lèi)別4.5內(nèi)部函數(shù)與外部函數(shù)4.6遞歸函數(shù)4.7編譯預(yù)處理4.8綜合范例4.9本章小結(jié)4.10問(wèn)與答內(nèi)容簡(jiǎn)介4.1函數(shù)的概念及其分類(lèi)語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C在第一章中已經(jīng)介紹過(guò),C源程序是由函數(shù)組成的。雖然在前面各章的程序中都只有一個(gè)主函數(shù)main(),但真正實(shí)用的程序往往由大量的小函數(shù)而不是由少量大函數(shù)構(gòu)成的,即所謂“小函數(shù)構(gòu)成大程序”。這樣的好處是讓各部分相對(duì)簡(jiǎn)單獨(dú)立,并且任務(wù)單一。

所謂函數(shù)就是一個(gè)具有一定功能、且相對(duì)獨(dú)立的、可供其它程序調(diào)用的程序模塊。它是C源程序的基本模塊,通過(guò)對(duì)函數(shù)模塊的調(diào)用實(shí)現(xiàn)特定的功能。C語(yǔ)言中的函數(shù)相當(dāng)于其它高級(jí)語(yǔ)言的子程序(或過(guò)程)。4.1函數(shù)的概念及其分類(lèi)語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理CC語(yǔ)言不僅提供了極為豐富的庫(kù)函數(shù)(如TurboC,MSC都提供了三百多個(gè)庫(kù)函數(shù)),還允許用戶(hù)建立自己定義的函數(shù)。用戶(hù)可把自己的算法編成一個(gè)個(gè)相對(duì)獨(dú)立的函數(shù)模塊,然后采取調(diào)用的方法來(lái)使用函數(shù)??梢哉f(shuō)C程序的全部工作都是由各式各樣的函數(shù)完成的,所以也有人把C語(yǔ)言稱(chēng)為函數(shù)式語(yǔ)言。由于采用了函數(shù)模塊式的結(jié)構(gòu),C語(yǔ)言易于實(shí)現(xiàn)結(jié)構(gòu)化程序設(shè)計(jì)。使程序的層次結(jié)構(gòu)清晰,便于程序的編寫(xiě)、閱讀、調(diào)試。4.1函數(shù)的概念及其分類(lèi)語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C在C語(yǔ)言中可從不同的角度對(duì)函數(shù)分類(lèi)。1.從函數(shù)定義的角度看,函數(shù)可分為庫(kù)函數(shù)和用戶(hù)定義函數(shù)兩種。1)庫(kù)函數(shù)由C系統(tǒng)提供,用戶(hù)無(wú)須定義,只需在程序前用#include宏命令包含要調(diào)用的函數(shù)原型的頭文件,即可在程序中直接調(diào)用。在前面各章的例題中反復(fù)用到printf

、scanf

、gets、puts等函數(shù)均屬此類(lèi)。2)用戶(hù)自定義函數(shù)自定義函數(shù)是由程序設(shè)計(jì)者根據(jù)問(wèn)題的需要自己定義的。

語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C2.C語(yǔ)言的函數(shù)兼有其它語(yǔ)言中的函數(shù)和過(guò)程兩種功能,從這個(gè)角度看,又可把函數(shù)分為有返回值函數(shù)和無(wú)返回值函數(shù)兩種。(1)有返回值函數(shù)此類(lèi)函數(shù)被調(diào)用執(zhí)行完成之后,將向調(diào)用者返回一個(gè)執(zhí)行結(jié)果,稱(chēng)為函數(shù)返回值。

(2)無(wú)返回值函數(shù)此類(lèi)函數(shù)用于完成某項(xiàng)特定的處理任務(wù),執(zhí)行完成之后不向調(diào)用者返回函數(shù)值。4.1函數(shù)的概念及其分類(lèi)語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C3.從主調(diào)函數(shù)和被調(diào)函數(shù)之間數(shù)據(jù)傳送的角度看又可分為無(wú)參函數(shù)和有參函數(shù)兩種。(1)無(wú)參函數(shù)函數(shù)定義、函數(shù)聲明及函數(shù)調(diào)用中均不帶參數(shù)。主調(diào)函數(shù)和被調(diào)函數(shù)之間不進(jìn)行參數(shù)傳送。此類(lèi)函數(shù)通常用來(lái)完成一些特定的功能。(2)有參函數(shù)也稱(chēng)為帶參函數(shù)。在函數(shù)定義及函數(shù)聲明時(shí)都有參數(shù),定義時(shí)指定的參數(shù)稱(chēng)為形式參數(shù)(簡(jiǎn)稱(chēng)為形參)。在函數(shù)調(diào)用時(shí)也必須給出參數(shù)值或有值的表達(dá)式,調(diào)用時(shí)給出的參數(shù)稱(chēng)為實(shí)際參數(shù)(簡(jiǎn)稱(chēng)為實(shí)參)。進(jìn)行函數(shù)調(diào)用時(shí),主調(diào)函數(shù)將把實(shí)參的值傳送給形參,供被調(diào)函數(shù)使用。4.1函數(shù)的概念及其分類(lèi)4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C函數(shù)定義的一般形式1.現(xiàn)代定義形式:[存儲(chǔ)類(lèi)別][返回值類(lèi)型]函數(shù)名稱(chēng)([類(lèi)型標(biāo)識(shí)1形參名稱(chēng)1[,類(lèi)型標(biāo)識(shí)2形參名稱(chēng)2…..]]){[變量定義;…]語(yǔ)句1;……語(yǔ)句n;}

4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C函數(shù)定義的一般形式2.傳統(tǒng)的定義形式[存儲(chǔ)類(lèi)別][返回值類(lèi)型]函數(shù)名([形參名稱(chēng)1[,形參名稱(chēng)2…..]])[類(lèi)型標(biāo)識(shí)1形參名稱(chēng)1;[類(lèi)型標(biāo)識(shí)2形參名稱(chēng)2;….]]{[變量定義;…]語(yǔ)句1;……語(yǔ)句n;}

4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C【例4-1】編寫(xiě)程序求解任意兩個(gè)數(shù)的最大公約數(shù),并輸出結(jié)果。int

Maxcd(int

X,intY)/*利用輾轉(zhuǎn)相除法求整數(shù)X與Y的最大公約數(shù)函數(shù)*/{intR;R=X;

if(X<Y){X=Y;Y=R;}

while(R=X%Y){X=Y;Y=R;}returnY;}voidTellMessage(){printf("Inputvaluesintoa&b,please!");}Ex4_1.c演示4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理Cvoidmain(){int

a,b,R;

TellMessage();/*調(diào)用TellMessage()函數(shù),提示輸入數(shù)據(jù)*/

scanf("%d%d",&a,&b);R=Maxcd(a,b);/*調(diào)用Maxcd(a,b)函數(shù),求出a和b最大公約數(shù)并賦給R*/

printf("%d和%d的最大公約數(shù)是%d\n",a,b,R);}

程序說(shuō)明:以上Maxcd(int

X,intY)函數(shù)的功能是專(zhuān)門(mén)求解兩數(shù)的最大公約數(shù)。其中的X和Y是形式參數(shù)。該函數(shù)有返回值(就是X和Y的最大公約數(shù)),返回值是整型,因此也被稱(chēng)之為整型函數(shù)。TellMessage()函數(shù)的功能只是在屏幕上給出提示信息:Inputvaluesintoa&b,please!它既是一個(gè)無(wú)參的,也是一個(gè)無(wú)返回值的函數(shù)。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C關(guān)于函數(shù)定義的幾點(diǎn)說(shuō)明:(1)[存儲(chǔ)類(lèi)別]指明函數(shù)的有效范圍,此類(lèi)型標(biāo)識(shí)符只有兩種:static和extern。static規(guī)定了當(dāng)前定義的函數(shù),只能被定義它的那個(gè)文件中的其它函數(shù)調(diào)用,不能被其它文件中的函數(shù)調(diào)用,因此,這類(lèi)函數(shù)又叫作內(nèi)部函數(shù);extern說(shuō)明了當(dāng)前定義的函數(shù)可供所有文件中的函數(shù)調(diào)用,因而又稱(chēng)為外部函數(shù)。默認(rèn)(不明確指定)的是extern,即外部函數(shù)。(2)[返回值類(lèi)型]規(guī)定函數(shù)有無(wú)返回值或規(guī)定函數(shù)執(zhí)行結(jié)束時(shí),返回值的數(shù)據(jù)類(lèi)型,默認(rèn)的是整型(int)。如果函數(shù)不需要或沒(méi)有返回值,應(yīng)當(dāng)明確用void說(shuō)明。4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C(3)函數(shù)名稱(chēng)必須是合法的標(biāo)識(shí)符,其與變量命名規(guī)則相同。正規(guī)的程序設(shè)計(jì),變量、函數(shù)與符號(hào)常量的取名最好要見(jiàn)名知義,這樣利于提高程序的可讀性和可維護(hù)性。良好的命名習(xí)慣是優(yōu)秀程序員的標(biāo)志之一。(4)[存儲(chǔ)類(lèi)別][返回值類(lèi)型]函數(shù)名稱(chēng)([類(lèi)型標(biāo)識(shí)1形參名稱(chēng)1[,類(lèi)型標(biāo)識(shí)2形參名稱(chēng)2…..]])或者[存儲(chǔ)類(lèi)別][返回值類(lèi)型]函數(shù)名([形參名稱(chēng)1[,形參名稱(chēng)2…..]])[類(lèi)型標(biāo)識(shí)1形參名稱(chēng)1;[類(lèi)型標(biāo)識(shí)2形參名稱(chēng)2;….]]被稱(chēng)之為函數(shù)頭,緊接其后的一對(duì)花括號(hào)”{“和“}”及其中的語(yǔ)句稱(chēng)之為函數(shù)體。4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C(5)[]中的說(shuō)明符是可有可無(wú)的,例如[形參名稱(chēng)1[,形參名稱(chēng)2…..]]表示函數(shù)定義中的形式參數(shù)個(gè)數(shù)≥0。(6)函數(shù)體中表示函數(shù)結(jié)束的三種情況:㈠函數(shù)有返回值時(shí),則函數(shù)體中表示函數(shù)結(jié)束的返回語(yǔ)句形式是:return表達(dá)式;或return(表達(dá)式);㈡函數(shù)無(wú)返回值時(shí),則函數(shù)體中函數(shù)結(jié)束的返回語(yǔ)句形式是:return;㈢函數(shù)無(wú)返回值,且函數(shù)體中最后一條語(yǔ)句就表示函數(shù)的結(jié)束,則函數(shù)體中無(wú)需返回語(yǔ)句return;㈣函數(shù)體中可以有多條返回語(yǔ)句。但是,只能有其中的一個(gè)返回語(yǔ)句可以被執(zhí)行。4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C(7)有返回值的函數(shù),對(duì)它的調(diào)用可以出現(xiàn)在表達(dá)式中,對(duì)無(wú)返回值的函數(shù)調(diào)用只能作為一條單獨(dú)的語(yǔ)句。(8)函數(shù)調(diào)用語(yǔ)句中每個(gè)實(shí)參的數(shù)據(jù)類(lèi)型,必須保證與函數(shù)定義中的每個(gè)形參一一對(duì)應(yīng)相容或相同。(9)函數(shù)有返回值時(shí),如果其返回值的類(lèi)型與定義函數(shù)指定的數(shù)據(jù)類(lèi)型不一致,則系統(tǒng)會(huì)自動(dòng)轉(zhuǎn)換為定義函數(shù)指定的數(shù)據(jù)類(lèi)型。10)函數(shù)定義不能嵌套,即函數(shù)體中不能再包含任何函數(shù)的定義。4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C【例4-2】編寫(xiě)函數(shù)實(shí)現(xiàn)從N個(gè)整數(shù)中找出其中的素?cái)?shù),并且按照從小到大的順序輸出這些素?cái)?shù)以及這些素?cái)?shù)的平均值(平均值保留兩位小數(shù))。#include"stdio.h"#defineNum10#defineTrue1#defineFalse0/*以下是利用選擇排序法把數(shù)組中N個(gè)元素的值從小到大排序的函數(shù)*/voidNsort(intA[],intN){intI,J,K,T;for(I=0;I<N-1;I++){K=I;for(J=I+1;J<N;J++)if(A[K]>A[J])K=J;if(I!=K){T=A[I];A[I]=A[K];A[K]=T;}}}4.2函數(shù)的定義Ex4_2.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理CvoidAcceptINum(intA[],intN);/*為了使得主函數(shù)main能夠調(diào)用它而對(duì)其進(jìn)行聲明*/voidmain(){int

I,IArray[Num],Pn=0;floatfAverage=0;

printf("Input10NumbersintoArray,please!");

AcceptINum(IArray,Num);/*調(diào)用AcceptINum函數(shù)接收鍵盤(pán)輸入Num個(gè)數(shù)*/Nsort(IArray,Num);/*調(diào)用Nsort

函數(shù),對(duì)IArray

中的元素值進(jìn)行排序*/printf("ThesortedNumbersAre:\n");/*從小到大輸出各個(gè)數(shù)*/for(I=0;I<Num;I++)printf(I==Num-1?"%d\n":"%d,",IArray[I]);4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理Cprintf("\nThePrimesare:");for(I=0;I<Num;I++)/*從小到大輸出各個(gè)素?cái)?shù)及素?cái)?shù)平均值*/if(IsPrime(IArray[I])){printf("%d,",IArray[I]);fAverrage+=IArray[I];Pn++;}if(Pn!=0)printf("The

AverrageofPrimesis:%.2f\n",fAverrage/Pn);elseprintf("ThereisnoneofPrimes!\n");}/*以下是接收鍵盤(pán)輸入N個(gè)整數(shù)函數(shù)*/voidAcceptINum(intA[],intN){intK;

for(K=0;K<N;K++)

scanf("%d",&A[K]);return;/*因?yàn)樵摵瘮?shù)沒(méi)有返回值,所以此處的

return可以刪去*/}4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C/*以下是判斷一個(gè)整數(shù)是否是素?cái)?shù),若是素?cái)?shù),1返回給調(diào)用者,否則0返回給調(diào)用者*/int

IsPrime(X)intX;{intI,N;

for(I=2;I<=X/2;I++)if(X%I==0)returnFalsereturnTrue;}4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C程序說(shuō)明:以上的例子中①函數(shù)Nsort(intA[],intN)沒(méi)有返回值,因此可以不需要返回語(yǔ)句。②函數(shù)IsPrime(intX)雖然只有一個(gè)返回值,但可以有兩個(gè)返回語(yǔ)句。③函數(shù)AcceptINum(int

A[],intN)雖然沒(méi)有返回值,也可以用return語(yǔ)句表示函數(shù)結(jié)束(當(dāng)然此處的return語(yǔ)句也可以不需要)。④本例中用到了一維數(shù)組(數(shù)組的概念以及數(shù)組的應(yīng)用要到下一章才學(xué)到),為了便于理解,在此對(duì)本例中用到的數(shù)組,作簡(jiǎn)單的說(shuō)明:這里主函數(shù)main中定義的數(shù)組IArray[Num],其中的Num是一個(gè)符號(hào)常量10,即Num與整數(shù)10是等價(jià)的。元素的引用形式是數(shù)組名稱(chēng)[整型表達(dá)式],并且整型表達(dá)式的值是0~Num-1。因此,可以把數(shù)組元素看成是一個(gè)普通的變量。

4.2函數(shù)的定義語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C一個(gè)函數(shù)能被另一個(gè)函數(shù)調(diào)用需要以下幾個(gè)條件:(1)該函數(shù)必須已經(jīng)存在,無(wú)論是庫(kù)函數(shù)還是用戶(hù)自定義函數(shù)。(2)調(diào)用系統(tǒng)提供的庫(kù)函數(shù)時(shí),與被調(diào)用函數(shù)相關(guān)的頭文件,必須在源程序的開(kāi)頭用#include命令把它包含進(jìn)來(lái)。(3)用戶(hù)自定義函數(shù),在被調(diào)用之前,需要對(duì)自定義函數(shù)進(jìn)行聲明。

4.3函數(shù)的聲明與調(diào)用

4.3.1函數(shù)能被使用的條件語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C被調(diào)用的用戶(hù)自定義函數(shù),同時(shí)具備下列情況,需要對(duì)它進(jìn)行聲明。(1)與調(diào)用它的主調(diào)函數(shù)在同一文件中,(2)它的定義位置在調(diào)用它的那個(gè)主調(diào)函數(shù)之后,(3)它的返回值類(lèi)型不是整型,也不是字符型的;(4)在調(diào)用它的那個(gè)主調(diào)函數(shù)之前沒(méi)有被聲明4.3函數(shù)的聲明與調(diào)用

4.3.2函數(shù)聲明的場(chǎng)合語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C(1)[返回值類(lèi)型]函數(shù)名稱(chēng)([類(lèi)型標(biāo)識(shí)1形參名稱(chēng)1[,類(lèi)型標(biāo)識(shí)2形參名稱(chēng)2…..]]);或者:(2)[返回值類(lèi)型]函數(shù)名稱(chēng)([類(lèi)型標(biāo)識(shí)1[,類(lèi)型標(biāo)識(shí)2…..]]);最簡(jiǎn)單的方法就是把被調(diào)用函數(shù)的函數(shù)頭,復(fù)制到調(diào)用它的主調(diào)函數(shù)之前,然后再加一個(gè)分號(hào);就一切搞定了!其實(shí)函數(shù)聲明格式中的形參部分只需給出每個(gè)參數(shù)的數(shù)據(jù)類(lèi)型就可以了,無(wú)須給出形參的名稱(chēng),即使給出形參的名稱(chēng),其名稱(chēng)可以隨意,只要名稱(chēng)符合標(biāo)識(shí)符命名規(guī)則即可。4.3函數(shù)的聲明與調(diào)用

4.3.3函數(shù)聲明的格式語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C(1)在所有函數(shù)的最前面;如【例4-3】所示。(2)在所有函數(shù)的外部,在調(diào)用它的主調(diào)函數(shù)之前;如【例4-4】所示的f2,f3,f4函數(shù)的聲明?!纠?-4】(3)在調(diào)用它的主調(diào)函數(shù)內(nèi)部,此時(shí),可以把它看作定義變量那樣對(duì)待;如【例4-4】所示的f1函數(shù)的聲明和【例4-5】所示的f1,f2,f3,f4函數(shù)的聲明

4.3函數(shù)的聲明與調(diào)用

4.3.4函數(shù)聲明的位置語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C【例4-3】/*在程序的最前面聲明*/floatf1(floatx,floaty);floatf2(float,float);floatf3(floata,floatb);floatf4(float,float);main(){floata=78.68,b=36.43;

clrscr();

printf("sum=%f\n",f1(a,b));}floatf1(floatx,floaty){return(f2(x,y)*f3(x,y));}floatf2(floats,floatr){returns+r;}floatf3(floatu,floatv){return(u-v)*f4(u,v);}floatf4(floatu,floatv){returnu/v;}4.3函數(shù)的聲明與調(diào)用Ex4_3.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.3函數(shù)的聲明與調(diào)用【例4-4】main()/*在調(diào)用函數(shù)的前面聲明*/{floatf1(floatx,floaty);floata=78.68,b=36.43;

clrscr();printf("sum=%f\n",f1(a,b));}floatf2(float,float),f3(floata,floatb),f4(float,float);floatf1(floatx,floaty){return(f2(x,y)*f3(x,y));}floatf2(floats,floatr){returns+r;}floatf3(floatu,floatv){return(u-v)*f4(u,v);}floatf4(floatu,floatv){returnu/v;}Ex4_4.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C【例4-5】main()/*在main函數(shù)中的聲明*/{floatf1(floatx,floaty),f2(float,float),f3(floata,floatb),f4(float,float);floata=78.68,b=36.43;

clrscr();

printf("sum=%f\n",f1(a,b));}floatf1(floatx,floaty){return(f2(x,y)*f3(x,y));}floatf2(floats,floatr){returns+r;}floatf3(floatu,floatv){return(u-v)*f4(u,v);}floatf4(floatu,floatv){returnu/v;}4.3函數(shù)的聲明與調(diào)用Ex4_5.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C注意!以下三種情況可以省略對(duì)被調(diào)函數(shù)的聲明:(1)如果被調(diào)函數(shù)的定義出現(xiàn)在主調(diào)函數(shù)之前,則可以省略聲明。如【例4-2】的Nsort函數(shù)。(2)如果在所有函數(shù)定義之前,在函數(shù)的外部已作了函數(shù)聲明,則在以后的各主調(diào)函數(shù)中,可以不必對(duì)被調(diào)函數(shù)作聲明。如【例4-3】的f1、f2、f3、f4函數(shù)。(3)如果函數(shù)類(lèi)型為整型或字符型,則在主調(diào)函數(shù)中可以不要聲明。如【例4-2】中的IsPrime(X)函數(shù)。但使用這種方法時(shí),系統(tǒng)無(wú)法對(duì)參數(shù)的類(lèi)型作檢查,因此在調(diào)用時(shí)若參數(shù)使用不當(dāng),編譯時(shí)也不報(bào)錯(cuò)。為了程序的安全,建議都加以聲明為好。4.3函數(shù)的聲明與調(diào)用

4.3.4函數(shù)聲明的位置語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C一個(gè)函數(shù)被定義之后,不被別的函數(shù)使用,即使功能再?gòu)?qiáng)大,也發(fā)揮不了任何作用。通過(guò)函數(shù)調(diào)用語(yǔ)句來(lái)達(dá)到使用函數(shù)的目的。函數(shù)調(diào)用語(yǔ)句有以下兩種形式:(1)無(wú)返回值的函數(shù)調(diào)用語(yǔ)句格式:函數(shù)名稱(chēng)([實(shí)參列表]);(2)有返回值的函數(shù)調(diào)用語(yǔ)句格式:變量名=函數(shù)名稱(chēng)([實(shí)參列表]);此處的變量名的數(shù)據(jù)類(lèi)型必須與函數(shù)返回值的數(shù)據(jù)類(lèi)型相容。無(wú)論是上述哪種調(diào)用語(yǔ)句,都會(huì)去執(zhí)行被調(diào)用函數(shù)體中的語(yǔ)句,函數(shù)執(zhí)行完畢,會(huì)返回到函數(shù)調(diào)用語(yǔ)句之后,繼續(xù)執(zhí)行調(diào)用函數(shù)語(yǔ)句之后的其它語(yǔ)句。注意:前面說(shuō)過(guò)函數(shù)不可以嵌套定義。但是函數(shù)可以嵌套調(diào)用。

4.3函數(shù)的聲明與調(diào)用

4.3.5函數(shù)的調(diào)用、參數(shù)與返回值語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C【例4-6】編寫(xiě)程序求5個(gè)整數(shù)中的最大數(shù),并輸出。floatmax(intX,floatY)/*求兩數(shù)中最大值的函數(shù)*/{if(X>=Y)returnX;elsereturnY;}voidmain(){int

a,b,c,d,e,Maxvalue;

printf("Intputvaluesintoa,b,c,d&e,please!\n");

scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);

Maxvalue=max(a,max(max(max(b,c),d),e));/*函數(shù)max多重嵌套調(diào)用自己*//*也可改成maxvalue=max(max(max(a,b),max(c,d)),e);*/

printf("Maxvalue=%d\n",Maxvalue); }4.3函數(shù)的聲明與調(diào)用

4.3.5函數(shù)的調(diào)用、參數(shù)與返回值Ex4_6.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C注意!(1)函數(shù)返回值的類(lèi)型取決于函數(shù)定義中的函數(shù)名稱(chēng)之前的數(shù)據(jù)類(lèi)型,與return后表達(dá)式值的類(lèi)型無(wú)關(guān)。如果return后表達(dá)式值的類(lèi)型與函數(shù)的定義中函數(shù)名稱(chēng)之前的數(shù)據(jù)類(lèi)型不一致,系統(tǒng)會(huì)自動(dòng)轉(zhuǎn)換。例如函數(shù)max返回值的類(lèi)型是實(shí)型,函數(shù)體中的if(X>=Y)returnX;elsereturnY;語(yǔ)句,不論返回值表達(dá)式是X還是Y,它返回值的類(lèi)型總是實(shí)型。(2)函數(shù)調(diào)用語(yǔ)句中的實(shí)參數(shù)量與形參數(shù)量必須相等,與形參相對(duì)應(yīng)的實(shí)參數(shù)據(jù)類(lèi)型必須相容。4.3函數(shù)的聲明與調(diào)用

4.3.5函數(shù)的調(diào)用、參數(shù)與返回值語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C函數(shù)調(diào)用中,如果函數(shù)有參數(shù),則系統(tǒng)會(huì)按照函數(shù)形式參數(shù)的個(gè)數(shù)和對(duì)應(yīng)的數(shù)據(jù)類(lèi)型,自動(dòng)申請(qǐng)內(nèi)存區(qū)域,用于存放函數(shù)調(diào)用語(yǔ)句中對(duì)應(yīng)的實(shí)際參數(shù)的值。被調(diào)用的函數(shù)中形參的值變化與否,都不影響函數(shù)調(diào)用語(yǔ)句中實(shí)際參數(shù)的值。即函數(shù)的參數(shù)值傳遞是單向的,在函數(shù)調(diào)用時(shí),系統(tǒng)只是把實(shí)際參數(shù)的值復(fù)制到對(duì)應(yīng)形式參數(shù)的內(nèi)存區(qū)域。

4.3函數(shù)的聲明與調(diào)用

4.3.6函數(shù)的傳值方式語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C【例4-7】voidExchange(float

X,floatY){floatT;T=X;X=Y;Y=T;printf("Innerexchange:X=%3.0f,Y=%3.0f\n",X,Y);}main(){floatX=5,Y=8;printf("Beforeexchange:X=%3.0f,Y=%3.0f\n",X,Y);Exchange(X,Y);printf("Afterexchange:X=%3.0f,Y=%3.0f\n",X,Y);

}4.3函數(shù)的聲明與調(diào)用

4.3.6函數(shù)的傳值方式Ex4_7.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C程序說(shuō)明:【例4-7】中主函數(shù)main執(zhí)行到調(diào)用語(yǔ)句Exchange(X,Y);時(shí),此后的程序執(zhí)行過(guò)程如下:1、系統(tǒng)會(huì)把此處實(shí)參X、Y的值5和8分別賦值給函數(shù)Exchange中的形參變量X和Y,2、然后,開(kāi)始執(zhí)行Exchange函數(shù),3、在Exchange函數(shù)中,通過(guò)T=X;X=Y;Y=T;語(yǔ)句序列的執(zhí)行,實(shí)現(xiàn)了Exchange函數(shù)中對(duì)形參X和Y中值的交換,4、因此,執(zhí)行到printf("Innerexchange:X=%3.0f,Y=%3.0f\n”,X,Y);語(yǔ)句時(shí),其輸出結(jié)果是:Innerexchange:X=8,Y=5,說(shuō)明在Exchange函數(shù)體內(nèi),確實(shí)實(shí)現(xiàn)了X與Y的交換。5、Exchange函數(shù)執(zhí)行完成,返回到主函數(shù)main中調(diào)用Exchange函數(shù)語(yǔ)句之后,繼續(xù)執(zhí)行下一條語(yǔ)句:printf("Afterexchange:X=%3.0f,Y=%3.0f\n",X,Y);6、該語(yǔ)句輸出的結(jié)果是:Afterexchange:X=5,Y=84.3函數(shù)的聲明與調(diào)用

4.3.6函數(shù)的傳值方式語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C局部變量:所謂局部變量,就是在函數(shù)或復(fù)合語(yǔ)句內(nèi)定義的變量。函數(shù)體內(nèi)定義的變量,其有效范圍只局限于定義它的函數(shù)體內(nèi)。也就是只能在定義它的那個(gè)函數(shù)體內(nèi)可以使用它,在函數(shù)體外部,它就無(wú)效了。同理,復(fù)合語(yǔ)句中定義的變量,只能在定義它的那個(gè)復(fù)合語(yǔ)句中使用它,出了復(fù)合語(yǔ)句,就不能引用它了!此外,形參只限于它所在的函數(shù)內(nèi)部使用,因此形參是局部變量。全局變量:所謂全局變量,就是在函數(shù)外面定義的變量,因此又稱(chēng)之為外部變量。它的有效范圍是從它的定義之點(diǎn)起到定義它的那個(gè)文件結(jié)束。與它在同一個(gè)文件中的所有函數(shù)都可以引用它。4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.1變量的作用域語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C【例4-8】程序及其運(yùn)行的結(jié)果intX=5;/*此處X是全局變量,在它后面的函數(shù)都可以引用它*/intAdd(intX,intY){intZ;/*此函數(shù)中的X,Y,Z均是局部變量*/Z=X+Y;returnZ

;}intSubX(intY){returnY-X;}/*此函數(shù)中的Y是局部變量,X是全局變量*/voidmain(){intX=8,Y=20,Z;/*此函數(shù)中的X,Y,Z均是局部變量*/Z=Add(X,Y);

printf(“%d+%d=%d\n”,X,Y,Z);Z=SubX(Y);printf(“%d-5=%d\n”,Y,Z);}

4.4變量的作用域和存儲(chǔ)類(lèi)別Ex4_8.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C全局變量與局部變量的關(guān)系,如同中央政府頒布的國(guó)家法令與地方政府頒布的地方法令之間的關(guān)系。如果某省政府沒(méi)有頒布治安處罰條例,那么在該省內(nèi)處理治安事件的依據(jù),引用的就是國(guó)家治安處罰條例;如果該省政府頒布了該省的治安處罰條例,那么在該省內(nèi)處理治安事件的依據(jù),如果沒(méi)特別說(shuō)明,引用的就是指該省的治安處罰條例。就是說(shuō)局部變量掩蓋了同名的全局變量。

4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.1變量的作用域語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C變量的存儲(chǔ)類(lèi)別是指變量的存儲(chǔ)屬性,即變量被分配在內(nèi)存的那種區(qū)域內(nèi)。計(jì)算機(jī)內(nèi)存一般被劃分成系統(tǒng)區(qū)和用戶(hù)區(qū)兩種,系統(tǒng)區(qū)是指系統(tǒng)程序駐留和工作的區(qū)域;用戶(hù)區(qū)就是用戶(hù)程序駐留和工作的場(chǎng)所。為了便于操作系統(tǒng)為程序分配存儲(chǔ)區(qū)域和控制用戶(hù)程序的運(yùn)行,把程序分成執(zhí)行命令的操作(代碼)和被操作的數(shù)據(jù)兩部分進(jìn)行存儲(chǔ)。其中數(shù)據(jù)區(qū)又被分成靜態(tài)存儲(chǔ)區(qū)和動(dòng)態(tài)存儲(chǔ)區(qū)。因此用于存放用戶(hù)程序的用戶(hù)區(qū),被對(duì)應(yīng)地分成代碼區(qū)和靜態(tài)存儲(chǔ)區(qū)和動(dòng)態(tài)存儲(chǔ)區(qū)。一般來(lái)說(shuō),內(nèi)存的動(dòng)態(tài)區(qū)用于存放程序的局部變量,靜態(tài)區(qū)用于存放程序的靜態(tài)局部變量和全局變量。4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別系統(tǒng)區(qū)用戶(hù)區(qū)················動(dòng)態(tài)存儲(chǔ)區(qū)靜態(tài)存儲(chǔ)區(qū)數(shù)據(jù)區(qū)程序區(qū)代碼區(qū)語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C變量的存儲(chǔ)類(lèi)別有auto、register、static和exturn四種。auto是局部變量的默認(rèn)存儲(chǔ)類(lèi)別。register指定為變量分配寄存器,而不是內(nèi)存區(qū)域,就是使用CPU的寄存器存放變量的值。auto、register只能用于定義局部變量。exturn是外部(全局)變量的默認(rèn)存儲(chǔ)類(lèi)別。static既可以用于定義局部變量,也可以用于定義全局變量。static用于定義局部變量時(shí),出了定義該變量的那個(gè)程序塊(函數(shù)體或復(fù)合語(yǔ)句)其變量值仍然保留在內(nèi)存中;如果被定義的變量未賦初值,系統(tǒng)自動(dòng)予以置0。static用于定義全局變量時(shí),其變量只能被定義它的那個(gè)文件中引用,其它文件不可使用它。此時(shí)定義的變量也稱(chēng)之為內(nèi)部變量。4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4.2.1靜態(tài)存儲(chǔ)的局部變量運(yùn)用舉例【例4-9】分別求出1、2、3、4和5的階乘并輸出。其程序及其運(yùn)行結(jié)果如下:voidfact(intN){staticlongs=1;/*s是靜態(tài)存儲(chǔ)的局部變量*/s=s*N;

printf("%d!=%ld\n",N,s);}voidmain(){intk;

for(k=1;k<=5;k++)fact(k);}4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別Ex4_9.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4.2.2動(dòng)態(tài)存儲(chǔ)的局部變量運(yùn)用舉例【例4-10】把上述程序函數(shù)fact()中的staticlongs=1;語(yǔ)句,改成longs=1;則程序及其運(yùn)行結(jié)果如下:voidfact(intN){longs=1;/*s是動(dòng)態(tài)存儲(chǔ)的局部變量*/s=s*N;

printf("%d!=%ld\n",N,s);}voidmain(){intk;

for(k=1;k<=5;k++)fact(k);}4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別Ex4_10.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C在TurboC系統(tǒng)大型程序開(kāi)發(fā)中傳統(tǒng)的做法有兩種辦法:一是在主函數(shù)文件(即main函數(shù)所在的文件)的首部,利用文件包含宏命令#include指定要包含的其它各個(gè)程序文件。然后編譯連接主函數(shù)文件,生成可執(zhí)行的程序文件(擴(kuò)展名為.EXE)。二是編寫(xiě)一個(gè)工程文件(其擴(kuò)展名為.prj),在工程文件中指定組成工程文件的各個(gè)程序文件位置與名稱(chēng),然后編譯連接這個(gè)工程文件,生成可執(zhí)行的程序文件(擴(kuò)展名為.EXE);具體方法請(qǐng)看下面的例子。4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C【例4-11】把計(jì)算AN的函數(shù)fpow存放在一個(gè)文件(如Ex4_11_1.c)中,供其它函數(shù)調(diào)用。調(diào)用它的程序存放在另一個(gè)文件(如Ex4_11_2.c)中,其程序如下:/*Ex4_11_1.c文件內(nèi)容*/#include"stdio.h"externintN;/*聲明外部變量N*/externfloatS,A;/*聲明外部變量S和A*/voidfpow()/*計(jì)算A的N次冪并存放到全局變量S中,即S=AN*/{intk;S=1;for(k=1;k<=N;k++)S=S*A;}4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別Ex4_11_2.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別/*Ex4_11_2.c文件內(nèi)容*/#include"d:\Clessons\Example\Ex4_11_1.c

"intN;/*定義外部變量N*/floatA;/*定義外部變量A*/voidmain(){externfloatS;/*聲明外部變量S*/printf("InputvaluesintoA&N,please!");

scanf("%f%d",&A,&N); fpow();printf("\nS=%f\n",S); }floatS;/*定義外部變量S*/語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C由以上兩個(gè)程序文件構(gòu)成的工程文件(Myproj.prj)如下:/*工程文件Myproj.prj內(nèi)容*/d:\Clessons\Example\Ex4_11_1.cd:\Clessons\Example\Ex4_11_2.c工程文件Myproj.prj的編譯選項(xiàng)中的PrimaryCfile必須指定為main函數(shù)所在文件的名稱(chēng)。如圖4.6所示,指定為D盤(pán)下的Ex4_11_2.c即d:\Clessons\Example\Ex4_11_2.c4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別

語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4.2.4靜態(tài)外部變量(文件內(nèi)部變量)的應(yīng)用舉例如果把【例4-11】程序改寫(xiě)成如【例4-12】所示:【例4-12】/*Ex4_12_1.c文件內(nèi)容*/#include"stdio.h"externintN;/*聲明外部變量N*/externfloatS,A;/*聲明外部變量S和A*/voidfpow()/*計(jì)算A的N次冪并存放到全局變量S中,即S=AN*/{intk;S=1;for(k=1;k<=N;k++)S=S*A;}4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別Myroj1.prj演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別/*Ex4_12_2.c文件內(nèi)容*/staticintN;/*定義內(nèi)部變量N*/floatS;/*定義外部變量S*/floatA;/*定義外部變量A*/voidmain(){printf("InputvaluesintoA&N,please!");

scanf("%f%d",&A,&N); fpow();printf("\nS=%f\n",S); }當(dāng)編譯該程序文件件Myproj1.prj時(shí),系統(tǒng)會(huì)給出如下的錯(cuò)誤:LinkerError:Undefinedsymbol'_N'inmoduleEX4_12_1.C!語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4變量的作用域和存儲(chǔ)類(lèi)別4.4.2變量的存儲(chǔ)類(lèi)別但是如果把Ex4_12_2.c文件內(nèi)容改成如【例4-13】所示【例4-13】利用文件包含的方法實(shí)現(xiàn)全局變量的共享。/*Ex4_13_1.c文件內(nèi)容*/#include"stdio.h"externintN;/*聲明外部變量N*/externfloatS,A;/*聲明外部變量S和A*/voidfpow()/*計(jì)算A的N次冪并存放到全局變量S中,即

S=AN*/{intk;S=1;for(k=1;k<=N;k++)S=S*A;}Ex4_13_2.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別/*Ex4_13_2.c文件內(nèi)容*/#include“d:\Clessons\Example\ex4_13_1.c"/*在文件頭部把c:\Ex4_13_1.c包含進(jìn)來(lái)*/staticintN;/*定義外部變量N*/floatS;/*定義外部變量S*/floatA;/*定義外部變量A*/voidmain(){printf("InputvaluesintoA&N,please!");

scanf("%f%d",&A,&N); fpow();printf("\nS=%f\n",S); }語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.4變量的作用域和存儲(chǔ)類(lèi)別

4.4.2變量的存儲(chǔ)類(lèi)別在文件Ex4_13_2.c的頭部,把c:\Ex4_13_1.c包含進(jìn)來(lái),相當(dāng)于把c:\Ex4_13_1.c文件的內(nèi)容放在Ex4_13_2.c文件的前面,即把c:\Ex4_13_1.c文件的內(nèi)容合并到文件Ex4_13_2.c中,這樣,只需對(duì)Ex4_13_2.c進(jìn)行編譯連接,就會(huì)生成與Ex4_13_2同名的可執(zhí)行文件Ex4_13_2.exe。既不需要建立工程文件,盡管在Ex4_13_2.c文件中把N定義成靜態(tài)整型變量,也不會(huì)像【例4-12】那樣出現(xiàn)錯(cuò)誤!這是為什么呢?請(qǐng)同學(xué)思考。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.5內(nèi)部函數(shù)與外部函數(shù)與指定外部變量的靜態(tài)存儲(chǔ)類(lèi)別類(lèi)似,函數(shù)也有文件內(nèi)部函數(shù)和可供其它文件調(diào)用的外部函數(shù)兩種類(lèi)型。如果在一個(gè)源文件中定義的函數(shù)只能被本文件中的函數(shù)調(diào)用,而不能被同一源程序其它文件中的函數(shù)調(diào)用,這種函數(shù)稱(chēng)為內(nèi)部函數(shù)。定義內(nèi)部函數(shù)的一般形式是:static類(lèi)型說(shuō)明符函數(shù)名(形參表)例如:staticint

f(int

a,intb)語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.5內(nèi)部函數(shù)與外部函數(shù)內(nèi)部函數(shù)也稱(chēng)為靜態(tài)函數(shù)。但此處?kù)o態(tài)static的含義已不是指存儲(chǔ)方式,而是指對(duì)函數(shù)的調(diào)用范圍只局限于定義它的文件中。因此在不同的源文件中定義同名的靜態(tài)函數(shù)不會(huì)引起混淆。外部函數(shù)是指在定義函數(shù)時(shí)未指定關(guān)鍵字static。這樣的函數(shù)可供任一C文件中的函數(shù)對(duì)它調(diào)用。定義外部函數(shù)的一般形式為:[extern]類(lèi)型說(shuō)明符函數(shù)名(形參表)例如:externint

f(int

a,intb)如在函數(shù)定義中沒(méi)有指明extern或static則隱含為extern。如果一個(gè)文件中要調(diào)用外部函數(shù),必須在主調(diào)文件中要對(duì)被調(diào)用的函數(shù)進(jìn)行顯式的extern說(shuō)明。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.5內(nèi)部函數(shù)與外部函數(shù)【例4-14】:

1externint

func();2voidmain()3{4func();5}6intmax(inta,intb)7{8return(a>b?a:b);9}prg1.c文件的內(nèi)容如下:

1externintmax(inta,intb);2staticint

func()3{4intx,y,z;5scanf(“%d%d”,&x,&y);6z=max(x,y);7return(z);8}

prg2.c文件的內(nèi)容如下:

語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.5內(nèi)部函數(shù)與外部函數(shù)由于func()被定義成prg2.c文件的內(nèi)部函數(shù),該函數(shù)只能在prg2.c文件的內(nèi)部使用,不能被其它文件的函數(shù)調(diào)用,因此prg1.c文件的第1行對(duì)函數(shù)func()的聲明是錯(cuò)誤的。而在prg1.c文件中的max(inta,intb)被定義成外部函數(shù),不僅在定義它的文件prg1.c中可以調(diào)用它,而且其它文件中也可以調(diào)用它。為了使得prg2.c文件的第6行能夠調(diào)用外部函數(shù)max,還必須在第6行之前對(duì)它進(jìn)行聲明。prg2.c文件的第1行就是起著這樣的作用。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)C語(yǔ)言中的函數(shù)既可以像4.3.5節(jié)所述的那樣可以嵌套調(diào)用,也可以遞歸調(diào)用。函數(shù)體內(nèi)出現(xiàn)調(diào)用自身的語(yǔ)句的函數(shù),稱(chēng)之為遞歸函數(shù)。函數(shù)的遞歸調(diào)用是指一個(gè)函數(shù)在它的函數(shù)體內(nèi),直接或間接地調(diào)用它自身。其間接遞歸調(diào)用如圖所示main(){………Func1(x,y);………}Func1(intx,inty){………

Func2(a+2);………}Func2(intw){………Func1(w,u);………}第1步調(diào)用

func1第2步調(diào)用

func2第3~N步調(diào)用func1第N+1步返回到func1第N+2步返回到main語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)直接遞歸調(diào)用如圖所示main(){………Func(x,y);………}Func(intx,inty){………Func(a+2,y-b);………}第2~N步調(diào)用自身第1步調(diào)用Funct第N+1步返回main語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)在遞歸調(diào)用中,主調(diào)用函數(shù)又是被調(diào)用函數(shù)(如圖4.9中的函數(shù)Func1調(diào)用Func2調(diào)用,函數(shù)Func2又調(diào)用Func1),即函數(shù)Func1既是調(diào)用者也是被調(diào)用者)。執(zhí)行遞歸函數(shù)將反復(fù)調(diào)用其自身。每調(diào)用一次就進(jìn)入新的一層。例如有函數(shù)f如下:intfun(inta){intb=0,c;b++;c=f(b);returnc;}這個(gè)函數(shù)是一個(gè)遞歸函數(shù)。但是運(yùn)行該函數(shù)將無(wú)休止地調(diào)用其自身,這當(dāng)然是不正確的。為了防止遞歸調(diào)用無(wú)休止地進(jìn)行,必須在函數(shù)內(nèi)有終止遞歸調(diào)用的手段。常用的辦法是加條件判斷,滿(mǎn)足某種條件后就不再作遞歸調(diào)用,然后逐層返回。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)【例4-15】用遞歸法計(jì)算N!可用下述公式表示

N!=1當(dāng)N≤1(遞歸結(jié)束條件)N*(N-1)!當(dāng)N>1為了便于編寫(xiě)程序,我們?cè)O(shè)計(jì)一個(gè)變量N的函數(shù)F(N)如下:F(N)=1當(dāng)N≤1(遞歸結(jié)束條件)N*F(N-1)當(dāng)N>1語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)【例4-15】用遞歸法計(jì)算N!可用下述公式表示

按上述公式對(duì)應(yīng)的程序如下:longF(intN){if(N<=1)return1;elsereturnN*F(N-1);}main(){intN;longS;printf("\ninputainteagernumber:\n");scanf("%d",&N);if(N<0){printf("Nmustbenotlessthanzero!\n");exit(1);}S=F(N);printf("%d!=%ld",N,S);getch();}

Ex4_15.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)程序說(shuō)明:程序中給出的函數(shù)F(intN)是一個(gè)遞歸函數(shù)。主函數(shù)調(diào)用F(N)后即進(jìn)入函數(shù)F(N)執(zhí)行,如果N=0或N=1時(shí)都將結(jié)束函數(shù)的執(zhí)行,否則就遞歸調(diào)用函數(shù)自身。由于每次遞歸調(diào)用的實(shí)參為N-1,即把N-1的值賦予形參N,最后當(dāng)N-1的值為1時(shí)再作遞歸調(diào)用,形參N的值也為1,將使遞歸終止。然后可逐層退回。設(shè)執(zhí)行本程序時(shí)輸入為5,即求5!。在主函數(shù)中的調(diào)用語(yǔ)句即為S=F(N);,進(jìn)入F函數(shù)后,由于N=5,執(zhí)行N*F(N-1),即5*F(5-1)。該語(yǔ)句對(duì)F作遞歸調(diào)用即F(4)。逐次遞歸展開(kāi)F(5)=5*F(4)=5*4*F(3)=5*4*3*F(2)=5*4*3*2*F(1)=5*4*3*2*1=120。進(jìn)行五次遞歸調(diào)用后,F(xiàn)函數(shù)形參取得的值變?yōu)?,故不再繼續(xù)遞歸調(diào)用而開(kāi)始逐層返回主調(diào)函數(shù)。F(5)的函數(shù)調(diào)用計(jì)算過(guò)程如下圖所示。圖中實(shí)線(xiàn)表示調(diào)用函數(shù),虛線(xiàn)表示函數(shù)結(jié)束返回。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)voidmain(){…L=factn(5);…}longfactn(5){longL;…L=5*factn(4);return(L);}longfactn(3){longL;…L=3*factn(2);return(L);}longfactn(4){longL;…L=4*factn(3);return(L);}longfactn(1){longL;…return(1);}longfactn(2){longL;…L=2*factn(1);return(L);}函數(shù)調(diào)用計(jì)算過(guò)程語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)一個(gè)問(wèn)題的求解能否設(shè)計(jì)成遞歸函數(shù),往往取決于對(duì)問(wèn)題本身描述。如果問(wèn)題的描述具有如下的三個(gè)條件,就可用遞歸函數(shù)求解。1、問(wèn)題的描述分成兩部分,其中前一部分描述問(wèn)題求解的結(jié)束條件,后一部分與原始的描述相似或相同;2、后一部分的描述是原始問(wèn)題的簡(jiǎn)化;3、后一部分的描述趨于問(wèn)題求解的結(jié)束。N階乘問(wèn)題的求解過(guò)程(算法),用自然語(yǔ)言可以描述如下:1、N=0或1時(shí),其階乘的值是1,2、N>1時(shí),N的階乘值是N與(N-1)階乘的積,3、因?yàn)镹的值經(jīng)過(guò)若干次減1的運(yùn)算,使得N趨于結(jié)束條件0或1。顯然,這是對(duì)問(wèn)題的遞歸描述,且滿(mǎn)上述的三個(gè)條件,因此可以設(shè)計(jì)成遞歸函數(shù)來(lái)求解。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)【例4-16】編寫(xiě)遞歸函數(shù)求解斐波那契數(shù)列的第N項(xiàng)的值。斐波那契數(shù)列的組成規(guī)律是:第一項(xiàng)是0,第二項(xiàng)是1,從第三項(xiàng)起每一項(xiàng)都等于緊鄰的前兩項(xiàng)之和。即數(shù)列的組成如下:0,1,1,2,3,5,8……。根據(jù)問(wèn)題的描述,建立如下的數(shù)學(xué)模型

Fibo(N)=0N=11N=2Fibo(N-1)+Fibo(N-2)N>2語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)有了以上數(shù)學(xué)模型,不難寫(xiě)出如下遞歸函數(shù):longFibo(intN){if(N==1)return0;

if(N==2)return1;returnFibo(N-1)+Fibo(N-2);}或者定義成:longFibo(intN){return(N==1||N==2)?N-1:Fibo(N-1)+Fibo(N-2);}voidmain(){intN;

printf("InputavalueofN,please!\n");

scanf("%d",&N);if(N>0) printf("F(%d)=%ld\n",N,Fibo(N));

elseprintf("Nmustbegreaterthanzero!\n");}Ex4_16.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)【例4-17】求兩個(gè)整數(shù)M和N的最大公約數(shù),按照中國(guó)古代的九章算術(shù)記載的輾轉(zhuǎn)相除法描述:令R=M%N;當(dāng)R=0時(shí),則N就是M,N兩數(shù)的最大公約數(shù)(N即為所求),終止計(jì)算;否則(即R≠0),求N和R的最大公約數(shù)(即求N和M%N的最大公約數(shù))。根據(jù)上述,可以建立相應(yīng)的數(shù)學(xué)模型:Gcd(M,N)=N當(dāng)M%N=0Gcd(N,M%N)當(dāng)M%N≠0語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)根據(jù)上述的數(shù)學(xué)模型,我們既可以用遞歸函數(shù)實(shí)現(xiàn)求解,也可以用迭代的方法編寫(xiě)函數(shù)求解。下面我們分寫(xiě)出各自的函數(shù):遞歸法求解函數(shù):longgcd1(longM,longN){return(M%N==0)?N:gcd1(N,M%N);}循環(huán)迭代法求解函數(shù):longgcd2(longM,longN){longR=M%N;while(R){M=N;N=R;R=M%N;}returnN;}語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)voidmain(){longM,N,t;

printf("InputavalueofN,please!\n");

scanf("%ld%ld",&M,&N);if(M<N){t=M;M=N;N=t;} /*保證M≥N*/printf("GreatestCommondividerof%ld&%ldis%ld!\n",M,N,gcd1(M,N));printf("GreatestCommondividerof%ld&%ldis%ld!\n",M,N,gcd2(M,N));}Ex4_17.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)【例4-18】猩猩剝花生問(wèn)題。動(dòng)物園管理員第一天給了大猩猩一堆花生。當(dāng)天這些猩猩撥了三分之二多一只,第二天在剩下的花生中又撥了三分之二多一只。此后每天都撥了前一天剩下的三分之二多一只。到了第10天早上,只剩了一只花生。求動(dòng)物園管理員給了大猩猩多少只花生?Penut(day)=1day=10Penut(day)=3*(Penut(day+1)+1)0<day<10語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)根據(jù)遞推公式Xn-1=3*(Xn+1)編寫(xiě)函數(shù)如下:longPenut1(intday){longX=1;

for(;day>1;day--)X=3*(X+1);returnX;}longPenut(intday){if(day==10)return1;return(3*(Penut(day+1)+1));}voidmain(){

printf("The

penutnumber=%ld!\n",Penut(1));printf("The

penutnumber=%ld!\n",Penut1(10));}Ex4_18.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)由【例4-17】和【例4-18】我們可以看出,一個(gè)問(wèn)題的求解算法往往有多種。究竟采用什么算法更好,這不是本書(shū)討論的話(huà)題。但是有一點(diǎn),在既可以采用遞歸也可以采用非遞歸算法的情況下,盡量不用遞歸方法。因?yàn)檫f歸深度過(guò)大,用于存放返回信息的堆棧耗用大量的內(nèi)存,可能會(huì)造成內(nèi)存不夠用的困境。在遞歸深度不大,采用遞歸使得問(wèn)題求解的描述更易理解和實(shí)現(xiàn)的情況下,采用遞歸是一種有效的方法。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)【例4-19】編寫(xiě)程序求漢諾塔盤(pán)子移動(dòng)的步驟。本題算法分析如下,設(shè)A上有n個(gè)盤(pán)子。移動(dòng)的過(guò)程可分解為三個(gè)步驟:第一步借助于C座,把A上的n-1個(gè)圓盤(pán)移到B上;第二步把A上的最后一個(gè)圓盤(pán)移到C上;第三步借助于A(yíng)座,把B上的n-1個(gè)圓盤(pán)移到C上;其中第一步和第三步是類(lèi)同的。當(dāng)n=3時(shí),第一步和第三步又分解為類(lèi)同的三步,即把n-1個(gè)圓盤(pán)從一個(gè)座移到另一個(gè)座上,這里的n=n-1。顯然這是一個(gè)遞歸過(guò)程,據(jù)此可把算法表述成:Move(N,A,B,C)

=Move(N-1,A,C,B)當(dāng)N>1Move(N-1,B,A,C)當(dāng)N>1A→C當(dāng)N=1語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)根據(jù)上述算法模型可編程如下:#include"stdio.h"voidmove(int

n,char

A,char

B,charC)/*將A座上的n個(gè)圓盤(pán)移到C座的函數(shù)*/{

if(n==1)/*當(dāng)n=1時(shí),直接將A座上的盤(pán)子移到C座上*/printf("%c-->%c\n",A,C);

else{/*當(dāng)n>1時(shí),借助于C座,將A座上的n-1個(gè)盤(pán)子移到B座上*/move(n-1,A,C,B);

printf("%c-->%c\n",A,C);/*直接將A座上最后一個(gè)盤(pán)子,移到C座上*/move(n-1,B,A,C);/*借助于A(yíng)座,將B座上的n-1個(gè)盤(pán)子移到C座上*/}}Ex4_19.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)main(){intn;printf("\ninputnumber:\n");scanf("%d",&n);printf("thesteptomoving%2ddiskes:\n",n);move(n,'A','B','C');}語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.6遞歸函數(shù)程序說(shuō)明:move函數(shù)是一個(gè)遞歸函數(shù),它有四個(gè)形參n,A,B,C。n表示圓盤(pán)數(shù),A,B,C分別表示三個(gè)座。move函數(shù)的功能是把A上的n個(gè)圓盤(pán)移動(dòng)到C上。當(dāng)n==1時(shí),直接把A上的圓盤(pán)移至C上,輸出A→C。如n≠1則分為三步:遞歸調(diào)用move函數(shù),把n-1個(gè)圓盤(pán)從A移到B;輸出A→C;遞歸調(diào)用move函數(shù),把n-1個(gè)圓盤(pán)從B移到C。在遞歸調(diào)用過(guò)程中n=n-1,故n的值逐次遞減,最后n=1時(shí),終止遞歸,逐層返回。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.7編譯預(yù)處理ANSIC規(guī)定可以在C源程序中插入一些傳給編譯程序的預(yù)處理命令,由于這些命令不是C語(yǔ)言的組成部分,不能直接進(jìn)行編譯,通常在編譯之前預(yù)先進(jìn)行處理,所以在C語(yǔ)言源程序中,凡是以“#”號(hào)開(kāi)頭的一律作為編譯預(yù)處理命令對(duì)待。例如:"#definePAI3.14159",預(yù)處理時(shí)將程序中所有的PAI置換為指定的字符串3.14159。"#include<math.h>",預(yù)處理時(shí)就用math.h文件中的實(shí)際內(nèi)容代替該行命令,然后將處理結(jié)果和源程序一起進(jìn)行編譯,這就擴(kuò)充了程序的設(shè)計(jì)環(huán)境,提高了編程效率。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.7編譯預(yù)處理編譯預(yù)處理是編譯系統(tǒng)的一個(gè)組成部分,主要有三類(lèi)命令:宏定義#define、#undef預(yù)處理文件包含#include

條件編譯#if、#ifdef、#ifndef、#else、#elif、#endif預(yù)處理命令的特點(diǎn):(1)命令以#開(kāi)頭,表示編譯預(yù)處理命令行的開(kāi)始標(biāo)志;(2)每條命令獨(dú)占一行,即每一行只能有一條編譯預(yù)處理命令;(3)行末不能有";"號(hào)。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.7編譯預(yù)處理1.不帶參數(shù)的宏定義用一個(gè)指定的名字代表一個(gè)字符串,一般形式為:#define宏名字符串功能:編譯預(yù)處理時(shí),將程序中所有的該宏名(標(biāo)識(shí)符)用該字符串替換。其中:(1)#define是宏定義命令。(2)宏名是用戶(hù)定義的標(biāo)識(shí)符,不得與程序中其他標(biāo)識(shí)符同名。宏名中不能含空格,宏名與字符串之間用空格分隔開(kāi)。字符串兩側(cè)沒(méi)有雙引號(hào)時(shí),串中不能含空格。(3)如字符串加了雙引號(hào),雙引號(hào)將一起參與替換。(4)預(yù)處理時(shí)用字符串替換宏名的過(guò)程稱(chēng)為宏替換,或宏代換、宏展開(kāi)。

4.7.1宏定義與宏替換語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.7編譯預(yù)處理【例4-20】通過(guò)鍵盤(pán)輸入半徑的值,求圓的周長(zhǎng)、面積和球的表面積、體積。#definePAI3.1415926#defineMESSAGE1"這是一個(gè)宏定義示例"#defineMESSAGE2"請(qǐng)輸入半徑"main(){floatS,R,L,V,T;printf(MESSAGE1);printf("%s",MESSAGE2);scanf("%f",&R);L=2*PAI*R;S=PAI*R*R;T=4*S;V=4/3.0*PAI*R*R*R;printf("L=%10.3f\nS=10.3\nT=%10.3f\nV=%10.3f\n",L,S,T,V);}Ex4_20.c演示語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理C4.7編譯預(yù)處理上述程序經(jīng)過(guò)預(yù)處理(即宏替換)之后,源程序的內(nèi)容如下:main(){floatS,R,L,V,T;printf("這是一個(gè)宏定義示例");printf("%s","請(qǐng)輸入半徑");scanf("%f",&R);L=2*3.1415926*R;S=3.1415926*R*R;T=4*S;V=4/3.0*3.1415926*R*R*R;printf("L=%10.3f\nS=10.3\nT=%10.3f\nV=%10.3f\n",L,S,T,V);}預(yù)處理后,宏名PAI、MESSAGE1和MESSAGE2不見(jiàn)了,相應(yīng)處分別被替換為3.1415926、"這是一個(gè)宏定義示例"和"請(qǐng)輸入半徑"。語(yǔ)言程序設(shè)計(jì)第四章函數(shù)與編譯預(yù)處理

溫馨提示

  • 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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論