C語言程序設(shè)計:第6章 模塊化程序設(shè)計與函數(shù)_第1頁
C語言程序設(shè)計:第6章 模塊化程序設(shè)計與函數(shù)_第2頁
C語言程序設(shè)計:第6章 模塊化程序設(shè)計與函數(shù)_第3頁
C語言程序設(shè)計:第6章 模塊化程序設(shè)計與函數(shù)_第4頁
C語言程序設(shè)計:第6章 模塊化程序設(shè)計與函數(shù)_第5頁
已閱讀5頁,還剩114頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第6章模塊化程序設(shè)計與函數(shù)2主要內(nèi)容6.1函數(shù)概述6.2函數(shù)定義6.3函數(shù)返回6.4函數(shù)調(diào)用6.5標(biāo)識符的作用域6.6變量的存儲屬性6.7*參數(shù)個數(shù)可變函數(shù)的定義及調(diào)用6.8編譯預(yù)處理及預(yù)處理命令36.1函數(shù)概述6.1.1模塊化程序設(shè)計6.1.2函數(shù)46.1.1模塊化程序設(shè)計大規(guī)模程序開發(fā)策略——模塊化模塊化程序開發(fā)基本步驟(1)設(shè)計階段自頂向下將一個原始復(fù)雜任務(wù)分解為多個較簡單的子任務(wù)。(2)編碼階段自低向上為每個單一功能的子任務(wù)設(shè)計算法,將描述其算法的一組語句封裝為一個獨立代碼塊,為每個獨立代碼塊定義一個名字和能與其他獨立代碼塊通信的接口。模塊化策略開發(fā)程序的優(yōu)點從整體上簡化概念結(jié)構(gòu),降低程序開發(fā)和修改的復(fù)雜度,提高程序易讀性。56.1.2函數(shù)函數(shù)是什么將一組語句封裝為一個獨立代碼塊的實現(xiàn)方法。與函數(shù)有關(guān)的3個語法概念函數(shù)聲明,函數(shù)調(diào)用,函數(shù)返回。66.1.2函數(shù)#include<stdio.h>#include<conio.h>intmax(intx,inty);/*函數(shù)引用性聲明*/intmin(intx,inty);/*函數(shù)引用性聲明*/intmain(void)/*函數(shù)定義性聲明*/{charcmd;inta,b,c;printf(“\nInputtwonumber:”);scanf(“%d%d”,&a,&b);printf(“Inputcommand:\n1.max\n2.min\n3.average“);

cmd=getch();switch(cmd){ case‘1’:c=max(a,b);/*函數(shù)調(diào)用*/

break;case‘2’:c=min(a,b);/*函數(shù)調(diào)用*/

break;case‘3’:c=(a+b)/2;}76.1.2函數(shù)printf(“\nresultis%d”,c);return0;}intmax(intx,inty)/*函數(shù)定義性聲明*/{intz;if(x>y)z=x;elsez=y;returnz;}intmin(intx,inty)/*函數(shù)定義性聲明*/{if(x<y)returnx;elsereturny;}86.1.2函數(shù)(1)函數(shù)定義性聲明(簡稱“函數(shù)定義”)將一組語句和一組可接收外部數(shù)據(jù)的變量定義為一個獨立代碼塊,用函數(shù)名(符號)標(biāo)識。例如:intmax(intx,inty)/*函數(shù)定義*/{intz;if(x>y)z=x;elsez=y;returnz;}

函數(shù)聲明

96.1.2函數(shù)函數(shù)定義是C源程序必不可少的構(gòu)件。一個源程序中包含的所有函數(shù)定義可按任意次序保存在一個源文件(擴展名“.c”)中,也可以經(jīng)分割后保存在多個源文件中。不允許將一個函數(shù)定義分割開來保存在多個源文件中。

函數(shù)定義的分類:庫函數(shù):不需定義,可多次調(diào)用,例sqrt()自定義函數(shù):定義一次,可多次調(diào)用,例min()

函數(shù)定義性聲明

106.1.2函數(shù) 函數(shù)引用性聲明(簡稱“函數(shù)聲明”)描述一個函數(shù)的特性及擴大函數(shù)名的作用域。例如:intmax(intx,inty);

⑵函數(shù)引用性聲明

116.1.2函數(shù)從當(dāng)前正在執(zhí)行的函數(shù)跳轉(zhuǎn)到另一個函數(shù)執(zhí)行或重新開始執(zhí)行本函數(shù)的操作。例如:max(a,b)min(a,b)printf(“\nresultis%d”,c)

函數(shù)調(diào)用126.1.2函數(shù)結(jié)束被調(diào)函數(shù)執(zhí)行返回主調(diào)函數(shù)的操作。函數(shù)返回時,被調(diào)函數(shù)可以將一個結(jié)果值帶回主調(diào)函數(shù),這個值被稱為“函數(shù)返回值”。例如:intmax(intx,inty){intz;if(x>y)z=x;elsez=y;returnz;/*函數(shù)返回語句,z:返回值*/}函數(shù)返回136.2函數(shù)定義6.2.1函數(shù)定義形式6.2.2函數(shù)名6.2.3函數(shù)返回值類型6.2.4函數(shù)的形式參數(shù)6.2.5函數(shù)體6.2.6函數(shù)的存儲類型146.2.1函數(shù)定義形式intmin(intx,inty)/*函數(shù)首部*/{/*函數(shù)體開始*/

intz;/*局部變量聲明*/

z=x<y?x:y;/*語句*/

returnz;/*語句*/}/*函數(shù)體結(jié)束*/函數(shù)名返回值類型形式參數(shù)聲明156.2.1函數(shù)定義形式函數(shù)定義一般形式存儲類型說明符返回值類型說明符函數(shù)名(形式參數(shù)聲明表){聲明序列語句序列}

