輕鬆學會C語言:[7]函數?

函數的嵌套調用  C語言中不允許作嵌套的函數定義。因此各函數之間是平行的,不存在上一級函數和下一級函數的問題。
但是C語言允許在一個函數的定義中出現對另一個函數的調用。 這樣就出現了函數的嵌套調用。即在被調函數中又調用其它函數。
這與其它語言的子程序嵌套的情形是類似的。其關係可表示如圖5.2。  圖5.2表示了兩層嵌套的情形。其執行過程是:執行main函數中調用a函數的語句時,即轉去執行a函數,在a函數中調用b
函數時,又轉去執行b函數,b函數執行完畢返回a函數的斷點繼續執行,a
函數執行完畢返回main函數的斷點繼續執行。[例5.8]計算s=22!+32!本題可編寫兩個函數,一個是用來計算平方值的函數f1,
另一個是用來計算階乘值的函數f2。主函數先調f1計算出平方值, 再在f1中以平方值為實參,調用
f2計算其階乘值,然後返回f1,再返回主函數,在循環程序中計算累加和。long f1(int
p){int k;long r;long f2(int);k=p*p;r=f2(k);return
r;}long f2(int q){long c=1;int
i;for(i=1;i<=q;i++)c=c*i;return c;}main(){int
i;long s=0;for
(i=2;i<=3;i++)s=s+f1(i);printf("\ns=%ld\n",s);}long f1(int
p){……long f2(int);r=f2(k);……}long f2(int q){……}main(){
……s=s+f1(i);……}  在程序中,函數f1和f2均為長整型,都在主函數之前定義,
故不必再在主函數中對f1和f2加以說明。在主程序中,
執行循環程序依次把i值作為實參調用函數f1求i2值。在f1中又發生對函數f2的調用,這時是把i2的值作為實參去調f2,在f2 中完成求i2!
的計算。f2執行完畢把C值(即i2!)返回給f1,再由f1 返回主函數實現累加。至此,由函數的嵌套調用實現了題目的要求。 由於數值很大,
所以函數和一些變量的類型都說明為長整型,否則會造成計算錯誤。函數的遞歸調用  一個函數在它的函數體內調用它自身稱為遞歸調用。
這種函數稱為遞歸函數。C語言允許函數的遞歸調用。在遞歸調用中, 主調函數又是被調函數。執行遞歸函數將反覆調用其自身。
每調用一次就進入新的一層。例如有函數f如下:int f (int x){int
y;z=f(y);return z;}  這個函數是一個遞歸函數。
但是運行該函數將無休止地調用其自身,這當然是不正確的。為了防止遞歸調用無終止地進行, 必須在函數內有終止遞歸調用的手段。常用的辦法是加條件判斷,
滿足某種條件後就不再作遞歸調用,然後逐層返回。
下面舉例說明遞歸調用的執行過程。[例5.9]用遞歸法計算n!用遞歸法計算n!可用下述公式表示:n!=1 (n=0,1)n×(n-1)!
(n>1)按公式可編程如下:long ff(int n){long
f;if(n<0) printf("n<0,input error");else if(n==0 n==1)
f=1;else f=ff(n-1)*n;return(f);}main(){int n;long
y;printf("\ninput a inteager
number:\n");scanf("%d",&n);y=ff(n);printf("%d!=%ld",n,y);}long
ff(int n){ ……else f=ff(n-1)*n;……}main(){
……y=ff(n);……}  程序中給出的函數ff是一個遞歸函數。主函數調用ff
後即進入函數ff執行,如果n<0,n==0或n=1時都將結束函數的執行,否則就遞歸調用ff函數自身。由於每次遞歸調用的實參為n-1,即把n-1
的值賦予形參n,最後當n-1的值為1時再作遞歸調用,形參n的值也為1,將使遞歸終止。然後可逐層退回。下面我們再舉例說明該過程。 設執行本程序時輸入為5, 即求
5!。在主函數中的調用語句即為y=ff(5),進入ff函數後,由於n=5,不等於0或1,故應執行f=ff(n-1)*n,即f=ff(5-1)*5。該語句對ff作遞歸調用即ff(4)。
逐次遞歸展開如圖5.3所示。進行四次遞歸調用後,ff函數形參取得的值變為1,故不再繼續遞歸調用而開始逐層返回主調函數。ff(1)的函數返回值為1,ff(2)的返回值為1*2=2,ff(3)的返回值為2*3=6,ff(4)
的返回值為6*4=24,最後返回值ff(5)為24*5=120。  例5.
9也可以不用遞歸的方法來完成。如可以用遞推法,即從1開始乘以2,再乘以3…直到n。遞推法比遞歸法更容易理解和實現。但是有些問題則只能用遞歸算法才能實現。典型的問題是Hanoi塔問題。  [例5.10]Hanoi塔問題一塊板上有三根針,A,B,C。A針上套有64個大小不等的圓盤,
大的在下,小的在上。如圖5.4所示。要把這64個圓盤從A針移動C針上,每次只能移動一個圓盤,移動可以藉助B針進行。但在任何時候,任何針上的圓盤都必須保持大盤在下,小盤在上。求移動的步驟。本題算法分析如下,設A上有n個盤子。如果n=1,則將圓盤從A直接移動到C。如果n=2,則:1.將A上的n-1(等於1)個圓盤移到B上;2.再將A上的一個圓盤移到C上;3.最後將B上的n-1(等於1)個圓盤移到C上。如果n=3,則:A.
將A上的n-1(等於2,令其為n`)個圓盤移到B(藉助於C),步驟如下:(1)將A上的n`-1(等於1)個圓盤移到C上,見圖5.5(b)。(2)將A上的一個圓盤移到B,見圖5.5(c)(3)將C上的n`-1(等於1)個圓盤移到B,見圖5.5(d)B.
將A上的一個圓盤移到C,見圖5.5(e)C.
將B上的n-1(等於2,令其為n`)個圓盤移到C(藉助A),步驟如下:(1)將B上的n`-1(等於1)個圓盤移到A,見圖5.5(f)(2)將B上的一個盤子移到C,見圖5.5(g)(3)將A上的n`-1(等於1)個圓盤移到C,見圖5.5(h)。到此,完成了三個圓盤的移動過程。從上面分析可以看出,當n大於等於2時,
移動的過程可分解為三個步驟:第一步 把A上的n-1個圓盤移到B上;第二步 把A上的一個圓盤移到C上;第三步
把B上的n-1個圓盤移到C上;其中第一步和第三步是類同的。當n=3時,第一步和第三步又分解為類同的三步,即把n`-1個圓盤從一個針移到另一個針上,這裡的n`=n-1。
顯然這是一個遞歸過程,據此算法可編程如下:move(int n,int x,int y,int
z){if(n==1)printf("%c-->%c\n",x,z);else{move(n-1,x,z,y);printf("%c-->%c\n",x,z);move(n-1,y,x,z);}}main(){int
h;printf("\ninput number:\n");scanf("%d",&h);printf("the step to
moving %2d diskes:\n",h);move(h,'a','b','c');}move(int n,int x,int
y,int
z){if(n==1)printf("%-->%c\n",x,z);else{move(n-1,x,z,y);printf("%c-->%c\n",x,z);move(n-1,y,x,z);}}main(){
……move(h,'a','b','c');}  從程序中可以看出,move函數是一個遞歸函數,它有四個形參n,x,y,z。n表示圓盤數,x,y,z分別表示三根針。move
函數的功能是把x上的n個圓盤移動到z
上。當n==1時,直接把x上的圓盤移至z上,輸出x→z。如n!=1則分為三步:遞歸調用move函數,把n-1個圓盤從x移到y;輸出x→z;遞歸調用move函數,把n-1個圓盤從y移到z。在遞歸調用過程中n=n-1,故n的值逐次遞減,最後n=1時,終止遞歸,逐層返回。當n=4
時程序運行的結果為input number:4the step to moving 4
diskes:a→ba→cb→ca→bc→ac→ba→ba→cb→cb→ac→ab→ca→ba→cb→c變量的作用域  在討論函數的形參變量時曾經提到,
形參變量只在被調用期間才分配內存單元,調用結束立即釋放。 這一點表明形參變量只有在函數內才是有效的,
離開該函數就不能再使用了。這種變量有效性的範圍稱變量的作用域。不僅對於形參變量, C語言中所有的量都有自己的作用域。變量說明的方式不同,其作用域也不同。
C語言中的變量,按作用域範圍可分為兩種, 即局部變量和全局變量。一、局部變量  局部變量也稱為內部變量。局部變量是在函數內作定義說明的。其作用域僅限於函數內,
離開該函數後再使用這種變量是非法的。例如:int f1(int a)
/*函數f1*/{int b,c;……}a,b,c作用域int f2(int x)
/*函數f2*/{int y,z;}x,y,z作用域main(){int m,n;}m,n作用域 在函數f1內定義了三個變量,a為形參,b,c為一般變量。在
f1的範圍內a,b,c有效,或者說a,b,c變量的作用域限於f1內。同理,x,y,z的作用域限於f2內。
m,n的作用域限於main函數內。關於局部變量的作用域還要說明以下幾點:1.
主函數中定義的變量也只能在主函數中使用,不能在其它函數中使用。同時,主函數中也不能使用其它函數中定義的變量。因為主函數也是一個函數,它與其它函數是平行關係。這一點是與其它語言不同的,應予以注意。2.
形參變量是屬於被調函數的局部變量,實參變量是屬於主調函數的局部變量。3.
允許在不同的函數中使用相同的變量名,它們代表不同的對象,分配不同的單元,互不干擾,也不會發生混淆。如在例5.3 中,形參和實參的變量名都為n,是完全允許的。4.
在複合語句中也可定義變量,其作用域只在複合語句範圍內。例如:main(){int
s,a;……{int b;s=a+b;……b作用域}……s,a作用域}[例5.11]main(){int i=2,j=3,k;k=i+j;{int
k=8;if(i==3)
printf("%d\n",k);}printf("%d\n%d\n",i,k);}main(){int
i=2,j=3,k;k=i+j;{int k=8;if(i=3)
printf("%d\n",k);}printf("%d\n%d\n",i,k);}  本程序在main中定義了i,j,k三個變量,其中k未賦初值。
而在複合語句內又定義了一個變量k,並賦初值為8。應該注意這兩個k不是同一個變量。在複合語句外由main定義的k起作用,而在複合語句內則由在複合語句內定義的k起作用。因此程序第4行的k為main所定義,其值應為5。第7行輸出k值,該行在複合語句內,由複合語句內定義的k起作用,其初值為8,故輸出值為8,第9行輸出i,k值。i是在整個程序中有效的,第7行對i賦值為3,故以輸出也為3。而第9行已在複合語句之外,輸出的k應為main所定義的k,此k值由第4
行已獲得為5,故輸出也為5。二、全局變量全局變量也稱為外部變量,它是在函數外部定義的變量。
它不屬於哪一個函數,它屬於一個源程序文件。其作用域是整個源程序。在函數中使用全局變量,一般應作全局變量說明。
只有在函數內經過說明的全局變量才能使用。全局變量的說明符為extern。 但在一個函數之前定義的全局變量,在該函數內使用可不再加以說明。
例如:int a,b; /*外部變量*/void f1()
/*函數f1*/{……}float x,y; /*外部變量*/int fz()
/*函數fz*/{……}main() /*主函數*/{……}/*全局變量x,y作用域
全局變量a,b作用域*/  從上例可以看出a、b、x、y 都是在函數外部定義的外部變量,都是全局變量。但x,y
定義在函數f1之後,而在f1內又無對x,y的說明,所以它們在f1內無效。
a,b定義在源程序最前面,因此在f1,f2及main內不加說明也可使用。[例5.12]輸入正方體的長寬高l,w,h。求體積及三個面x*y,x*z,y*z的面積。int s1,s2,s3;int vs( int a,int b,int c){int
v;v=a*b*c;s1=a*b;s2=b*c;s3=a*c;return
v;}main(){int v,l,w,h;printf("\ninput length,width and
height\n");scanf("%d%d%d",&l,&w,&h);v=vs(l,w,h);printf("v=%d
s1=%d s2=%d s3=%d\n",v,s1,s2,s3);}  本程序中定義了三個外部變量s1,s2,s3,
用來存放三個面積,其作用域為整個程序。函數vs用來求正方體體積和三個面積,
函數的返回值為體積v。由主函數完成長寬高的輸入及結果輸出。由於C語言規定函數返回值只有一個,
當需要增加函數的返回數據時,用外部變量是一種很好的方式。本例中,如不使用外部變量, 在主函數中就不可能取得v,s1,s2,s3四個值。而採用了外部變量,
在函數vs中求得的s1,s2,s3值在main 中仍然有效。因此外部變量是實現函數之間數據通訊的有效手段。對於全局變量還有以下幾點說明:1.
對於局部變量的定義和說明,可以不加區分。而對於外部變量則不然,外部變量的定義和外部變量的說明並不是一回事。外部變量定義必須在所有的函數之外,且只能定義一次。其一般形式為:
[extern] 類型說明符 變量名,變量名… 其中方括號內的extern可以省去不寫。例如: int a,b;等效於:extern
int a,b;  而外部變量說明出現在要使用該外部變量的各個函數內, 在整個程序內,可能出現多次,外部變量說明的一般形式為: extern 類型說明符
變量名,變量名,…; 外部變量在定義時就已分配了內存單元, 外部變量定義可作初始賦值,外部變量說明不能再賦初始值,
只是表明在函數內要使用某外部變量。2. 外部變量可加強函數模塊之間的數據聯繫,
但是又使函數要依賴這些變量,因而使得函數的獨立性降低。從模塊化程序設計的觀點來看這是不利的, 因此在不必要時儘量不要使用全局變量。3.
在同一源文件中,允許全局變量和局部變量同名。在局部變量的作用域內,全局變量不起作用。[例5.13]int
vs(int l,int w){extern int h;int v;v=l*w*h;return
v;}main(){extern int w,h;int
l=5;printf("v=%d",vs(l,w));}int
l=3,w=4,h=5;  本例程序中,外部變量在最後定義,
因此在前面函數中對要用的外部變量必須進行說明。外部變量l,w和vs函數的形參l,w同名。外部變量都作了初始賦值,mian函數中也對l作了初始化賦值。執行程序時,在printf語句中調用vs函數,實參l的值應為main中定義的l值,等於5,外部變量l在main內不起作用;實參w的值為外部變量w的值為4,進入vs後這兩個值傳送給形參l,wvs函數中使用的h
為外部變量,其值為5,因此v的計算結果為100,返回主函數後輸出。變量的存儲類型各種變量的作用域不同,
就其本質來說是因變量的存儲類型相同。所謂存儲類型是指變量佔用內存空間的方式, 也稱為存儲方式。變量的存儲方式可分為“靜態存儲”和“動態存儲”兩種。  靜態存儲變量通常是在變量定義時就分定存儲單元並一直保持不變,
直至整個程序結束。5.5.1節中介紹的全局變量即屬於此類存儲方式。動態存儲變量是在程序執行過程中,使用它時才分配存儲單元, 使用完畢立即釋放。
典型的例子是函數的形式參數,在函數定義時並不給形參分配存儲單元,只是在函數被調用時,才予以分配, 調用函數完畢立即釋放。如果一個函數被多次調用,則反覆地分配、
釋放形參變量的存儲單元。從以上分析可知, 靜態存儲變量是一直存在的,
而動態存儲變量則時而存在時而消失。我們又把這種由於變量存儲方式不同而產生的特性稱變量的生存期。 生存期表示了變量存在的時間。
生存期和作用域是從時間和空間這兩個不同的角度來描述變量的特性,這兩者既有聯繫,又有區別。 一個變量究竟屬於哪一種存儲方式,
並不能僅從其作用域來判斷,還應有明確的存儲類型說明。  在C語言中,對變量的存儲類型說明有以下四種:auto    
自動變量register   寄存器變量extern    外部變量static    靜態變量  自動變量和寄存器變量屬於動態存儲方式, 外部變量和靜態變量屬於靜態存儲方式。在介紹了變量的存儲類型之後,
可以知道對一個變量的說明不僅應說明其數據類型,還應說明其存儲類型。 因此變量說明的完整形式應為: 存儲類型說明符 數據類型說明符 變量名,變量名…;
例如:static int a,b;           說明a,b為靜態類型變量auto char c1,c2;
         說明c1,c2為自動字符變量static int a[5]={1,2,3,4,5};    說明a為靜整型數組extern
int x,y;          
說明x,y為外部整型變量下面分別介紹以上四種存儲類型:一、自動變量的類型說明符為auto。  這種存儲類型是C語言程序中使用最廣泛的一種類型。C語言規定,
函數內凡未加存儲類型說明的變量均視為自動變量, 也就是說自動變量可省去說明符auto。
在前面各章的程序中所定義的變量凡未加存儲類型說明符的都是自動變量。例如:{ int i,j,k;char
c;……}等價於: { auto int i,j,k;auto char
c;……}  自動變量具有以下特點:1.
自動變量的作用域僅限於定義該變量的個體內。在函數中定義的自動變量,只在該函數內有效。在複合語句中定義的自動變量只在該複合語句中有效。 例如:int kv(int a){auto int x,y;{ auto char c;}
/*c的作用域*/……} /*a,x,y的作用域*/2.
自動變量屬於動態存儲方式,只有在使用它,即定義該變量的函數被調用時才給它分配存儲單元,開始它的生存期。函數調用結束,釋放存儲單元,結束生存期。因此函數調用結束之後,自動變量的值不能保留。在複合語句中定義的自動變量,在退出複合語句後也不能再使用,否則將引起錯誤。例如以下程序:main(){ auto int a,s,p;printf("\ninput a
number:\n");scanf("%d",&a);if(a>0){s=a+a;p=a*a;}printf("s=%d
p=%d\n",s,p);}s,p是在複合語句內定義的自動變量,只能在該複合語句內有效。而程序的第9行卻是退出複合語句之後用printf語句輸出s,p的值,這顯然會引起錯誤。3.
由於自動變量的作用域和生存期都侷限於定義它的個體內( 函數或複合語句內), 因此不同的個體中允許使用同名的變量而不會混淆。
即使在函數內定義的自動變量也可與該函數內部的複合語句中定義的自動變量同名。例5.14表明了這種情況。[例5.14]main(){auto int a,s=100,p=100;printf("\ninput a
number:\n");scanf("%d",&a);if(a>0){auto int
s,p;s=a+a;p=a*a;printf("s=%d p=%d\n",s,p);}printf("s=%d
p=%d\n",s,p);}  本程序在main函數中和複合語句內兩次定義了變量s,p為自動變量。按照C語言的規定,在複合語句內,應由複合語句中定義的s,p起作用,故s的值應為a+
a,p的值為a*a。退出複合語句後的s,p 應為main所定義的s,p,其值在初始化時給定,均為100。從輸出結果可以分析出兩個s和兩個p雖變量名相同,
但卻是兩個不同的變量。4. 對構造類型的自動變量如數組等,不可作初始化賦值。二、外部變量外部變量的類型說明符為extern。在前面介紹全局變量時已介紹過外部變量。這裡再補充說明外部變量的幾個特點:1.
外部變量和全局變量是對同一類變量的兩種不同角度的提法。全局變是是從它的作用域提出的,外部變量從它的存儲方式提出的,表示了它的生存期。2.
當一個源程序由若干個源文件組成時, 在一個源文件中定義的外部變量在其它的源文件中也有效。例如有一個源程序由源文件F1.C和F2.C組成:F1.Cint a,b; /*外部變量定義*/char c; /*外部變量定義*/main(){……}F2.Cextern int a,b; /*外部變量說明*/extern char c;
/*外部變量說明*/func (int
x,y){……}在F1.C和F2.C兩個文件中都要使用a,b,c三個變量。在F1.C文件中把a,b,c都定義為外部變量。在F2.C文件中用extern把三個變量說明為外部變量,表示這些變量已在其它文件中定義,並把這些變量的類型和變量名,編譯系統不再為它們分配內存空間。
對構造類型的外部變量, 如數組等可以在說明時作初始化賦值,若不賦初值,則系統自動定義它們的初值為0。三、靜態變量  靜態變量的類型說明符是static。
靜態變量當然是屬於靜態存儲方式,但是屬於靜態存儲方式的量不一定就是靜態變量, 例如外部變量雖屬於靜態存儲方式,但不一定是靜態變量,必須由
static加以定義後才能成為靜態外部變量,或稱靜態全局變量。 對於自動變量,前面已經介紹它屬於動態存儲方式。
但是也可以用static定義它為靜態自動變量,或稱靜態局部變量,從而成為靜態存儲方式。由此看來,
一個變量可由static進行再說明,並改變其原有的存儲方式。1.
靜態局部變量  在局部變量的說明前再加上static說明符就構成靜態局部變量。例如:static int a,b;static
float
array[5]={1,2,3,4,5};  靜態局部變量屬於靜態存儲方式,它具有以下特點:(1)靜態局部變量在函數內定義,但不象自動變量那樣,當調用時就存在,退出函數時就消失。靜態局部變量始終存在著,也就是說它的生存期為整個源程序。(2)靜態局部變量的生存期雖然為整個源程序,但是其作用域仍與自動變量相同,即只能在定義該變量的函數內使用該變量。退出該函數後,
儘管該變量還繼續存在,但不能使用它。(3)允許對構造類靜態局部量賦初值。在數組一章中,介紹數組初始化時已作過說明。若未賦以初值,則由系統自動賦以0值。(4)對基本類型的靜態局部變量若在說明時未賦以初值,則系統自動賦予0值。而對自動變量不賦初值,則其值是不定的。
根據靜態局部變量的特點, 可以看出它是一種生存期為整個源程序的量。雖然離開定義它的函數後不能使用,但如再次調用定義它的函數時,它又可繼續使用,
而且保存了前次被調用後留下的值。
因此,當多次調用一個函數且要求在調用之間保留某些變量的值時,可考慮採用靜態局部變量。雖然用全局變量也可以達到上述目的,但全局變量有時會造成意外的副作用,因此仍以採用局部靜態變量為宜。[例5.15]main(){int i;void f();
/*函數說明*/for(i=1;i<=5;i++)f(); /*函數調用*/}void f()
/*函數定義*/{auto int
j=0;++j;printf("%d\n",j);}  程序中定義了函數f,其中的變量j
說明為自動變量並賦予初始值為0。當main中多次調用f時,j均賦初值為0,故每次輸出值均為1。現在把j改為靜態局部變量,程序如下:main(){int i;void f();for
(i=1;i<=5;i++)f();}void f(){static int
j=0;++j;printf("%d\n",j);}void f(){static int
j=0;++j;printf("%d/n",j);}由於j為靜態變量,能在每次調用後保留其值並在下一次調用時繼續使用,所以輸出值成為累加的結果。讀者可自行分析其執行過程。2.靜態全局變量  全局變量(外部變量)的說明之前再冠以static
就構成了靜態的全局變量。全局變量本身就是靜態存儲方式, 靜態全局變量當然也是靜態存儲方式。
這兩者在存儲方式上並無不同。這兩者的區別雖在於非靜態全局變量的作用域是整個源程序, 當一個源程序由多個源文件組成時,非靜態的全局變量在各個源文件中都是有效的。
而靜態全局變量則限制了其作用域, 即只在定義該變量的源文件內有效,
在同一源程序的其它源文件中不能使用它。由於靜態全局變量的作用域侷限於一個源文件內,只能為該源文件內的函數公用,
因此可以避免在其它源文件中引起錯誤。從以上分析可以看出,
把局部變量改變為靜態變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變為靜態變量後是改變了它的作用域, 限制了它的使用範圍。因此static
這個說明符在不同的地方所起的作用是不同的。應予以注意。四、寄存器變量  上述各類變量都存放在存儲器內,
因此當對一個變量頻繁讀寫時,必須要反覆訪問內存儲器,從而花費大量的存取時間。
為此,C語言提供了另一種變量,即寄存器變量。這種變量存放在CPU的寄存器中,使用時,不需要訪問內存,而直接從寄存器中讀寫,
這樣可提高效率。寄存器變量的說明符是register。 對於循環次數較多的循環控制變量及循環體內反覆使用的變量均可定義為寄存器變量。[例5.16]求∑200i=1imain(){register
i,s=0;for(i=1;i<=200;i++)s=s+i;printf("s=%d\n",s);}本程序循環200次,i和s都將頻繁使用,因此可定義為寄存器變量。對寄存器變量還要說明以下幾點:1.
只有局部自動變量和形式參數才可以定義為寄存器變量。因為寄存器變量屬於動態存儲方式。凡需要採用靜態存儲方式的量不能定義為寄存器變量。2.
在Turbo C,MS C等微機上使用的C語言中, 實際上是把寄存器變量當成自動變量處理的。因此速度並不能提高。
而在程序中允許使用寄存器變量只是為了與標準C保持一致。3. 即使能真正使用寄存器變量的機器,由於CPU
中寄存器的個數是有限的,因此使用寄存器變量的個數也是有限的。內部函數和外部函數  函數一旦定義後就可被其它函數調用。 但當一個源程序由多個源文件組成時,
在一個源文件中定義的函數能否被其它源文件中的函數調用呢?為此,C語言又把函數分為兩類:一、內部函數  如果在一個源文件中定義的函數只能被本文件中的函數調用,而不能被同一源程序其它文件中的函數調用,
這種函數稱為內部函數。定義內部函數的一般形式是: static 類型說明符 函數名(形參表) 例如:static int f(int
a,int b) 內部函數也稱為靜態函數。但此處靜態static 的含義已不是指存儲方式,而是指對函數的調用範圍只侷限於本文件。
因此在不同的源文件中定義同名的靜態函數不會引起混淆。二、外部函數  外部函數在整個源程序中都有效,其定義的一般形式為: extern
類型說明符 函數名(形參表) 例如:extern int f(int a,int
b)如在函數定義中沒有說明extern或static則隱含為extern。在一個源文件的函數中調用其它源文件中定義的外部函數時,應
用extern說明被調函數為外部函數。例如:F1.C
(源文件一)main(){extern int f1(int i);
/*外部函數說明,表示f1函數在其它源文件中*/……}F2.C (源文件二)extern int f1(int i);
/*外部函數定義*/{……}本章小結1.
函數的分類(1)庫函數:由C系統提供的函數;(2)用戶定義函數:由用戶自己定義的函數;(3)有返回值的函數向調用者返回函數值,應說明函數類型(
即返回值的類型
);(4)無返回值的函數:不返回函數值,說明為空(void)類型;(5)有參函數:主調函數向被調函數傳送數據;(6)無參函數:主調函數與被調函數間無數據傳送;(7)內部函數:只能在本源文件中使用的函數;(8)外部函數:可在整個源程序中使用的函數。2.
函數定義的一般形式[extern/static] 類型說明符 函數名([形參表]) 方括號內為可選項。3. 函數說明的一般形式
[extern] 類型說明符 函數名([形參表]);4. 函數調用的一般形式 函數名([實參表])5.
函數的參數分為形參和實參兩種,形參出現在函數定義中,實參出現在函數調用中,發生函數調用時,將把實參的值傳送給形參。6.
函數的值是指函數的返回值,它是在函數中由return語句返回的。7.
數組名作為函數參數時不進行值傳送而進行地址傳送。形參和實參實際上為同一數組的兩個名稱。因此形參數組的值發生變化,實參數組的值當然也變化。8.
C語言中,允許函數的嵌套調用和函數的遞歸調用。9.
可從三個方面對變量分類,即變量的數據類型,變量作用域和變量的存儲類型。在第二章中主要介紹變量的數據類型,本章中介紹了變量的作用域和變量的存儲類型。10.變量的作用域是指變量在程序中的有效範圍,
分為局部變量和全局變量。11.變量的存儲類型是指變量在內存中的存儲方式,分為靜態存儲和動態存儲,表示了變量的生存期。12.變量分類特性表存儲方式存儲類型說明符何處定義生存期作用域賦值前的值可賦初值類型動態存儲自動變量
auto 寄存器變量 register
函數或複合語句內被調用時在定義它的函數或複合語句內不定基本類型int或char外部變量extern函數之外整個源程序整個源程序靜態局部變量static
函數或複合語句內靜態全局變量static 函數之外整個源程序在定義它的函數或複合語句內在定義它的源文件內0任何類型

輕鬆學會C語言 (共13篇) 上一篇:第五章:函數 下一篇:第六章:指針

語言, 函數, 變量, 定義, 靜態,
相關問題答案