C程序設(shè)計教程課件第7章_第1頁
C程序設(shè)計教程課件第7章_第2頁
C程序設(shè)計教程課件第7章_第3頁
C程序設(shè)計教程課件第7章_第4頁
C程序設(shè)計教程課件第7章_第5頁
已閱讀5頁,還剩71頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

為什么要用函數(shù)

VS.使用函數(shù)可使程序清晰、精煉、簡單、靈活。函數(shù)就是功能。每一個函數(shù)用來實現(xiàn)一個特定的功能。函數(shù)名應(yīng)反映其代表的功能。在設(shè)計較大程序時,往往把它分為若干個程序模塊,每一個模塊包括一個或多個函數(shù),每個函數(shù)實現(xiàn)一個特定的功能。一個C程序可由一個主函數(shù)和若干個其他函數(shù)構(gòu)成。由主函數(shù)調(diào)用其他函數(shù),其他函數(shù)也可以互相調(diào)用。為什么要用函數(shù)【例7.1】想輸出以下的結(jié)果,用函數(shù)調(diào)用實現(xiàn)。#include<stdio.h>intmain(){ voidprint_star(); //聲明print_star函數(shù)

voidprint_message(); //聲明print_message函數(shù)

print_star(); //調(diào)用print_star函數(shù)

print_message(); //print_message函數(shù)

print_star(); //調(diào)用print_star函數(shù)

return0;}voidprint_star() //定義print_star函數(shù){ printf("******************\n"); //輸出一行*號}voidprint_message() //定義print_message函數(shù){ printf("Howdoyoudo!\n"); //輸出一行文字信息}print_star和print_message都是用戶定義的函數(shù)名,分別用來輸出一排“*”號和一行文字信息。在定義這兩個函數(shù)時指定函數(shù)的類型為void,意為函數(shù)無類型,即無函數(shù)值,也就是說,執(zhí)行這兩個函數(shù)后不會把任何值帶回main函數(shù)。在程序中,定義print_star函數(shù)和print_message函數(shù)的位置是在main函數(shù)的后面,在這種情況下,應(yīng)當(dāng)在main函數(shù)之前或main函數(shù)中的開頭部分,對以上兩個函數(shù)進行“聲明”。函數(shù)聲明的作用是把有關(guān)函數(shù)的信息(函數(shù)名、函數(shù)類型、函數(shù)參數(shù)的個數(shù)與類型)通知編譯系統(tǒng),以便在編譯系統(tǒng)對程序進行編譯時,在進行到main函數(shù)調(diào)用print_star()和print_message()時知道它們是函數(shù)而不是變量或其他對象。此外,還對調(diào)用函數(shù)的正確性進行檢查(如類型、函數(shù)名、參數(shù)個數(shù)、參數(shù)類型等是否正確)。為什么要用函數(shù)(1)一個C程序由一個或多個程序模塊組成,每一個程序模塊作為一個源程序文件。較大的程序,可分別放在若干個源文件中。這樣便于分別編寫和編譯,提高調(diào)試效率。一個源程序文件可以為多個C程序共用。(2)一個源程序文件由一個或多個函數(shù)以及其他有關(guān)內(nèi)容(如指令、數(shù)據(jù)聲明與定義等)組成。一個源程序文件是一個編譯單位,在程序編譯時是以源程序文件為單位進行編譯的,而不是以函數(shù)為單位進行編譯的。(3)C程序的執(zhí)行是從main函數(shù)開始的,如果在main函數(shù)中調(diào)用其他函數(shù),在調(diào)用后流程返回到main函數(shù),在main函數(shù)中結(jié)束整個程序的運行。(4)所有函數(shù)都是平行的,即在定義函數(shù)時是分別進行的,是互相獨立的。一個函數(shù)并不從屬于另一個函數(shù),即函數(shù)不能嵌套定義。函數(shù)間可以互相調(diào)用,但不能調(diào)用main函數(shù)。main函數(shù)是被操作系統(tǒng)調(diào)用的。(5)從用戶使用的角度看,函數(shù)有兩種。①庫函數(shù),它是由系統(tǒng)提供的,用戶不必自己定義,可直接使用它們。應(yīng)該說明,不同的C語言編譯系統(tǒng)提供的庫函數(shù)的數(shù)量和功能會有一些不同,當(dāng)然許多基本的函數(shù)是共同的。②用戶自己定義的函數(shù)。它是用以解決用戶專門需要的函數(shù)。(6)從函數(shù)的形式看,函數(shù)分兩類。①無參函數(shù)。在調(diào)用無參函數(shù)時,主調(diào)函數(shù)不向被調(diào)用函數(shù)傳遞數(shù)據(jù)。②有參函數(shù)。在調(diào)用函數(shù)時,主調(diào)函數(shù)在調(diào)用被調(diào)用函數(shù)時,通過參數(shù)向被調(diào)用函數(shù)傳遞數(shù)據(jù)。定義函數(shù)為什么定義函數(shù)定義函數(shù)應(yīng)包括以下幾個內(nèi)容:(1)指定函數(shù)的名字,以便以后按名調(diào)用。(2)指定函數(shù)的類型,即函數(shù)返回值的類型。(3)指定函數(shù)的參數(shù)的名字和類型,以便在調(diào)用函數(shù)時向它們傳遞數(shù)據(jù)。對無參函數(shù)不需要這項。(4)指定函數(shù)應(yīng)當(dāng)完成什么操作,也就是函數(shù)是做什么的,即函數(shù)的功能。這是最重要的,是在函數(shù)體中解決的。C語言要求,在程序中用到的所有函數(shù),必須“先定義,后使用”。定義函數(shù)的方法類型名函數(shù)名(){

函數(shù)體}函數(shù)名后面括號內(nèi)的void表示“空”,即函數(shù)沒有參數(shù)。函數(shù)體包括聲明部分和語句部分。在定義函數(shù)時要用“類型標(biāo)識符”(即類型名)指定函數(shù)值的類型,即指定函數(shù)帶回來的值的類型。定義無參函數(shù)類型名函數(shù)名(void){

函數(shù)體}或類型名函數(shù)名(形式參數(shù)表列){

函數(shù)體}定義有參函數(shù)intmax(intx,inty){ intz; //聲明部分

z=x>y?x:y; //執(zhí)行語句部分

return(z);}類型名函數(shù)名(){}定義空函數(shù)函數(shù)體為空,什么也不做。調(diào)用函數(shù)函數(shù)調(diào)用的形式函數(shù)名(實參表列)print_star(); //調(diào)用無參函數(shù)c=max(a,b); //調(diào)用有參函數(shù)1.函數(shù)調(diào)用語句把函數(shù)調(diào)用單獨作為一個語句。如printf_star();這時不要求函數(shù)帶回值,只要求函數(shù)完成一定的操作。2.函數(shù)表達式函數(shù)調(diào)用出現(xiàn)在另一個表達式中,如c=max(a,b);

這時要求函數(shù)帶回一個確定的值以參加表達式的運算。3.函數(shù)參數(shù)函數(shù)調(diào)用作為另一個函數(shù)調(diào)用時的實參。如m=max(a,max(b,c));,又如:printf(″%d″,max(a,b));形式參數(shù)和實際參數(shù)在調(diào)用有參函數(shù)時,主調(diào)函數(shù)和被調(diào)用函數(shù)之間有數(shù)據(jù)傳遞關(guān)系。在定義函數(shù)時函數(shù)名后面括號中的變量名稱為“形式參數(shù)”(簡稱“形參”)或“虛擬參數(shù)”。在主調(diào)函數(shù)中調(diào)用一個函數(shù)時,函數(shù)名后面括號中的參數(shù)稱為“實際參數(shù)”(簡稱“實參”)。實際參數(shù)可以是常量、變量或表達式,但要求它們有確定的值。實參與形參的類型應(yīng)相同或賦值兼容。賦值兼容是指實參與形參類型不同時能按不同類型數(shù)值的賦值規(guī)則進行轉(zhuǎn)換。實參和形參間的數(shù)據(jù)傳遞【例7.2】輸入兩個整數(shù),要求輸出其中值較大者。要求用函數(shù)來找到大數(shù)。#include<stdio.h>intmain(){ intmax(intx,inty);

