?? 8.txt
字號:
8 函 數(shù) 1
8.1 概述 1
8.2 函數(shù)定義的一般形式 3
8.3 函數(shù)的參數(shù)和函數(shù)的值 4
8.3.1 形式參數(shù)和實際參數(shù) 4
8.3.2 函數(shù)的返回值 5
8.4 函數(shù)的調(diào)用 6
8.4.1 函數(shù)調(diào)用的一般形式 6
8.4.2 函數(shù)調(diào)用的方式 6
8.4.3 被調(diào)用函數(shù)的聲明和函數(shù)原型 7
8.5 函數(shù)的嵌套調(diào)用 8
8.6 函數(shù)的遞歸調(diào)用 10
8.7 數(shù)組作為函數(shù)參數(shù) 12
8.8 局部變量和全局變量 17
8.8.1 局部變量 17
8.8.2 全局變量 19
8.9 變量的存儲類別 20
8.9.1 動態(tài)存儲方式與靜態(tài)動態(tài)存儲方式 20
8.9.2 auto變量 21
8.9.3 用static聲明局部變量 21
8.9.4 register變量 22
8.9.5 用extern聲明外部變量 23
8 函 數(shù)
8.1 概述
在前面已經(jīng)介紹過,C源程序是由函數(shù)組成的。雖然在前面各章的程序中大都只有一個主函數(shù)main(),但實用程序往往由多個函數(shù)組成。函數(shù)是C源程序的基本模塊,通過對函數(shù)模塊的調(diào)用實現(xiàn)特定的功能。C語言中的函數(shù)相當(dāng)于其它高級語言的子程序。C語言不僅提供了極為豐富的庫函數(shù)(如Turbo C,MS C都提供了三百多個庫函數(shù)),還允許用戶建立自己定義的函數(shù)。用戶可把自己的算法編成一個個相對獨立的函數(shù)模塊,然后用調(diào)用的方法來使用函數(shù)。可以說C程序的全部工作都是由各式各樣的函數(shù)完成的,所以也把C語言稱為函數(shù)式語言。
由于采用了函數(shù)模塊式的結(jié)構(gòu),C語言易于實現(xiàn)結(jié)構(gòu)化程序設(shè)計。使程序的層次結(jié)構(gòu)清晰,便于程序的編寫、閱讀、調(diào)試。
在C語言中可從不同的角度對函數(shù)分類。
1. 從函數(shù)定義的角度看,函數(shù)可分為庫函數(shù)和用戶定義函數(shù)兩種。
1) 庫函數(shù):由C系統(tǒng)提供,用戶無須定義,也不必在程序中作類型說明,只需在程序前包含有該函數(shù)原型的頭文件即可在程序中直接調(diào)用。在前面各章的例題中反復(fù)用到printf、scanf、getchar、putchar、gets、puts、strcat等函數(shù)均屬此類。
2) 用戶定義函數(shù):由用戶按需要寫的函數(shù)。對于用戶自定義函數(shù),不僅要在程序中定義函數(shù)本身,而且在主調(diào)函數(shù)模塊中還必須對該被調(diào)函數(shù)進(jìn)行類型說明,然后才能使用。
2. C語言的函數(shù)兼有其它語言中的函數(shù)和過程兩種功能,從這個角度看,又可把函數(shù)分為有返回值函數(shù)和無返回值函數(shù)兩種。
1) 有返回值函數(shù):此類函數(shù)被調(diào)用執(zhí)行完后將向調(diào)用者返回一個執(zhí)行結(jié)果,稱為函數(shù)返回值。如數(shù)學(xué)函數(shù)即屬于此類函數(shù)。由用戶定義的這種要返回函數(shù)值的函數(shù),必須在函數(shù)定義和函數(shù)說明中明確返回值的類型。
2) 無返回值函數(shù):此類函數(shù)用于完成某項特定的處理任務(wù),執(zhí)行完成后不向調(diào)用者返回函數(shù)值。這類函數(shù)類似于其它語言的過程。由于函數(shù)無須返回值,用戶在定義此類函數(shù)時可指定它的返回為“空類型”, 空類型的說明符為“void”。
3. 從主調(diào)函數(shù)和被調(diào)函數(shù)之間數(shù)據(jù)傳送的角度看又可分為無參函數(shù)和有參函數(shù)兩種。
1) 無參函數(shù):函數(shù)定義、函數(shù)說明及函數(shù)調(diào)用中均不帶參數(shù)。主調(diào)函數(shù)和被調(diào)函數(shù)之間不進(jìn)行參數(shù)傳送。此類函數(shù)通常用來完成一組指定的功能,可以返回或不返回函數(shù)值。
2) 有參函數(shù):也稱為帶參函數(shù)。在函數(shù)定義及函數(shù)說明時都有參數(shù),稱為形式參數(shù)(簡稱為形參)。在函數(shù)調(diào)用時也必須給出參數(shù),稱為實際參數(shù)(簡稱為實參)。進(jìn)行函數(shù)調(diào)用時,主調(diào)函數(shù)將把實參的值傳送給形參,供被調(diào)函數(shù)使用。
4. C語言提供了極為豐富的庫函數(shù),這些庫函數(shù)又可從功能角度作以下分類。
1) 字符類型分類函數(shù):用于對字符按ASCII碼分類:字母,數(shù)字,控制字符,分隔符,大小寫字母等。
2) 轉(zhuǎn)換函數(shù):用于字符或字符串的轉(zhuǎn)換;在字符量和各類數(shù)字量(整型,實型等)之間進(jìn)行轉(zhuǎn)換;在大、小寫之間進(jìn)行轉(zhuǎn)換。
3) 目錄路徑函數(shù):用于文件目錄和路徑操作。
4) 診斷函數(shù):用于內(nèi)部錯誤檢測。
5) 圖形函數(shù):用于屏幕管理和各種圖形功能。
6) 輸入輸出函數(shù):用于完成輸入輸出功能。
7) 接口函數(shù):用于與DOS,BIOS和硬件的接口。
8) 字符串函數(shù):用于字符串操作和處理。
9) 內(nèi)存管理函數(shù):用于內(nèi)存管理。
10) 數(shù)學(xué)函數(shù):用于數(shù)學(xué)函數(shù)計算。
11) 日期和時間函數(shù):用于日期,時間轉(zhuǎn)換操作。
12) 進(jìn)程控制函數(shù):用于進(jìn)程管理和控制。
13) 其它函數(shù):用于其它各種功能。
以上各類函數(shù)不僅數(shù)量多,而且有的還需要硬件知識才會使用,因此要想全部掌握則需要一個較長的學(xué)習(xí)過程。應(yīng)首先掌握一些最基本、最常用的函數(shù),再逐步深入。由于課時關(guān)系,我們只介紹了很少一部分庫函數(shù),其余部分讀者可根據(jù)需要查閱有關(guān)手冊。
還應(yīng)該指出的是,在C語言中,所有的函數(shù)定義,包括主函數(shù)main在內(nèi),都是平行的。也就是說,在一個函數(shù)的函數(shù)體內(nèi),不能再定義另一個函數(shù),即不能嵌套定義。但是函數(shù)之間允許相互調(diào)用,也允許嵌套調(diào)用。習(xí)慣上把調(diào)用者稱為主調(diào)函數(shù)。函數(shù)還可以自己調(diào)用自己,稱為遞歸調(diào)用。
main 函數(shù)是主函數(shù),它可以調(diào)用其它函數(shù),而不允許被其它函數(shù)調(diào)用。因此,C程序的執(zhí)行總是從main函數(shù)開始,完成對其它函數(shù)的調(diào)用后再返回到main函數(shù),最后由main函數(shù)結(jié)束整個程序。一個C源程序必須有,也只能有一個主函數(shù)main。
8.2 函數(shù)定義的一般形式
1. 無參函數(shù)的定義形式
類型標(biāo)識符 函數(shù)名()
{聲明部分
語句
}
其中類型標(biāo)識符和函數(shù)名稱為函數(shù)頭。類型標(biāo)識符指明了本函數(shù)的類型,函數(shù)的類型實際上是函數(shù)返回值的類型。 該類型標(biāo)識符與前面介紹的各種說明符相同。函數(shù)名是由用戶定義的標(biāo)識符,函數(shù)名后有一個空括號,其中無參數(shù),但括號不可少。
{}中的內(nèi)容稱為函數(shù)體。在函數(shù)體中聲明部分,是對函數(shù)體內(nèi)部所用到的變量的類型說明。
在很多情況下都不要求無參函數(shù)有返回值,此時函數(shù)類型符可以寫為void。
我們可以改寫一個函數(shù)定義:
void Hello()
{
printf ("Hello,world \n");
}
這里,只把main改為Hello作為函數(shù)名,其余不變。Hello函數(shù)是一個無參函數(shù),當(dāng)被其它函數(shù)調(diào)用時,輸出Hello world字符串。
2. 有參函數(shù)定義的一般形式
類型標(biāo)識符 函數(shù)名(形式參數(shù)表列)
{聲明部分
語句
}
有參函數(shù)比無參函數(shù)多了一個內(nèi)容,即形式參數(shù)表列。在形參表中給出的參數(shù)稱為形式參數(shù),它們可以是各種類型的變量,各參數(shù)之間用逗號間隔。在進(jìn)行函數(shù)調(diào)用時,主調(diào)函數(shù)將賦予這些形式參數(shù)實際的值。形參既然是變量,必須在形參表中給出形參的類型說明。
例如,定義一個函數(shù),用于求兩個數(shù)中的大數(shù),可寫為:
int max(int a, int b)
{
if (a>b) return a;
else return b;
}
第一行說明max函數(shù)是一個整型函數(shù),其返回的函數(shù)值是一個整數(shù)。形參為a,b,均為整型量。a,b的具體值是由主調(diào)函數(shù)在調(diào)用時傳送過來的。在{}中的函數(shù)體內(nèi),除形參外沒有使用其它變量,因此只有語句而沒有聲明部分。在max函數(shù)體中的return語句是把a(bǔ)(或b)的值作為函數(shù)的值返回給主調(diào)函數(shù)。有返回值函數(shù)中至少應(yīng)有一個return語句。
在C程序中,一個函數(shù)的定義可以放在任意位置,既可放在主函數(shù)main之前,也可放在main之后。
例如:
可把max 函數(shù)置在main之后,也可以把它放在main之前。修改后的程序如下所示。
【例8.1】
int max(int a,int b)
{
if(a>b)return a;
else return b;
}
main()
{
int max(int a,int b);
int x,y,z;
printf("input two numbers:\n");
scanf("%d%d",&x,&y);
z=max(x,y);
printf("maxmum=%d",z);
}
現(xiàn)在我們可以從函數(shù)定義、函數(shù)說明及函數(shù)調(diào)用的角度來分析整個程序,從中進(jìn)一步了解函數(shù)的各種特點。
程序的第1行至第5行為max函數(shù)定義。進(jìn)入主函數(shù)后,因為準(zhǔn)備調(diào)用max函數(shù),故先對max函數(shù)進(jìn)行說明(程序第8行)。函數(shù)定義和函數(shù)說明并不是一回事,在后面還要專門討論。 可以看出函數(shù)說明與函數(shù)定義中的函數(shù)頭部分相同,但是末尾要加分號。程序第12 行為調(diào)用max函數(shù),并把x, y中的值傳送給max的形參a, b。max函數(shù)執(zhí)行的結(jié)果(a或b)將返回給變量z。最后由主函數(shù)輸出z的值。
8.3 函數(shù)的參數(shù)和函數(shù)的值
8.3.1 形式參數(shù)和實際參數(shù)
前面已經(jīng)介紹過,函數(shù)的參數(shù)分為形參和實參兩種。在本小節(jié)中,進(jìn)一步介紹形參、實參的特點和兩者的關(guān)系。形參出現(xiàn)在函數(shù)定義中,在整個函數(shù)體內(nèi)都可以使用,離開該函數(shù)則不能使用。實參出現(xiàn)在主調(diào)函數(shù)中,進(jìn)入被調(diào)函數(shù)后,實參變量也不能使用。形參和實參的功能是作數(shù)據(jù)傳送。發(fā)生函數(shù)調(diào)用時,主調(diào)函數(shù)把實參的值傳送給被調(diào)函數(shù)的形參從而實現(xiàn)主調(diào)函數(shù)向被調(diào)函數(shù)的數(shù)據(jù)傳送。
函數(shù)的形參和實參具有以下特點:
1. 形參變量只有在被調(diào)用時才分配內(nèi)存單元,在調(diào)用結(jié)束時,即刻釋放所分配的內(nèi)存單元。因此,形參只有在函數(shù)內(nèi)部有效。函數(shù)調(diào)用結(jié)束返回主調(diào)函數(shù)后則不能再使用該形參變量。
2. 實參可以是常量、變量、表達(dá)式、函數(shù)等,無論實參是何種類型的量,在進(jìn)行函數(shù)調(diào)用時,它們都必須具有確定的值,以便把這些值傳送給形參。因此應(yīng)預(yù)先用賦值,輸入等辦法使實參獲得確定值。
3. 實參和形參在數(shù)量上,類型上,順序上應(yīng)嚴(yán)格一致,否則會發(fā)生類型不匹配”的錯誤。
4. 函數(shù)調(diào)用中發(fā)生的數(shù)據(jù)傳送是單向的。即只能把實參的值傳送給形參,而不能把形參的值反向地傳送給實參。 因此在函數(shù)調(diào)用過程中,形參的值發(fā)生改變,而實參中的值不會變化。
【例8.2】可以說明這個問題。
main()
{
int n;
printf("input number\n");
scanf("%d",&n);
s(n);
printf("n=%d\n",n);
}
int s(int n)
{
int i;
for(i=n-1;i>=1;i--)
n=n+i;
printf("n=%d\n",n);
}
本程序中定義了一個函數(shù)s,該函數(shù)的功能是求∑ni的值。在主函數(shù)中輸入n值,并作為實參,在調(diào)用時傳送給s 函數(shù)的形參量n( 注意,本例的形參變量和實參變量的標(biāo)識符都為n,但這是兩個不同的量,各自的作用域不同)。在主函數(shù)中用printf 語句輸出一次n值,這個n值是實參n的值。在函數(shù)s中也用printf 語句輸出了一次n值,這個n值是形參最后取得的n值0。從運行情況看,輸入n值為100。即實參n的值為100。把此值傳給函數(shù)s時,形參n的初值也為100,在執(zhí)行函數(shù)過程中,形參n的值變?yōu)?050。返回主函數(shù)之后,輸出實參n的值仍為100??梢妼崊⒌闹挡浑S形參的變化而變化。
8.3.2 函數(shù)的返回值
函數(shù)的值是指函數(shù)被調(diào)用之后,執(zhí)行函數(shù)體中的程序段所取得的并返回給主調(diào)函數(shù)的值。如調(diào)用正弦函數(shù)取得正弦值,調(diào)用例8.1的max函數(shù)取得的最大數(shù)等。對函數(shù)的值(或稱函數(shù)返回值)有以下一些說明:
1) 函數(shù)的值只能通過return語句返回主調(diào)函數(shù)。
return 語句的一般形式為:
return 表達(dá)式;
或者為:
return (表達(dá)式);
該語句的功能是計算表達(dá)式的值,并返回給主調(diào)函數(shù)。在函數(shù)中允許有多個return語句,但每次調(diào)用只能有一個return 語句被執(zhí)行,因此只能返回一個函數(shù)值。
2) 函數(shù)值的類型和函數(shù)定義中函數(shù)的類型應(yīng)保持一致。如果兩者不一致,則以函數(shù)類型為準(zhǔn),自動進(jìn)行類型轉(zhuǎn)換。
3) 如函數(shù)值為整型,在函數(shù)定義時可以省去類型說明。
4) 不返回函數(shù)值的函數(shù),可以明確定義為“空類型”,類型說明符為“void”。如例8.2中函數(shù)s并不向主函數(shù)返函數(shù)值,因此可定義為:
void s(int n)
{ ……
}
一旦函數(shù)被定義為空類型后,就不能在主調(diào)函數(shù)中使用被調(diào)函數(shù)的函數(shù)值了。例如,在定義s為空類型后,在主函數(shù)中寫下述語句
sum=s(n);
就是錯誤的。
為了使程序有良好的可讀性并減少出錯, 凡不要求返回值的函數(shù)都應(yīng)定義為空類型。
8.4 函數(shù)的調(diào)用
8.4.1 函數(shù)調(diào)用的一般形式
前面已經(jīng)說過,在程序中是通過對函數(shù)的調(diào)用來執(zhí)行函數(shù)體的,其過程與其它語言的子程序調(diào)用相似。
C語言中,函數(shù)調(diào)用的一般形式為:
函數(shù)名(實際參數(shù)表)
對無參函數(shù)調(diào)用時則無實際參數(shù)表。實際參數(shù)表中的參數(shù)可以是常數(shù),變量或其它構(gòu)造類型數(shù)據(jù)及表達(dá)式。各實參之間用逗號分隔。
8.4.2 函數(shù)調(diào)用的方式
在C語言中,可以用以下幾種方式調(diào)用函數(shù):
1. 函數(shù)表達(dá)式:函數(shù)作為表達(dá)式中的一項出現(xiàn)在表達(dá)式中,以函數(shù)返回值參與表達(dá)式的運算。這種方式要求函數(shù)是有返回值的。例如:z=max(x,y)是一個賦值表達(dá)式,把max的返回值賦予變量z。
2. 函數(shù)語句:函數(shù)調(diào)用的一般形式加上分號即構(gòu)成函數(shù)語句。例如: printf ("%d",a);scanf ("%d",&b);都是以函數(shù)語句的方式調(diào)用函數(shù)。
3. 函數(shù)實參:函數(shù)作為另一個函數(shù)調(diào)用的實際參數(shù)出現(xiàn)。這種情況是把該函數(shù)的返回值作為實參進(jìn)行傳送,因此要求該函數(shù)必須是有返回值的。例如: printf("%d",max(x,y)); 即是把max調(diào)用的返回值又作為printf函數(shù)的實參來使用的。在函數(shù)調(diào)用中還應(yīng)該注意的一個問題是求值順序的問題。所謂求值順序是指對實參表中各量是自左至右使用呢,還是自右至左使用。對此,各系統(tǒng)的規(guī)定不一定相同。介紹printf 函數(shù)時已提到過,這里從函數(shù)調(diào)用的角度再強(qiáng)調(diào)一下。
【例8.3】
main()
{
int i=8;
printf("%d\n%d\n%d\n%d\n",++i,--i,i++,i--);
}
如按照從右至左的順序求值。運行結(jié)果應(yīng)為:
8
7
7
8
如對printf語句中的++i,--i,i++,i--從左至右求值,結(jié)果應(yīng)為:
9
8
8
9
應(yīng)特別注意的是,無論是從左至右求值, 還是自右至左求值,其輸出順序都是不變的, 即輸出順序總是和實參表中實參的順序相同。由于Turbo C現(xiàn)定是自右至左求值,所以結(jié)果為8,7,7,8。上述問題如還不理解,上機(jī)一試就明白了。
8.4.3 被調(diào)用函數(shù)的聲明和函數(shù)原型
在主調(diào)函數(shù)中調(diào)用某函數(shù)之前應(yīng)對該被調(diào)函數(shù)進(jìn)行說明(聲明),這與使用變量之前要先進(jìn)行變量說明是一樣的。在主調(diào)函數(shù)中對被調(diào)函數(shù)作說明的目的是使編譯系統(tǒng)知道被調(diào)函數(shù)返回值的類型,以便在主調(diào)函數(shù)中按此種類型對返回值作相應(yīng)的處理。
其一般形式為:
類型說明符 被調(diào)函數(shù)名(類型 形參,類型 形參…);
或為:
類型說明符 被調(diào)函數(shù)名(類型,類型…);
括號內(nèi)給出了形參的類型和形參名,或只給出形參類型。這便于編譯系統(tǒng)進(jìn)行檢錯,以防止可能出現(xiàn)的錯誤。
例8.1 main函數(shù)中對max函數(shù)的說明為:
int max(int a,int b);
或?qū)憺?
int max(int,int);
C語言中又規(guī)定在以下幾種情況時可以省去主調(diào)函數(shù)中對被調(diào)函數(shù)的函數(shù)說明。
1) 如果被調(diào)函數(shù)的返回值是整型或字符型時,可以不對被調(diào)函數(shù)作說明,而直接調(diào)用。這時系統(tǒng)將自動對被調(diào)函數(shù)返回值按整型處理。例8.2的主函數(shù)中未對函數(shù)s作說明而直接調(diào)用即屬此種情形。
2) 當(dāng)被調(diào)函數(shù)的函數(shù)定義出現(xiàn)在主調(diào)函數(shù)之前時,在主調(diào)函數(shù)中也可以不對被調(diào)函數(shù)再作說明而直接調(diào)用。例如例8.1中,函數(shù)max的定義放在main 函數(shù)之前,因此可在main函數(shù)中省去對max函數(shù)的函數(shù)說明int max(int a,int b)。
3) 如在所有函數(shù)定義之前,在函數(shù)外預(yù)先說明了各個函數(shù)的類型,則在以后的各主調(diào)函數(shù)中,可不再對被調(diào)函數(shù)作說明。例如:
char str(int a);
float f(float b);
main()
{
……
}
char str(int a)
{
……
}
float f(float b)
{
……
}
其中第一,二行對str函數(shù)和f函數(shù)預(yù)先作了說明。因此在以后各函數(shù)中無須對str和f函數(shù)再作說明就可直接調(diào)用。
4) 對庫函數(shù)的調(diào)用不需要再作說明,但必須把該函數(shù)的頭文件用include命令包含在源文件前部。
8.5 函數(shù)的嵌套調(diào)用
C語言中不允許作嵌套的函數(shù)定義。因此各函數(shù)之間是平行的,不存在上一級函數(shù)和下一級函數(shù)的問題。但是C語言允許在一個函數(shù)的定義中出現(xiàn)對另一個函數(shù)的調(diào)用。這樣就出現(xiàn)了函數(shù)的嵌套調(diào)用。即在被調(diào)函數(shù)中又調(diào)用其它函數(shù)。這與其它語言的子程序嵌套的情形是類似的。其關(guān)系可表示如圖。
圖表示了兩層嵌套的情形。其執(zhí)行過程是:執(zhí)行main函數(shù)中調(diào)用a函數(shù)的語句時,即轉(zhuǎn)去執(zhí)行a函數(shù),在a函數(shù)中調(diào)用b 函數(shù)時,又轉(zhuǎn)去執(zhí)行b函數(shù),b函數(shù)執(zhí)行完畢返回a函數(shù)的斷點繼續(xù)執(zhí)行,a函數(shù)執(zhí)行完畢返回main函數(shù)的斷點繼續(xù)執(zhí)行。
【例8.4】計算s=22!+32!
本題可編寫兩個函數(shù),一個是用來計算平方值的函數(shù)f1,另一個是用來計算階乘值的函數(shù)f2。主函數(shù)先調(diào)f1計算出平方值,再在f1中以平方值為實參,調(diào)用 f2計算其階乘值,然后返回f1,再返回主函數(shù),在循環(huán)程序中計算累加和。
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;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -