第04章 函數(shù)與C程序結(jié)構(gòu)_第1頁
第04章 函數(shù)與C程序結(jié)構(gòu)_第2頁
第04章 函數(shù)與C程序結(jié)構(gòu)_第3頁
第04章 函數(shù)與C程序結(jié)構(gòu)_第4頁
第04章 函數(shù)與C程序結(jié)構(gòu)_第5頁
已閱讀5頁,還剩105頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

程序設(shè)計技術(shù)C語言數(shù)據(jù)描述和C程序設(shè)計初步

結(jié)構(gòu)化程序設(shè)計基礎(chǔ)和C語言的控制結(jié)構(gòu)

數(shù)組及其應(yīng)用

函數(shù)與C程序結(jié)構(gòu)

指針與函數(shù)

指針與數(shù)組

字符串及其應(yīng)用結(jié)構(gòu)體類型和聯(lián)合體類型C語言的文件處理及其應(yīng)用位運算與枚舉類型函數(shù)與程序結(jié)構(gòu)函數(shù)的定義和調(diào)用函數(shù)的嵌套調(diào)用和遞歸調(diào)用變量的作用域和生存期編譯預(yù)處理多源文件C程序的組織方法4.1函數(shù)的定義和調(diào)用C程序的一般結(jié)構(gòu)

C源程序源文件1源文件i源文件n預(yù)處理語句函數(shù)1函數(shù)n說明/定義部分執(zhí)行部分圖4.1C程序結(jié)構(gòu)從用戶使用角度分:標(biāo)準(zhǔn)函數(shù)如printf、scanf函數(shù)等。自定義函數(shù)解決用戶自己的需要。

從函數(shù)形式分:

有參函數(shù)主調(diào)函數(shù)向被調(diào)函數(shù)傳值,一般會得到一個返回值。無參函數(shù)不傳值,一般無返回值,主要執(zhí)行一些操作。4.1函數(shù)的定義和調(diào)用4.1.1函數(shù)的定義和聲明

函數(shù)定義:函數(shù)要完成的功能。

1)函數(shù)定義形式:

返回類型符函數(shù)名(形式參數(shù)表及其說明)//函數(shù)頭

{

變量定義和說明及函數(shù)執(zhí)行語句//函數(shù)體

}

2)函數(shù)體:由變量定義與函數(shù)執(zhí)行語句組成。二者全無則是空函數(shù),先占位置,以后補上。函數(shù)的定義內(nèi)容如下:函數(shù)返回值類型可是任何有效類型,void表示函數(shù)無返回值。函數(shù)名用戶自定義標(biāo)識符,不能重名。形式參數(shù)(簡稱形參)—函數(shù)定義時設(shè)置的參數(shù)作用是為函數(shù)接受外來數(shù)據(jù)提供變量名、類型和數(shù)目。如示例中的doublearea(doubler)中的r。4.1.1函數(shù)的定義和聲明定義prn函數(shù):void型、無參定義area函數(shù):返回值為double型,參數(shù)r也是double型。函數(shù)的定義函數(shù)體函數(shù)體return<表達(dá)式>語句函數(shù)的返回值必須要通過函數(shù)中的return語句獲得。1、一個函數(shù)中可以有多個return語句,執(zhí)行到哪個return,哪個return就起作用。例如根據(jù)傳過來的參數(shù)判斷,if滿足某個條件就返回if下表達(dá)式的值,否則返回else下表達(dá)式的值。執(zhí)行哪個return就看傳過來的參數(shù)是否滿足某種條件。

2、return(x)等價于returnx

3、return還可以返回表達(dá)式的值如return(x>y?x:y)返回兩者中的較大值。函數(shù)執(zhí)行結(jié)果(按函數(shù)定義的返回類型)返回給主調(diào)函數(shù)。如果函數(shù)定義時返回類型為void,則不需要return語句。4.1.1函數(shù)的定義和聲明intfind_char(chars1,chars2){if(s1==s2)return1;

elsereturn-1;}參數(shù)傳遞返回值參數(shù)傳遞返回值

注意:C語言中的每一個函數(shù)都是一個獨立的代碼塊。除調(diào)用它的語句之外,不能被任何其它函數(shù)中的任何語句所訪問。在一個函數(shù)的內(nèi)部不能定義其他函數(shù)(即函數(shù)不能嵌套定義)。這個規(guī)定保證了每個函數(shù)都是一個相對獨立的程序模塊。由多個函數(shù)組成的C程序中,各個函數(shù)的定義順序是任意的,它不影響C程序運行時函數(shù)的執(zhí)行順序

函數(shù)的定義

2)函數(shù)的聲明

將函數(shù)的名字、類型及形式參數(shù)的類型、個數(shù)及順序等通知編譯系統(tǒng),以便在調(diào)用該函數(shù)時進(jìn)行對照檢查,如函數(shù)名是否正確、實際參數(shù)的類型和個數(shù)是否與形式參數(shù)一致等等。函數(shù)的聲明標(biāo)準(zhǔn)庫函數(shù)的聲明使用標(biāo)準(zhǔn)庫函數(shù)時,由于系統(tǒng)提供的標(biāo)準(zhǔn)庫函數(shù)的說明都分門別類集中在一些稱為“頭文件”的文本文件中,所以在程序中如果要調(diào)用系統(tǒng)標(biāo)準(zhǔn)庫函數(shù),也要在程序的適當(dāng)位置使用編譯預(yù)處理語句來進(jìn)行聲明。

例如:

#include<stdio.h>

或#inlcude“stdio.h”

作用:將調(diào)用有關(guān)庫函數(shù)的必要信息包含到本源文件中來。函數(shù)的聲明用戶自定義函數(shù)的聲明