//對max函數(shù)的聲明

inta,b,c; printf("pleaseentertwointegernumbers:");//提示輸入數(shù)據(jù)

scanf("%d,%d",&a,&b); //輸入兩個整數(shù)

c=max(a,b);

//調(diào)用max函數(shù),有兩個實參。大數(shù)賦給變量c printf("maxis%d\n",c); //輸出大數(shù)c return0;}intmax(intx,inty)

//定義max函數(shù),有兩個參數(shù){ intz; //定義臨時變量z z=x>y?x:y; //把x和y中大者賦給z

return(z);

//把z作為max函數(shù)的值帶回main函數(shù)}定義函數(shù),名為max,函數(shù)類型為int。指定兩個形參x和y,形參的類型為int。主函數(shù)中包含了一個函數(shù)調(diào)用max(a,b)。max后面括號內(nèi)的a和b是實參。a和b是在main函數(shù)中定義的變量,x和y是函數(shù)max的形式參數(shù)。通過函數(shù)調(diào)用,在兩個函數(shù)之間發(fā)生數(shù)據(jù)傳遞,實參a和b的值傳遞給形參x和y,在max函數(shù)中把x和y中的大者賦給變量z,z的值作為函數(shù)值返回main函數(shù),賦給變量c。c=max(a,b); (main函數(shù))intmax(intx,inty) (max函數(shù)){ intz; z=x>y?x:y; return(z);}在調(diào)用函數(shù)過程中發(fā)生的實參與形參間的數(shù)據(jù)傳遞稱為“虛實結(jié)合”。函數(shù)調(diào)用的過程(1)在定義函數(shù)中指定的形參,在未出現(xiàn)函數(shù)調(diào)用時,它們并不占內(nèi)存中的存儲單元。在發(fā)生函數(shù)調(diào)用時,函數(shù)的形參才被臨時分配內(nèi)存單元。(2)將實參的值傳遞給對應(yīng)形參。(3)在執(zhí)行函數(shù)期間,由于形參已經(jīng)有值,就可以利用形參進行有關(guān)的運算。(4)通過return語句將函數(shù)值帶回到主調(diào)函數(shù)。應(yīng)當(dāng)注意返回值的類型與函數(shù)類型一致。如果函數(shù)不需要返回值,則不需要return語句。這時函數(shù)的類型應(yīng)定義為void類型。(5)調(diào)用結(jié)束,形參單元被釋放。注意:實參單元仍保留并維持原值,沒有改變。如果在執(zhí)行一個被調(diào)用函數(shù)時,形參的值發(fā)生改變,不會改變主調(diào)函數(shù)的實參的值。因為實參與形參是兩個不同的存儲單元。注意實參向形參的數(shù)據(jù)傳遞是“值傳遞”,單向傳遞,只能由實參傳給形參,而不能由形參傳給實參。實參和形參在內(nèi)存中占有不同的存儲單元,實參無法得到形參的值。函數(shù)的返回值(1)函數(shù)的返回值是通過函數(shù)中的return語句獲得的。一個函數(shù)中可以有一個以上的return語句,執(zhí)行到哪一個return語句,哪一個return語句就起作用。return語句后面的括號可以不要,如“returnz;”與“return(z);”等價。return后面的值可以是一個表達式。(2)函數(shù)值的類型。函數(shù)值的類型在定義函數(shù)時指定。(3)在定義函數(shù)時指定的函數(shù)類型一般應(yīng)該和return語句中的表達式類型一致。如果函數(shù)值的類型和return語句中表達式的值不一致,則以函數(shù)類型為準。對數(shù)值型數(shù)據(jù),可以自動進行類型轉(zhuǎn)換。即函數(shù)類型決定返回值的類型。(4)對于不帶回值的函數(shù),應(yīng)當(dāng)用定義函數(shù)為“void類型”(或稱“空類型”)。這樣,系統(tǒng)就保證不使函數(shù)帶回任何值,即禁止在調(diào)用函數(shù)中使用被調(diào)用函數(shù)的返回值。此時在函數(shù)體中不得出現(xiàn)return語句。通常,希望通過函數(shù)調(diào)用使主調(diào)函數(shù)能得到一個確定的值,這就是函數(shù)值(函數(shù)的返回值)。intmax(floatx,floaty) //函數(shù)值為整型charletter(charc1,charc2) //函數(shù)值為字符型doublemin(intx,inty) //函數(shù)值為雙精度型函數(shù)的返回值【例7.3】將例7.2稍作改動,將在max函數(shù)中定義的變量z改為float型。函數(shù)返回值的類型與指定的函數(shù)類型不同,分析其處理方法。max函數(shù)的形參是float型,實參也是float型,在main函數(shù)中輸入給a和b的值是1.5和2.6。在調(diào)用max(a,b)時,把a和b的值1.5和2.6傳遞給形參x和y。執(zhí)行函數(shù)max中的條件表達式“z=x>y?x:y”,使得變量z得到的值為2.6。現(xiàn)在出現(xiàn)了矛盾:函數(shù)定義為int型,而return語句中的z為float型,要把z的值作為函數(shù)的返回值,二者不一致。怎樣處理呢?按賦值規(guī)則處理,先將z的值轉(zhuǎn)換為int型,得到2,它就是函數(shù)得到的返回值。如果將main函數(shù)中的c改為float型,用%f格式符輸出,輸出2.000000。因為調(diào)用max函數(shù)得到的是int型,函數(shù)值為整數(shù)2。#include<stdio.h>intmain(){ intmax(floatx,floaty);

floata,b; intc;

scanf("%f,%f",&a,&b);

c=max(a,b); printf("maxis%d\n",c); return0;}intmax(floatx,floaty){ floatz; //z為實型變量 z=x>y?x:y;

return(z); }對被調(diào)用函數(shù)的聲明和函數(shù)原型在一個函數(shù)中調(diào)用另一個函數(shù)(即被調(diào)用函數(shù))需要具備如下條件:(1)首先被調(diào)用的函數(shù)必須是已經(jīng)定義的函數(shù)(是庫函數(shù)或用戶自己定義的函數(shù))。(2)如果使用庫函數(shù),應(yīng)該在本文件開頭用#include指令將調(diào)用有關(guān)庫函數(shù)時所需用到的信息“包含”到本文件中來。(3)如果使用用戶自己定義的函數(shù),而該函數(shù)的位置在調(diào)用它的函數(shù)(即主調(diào)函數(shù))的后面(在同一個文件中),應(yīng)該在主調(diào)函數(shù)中對被調(diào)用的函數(shù)作聲明(declaration)。聲明的作用是把函數(shù)名、函數(shù)參數(shù)的個數(shù)和參數(shù)類型等信息通知編譯系統(tǒng),以便在遇到函數(shù)調(diào)用時,編譯系統(tǒng)能正確識別函數(shù)并檢查調(diào)用是否合法。對被調(diào)用函數(shù)的聲明和函數(shù)原型【例7.4】輸入兩個實數(shù),用一個函數(shù)求出它們之和。函數(shù)的聲明和函數(shù)定義中的第1行(函數(shù)首部)基本上是相同的,只差一個分號(函數(shù)聲明比函數(shù)定義中的首行多一個分號)。函數(shù)的首行(即函數(shù)首部)稱為函數(shù)原型(functionprototype)。因為在函數(shù)的首部包含了檢查調(diào)用函數(shù)是否合法的基本信息(它包括了函數(shù)名、函數(shù)值類型、參數(shù)個數(shù)、參數(shù)類型和參數(shù)順序),因此,在函數(shù)調(diào)用時檢查函數(shù)原型是否與函數(shù)聲明一致。這樣就能保證函數(shù)的正確調(diào)用。#include<stdio.h>intmain(){ floatadd(floatx,floaty);