可缺省:存儲類型說明符、返回值類型說明符、形式參數(shù)聲明表166.2.2函數(shù)名函數(shù)名是函數(shù)的標(biāo)識,按標(biāo)識符命名規(guī)則確定。自定義的函數(shù)名:不允許與同一源程序中其它自定義函數(shù)同名,允許與庫函數(shù)同名;intsqrt(intx){returnx+2;}intmain(){……}intf(intx){......}floatf(intx){……}intmain(){……}17允許與局部變量同名,允許與形式參數(shù)同名,不允許與同一源程序中全局變量同名。

intf;floatf(intx){……}intmain(){……}intf(intf){......}intmain(){……}intf(intx){floatf;……}intmain(){……}intf(intf){floatf;……}intmain(){……}6.2.2函數(shù)名186.2.3返回值類型定義無返回值函數(shù)時返回值類型說明符為void

例如:voidprint_value(intx){printf(“x=%d”,x);}

196.2.3返回值類型

定義有返回值函數(shù)時必須在返回值類型說明符位置給出返回值的數(shù)據(jù)類型。例如:intf(intx){return(x+2);}

C89標(biāo)準(zhǔn)允許省略返回值類型說明符,省略時編譯系統(tǒng)假定函數(shù)的返回值類型為int。206.2.4形式參數(shù)形式參數(shù)是一個函數(shù)與其他函數(shù)之間傳遞數(shù)據(jù)的接口

定義無參函數(shù)時形式參數(shù)聲明為void或空例如:voidprint_word(void)/*voidprint_word()*/{printf(“hello”);}216.2.4形式參數(shù)定義有參函數(shù)時形式參數(shù)的一般聲明形式存儲類型說明符數(shù)據(jù)類型說明符形式參數(shù)名存儲類型說明符:表示形式參數(shù)的存儲屬性,只能是auto與register,允許省略,省略時為auto。intf(intx,inty){……}intf(intx,y){……}intf(x,y)intx,y;{……}OLD226.2.4形式參數(shù)形式參數(shù)名:是形式參數(shù)的標(biāo)識,僅在該函數(shù)體內(nèi)使用,在其他函數(shù)中不可見。不允許在一個函數(shù)中定義同名的多個形式參數(shù),允許在不同函數(shù)中定義同名的形式參數(shù)。

intf(intx,intx){……}intmain(){……}intf(intx){floatx;……}intmain(){……}236.2.4形式參數(shù)數(shù)據(jù)類型說明符:指定形式參數(shù)的數(shù)據(jù)類型。形式參數(shù)允許:基本類型指針類型結(jié)構(gòu)類型聯(lián)合類型枚舉類型數(shù)組類型函數(shù)類型24*6.2.4形式參數(shù)編譯系統(tǒng)自動將“數(shù)據(jù)類型為T的一維數(shù)組類型”調(diào)整為“基類型為T的指針類型”例如:voidfun(intx[10])/*或voidfun(intx[])*/{…x++;…

}

