




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第4章函數(shù)與編譯預處理語言程序設(shè)計第四章函數(shù)與編譯預處理C4.1函數(shù)的概念及其分類4.2函數(shù)的定義4.3函數(shù)的聲明與調(diào)用4.4變量的作用域和存儲類別4.5內(nèi)部函數(shù)與外部函數(shù)4.6遞歸函數(shù)4.7編譯預處理4.8綜合范例4.9本章小結(jié)4.10問與答內(nèi)容簡介4.1函數(shù)的概念及其分類語言程序設(shè)計第四章函數(shù)與編譯預處理C在第一章中已經(jīng)介紹過,C源程序是由函數(shù)組成的。雖然在前面各章的程序中都只有一個主函數(shù)main(),但真正實用的程序往往由大量的小函數(shù)而不是由少量大函數(shù)構(gòu)成的,即所謂“小函數(shù)構(gòu)成大程序”。這樣的好處是讓各部分相對簡單獨立,并且任務(wù)單一。
所謂函數(shù)就是一個具有一定功能、且相對獨立的、可供其它程序調(diào)用的程序模塊。它是C源程序的基本模塊,通過對函數(shù)模塊的調(diào)用實現(xiàn)特定的功能。C語言中的函數(shù)相當于其它高級語言的子程序(或過程)。4.1函數(shù)的概念及其分類語言程序設(shè)計第四章函數(shù)與編譯預處理CC語言不僅提供了極為豐富的庫函數(shù)(如TurboC,MSC都提供了三百多個庫函數(shù)),還允許用戶建立自己定義的函數(shù)。用戶可把自己的算法編成一個個相對獨立的函數(shù)模塊,然后采取調(diào)用的方法來使用函數(shù)??梢哉fC程序的全部工作都是由各式各樣的函數(shù)完成的,所以也有人把C語言稱為函數(shù)式語言。由于采用了函數(shù)模塊式的結(jié)構(gòu),C語言易于實現(xiàn)結(jié)構(gòu)化程序設(shè)計。使程序的層次結(jié)構(gòu)清晰,便于程序的編寫、閱讀、調(diào)試。4.1函數(shù)的概念及其分類語言程序設(shè)計第四章函數(shù)與編譯預處理C在C語言中可從不同的角度對函數(shù)分類。1.從函數(shù)定義的角度看,函數(shù)可分為庫函數(shù)和用戶定義函數(shù)兩種。1)庫函數(shù)由C系統(tǒng)提供,用戶無須定義,只需在程序前用#include宏命令包含要調(diào)用的函數(shù)原型的頭文件,即可在程序中直接調(diào)用。在前面各章的例題中反復用到printf
、scanf
、gets、puts等函數(shù)均屬此類。2)用戶自定義函數(shù)自定義函數(shù)是由程序設(shè)計者根據(jù)問題的需要自己定義的。
語言程序設(shè)計第四章函數(shù)與編譯預處理C2.C語言的函數(shù)兼有其它語言中的函數(shù)和過程兩種功能,從這個角度看,又可把函數(shù)分為有返回值函數(shù)和無返回值函數(shù)兩種。(1)有返回值函數(shù)此類函數(shù)被調(diào)用執(zhí)行完成之后,將向調(diào)用者返回一個執(zhí)行結(jié)果,稱為函數(shù)返回值。
(2)無返回值函數(shù)此類函數(shù)用于完成某項特定的處理任務(wù),執(zhí)行完成之后不向調(diào)用者返回函數(shù)值。4.1函數(shù)的概念及其分類語言程序設(shè)計第四章函數(shù)與編譯預處理C3.從主調(diào)函數(shù)和被調(diào)函數(shù)之間數(shù)據(jù)傳送的角度看又可分為無參函數(shù)和有參函數(shù)兩種。(1)無參函數(shù)函數(shù)定義、函數(shù)聲明及函數(shù)調(diào)用中均不帶參數(shù)。主調(diào)函數(shù)和被調(diào)函數(shù)之間不進行參數(shù)傳送。此類函數(shù)通常用來完成一些特定的功能。(2)有參函數(shù)也稱為帶參函數(shù)。在函數(shù)定義及函數(shù)聲明時都有參數(shù),定義時指定的參數(shù)稱為形式參數(shù)(簡稱為形參)。在函數(shù)調(diào)用時也必須給出參數(shù)值或有值的表達式,調(diào)用時給出的參數(shù)稱為實際參數(shù)(簡稱為實參)。進行函數(shù)調(diào)用時,主調(diào)函數(shù)將把實參的值傳送給形參,供被調(diào)函數(shù)使用。4.1函數(shù)的概念及其分類4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C函數(shù)定義的一般形式1.現(xiàn)代定義形式:[存儲類別][返回值類型]函數(shù)名稱([類型標識1形參名稱1[,類型標識2形參名稱2…..]]){[變量定義;…]語句1;……語句n;}
4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C函數(shù)定義的一般形式2.傳統(tǒng)的定義形式[存儲類別][返回值類型]函數(shù)名([形參名稱1[,形參名稱2…..]])[類型標識1形參名稱1;[類型標識2形參名稱2;….]]{[變量定義;…]語句1;……語句n;}
4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C【例4-1】編寫程序求解任意兩個數(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ù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理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);}
程序說明:以上Maxcd(int
X,intY)函數(shù)的功能是專門求解兩數(shù)的最大公約數(shù)。其中的X和Y是形式參數(shù)。該函數(shù)有返回值(就是X和Y的最大公約數(shù)),返回值是整型,因此也被稱之為整型函數(shù)。TellMessage()函數(shù)的功能只是在屏幕上給出提示信息:Inputvaluesintoa&b,please!它既是一個無參的,也是一個無返回值的函數(shù)。語言程序設(shè)計第四章函數(shù)與編譯預處理C關(guān)于函數(shù)定義的幾點說明:(1)[存儲類別]指明函數(shù)的有效范圍,此類型標識符只有兩種:static和extern。static規(guī)定了當前定義的函數(shù),只能被定義它的那個文件中的其它函數(shù)調(diào)用,不能被其它文件中的函數(shù)調(diào)用,因此,這類函數(shù)又叫作內(nèi)部函數(shù);extern說明了當前定義的函數(shù)可供所有文件中的函數(shù)調(diào)用,因而又稱為外部函數(shù)。默認(不明確指定)的是extern,即外部函數(shù)。(2)[返回值類型]規(guī)定函數(shù)有無返回值或規(guī)定函數(shù)執(zhí)行結(jié)束時,返回值的數(shù)據(jù)類型,默認的是整型(int)。如果函數(shù)不需要或沒有返回值,應(yīng)當明確用void說明。4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C(3)函數(shù)名稱必須是合法的標識符,其與變量命名規(guī)則相同。正規(guī)的程序設(shè)計,變量、函數(shù)與符號常量的取名最好要見名知義,這樣利于提高程序的可讀性和可維護性。良好的命名習慣是優(yōu)秀程序員的標志之一。(4)[存儲類別][返回值類型]函數(shù)名稱([類型標識1形參名稱1[,類型標識2形參名稱2…..]])或者[存儲類別][返回值類型]函數(shù)名([形參名稱1[,形參名稱2…..]])[類型標識1形參名稱1;[類型標識2形參名稱2;….]]被稱之為函數(shù)頭,緊接其后的一對花括號”{“和“}”及其中的語句稱之為函數(shù)體。4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C(5)[]中的說明符是可有可無的,例如[形參名稱1[,形參名稱2…..]]表示函數(shù)定義中的形式參數(shù)個數(shù)≥0。(6)函數(shù)體中表示函數(shù)結(jié)束的三種情況:㈠函數(shù)有返回值時,則函數(shù)體中表示函數(shù)結(jié)束的返回語句形式是:return表達式;或return(表達式);㈡函數(shù)無返回值時,則函數(shù)體中函數(shù)結(jié)束的返回語句形式是:return;㈢函數(shù)無返回值,且函數(shù)體中最后一條語句就表示函數(shù)的結(jié)束,則函數(shù)體中無需返回語句return;㈣函數(shù)體中可以有多條返回語句。但是,只能有其中的一個返回語句可以被執(zhí)行。4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C(7)有返回值的函數(shù),對它的調(diào)用可以出現(xiàn)在表達式中,對無返回值的函數(shù)調(diào)用只能作為一條單獨的語句。(8)函數(shù)調(diào)用語句中每個實參的數(shù)據(jù)類型,必須保證與函數(shù)定義中的每個形參一一對應(yīng)相容或相同。(9)函數(shù)有返回值時,如果其返回值的類型與定義函數(shù)指定的數(shù)據(jù)類型不一致,則系統(tǒng)會自動轉(zhuǎn)換為定義函數(shù)指定的數(shù)據(jù)類型。10)函數(shù)定義不能嵌套,即函數(shù)體中不能再包含任何函數(shù)的定義。4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C【例4-2】編寫函數(shù)實現(xiàn)從N個整數(shù)中找出其中的素數(shù),并且按照從小到大的順序輸出這些素數(shù)以及這些素數(shù)的平均值(平均值保留兩位小數(shù))。#include"stdio.h"#defineNum10#defineTrue1#defineFalse0/*以下是利用選擇排序法把數(shù)組中N個元素的值從小到大排序的函數(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演示語言程序設(shè)計第四章函數(shù)與編譯預處理CvoidAcceptINum(intA[],intN);/*為了使得主函數(shù)main能夠調(diào)用它而對其進行聲明*/voidmain(){int
I,IArray[Num],Pn=0;floatfAverage=0;
printf("Input10NumbersintoArray,please!");
AcceptINum(IArray,Num);/*調(diào)用AcceptINum函數(shù)接收鍵盤輸入Num個數(shù)*/Nsort(IArray,Num);/*調(diào)用Nsort
函數(shù),對IArray
中的元素值進行排序*/printf("ThesortedNumbersAre:\n");/*從小到大輸出各個數(shù)*/for(I=0;I<Num;I++)printf(I==Num-1?"%d\n":"%d,",IArray[I]);4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理Cprintf("\nThePrimesare:");for(I=0;I<Num;I++)/*從小到大輸出各個素數(shù)及素數(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");}/*以下是接收鍵盤輸入N個整數(shù)函數(shù)*/voidAcceptINum(intA[],intN){intK;
for(K=0;K<N;K++)
scanf("%d",&A[K]);return;/*因為該函數(shù)沒有返回值,所以此處的
return可以刪去*/}4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C/*以下是判斷一個整數(shù)是否是素數(shù),若是素數(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ù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C程序說明:以上的例子中①函數(shù)Nsort(intA[],intN)沒有返回值,因此可以不需要返回語句。②函數(shù)IsPrime(intX)雖然只有一個返回值,但可以有兩個返回語句。③函數(shù)AcceptINum(int
A[],intN)雖然沒有返回值,也可以用return語句表示函數(shù)結(jié)束(當然此處的return語句也可以不需要)。④本例中用到了一維數(shù)組(數(shù)組的概念以及數(shù)組的應(yīng)用要到下一章才學到),為了便于理解,在此對本例中用到的數(shù)組,作簡單的說明:這里主函數(shù)main中定義的數(shù)組IArray[Num],其中的Num是一個符號常量10,即Num與整數(shù)10是等價的。元素的引用形式是數(shù)組名稱[整型表達式],并且整型表達式的值是0~Num-1。因此,可以把數(shù)組元素看成是一個普通的變量。
4.2函數(shù)的定義語言程序設(shè)計第四章函數(shù)與編譯預處理C一個函數(shù)能被另一個函數(shù)調(diào)用需要以下幾個條件:(1)該函數(shù)必須已經(jīng)存在,無論是庫函數(shù)還是用戶自定義函數(shù)。(2)調(diào)用系統(tǒng)提供的庫函數(shù)時,與被調(diào)用函數(shù)相關(guān)的頭文件,必須在源程序的開頭用#include命令把它包含進來。(3)用戶自定義函數(shù),在被調(diào)用之前,需要對自定義函數(shù)進行聲明。
4.3函數(shù)的聲明與調(diào)用
4.3.1函數(shù)能被使用的條件語言程序設(shè)計第四章函數(shù)與編譯預處理C被調(diào)用的用戶自定義函數(shù),同時具備下列情況,需要對它進行聲明。(1)與調(diào)用它的主調(diào)函數(shù)在同一文件中,(2)它的定義位置在調(diào)用它的那個主調(diào)函數(shù)之后,(3)它的返回值類型不是整型,也不是字符型的;(4)在調(diào)用它的那個主調(diào)函數(shù)之前沒有被聲明4.3函數(shù)的聲明與調(diào)用
4.3.2函數(shù)聲明的場合語言程序設(shè)計第四章函數(shù)與編譯預處理C(1)[返回值類型]函數(shù)名稱([類型標識1形參名稱1[,類型標識2形參名稱2…..]]);或者:(2)[返回值類型]函數(shù)名稱([類型標識1[,類型標識2…..]]);最簡單的方法就是把被調(diào)用函數(shù)的函數(shù)頭,復制到調(diào)用它的主調(diào)函數(shù)之前,然后再加一個分號;就一切搞定了!其實函數(shù)聲明格式中的形參部分只需給出每個參數(shù)的數(shù)據(jù)類型就可以了,無須給出形參的名稱,即使給出形參的名稱,其名稱可以隨意,只要名稱符合標識符命名規(guī)則即可。4.3函數(shù)的聲明與調(diào)用
4.3.3函數(shù)聲明的格式語言程序設(shè)計第四章函數(shù)與編譯預處理C(1)在所有函數(shù)的最前面;如【例4-3】所示。(2)在所有函數(shù)的外部,在調(diào)用它的主調(diào)函數(shù)之前;如【例4-4】所示的f2,f3,f4函數(shù)的聲明。【例4-4】(3)在調(diào)用它的主調(diào)函數(shù)內(nèi)部,此時,可以把它看作定義變量那樣對待;如【例4-4】所示的f1函數(shù)的聲明和【例4-5】所示的f1,f2,f3,f4函數(shù)的聲明
4.3函數(shù)的聲明與調(diào)用
4.3.4函數(shù)聲明的位置語言程序設(shè)計第四章函數(shù)與編譯預處理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演示語言程序設(shè)計第四章函數(shù)與編譯預處理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演示語言程序設(shè)計第四章函數(shù)與編譯預處理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演示語言程序設(shè)計第四章函數(shù)與編譯預處理C注意!以下三種情況可以省略對被調(diào)函數(shù)的聲明:(1)如果被調(diào)函數(shù)的定義出現(xiàn)在主調(diào)函數(shù)之前,則可以省略聲明。如【例4-2】的Nsort函數(shù)。(2)如果在所有函數(shù)定義之前,在函數(shù)的外部已作了函數(shù)聲明,則在以后的各主調(diào)函數(shù)中,可以不必對被調(diào)函數(shù)作聲明。如【例4-3】的f1、f2、f3、f4函數(shù)。(3)如果函數(shù)類型為整型或字符型,則在主調(diào)函數(shù)中可以不要聲明。如【例4-2】中的IsPrime(X)函數(shù)。但使用這種方法時,系統(tǒng)無法對參數(shù)的類型作檢查,因此在調(diào)用時若參數(shù)使用不當,編譯時也不報錯。為了程序的安全,建議都加以聲明為好。4.3函數(shù)的聲明與調(diào)用
4.3.4函數(shù)聲明的位置語言程序設(shè)計第四章函數(shù)與編譯預處理C一個函數(shù)被定義之后,不被別的函數(shù)使用,即使功能再強大,也發(fā)揮不了任何作用。通過函數(shù)調(diào)用語句來達到使用函數(shù)的目的。函數(shù)調(diào)用語句有以下兩種形式:(1)無返回值的函數(shù)調(diào)用語句格式:函數(shù)名稱([實參列表]);(2)有返回值的函數(shù)調(diào)用語句格式:變量名=函數(shù)名稱([實參列表]);此處的變量名的數(shù)據(jù)類型必須與函數(shù)返回值的數(shù)據(jù)類型相容。無論是上述哪種調(diào)用語句,都會去執(zhí)行被調(diào)用函數(shù)體中的語句,函數(shù)執(zhí)行完畢,會返回到函數(shù)調(diào)用語句之后,繼續(xù)執(zhí)行調(diào)用函數(shù)語句之后的其它語句。注意:前面說過函數(shù)不可以嵌套定義。但是函數(shù)可以嵌套調(diào)用。
4.3函數(shù)的聲明與調(diào)用
4.3.5函數(shù)的調(diào)用、參數(shù)與返回值語言程序設(shè)計第四章函數(shù)與編譯預處理C【例4-6】編寫程序求5個整數(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演示語言程序設(shè)計第四章函數(shù)與編譯預處理C注意!(1)函數(shù)返回值的類型取決于函數(shù)定義中的函數(shù)名稱之前的數(shù)據(jù)類型,與return后表達式值的類型無關(guān)。如果return后表達式值的類型與函數(shù)的定義中函數(shù)名稱之前的數(shù)據(jù)類型不一致,系統(tǒng)會自動轉(zhuǎn)換。例如函數(shù)max返回值的類型是實型,函數(shù)體中的if(X>=Y)returnX;elsereturnY;語句,不論返回值表達式是X還是Y,它返回值的類型總是實型。(2)函數(shù)調(diào)用語句中的實參數(shù)量與形參數(shù)量必須相等,與形參相對應(yīng)的實參數(shù)據(jù)類型必須相容。4.3函數(shù)的聲明與調(diào)用
4.3.5函數(shù)的調(diào)用、參數(shù)與返回值語言程序設(shè)計第四章函數(shù)與編譯預處理C函數(shù)調(diào)用中,如果函數(shù)有參數(shù),則系統(tǒng)會按照函數(shù)形式參數(shù)的個數(shù)和對應(yīng)的數(shù)據(jù)類型,自動申請內(nèi)存區(qū)域,用于存放函數(shù)調(diào)用語句中對應(yīng)的實際參數(shù)的值。被調(diào)用的函數(shù)中形參的值變化與否,都不影響函數(shù)調(diào)用語句中實際參數(shù)的值。即函數(shù)的參數(shù)值傳遞是單向的,在函數(shù)調(diào)用時,系統(tǒng)只是把實際參數(shù)的值復制到對應(yīng)形式參數(shù)的內(nèi)存區(qū)域。
4.3函數(shù)的聲明與調(diào)用
4.3.6函數(shù)的傳值方式語言程序設(shè)計第四章函數(shù)與編譯預處理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演示語言程序設(shè)計第四章函數(shù)與編譯預處理C程序說明:【例4-7】中主函數(shù)main執(zhí)行到調(diào)用語句Exchange(X,Y);時,此后的程序執(zhí)行過程如下:1、系統(tǒng)會把此處實參X、Y的值5和8分別賦值給函數(shù)Exchange中的形參變量X和Y,2、然后,開始執(zhí)行Exchange函數(shù),3、在Exchange函數(shù)中,通過T=X;X=Y;Y=T;語句序列的執(zhí)行,實現(xiàn)了Exchange函數(shù)中對形參X和Y中值的交換,4、因此,執(zhí)行到printf("Innerexchange:X=%3.0f,Y=%3.0f\n”,X,Y);語句時,其輸出結(jié)果是:Innerexchange:X=8,Y=5,說明在Exchange函數(shù)體內(nèi),確實實現(xiàn)了X與Y的交換。5、Exchange函數(shù)執(zhí)行完成,返回到主函數(shù)main中調(diào)用Exchange函數(shù)語句之后,繼續(xù)執(zhí)行下一條語句:printf("Afterexchange:X=%3.0f,Y=%3.0f\n",X,Y);6、該語句輸出的結(jié)果是:Afterexchange:X=5,Y=84.3函數(shù)的聲明與調(diào)用
4.3.6函數(shù)的傳值方式語言程序設(shè)計第四章函數(shù)與編譯預處理C局部變量:所謂局部變量,就是在函數(shù)或復合語句內(nèi)定義的變量。函數(shù)體內(nèi)定義的變量,其有效范圍只局限于定義它的函數(shù)體內(nèi)。也就是只能在定義它的那個函數(shù)體內(nèi)可以使用它,在函數(shù)體外部,它就無效了。同理,復合語句中定義的變量,只能在定義它的那個復合語句中使用它,出了復合語句,就不能引用它了!此外,形參只限于它所在的函數(shù)內(nèi)部使用,因此形參是局部變量。全局變量:所謂全局變量,就是在函數(shù)外面定義的變量,因此又稱之為外部變量。它的有效范圍是從它的定義之點起到定義它的那個文件結(jié)束。與它在同一個文件中的所有函數(shù)都可以引用它。4.4變量的作用域和存儲類別
4.4.1變量的作用域語言程序設(shè)計第四章函數(shù)與編譯預處理C【例4-8】程序及其運行的結(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變量的作用域和存儲類別Ex4_8.c演示語言程序設(shè)計第四章函數(shù)與編譯預處理C全局變量與局部變量的關(guān)系,如同中央政府頒布的國家法令與地方政府頒布的地方法令之間的關(guān)系。如果某省政府沒有頒布治安處罰條例,那么在該省內(nèi)處理治安事件的依據(jù),引用的就是國家治安處罰條例;如果該省政府頒布了該省的治安處罰條例,那么在該省內(nèi)處理治安事件的依據(jù),如果沒特別說明,引用的就是指該省的治安處罰條例。就是說局部變量掩蓋了同名的全局變量。
4.4變量的作用域和存儲類別
4.4.1變量的作用域語言程序設(shè)計第四章函數(shù)與編譯預處理C變量的存儲類別是指變量的存儲屬性,即變量被分配在內(nèi)存的那種區(qū)域內(nèi)。計算機內(nèi)存一般被劃分成系統(tǒng)區(qū)和用戶區(qū)兩種,系統(tǒng)區(qū)是指系統(tǒng)程序駐留和工作的區(qū)域;用戶區(qū)就是用戶程序駐留和工作的場所。為了便于操作系統(tǒng)為程序分配存儲區(qū)域和控制用戶程序的運行,把程序分成執(zhí)行命令的操作(代碼)和被操作的數(shù)據(jù)兩部分進行存儲。其中數(shù)據(jù)區(qū)又被分成靜態(tài)存儲區(qū)和動態(tài)存儲區(qū)。因此用于存放用戶程序的用戶區(qū),被對應(yīng)地分成代碼區(qū)和靜態(tài)存儲區(qū)和動態(tài)存儲區(qū)。一般來說,內(nèi)存的動態(tài)區(qū)用于存放程序的局部變量,靜態(tài)區(qū)用于存放程序的靜態(tài)局部變量和全局變量。4.4變量的作用域和存儲類別
4.4.2變量的存儲類別語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4變量的作用域和存儲類別
4.4.2變量的存儲類別系統(tǒng)區(qū)用戶區(qū)················動態(tài)存儲區(qū)靜態(tài)存儲區(qū)數(shù)據(jù)區(qū)程序區(qū)代碼區(qū)語言程序設(shè)計第四章函數(shù)與編譯預處理C變量的存儲類別有auto、register、static和exturn四種。auto是局部變量的默認存儲類別。register指定為變量分配寄存器,而不是內(nèi)存區(qū)域,就是使用CPU的寄存器存放變量的值。auto、register只能用于定義局部變量。exturn是外部(全局)變量的默認存儲類別。static既可以用于定義局部變量,也可以用于定義全局變量。static用于定義局部變量時,出了定義該變量的那個程序塊(函數(shù)體或復合語句)其變量值仍然保留在內(nèi)存中;如果被定義的變量未賦初值,系統(tǒng)自動予以置0。static用于定義全局變量時,其變量只能被定義它的那個文件中引用,其它文件不可使用它。此時定義的變量也稱之為內(nèi)部變量。4.4變量的作用域和存儲類別
4.4.2變量的存儲類別語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4.2.1靜態(tài)存儲的局部變量運用舉例【例4-9】分別求出1、2、3、4和5的階乘并輸出。其程序及其運行結(jié)果如下:voidfact(intN){staticlongs=1;/*s是靜態(tài)存儲的局部變量*/s=s*N;
printf("%d!=%ld\n",N,s);}voidmain(){intk;
for(k=1;k<=5;k++)fact(k);}4.4變量的作用域和存儲類別
4.4.2變量的存儲類別Ex4_9.c演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4.2.2動態(tài)存儲的局部變量運用舉例【例4-10】把上述程序函數(shù)fact()中的staticlongs=1;語句,改成longs=1;則程序及其運行結(jié)果如下:voidfact(intN){longs=1;/*s是動態(tài)存儲的局部變量*/s=s*N;
printf("%d!=%ld\n",N,s);}voidmain(){intk;
for(k=1;k<=5;k++)fact(k);}4.4變量的作用域和存儲類別
4.4.2變量的存儲類別Ex4_10.c演示語言程序設(shè)計第四章函數(shù)與編譯預處理C在TurboC系統(tǒng)大型程序開發(fā)中傳統(tǒng)的做法有兩種辦法:一是在主函數(shù)文件(即main函數(shù)所在的文件)的首部,利用文件包含宏命令#include指定要包含的其它各個程序文件。然后編譯連接主函數(shù)文件,生成可執(zhí)行的程序文件(擴展名為.EXE)。二是編寫一個工程文件(其擴展名為.prj),在工程文件中指定組成工程文件的各個程序文件位置與名稱,然后編譯連接這個工程文件,生成可執(zhí)行的程序文件(擴展名為.EXE);具體方法請看下面的例子。4.4變量的作用域和存儲類別
4.4.2變量的存儲類別語言程序設(shè)計第四章函數(shù)與編譯預處理C【例4-11】把計算AN的函數(shù)fpow存放在一個文件(如Ex4_11_1.c)中,供其它函數(shù)調(diào)用。調(diào)用它的程序存放在另一個文件(如Ex4_11_2.c)中,其程序如下:/*Ex4_11_1.c文件內(nèi)容*/#include"stdio.h"externintN;/*聲明外部變量N*/externfloatS,A;/*聲明外部變量S和A*/voidfpow()/*計算A的N次冪并存放到全局變量S中,即S=AN*/{intk;S=1;for(k=1;k<=N;k++)S=S*A;}4.4變量的作用域和存儲類別
4.4.2變量的存儲類別Ex4_11_2.c演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4變量的作用域和存儲類別
4.4.2變量的存儲類別/*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*/語言程序設(shè)計第四章函數(shù)與編譯預處理C由以上兩個程序文件構(gòu)成的工程文件(Myproj.prj)如下:/*工程文件Myproj.prj內(nèi)容*/d:\Clessons\Example\Ex4_11_1.cd:\Clessons\Example\Ex4_11_2.c工程文件Myproj.prj的編譯選項中的PrimaryCfile必須指定為main函數(shù)所在文件的名稱。如圖4.6所示,指定為D盤下的Ex4_11_2.c即d:\Clessons\Example\Ex4_11_2.c4.4變量的作用域和存儲類別
4.4.2變量的存儲類別
語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4.2.4靜態(tài)外部變量(文件內(nèi)部變量)的應(yīng)用舉例如果把【例4-11】程序改寫成如【例4-12】所示:【例4-12】/*Ex4_12_1.c文件內(nèi)容*/#include"stdio.h"externintN;/*聲明外部變量N*/externfloatS,A;/*聲明外部變量S和A*/voidfpow()/*計算A的N次冪并存放到全局變量S中,即S=AN*/{intk;S=1;for(k=1;k<=N;k++)S=S*A;}4.4變量的作用域和存儲類別
4.4.2變量的存儲類別Myroj1.prj演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4變量的作用域和存儲類別
4.4.2變量的存儲類別/*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); }當編譯該程序文件件Myproj1.prj時,系統(tǒng)會給出如下的錯誤:LinkerError:Undefinedsymbol'_N'inmoduleEX4_12_1.C!語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4變量的作用域和存儲類別4.4.2變量的存儲類別但是如果把Ex4_12_2.c文件內(nèi)容改成如【例4-13】所示【例4-13】利用文件包含的方法實現(xiàn)全局變量的共享。/*Ex4_13_1.c文件內(nèi)容*/#include"stdio.h"externintN;/*聲明外部變量N*/externfloatS,A;/*聲明外部變量S和A*/voidfpow()/*計算A的N次冪并存放到全局變量S中,即
S=AN*/{intk;S=1;for(k=1;k<=N;k++)S=S*A;}Ex4_13_2.c演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4變量的作用域和存儲類別
4.4.2變量的存儲類別/*Ex4_13_2.c文件內(nèi)容*/#include“d:\Clessons\Example\ex4_13_1.c"/*在文件頭部把c:\Ex4_13_1.c包含進來*/staticintN;/*定義外部變量N*/floatS;/*定義外部變量S*/floatA;/*定義外部變量A*/voidmain(){printf("InputvaluesintoA&N,please!");
scanf("%f%d",&A,&N); fpow();printf("\nS=%f\n",S); }語言程序設(shè)計第四章函數(shù)與編譯預處理C4.4變量的作用域和存儲類別
4.4.2變量的存儲類別在文件Ex4_13_2.c的頭部,把c:\Ex4_13_1.c包含進來,相當于把c:\Ex4_13_1.c文件的內(nèi)容放在Ex4_13_2.c文件的前面,即把c:\Ex4_13_1.c文件的內(nèi)容合并到文件Ex4_13_2.c中,這樣,只需對Ex4_13_2.c進行編譯連接,就會生成與Ex4_13_2同名的可執(zhí)行文件Ex4_13_2.exe。既不需要建立工程文件,盡管在Ex4_13_2.c文件中把N定義成靜態(tài)整型變量,也不會像【例4-12】那樣出現(xiàn)錯誤!這是為什么呢?請同學思考。語言程序設(shè)計第四章函數(shù)與編譯預處理C4.5內(nèi)部函數(shù)與外部函數(shù)與指定外部變量的靜態(tài)存儲類別類似,函數(shù)也有文件內(nèi)部函數(shù)和可供其它文件調(diào)用的外部函數(shù)兩種類型。如果在一個源文件中定義的函數(shù)只能被本文件中的函數(shù)調(diào)用,而不能被同一源程序其它文件中的函數(shù)調(diào)用,這種函數(shù)稱為內(nèi)部函數(shù)。定義內(nèi)部函數(shù)的一般形式是:static類型說明符函數(shù)名(形參表)例如:staticint
f(int
a,intb)語言程序設(shè)計第四章函數(shù)與編譯預處理C4.5內(nèi)部函數(shù)與外部函數(shù)內(nèi)部函數(shù)也稱為靜態(tài)函數(shù)。但此處靜態(tài)static的含義已不是指存儲方式,而是指對函數(shù)的調(diào)用范圍只局限于定義它的文件中。因此在不同的源文件中定義同名的靜態(tài)函數(shù)不會引起混淆。外部函數(shù)是指在定義函數(shù)時未指定關(guān)鍵字static。這樣的函數(shù)可供任一C文件中的函數(shù)對它調(diào)用。定義外部函數(shù)的一般形式為:[extern]類型說明符函數(shù)名(形參表)例如:externint
f(int
a,intb)如在函數(shù)定義中沒有指明extern或static則隱含為extern。如果一個文件中要調(diào)用外部函數(shù),必須在主調(diào)文件中要對被調(diào)用的函數(shù)進行顯式的extern說明。語言程序設(shè)計第四章函數(shù)與編譯預處理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)容如下:
語言程序設(shè)計第四章函數(shù)與編譯預處理C4.5內(nèi)部函數(shù)與外部函數(shù)由于func()被定義成prg2.c文件的內(nèi)部函數(shù),該函數(shù)只能在prg2.c文件的內(nèi)部使用,不能被其它文件的函數(shù)調(diào)用,因此prg1.c文件的第1行對函數(shù)func()的聲明是錯誤的。而在prg1.c文件中的max(inta,intb)被定義成外部函數(shù),不僅在定義它的文件prg1.c中可以調(diào)用它,而且其它文件中也可以調(diào)用它。為了使得prg2.c文件的第6行能夠調(diào)用外部函數(shù)max,還必須在第6行之前對它進行聲明。prg2.c文件的第1行就是起著這樣的作用。語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)C語言中的函數(shù)既可以像4.3.5節(jié)所述的那樣可以嵌套調(diào)用,也可以遞歸調(diào)用。函數(shù)體內(nèi)出現(xiàn)調(diào)用自身的語句的函數(shù),稱之為遞歸函數(shù)。函數(shù)的遞歸調(diào)用是指一個函數(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語言程序設(shè)計第四章函數(shù)與編譯預處理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語言程序設(shè)計第四章函數(shù)與編譯預處理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ù)將反復調(diào)用其自身。每調(diào)用一次就進入新的一層。例如有函數(shù)f如下:intfun(inta){intb=0,c;b++;c=f(b);returnc;}這個函數(shù)是一個遞歸函數(shù)。但是運行該函數(shù)將無休止地調(diào)用其自身,這當然是不正確的。為了防止遞歸調(diào)用無休止地進行,必須在函數(shù)內(nèi)有終止遞歸調(diào)用的手段。常用的辦法是加條件判斷,滿足某種條件后就不再作遞歸調(diào)用,然后逐層返回。語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)【例4-15】用遞歸法計算N!可用下述公式表示
N!=1當N≤1(遞歸結(jié)束條件)N*(N-1)!當N>1為了便于編寫程序,我們設(shè)計一個變量N的函數(shù)F(N)如下:F(N)=1當N≤1(遞歸結(jié)束條件)N*F(N-1)當N>1語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)【例4-15】用遞歸法計算N!可用下述公式表示
按上述公式對應(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演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)程序說明:程序中給出的函數(shù)F(intN)是一個遞歸函數(shù)。主函數(shù)調(diào)用F(N)后即進入函數(shù)F(N)執(zhí)行,如果N=0或N=1時都將結(jié)束函數(shù)的執(zhí)行,否則就遞歸調(diào)用函數(shù)自身。由于每次遞歸調(diào)用的實參為N-1,即把N-1的值賦予形參N,最后當N-1的值為1時再作遞歸調(diào)用,形參N的值也為1,將使遞歸終止。然后可逐層退回。設(shè)執(zhí)行本程序時輸入為5,即求5!。在主函數(shù)中的調(diào)用語句即為S=F(N);,進入F函數(shù)后,由于N=5,執(zhí)行N*F(N-1),即5*F(5-1)。該語句對F作遞歸調(diào)用即F(4)。逐次遞歸展開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。進行五次遞歸調(diào)用后,F(xiàn)函數(shù)形參取得的值變?yōu)?,故不再繼續(xù)遞歸調(diào)用而開始逐層返回主調(diào)函數(shù)。F(5)的函數(shù)調(diào)用計算過程如下圖所示。圖中實線表示調(diào)用函數(shù),虛線表示函數(shù)結(jié)束返回。語言程序設(shè)計第四章函數(shù)與編譯預處理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)用計算過程語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)一個問題的求解能否設(shè)計成遞歸函數(shù),往往取決于對問題本身描述。如果問題的描述具有如下的三個條件,就可用遞歸函數(shù)求解。1、問題的描述分成兩部分,其中前一部分描述問題求解的結(jié)束條件,后一部分與原始的描述相似或相同;2、后一部分的描述是原始問題的簡化;3、后一部分的描述趨于問題求解的結(jié)束。N階乘問題的求解過程(算法),用自然語言可以描述如下:1、N=0或1時,其階乘的值是1,2、N>1時,N的階乘值是N與(N-1)階乘的積,3、因為N的值經(jīng)過若干次減1的運算,使得N趨于結(jié)束條件0或1。顯然,這是對問題的遞歸描述,且滿上述的三個條件,因此可以設(shè)計成遞歸函數(shù)來求解。語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)【例4-16】編寫遞歸函數(shù)求解斐波那契數(shù)列的第N項的值。斐波那契數(shù)列的組成規(guī)律是:第一項是0,第二項是1,從第三項起每一項都等于緊鄰的前兩項之和。即數(shù)列的組成如下:0,1,1,2,3,5,8……。根據(jù)問題的描述,建立如下的數(shù)學模型
Fibo(N)=0N=11N=2Fibo(N-1)+Fibo(N-2)N>2語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)有了以上數(shù)學模型,不難寫出如下遞歸函數(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演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)【例4-17】求兩個整數(shù)M和N的最大公約數(shù),按照中國古代的九章算術(shù)記載的輾轉(zhuǎn)相除法描述:令R=M%N;當R=0時,則N就是M,N兩數(shù)的最大公約數(shù)(N即為所求),終止計算;否則(即R≠0),求N和R的最大公約數(shù)(即求N和M%N的最大公約數(shù))。根據(jù)上述,可以建立相應(yīng)的數(shù)學模型:Gcd(M,N)=N當M%N=0Gcd(N,M%N)當M%N≠0語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)根據(jù)上述的數(shù)學模型,我們既可以用遞歸函數(shù)實現(xiàn)求解,也可以用迭代的方法編寫函數(shù)求解。下面我們分寫出各自的函數(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;}語言程序設(shè)計第四章函數(shù)與編譯預處理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演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)【例4-18】猩猩剝花生問題。動物園管理員第一天給了大猩猩一堆花生。當天這些猩猩撥了三分之二多一只,第二天在剩下的花生中又撥了三分之二多一只。此后每天都撥了前一天剩下的三分之二多一只。到了第10天早上,只剩了一只花生。求動物園管理員給了大猩猩多少只花生?Penut(day)=1day=10Penut(day)=3*(Penut(day+1)+1)0<day<10語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)根據(jù)遞推公式Xn-1=3*(Xn+1)編寫函數(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演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)由【例4-17】和【例4-18】我們可以看出,一個問題的求解算法往往有多種。究竟采用什么算法更好,這不是本書討論的話題。但是有一點,在既可以采用遞歸也可以采用非遞歸算法的情況下,盡量不用遞歸方法。因為遞歸深度過大,用于存放返回信息的堆棧耗用大量的內(nèi)存,可能會造成內(nèi)存不夠用的困境。在遞歸深度不大,采用遞歸使得問題求解的描述更易理解和實現(xiàn)的情況下,采用遞歸是一種有效的方法。語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)【例4-19】編寫程序求漢諾塔盤子移動的步驟。本題算法分析如下,設(shè)A上有n個盤子。移動的過程可分解為三個步驟:第一步借助于C座,把A上的n-1個圓盤移到B上;第二步把A上的最后一個圓盤移到C上;第三步借助于A座,把B上的n-1個圓盤移到C上;其中第一步和第三步是類同的。當n=3時,第一步和第三步又分解為類同的三步,即把n-1個圓盤從一個座移到另一個座上,這里的n=n-1。顯然這是一個遞歸過程,據(jù)此可把算法表述成:Move(N,A,B,C)
=Move(N-1,A,C,B)當N>1Move(N-1,B,A,C)當N>1A→C當N=1語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)根據(jù)上述算法模型可編程如下:#include"stdio.h"voidmove(int
n,char
A,char
B,charC)/*將A座上的n個圓盤移到C座的函數(shù)*/{
if(n==1)/*當n=1時,直接將A座上的盤子移到C座上*/printf("%c-->%c\n",A,C);
else{/*當n>1時,借助于C座,將A座上的n-1個盤子移到B座上*/move(n-1,A,C,B);
printf("%c-->%c\n",A,C);/*直接將A座上最后一個盤子,移到C座上*/move(n-1,B,A,C);/*借助于A座,將B座上的n-1個盤子移到C座上*/}}Ex4_19.c演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)main(){intn;printf("\ninputnumber:\n");scanf("%d",&n);printf("thesteptomoving%2ddiskes:\n",n);move(n,'A','B','C');}語言程序設(shè)計第四章函數(shù)與編譯預處理C4.6遞歸函數(shù)程序說明:move函數(shù)是一個遞歸函數(shù),它有四個形參n,A,B,C。n表示圓盤數(shù),A,B,C分別表示三個座。move函數(shù)的功能是把A上的n個圓盤移動到C上。當n==1時,直接把A上的圓盤移至C上,輸出A→C。如n≠1則分為三步:遞歸調(diào)用move函數(shù),把n-1個圓盤從A移到B;輸出A→C;遞歸調(diào)用move函數(shù),把n-1個圓盤從B移到C。在遞歸調(diào)用過程中n=n-1,故n的值逐次遞減,最后n=1時,終止遞歸,逐層返回。語言程序設(shè)計第四章函數(shù)與編譯預處理C4.7編譯預處理ANSIC規(guī)定可以在C源程序中插入一些傳給編譯程序的預處理命令,由于這些命令不是C語言的組成部分,不能直接進行編譯,通常在編譯之前預先進行處理,所以在C語言源程序中,凡是以“#”號開頭的一律作為編譯預處理命令對待。例如:"#definePAI3.14159",預處理時將程序中所有的PAI置換為指定的字符串3.14159。"#include<math.h>",預處理時就用math.h文件中的實際內(nèi)容代替該行命令,然后將處理結(jié)果和源程序一起進行編譯,這就擴充了程序的設(shè)計環(huán)境,提高了編程效率。語言程序設(shè)計第四章函數(shù)與編譯預處理C4.7編譯預處理編譯預處理是編譯系統(tǒng)的一個組成部分,主要有三類命令:宏定義#define、#undef預處理文件包含#include
條件編譯#if、#ifdef、#ifndef、#else、#elif、#endif預處理命令的特點:(1)命令以#開頭,表示編譯預處理命令行的開始標志;(2)每條命令獨占一行,即每一行只能有一條編譯預處理命令;(3)行末不能有";"號。語言程序設(shè)計第四章函數(shù)與編譯預處理C4.7編譯預處理1.不帶參數(shù)的宏定義用一個指定的名字代表一個字符串,一般形式為:#define宏名字符串功能:編譯預處理時,將程序中所有的該宏名(標識符)用該字符串替換。其中:(1)#define是宏定義命令。(2)宏名是用戶定義的標識符,不得與程序中其他標識符同名。宏名中不能含空格,宏名與字符串之間用空格分隔開。字符串兩側(cè)沒有雙引號時,串中不能含空格。(3)如字符串加了雙引號,雙引號將一起參與替換。(4)預處理時用字符串替換宏名的過程稱為宏替換,或宏代換、宏展開。
4.7.1宏定義與宏替換語言程序設(shè)計第四章函數(shù)與編譯預處理C4.7編譯預處理【例4-20】通過鍵盤輸入半徑的值,求圓的周長、面積和球的表面積、體積。#definePAI3.1415926#defineMESSAGE1"這是一個宏定義示例"#defineMESSAGE2"請輸入半徑"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演示語言程序設(shè)計第四章函數(shù)與編譯預處理C4.7編譯預處理上述程序經(jīng)過預處理(即宏替換)之后,源程序的內(nèi)容如下:main(){floatS,R,L,V,T;printf("這是一個宏定義示例");printf("%s","請輸入半徑");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);}預處理后,宏名PAI、MESSAGE1和MESSAGE2不見了,相應(yīng)處分別被替換為3.1415926、"這是一個宏定義示例"和"請輸入半徑"。語言程序設(shè)計第四章函數(shù)與編譯預處理
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025至2030年中國超薄頻閃警燈市場分析及競爭策略研究報告
- 2025至2030年中國緊急切斷手動泄壓閥市場分析及競爭策略研究報告
- 2025至2030年中國鹽酸左氧氟沙星注射液市場分析及競爭策略研究報告
- 2025至2030年中國環(huán)保解毒節(jié)水洗菜機市場分析及競爭策略研究報告
- 2025至2030年中國液體貯運容器市場分析及競爭策略研究報告
- 2025至2030年中國氣管夾頭市場分析及競爭策略研究報告
- 2025至2030年中國智能高頻開關(guān)壁掛電源市場分析及競爭策略研究報告
- 2025至2030年中國打印機墨盒專用海綿市場分析及競爭策略研究報告
- 2025至2030年中國布制復合材料市場分析及競爭策略研究報告
- 2025至2030年中國夾心威化餅菠蘿派市場分析及競爭策略研究報告
- 綠化監(jiān)理養(yǎng)護記錄范本
- 電纜橋架技術(shù)規(guī)范書
- 廣東藥科大學 作業(yè)紙 GDPU廣藥
- 成套設(shè)備電氣技術(shù)要求
- 《HSK標準教程3》第5課課件
- 戰(zhàn)術(shù)基礎(chǔ)動作教案
- 公益協(xié)會財務(wù)管理制度3篇-2023修改整理
- 高中英語3500單詞(表格)只有中文
- 公司理財-羅斯(完整版)
- 改變觀念提高效率課件
- 立責于心履責于行全面落實企業(yè)安全生產(chǎn)主體責任課件
評論
0/150
提交評論