對于用戶自定義函數(shù),如果被調(diào)用函數(shù)(簡稱被調(diào)函數(shù))與調(diào)用它的函數(shù)(簡稱主調(diào)函數(shù))在同一源文件中,在函數(shù)調(diào)用之前,需要對被調(diào)函數(shù)進(jìn)行聲明。被調(diào)函數(shù)聲明的一般形式:

返回類型符函數(shù)名(形式參數(shù)表及其說明);

函數(shù)的聲明在函數(shù)聲明中,形參變量名字無關(guān)緊要(可與函數(shù)定義不同或缺?。?/p>

area函數(shù)的聲明語句可寫成如下兩種形式:

doublearea(double);

/*缺省形參名*/

doublearea(doublex);

/*形參名與定義不同*/

注意:被調(diào)函數(shù)的定義出現(xiàn)在主調(diào)函數(shù)之前,不必進(jìn)行說明,其原因是編譯系統(tǒng)此時已經(jīng)知道了被調(diào)函數(shù)的返回類型。函數(shù)的聲明標(biāo)準(zhǔn)庫函數(shù)聲明自定義函數(shù)的聲明對比對比函數(shù)調(diào)用一個函數(shù)調(diào)用另外一個函數(shù)以完成某一特定的功能稱之為函數(shù)調(diào)用。調(diào)用者稱為主調(diào)函數(shù)被調(diào)者稱為被調(diào)函數(shù)函數(shù)調(diào)用的一般形式:

函數(shù)名(實參表);調(diào)用時填入的參數(shù),稱為實際參數(shù),簡稱實參。實參的個數(shù)、類型和順序,應(yīng)該與被調(diào)函數(shù)的形參個數(shù)、類型和順序一致。4.1.2值參數(shù)傳遞的函數(shù)調(diào)用三種調(diào)用函數(shù)的方式①函數(shù)語句(p119):將函數(shù)調(diào)用作為一個單獨的C語句,此種方式主要對應(yīng)于返回值為空類型(void)或輸出語句設(shè)計在被調(diào)函數(shù)中的函數(shù)調(diào)用。②函數(shù)表達(dá)式:函數(shù)作為一項,出現(xiàn)在表達(dá)式中,以函數(shù)返回值參與表達(dá)式的運算。這種方式要求函數(shù)是有返回值的。③函數(shù)實參:函數(shù)調(diào)用作為另外一個函數(shù)調(diào)用的實際參數(shù)出現(xiàn)。此時要求函數(shù)被調(diào)用后必須要返回一個確定值以作為其外層函數(shù)調(diào)用的實際參數(shù)。如:printf(“%d\n”,area(r1)+area(r2));4.1.2值參數(shù)傳遞的函數(shù)調(diào)用如:prn();如:sum=area(r1)+area(r2);調(diào)用area函數(shù)調(diào)用prn函數(shù)傳給r返回32.153600傳給r返回91.362400函數(shù)聲明部分3.25.4printf(“sum=%lf\n”,area(r1)+area(r2));

當(dāng)一個函數(shù)調(diào)用另一個函數(shù)時,實參的值傳遞到形參變量中就實現(xiàn)了主調(diào)函數(shù)到被調(diào)函數(shù)間的數(shù)據(jù)傳遞。函數(shù)間參數(shù)傳遞有兩種方式:

傳值方式傳地址方式

4.1.2值參數(shù)傳遞的函數(shù)調(diào)用函數(shù)調(diào)用時實參的種類實參是值參數(shù)變量常數(shù)表達(dá)式實參是地址值參數(shù)指針變量變量的地址(&a)數(shù)組名或某數(shù)組元素地址函數(shù)名4.1.2值參數(shù)傳遞的函數(shù)調(diào)用

例4.3傳值方式(P119)#include<stdio.h>voidmain(){ inta=10,b=5; voidswap(intx,inty);/*函數(shù)聲明語句*/

swap(a,b);

/*函數(shù)調(diào)用語句*/ printf(“swap調(diào)用后:a=%d,b=%d\n”,a,b);}voidswap(intx,inty)/*函數(shù)的定義*/{ inttemp; temp=x,x=y,y=temp; printf(“swap調(diào)用中:x=%d,y=%d”,x,y);}4.1.2值參數(shù)傳遞的函數(shù)調(diào)用105x=5,y=10a=10,b=5為被調(diào)函數(shù)的形參變量(局部變量)分配存儲;實際參數(shù)拷貝到對應(yīng)形式參數(shù)(拷貝完成后形參與實參無關(guān));控制轉(zhuǎn)到被調(diào)函數(shù)執(zhí)行;程序控制流程從被調(diào)函數(shù)返回主調(diào)函數(shù)(系統(tǒng)自動撤消為被調(diào)函數(shù)建立的形參局部變量);105abyxtemp10510①②5③10函數(shù)調(diào)用執(zhí)行過程與參數(shù)傳遞上一張下一張重要結(jié)論:

函數(shù)的傳值調(diào)用方式是一種數(shù)據(jù)復(fù)制方式,在這種方式下,實參值通過復(fù)制的方式傳遞給形參變量,實參與形參各自占用內(nèi)存不同的存儲單元,當(dāng)數(shù)據(jù)傳遞結(jié)束后,它們互不相干。因此,在被調(diào)函數(shù)中無論形參怎樣變化,都不會影響主調(diào)函數(shù)中實參的值。4.1.2值參數(shù)傳遞的函數(shù)調(diào)用函數(shù)與程序結(jié)構(gòu)函數(shù)的定義和調(diào)用函數(shù)的嵌套調(diào)用和遞歸調(diào)用變量的作用域和生存期編譯預(yù)處理多源文件C程序的組織方法4.2函數(shù)的嵌套調(diào)用和遞歸調(diào)用