形式參數(shù)聲明中的“intx[10]”或“intx[]”在編譯時被調(diào)整為“int*x”25*6.2.4形式參數(shù)編譯系統(tǒng)自動將“返回T類型值的函數(shù)類型”調(diào)整為“指向返回T類型值函數(shù)的指針類型”例如:doublefun(doublepf(doublex)){…printf(“%f",pf(1.5));…}形式參數(shù)聲明中的“doublepf(doublex)”在編譯時被調(diào)整為“double(*pf)(double)”266.2.5函數(shù)體函數(shù)體——{}

C89要求所有聲明必須出現(xiàn)在第一條語句之前,C99則允許分散的聲明和語句。例如:intmain(void){inta;a=1;intb;/*C89報錯,C99正確*/

for(inti=1;i<10;i++)

a*=i;}

276.2.6存儲類型函數(shù)首部中的存儲類型說明符定義了函數(shù)名作為一個外部標(biāo)識符在多文件程序中的連接屬性可使用的存儲類型說明符是extern和static。

缺省存儲類型說明符時系統(tǒng)默認(rèn)為extern。

286.3函數(shù)返回函數(shù)返回通過return語句實現(xiàn)return語句的三個用途結(jié)束函數(shù)的執(zhí)行并返回到主調(diào)函數(shù)向主調(diào)函數(shù)傳遞回一個函數(shù)類型的返回值;歸還函數(shù)中定義的局部對象的存儲空間

296.3函數(shù)返回return語句的兩種形式return;返回主調(diào)函數(shù)void型函數(shù)用“return;”完成返回操作;函數(shù)體結(jié)束的右花括號等同于一個“return;”語句。return(e);返回主調(diào)函數(shù)并將e值帶回主調(diào)函數(shù)非void類型函數(shù)用“return(e);”完成返回操作并將e值帶回主調(diào)函數(shù)。e:返回值表達(dá)式,圓括號可省略。數(shù)據(jù)類型允許是基本類型、指針類型、結(jié)構(gòu)類型、聯(lián)合類型、枚舉類型。306.3函數(shù)返回C89允許非void類型函數(shù)中使用“return;”返回,對于int型函數(shù)將返回給主調(diào)函數(shù)0值;對于其他類型函數(shù)將返回一個不確定的值。print_value(intx){printf(“x=%d”,x);}

C99規(guī)定非void類型函數(shù)必須使用“return(e);”返回。

316.3函數(shù)返回一個函數(shù)是否有返回值及返回值類型的決定因素是函數(shù)定義時的返回值類型說明符。函數(shù)每次調(diào)用后返回的值由“return(e);”語句決定。允許“return(e);”中e的類型與返回值類型說明符不同,但兩者應(yīng)賦值兼容。例如:intf(doublex){returnx*x;}最終f函數(shù)返回一個int類型值給主調(diào)函數(shù)。

326.3函數(shù)返回不能通過return語句返回多個值給主調(diào)函數(shù)例如:intf(intx,inty){return(x,y);}f函數(shù)被調(diào)用時總是返回y的值336.3函數(shù)返回當(dāng)函數(shù)的返回值類型為指針類型時,應(yīng)返回指針類型形式參數(shù)的值或static型局部變量的地址。例如:char*f(char*x,chary){charz=y; *x=y; return&z;}f函數(shù)返回z的地址或y的地址是不可靠的,返回x的值是可靠的。

static346.3函數(shù)返回main函數(shù)的特殊性函數(shù)名不能自定義;既允許帶形式參數(shù)也允許不帶形式參數(shù)。若有其形式參數(shù),其數(shù)量和類型不能隨意定義;函數(shù)首部:C89允許“intmain()”、”main()”或“voidmain()”;C99規(guī)定必須為“intmain()”。程序開始運行時main函數(shù)首先被操作系統(tǒng)調(diào)用;執(zhí)行到main函數(shù)中任一return語句或函數(shù)體結(jié)束右花括號時,結(jié)束程序運行。356.4函數(shù)調(diào)用6.4.1調(diào)用函數(shù)的引用性聲明6.4.2函數(shù)調(diào)用6.4.3函數(shù)調(diào)用時的參數(shù)傳遞6.4.4函數(shù)間數(shù)據(jù)通信的實現(xiàn)6.4.5遞歸函數(shù)366.4函數(shù)調(diào)用一個函數(shù)調(diào)用另一個函數(shù)意味著將程序執(zhí)行流程轉(zhuǎn)移到被調(diào)用函數(shù)。正確實現(xiàn)函數(shù)間相互調(diào)用必須滿足以下條件被調(diào)用函數(shù)存在且允許被調(diào)用;給出滿足被調(diào)函數(shù)運行時要求的參數(shù)值;在調(diào)用函數(shù)前對被調(diào)用函數(shù)做引用性聲明;按指定格式調(diào)用。

376.4.1函數(shù)的引用性聲明引用性函數(shù)聲明的目的擴大函數(shù)名的作用域為編譯系統(tǒng)提供被調(diào)函數(shù)的形式參數(shù)和返回值信息,使得編譯系統(tǒng)可以對隨后出現(xiàn)的所有對該函數(shù)調(diào)用的參數(shù)與返回值作一致性檢查并作適當(dāng)?shù)念愋娃D(zhuǎn)換。函數(shù)引用性聲明通常被稱為“函數(shù)原型”386.4.1函數(shù)的引用性聲明庫函數(shù)的引用性聲明(函數(shù)原型)分類保存在一組系統(tǒng)頭文件中。例如:某程序中調(diào)用了sqrt函數(shù),在sqrt調(diào)用之前出現(xiàn)“#include<math.h>”表示在#include處添加了sqrt函數(shù)的引用性聲明“doublesqrt(doublex);”。

396.4.1函數(shù)的引用性聲明自定義函數(shù)的引用性聲明(函數(shù)原型)例如:intmax(intx,inty){intz;if(x>y)z=x;elsez=y;returnz;}max函數(shù)的引用性聲明通常是:intmax(intx,inty);

406.4.1函數(shù)的引用性聲明函數(shù)引用性聲明一般形式存儲類型說明符返回值類型說明符函數(shù)名(形式參數(shù)類型表);形式參數(shù)類型表中形式參數(shù)允許有兩種形式:

數(shù)據(jù)類型

數(shù)據(jù)類型參數(shù)名例如,max函數(shù)的引用性聲明也允許如下:intmax(inta,intb);intmax(int,int);416.4.1函數(shù)的引用性聲明函數(shù)定義本身也是函數(shù)聲明。若將函數(shù)定義放在該函數(shù)所有調(diào)用之前則不需要該函數(shù)的引用性聲明。若將函數(shù)定義放在該函數(shù)調(diào)用之后并且在函數(shù)調(diào)用前沒有該函數(shù)的引用性聲明:

C89編譯系統(tǒng)在函數(shù)調(diào)用所在最內(nèi)層代碼塊中自動創(chuàng)建一個隱式函數(shù)聲明“externint函數(shù)名();”C99編譯系統(tǒng)顯示警告性錯誤。426.4.2函數(shù)調(diào)用直接函數(shù)調(diào)用用函數(shù)名、圓括號及實在參數(shù)表達(dá)式表調(diào)用函數(shù)的形式例1:庫函數(shù)pow的聲明為“doublepow(doublex,doubley);”“pow(2,3)”是pow函數(shù)的一種直接調(diào)用形式436.4.2函數(shù)調(diào)用例2:自定義函數(shù)print_word的定義為voidprint_word(void){printf(“hello”);}

intmain(void){print_word();······}446.4.2函數(shù)調(diào)用無參函數(shù)直接調(diào)用一般形式

函數(shù)名()有參函數(shù)直接調(diào)用的一般形式

函數(shù)名(實在參數(shù)表達(dá)式表)

當(dāng)實參表達(dá)式表中有多個表達(dá)式時,表達(dá)式之間用逗號分隔。

456.4.2函數(shù)調(diào)用非void型函數(shù)調(diào)用函數(shù)調(diào)用表達(dá)式語句函數(shù)調(diào)用作為其它表達(dá)式的運算分量例如:y=pow(2,3);和pow(2,3);均是正確語句void型函數(shù)調(diào)用函數(shù)調(diào)用不能作為運算分量出現(xiàn)其它表達(dá)式中例如:對于以下函數(shù)定義voidprint_value(intx){printf(“x=%d”,x);}

“print_value(2);”正確語句

“y=print_value(2);”錯誤語句

466.4.2函數(shù)調(diào)用若在函數(shù)調(diào)用前已有該函數(shù)的定義或聲明,編譯時系統(tǒng)會檢查函數(shù)調(diào)用中實參個數(shù)是否與被調(diào)函數(shù)形參個數(shù)相同,若發(fā)現(xiàn)不同則報錯。當(dāng)函數(shù)調(diào)用中某實參數(shù)據(jù)類型與對應(yīng)形參數(shù)據(jù)類型不同但二者賦值兼容時,編譯系統(tǒng)先自動將該實參數(shù)據(jù)類型轉(zhuǎn)換為形參數(shù)據(jù)類型,再將轉(zhuǎn)換類型后的實參再傳給對應(yīng)的形參。當(dāng)函數(shù)調(diào)用有多個實參時,由于C標(biāo)準(zhǔn)沒有規(guī)定實參求值順序,因此不同編譯系統(tǒng)采用的求值順序有所不同(有的自左向右,有的自右向左)。若實參中包含有副作用的表達(dá)式,則實參表達(dá)式的求值順序不同,求值結(jié)果也不同。

關(guān)于函數(shù)調(diào)用中實參的幾點說明476.4.2函數(shù)調(diào)用間接函數(shù)調(diào)用用指向函數(shù)的指針、圓括號及實在參數(shù)表調(diào)用函數(shù)的形式。函數(shù)名是一個指針類型的常量。若將一個函數(shù)的函數(shù)名保存到了一個指針變量中,則這個指針變量便指向該函數(shù)。聲明指向函數(shù)的指針變量一般形式

函數(shù)返回值類型(*指針變量名)(形式參數(shù)類型表);486.4.2函數(shù)調(diào)用用指向函數(shù)的指針間接調(diào)用有參函數(shù)一般形式指針(實參表)或

(*指針)(實參表)

用指向函數(shù)的指針間接調(diào)用無參函數(shù)一般形式指針()或(*指針)()496.4.2函數(shù)調(diào)用用指向函數(shù)的指針變量間接調(diào)用函數(shù)程序例1#include<stdio.h>#include<math.h>intmain(void){double(*pf)(double,double);/*聲明指針變量pf*/

pf=pow;/*使pf指向庫函數(shù)pow*/printf(“%f”,pf(2,3));/*用pf間接調(diào)用pow函數(shù)*//*或printf(“%f”,(*pf)(2,3));*/}