//對add函數(shù)作聲明

floata,b,c; printf("Pleaseenteraandb:"); //提示輸入

scanf("%f,%f",&a,&b); //輸入兩個實數(shù)

c=add(a,b);

//調(diào)用add函數(shù)

printf("sumis%f\n",c); //輸出兩數(shù)之和

return0;}floatadd(floatx,floaty)

//定義add函數(shù){ floatz; z=x+y;

return(z);

//把變量z的值作為函數(shù)值返回}對被調(diào)用函數(shù)的聲明和函數(shù)原型在函數(shù)聲明中的形參名可以省寫,而只寫形參的類型。如果已在文件的開頭(在所有函數(shù)之前),已對本文件中所調(diào)用的函數(shù)進行了聲明,則在各函數(shù)中不必對其所調(diào)用的函數(shù)再作聲明。floatadd(floatx,floaty);floatadd(float,float); //不寫參數(shù)名,只寫參數(shù)類型floatadd(floata,

floatb); //參數(shù)名不用x,y,而用a,b。合法函數(shù)類型函數(shù)名(參數(shù)類型1參數(shù)名1,參數(shù)類型2參數(shù)名2,…,參數(shù)類型n參數(shù)名n);函數(shù)類型函數(shù)名(參數(shù)類型1,參數(shù)類型2,

…,參數(shù)類型n);或注意對函數(shù)的“定義”和“聲明”不是同一回事。函數(shù)的定義是指對函數(shù)功能的確立,包括指定函數(shù)名、函數(shù)值類型、形參及其類型以及函數(shù)體等,它是一個完整的、獨立的函數(shù)單位。而函數(shù)的聲明的作用則是把函數(shù)的名字、函數(shù)類型以及形參的類型、個數(shù)和順序通知編譯系統(tǒng),以便在調(diào)用該函數(shù)時系統(tǒng)按此進行對照檢查,它不包含函數(shù)體。charletter(char,char);floatf(float,float);inti(float,float);//所有函數(shù)之前,且在函數(shù)外部進行函數(shù)聲明intmain(){…}//在main函數(shù)中要調(diào)用letter,f和i函數(shù),不必再對所調(diào)用的這3個函數(shù)進行聲明charletter(charc1,charc2){…} //定義letter函數(shù)floatf(floatx,floaty){…} //定義f函數(shù)inti(floatj,floatk){…} //定義i函數(shù)函數(shù)的嵌套調(diào)用①執(zhí)行main函數(shù)的開頭部分;②遇函數(shù)調(diào)用語句,調(diào)用函數(shù)a,流程轉(zhuǎn)去a函數(shù);③執(zhí)行a函數(shù)的開頭部分;④遇函數(shù)調(diào)用語句,調(diào)用函數(shù)b,流程轉(zhuǎn)去函數(shù)b;⑤執(zhí)行b函數(shù),如果再無其他嵌套的函數(shù),則完成b函數(shù)的全部操作;⑥返回到a函數(shù)中調(diào)用b函數(shù)的位置;⑦繼續(xù)執(zhí)行a函數(shù)中尚未執(zhí)行的部分,直到a函數(shù)結(jié)束;⑧返回main函數(shù)中調(diào)用a函數(shù)的位置;⑨繼續(xù)執(zhí)行main函數(shù)的剩余部分直到結(jié)束。C語言的函數(shù)定義是互相平行、獨立的,也就是說,在定義函數(shù)時,一個函數(shù)內(nèi)不能再定義另一個函數(shù),即不能嵌套定義,但可以嵌套調(diào)用函數(shù),即在調(diào)用一個函數(shù)的過程中,又調(diào)用另一個函數(shù)。main函數(shù) a函數(shù) b函數(shù)①

④調(diào)用a函數(shù)

調(diào)用b函數(shù)

⑤⑨

⑥結(jié)束函數(shù)的嵌套調(diào)用【例7.5】輸入4個整數(shù),找出其中最大的數(shù)。用函數(shù)的嵌套調(diào)用來處理。#include<stdio.h>intmain(){ intmax4(inta,intb,intc,intd); //對max4的函數(shù)聲明

inta,b,c,d,max; printf("Pleaseenter4intergernumbers:"); //提示輸入4個數(shù)

scanf("%d%d%d%d",&a,&b,&c,&d); //輸入4個數(shù)

max=max4(a,b,c,d);//調(diào)用max4函數(shù),得到4個數(shù)中的最大者

printf("max=%d\n",max); //輸出4個數(shù)中的最大者

return0;}intmax4(inta,intb,intc,intd) //定義max4函數(shù){ intmax2(inta,intb); //對max2的函數(shù)聲明

intm; m=max2(a,b); //調(diào)用max2函數(shù),得到a和b中的大者,放在m中

m=max2(m,c);//調(diào)用max2函數(shù),得到a,b,c中的大者,放在m中

m=max2(m,d);//調(diào)用max2函數(shù),得到a,b,c,d中的大者,放在m中

return(m); //把m作為函數(shù)值帶回main函數(shù)}intmax2(inta,intb) //定義max2函數(shù){ if(a>=b) returna; //若a≥b,將a作為函數(shù)返回值

else returnb; //若a<b,將b作為函數(shù)返回值}在主函數(shù)中要調(diào)用max4函數(shù),因此在主函數(shù)的開頭要對max4函數(shù)作聲明。在max4函數(shù)中3次調(diào)用max2函數(shù),因此在max4函數(shù)的開頭要對max2函數(shù)作聲明。由于在主函數(shù)中沒有直接調(diào)用max2函數(shù),因此在主函數(shù)中不必對max2函數(shù)作聲明,只須在max4函數(shù)中作聲明即可。max4函數(shù)執(zhí)行過程:第1次調(diào)用max2函數(shù)得到的函數(shù)值是a和b中的大者,把它賦給變量m,第2次調(diào)用max2得到m和c中的大者,也就是a,b,c中的最大者,再把它賦給變量m。第3次調(diào)用max2得到m和d中的大者,也就是a,b,c,d中的最大者,再把它賦給變量m。這是一種遞推方法,先求出2個數(shù)的大者;再以此為基礎(chǔ)求出3個數(shù)的大者;再以此為基礎(chǔ)求出4個數(shù)的大者。m的值一次一次地變化,直到實現(xiàn)最終要求。(1)可以將max2函數(shù)的函數(shù)體改為只用一個return語句,返回一個條件表達式的值:(2)在max4函數(shù)中,3個調(diào)用max2的語句可以用以下一行代替:甚至可以取消變量m,max4函數(shù)可寫成先調(diào)用“max2(a,b)”,得到a和b中的大者。再調(diào)用“max2(max2(a,b),c)”(其中max2(a,b)為已知),得到a,b,c三者中的大者。最后由“max2(max2(max2(a,b),c),d)”求得a,b,c,d四者中的大者。程序改進intmax2(inta,intb)

//定義max2函數(shù){return(a>=b?a:b);}

//返回條件表達式的值,即a和b中的大者m=max2(max2(max2(a,b),c),d);

//把函數(shù)調(diào)用作為函數(shù)參數(shù)intmax4(inta,intb,intc,intd){

intmax2(inta,intb);

//對max2的函數(shù)聲明

returnmax2(max2(max2(a,b),c),d);}函數(shù)的遞歸調(diào)用函數(shù)的遞歸調(diào)用程序中不應(yīng)出現(xiàn)無終止的遞歸調(diào)用,而只應(yīng)出現(xiàn)有限次數(shù)的、有終止的遞歸調(diào)用,這可以用if語句來控制,只有在某一條件成立時才繼續(xù)執(zhí)行遞歸調(diào)用;否則就不再繼續(xù)。在調(diào)用一個函數(shù)的過程中又出現(xiàn)直接或間接地調(diào)用該函數(shù)本身,稱為函數(shù)的遞歸調(diào)用。intf(intx){ inty,z; z=f(y); //在執(zhí)行f函數(shù)的過程中又要調(diào)用f函數(shù)

return(2*z);}f函數(shù)調(diào)用f函數(shù)直接遞歸f1函數(shù) f2函數(shù)調(diào)用f2函數(shù)