4.2.1函數(shù)的嵌套調(diào)用

(P131)

C語言規(guī)定:在C程序中所有的函數(shù)都是平行的。即在C程序中函數(shù)不能嵌套定義,但函數(shù)可以嵌套調(diào)用,即一個函數(shù)在被調(diào)用的過程中又調(diào)用了另外的一個函數(shù)。一個兩層嵌套函數(shù)調(diào)用的過程如下圖所示:被嵌套調(diào)用函數(shù)4.2.1函數(shù)的嵌套調(diào)用4.2.1函數(shù)的嵌套調(diào)用(P132)例4.12:計算s=1k+2k+3k+……+Nk

程序設(shè)計思路:可以把問題分解為兩個模塊:求冪次方模塊和求和模塊,在求和模塊中要包含求冪次方模塊。

f1()函數(shù)的參數(shù)為n和k,其返回值是n的k次方。

f2()函數(shù)的參數(shù)為n和k,返回值是冪次方的累加和。4.2.1函數(shù)的嵌套調(diào)用s=1k+2k+3k+……+Nk#include<stdio.h>longf1(intx,inty) {longpower=x;intj;for(j=1;j<y;j++)power=power*x;returnpower;}longf2(intn,intk) {longsum=0;inti;for(i=1;i<=n;i++)sum=sum+f1(i,k);returnsum;}voidmain(){intn,k,s;

scanf("%d,%d",&n,&k);s=f2(n,k);printf("自然數(shù)1~%d的%d次方和為:%ld",n,k,s);}

例4.12程序演示

43(4,3)43434.2.2函數(shù)的遞歸調(diào)用

一個函數(shù)直接地或間接地自己調(diào)用自己,稱為函數(shù)的遞歸調(diào)用。

直接遞歸調(diào)用:調(diào)用函數(shù)在函數(shù)體內(nèi)直接調(diào)用該函數(shù)自身。

間接遞歸調(diào)用:調(diào)用函數(shù)調(diào)用其他的被調(diào)函數(shù),最后又由被調(diào)函數(shù)調(diào)用到該函數(shù)自己遞歸調(diào)用可以看成是一種特殊的嵌套調(diào)用,它與一般的嵌套調(diào)用有明顯的不同點:

4.2.2函數(shù)的遞歸調(diào)用①每次嵌套調(diào)用的函數(shù)都是該函數(shù)本身;②嵌套調(diào)用不會無限制進(jìn)行下去,總會在某種條件下結(jié)束;③每次調(diào)用時,本次的函數(shù)體并沒有執(zhí)行完畢。故必須依靠系統(tǒng)提供一個特殊部件(堆棧)存放未完成的操作,以保證當(dāng)遞歸調(diào)用結(jié)束時不會丟失操作。④在遞歸調(diào)用時將遞歸過程中未執(zhí)行的操作依次從堆棧棧底開始存入(簡稱壓棧),當(dāng)遞歸結(jié)束時再依存放時的相反順序?qū)⑺鼈儚亩褩m攺棾?簡稱出棧),系統(tǒng)用堆棧指針指示應(yīng)該存入和取出數(shù)據(jù)的位置。堆棧:一段先進(jìn)后出的內(nèi)存區(qū)域。4.2.2函數(shù)的遞歸調(diào)用fac(5)→5*fac(4)fac(4)→4*fac(3)fac(3)→3*fac(2)fac(2)→2*fac(1)fac(1)→1遞歸壓棧方向(回推)fac(2)→2*fac(1)→2*1→2fac(3)→3*fac(2)→3*2→6fac(4)→4*fac(3)→4*6→24fac(5)→5*fac(4)→5*24→120遞歸回溯方向(遞推)圖4.12遞歸調(diào)用過程示意例4.14程序演示例4.14

用遞歸方式求n!。4.2.2函數(shù)的遞歸調(diào)用

例4.14

用遞歸方式求n!。遞歸公式:n!=n*(n-1)!(n>1)

遞歸結(jié)束條件:n!=1(n<=1)

遞歸算法描述:n<=1fac(n)return1returnfac(n-1)*nTF圖4.14求n!的遞歸算法555fac(4)*5fac(2)*3fac(1)*2fac(3)*45544433322211(P133)4.13遞歸調(diào)用例,反向輸出輸入的字符串。

#include<stdio.h>voidmain() {voidreverse(); reverse(); } voidreverse() {charch; ch=getchar(); if(ch==’#’) putchar(ch); else {reverse(); putchar(ch); } }輸入數(shù)據(jù):ab#輸出結(jié)果:putchar(‘a(chǎn)’)putchar(‘b’)#ba4.2.2函數(shù)的遞歸調(diào)用例4.13程序演示4.2.2函數(shù)的遞歸調(diào)用例4.15

求菲波拉契數(shù)列。已知一對小兔出生一個月后變成一對成兔,兩個月后這對成兔就會生出一對小兔,三個月后這對成兔將生出第二對小兔,而第一對小兔又長大變成一對成兔,即一月成熟,二月生育,如此類推。請用計算機求解一對小兔經(jīng)n月后將繁衍成多少對兔子?依題意分析出遞歸關(guān)系:n=1或n=2

遞歸結(jié)束條件n>=3

遞歸公式n=1或n=2f(n)return1returnf(n-1)+f(n-2)TF圖4.13菲波拉契數(shù)列算法例4.15程序演示菲波拉契數(shù)列的遞歸調(diào)用過程f(2)f(3)f(4)f(1)f(2)f(5)f(1)f(3)f(2)第一分支第二分支4.2.2函數(shù)的遞歸調(diào)用通過三個示例的分析,遞歸方式的實現(xiàn)也是基于C語言的條件控制結(jié)構(gòu)。遞歸函數(shù)設(shè)計的基本框架是相對固定的。