506.4.2函數(shù)調(diào)用用指向函數(shù)的指針變量間接調(diào)用函數(shù)。程序例2#include<stdio.h>#include<math.h>#include<conio.h>

doublectan(doublex){return1/tan(x);}intmain(void){double(*pf)(double),x;charcmd;printf(“\nIntputavalue:”);scanf(“%lf”,&x);printf(“\nIntputacommand:”);516.4.2函數(shù)調(diào)用printf(“\n1.sin(x)\n2.cos(x)\n3.tg(x)\n4.ctg(x)\nInputchoice:”);cmd=getch();switch(cmd){case‘1’:pf=sin;break;case‘2’:pf=cos;break;case‘3’:pf=tan;break;case‘4’:pf=ctan;}printf(“\n%f”,pf(x));return0;}

526.4.3函數(shù)調(diào)用時的參數(shù)傳遞調(diào)用一個有參函數(shù)的執(zhí)行過程(1)對實參表中所有實參表達(dá)式求值(2)為被調(diào)函數(shù)的所有形式參數(shù)分配存儲空間(3)檢查每個實參值的類型與對應(yīng)形參數(shù)據(jù)類型是否相同,若不同則將實參類型轉(zhuǎn)換為形參要求的類型(4)將實參值復(fù)制給形參(形參=實參,參數(shù)傳遞)(5)轉(zhuǎn)入被調(diào)函數(shù)執(zhí)行536.4.3函數(shù)調(diào)用時的參數(shù)傳遞函數(shù)調(diào)用時參數(shù)傳遞的類型(1)傳遞數(shù)值(值傳遞)形式參數(shù)的數(shù)據(jù)類型是基本類型,函數(shù)調(diào)用時傳遞給該形參的實參應(yīng)是與形參兼容的基本類型數(shù)據(jù)。若實參數(shù)據(jù)類型級別高于形參數(shù)據(jù)類型,對實參值做類型轉(zhuǎn)換時會產(chǎn)生轉(zhuǎn)換誤差,出現(xiàn)數(shù)據(jù)損失。546.4.3函數(shù)調(diào)用時的參數(shù)傳遞當(dāng)主調(diào)函數(shù)中用值傳遞方式傳遞實參值時,被調(diào)函數(shù)不能通過改變形參的值而改變對應(yīng)實參對象的值。例如:#include<stdio.h>voidswap(intx,inty){intt;t=x;x=y;y=t;/*交換x、y中數(shù)據(jù)*/}intmain(void){inta=1,b=2;swap(a,b);/*a、b中數(shù)據(jù)沒有被交換*/

printf(“a=%d,b=%d”,a,b);}