調(diào)用f1函數(shù)間接遞歸函數(shù)的遞歸調(diào)用【例7.6】有5個學(xué)生坐在一起,問第5個學(xué)生多少歲,他說比第4個學(xué)生大2歲。問第4個學(xué)生歲數(shù),他說比第3個學(xué)生大2歲。問第3個學(xué)生,又說比第2個學(xué)生大2歲。問第2個學(xué)生,說比第1個學(xué)生大2歲。最后問第1個學(xué)生,他說是10歲。請問第5個學(xué)生多大。解題思路:age(n)=10 (n=1)age(n)=age(n-1)+2 (n>1)age(5) age(5)=age(4)+2 =18 age(4) age(4) =age(3)+2 =16 age(3) age(3) =age(2)+2 =14 age(2) age(2) =age(1)+2 =12 age(1)=10函數(shù)的遞歸調(diào)用【例7.6】有5個學(xué)生坐在一起,問第5個學(xué)生多少歲,他說比第4個學(xué)生大2歲。問第4個學(xué)生歲數(shù),他說比第3個學(xué)生大2歲。問第3個學(xué)生,又說比第2個學(xué)生大2歲。問第2個學(xué)生,說比第1個學(xué)生大2歲。最后問第1個學(xué)生,他說是10歲。請問第5個學(xué)生多大。#include<stdio.h>intmain(){ intage(intn); //對age函數(shù)的聲明

printf("NO.5,age:%d\n",age(5)); //輸出第5個學(xué)生的年齡

return0;}intage(intn) //定義遞歸函數(shù){ intc; //c用作存放函數(shù)的返回值的變量 if(n==1) //如果n等于1 c=10; //年齡為10 else //如果n不等于1 c=age(n-1)+2;

//年齡是前一個學(xué)生的年齡加2(如第4個學(xué)生年齡是第3個學(xué)生年齡加2) return(c); //返回年齡}注意分析遞歸的終止條件。mainage(n)n=5age(n)n=4age(n)n=3age(n)n=2age(n)n=1age(5)輸出age(5)c=age(4)+2c=age(3)+2c=age(2)+2c=age(1)+2c=10age(5)=18age(4)=16age(3)=14age(2)=12age(1)=10函數(shù)的遞歸調(diào)用【例7.7】用遞歸方法求n!。

#include<stdio.h>intmain(){ intfac(intn); //fac函數(shù)聲明

intn; inty; printf("inputanintegernumber:"); scanf("%d",&n); //輸入要求階乘的數(shù)

y=fac(n); printf("%d!=%d\n",n,y); return0;}intfac(intn) //定義fac函數(shù){ intf; if(n<0) //n不能小于0 printf("n<0,dataerror!"); elseif(n==0||n==1) //n=0或,1時n!=1 f=1; //遞歸終止條件 else f=fac(n-1)*n; //n>1時,n!=n*(n-1) return(f);}mainfac(n)n=5fac(n)n=4fac(n)n=3fac(n)n=2fac(n)n=1fac(5)輸出fac(5)f=fac(4)*5f=fac(3)*4f=fac(2)*3f=fac(1)*2f=1fac(5)=120fac(4)=24fac(3)=6fac(2)=2fac(1)=1注意程序中的變量是int型,如果用VisualC++、GCC以及多數(shù)C編譯系統(tǒng)為int型數(shù)據(jù)分配4個字節(jié),能表示的最大數(shù)為2147483647,當(dāng)n=12時,運行正常,輸出為479001600。如果輸入13,企圖求13!,是得不到預(yù)期結(jié)果的,因為求出的結(jié)果超過了int型數(shù)據(jù)的最大值??蓪,y和fac函數(shù)定義為float或double型。函數(shù)的遞歸調(diào)用【例7.8】Hanoi(漢諾)塔問題。古代有一個梵塔,塔內(nèi)有3個座A,B,C。開始時A座上有64個盤子,盤子大小不等,大的在下,小的在上。有一個老和尚想把這64個盤子從A座移到C座,但規(guī)定每次只允許移動一個盤,且在移動過程中在3個座上都始終保持大盤在下,小盤在上。在移動過程中可以利用B座。要求編程序輸出移動盤子的步驟。A B C解題思路:老和尚會這樣想:假如有另外一個和尚能有辦法將上面63個盤子從一個座移到另一座。那么,問題就解決了。此時老和尚只須這樣做:①命令第2個和尚將63個盤子從A座移到B座;②自己將1個盤子(最底下的、最大的盤子)從A座移到C座;③再命令第2個和尚將63個盤子從B座移到C座。第2個和尚又想:如果有人能將62個盤子從一個座移到另一座,我就能將63個盤子從A座移到B座,他是這樣做的:①命令第3個和尚將62個盤子從A座移到C座;②自己將1個盤子從A座移到B座;③再命令第3個和尚將62個盤子從C座移到B座?!瑼 B C63個盤子①③②A B C移動前解題思路:為便于理解,先分析將A座上3個盤子移到C座上的過程:①將A座上2個盤子移到B座上(借助C座)。②將A座上1個盤子移到C座上。③將B座上2個盤子移到C座上(借助A座)。其中第②步可以直接實現(xiàn)。第①步又可用遞歸方法分解為:

將A座上1個盤子從A座移到C座;將A座上1個盤子從A座移到B座;將C座上1個盤子從C座移到B座。第③步可以分解為:

將B座上1個盤子從B座移到A座上;將B座上1個盤子從B座移到C座上;將A座上1個盤子從A座移到C座上。將以上綜合起來,可得到移動3個盤子的步驟為:A→C,A→B,C→B,A→C,B→A,B→C,A→C。共經(jīng)歷7步。由此可推出:移動n個盤子要經(jīng)歷(2n-1)步。A B C①A B C②A B C③解題思路:由上面的分析可知:將n個盤子從A座移到C座可以分解為以下3個步驟:①將A座上n-1個盤借助C座先移到B座上;②把A座上剩下的一個盤移到C座上;③將n-1個盤從B座借助于A座移到C座上。上面第①步和第③步,都是把n-1個盤從一個座移到另一個座上,采取的辦法是一樣的,只是座的名字不同而已。為使之一般化,可以將第①步和第③步表示為:將one座上n-1個盤移到two座(借助three座)。只是在第①步和第③步中,one,two,three和A,B,C的對應(yīng)關(guān)系不同。對第①步,對應(yīng)關(guān)系是one對應(yīng)A,two對應(yīng)B,three對應(yīng)C。對第③步,是:one對應(yīng)B,two對應(yīng)C,three對應(yīng)A。因此,可以把上面3個步驟分成兩類操作:①將n-1個盤從一個座移到另一個座上(n>1)。這就是大和尚讓小和尚做的工作,它是一個遞歸的過程,即和尚將任務(wù)層層下放,直到第64個和尚為止?!猦anoi函數(shù)②將1個盤子從一個座上移到另一座上。這是大和尚自己做的工作。——move函數(shù)在本程序中,調(diào)用遞歸函數(shù)hanoi,其終止條件為hanoi函數(shù)的參數(shù)n的值等于1。顯然,此時不必再調(diào)用hanoi函數(shù)了,直接執(zhí)行move函數(shù)即可。在本程序中move函數(shù)并未真正移動盤子,而只是輸出移盤的方案(表示從哪一個座移到哪一個座)。#include<stdio.h>intmain(){ voidhanoi(intn,charone,chartwo,charthree);

//對hanoi函數(shù)的聲明