其一般形式描述如下:

if

遞歸結(jié)束條件成立

return

已知結(jié)果

else

將問題轉(zhuǎn)化為同性質(zhì)的較簡單子問題;以遞歸方式求解子問題(遞歸方程);

上幾例中的遞歸方程:

fac(n-1)*n例4.14putchar(ch)例4.13fib(n-1)+fib(n-2)例4.15

函數(shù)與程序結(jié)構(gòu)函數(shù)的定義和調(diào)用函數(shù)的嵌套調(diào)用和遞歸調(diào)用變量的作用域和生存期編譯預(yù)處理多源文件C程序的組織方法

一個變量的性質(zhì)可以從兩方面進(jìn)行分析:

變量的作用域:變量能夠起作用的空間范圍。

變量的生存期:其變量值存在的時間范圍。

它們的基本意義如下:一個變量在某個函數(shù)、某個源程序文件或某幾個源程序文件范圍內(nèi)是有效的,則稱其有效的范圍為該變量的作用域,在此范圍內(nèi)可以訪問或引用該變量。一個變量的值在某一時刻是存在的,則認(rèn)為這一時刻屬于該變量的“生存期”,或稱其在此時刻“存在”。4.3變量的作用域和生存期(P138)

為了能夠有效地確定變量的作用域和生存期兩項屬性,C語言用存儲類別對變量進(jìn)行限定。變量定義的完整形式為:

[存儲類別符]<數(shù)據(jù)類型符>變量表;存儲類別用于指定變量在內(nèi)存中的存放方法。數(shù)據(jù)類型說明變量的取值范圍及允許的操作;(如int:-2147483648~2147483647)變量的存儲類別有四種自動型(auto)寄存器型(register)靜態(tài)型(static)外部參照型(extern)4.3變量的作用域和生存期

可在程序的三個位置定義變量:函數(shù)內(nèi)部、函數(shù)的參數(shù)定義和函數(shù)外部。按變量的作用域分類

全局變量(外部變量):指定義在所有函數(shù)外的變量,其作用范圍從定義處開始到源文件結(jié)束為止。全局變量的定義形式:

[extern]

<數(shù)據(jù)類型符>變量表;

局部變量(自動變量):有三個位置可定義

①函數(shù)形參;②函數(shù)體內(nèi)部;③復(fù)合語句內(nèi)部。其作用域限定在定義范圍內(nèi)。局部變量的定義形式:

[auto]

<數(shù)據(jù)類型符>變量表;4.3.1變量的作用域用戶使用內(nèi)存存儲空間的情況程序區(qū)靜態(tài)存儲區(qū)動態(tài)存儲區(qū)用戶區(qū)所有的全局(外部)變量及靜態(tài)局部變量都存放在靜態(tài)存儲區(qū),程序執(zhí)行完畢才釋放。函數(shù)的形參局部(自動)變量vodimain(){……}intx;voidf1();{inty;{intz;……}}voidf2(){……}全局變量與局部變量的關(guān)系xyz0164例4.18全局變量的作用域4x4.3.1變量的作用域局部變量(自動變量)的作用域局部變量的建立和撤消由系統(tǒng)自動進(jìn)行。如在某函數(shù)中定義了自動變量,只有該函數(shù)被調(diào)用時,系統(tǒng)才為函數(shù)范圍內(nèi)的局部變量分配存儲單元;當(dāng)函數(shù)執(zhí)行完畢,自動變量被系統(tǒng)自動撤銷。在局部變量定義中省略auto的均為自動變量。

⑴自動變量的值在一個函數(shù)的兩次調(diào)用之間不會保留。

⑵不同函數(shù)中定義的同名局部變量之間是毫無關(guān)系的。4.19程序演示25254.3.1變量的作用域同名全局變量與局部變量作用域重疊問題即在某些特定的情況下,出現(xiàn)全局變量、函數(shù)內(nèi)定義的局部變量、復(fù)合語句中定義的局部變量名字相同的現(xiàn)象。即在全局變量與局部變量作用域重疊的情況下,C語言規(guī)定按“定義就近原則”來引用變量。

⑴如果定義的全局變量與函數(shù)中局部變量同名,程序進(jìn)入函數(shù)內(nèi),使用定義的同名局部變量。

⑵在復(fù)合語句中如果定義有與較大范圍(函數(shù)局部或全局)變量同名的變量,則使用該小局部范圍內(nèi)定義的同名局部變量;同名全局變量與局部變量作用域重疊問題4.21程序演示0x=20x=10x=04.3.2變量的生存期

程序運行中,不同存儲類別的變量,占用的存儲區(qū)域不同,分配的存儲時間(生存期)也不同。按變量的生存期分類局部變量(自動變量)的生存期:這類變量存儲于內(nèi)存的動態(tài)存儲區(qū),它在程序運行中使用到該變量的時間段存在。即程序進(jìn)入該函數(shù)或復(fù)合語句時才分配存儲空間,當(dāng)該函數(shù)或復(fù)合語句執(zhí)行完后存儲空間被撤銷。(未初始化的變量是隨機值)

全局變量或靜態(tài)變量(全局或局部)的生存期:這類變量存儲于內(nèi)存的靜態(tài)存儲區(qū),它在編譯時分配存儲空間,在程序運行的整個期間都存在。4.3.2變量的生存期

在C程序設(shè)計中,為了合理選擇變量的存儲類別,有必要對不同存儲類別的變量在程序中的作用分兩方面進(jìn)行討論。全局變量的存儲類別對于全局變量而言,能夠起作用的存儲類別為extern和static。局部變量的存儲類別對局部變量能夠起作用的存儲類別為auto和static。1)全局變量的存儲類別extern