556.4.3函數(shù)調(diào)用時的參數(shù)傳遞(2)傳遞地址形式參數(shù)的數(shù)據(jù)類型是指針類型,函數(shù)調(diào)用時實參向該形參傳遞的應(yīng)是與其形參基類型相同的對象地址。用運算符&得到的對象地址或指向?qū)ο蟮闹羔樉捎米鲗崊ⅰ1徽{(diào)函數(shù)通過指針類型形參可以訪問主調(diào)函數(shù)中聲明的局部數(shù)據(jù)對象。566.4.3函數(shù)調(diào)用時的參數(shù)傳遞例如:#include<stdio.h>voidswap(int*x,int*y){intt;t=*x;*x=*y;*y;*y=t;/*交換x指向?qū)ο蠛蛓指向?qū)ο笾械臄?shù)據(jù)*/}intmain(void){inta=1,b=2;swap(&a,&b);/*a、b中數(shù)據(jù)被交換*/

printf(“a=%d,b=%d”,a,b);}576.4.3函數(shù)調(diào)用時的參數(shù)傳遞(3)傳遞函數(shù)地址形式參數(shù)的數(shù)據(jù)類型是指向返回T類型值函數(shù)的指針類型函數(shù)調(diào)用時實參向該形參傳遞的應(yīng)是返回值類型為T的函數(shù)地址函數(shù)名或指向函數(shù)的指針均可用作實參被調(diào)函數(shù)內(nèi)部通過該指針類型形參可以間接調(diào)用其他函數(shù)586.4.3函數(shù)調(diào)用時的參數(shù)傳遞例如:以下程序中通過調(diào)用函數(shù)root計算方程3x3+4x2-5x+6=0在[1,2]內(nèi)的一個近似根,root函數(shù)采用弦截法求方程的根,允許誤差為10-6。root函數(shù)4個形參含義是:a和b指出求根區(qū)間[a,b],eps是對所求方程根的誤差要求,pf是指向返回值類型為double的函數(shù)的指針變量。函數(shù)f計算方程f(x)=0中f(x)的值。596.4.3函數(shù)調(diào)用時的參數(shù)傳遞#include<stdio.h>#include<math.h>doubleroot(doublea,doubleb,doubleeps,double(*pf)(double)){doublec;while(1){c=(a*pf(b)-b*pf(a))/(pf(b)-pf(a));if(fabs(pf(c))<eps||fabs(b-a)<eps)returnc;if(pf(a)*pf(c)<0)b=c;elsea=c;}}606.4.3函數(shù)調(diào)用時的參數(shù)傳遞doublef(doublex){return6-x*(5-x*(4-3*x));}intmain(void){printf(“x=%f”,root(1,2,1e-6,f));}

616.4.4函數(shù)間數(shù)據(jù)通信的實現(xiàn)通過非指針型形式參數(shù)和return語句實現(xiàn)函數(shù)之間的通信例如:#include<stdio.h>intf(intx,inty){returnx+y;}intmain(void){inta=1,b=2,c;c=f(a,b);

printf(“%d”,c);}626.4.4函數(shù)間數(shù)據(jù)通信的實現(xiàn)通過非指針型形式參數(shù)、指針型形式參數(shù)及return語句實現(xiàn)函數(shù)之間的通信。例如:#include<stdio.h>intf(intx,inty,int*p){*p=x-y;returnx+y;}intmain(void){inta=1,b=2,c,d;c=f(a,b,&d);

printf(“a+b=%d,a-b=%d”,c,d);}636.4.4函數(shù)間數(shù)據(jù)通信的實現(xiàn)通過外部變量實現(xiàn)函數(shù)之間的通信例如:#include<stdio.h>intx,y,z,w;/*外部變量定義*/voidf(){z=x+y;w=x-y;}intmain(void){inta=1,b=2;x=a;y=b;f();printf(“a+b=%d,a-b=%d”,z,w);}

646.4.5遞歸函數(shù)656.4.5遞歸函數(shù)初步認(rèn)識遞歸函數(shù)n!的計算可定義為:

n=0是該問題的最小數(shù)據(jù)規(guī)模,1!的值是已知的;n>1時可將n!計算問題分解為n和(n-1)!兩部分,如果能求得(n-1)!的值,便可以得到n!的值。同樣地,可以將(n-1)!的計算問題分解為(n-1)和(n-2)!兩部分,其他依此類推。n!=1(n=0或n=1)n×(n-1)!(n>1)666.4.5遞歸函數(shù)計算n!函數(shù):longf(longn){if(n==1)/*基本問題判斷及計算結(jié)果*/return1;

elsereturnn*f(n-1);/*簡化問題,遞歸調(diào)用*/}

676.4.5遞歸函數(shù)(1)用遞歸函數(shù)解決復(fù)雜問題時,每次遞歸調(diào)用時要解決的問題都要比上次的調(diào)用簡單,數(shù)據(jù)規(guī)模越來越小,最終到達(dá)最小數(shù)據(jù)規(guī)模(基本問題)。解決完基本問題后,函數(shù)沿著調(diào)用順序逐級返回上次調(diào)用一個結(jié)果值,直到函數(shù)的原始調(diào)用處為止。(2)

遞歸函數(shù)一般由一個選擇結(jié)構(gòu)組成:條件為真的部分,計算基本問題終止遞歸調(diào)用;條件為假的部分,簡化問題繼續(xù)遞歸調(diào)用。(3)遞歸函數(shù)的每次調(diào)用系統(tǒng)都為函數(shù)的所有動態(tài)變量(形式參數(shù)和動態(tài)局部變量)分配本次調(diào)用使用的存儲空間,直到本次調(diào)用結(jié)束返回時方才釋放。