intm; printf("inputthenumberofdiskes:"); scanf("%d",&m); printf("Thesteptomove%ddiskes:\n",m); hanoi(m,'A','B','C');}voidhanoi(intn,charone,chartwo,charthree) //定義hanoi函數(shù)//將n個盤從one座借助two座,移到three座{ voidmove(charx,chary); //對move函數(shù)的聲明

if(n==1) move(one,three); else { hanoi(n-1,one,three,two); move(one,three); hanoi(n-1,two,one,three); }}voidmove(charx,chary) //定義move函數(shù){ printf("%c->%c\n",x,y);}數(shù)組作為函數(shù)參數(shù)形式參數(shù)實在參數(shù)變量常量、變量、表達式、數(shù)組元素數(shù)組數(shù)組數(shù)組元素作為函數(shù)實參數(shù)組元素可以用作函數(shù)實參,但是不能用作形參。因為形參是在函數(shù)被調(diào)用時臨時分配存儲單元的,不可能為一個數(shù)組元素單獨分配存儲單元(數(shù)組是一個整體,在內(nèi)存中占連續(xù)的一段存儲單元)。在用數(shù)組元素作函數(shù)實參時,把實參的值傳給形參,是“值傳遞”方式。數(shù)據(jù)傳遞的方向是從實參傳到形參,單向傳遞。數(shù)組元素作函數(shù)實參【例7.9】輸入10個數(shù),要求輸出其中值最大的元素和該數(shù)是第幾個數(shù)。從鍵盤輸入10個數(shù)給a[0]~a[9]。變量m用來存放當(dāng)前已比較過的各數(shù)中的最大者。開始時設(shè)m的值為a[0],然后依次將m與a[i]比,如果a[i]大于m,就以a[i]的值取代m的原值。下一次以m的新值與下一個a[i]比較。經(jīng)過9輪循環(huán)的比較,m最后的值就是10個數(shù)的最大數(shù)。請注意分析怎樣得到最大數(shù)是10個數(shù)中第幾個數(shù)。當(dāng)每次出現(xiàn)以max(m,a[i])的值取代m的原值時,就把i的值保存在變量n中。n最后的值就是最大數(shù)的序號(注意序號從0開始),如果要輸出“最大數(shù)是10個數(shù)中第幾個數(shù)”,應(yīng)為n+1。因為數(shù)組元素序號從0開始。#include<stdio.h>intmain(){ intmax(intx,inty); //函數(shù)聲明

inta[10],m,n,i; printf("enter10integernumbers:"); for(i=0;i<10;i++) //輸入10個數(shù)給a[0]~a[9] scanf("%d",&a[i]); printf("\n"); for(i=1,m=a[0],n=0;i<10;i++) { if(max(m,a[i])>m) //若max函數(shù)返回的值大于m { m=max(m,a[i]);

//max函數(shù)返回的值取代m原值

n=i; //把此數(shù)組元素的序號記下來,放在n中

} } printf("Thelargestnumberis%d\nitisthe%dthnumber.\n",m,n+1);}intmax(intx,inty) //定義max函數(shù){ return(x>y?x:y); //返回x和y中的大者}一維數(shù)組名作函數(shù)參數(shù)【例7.10】有一個一維數(shù)組score,內(nèi)放10個學(xué)生成績,求平均成績。(1)用數(shù)組名作函數(shù)參數(shù),應(yīng)該在主調(diào)函數(shù)和被調(diào)用函數(shù)分別定義數(shù)組。(2)實參數(shù)組與形參數(shù)組類型必須一致。(3)在定義average函數(shù)時,聲明形參數(shù)組的大小為10,但在實際上,指定其大小是不起任何作用的,因為C語言編譯系統(tǒng)并不檢查形參數(shù)組大小,只是將實參數(shù)組的首元素的地址傳給形參數(shù)組名。(4)形參數(shù)組可以不指定大小,在定義數(shù)組時在數(shù)組名后面跟一個空的方括號。#include<stdio.h>intmain(){ floataverage(floatarray[10]); //函數(shù)聲明

floatscore[10],aver; inti; printf("input10scores:\n"); for(i=0;i<10;i++) scanf("%f",&score[i]); printf("\n"); aver=average(score); //調(diào)用average函數(shù)

printf("averagescoreis%5.2f\n",aver); return0;}floataverage(floatarray[10]) //定義average函數(shù){ inti; floataver,sum=array[0]; for(i=1;i<10;i++) sum=sum+array[i]; //累加學(xué)生成績

aver=sum/10; return(aver);}floataverage(floatarray[])注意用數(shù)組元素作實參時,向形參變量傳遞的是數(shù)組元素的值,而用數(shù)組名作函數(shù)實參時,向形參(數(shù)組名或指針變量)傳遞的是數(shù)組首元素的地址。一維數(shù)組名作函數(shù)參數(shù)【例7.11】有兩個班級,分別有35和30名學(xué)生,調(diào)用average函數(shù),分別求這兩個班的學(xué)生的平均成績。#include<stdio.h>intmain(){ floataverage(floatarray[],intn); floatscore1[5]={98.5,97,91.5,60,55}; //定義長度為5的數(shù)組

floatscore2[10]={67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5};

//定義長度為10的數(shù)組

printf("TheaverageofclassAis%6.2f\n",average(score1,5));

//用數(shù)組名score1和5作實參

printf("TheaverageofclassBis%6.2f\n",average(score2,10));

//用數(shù)組名score2和10作實參

return0;}floataverage(floatarray[],intn)//定義average函數(shù),未指定形參數(shù)組長度{ inti; floataver,sum=array[0]; for(i=1;i<n;i++) sum=sum+array[i]; //累加n個學(xué)生成績

aver=sum/n; return(aver);}floataverage(floatarray[])注意用數(shù)組名作函數(shù)實參時,不是把數(shù)組元素的值傳遞給形參,而是把實參數(shù)組的首元素的地址傳遞給形參數(shù)組,這樣兩個數(shù)組就共占同一段內(nèi)存單元。a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]起始地址10002468101214161820b[0]b[1]b[2]b[3]b[4]b[5]b[6]b[7]b[8]b[9]一維數(shù)組名作函數(shù)參數(shù)【例7.12】用選擇法對數(shù)組中10個整數(shù)按由小到大排序。解題思路:所謂選擇法就是先將10個數(shù)中最小的數(shù)與a[0]對換;再將a[1]~a[9]中最小的數(shù)與a[1]對換……每比較一輪,找出一個未經(jīng)排序的數(shù)中最小的一個。共比較9輪。選擇排序法算法a[0]a[1]a[2]a[3]a[4]36194未排序時的情況16394將5個數(shù)中最小的數(shù)1與a[0]對換13694將余下的后面4個數(shù)中最小的數(shù)3與a[1]對換13496將余下的3個數(shù)中最小的數(shù)4與a[2]對換13469將余下的2個數(shù)中最小的數(shù)6與a[3]對換,至此完成排序可以看到在執(zhí)行函數(shù)調(diào)用語句“sort(a,10);”之前和之后,a數(shù)組中各元素的值是不同的。原來是無序的,執(zhí)行“sort(a,10);”后,a數(shù)組已經(jīng)排好序了,這是由于形參數(shù)組array已用選擇法進行排序了,形參數(shù)組改變也使實參數(shù)組隨之改變。#include<stdio.h>intmain(){ voidsort(intarray[],intn); inta[10],i; printf("enterarray:\n"); for(i=0;i<10;i++) scanf("%d",&a[i]);