擴(kuò)展作用域static

限制作用域限制強于擴(kuò)展,即若兩種存儲說明對某全局變量同時出現(xiàn),以限制說明為準(zhǔn)。intx;staticinty;externintx;externintx;externinty;yxxy是靜態(tài)全局變量不能擴(kuò)展作用域X原作用范圍File1.cpp源文件擴(kuò)展xFile2.cpp源文件擴(kuò)展xexterninty;使用extern聲明,可擴(kuò)充全局變量在一個源程序的作用域例4.22程序演示1)全局變量的存儲類別X原作用域X被擴(kuò)充后的作用域100110130

自動變量的生存期與其所在函數(shù)被調(diào)用運行的時間相同,并且自動變量的值在函數(shù)的多次調(diào)用中都不會保留。為滿足在函數(shù)的多次調(diào)用中,局部變量仍能在保持原來值基礎(chǔ)上繼續(xù)使用,C語言提供了靜態(tài)存儲類別(static)。

靜態(tài)局部變量的定義形式:

static

數(shù)據(jù)類型符變量表;2)局部變量的存儲類別靜態(tài)局部變量具有如下特點:①系統(tǒng)在編譯時就為它分配了存儲空間,且這個存儲空間在程序的整個運行期間是固定的,因此它的生存期是整個程序的運行期間。②靜態(tài)局部變量的初始化是在程序編譯時進(jìn)行的。如果在定義時沒有對它進(jìn)行初始化,那么系統(tǒng)將它自動初始化為0(int型)、0.000000(float或double型)、’\0’(char字符型)。③靜態(tài)局部變量的值在函數(shù)多次調(diào)用中具有可繼承性。④靜態(tài)局部變量的值只能在定義它的局部范圍內(nèi)使用。在它的作用域范圍之外,該靜態(tài)局部變量雖然存在,但不能對它進(jìn)行訪問。2)局部變量的存儲類別例4.23靜態(tài)局部變量與自動變量的比較1

/*Name:ex04-23.cpp*/2 #include<stdio.h>3 voidmain()4 {voidf1();5 f1();6 f1();7 }8voidf1()9 {inta=10;10 staticintb=10;11 a+=100;12 b+=100;13printf("a=%d,b=%d\n",a,b);14}例4.23程序演示2)局部變量的存儲類別110110a=110,b=110110210a=110,b=210b++;總結(jié):1、自動變量在函數(shù)內(nèi)外的“作用域”和“生存期”是一致的,即離開函數(shù)后其值不能被引用,值也不存在。2、靜態(tài)外部變量和外部變量的“作用域”和“生存期”也是一致的,離開函數(shù)后變量值仍存在,且可被引用。3、而靜態(tài)局部變量的“作用域”和“生存期”不一致,離開函數(shù)后,變量值仍存在,但不能被引用。即仍在生存期但其作用域已不存在。函數(shù)與程序結(jié)構(gòu)函數(shù)的定義和調(diào)用函數(shù)的嵌套調(diào)用和遞歸調(diào)用變量的作用域和生存期編譯預(yù)處理多源文件C程序的組織方法編譯預(yù)處理概念預(yù)處理命令是由美國國家標(biāo)準(zhǔn)化協(xié)會(ANSIC)統(tǒng)一規(guī)定的,但它不是C語言本身的組成部分,不能直接對之進(jìn)行編譯,必須在編譯前先處理它。如:#defineN20

預(yù)處理就是把程序中所有的N置換為20;又如:#include<stdio.h>預(yù)處理則是把“stdio.h”文件中的實際內(nèi)容代替該命令,經(jīng)過預(yù)處理后就可以對程序進(jìn)行編譯了。編譯預(yù)處理語句可以出現(xiàn)在C源程序的任何位置,其作用范圍是從出現(xiàn)點開始到源程序末尾。編譯預(yù)處理語句主要有如下三種:宏定義文件包含條件編譯4.4編譯預(yù)處理

宏定義分為代參數(shù)的宏定義和不代參數(shù)的宏定義不代參數(shù)的宏定義

定義形式:#define

宏標(biāo)識符字符串

調(diào)用形式:

宏標(biāo)識符(直接用在表達(dá)式中)

宏定義的作用:在宏定義的作用范圍之內(nèi),將所有的宏標(biāo)識符用指定的字符串替換。

字符串:可以是字符串常量、已定義的宏、表達(dá)式或語句組成的字符串等。

注意:

使用#define

宏標(biāo)識符語句可撤消宏定義。4.4.1宏定義4.4.1宏定義例4.24宏定義預(yù)處理/*Name:ex04-24.cpp*/#include<stdio.h>#definePI3.1415926#defineR2.0voidmain(){doublecircum();doublearea();printf(“circum=%f\n",circum());printf("area=%f\n",area());}doublecircum(){return2.0*PI*R;}

doublearea(){returnPI*R*R;}例4.24程序演示不進(jìn)行宏代換的情況宏名出現(xiàn)在一個標(biāo)識符中例:#defineloc

12345 intlocal; int12345al;(不會進(jìn)行這種替換)宏名出現(xiàn)在字符串常量中例:#definePI

3.14語句printf(“ThevalueofPIis:%f\n”,PI);結(jié)果是:ThevalueofPIis:3.1400004.4.1宏定義此處不替換4.4.1宏定義例4.25宏調(diào)用替換問題的理解/*Name:ex04-25.cpp*/#include<stdio.h>#defineN

2#defineMN+2#defineMN2*Mvoidmain(){ intx=MN; printf("x=%d\n",x); }錯誤理解:N←2M←4(2+2)MN←8(2*4)輸出結(jié)果:x=8正確理解:N←2M←2+2MN←2*2+2正確結(jié)果:x=6程序演示(N+2)帶參數(shù)的宏定義