遞歸函數(shù)特點686.4.5遞歸函數(shù)遞歸函數(shù)執(zhí)行過程

696.4.5遞歸函數(shù)例1:用輾轉(zhuǎn)相除法求兩個整數(shù)的最大公約數(shù)。#include<stdio.h>intgcd(inta,intb){intr;if((r=a%b)==0)returnb;elsereturngcd(b,r);}intmain(void){printf(“%d”,gcd(25,30));}

遞歸法解題程序?qū)嵗?06.4.5遞歸函數(shù)例2:用二分法求方程-3x3+4x2-5x+6=0在[1,2]中的一個近似根,允許誤差10-6。

#include<stdio.h>#include<math.h>doublef(doublex){return6-x*(5-x*(4-3*x));}doubleroot(doublea,doubleb){doublec;if(fabs(f(a))<1e-6)returna;if(fabs(f(b))<1e-6)returnb;c=(b+a)/2;if(fabs(f(c))<1e-6)returnc;if((f(c))*f(a)<0)returnroot(a,c);elsereturnroot(c,b);}intmain(void){printf(“%f”,root(1,2));}

716.4.5遞歸函數(shù)有3個底座(分別標(biāo)記為A、B和C),A座上已從大到小依次疊放了64個大小不同的盤子,要求將A座上的盤子全部搬到C座上。在搬運過程中可以借助于B座,每次只能搬一個盤子,任何時候每個底座上的盤子都必須保持大盤在下小盤在上的疊放順序。簡化:A座上有3個盤子,將這3個盤子借助于B座搬到C座上

ABC例3:Hanoi塔問題726.4.5遞歸函數(shù)#include<stdio.h>voidHanoi(intn,charA,charB,charC){if(n==1)printf(“\nmove%dfrom%cto%c”,n,A,C);else{ Hanoi(n-1,A,C,B);printf(“\nmove%dfrom%cto%c”,n,A,C);

Hanoi(n-1,B,A,C);}}intmain(void){Hanoi(3,‘A’,‘B’,‘C’);}例3:Hanoi塔問題736.4.5遞歸函數(shù)⑴缺少對數(shù)據(jù)最小規(guī)模的正確判斷、處理及返回操作。函數(shù)一旦被調(diào)用將進入無窮遞歸。例如:longf(longn){returnn*fact(n-1);}初學(xué)者編寫遞歸函數(shù)時常犯錯誤746.4.5遞歸函數(shù)(2)函數(shù)遞歸調(diào)用時所用的數(shù)據(jù)規(guī)模不小于本次函數(shù)被調(diào)用時的數(shù)據(jù)規(guī)模。函數(shù)一旦被調(diào)用也將進入無窮遞歸。例如:longf(longn){if(n<=1)return1;elsereturnn*fact(n);}

初學(xué)者編寫遞歸函數(shù)時常犯錯誤756.4.5遞歸函數(shù)用遞歸法計算#include<stdio.h>#include<math.h>longf(intn){inti,s=1;for(i=1;i<=n;i++)s*=i;returns;}doublef1(doublex,intn){if(n==1)returnx;elsereturnf1(x,n-1)+pow(x,n)/f(n);}intmain(void){printf(“%lf\n”,f1(2,4));}

766.4.5遞歸函數(shù)用遞推法計算#include<stdio.h>doublef1(doublex,intn){doubles=0,t=1;intk;for(k=1;k<=n;k++){t*=x/k;s+=t;}returns;}intmain(void){

printf(“%lf\n”,f1(2,4));}

776.4.5遞歸函數(shù)遞推法使用循環(huán)結(jié)構(gòu)實現(xiàn)循環(huán)循環(huán)執(zhí)行函數(shù)中的一段代碼(循環(huán)語句)遞歸法使用選擇結(jié)構(gòu)實現(xiàn)循環(huán)循環(huán)執(zhí)行整個函數(shù)體代碼(循環(huán)調(diào)用)

比較遞推法和遞歸法786.5標(biāo)識符的作用域6.5.1標(biāo)識符的作用域*6.5.2外部對象的連接屬性796.5標(biāo)識符的作用域標(biāo)識符(identifier)代表程序中的各類對象標(biāo)識符的作用域與已定義或聲明的標(biāo)識符相關(guān)的一個代碼段。在這個代碼段內(nèi)使用該標(biāo)識符是合法的,在這個代碼段外使用該標(biāo)識符是非法的。806.5標(biāo)識符的作用域

標(biāo)識符的類型變量名:代表一個值可改變的數(shù)據(jù)量數(shù)組名:代表一組值可改變的數(shù)據(jù)量起始地址函數(shù)名:代表一個函數(shù)在內(nèi)存的存儲位置數(shù)據(jù)類型說明符:代表一個系統(tǒng)預(yù)定義、自定義或用typedef定義的數(shù)據(jù)類型宏名:代表一個常量或一組語句語句標(biāo)號:代表一條語句的位置

外部變量名既需要定義又需要聲明語句標(biāo)號既不需要定義也不需要聲明

816.5.1標(biāo)識符的作用域

各類標(biāo)識符的四類作用域(1)文件作用域從標(biāo)識符定義或聲明位置起到源文件結(jié)尾的源文件范圍文件作用域標(biāo)識符:外部對象名全局變量名全局?jǐn)?shù)組名函數(shù)名在函數(shù)外自定義的數(shù)據(jù)類型名一個文件作用域標(biāo)識符的作用域可通過引用性聲明被擴大826.5.1標(biāo)識符的作用域

836.5.1標(biāo)識符的作用域