sort(a,10); //調(diào)用sort函數(shù),a為數(shù)組名,大小為10 printf("Thesortedarray:\n"); for(i=0;i<10;i++) printf("%d",a[i]); printf("\n"); return0;}voidsort(intarray[],intn){ inti,j,k,t; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) if(array[j]<array[k]) k=j; t=array[k];array[k]=array[i];array[i]=t; }}多維數(shù)組名作函數(shù)參數(shù)可以用多維數(shù)組名作為函數(shù)的實參和形參,在被調(diào)用函數(shù)中對形參數(shù)組定義時可以指定每一維的大小,也可以省略第一維的大小說明。在定義二維數(shù)組時,必須指定列數(shù)(即一行中包含幾個元素),由于形參數(shù)組與實參數(shù)組類型相同,所以它們是由具有相同長度的一維數(shù)組所組成的。不能只指定第1維(行數(shù))而省略第2維(列數(shù))。在第2維大小相同的前提下,形參數(shù)組的第1維可以與實參數(shù)組不同。例如,實參數(shù)組定義為intscore[5][10];而形參數(shù)組定義為intarray[][10];或intarray[8][10];均可以。這時形參數(shù)組和實參數(shù)組都是由相同類型和大小的一維數(shù)組組成的。C語言編譯系統(tǒng)不檢查第一維的大小。intarray[3][10];或intarray[][10]; //二者等價intarray[][];或intarray[3][]; //必須指定列數(shù)多維數(shù)組名作函數(shù)參數(shù)【例7.13】有一個3×4的矩陣,求所有元素中的最大值。形參數(shù)組array第1維的大小省略,第2維大小不能省略,而且要和實參數(shù)組a的第2維的大小相同。在主函數(shù)調(diào)用max_value函數(shù)時,把實參二維數(shù)組a的第1行的起始地址傳遞給形參數(shù)組array,因此array數(shù)組第1行的起始地址與a數(shù)組的第1行的起始地址相同。由于兩個數(shù)組的列數(shù)相同,因此array數(shù)組第2行的起始地址與a數(shù)組的第2行的起始地址相同。a[i][j]與array[i][j]同占一個存儲單元,它們具有同一個值。實際上,array[i][j]就是a[i][j],在函數(shù)中對array[i][j]的操作就是對a[i][j]的操作。#include<stdio.h>intmain(){ intmax_value(intarray[][4]); //函數(shù)聲明

inta[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}}; //對數(shù)組元素賦初值

printf("Maxvalueis%d\n",max_value(a));

//max_value(a)為函數(shù)調(diào)用

return0;}intmax_value(intarray[][4]) //函數(shù)定義{ inti,j,max; max=array[0][0]; for(i=0;i<3;i++) for(j=0;j<4;j++) if(array[i][j]>max)max=array[i][j]; //把大者放在max中

return(max);}局部變量和全局變量每一個變量都有一個作用域問題,即它們在什么范圍內(nèi)有效。局部變量定義變量可能有3種情況:(1)在函數(shù)的開頭定義;(2)在函數(shù)內(nèi)的復(fù)合語句內(nèi)定義;(3)在函數(shù)的外部定義。在一個函數(shù)內(nèi)部定義的變量只在本函數(shù)范圍內(nèi)有效,也就是說只有在本函數(shù)內(nèi)才能引用它們,在此函數(shù)以外是不能使用這些變量的。在復(fù)合語句內(nèi)定義的變量只在本復(fù)合語句范圍內(nèi)有效,只有在本復(fù)合語句內(nèi)才能引用它們。在該復(fù)合語句以外是不能使用這些變量的,以上這些稱為“局部變量”。局部變量

(1)主函數(shù)中定義的變量也只在主函數(shù)中有效。主函數(shù)也不能使用其他函數(shù)中定義的變量。(2)不同函數(shù)中可以使用同名的變量,它們代表不同的對象,互不干擾。(3)形式參數(shù)也是局部變量。只在定義它的函數(shù)中有效。其他函數(shù)中不能直接引用形參。(4)在一個函數(shù)內(nèi)部,可以在復(fù)合語句中定義變量,這些變量只在本復(fù)合語句中有效,這種復(fù)合語句也稱為“分程序”或“程序塊”。

全局變量程序的編譯單位是源程序文件,一個源文件可以包含一個或若干個函數(shù)。在函數(shù)內(nèi)定義的變量是局部變量,而在函數(shù)之外定義的變量稱為外部變量,外部變量是全局變量(也稱全程變量)。全局變量可以為本文件中其他函數(shù)所共用。它的有效范圍為從定義變量的位置開始到本源文件結(jié)束。注意在函數(shù)內(nèi)定義的變量是局部變量,在函數(shù)外定義的變量是全局變量。全局變量

設(shè)置全局變量的作用是增加了函數(shù)間數(shù)據(jù)聯(lián)系的渠道。由于同一文件中的所有函數(shù)都能引用全局變量的值,因此如果在一個函數(shù)中改變了全局變量的值,就能影響到其他函數(shù)中全局變量的值。相當(dāng)于各個函數(shù)間有直接的傳遞通道。由于函數(shù)的調(diào)用只能帶回一個函數(shù)返回值,因此有時可以利用全局變量來增加函數(shù)間的聯(lián)系渠道,通過函數(shù)調(diào)用能得到一個以上的值。*為了便于區(qū)別全局變量和局部變量,在C程序設(shè)計人員中有一個習(xí)慣(但非規(guī)定),將全局變量名的第1個字母用大寫表示。全局變量c1,c2的作用范圍全局變量p,q的作用范圍全局變量【例7.14】有一個一維數(shù)組,內(nèi)放10個學(xué)生成績,寫一個函數(shù),當(dāng)主函數(shù)調(diào)用此函數(shù)后,能求出平均分、最高分和最低分。#include<stdio.h>floatMax=0,Min=0;

//定義全局變量Max,Minintmain(){ floataverage(floatarray[],intn); floatave,score[10]; inti; printf("Pleaseenter10scores:"); for(i=0;i<10;i++) scanf("%f",&score[i]); ave=average(score,10); printf("max=%6.2f\nmin=%6.2f\naverage=%6.2f\n",Max,Min,ave); return0;}floataverage(floatarray[],intn) //定義函數(shù),有一形參是數(shù)組{ inti; floataver,sum=array[0]; Max=Min=array[0]; for(i=1;i<n;i++) { if(array[i]>Max)Max=array[i]; elseif(array[i]<Min)Min=array[i]; sum=sum+array[i]; } aver=sum/n; return(aver);}全局變量MaxMinavescore10MaxMinmain函數(shù)averarraynMaxMinaverage函數(shù)變量的關(guān)系:全局變量但是,建議不在必要時不要使用全局變量,原因如下:①全局變量在程序的全部執(zhí)行過程中都占用存儲單元,而不是僅在需要時才開辟單元。②它使函數(shù)的通用性降低了,因為如果在函數(shù)中引用了全局變量,那么執(zhí)行情況會受到有關(guān)的外部變量的影響,如果將一個函數(shù)移到另一個文件中,還要考慮把有關(guān)的外部變量及其值一起移過去。但是若該外部變量與其他文件的變量同名時,就會出現(xiàn)問題。這就降低了程序的可靠性和通用性。在程序設(shè)計中,在劃分模塊時要求模塊的“內(nèi)聚性”強、與其他模塊的“耦合性”弱。即模塊的功能要單一(不要把許多互不相干的功能放到一個模塊中),與其他模塊的相互影響要盡量少,而用全局變量是不符合這個原則的。一般要求把C程序中的函數(shù)做成一個相對的封閉體,除了可以通過“實參—形參”的渠道與外界發(fā)生聯(lián)系外,沒有其他渠道。這樣的程序移植性好,可讀性強。③使用全局變量過多,會降低程序的清晰性,人們往往難以清楚地判斷出每個瞬時各個外部變量的值。由于在各個函數(shù)執(zhí)行時都可能改變外部變量的值,程序容易出錯。因此,要限制使用全局變量。全局變量【例7.15】若外部變量與局部變量同名,分析結(jié)果。#include<stdio.h>inta=3,b=5; //a,b是全局變量intmain(){ intmax(inta,intb); //函數(shù)聲明。a,b是形參

inta=8; //a是局部變量