定義形式:

#define

宏標(biāo)識符(形參表)表達(dá)式

調(diào)用形式:宏標(biāo)識符(實參表)

宏調(diào)用的作用:將所有的宏標(biāo)識符用指定的表達(dá)式替換并且用實際參數(shù)代替表達(dá)式中的形式參數(shù)。

注意:為了避免當(dāng)實際參數(shù)是表達(dá)式時引起的宏調(diào)用錯誤,最好將宏定義中表達(dá)式樣式字符串的形式參數(shù)用圓括號括起來。4.4.1宏定義4.4.1宏定義例4.26代參數(shù)宏定義使用示例/*Name:ex04-26.cpp*/#include<stdio.h>#definePI3.14159#defineS(r)PI*r*rvoidmain(){ doublea,b,area1,area2; a=3.3; b=3.2; area1=S(a); area2=S(a+b);

printf("area1=%f\narea2=%f\n",area1,area2);}程序演示#defineS(r)PI*(r)*(r)展開后:area2=3.14159*a+b*a+barea1=34.211943area2=24.127256area2=3.14159*(a+b)*(a+b)area1=34.211943area2=132.732287展開后:area1=3.14159*a*a帶參數(shù)的宏與函數(shù)的主要區(qū)別:函數(shù)的調(diào)用需要進(jìn)行控制的轉(zhuǎn)移,而帶參數(shù)的宏僅僅是表達(dá)式的替換。帶參數(shù)的宏沒有一個確定的類型。在宏中隨著帶入的實參類型的不同,其結(jié)果的類型隨之而變。函數(shù)調(diào)用時,對實際參數(shù)有數(shù)據(jù)類型的限制,要求與定義類型一致;帶參數(shù)的宏進(jìn)行調(diào)用時沒有實參數(shù)據(jù)類型的限制,實參可以是任意類型。函數(shù)調(diào)用存在從實際參數(shù)向形式參數(shù)傳遞數(shù)據(jù)的過程,而帶參數(shù)的宏調(diào)用中不存在傳遞過程,因而宏調(diào)用一般比函數(shù)調(diào)用具有較高的時間效率。4.4.1宏定義4.4.1宏定義例4.27宏調(diào)用替換問題的理解/*Name:ex04-27.cpp*/#include<stdio.h>#defineMin(x,y)(x)<(y)?(x):(y)voidmain(){ inta=1,b=2,c=3,d=4,t;

t=Min(a+b,c+d)*1000;

printf("t=%d\n",t);}

正確結(jié)果為:t=程序演示3

t=(a+b)<(c+d)?(a+b):(c+d)*10004.4.2文件包含

文件包含的一般形式:

#include<文件名>

或#include

“文件名” 文件包含的功能:在編譯本源程序文件之前,將指定的文件整個內(nèi)容嵌入到本文件之中。 文件包含中使用尖括號:意味著指示編譯系統(tǒng)按系統(tǒng)設(shè)定的標(biāo)準(zhǔn)目錄搜索被包含的文件;文件包含中使用雙引號:意味著按指定的路徑搜索,未指定路徑時則在當(dāng)前目錄中搜索。

#include<stdio.h>D:\Cxsjc\VC6\VC98\Include\stdio.h#include"D:\Cxsjc\VC6\VC98\Include\stdio.h"條件編譯使用條件編譯可以對C語言的源程序內(nèi)容進(jìn)行有選擇性地編譯。條件編譯可有效地提高程序的可移植性,并廣泛地應(yīng)用在商業(yè)軟件中,為一個程序提供各種不同的版本。條件編譯命令常用形式一

#if<條件1>

<程序段1> #elif<條件2> <程序段2> …… #else <缺省程序段> #endif

4.4.3條件編譯例4-28輸入字符,根據(jù)需要設(shè)置條件編譯,使之能將字母全改為大寫字母輸出,或全改為小寫字母輸出,直到鍵入#結(jié)束。

0104.4.3條件編譯

使用條件編譯可為一個程序提供各種不同的版本。

只需要修改此處只需要修改此處,就可以把相應(yīng)的頭文件包含進(jìn)去。函數(shù)與程序結(jié)構(gòu)函數(shù)的定義和調(diào)用函數(shù)的嵌套調(diào)用和遞歸調(diào)用變量的作用域和生存期編譯預(yù)處理多源文件C程序的組織方法多源文件C程序概念

C程序是由函數(shù)組成的模塊化結(jié)構(gòu)程序。組成一個程序的所有函數(shù)模塊可以放在同一個源程序文件中,也可以分別放在幾個不同的源程序文件中。一般情況下,一個較大的C程序可以由若干個源文件組成。多源文件C程序的組織方法使用文件包含的方法;使用工程文件的方法;4.5多源文件C程序的組織方法4.5.1使用文件包含的方法使用文件包含的方法使用預(yù)編譯語句#include將其它C源程序文件包含到本源文件,將它們組合成為一個完整的C程序。/*Name:ex04-30a.cpp*/#include<stdio.h>#include"ex04-30b.cpp"voidmain(){ intn; printf("Inputthen:"); scanf("%d",&n); printf("%d!=%ld",n,fac(n));}/*Name:ex04-30b.cpp*/longfac(longn){if(n<=1)return(1);elsereturn(fac(n-1)*n);}程序演示4.1.3指針與地址值參數(shù)傳遞的函數(shù)調(diào)用(P120)如果要在被調(diào)函數(shù)中對主調(diào)函數(shù)的實參單元進(jìn)行操作,則需要將主調(diào)函數(shù)中實參的內(nèi)存地址值傳遞給被調(diào)函數(shù)對應(yīng)的形參單元。在傳地址方式下,被調(diào)函數(shù)中用于接收對應(yīng)地址值的形參必須是指針變量或數(shù)組。本小節(jié)主要介紹指針變量的基本用法和地址值參數(shù)傳遞的函數(shù)調(diào)用。指針與函數(shù)◆指針是c語言的一個重要特色,它能夠:

調(diào)用函數(shù)時獲得1個以上的結(jié)果(返回值)

方便使用字符串

方便使用數(shù)組

動態(tài)分配內(nèi)存

有效表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu)

直接處理內(nèi)存單元的地址等使用指針能使程序簡潔、緊湊、高效、靈活。1)指針與指針變量的概念指針(一個變量的地址)

指針就是放入指針變量中的地址。指針變量(專門用來存放變量地址的變量)

內(nèi)存單元地址是用有序無符號整型數(shù)進(jìn)行編址。為了能夠操作這些地址量,有必要構(gòu)造一種變量來存儲它們,這種變量稱為“指針變量”(見圖2)。4.1.3指針與地址值參數(shù)傳遞的函數(shù)調(diào)用地址的概念

變量的地址在程序中定義的變量,編譯系統(tǒng)按變量類型分配空間。一旦分配完成,變量與內(nèi)存單元的首地址就建立了一種對應(yīng)關(guān)系。如:char型占1個字節(jié)

int型占4個字節(jié)

float型占4個字節(jié)

double型占8個字節(jié)例:inti=2,j=5,k;假定編譯時給i、j、k分配的內(nèi)存空間如圖所示:變量i占2000、2001、2002、2003四個字節(jié);變量j占2004、2005、2006、2007四個字節(jié);變量k占2008、2009、2010、2011四個字節(jié)。

1、直接訪問變量的方式

printf(“%d”,i);其含義是從2000~2003單元中取出數(shù)據(jù)

2并輸出,表面看是通過變量名來存取數(shù)據(jù),實際上編譯后已將變量名轉(zhuǎn)換為其對應(yīng)的地址,對變量的存取實際上是通過地址進(jìn)行的。⑵

scanf(“%d”,&i);其含義是將從鍵盤輸入的值放入2000~2003內(nèi)存單元中。⑶

k=i+j;的含義是從2000~2003單元中取出i值2,再從2004~2007單元中取出j值5,相加后將其和送入變量k所占的2008~2011單元中。2、間接訪問變量的方式先定義一種特殊的變量來存放變量的地址如

int*pi;

假定pi被分配了3000~3003四個字節(jié)的內(nèi)存單元

pi=&i;將變量i的起始地址2000存放到pi的3000~3003單元中,就可以先找到pi,取出變量i的起始地址(2000),然后到2000~2003單元中取出i值2,這種訪問變量的方式就叫間接訪問。地址指向變量i的單元,在c語言中形象地稱地址為“指針”,而專門用來存放指針(即地址)的變量稱為指針變量,如上例中地址2000就是變量i的指針,而pi就是指向變量i的指針變量。二、變量的指針和指向變量的指針變量變量的指針就是變量的地址,存放變量地址的變量就是指針變量,它用于指向另一個變量,這種指向關(guān)系用“*”表示。所以*pi與i是一回事

int*pi,i;pi=&i;i=2;*pi=2;

二者等價可解釋為將2賦給指針變量pi所指向的變量,也就是i。i1、定義一個指針變量一般形式:基類型*指針變量名注意:①定義為某類型的指針變量只能指向與之類型相匹配的變量;

②如基類型為int型,使指針移動一個位置或指針+1意味著移動4個字節(jié),而double則會移動8個字節(jié)。例inti,j;int*pi,*pj;/*只是定義了兩個指針變量,但沒有指向*/pi=&i;/*使pi指向變量i*/pj=&j;/*使pj指向變量j*/即將變量i的地址存放到指針變量pi中,于是pi就指向了變量i,同理,pj指向了變量j。例:floata;

int*pa;

pa=&a;×

類型不匹配,用int型指針指向了float型變量。2、指針變量的引用注意:指針變量中只能存放地址如:int*p1;

p1=2000;錯誤,2000是整數(shù)而不是地址!將變量地址賦給指針變量一定要通過取地址運算符“&”。取出指針變量所指向變量的內(nèi)容時要用指針運算符“*”。如:inta=6;int*pa;pa=&a;printf(“%d”,*pa);結(jié)果為:6pa指向變量a,*pa即變量a的內(nèi)容也就是a本身。,a,pa);1244996變量a的首地址看一個例子:利用指針的交換來交換a、b變量的值#include<stdio.h>voidmain(){inta=10,b=20;int*pa,*pb,*p,temp;pa=&a;pb=&b;p=pa;pa=pb;pb=p;

printf(“a=%d,b=%d\n”,a,b);}a=10,b=20temp=*pa;*pa=*pb;*pb=tempa=20,b=10注意:如果有pa=&a;則:①

&*pa取地址運算符“&”與指針運算符“*”同級,右結(jié)合,所以&*pa等價于

&(*pa)等價于

&a就是變量a的地址。②*&a等價于*(&a)變量a的地址相當(dāng)于pa,而*pa就是變量a本身。③(*pa)++相當(dāng)于a++,即將a值取出再加1,如果不加括號呢?*pa++等價于*(pa++),因為*和++同級,且右結(jié)合,而pa++是后綴,相當(dāng)于先做*pa,即取出a,再將pa++就指向了變量a的以后的單元,不再指向變量a了。apa&aa指針變量作為函數(shù)的形參使用指針變量作為函數(shù)的形參實現(xiàn)的是傳地址值調(diào)用方式,其主要特征為:主調(diào)函數(shù)中,以數(shù)據(jù)對象存放的地址值(地址或指針)作為實參調(diào)用另外一個函數(shù);被調(diào)函數(shù)的形參必須是可以接收地址值的指針變量;實參和形參數(shù)據(jù)類型必須相同