外部變量定義性聲明與引用性聲明的差別

定義性聲明一個外部變量時可以帶有初始化值也可以不帶初始化值,引用性聲明一個外部變量時不能指定初始化值;定義性聲明一個外部變量時可以使用存儲類型extern、static或缺省,引用性聲明一個外部變量時使用存儲類型extern或缺省。846.5.1標(biāo)識符的作用域

(2)函數(shù)作用域一個函數(shù)定義覆蓋的區(qū)域函數(shù)作用域標(biāo)識符:語句標(biāo)號函數(shù)作用域總是嵌入在文件作用域內(nèi)。一個文件作用域內(nèi)可能包含多個函數(shù)作用域。856.5.1標(biāo)識符的作用域

(3)塊作用域函數(shù)體內(nèi)一個代碼塊(復(fù)合語句)覆蓋的范圍塊作用域標(biāo)識符:函數(shù)定義中出現(xiàn)的形式參數(shù)名,局部變量名形式參數(shù)名作用域:聲明所在函數(shù)體代碼塊內(nèi)局部變量名作用域:聲明所在代碼塊內(nèi)塊作用域總是嵌入在函數(shù)作用域內(nèi)。一個塊作用域內(nèi)還可以包含多個塊作用域。6.5.1標(biāo)識符的作用域876.5.1標(biāo)識符的作用域

(4)函數(shù)原型作用域函數(shù)原型(引用性函數(shù)聲明)覆蓋的范圍。函數(shù)原型作用域標(biāo)識符:函數(shù)原型中出現(xiàn)的形式參數(shù)名例如:“intmight(intsmall,doublelarge);”中的small和large的作用域僅到該行的分號。886.5.1標(biāo)識符的作用域⑴

不允許在同一作用域內(nèi)定義或聲明代表不同對象的兩個或多個同名標(biāo)識符。例如:#include<stdio.h>intf=0;intf(intx)/*編譯報錯:重復(fù)聲明f*/{intx;}/*編譯報錯:重復(fù)聲明x*/intmain(void){intx=f(1);}

標(biāo)識符的作用域規(guī)則896.5.1標(biāo)識符的作用域

允許在不同的作用域內(nèi)定義或聲明代表不同對象的兩個或多個同名的標(biāo)識符。例如:#include<stdio.h>intx=0;intf(){intx,y;}intmain(void){inty;}

標(biāo)識符的作用域規(guī)則906.5.1標(biāo)識符的作用域

(3)當(dāng)一個作用域內(nèi)包含了另一個作用域,允許內(nèi)層作用域和外層作用域中分別聲明代表不同對象的兩個同名標(biāo)識符。內(nèi)層作用域中訪問的同名標(biāo)識符是內(nèi)層作用域中定義的標(biāo)識符,此時外層作用域中定義的同名標(biāo)識符在內(nèi)層作用域中被自動隱蔽而不可訪問。標(biāo)識符的作用域規(guī)則6.5.1標(biāo)識符的作用域#include<stdio.h>intx=0;voidf();intmain(void){intx,loop=0;

loop:for(x=1;x<5;x++){intx=2;

printf(“%d”,x);}printf(“%d”,x);f();loop++;if(loop<1)gotoloop;}voidf(){printf(“%d”,x++);}

92*6.5.2外部對象的連接屬性在一個多文件程序中,外部對象名(函數(shù)名,外部變量名)具有其他標(biāo)識符不具備的兩個特殊屬性:

⑴在使用之前既需要定義也需要引用性聲明一個外部對象名只允許在一個源程序中定義一次,但允許在定義所在的源文件或其他源文件中被多次地引用性聲明。

93*6.5.2外部對象的連接屬性⑵在多文件程序中定義的一個外部對象名具有連接屬性內(nèi)部連接:僅允許在對象定義所在源文件內(nèi)使用該對象標(biāo)識符外部連接:允許在組成一個源程序的所有源文件內(nèi)使用該對象名定義外部對象連接屬性時使用存儲類型說明符extern(外部連接)和static(內(nèi)部連接)缺省存儲類型說明符時系統(tǒng)默認(rèn)為extern。94*6.5.2外部對象的連接屬性在一個多文件程序中將一個已定義的具有外部連接屬性的標(biāo)識符作用域從定義所在的源文件擴展到其他源文件的方法是:在其他源文件中引用性聲明該標(biāo)識符。函數(shù)引用性聲明一般形式extern返回值類型說明符函數(shù)名(形式參數(shù)類型表);

全局變量引用性聲明一般形式

extern數(shù)據(jù)類型說明符全局變量名;

95*6.5.2外部對象的連接屬性多文件程序舉例源文件F1.c的內(nèi)容#include<stdio.h>externvoidfunc2(void);/*聲明函數(shù)func2*/voidfunc1();/*聲明函數(shù)func1*/intx=1;/*定義外部全局變量x*/intmain(void){func1();}voidfunc1()/*定義外部函數(shù)func1*/{x++;printf(“\n%d”,x);func2();}voidfunc3()/*定義外部函數(shù)func3*/{x++;printf(“\n%d”,x);}96*6.5.2外部對象的連接屬性源文件F2.c的內(nèi)容:#include<stdio.h>externvoidfunc3();/*聲明函數(shù)func3*/externintx;/*聲明變量x*/voidfunc4(void);/*聲明函數(shù)func4*/staticinty=1;/*定義內(nèi)部全局變量y*/voidfunc2()/*定義外部函數(shù)func2*/{x++;y++;printf(“\n%d,%d”,x,y);func3();func4();}staticvoidfunc4()/*定義內(nèi)部函數(shù)func4*/{x++;y++;printf(“\n%d,%d”,x,y);}97*6.5.2外部對象的連接屬性宏名的特殊性(1)關(guān)鍵字可以用作宏名(2)從#define命令所在行開始到源文件結(jié)尾的代碼段為該#define命令所定義宏名的作用域例如:#definePI3.14PI:宏名,3.14:宏體一個宏名作用域內(nèi)出現(xiàn)的所有宏名引用在預(yù)處理時均被替換為宏體。宏名不應(yīng)與其作用域內(nèi)函數(shù)定義及函數(shù)調(diào)用中出現(xiàn)的函數(shù)同名,也不應(yīng)與變量同名。否則編譯時會出現(xiàn)語法錯誤。98*6.5.2外部對象的連接屬性例如:#definea3#definef4intmain(void){inta=1;/*該行將被替換成“int3=1;”,語法錯*/intx;x=f(2);/*該行被替換成“x=4(2);”,語法錯*/}intf(intx)/*該行被替換成”int4(intx)”,語法錯*/{returnx*x;}

