版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第6章函數(shù)與編譯預(yù)處理
張倩第6章函數(shù)與編譯預(yù)處理
函數(shù)是C語(yǔ)言程序的基本模塊,由于采用了函數(shù)模塊式的結(jié)構(gòu),C語(yǔ)言易于實(shí)現(xiàn)結(jié)構(gòu)化程序設(shè)計(jì),使程序的結(jié)構(gòu)清晰、減少重復(fù)編寫程序的工作量、提高程序的可讀性和可維護(hù)性。本章主要介紹函數(shù)的定義與調(diào)用、函數(shù)間的數(shù)據(jù)傳遞方法、函數(shù)的遞歸調(diào)用、變量的作用域和存儲(chǔ)類別以及編譯預(yù)處理命令等相關(guān)內(nèi)容。
第6章函數(shù)與編譯預(yù)處理
第66.1函數(shù)概述6.2函數(shù)的調(diào)用6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值6.4函數(shù)的嵌套調(diào)用與遞歸調(diào)用6.5變量的作用域與存儲(chǔ)類別6.6內(nèi)部函數(shù)和外部函數(shù)6.7編譯預(yù)處理6.8文件包含6.9條件編譯
6.10程序舉例6.1函數(shù)概述
6.1.1為什么要用函數(shù)問題:如果程序的功能比較多,規(guī)模比較大,把所有代碼都寫在main函數(shù)中,就會(huì)使主函數(shù)變得龐雜、頭緒不清,閱讀和維護(hù)變得困難有時(shí)程序中要多次實(shí)現(xiàn)某一功能,就需要多次重復(fù)編寫實(shí)現(xiàn)此功能的程序代碼,這使程序冗長(zhǎng),不精煉6.1.1為什么要用函數(shù)解決的方法:用模塊化程序設(shè)計(jì)的思路采用“組裝”的辦法簡(jiǎn)化程序設(shè)計(jì)的過程事先編好一批實(shí)現(xiàn)各種不同功能的函數(shù)把它們保存在函數(shù)庫(kù)中,需要時(shí)直接用6.1.1為什么要用函數(shù)解決的方法:用模塊化程序設(shè)計(jì)的思路函數(shù)就是功能每一個(gè)函數(shù)用來(lái)實(shí)現(xiàn)一個(gè)特定的功能函數(shù)的名字應(yīng)反映其代表的功能6.1.1為什么要用函數(shù)在設(shè)計(jì)一個(gè)較大的程序時(shí),往往把它分為若干個(gè)程序模塊,每一個(gè)模塊包括一個(gè)或多個(gè)函數(shù),每個(gè)函數(shù)實(shí)現(xiàn)一個(gè)特定的功能C程序可由一個(gè)主函數(shù)和若干個(gè)其他函數(shù)構(gòu)成主函數(shù)調(diào)用其他函數(shù),其他函數(shù)也可以互相調(diào)用同一個(gè)函數(shù)可以被一個(gè)或多個(gè)函數(shù)調(diào)用任意多次
6.1.1為什么要用函數(shù)mainabcfghdeie6.1.1為什么要用函數(shù)可以使用庫(kù)函數(shù)可以使用自己編寫的函數(shù)在程序設(shè)計(jì)中要善于利用函數(shù),可以減少重復(fù)編寫程序段的工作量,同時(shí)可以方便地實(shí)現(xiàn)模塊化的程序設(shè)計(jì)6.1函數(shù)概述
在C語(yǔ)言中,函數(shù)是程序的基本組成單位,因此可以很方便地用函數(shù)作為程序模塊來(lái)實(shí)現(xiàn)C語(yǔ)言程序。利用函數(shù),不僅可以實(shí)現(xiàn)程序的模塊化,避免大量的重復(fù)工作、簡(jiǎn)化程序,提高程序的易讀性和可維護(hù)性,還可以提高效率。例如,以下是使用主函數(shù)調(diào)用line()函數(shù)輸出一個(gè)簡(jiǎn)單的信頭的程序。
#include<stdio.h>voidline()/*定義函數(shù)*/{printf("=======================================\n");}voidmain(){line();/*調(diào)用函數(shù)*/
printf("%s","XinjiangAgriculturalUniversity\n");printf(“%s”,"No.42Nanchangd,Urumqi,Xinjiang,P.R.China\n");line();/*調(diào)用函數(shù)*/}程序運(yùn)行結(jié)果:=======================================XinjiangAgriculturalUniversityNo.42NanchangRd,Urumqi,Xinjiang,P.R.China=======================================6.1函數(shù)概述說(shuō)明:
(1)一個(gè)C程序由一個(gè)或多個(gè)程序模塊組成,每一個(gè)程序模塊作為一個(gè)源程序文件。對(duì)較大的程序,一般不希望把所有內(nèi)容全放在一個(gè)文件中,而是將它們分別放在若干個(gè)源文件中,由若干個(gè)源程序文件組成一個(gè)C程序。這樣便于分別編寫、分別編譯,提高調(diào)試效率。一個(gè)源程序文件可以為多個(gè)C程序共用。說(shuō)明:
(2)一個(gè)源程序文件由一個(gè)或多個(gè)函數(shù)以及其他有關(guān)內(nèi)容(如預(yù)處理指令、數(shù)據(jù)聲明與定義等)組成。一個(gè)源程序文件是一個(gè)編譯單位,在程序編譯時(shí)是以源程序文件為單位進(jìn)行編譯的,而不是以函數(shù)為單位進(jìn)行編譯的。說(shuō)明:
(3)C程序的執(zhí)行是從main函數(shù)開始的,如果在main函數(shù)中調(diào)用其他函數(shù),在調(diào)用后流程返回到main函數(shù),在main函數(shù)中結(jié)束整個(gè)程序的運(yùn)行。說(shuō)明:
(4)所有函數(shù)都是平行的,即在定義函數(shù)時(shí)是分別進(jìn)行的,是互相獨(dú)立的。一個(gè)函數(shù)并不從屬于另一個(gè)函數(shù),即函數(shù)不能嵌套定義。函數(shù)間可以互相調(diào)用,但不能調(diào)用main函數(shù)。main函數(shù)是被操作系統(tǒng)調(diào)用的。6.1.2函數(shù)的分類
C語(yǔ)言不僅提供了極為豐富的庫(kù)函數(shù),還允許用戶建立自己定義的函數(shù)。我們可以從不同的角度對(duì)C語(yǔ)言的函數(shù)進(jìn)行分類。6.1函數(shù)概述6.1.2函數(shù)的分類
1.從函數(shù)定義的角度,函數(shù)可分為庫(kù)函數(shù)(又稱標(biāo)準(zhǔn)函數(shù))和用戶自定義函數(shù)兩種。庫(kù)函數(shù)包括了常用的數(shù)學(xué)函數(shù)、字符和字符串處理函數(shù)、輸入/輸出函數(shù)等。對(duì)每一類庫(kù)函數(shù),系統(tǒng)都提供了相應(yīng)的頭文件,該頭文件中包含了這一類庫(kù)函數(shù)的聲明,如數(shù)學(xué)函數(shù)的說(shuō)明包含在“math.h”文件中,所以程序中如果要用到庫(kù)函數(shù)時(shí),在程序文件的開頭應(yīng)使用#include命令包含相應(yīng)的頭文件。用戶自定義函數(shù)是用戶根據(jù)自己的需要編寫的函數(shù),以解決用戶的專門需要。6.1函數(shù)概述6.1.2函數(shù)的分類
2.從函數(shù)是否具有返回值的角度,函數(shù)分為有返回值函數(shù)和無(wú)返回值函數(shù)兩種。有返回值函數(shù)被調(diào)用執(zhí)行完后將向調(diào)用者返回一個(gè)執(zhí)行結(jié)果,即函數(shù)返回值。如數(shù)學(xué)函數(shù)sin()等即屬于此類函數(shù)。無(wú)返回值函數(shù)用于完成某項(xiàng)特定的處理任務(wù),執(zhí)行完成后不向調(diào)用者返回函數(shù)值。由于函數(shù)無(wú)須返回值,用戶在定義此類函數(shù)時(shí)可指定它的返回值為“空類型”,空類型的說(shuō)明符為“void”。6.1函數(shù)概述6.1.2函數(shù)的分類
3.從函數(shù)是否帶有參數(shù)角度,函數(shù)分為無(wú)參函數(shù)和有參函數(shù)兩種。無(wú)參函數(shù)在調(diào)用時(shí),主調(diào)函數(shù)并不將數(shù)據(jù)傳送給被調(diào)函數(shù)。而調(diào)用有參數(shù)函數(shù)時(shí),在主調(diào)函數(shù)和被調(diào)函數(shù)之間有數(shù)據(jù)傳送。6.1函數(shù)概述6.1.3函數(shù)的定義函數(shù)是C語(yǔ)言程序的模塊結(jié)構(gòu),除了標(biāo)準(zhǔn)庫(kù)函數(shù)以外,要在C語(yǔ)言程序中使用用戶自定義函數(shù),必須遵循函數(shù)的先定義、后聲明、再使用的步驟,即首先應(yīng)定義好函數(shù)的數(shù)據(jù)類型、存儲(chǔ)類型和函數(shù)體,然后才能進(jìn)行使用。指定函數(shù)名字、函數(shù)返回值類型、函數(shù)實(shí)現(xiàn)的功能以及參數(shù)的個(gè)數(shù)與類型,將這些信息通知編譯系統(tǒng)。
6.1函數(shù)概述指定函數(shù)的名字,以便以后按名調(diào)用指定函數(shù)類型,即函數(shù)返回值的類型指定函數(shù)參數(shù)的名字和類型,以便在調(diào)用函數(shù)時(shí)向它們傳遞數(shù)據(jù)指定函數(shù)的功能。這是最重要的,這是在函數(shù)體中解決的對(duì)于庫(kù)函數(shù),程序設(shè)計(jì)者只需用#include指令把有關(guān)的頭文件包含到本文件模塊中即可程序設(shè)計(jì)者需要在程序中自己定義想用的而庫(kù)函數(shù)并沒有提供的函數(shù)C語(yǔ)言函數(shù)的定義形式如下:
[數(shù)據(jù)類型說(shuō)明符]函數(shù)名([形參定義表]){
說(shuō)明語(yǔ)句;可執(zhí)行語(yǔ)句;
}例如:說(shuō)明:①數(shù)據(jù)類型確定該函數(shù)返回值的數(shù)據(jù)類型,缺省時(shí)系統(tǒng)認(rèn)為是整型或字符型。②函數(shù)名由用戶自己確定,必須符合C語(yǔ)言標(biāo)識(shí)符的規(guī)則。③形參之間用逗號(hào)隔開。函數(shù)可以沒有形參,但函數(shù)名后面的一對(duì)圓括號(hào)不能缺省。6.1函數(shù)概述例6.1編寫一個(gè)函數(shù),輸出由指定數(shù)量的指定字符組成的分隔條。#include<stdio.h>#include<string.h>voidline(char
c,intn)/*此函數(shù)用于輸出由指定字符組成的分隔條*/{inti;
for(i=1;i<=n;i++)/*循環(huán)n次*/
putchar(c);/*循環(huán)輸出n個(gè)字符*/
printf("\n");}voidmain(){line('*',47);/*傳送'*'字符以及輸出的字符個(gè)數(shù)47*/
printf("%s","XinjiangAgriculturalUniversity\n");
printf("%s","No.42NanchangRd,Urumqi,Xinjiang,P.R.China\n");line('*',47);/*傳送'*'字符以及輸出的字符個(gè)數(shù)47*/}程序運(yùn)行結(jié)果:*********************************************
XinjiangAgriculturalUniversityNo.42NanchangRd,Urumqi,Xinjiang,P.R.China*********************************************6.2函數(shù)的調(diào)用在C語(yǔ)言中,用戶可以根據(jù)需要調(diào)用任何函數(shù)來(lái)完成某種處理。一個(gè)函數(shù)調(diào)用另一個(gè)函數(shù)稱為函數(shù)調(diào)用。6.2函數(shù)的調(diào)用6.2.1函數(shù)的調(diào)用方式函數(shù)調(diào)用的一般形式為:函數(shù)名(實(shí)參表)
實(shí)參可以是常量、變量、表達(dá)式及函數(shù),各實(shí)參之間用逗號(hào)隔開,如果函數(shù)沒有參數(shù),則“實(shí)參表”為空。函數(shù)的調(diào)用有三種方式:
1)函數(shù)表達(dá)式。函數(shù)調(diào)用出現(xiàn)在表達(dá)式中。例如:
s=area(3,4,5);是一個(gè)賦值表達(dá)式,把a(bǔ)rea函數(shù)的返回值賦予變量s。
2)函數(shù)語(yǔ)句。函數(shù)的調(diào)用是一個(gè)單獨(dú)的語(yǔ)句。例如:printf("IloveChina.\n");scanf("%d",&a);都是以函數(shù)語(yǔ)句的方式調(diào)用函數(shù)。
3)函數(shù)參數(shù)。函數(shù)的調(diào)用出現(xiàn)在參數(shù)的位置。例如:printf("%d",min(x,y));max(max(a,b),c);前者把min函數(shù)的返回值作為printf函數(shù)的實(shí)參來(lái)使用,而后者把max函數(shù)的返回值又作為max函數(shù)的實(shí)參來(lái)使用。在函數(shù)調(diào)用中還應(yīng)該注意的一個(gè)問題是求值順序的問題,所謂求值順序是指對(duì)實(shí)參表中各量是自左至右使用呢,還是自右至左使用。對(duì)此,各系統(tǒng)的規(guī)定不一定相同。6.2函數(shù)的調(diào)用例6.2求m個(gè)元素中取出n個(gè)元素的組合數(shù)。求組合的公式為:這個(gè)問題三次計(jì)算階乘,因此編寫一個(gè)函數(shù)計(jì)算階乘,主函數(shù)三次調(diào)用計(jì)算階乘的函數(shù),即可完成組合的計(jì)算。6.2函數(shù)的調(diào)用voidmain(){longcmn;
intm,n,t;
printf("input
m,n=");
scanf("%d,%d",&m,&n);
if(m<n)/*若m<n,則交換m,n的值*/{t=m;m=n;n=t;}
cmn=fac(m);/*調(diào)用fac函數(shù)計(jì)算m!*/
cmn=cmn/fac(n);/*調(diào)用fac函數(shù)計(jì)算n!,并且計(jì)算(m!/n!)*/
cmn=cmn/fac(m-n);/*調(diào)用fac函數(shù)計(jì)算(m-n)!,并且計(jì)算m!/(n!(m-n)!)*/
printf("cmn=%ld\n",cmn);/*輸出計(jì)算結(jié)果*/}程序運(yùn)行結(jié)果:inputm,n=10,3↙cmn=1206.2函數(shù)的調(diào)用#include<stdio.h>longfac(intn)/*此函數(shù)用于計(jì)算階乘*/{longt=1;
intk;
for(k=2;k<=n;k++)t=t*k;
return(t);}6.2.2對(duì)被調(diào)函數(shù)原型的說(shuō)明
C語(yǔ)言程序中一個(gè)函數(shù)調(diào)用另一個(gè)函數(shù)需要具備的條件是:①被調(diào)用的函數(shù)必須是已經(jīng)存在的函數(shù),是庫(kù)函數(shù)或用戶自定義函數(shù)。②如果調(diào)用庫(kù)函數(shù),必須要在程序文件的開頭用#include命令將與被調(diào)用函數(shù)有關(guān)的庫(kù)函數(shù)所在的頭文件包含到文件中來(lái)。如在前面幾章已經(jīng)用過的文件包含宏命令(詳見6.8節(jié)內(nèi)容):
#include<math.h>/*說(shuō)明被調(diào)用函數(shù)將要用到數(shù)學(xué)函數(shù)*/6.2函數(shù)的調(diào)用③如果調(diào)用用戶自定義函數(shù),并且該函數(shù)與調(diào)用它的函數(shù)(即主調(diào)函數(shù))在同一個(gè)程序文件中,一般還應(yīng)該在主調(diào)函數(shù)中對(duì)被調(diào)函數(shù)作聲明。即向編譯系統(tǒng)聲明將要調(diào)用此函數(shù),并將有關(guān)信息通知編譯。與函數(shù)定義的格式對(duì)應(yīng),函數(shù)的聲明格式如下:存儲(chǔ)類型類型標(biāo)識(shí)符函數(shù)名(形參的定義表);例如:要對(duì)例6.1和例6.2中被調(diào)用函數(shù)
voidline(char
c,intn)
作函數(shù)原型的聲明,只在其最后再加一個(gè)分號(hào)即可,即:
voidline(char
c,intn);longfac(intn);6.2函數(shù)的調(diào)用#include<stdio.h>#include<string.h>voidline(char
c,intn);voidmain(){line('*',47);
printf("%s","XinjiangAgriculturalUniversity\n");
printf("%s","No.42NanchangRd,Urumqi,Xinjiang,P.R.China\n");line('*',47);}voidline(char
c,intn){inti;
for(i=1;i<=n;i++)
putchar(c);
printf("\n");}6.2函數(shù)的調(diào)用6.2.2對(duì)被調(diào)函數(shù)原型的聲明以下幾種情況可以不在主調(diào)函數(shù)中對(duì)被調(diào)函數(shù)原型進(jìn)行聲明:①如果被調(diào)用函數(shù)的定義出現(xiàn)在主調(diào)函數(shù)之前,可以不必加聲明。例如,在例6.1和例6.2中,函數(shù)line()和fac()均被寫在主函數(shù)main()之前,在主函數(shù)main()的前面可以不必對(duì)被調(diào)函數(shù)line()、fac()進(jìn)行聲明。如果函數(shù)line()和fac()均被寫在主函數(shù)main()之后,則在主函數(shù)main()之前必須對(duì)被調(diào)函數(shù)line()、fac()進(jìn)行聲明。6.2函數(shù)的調(diào)用②如果一個(gè)函數(shù)只被另一個(gè)函數(shù)所調(diào)用,在主調(diào)函數(shù)中聲明和在函數(shù)外聲明是等價(jià)的。如果一個(gè)函數(shù)被多個(gè)函數(shù)所調(diào)用,可以在所有函數(shù)的定義之前對(duì)被調(diào)函數(shù)進(jìn)行聲明,這樣,在所有主調(diào)函數(shù)中就不必再對(duì)被調(diào)函數(shù)進(jìn)行聲明了。例如:
6.2函數(shù)的調(diào)用charletter(char,char);/*以下3行在所有函數(shù)之前,且在函數(shù)外部*/floatf(float,float);int
i(float,float);voidmain()/*在main函數(shù)中要調(diào)用letter、f和i函數(shù)*/{…../*不必對(duì)它所調(diào)用的這3個(gè)函數(shù)進(jìn)行聲明*/}/*下面定義被main函數(shù)調(diào)用的3個(gè)函數(shù)*/charletter(charc1,charc2)/*定義letter函數(shù)*/{……}floatf(float
x,floaty)/*定義f函數(shù)*/{…….}int
i(float
j,floatk)/*定義i函數(shù)*/{…….}
由于在文件的開頭已對(duì)要調(diào)用的函數(shù)進(jìn)行了聲明,因此編譯系統(tǒng)從聲明中已經(jīng)知道了函數(shù)的有關(guān)情況,所以不必在主調(diào)函數(shù)中再進(jìn)行聲明。
函數(shù)的定義和函數(shù)原型的聲明不是一回事。函數(shù)的定義是對(duì)函數(shù)功能的確定,包括指定函數(shù)名、函數(shù)值的類型、形式參數(shù)及其類型、函數(shù)體等,它是一個(gè)完整的、獨(dú)立的程序函數(shù)單位。函數(shù)原型的聲明的作用是把函數(shù)的名字、函數(shù)的類型及參數(shù)的類型、個(gè)數(shù)、順序通知編譯系統(tǒng),以便在調(diào)用該函數(shù)時(shí)系統(tǒng)按此進(jìn)行對(duì)照檢查(函數(shù)名是否正確,實(shí)參和形參的個(gè)數(shù)、類型、順序是否一致)。另外,對(duì)被調(diào)函數(shù)原型的聲明,僅僅是在已定義的函數(shù)的首部最后再加一個(gè)分號(hào)即可。6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值6.3.1函數(shù)的參數(shù)傳遞方式函數(shù)的參數(shù)主要用于在主調(diào)函數(shù)和被調(diào)函數(shù)之間進(jìn)行數(shù)據(jù)傳遞。在定義函數(shù)時(shí),函數(shù)名后面圓括號(hào)中的變量名稱為形式參數(shù),簡(jiǎn)稱形參。在主調(diào)函數(shù)中調(diào)用一個(gè)函數(shù)時(shí),函數(shù)名后面圓括號(hào)中的參數(shù)稱為實(shí)際參數(shù),簡(jiǎn)稱實(shí)參。在函數(shù)調(diào)用時(shí),主調(diào)函數(shù)把實(shí)參的值(實(shí)參都必須具有確定的值)傳送給被調(diào)函數(shù)的形參,從而實(shí)現(xiàn)主調(diào)函數(shù)向被調(diào)函數(shù)的數(shù)據(jù)傳送,達(dá)到被調(diào)函數(shù)從主調(diào)函數(shù)接收數(shù)據(jù)的目的。在C語(yǔ)言中,參數(shù)的類型不同,其傳遞方式也不同,下面給出C語(yǔ)言中的參數(shù)傳遞方式。6.3.1函數(shù)的參數(shù)傳遞方式
1.簡(jiǎn)單變量作函數(shù)參數(shù)簡(jiǎn)單變量作函數(shù)參數(shù)時(shí),主調(diào)函數(shù)把實(shí)參的值傳送給被調(diào)函數(shù)的形參,從而實(shí)現(xiàn)主調(diào)函數(shù)向被調(diào)函數(shù)的數(shù)據(jù)傳送。進(jìn)行數(shù)據(jù)傳送時(shí),形參和實(shí)參具有以下特點(diǎn):①形參與實(shí)參各占獨(dú)立的存儲(chǔ)單元。但是值得注意的是,形參變量只有在被調(diào)用時(shí)才分配臨時(shí)內(nèi)存單元,在調(diào)用結(jié)束時(shí),立即釋放所分配的內(nèi)存單元。因此,形參只有在函數(shù)內(nèi)部使用,函數(shù)調(diào)用結(jié)束返回主調(diào)函數(shù)后,則不能再使用該形參變量。②函數(shù)調(diào)用中發(fā)生的數(shù)據(jù)傳送是單向的(也被稱為“值傳遞”方式),即只能把實(shí)參的值傳送給形參,而不能把形參的值反向地傳送給實(shí)參,因此在函數(shù)調(diào)用過程中,形參的值發(fā)生改變,而實(shí)參中的值不會(huì)變化。6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值例6.3編寫一個(gè)程序,將主函數(shù)中的兩個(gè)變量的值傳送給swap函數(shù)中的兩個(gè)形參,交換兩個(gè)形參的值。#include<stdio.h>voidswap(int
x,inty)/*簡(jiǎn)單變量作被調(diào)函數(shù)的形參*/{intt;t=x;x=y;y=t;/*通過中間變量t,進(jìn)行數(shù)據(jù)交換*/
printf("x=%d,y=%d\n",x,y);}voidmain(){inta=10,b=20;
swap(a,b);/*調(diào)用swap函數(shù)時(shí),簡(jiǎn)單變量a,b做實(shí)參*/
printf("a=%d,b=%d\n",a,b);}程序運(yùn)行結(jié)果:x=20,y=10a=10,b=206.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值6.3.1函數(shù)的參數(shù)傳遞方式
2.?dāng)?shù)組作為函數(shù)的參數(shù)
(1)數(shù)組元素作函數(shù)的參數(shù)數(shù)組元素作函數(shù)的參數(shù),與簡(jiǎn)單變量作參數(shù)一樣,遵循單向的“值傳遞”。即數(shù)組元素把它的值傳遞到系統(tǒng)為形參變量分配的臨時(shí)存儲(chǔ)單元中。6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值例6.4一個(gè)班學(xué)生的成績(jī)已存入一個(gè)一維數(shù)組中,調(diào)用函數(shù)統(tǒng)計(jì)及格的人數(shù)。#include<stdio.h>#defineN10int
fun(intx)/*簡(jiǎn)單變量作被調(diào)函數(shù)的形參*/{if(x>=60)return(1);/*若學(xué)生成績(jī)及格返回1*/elsereturn(0);/*若學(xué)生成績(jī)不及格返回0*/}voidmain(){int
cj[N]={76,80,65,60,58,91,47,63,70,85};
intcount=0,k;
for(k=0;k<N;k++)
if(fun(cj[k]))/*調(diào)用fun函數(shù)時(shí),數(shù)組元素cj[k]做實(shí)參*/count++;/*若fun(cj[k])的值為1,則學(xué)生及格人數(shù)加1*/
printf("count=%d\n",count);/*輸出及格的人數(shù)*/}程序運(yùn)行結(jié)果:count=8
6.3.1函數(shù)的參數(shù)傳遞方式
2.?dāng)?shù)組作為函數(shù)的參數(shù)(2)數(shù)組名作函數(shù)的參數(shù)簡(jiǎn)單變量和數(shù)組元素作函數(shù)的參數(shù),遵循的是“值傳遞”方式,而數(shù)組名作函數(shù)的參數(shù),遵循“地址傳遞”方式,即在函數(shù)調(diào)用時(shí),若數(shù)組名作函數(shù)的參數(shù),則將數(shù)組的起始地址(數(shù)組名代表數(shù)組的起始地址)作為參數(shù)傳遞給形參。換言之,“地址傳遞”方式的特點(diǎn)是,形參數(shù)組和實(shí)參數(shù)組共同使用同樣的內(nèi)存單元,被調(diào)函數(shù)中對(duì)形參數(shù)組的操作其實(shí)就是對(duì)實(shí)參數(shù)組的操作,因此,函數(shù)中對(duì)形參值的改變也會(huì)改變實(shí)參的值。6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值例6.5一個(gè)班學(xué)生的成績(jī)已存入一個(gè)一維數(shù)組中,調(diào)用函數(shù)求平均成績(jī)。#include<stdio.h>#defineN10floataverage(float
x[N])/*數(shù)組作被調(diào)函數(shù)的形參*/{floatsum=0,aver;
intk;
for(k=0;k<N;k++)/*計(jì)算成績(jī)之和*/sum+=x[k];aver=sum/N;/*計(jì)算平均成績(jī)*/
return(aver);}voidmain(){floatcj[N],aver;
intk;
printf("input%dscores:\n",N);
for(k=0;k<N;k++)/*通過鍵盤輸入N個(gè)學(xué)生的成績(jī)*/
scanf("%f",&cj[k]);aver=average(cj);/*調(diào)用average函數(shù)時(shí),數(shù)組名cj作實(shí)參*/
printf("averagescoreis:%6.2f\n",aver);}程序運(yùn)行結(jié)果:input10score:78676058908871546280↙averagescoreis:70.806.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值6.3.1函數(shù)的參數(shù)傳遞方式
2.?dāng)?shù)組作為函數(shù)的參數(shù)(3)多維數(shù)組名作函數(shù)的參數(shù)多維數(shù)組名作函數(shù)的參數(shù)時(shí),除第一維可以不指定長(zhǎng)度外(也可以指定),其余各維都必須指定長(zhǎng)度。因此,以下寫法都是合法的:
int
fun(inta[3][4])
或
int
fun(inta[][4])6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值例6.7使用調(diào)用函數(shù)的方法,求3×4的矩陣中最大和最小的元素。#include<stdio.h>#defineM3/*定義矩陣的行數(shù)*/#defineN4/*定義矩陣的列數(shù)*/voidput_matric(int
a[M][N])/*輸出矩陣的函數(shù)*/{int
i,j;
printf("arrayis:\n");
for(i=0;i<M;i++){for(j=0;j<N;j++)printf("%4d",a[i][j]);
printf("\n");}
printf("\n");}voidmax(int
a[][N],intb[])/*求矩陣元素中最大值和最小值的函數(shù)*/{int
i,j;b[0]=a[0][0];/*假設(shè)矩陣的第1行第1列的元素是最大的*/b[1]=a[0][0];/*假設(shè)矩陣的第1行第1列的元素是最小的*/
for(i=0;i<M;i++){for(j=0;j<N;j++){if(a[i][j]>b[0])/*將矩陣中最大的元素存放在b[0]中*/b[0]=a[i][j];
if(a[i][j]<b[1])/*將矩陣中最小的元素存放在b[1]中*/b[1]=a[i][j];}}}6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值voidmain(){intb[2],a[M][N]={{2,-1,6,8},{11,45,-25,0},{55,18,3,-7}};
put_matric(a);
max(a,b);
printf("maxvalueis:%4d\nminvalueis:%4d\n",b[0],b[1]);}程序運(yùn)行結(jié)果:arrayis:2-1681145-25055183-7maxvalueis:55minvalueis:-256.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值例6.8使用調(diào)用函數(shù),實(shí)現(xiàn)矩陣的轉(zhuǎn)置。#include<stdio.h>#defineN3voidput_matric(int
a[N][N])/*輸出矩陣的函數(shù)*/{int
i,j;
for(i=0;i<N;i++){for(j=0;j<N;j++)printf("%4d",a[i][j]);
printf("\n");}
printf("\n");}6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值voidfun(int
b[][N])/*實(shí)現(xiàn)矩陣轉(zhuǎn)置函數(shù)*/{int
i,j,t;
for(i=0;i<N;i++)/*將b矩陣i行j列元素和j行i列元素進(jìn)行交換*/
for(j=i+1;j<N;j++){t=b[i][j];
b[i][j]=b[j][i];b[j][i]=t;}}voidmain(){inti,j,c[N][N]={{1,55,66},{35,1,75},{25,45,1}};
printf("original
matric:\n");
put_matric(c);/*調(diào)用輸出矩陣函數(shù),輸出原始矩陣*/
fun(c);/*調(diào)用矩陣轉(zhuǎn)置函數(shù)*/
printf("transposed
matric:\n");
put_matric(c);/*調(diào)用輸出矩陣函數(shù),輸出轉(zhuǎn)置矩陣*/}程序運(yùn)行結(jié)果:
originalmatric:155663517525451transposedmatric:1352555145667516.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值6.3.2函數(shù)的返回值函數(shù)的值是指函數(shù)被調(diào)用后,執(zhí)行函數(shù)體中的語(yǔ)句序列后所取得的值。函數(shù)的值只能通過return語(yǔ)句返回主調(diào)函數(shù)。return語(yǔ)句的一般形式為:
return;return表達(dá)式;
return(表達(dá)式);
return語(yǔ)句的作用是:結(jié)束函數(shù)的執(zhí)行,并將表達(dá)式的值帶回給主調(diào)函數(shù)。6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值說(shuō)明:①表達(dá)式的類型應(yīng)與函數(shù)定義的數(shù)據(jù)類型一致,如果不一致則以函數(shù)定義的數(shù)據(jù)類型為準(zhǔn)。②在一個(gè)函數(shù)中允許有多個(gè)return語(yǔ)句,流程執(zhí)行到其中一個(gè)return時(shí),立即返回主調(diào)函數(shù)。③如果被調(diào)函數(shù)中沒有return語(yǔ)句,函數(shù)不是不帶回值,而是帶回一個(gè)不確定的值。為了明確表示函數(shù)不帶回值,可以定義函數(shù)為無(wú)類型“void”(或稱空類型)。例如:
voidprintline(){printf("**********\n");}6.3函數(shù)的參數(shù)傳遞方式與函數(shù)的返回值例6.9求一個(gè)浮點(diǎn)數(shù)的絕對(duì)值。#include<stdio.h>floatxabs(floatx)/*此函數(shù)用于求一個(gè)浮點(diǎn)數(shù)的絕對(duì)值*/{if(x<0)return(-x);else
return(x);}voidmain(){floatx,y;
printf("inputx=");
scanf("%f",&x);y=xabs(x);/*調(diào)用xabs函數(shù),并將其結(jié)果賦值給y*/
printf("y=%f\n",y);}程序運(yùn)行結(jié)果:
inputx=-3.5↙y=3.5000006.4函數(shù)的嵌套調(diào)用與遞歸調(diào)用
6.4.1函數(shù)的嵌套調(diào)用函數(shù)的定義不能嵌套,但函數(shù)的調(diào)用可以嵌套,即被調(diào)用的函數(shù)還可以再調(diào)用其它函數(shù)。函數(shù)的嵌套調(diào)用執(zhí)行過程如圖6-2所示。其執(zhí)行過程是:執(zhí)行main函數(shù)中調(diào)用f1函數(shù)的語(yǔ)句時(shí),即轉(zhuǎn)去執(zhí)行f1函數(shù),在f1函數(shù)中又調(diào)用f2函數(shù)時(shí),又轉(zhuǎn)去執(zhí)行f2函數(shù),f2函數(shù)執(zhí)行完畢返回f1函數(shù)的斷點(diǎn)繼續(xù)執(zhí)行,f1函數(shù)執(zhí)行完畢返回main函數(shù)的斷點(diǎn)繼續(xù)執(zhí)行。圖6-2函數(shù)的嵌套調(diào)用執(zhí)行過程例6.10函數(shù)的嵌套調(diào)用舉例。#include<stdio.h>voidfun2()/*定義函數(shù)f2*/{printf("BBB\n");}voidfun1()/*定義函數(shù)f1*/{printf("A\n");fun2();/*調(diào)用函數(shù)f2*/}voidmain()/*主函數(shù)*/{fun1();/*調(diào)用函數(shù)f1*/
printf("CCCCC\n");}程序運(yùn)行結(jié)果:
ABBBCCCCC6.4.2函數(shù)的遞歸調(diào)用遞歸是在連續(xù)執(zhí)行某一處理過程時(shí),該過程中的某一步要用到它自身的上一步(或上幾步)的結(jié)果。在一個(gè)程序中,若存在程序自己調(diào)用自己的現(xiàn)象就構(gòu)成了遞歸。遞歸又可分為直接遞歸和間接遞歸。如果函數(shù)funA在執(zhí)行過程又調(diào)用函數(shù)funA自己,則稱函數(shù)funA為直接遞歸。如果函數(shù)funA在執(zhí)行過程中先調(diào)用函數(shù)funB,函數(shù)funB在執(zhí)行過程中又調(diào)用函數(shù)funA,則稱函數(shù)funA為間接遞歸。6.4函數(shù)的嵌套調(diào)用與遞歸調(diào)用
f2函數(shù)調(diào)用f1函數(shù)函數(shù)的遞歸調(diào)用
f函數(shù)調(diào)用f函數(shù)
f1函數(shù)調(diào)用f2函數(shù)直接調(diào)用本函數(shù)間接調(diào)用本函數(shù)遞歸分為兩個(gè)過程:(1)第一為遞推過程:將一個(gè)原始問題分解為一個(gè)新的問題,而這個(gè)新的問題的解決方法仍與原始問題的解決方法相同,逐步從未知向已知推進(jìn),最終達(dá)到遞歸結(jié)束條件,這時(shí)遞推過程結(jié)束。(2)第二為回歸過程:從遞歸結(jié)束條件出發(fā),沿遞推的逆過程,逐一求值回歸,直至遞推的起始處,結(jié)束回歸過程,完成遞歸調(diào)用。值得注意的是,為了防止遞歸調(diào)用無(wú)終止地進(jìn)行,必須在遞歸函數(shù)的函數(shù)體中給出遞歸終止條件,當(dāng)條件滿足時(shí)則結(jié)束遞歸調(diào)用,返回上一層,從而逐層返回,直到返回最上一層而結(jié)束整個(gè)遞歸調(diào)用。6.4函數(shù)的嵌套調(diào)用與遞歸調(diào)用
例6.11用遞歸方法求n!。當(dāng)n>1時(shí),n!=n·(n-1)!,因此求n!的問題轉(zhuǎn)化成了求n·(n-1)!的問題,而求(n-1)!的問題與求n!的解決方法相同,只是求階乘的對(duì)象的值減去1。當(dāng)n的值遞減至1時(shí),n!=1,從而使遞歸得以結(jié)束。如果把求n!寫成函數(shù)fact(n)的話,則fact(n)的實(shí)現(xiàn)依賴于fact(n-1),同理fact(n-1)的實(shí)現(xiàn)依賴于fact(n-2),…,最后fact(2)的實(shí)現(xiàn)依賴于fact(1),fact(1)=1。由于已知f(1),就可以向回推,計(jì)算出f(n)。#include<stdio.h>floatfact(intn){floatt;
if(n==0||n==1)/*當(dāng)n=0或n=1時(shí),遞歸結(jié)束*/t=1;elset=n*fact(n-1);/*遞歸調(diào)用fact函數(shù),并將值賦給t*/
return(t);/*返回t的值*/}voidmain(){intn;floatf;
printf("inputn=");
scanf("%d",&n);f=fact(n);/*調(diào)用fact函數(shù),并將值賦給f*/
printf("%d!=%5.0f\n",n,f);}程序運(yùn)行結(jié)果:
inputn=5↙5!=1206.4函數(shù)的嵌套調(diào)用與遞歸調(diào)用
fac(5)輸出fac(5)mainf=fac(4)×5fac函數(shù)n=5f=fac(3)×4fac函數(shù)n=4f=fac(1)×2fac函數(shù)n=2f=fac(2)×3fac函數(shù)n=3f=1fac函數(shù)n=1fac(1)=1fac(2)=2fac(3)=6fac(4)=24fac(5)=120120例6.12用遞歸方法求斐波納契(Fibonacci)數(shù)列的第n項(xiàng)。斐波納契數(shù)列的規(guī)律是:每個(gè)數(shù)等于前兩個(gè)數(shù)之和。即斐波納契數(shù)列的第n項(xiàng)fibona(n)=fibona(n-1)+fibona(n-2),第n-1項(xiàng)fibona(n-1)=fibona(n-2)+fibona(n-3),…,最后fibona(3)=fibona(2)+fibona(1)。即當(dāng)n=1、n=2時(shí),就可以向回推,計(jì)算出fibona(n)。6.4函數(shù)的嵌套調(diào)用與遞歸調(diào)用
#include<stdio.h>longfibona(intn){longf;
if(n==1||n==2)/*當(dāng)n=1或n=2時(shí),遞歸結(jié)束*/f=1;
elsef=fibona(n-1)+fibona(n-2);/*遞歸調(diào)用*/
return(f);}voidmain(){longintn;
printf("inputn=");scanf("%ld",&n);printf("fibona=%ld\n",fibona(n));/*調(diào)用fibona函數(shù),并輸出其值*/}程序運(yùn)行結(jié)果:inputn=20↙fibona=67656.4函數(shù)的嵌套調(diào)用與遞歸調(diào)用
6.5變量的作用域與存儲(chǔ)類別
C語(yǔ)言程序中的任何變量,系統(tǒng)都會(huì)在適當(dāng)?shù)臅r(shí)間為變量分配內(nèi)存單元,而且每一個(gè)變量都有兩個(gè)屬性:數(shù)據(jù)類型和數(shù)據(jù)的存儲(chǔ)類別。變量的數(shù)據(jù)類型決定了變量在內(nèi)存中所占的字節(jié)數(shù)以及數(shù)據(jù)的表示方法。變量的存儲(chǔ)類別決定了變量的空間上的作用域和時(shí)間上的生存期(變量存在的時(shí)間)。例如在前面我們已介紹,以某種數(shù)據(jù)類型聲明的函數(shù)的形參變量只有在函數(shù)被調(diào)用期間才分配內(nèi)存單元,調(diào)用結(jié)束立即釋放。這一點(diǎn)表明形參變量只有在函數(shù)內(nèi)才是有效的,離開該函數(shù)就不能再使用了。本節(jié)將介紹變量的作用域與存儲(chǔ)類別。6.5.1局部變量和全局變量在C語(yǔ)言中,所有的變量都有自己的作用域。變量的作用域是指變量在C程序中的有效范圍。變量定義的位置不同,其作用域也不同。C語(yǔ)言中的變量按照作用域,分為局部變量和全局變量,也稱為內(nèi)部變量和外部變量。如果變量定義在某函數(shù)或復(fù)合語(yǔ)句內(nèi)部,則稱該變量為局部變量。也就是說(shuō),局部變量只在定義它的函數(shù)內(nèi)部或復(fù)合語(yǔ)句內(nèi)有效。如果變量定義在所有函數(shù)外部,則稱該變量為全局變量。也就是說(shuō),全局變量的作用范圍是從定義變量的位置開始到本程序文件結(jié)束,即全局變量可以被在其定義位置之后的其他函數(shù)所共享。6.5變量的作用域與存儲(chǔ)類別
u、v、w雖然都是全局變量,但它們的作用范圍不同。即u、v在整個(gè)程序中都可以使用,而w只能在函數(shù)f2和主函數(shù)main中可以使用,不能在函數(shù)f1中使用。另外,允許在不同的函數(shù)中使用相同的變量名(如局部變量a、j),它們代表不同的對(duì)象,分配不同的存儲(chǔ)單元,互不干涉,也不會(huì)發(fā)生混淆。例6.13下面程序中包含有復(fù)合語(yǔ)句,分析其運(yùn)行結(jié)果。
#include<stdio.h>voidmain(){inti=2,j=3,k;k=i+j;{intk=8;/*復(fù)合語(yǔ)句開始*/
if(i==2){i=3;printf("k1=%d\n",k);}}/*復(fù)合語(yǔ)句結(jié)束*/
printf("i=%d\nk2=%d\n",i,k);}程序運(yùn)行結(jié)果:k1=8i=3k2=5例6.14分析下面程序的運(yùn)行結(jié)果。#include<stdio.h>voidfun();intn=5;/*定義全局變量n*/voidmain(){intn=10;/*定義局部變量n*/fun();/*調(diào)用函數(shù)fun()*/printf("n=%d\n",n);/*局部變量起作用*/}voidfun(){printf("n=%d\n",n);/*全局變量起作用*/}程序運(yùn)行結(jié)果:n=5n=10上述程序中,定義了兩個(gè)變量n,值為5的n是全局變量,其作用域是整個(gè)程序范圍,值為10的n是局部變量,其作用域是main函數(shù)內(nèi),執(zhí)行主函數(shù)時(shí),全局變量被屏蔽不起作用,所以輸出10。fun()函數(shù)被調(diào)用時(shí),該函數(shù)中出現(xiàn)的是全局變量,所以輸出5。使用全局變量時(shí)要注意以下幾個(gè)問題:①全局變量可以在多個(gè)函數(shù)中使用,當(dāng)其中一個(gè)函數(shù)改變了全局變量的值時(shí),可能會(huì)影響其他函數(shù)的執(zhí)行結(jié)果。②全局變量在整個(gè)程序執(zhí)行過程中始終占用存儲(chǔ)單元,因而浪費(fèi)內(nèi)存空間。③在一個(gè)函數(shù)內(nèi)定義了一個(gè)與全局變量名相同的局部變量(或者是形參)時(shí),局部變量有效,而全局變量在該函數(shù)內(nèi)不起作用。6.5.1局部變量和全局變量
6.5.2變量的動(dòng)態(tài)和靜態(tài)存儲(chǔ)方式編譯后的C語(yǔ)言程序,在內(nèi)存中占用的存儲(chǔ)空間通常分為程序區(qū)(存放代碼)、靜態(tài)存儲(chǔ)區(qū)(存放數(shù)據(jù))和動(dòng)態(tài)存儲(chǔ)區(qū)(存放數(shù)據(jù))三個(gè)部分。其中,程序區(qū)中存放的是可執(zhí)行程序的機(jī)器指令;靜態(tài)存儲(chǔ)區(qū)中存放的是需要占用固定存儲(chǔ)單元的變量;動(dòng)態(tài)存儲(chǔ)區(qū)中存放的是不需要占用固定存儲(chǔ)單元的變量。因而,從存儲(chǔ)空間的角度,我們把變量分為動(dòng)態(tài)存儲(chǔ)變量和靜態(tài)變量。6.5變量的作用域與存儲(chǔ)類別
動(dòng)態(tài)存儲(chǔ)變量(也稱自動(dòng)類變量)是指那些當(dāng)程序的流程轉(zhuǎn)到該函數(shù)時(shí)才開辟內(nèi)存單元,執(zhí)行后又立即釋放的變量。靜態(tài)存儲(chǔ)變量則是指在整個(gè)程序運(yùn)行期間分配固定存儲(chǔ)空間的變量。
C語(yǔ)言根據(jù)變量的動(dòng)態(tài)和靜態(tài)存儲(chǔ)方式提供了4種存儲(chǔ)類別,分別是:auto(動(dòng)態(tài)存儲(chǔ)類別)、extern(外部存儲(chǔ)類別)、register(寄存器型存儲(chǔ)類別)和static(靜態(tài)存儲(chǔ)類別)。一個(gè)完整的變量說(shuō)明的格式如下:存儲(chǔ)類別類型變量名表例如:
staticfloatx,y;/*表示定義了靜態(tài)存儲(chǔ)類別的整型變量x和y*/6.5變量的作用域與存儲(chǔ)類別
6.5.3局部變量的存儲(chǔ)類別局部變量有三種存儲(chǔ)類別:auto、static和register型。
1.a(chǎn)uto存儲(chǔ)類別在函數(shù)體內(nèi)或復(fù)合語(yǔ)句內(nèi)定義變量時(shí),如果沒有指定存儲(chǔ)類型或使用了auto,系統(tǒng)都認(rèn)為所定義的變量為auto存儲(chǔ)類別。auto存儲(chǔ)類別的變量也稱為自動(dòng)變量。例如,以下兩種定義方法是等價(jià)的。
autointa=2,b;
inta=2,b;
函數(shù)中的局部變量,如不專門定義類別,都是動(dòng)態(tài)地分配存儲(chǔ)空間的。函數(shù)中的形參和在函數(shù)中定義的變量,都屬于此類,在調(diào)用該函數(shù)時(shí)系統(tǒng)會(huì)給它們分配臨時(shí)的存儲(chǔ)空間,在函數(shù)調(diào)用結(jié)束時(shí)就自動(dòng)釋放這些存儲(chǔ)空間。6.5變量的作用域與存儲(chǔ)類別
例6.16分析下面程序的運(yùn)行結(jié)果。#include<stdio.h>voidfun(){intn=2;/*沒有指定n的存儲(chǔ)類別,因此n為auto存儲(chǔ)類別的局部變量*/n++;
printf("n=%d\n",n);}voidmain(){fun();fun();}函數(shù)fun()中定義的n為自動(dòng)變量。第一次調(diào)用時(shí),系統(tǒng)為n分配臨時(shí)存儲(chǔ)單元,n的初值為2,執(zhí)行n++后,n的值為3,輸出3。第一次調(diào)用后分配給n的存儲(chǔ)單元被釋放,第二次調(diào)用時(shí),系統(tǒng)為n重新分配存儲(chǔ)單元,因此輸出結(jié)果仍然是3。運(yùn)行結(jié)果:n=3n=3
2.static存儲(chǔ)類別對(duì)于某些局部變量,如果希望在函數(shù)調(diào)用結(jié)束后仍然保留函數(shù)中定義的局部變量的值,則可以使用static將該局部變量定義為靜態(tài)局部變量。例如:
staticdoublex;
靜態(tài)局部變量是在靜態(tài)存儲(chǔ)區(qū)中分配存儲(chǔ)空間,在程序的整個(gè)執(zhí)行過程中不釋放,因此函數(shù)調(diào)用結(jié)束后,它的值并不消失,其值能夠保持連續(xù)性。使用靜態(tài)局部變量時(shí)特別要注意初始化,靜態(tài)局部變量是在編譯過程中賦初值的,且只賦一次初值,以后調(diào)用函數(shù)時(shí)不再賦初值,而是保留前一次調(diào)用函數(shù)時(shí)的結(jié)果。這一點(diǎn)是局部靜態(tài)變量和自動(dòng)變量的本質(zhì)的區(qū)別。6.5變量的作用域與存儲(chǔ)類別
例如,如果將第三個(gè)語(yǔ)句intn=2;改為staticintn=2;,即將auto存儲(chǔ)類別的局部變量改為靜態(tài)局部變量,則結(jié)果不同。因?yàn)榈谝淮握{(diào)用時(shí),系統(tǒng)為n分配臨時(shí)存儲(chǔ)單元,n的初值為2,執(zhí)行n++后,n的值為3,輸出3。第一次調(diào)用結(jié)束后分配給n的存儲(chǔ)單元不釋放,第二次調(diào)用時(shí),n仍然使用原存儲(chǔ)單元,不再執(zhí)行staticintn=2;語(yǔ)句,n的值不是2,而是3,再執(zhí)行n++后,n的值為4,因此輸出結(jié)果是4。6.5變量的作用域與存儲(chǔ)類別
#include<stdio.h>voidfun(){intn=2;/*auto存儲(chǔ)類別局部變量*/n++;
printf("n=%d\n",n);}voidmain(){fun();fun();}#include<stdio.h>voidfun(){static
intn=2;/*靜態(tài)局部變量*/n++;
printf("n=%d\n",n);}voidmain(){fun();fun();}運(yùn)行結(jié)果:n=3n=3運(yùn)行結(jié)果:n=3n=4
3.register存儲(chǔ)類別自動(dòng)變量和靜態(tài)局部變量都存放在計(jì)算機(jī)的內(nèi)存中。由于計(jì)算機(jī)從寄存器中讀取數(shù)據(jù)比從內(nèi)存中讀取速度快,所以為了提高程序的運(yùn)算速度,C語(yǔ)言允許將一些頻繁使用的局部變量定義為寄存器變量,這樣程序盡可能地為它分配寄存器存放,而不用內(nèi)存。例如:
registerintm;6.5變量的作用域與存儲(chǔ)類別
使用寄存器變量時(shí)要注意以下幾點(diǎn):①CPU中寄存器的數(shù)目是有限的,因此只能把極少數(shù)的頻繁使用的變量定義為寄存器變量。②寄存器變量不是保存在內(nèi)存中,因此不能進(jìn)行取地址運(yùn)算。③只有動(dòng)態(tài)局部變量才能定義成寄存器變量,全局變量和靜態(tài)局部變量不行。6.5.3局部變量的存儲(chǔ)類別6.5.4全局變量的存儲(chǔ)類別全部變量有兩種存儲(chǔ)類別:extern和static型。
1.extern存儲(chǔ)類別一個(gè)大型的C語(yǔ)言程序可以由多個(gè)源程序文件組成,這些源程序文件分別被經(jīng)過編譯和連接之后最終生成一個(gè)可執(zhí)行文件。如果其中一個(gè)文件要引用另一個(gè)文件中定義的外部變量,就應(yīng)該在需要引用此變量的文件中用關(guān)鍵字extern把此變量說(shuō)明為外部的即可。這種說(shuō)明一般應(yīng)在文件的開頭且位于所有函數(shù)的外面。例如:
externintn;
則說(shuō)明全局變量n在其他源程序文件中已經(jīng)說(shuō)明。6.5變量的作用域與存儲(chǔ)類別
例6.18用extern將全局變量的作用域擴(kuò)展到其他源程序文件中舉例。文件file1.c的內(nèi)容如下:
文件file2.c的內(nèi)容如下:
intn;/*定義全局變量n*/externintn;/*聲明全局變量n*/voidmain()voidfun(){n=1;{printf("fun:n=%d\n",n);fun();n++;
printf("main:n=%d\n",n);}}程序運(yùn)行結(jié)果:fun:n=1main:n=2
在file1.c文件中定義了全局變量n,此時(shí)給它分配存儲(chǔ)單元,在file2.c文件中只是對(duì)該變量進(jìn)行了聲明。在main函數(shù)中先給n賦值1,后調(diào)用fun函數(shù),fun函數(shù)先輸出n的值,輸出1,后執(zhí)行n++;n=2,返回main函數(shù),再輸出2。另外,若在同一個(gè)源程序文件中,全局變量的定義位于引用它的函數(shù)的后面時(shí),也可以在要引用該全局變量的函數(shù)中,用extern來(lái)說(shuō)明該變量是全局的,然后再引用該變量。即全局變量可以被所定義的同一個(gè)源程序文件中的各個(gè)函數(shù)共同引用。6.5變量的作用域與存儲(chǔ)類別
例6.19舉例說(shuō)明用extern聲明全局變量,以擴(kuò)展它在源程序文件中的作用域。#include<stdio.h>voidmain(){intm;intmax(intx,inty);
externint
a,b;/*聲明全局變量*/m=max(a,b);
printf("max=%d\n",m);}inta=3,b=5;
/*聲明全局變量*/intmax(intx,inty){return(x>y?x:y);}程序運(yùn)行結(jié)果:max=56.5變量的作用域與存儲(chǔ)類別
6.5.4全局變量的存儲(chǔ)類別
2.static存儲(chǔ)類別與extern存儲(chǔ)類別相反,如果希望一個(gè)源程序文件中的全局變量?jī)H限于該文件使用,只要在該全局變量定義時(shí)的類型說(shuō)明前加一個(gè)static即可。例如:staticintm;
則說(shuō)明全局變量m只能在該源程序文件內(nèi)有效,其他文件不能應(yīng)用。6.5變量的作用域與存儲(chǔ)類別
6.6內(nèi)部函數(shù)和外部函數(shù)
一個(gè)C語(yǔ)言程序可以由多個(gè)函數(shù)組成,這些函數(shù)既可以在一個(gè)文件中,也可以分散在多個(gè)不同的文件中,根據(jù)函數(shù)能否被其它文件中的函數(shù)調(diào)用,將函數(shù)分為內(nèi)部函數(shù)和外部函數(shù)。6.6內(nèi)部函數(shù)和外部函數(shù)6.6.1內(nèi)部函數(shù)
如果在一個(gè)文件中定義的函數(shù),只能被本文件中的函數(shù)調(diào)用,而不能被其它文件中的函數(shù)調(diào)用,則稱它為內(nèi)部函數(shù)。定義內(nèi)部函數(shù)時(shí)在函數(shù)類型前面加上關(guān)鍵字static。即:
static類型標(biāo)識(shí)符函數(shù)名([形參列表])
{
函數(shù)體
}例6.21內(nèi)部函數(shù)的說(shuō)明示例。文件file1.c的內(nèi)容如下:文件file2.c的內(nèi)容如下:
#include<stdio.h>#include<stdio.h>externinta;inta=2;staticvoidfun()voidmain(){{fun();a=a+1;printf("a=%d\n",a);}}在文件file1.c中定義了靜態(tài)函數(shù)fun,這就限制了函數(shù)fun的作用域只是在file1.c內(nèi),所以file2.c中函數(shù)調(diào)用語(yǔ)句fun();是錯(cuò)誤的,編譯時(shí)會(huì)出錯(cuò)。6.6內(nèi)部函數(shù)和外部函數(shù)6.6.2外部函數(shù)如果在一個(gè)源程序文件中定義的函數(shù),除了可以被本文件中的函數(shù)調(diào)用外,還可以被其它文件中的函數(shù)調(diào)用,則稱它為外部函數(shù)。定義外部函數(shù)時(shí)在函數(shù)類型前面加上關(guān)鍵字extern。即:
[extern]類型標(biāo)識(shí)符函數(shù)名([形參列表]){
函數(shù)體
}
定義外部函數(shù)時(shí),關(guān)鍵字extern可以省略,本書前面定義的函數(shù)都是外部函數(shù)。在需要調(diào)用外部函數(shù)的文件中,需要用extern對(duì)被調(diào)用的外部函數(shù)進(jìn)行如下聲明:
extern函數(shù)類型函數(shù)名([形參列表]);6.6內(nèi)部函數(shù)和外部函數(shù)例6.22外部函數(shù)的說(shuō)明示例。文件file1.c的內(nèi)容如下:文件file2.c的內(nèi)容如下:
#include<stdio.h>#include<stdio.h>externvoidfun(charstr1[100])voidmain(){{externvoidfun(charstr1[100]);…charstr2[100];}…fun(str2);…}6.6內(nèi)部函數(shù)和外部函數(shù)6.7編譯預(yù)處理
編譯預(yù)處理是在對(duì)源程序進(jìn)行正式編譯之前的處理。即編譯預(yù)處理負(fù)責(zé)在正式編譯之前對(duì)源程序的一些特殊行進(jìn)行預(yù)加工,通過編譯系統(tǒng)的預(yù)處理程序執(zhí)行源程序中的預(yù)處理。
在C語(yǔ)言程序中加入一些預(yù)處理命令,可以改善程序設(shè)計(jì)的環(huán)境,有助于編寫、易讀、易移植、易調(diào)試,也是模塊化程序設(shè)計(jì)的一個(gè)工具。6.7編譯預(yù)處理預(yù)處理命令都是以“#”開頭,末尾不加分號(hào),以區(qū)別C語(yǔ)句與C聲明和定義。預(yù)處理命令可以出現(xiàn)在程序的任何地方,但一般都將預(yù)處理命令放在源程序的首部,其作用域從說(shuō)明的位置開始到所在源程序的末尾。#include<stdio.h>#definePI3.141492voidmain(){floatr=2;s=PI*r*r;
printf("s=%6.2f\n",s);}#include<stdio.h>voidmain(){#definePI3.141492floatr=2;s=PI*r*r;
printf("s=%6.2f\n",s);}
C語(yǔ)言提供的預(yù)處理功能主要有三種:宏定義、文件包含和條件編譯,分別用宏定義命令、文件包含命令和條件編譯命令來(lái)實(shí)現(xiàn)。
6.7.1宏定義通過預(yù)處理命令#define指定的預(yù)處理就是宏定義。宏定義的作用是用標(biāo)識(shí)符來(lái)代表一個(gè)字符串,一旦對(duì)字符串命名,就可在源程序中使用宏定義標(biāo)識(shí)符,系統(tǒng)編譯之前會(huì)自動(dòng)將標(biāo)識(shí)符替換成字符串。通常把被定義為宏的標(biāo)識(shí)符稱為宏名,在編譯預(yù)處理時(shí),對(duì)程序中所有出現(xiàn)的宏名,都用宏定義中的字符串去替換,這個(gè)過程叫宏代換或宏展開。宏定義是由源程序中的宏定義命令完成的,宏替換是由預(yù)處理源程序自動(dòng)完成的。根據(jù)是否帶參數(shù)將宏定義分為不帶參數(shù)的宏定義和帶參數(shù)的宏定義。6.7編譯預(yù)處理
6.7.1宏定義
1.不帶參數(shù)的宏定義不帶參數(shù)的宏定義的一般形式如下:
#define標(biāo)識(shí)符字符串其中,define是關(guān)鍵字,它表示宏定義命令。標(biāo)識(shí)符為所定義的宏名,它的寫法符合C語(yǔ)言標(biāo)識(shí)符的規(guī)則。字符串可以是常數(shù)、表達(dá)式、格式串等。例如:
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 上海二手房產(chǎn)交易協(xié)議關(guān)鍵條款(2024版)版B版
- 小學(xué)教師如何運(yùn)用評(píng)價(jià)系統(tǒng)進(jìn)行課堂管理
- 市場(chǎng)營(yíng)銷專業(yè)掌握市場(chǎng)脈搏
- 教育大數(shù)據(jù)在小學(xué)數(shù)學(xué)教學(xué)中的應(yīng)用
- 二零二五版民商法擔(dān)保合同標(biāo)的執(zhí)行細(xì)則4篇
- 學(xué)生心理健康教育的挑戰(zhàn)與對(duì)策
- 校園公交亭租賃合同2025版:含設(shè)施升級(jí)條款3篇
- 現(xiàn)代家庭的日常聚會(huì)美食規(guī)劃建議
- 演講者的技巧學(xué)術(shù)會(huì)議論文匯報(bào)的關(guān)鍵要素
- 二零二五版長(zhǎng)途客運(yùn)駕駛員勞動(dòng)合同規(guī)范3篇
- 化學(xué)-河南省TOP二十名校2025屆高三調(diào)研考試(三)試題和答案
- 智慧農(nóng)貿(mào)批發(fā)市場(chǎng)平臺(tái)規(guī)劃建設(shè)方案
- 2023年水利部黃河水利委員會(huì)招聘考試真題
- Python編程基礎(chǔ)(項(xiàng)目式微課版)教案22
- 半導(dǎo)體工藝用膠帶全球市場(chǎng)、份額、市場(chǎng)規(guī)模、趨勢(shì)、行業(yè)分析報(bào)告2024-2030年
- 建筑施工中常見的安全問題及解決方法
- 近五年重慶中考物理試題及答案2023
- 乳腺導(dǎo)管原位癌
- 冷庫(kù)管道應(yīng)急預(yù)案
- 《學(xué)習(xí)教育重要論述》考試復(fù)習(xí)題庫(kù)(共250余題)
- 網(wǎng)易云音樂用戶情感畫像研究
評(píng)論
0/150
提交評(píng)論