傳地址值調(diào)用與傳值調(diào)用的區(qū)別p1a地址a地址a地址*p1a

重要結(jié)論傳地址值調(diào)用時,數(shù)據(jù)在主調(diào)函數(shù)和被調(diào)函數(shù)中均使用同一存儲單元,所以在被調(diào)函數(shù)中對數(shù)據(jù)任何的變動必然會反映到主調(diào)函數(shù)中。4)地址值參數(shù)傳遞調(diào)用/*指針變量作參數(shù)*/voidswap(int*x,int*y){inttemp;temp=*x;*x=*y;*y=temp;}4)地址值參數(shù)傳遞調(diào)用在主調(diào)函數(shù)中inta=10,b=20;int*pa=&a,*pb=&b;swap(pa,pb);printf("a=…b=…",a,b);ab1020paxpbytemp/*普通變量作參數(shù)*/voidswap(intx,inty){intt;t=x;x=y;y=t;}4)地址值參數(shù)傳遞調(diào)用inta=10,b=20;swap(a,b);printf("a=%,b=%d\n",a,b);4.1.4數(shù)組參數(shù)傳遞的函數(shù)調(diào)用

在C程序中,既可以用數(shù)組元素作為函數(shù)的參數(shù),也可將數(shù)組整體作為函數(shù)的參數(shù)。(參見P186表6.2)使用數(shù)組元素作為參數(shù)傳遞,是實現(xiàn)函數(shù)間的傳值調(diào)用。將數(shù)組整體作為參數(shù)傳遞時,用數(shù)組名或某數(shù)組元素的地址作為函數(shù)的實參,實現(xiàn)的是函數(shù)間的傳地址值調(diào)用。4.1.4數(shù)組參數(shù)傳遞的函數(shù)調(diào)用/*ex04-07.cpp*/#include<stdio.h>#include<stdlib.h>#include<time.h>#defineN5voidmain(){ voidmyprint(intx); inta[N],b[N][N],i,j; srand(time(NULL)); printf("數(shù)組a...\n"); for(i=0;i<N;i++) { a[i]=rand()%100;

myprint(a[i]); }printf("數(shù)組b...\n");for(i=0;i<N;i++){for(j=0;j<N;j++){b[i][j]=rand()%100;

myprint(b[i][j]);}printf("\n");}}voidmyprint(intx){ printf("%4d",x);}例4.7數(shù)組元素作值傳遞一維數(shù)組作函數(shù)的參數(shù)數(shù)組名或某元素地址作為函數(shù)的實參,實參數(shù)組將它的全部或部分存儲區(qū)域提供給形參數(shù)組共享,即形參數(shù)組與實參數(shù)組是同一存儲區(qū)域或是實參數(shù)組存儲區(qū)域的一部分。當(dāng)函數(shù)調(diào)用結(jié)束后,形參數(shù)組消失,主調(diào)函數(shù)的數(shù)組就保存了形參數(shù)組操作的結(jié)果。使用數(shù)組名或數(shù)組第一個元素的地址是把整個實參數(shù)組傳遞給被調(diào)函數(shù)。使用某個數(shù)組元素的地址作為主調(diào)函數(shù)的實參可以實現(xiàn)傳遞部分?jǐn)?shù)組元素到被調(diào)函數(shù)。 abs[]/*sv[]/*va或&a[0]作實參b+i或&b[i]作實參4.1.4數(shù)組參數(shù)傳遞的函數(shù)調(diào)用4.1.4數(shù)組參數(shù)傳遞函數(shù)調(diào)用例4.8P127編制求和函數(shù)并通過該函數(shù)求數(shù)組的各元素和。數(shù)組名a作實參數(shù)組v[]為形參數(shù)組a和v共享全部存儲單元。#include<stdio.h>#defineN10voidmain(){intsum(intv[],intn);inttotal;inta[N]={1,2,3,4,5,6,7,8,9,10};total=sum(a,N);printf("total=%ld\n",total);}intsum(intv[],intn){inti,s=0;for(i=0;i<n;i++)s+=v[i];returns;}例4.8數(shù)組名作地址傳遞total=sum(&a[3],N-5);total=30v[0]、v[1]、v[2]、v[3]、v[4]a[3]、a[4]、a[5]、a[6]、a[7]a+34.1.4數(shù)組參數(shù)傳遞函數(shù)調(diào)用數(shù)組的起始地址數(shù)組的起始地址a

平面起始地址(二級地址)&a[0][0]

線性起始地址(一級地址)a[0]

線性起始地址(一級地址)*a

線性的起始地址(一級地址)圖4.8二維數(shù)組起始地址的表示

二維數(shù)組作函數(shù)的參數(shù)

二維數(shù)組存儲時也是有序地占用一片連續(xù)的內(nèi)存區(qū)域,數(shù)組名表示這段存儲區(qū)域的首地址。

注意:二維數(shù)組的起始地址有多種表示法,有平面起始地址和線性起始地址之分,例如a[4][4]。

二維數(shù)組起始地址的等價表示:aa[0]&a[0][0]*a

a[0]a[1]a[2]a[3]4.1.4數(shù)組參數(shù)傳遞函數(shù)調(diào)用使用二維數(shù)組名作為實參用二維數(shù)組名作為函數(shù)參數(shù)實現(xiàn)的是“傳地址值調(diào)用”,其本質(zhì)是實參數(shù)組將它的全部存儲區(qū)域提供給形參數(shù)組共

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論