996.6變量的存儲屬性6.6.1變量的生命期屬性6.6.2變量的存儲器屬性1006.6.1變量的生命期屬性生命期屬性反映程序運行時變量的存在狀態(tài)按照生命期屬性分類變量靜態(tài)變量:存在周期與程序運行時間相同動態(tài)變量:存在周期與定義它的代碼塊執(zhí)行時間相同1016.6.1變量的生命期屬性全局變量都是靜態(tài)變量形式參數(shù)都是動態(tài)變量局部變量有靜態(tài)變量、動態(tài)變量之分,由存儲類型說明符決定。用static聲明的局部變量是靜態(tài)變量;用auto或register聲明的局部變量是動態(tài)變量;省略存儲類型說明符時系統(tǒng)默認(rèn)為auto。靜態(tài)局部變量的存在周期與全局變量相同,作用域與局部變量相同。1026.6.1變量的生命期屬性例1

動態(tài)局部變量存儲特性#include<stdio.h>voidf(intx){inty=0,i;printf(“x=%dy=%d”,++x,++y);for(i=0;i<2;i++){intz=0;printf(“z=%d”,++z);}}intmain(void){f(1);putchar(‘\n’);f(1);}程序運行結(jié)果:x=2y=1z=1z=1x=2y=1z=1z=11036.6.1變量的生命期屬性例2計算

#include<stdio.h>longf(intn){staticlongs;if(n<=1)s=1;elses*=n;returns;}intmain(void){inti;doublek=0;for(i=1;i<=10;i++)k+=1.0/f(i);printf(“%lf”,k);}1046.6.2變量的存儲器屬性存儲器屬性反映程序運行期間變量獲得的存儲單元所在的存儲器按照存儲器屬性分類變量內(nèi)存變量寄存器變量1056.6.2變量的存儲器屬性靜態(tài)變量(全局變量,靜態(tài)局部變量)都是內(nèi)存變量動態(tài)變量(形式參數(shù),動態(tài)局部變量)有內(nèi)存變量和寄存器變量之分,由存儲類型說明符決定。用auto聲明的局部變量是內(nèi)存變量;用register聲明的局部變量是寄存器變量;省略存儲類型說明符時系統(tǒng)默認(rèn)為auto。寄存器變量的特殊性(1)寄存器變量讀寫速度比內(nèi)存變量快(2)取地址運算符“&”不能用于寄存器變量1066.8編譯預(yù)處理及預(yù)處理命令6.8.1預(yù)處理概念6.8.2文件包含命令6.8.3宏定義命令6.8.4條件編譯命令1076.8.1預(yù)處理概念在C程序的開發(fā)過程中,編譯源程序時編譯程序?qū)υ闯绦蛭募鲀蓚€階段的編譯預(yù)處理。第1階段:預(yù)處理程序預(yù)處理階段預(yù)處理程序掃描源程序,對其中的“預(yù)處理命令”做相應(yīng)處理。預(yù)處理命令:⑴文件包含命令⑵宏定義命令⑶條件編譯命令1086.8.1預(yù)處理概念第2階段:編譯程序預(yù)處理階段(1)掃描源程序中的注釋,檢查是否符合書寫規(guī)則,若正確則將注釋替換為空格;例如:將以下代碼行:intsum;/*sum存放兩個數(shù)的和*/替換為:intsum;

1096.8.1預(yù)處理概念(2)查找源代碼中由續(xù)行符(反斜線后緊跟換行符)組成的物理行,把它們合并成一個邏輯行;。例如:將以下2行代碼:printf(“That’swond\erful!”);合并為1行代碼:printf(“That’swonderful!”);1106.8.1預(yù)處理概念(3)將源程序中用空白字符(空格,回車,TAB)作分隔符的多個字符串直接量連接為一個字符串直接量。例如:將以下代碼行:printf(“Astringisasequenceofcharacters”“surroundedby”“doublequotes.”);連接為:printf(“Astringisasequenceofcharacterssurroundedbydoublequotes.”);

1116.8.2文件包含命令命令功能預(yù)處理程序用filename文件中全部內(nèi)容替代源程序中的預(yù)處理命令行#include“filename”使其成為源程序的一部分。命令格式#include“filename”或#include<filename>

命令位置允許出現(xiàn)在源程序中任何位置但必須是一行起始1126.8.2文件包含命令命令應(yīng)用常用#include命令將系統(tǒng)頭文件內(nèi)容插入到源程序中。例如:#include<stdio.h>系統(tǒng)頭文件名主要內(nèi)容

溫馨提示

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

評論

0/150

提交評論