printf("max=%d\n",max(a,b)); return0;}intmax(inta,intb) //a,b是函數(shù)形參{ intc; c=a>b?a:b; //把a和b中的大者存放在c中

return(c);}程序第2行定義了全局變量a和b,并對其初始化。第3行是main函數(shù),在main函數(shù)中(第6行)定義了一個局部變量a。局部變量a的作用范圍為第6~8行。在此范圍內(nèi)全局變量a被局部變量a屏蔽,相當(dāng)于全局變量a在此范圍內(nèi)不存在(即它不起作用),而全局變量b在此范圍內(nèi)有效。因此第6行中max(a,b)的實參a應(yīng)是局部變量a,所以max(a,b)相當(dāng)于max(8,5)。它的值為8。第10行起定義max函數(shù),形參a和b是局部變量。全局變量a和b在max函數(shù)范圍內(nèi)不起作用,所以函數(shù)max中的a和b不是全局變量a和b,而是形參a和b,它們的值是由實參傳給形參的,即8和5。變量的存儲方式和生存期動態(tài)存儲方式與靜態(tài)存儲方式從變量值存在的時間(即生存期)來觀察,有的變量在程序運行的整個過程都是存在的,而有的變量則是在調(diào)用其所在的函數(shù)時才臨時分配存儲單元,而在函數(shù)調(diào)用結(jié)束后該存儲單元就馬上釋放了,變量不存在了。也就是說,變量的存儲有兩種不同的方式:靜態(tài)存儲方式和動態(tài)存儲方式。靜態(tài)存儲方式是指在程序運行期間由系統(tǒng)分配固定的存儲空間的方式。動態(tài)存儲方式則是在程序運行期間根據(jù)需要進行動態(tài)的分配存儲空間的方式。動態(tài)存儲方式與靜態(tài)存儲方式數(shù)據(jù)分別存放在靜態(tài)存儲區(qū)和動態(tài)存儲區(qū)中。全局變量全部存放在靜態(tài)存儲區(qū)中,在程序開始執(zhí)行時給全局變量分配存儲區(qū),程序執(zhí)行完畢就釋放。在程序執(zhí)行過程中它們占據(jù)固定的存儲單元,而不是動態(tài)地進行分配和釋放。在動態(tài)存儲區(qū)中存放以下數(shù)據(jù):①函數(shù)形式參數(shù)。在調(diào)用函數(shù)時給形參分配存儲空間。②函數(shù)中定義的沒有用關(guān)鍵字static聲明的變量,即自動變量。③函數(shù)調(diào)用時的現(xiàn)場保護和返回地址等。對以上這些數(shù)據(jù),在函數(shù)調(diào)用開始時分配動態(tài)存儲空間,函數(shù)結(jié)束時釋放這些空間。在程序執(zhí)行過程中,這種分配和釋放是動態(tài)的,如果在一個程序中兩次調(diào)用同一函數(shù),而在此函數(shù)中定義了局部變量,在兩次調(diào)用時分配給這些局部變量的存儲空間的地址可能是不相同的。如果一個程序中包含若干個函數(shù),每個函數(shù)中的局部變量的生存期并不等于整個程序的執(zhí)行周期,它只是程序執(zhí)行周期的一部分。在程序執(zhí)行過程中,先后調(diào)用各個函數(shù),此時會動態(tài)地分配和釋放存儲空間。用戶區(qū)程序區(qū)靜態(tài)存儲區(qū)動態(tài)存儲區(qū)存儲類別在C語言中,每一個變量和函數(shù)都有兩個屬性:數(shù)據(jù)類型和數(shù)據(jù)的存儲類別。存儲類別指的是數(shù)據(jù)在內(nèi)存中存儲的方式(如靜態(tài)存儲和動態(tài)存儲)。在定義和聲明變量和函數(shù)時,一般應(yīng)同時指定其數(shù)據(jù)類型和存儲類別,也可以采用默認方式指定(即如果用戶不指定,系統(tǒng)會隱含地指定為某一種存儲類別)。C的存儲類別包括4種:自動的(auto)、靜態(tài)的(statis)、寄存器的(register)、外部的(extern)。根據(jù)變量的存儲類別,可以知道變量的作用域和生存期。局部變量的存儲類別自動變量(auto變量)函數(shù)中的局部變量,如果不專門聲明為static(靜態(tài))存儲類別,都是動態(tài)地分配存儲空間的,數(shù)據(jù)存儲在動態(tài)存儲區(qū)中。函數(shù)中的形參和在函數(shù)中定義的局部變量(包括在復(fù)合語句中定義的局部變量),都屬于此類。在調(diào)用該函數(shù)時,系統(tǒng)會給這些變量分配存儲空間,在函數(shù)調(diào)用結(jié)束時就自動釋放這些存儲空間。因此這類局部變量稱為自動變量。自動變量用關(guān)鍵字auto作存儲類別的聲明。實際上,關(guān)鍵字auto可以省略,不寫auto則隱含指定為“自動存儲類別”,它屬于動態(tài)存儲方式。程序中大多數(shù)變量屬于自動變量。

autointb,c=3; //等價于intb,c=3;有時希望函數(shù)中的局部變量的值在函數(shù)調(diào)用結(jié)束后不消失而繼續(xù)保留原值,即其占用的存儲單元不釋放,在下一次再調(diào)用該函數(shù)時,該變量已有值(就是上一次函數(shù)調(diào)用結(jié)束時的值)。這時就應(yīng)該指定該局部變量為“靜態(tài)局部變量”,用關(guān)鍵字static進行聲明。局部變量的存儲類別靜態(tài)局部變量(static局部變量)【例7.16】考察靜態(tài)局部變量的值。#include<stdio.h>intmain(){ intf(int); //函數(shù)聲明

inta=2,i; //自動局部變量

for(i=0;i<3;i++) printf("%d\n",f(a)); //輸出f(a)的值

return0;}intf(inta){ autointb=0; //自動局部變量

staticintc=3; //靜態(tài)局部變量

b=b+1; c=c+1; return(a+b+c);}靜態(tài)變量與自動變量的值的比較分析第幾次調(diào)用調(diào)用時初值調(diào)用結(jié)束時的值bcbca+b+c第1次03147第2次04158第3次05169局部變量的存儲類別靜態(tài)局部變量(static局部變量)(1)靜態(tài)局部變量屬于靜態(tài)存儲類別,在靜態(tài)存儲區(qū)內(nèi)分配存儲單元。在程序整個運行期間都不釋放。而自動變量(即動態(tài)局部變量)屬于動態(tài)存儲類別,分配在動態(tài)存儲區(qū)空間而不在靜態(tài)存儲區(qū)空間,函數(shù)調(diào)用結(jié)束后即釋放。(2)對靜態(tài)局部變量是在編譯時賦初值的,即只賦初值一次,在程序運行時它已有初值。以后每次調(diào)用函數(shù)時不再重新賦初值而只是保留上次函數(shù)調(diào)用結(jié)束時的值。而對自動變量賦初值,不是在編譯時進行的,而是在函數(shù)調(diào)用時進行的,每調(diào)用一次函數(shù)重新給一次初值,相當(dāng)于執(zhí)行一次賦值語句。(3)如果在定義局部變量時不賦初值的話,則對靜態(tài)局部變量來說,編譯時自動賦初值0(對數(shù)值型變量)或空字符′\0′(對字符變量)。而對自動變量來說,它的值是一個不確定的值。這是由于每次函數(shù)調(diào)用結(jié)束后存儲單元已釋放,下次調(diào)用時又重新另分配存儲單元,而所分配的單元中的內(nèi)容是不可知的。(4)雖然靜態(tài)局部變量在函數(shù)調(diào)用結(jié)束后仍然存在,但其他函數(shù)是不能引用它的。因為它是局部變量,只能被本函數(shù)引用,而不能被其他函數(shù)引用。局部變量的存儲類別【例7.17】輸出1到5的階乘值。#include<stdio.h>intmain(){ intfac(intn); inti; for(i=1;i<=5;i++) //先后5次調(diào)用fac函數(shù)

printf("%d!=%d\n",i,fac(i)); //每次計算并輸出i!的值

return0;}intfac(intn){ staticintf=1;

//f保留了上次調(diào)用結(jié)束時的值

f=f*n; //在上次的f值的基礎(chǔ)上再乘以n return(f);

//返回值f是n!的值}(1)每次調(diào)用fac(i),輸出一個i!,同時保留這個i!的值以便下次再乘(i+1)。(2)如果函數(shù)中的變量只被引用而不改變值,則定義為靜態(tài)局部變量(同時初始化)比較方便,以免每次調(diào)用時重新賦值。注意用靜態(tài)存儲要多占內(nèi)存(長期占用不釋放,而不能像動態(tài)存儲那樣一個存儲單元可以先后為多個變量使用,節(jié)約內(nèi)存),而且降低了程序的可讀性,當(dāng)調(diào)用次數(shù)多時往往弄不清靜態(tài)局部變量的當(dāng)前值是什么。因此,若非必要,不要多用靜態(tài)局部變量。局部變量的存儲類別寄存器變量(register變量)一般情況下,變量(包括靜態(tài)存儲方式和動態(tài)存儲方式)的值是存放在內(nèi)存中的。當(dāng)程序中用到哪一個變量的值時,由控制器發(fā)出指令將內(nèi)存中該變量的值送到運算器中。經(jīng)過運算器進行運算,如果需要存數(shù),再從運算器將數(shù)據(jù)送到內(nèi)存存放。如果有一些變量使用頻繁(例如,在一個函數(shù)中執(zhí)行10000次循環(huán),每次循環(huán)中都要引用某局部變量),則為存取變量的值要花費不少時間。為提高執(zhí)行效率,允許將局部變量的值放在CPU中的寄存器中,需要用時直接從寄存器取出參加運算,不必再到內(nèi)存中去存取。由于對寄存器的存取速度遠高于對內(nèi)存的存取速度,因此這樣做可以提高執(zhí)行效率。這種變量叫做寄存器變量,用關(guān)鍵字register作聲明。如由于現(xiàn)在的計算機的速度愈來愈快,性能愈來愈高,優(yōu)化的編譯系統(tǒng)能夠識別使用頻繁的變量,從而自動地將這些變量放在寄存器中,而不需要程序設(shè)計者指定。因此,現(xiàn)在實際上用register聲明變量的必要性不大。registerintf; //定義f為寄存器變量注意3種局部變量的存儲位置是不同的:自動變量存儲在動態(tài)存儲區(qū);靜態(tài)局部變量存儲在靜態(tài)存儲區(qū);寄存器存儲在CPU中的寄存器中。全局變量的存儲類別全局變量都是存放在靜態(tài)存儲區(qū)中的。因此它們的生存期是固定的,存在于程序的整個運行過程。一般來說,外部變量是在函數(shù)的外部定義的全局變量,它的作用域是從變量的定義處開始,到本程序文件的末尾。在此作用域內(nèi),全局變量可以為程序中各個函數(shù)所引用。但有時程序設(shè)計人員希望能擴展外部變量的作用域。全局變量的存儲類別在一個文件內(nèi)擴展外部變量的作用域如果外部變量不在文件的開頭定義,其有效的作用范圍只限于定義處到文件結(jié)束。在定義點之前的函數(shù)不能引用該外部變量。如果由于某種考慮,在定義點之前的函數(shù)需要引用該外部變量,則應(yīng)該在引用之前用關(guān)鍵字extern對該變量作“外部變量聲明”,表示把該外部變量的作用域擴展到此位置。有了此聲明,就可以從“聲明”處起,合法地使用該外部變量?!纠?.18】調(diào)用函數(shù),求3個整數(shù)中的大者。#include<stdio.h>intmain(){ intmax();

externintA,B,C;

//把外部變量A,B,C的作用域擴展到從此處開始

printf("Pleaseenterthreeintegernumbers:"); scanf("%d%d%d",&A,&B,&C);

//輸入3個整數(shù)給A,B,C printf("maxis%d\n",max()); return0;}intA,B,C;

//定義外部變量A,B,Cintmax(){ intm; m=A>B?A:B; //把A和B中的大者放在m中

if(C>m)m=C;

//將A,B,C三者中的大者放在m中

return(m); //返回m的值}注意提倡將外部變量的定義放在引用它的所有函數(shù)之前,這樣可以避免在函數(shù)中多加一個extern聲明。用extern聲明外部變量時,類型名可以寫也可以省寫。例如,“externintA,B,C;”也可以寫成“externA,B,C;”。因為它不是定義變量,可以不指定類型,只須寫出外部變量名即可。全局變量的存儲類別將外部變量的作用域擴展到其他文件如果一個程序包含兩個文件,在兩個文件中都要用到同一個外部變量Num,不能分別在兩個文件中各自定義一個外部變量Num,否則在進行程序的連接時會出現(xiàn)“重復(fù)定義”的錯誤。正確的做法是:在任一個文件中定義外部變量Num,而在另一文件中用extern對Num作“外部變量聲明”,即“externNum;”。在編譯和連接時,系統(tǒng)會由此知道Num有“外部鏈接”,可以從別處找到已定義的外部變量Num,并將在另一文件中定義的外部變量Num的作用域擴展到本文件,在本文件中可以合法地引用外部變量Num?!纠?.19】給定b的值,輸入a和m,求a*b和am的值。#include<stdio.h>intA; //定義外部變量intmain(){ intpower(int); //函數(shù)聲明

intb=3,c,d,m; printf("enterthenumberaanditspowerm:\n"); scanf("%d,%d",&A,&m); c=A*b; printf("%d*%d=%d\n",A,b,c); d=power(m); printf("%d**%d=%d\n",A,m,d); return0;}file1.cexternA;//把file1中定義的外部變量的作用域擴展到本文件intpower(intn){ inti,y=1; for(i=1;i<=n;i++) y*=A; return(y);}file2.c注意用這種方法擴展全局變量的作用域應(yīng)十分慎重,因為在執(zhí)行一個文件中的操作時,可能會改變該全局變量的值,會影響到另一文件中全局變量的值,從而影響該文件中函數(shù)的執(zhí)行結(jié)果。全局變量的存儲類別將外部變量的作用域擴展到其他文件extern既可以用來擴展外部變量在本文件中的作用域,又可以使外部變量的作用域從一個文件擴展到程序中的其他文件,系統(tǒng)在編譯過程中遇到extern時,先在本文件中找外部變量的定義,如果找到,就在本文件中擴展作用域;如果找不到,就在連接時從其他文件中找外部變量的定義。如果從其他文件中找到了,就將作用域擴展到本文件;如果再找不到,就按出錯處理。全局變量的存儲類別將外部變量的作用域限制在本文件中有時在程序設(shè)計中希望某些外部變量只限于被本文件引用,而不能被其他文件引用。這時可以在定義外部變量時加一個static聲明。這種加上static聲明、只能用于本文件的外部變量稱為靜態(tài)外部變量。在程序設(shè)計中,常由若干人分別完成各個模塊,各人可以獨立地在其設(shè)計的文件中使用相同的外部變量名而互不相干。只須在每個文件中定義外部變量時加上static即可。這就為程序的模塊化、通用性提供方便。如果已確認其他文件不需要引用本文件的外部變量,就可以對本文件中的外部變量都加上static,成為靜態(tài)外部變量,以免被其他文件誤用。至于在各文件中在函數(shù)內(nèi)定義的局部變量,本來就不能被函數(shù)外引用,更不能被其他文件引用,因此是安全的。

file1.c

file2.c全局變量的存儲類別將外部變量的作用域限制在本文件中不要誤認為對外部變量加static

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論