函數(shù)與宏定義ppt課件_第1頁
函數(shù)與宏定義ppt課件_第2頁
函數(shù)與宏定義ppt課件_第3頁
函數(shù)與宏定義ppt課件_第4頁
函數(shù)與宏定義ppt課件_第5頁
已閱讀5頁,還剩124頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、2021/1/28,第1頁,第六章 函數(shù)與宏定義,6.1 函數(shù)概念,6.2 變量作用域和存儲(chǔ)類型,6.3 內(nèi)部函數(shù)與外部函數(shù),6.4 遞歸函數(shù)設(shè)計(jì)和調(diào)用,6.6 綜合范例,2021/1/28,第2頁,例1-3 #include int add(int x,int y); main( ) int a,b,c; printf(“please input value of a and b:n”); scanf(“%d%d”,2021/1/28,第3頁,6.1 函數(shù)概念,C語言允許把問題設(shè)計(jì)成一個(gè)一個(gè)的模塊,程序通過調(diào)用模塊功能來解決問題。這些模塊通常都是通過函數(shù)來實(shí)現(xiàn)的,又可稱其為函數(shù)模塊,C語言中

2、,函數(shù)可分為兩類,函數(shù)是指完成一個(gè)特定工作的獨(dú)立程序模塊。 庫函數(shù):由C語言系統(tǒng)提供定義 如scanf()、printf()等函數(shù) 自定義函數(shù):需要用戶自己定義,2021/1/28,第4頁,函數(shù)的組織,使用結(jié)構(gòu)化程序設(shè)計(jì)方法解決復(fù)雜的問題 把大問題分解成若干小問題,小問題再進(jìn)一步分解成若干更小的問題 寫程序時(shí),用main()解決整個(gè)問題,它調(diào)用解決小問題的函數(shù) 這些函數(shù)又進(jìn)一步調(diào)用解決更小問題的函數(shù),從而形成函數(shù)的嵌套調(diào)用,2021/1/28,第5頁,程序結(jié)構(gòu),2021/1/28,第6頁,main()也是一個(gè)函數(shù),C程序由一個(gè)main()或多個(gè)函數(shù)構(gòu)成。 程序中一旦調(diào)用了某個(gè)函數(shù),該函數(shù)就會(huì)完

3、成一些特定的工作,然后返回到調(diào)用它的地方。 1、函數(shù)經(jīng)過運(yùn)算,得到一個(gè)明確的運(yùn)算結(jié)果,并需要回送該結(jié)果。例如,函數(shù)add()返回兩個(gè)數(shù)的和。 2、函數(shù)完成一系列操作步驟,不需要回送任何運(yùn)算結(jié)果,2021/1/28,第7頁,程序解析計(jì)算圓柱體積,例6-1 輸入圓柱體的高和半徑,求圓柱體積,volume=*r2*h。 要求定義和調(diào)用函數(shù)cylinder (r, h )計(jì)算圓柱體的體積,2021/1/28,第8頁,例6-1源程序,* 計(jì)算圓柱體積 */ #include int main( void ) double height, radius, volume; double cylinder (

4、double r, double h); /* 函數(shù)聲明*/ printf (Enter radius and height: ); scanf (%lf%lf,2021/1/28,第9頁,例6-1源程序,* 定義求圓柱體積的函數(shù) */ double cylinder (double r, double h) double result; result =3.1415926 * r * r * h; /* 計(jì)算體積 */ return result; /* 返回結(jié)果 */,Enter radius and height: 3.0 10 Volume = 282.743,2021/1/28,第1

5、0頁,6.1.1 函數(shù)定義,函數(shù)定義的一般形式可以有兩種,形式一,存儲(chǔ)類型符 返回值類型符 函數(shù)名(形參說明表) 函數(shù)語句體,形式二,存儲(chǔ)類型符 返回值類型型符 函數(shù)名(形參表) 形參說明; 函數(shù)語句體,2021/1/28,第11頁,函數(shù)定義1: int abs_sum(int m, int n) if (m0) m=-m; if(n0) n=-n; return(m+n);,函數(shù)定義2: int abs_sum(m, n) int m,n if (m0) m=-m; if(n0) n=-n; return(m+n);,2021/1/28,第12頁,1返回運(yùn)算結(jié)果的函數(shù)定義,函數(shù)類型 函數(shù)名(

6、形參表)/* 函數(shù)首部 */ /* 函數(shù)體 */ 函數(shù)實(shí)現(xiàn)過程 return 表達(dá)式;,把函數(shù)運(yùn)算的結(jié)果回送給主函數(shù),只能返回一個(gè)值,函數(shù)返回值的類型,沒有分號(hào),double cylinder (double r, double h) double result; result = 3.1415926 * r * r * h; return result;,2021/1/28,第13頁,形參,類型1 參數(shù)1 ,類型2 參數(shù)2 ,類型n 參數(shù)n 參數(shù)之間用逗號(hào)分隔,每個(gè)參數(shù)前面的類型都必須分別寫明,函數(shù)類型 函數(shù)名(形參表) 函數(shù)實(shí)現(xiàn)過程 return 表達(dá)式;,不能寫成 double r, h

7、,double cylinder (double r, double h) double result; result =3.1415926 * r * r * h; return result;,2021/1/28,第14頁,double cylinder (double r, double h) /* 函數(shù)首部 */ /* 函數(shù)體,寫在一對(duì)園括號(hào)內(nèi) */ double result; result =3.1415926 * r * r * h; /* 計(jì)算圓柱體積 */ return result; /* 返回運(yùn)算結(jié)果*/,分析函數(shù)的定義,函數(shù)類型,函數(shù)名,形參表,與函數(shù)類型一致,2021

8、/1/28,第15頁,2不返回運(yùn)算結(jié)果的函數(shù)定義,void 函數(shù)名(參數(shù)表) /* 函數(shù)首部 */ /* 函數(shù)體 */ 函數(shù)實(shí)現(xiàn)過程 return; /* 可以省略return */,這類函數(shù)通常用于屏幕輸出等,表示不返回結(jié)果,不能省略 否則 函數(shù)類型被默認(rèn)定義為int,2021/1/28,第16頁,例6-2 輸出5之內(nèi)的數(shù)字金字塔,* 輸出數(shù)字金字塔 */ #include int main (void) void pyramid (int n); /* 函數(shù)聲明 */ pyramid(5); /* 調(diào)用函數(shù),輸出數(shù)字金字塔 */ return 0;,1 2 2 3 3 3 4 4 4 4

9、5 5 5 5 5,2021/1/28,第17頁,void pyramid (int n) /* 函數(shù)定義 */ int i, j; for (i = 1; i = n; i+) /* 需要輸出的行數(shù) */ for (j = 1; j = n-i; j+) /* 輸出每行左邊的空格 */ printf( ); for (j = 1; j = i; j+) /* 輸出每行的數(shù)字 */ printf( %d , i); /* 每個(gè)數(shù)字的前后各有一個(gè)空格 */ putchar (n);,2021/1/28,第18頁,6.1.2 函數(shù)的調(diào)用,定義一個(gè)函數(shù)后,就可以在程序中調(diào)用這個(gè)函數(shù)。 調(diào)用標(biāo)準(zhǔn)庫函數(shù)

10、時(shí),在程序的最前面用#include命令包含相應(yīng)的頭文件。 調(diào)用自定義函數(shù)時(shí),程序中必須有與調(diào)用函數(shù)相對(duì)應(yīng)的函數(shù)定義,2021/1/28,第19頁,1函數(shù)調(diào)用的形式和過程,使用返回值: volume = cylinder (radius, height ); printf(“%f n” , cylinder (radius, height ); 完成操作: pyramid(5,常用于void類型函數(shù)的調(diào)用,常用于返回結(jié)果的函數(shù)的調(diào)用,常量、變量、表達(dá)式,函數(shù)名(實(shí)參表,2021/1/28,第20頁,函數(shù)調(diào)用的過程,計(jì)算機(jī)在執(zhí)行程序時(shí),從主函數(shù)main開始執(zhí)行,如果遇到某個(gè)函數(shù)調(diào)用,主函數(shù)被暫停

11、執(zhí)行,轉(zhuǎn)而執(zhí)行相應(yīng)的函數(shù),該函數(shù)執(zhí)行完后,將返回主函數(shù),然后再從原先暫停的位置繼續(xù)執(zhí)行。 函數(shù)遇return或最后的大括號(hào),返回主函數(shù),2021/1/28,第21頁,分析函數(shù)調(diào)用的過程,include int main( void ) double height, radius, volume; double cylinder (double r, double h); printf (Enter radius and height: ); scanf (%lf%lf,調(diào)用函數(shù),實(shí)參形參,執(zhí)行函數(shù)中的語句,返回調(diào)用它的地方,2021/1/28,第22頁,2參數(shù)傳遞,函數(shù)定義時(shí)的參數(shù)被稱為形式參

12、數(shù)(簡(jiǎn)稱形參) double cylinder (double r, double h); 函數(shù)調(diào)用時(shí)的參數(shù)被稱為實(shí)際參數(shù)(簡(jiǎn)稱實(shí)參) volume = cylinder (radius, height); 實(shí)參形參 在參數(shù)傳遞過程中,實(shí)參把值復(fù)制給形參。 形參和實(shí)參一一對(duì)應(yīng):數(shù)量一致,類型一致,順序一致 形參:變量,用于接受實(shí)參傳遞過來的值 實(shí)參:常量、變量或表達(dá)式,單向傳遞,2021/1/28,第23頁,3函數(shù)結(jié)果返回,函數(shù)返回的兩種情況 完成確定的運(yùn)算,有一個(gè)運(yùn)算結(jié)果返回給主調(diào)函數(shù)。 完成指定工作,沒有確定的運(yùn)算結(jié)果需返回給主調(diào)函數(shù)(函數(shù)類型void)。 函數(shù)結(jié)果返回的形式: retur

13、n 表達(dá)式; return (表達(dá)式,2021/1/28,第24頁,例6-3】定義判斷奇偶數(shù)的函數(shù)even (n,定義一個(gè)判斷奇偶數(shù)的函數(shù)even (n),當(dāng)n為偶數(shù)時(shí)返回1,否則返回0。 /* 判斷奇偶數(shù)的函數(shù) */ int even (int n)/* 函數(shù)首部 */ if(n%2 = 0) /* 判別奇偶數(shù) */ return 1;/* 偶數(shù)返回1 */ else return 0;/* 奇數(shù)返回0 */,如何調(diào)用該函數(shù),2021/1/28,第25頁,4函數(shù)原型聲明,函數(shù)類型 函數(shù)名(參數(shù)表); double cylinder (double r, double h); void pyr

14、amid (int n); 函數(shù)必須先定義后調(diào)用,將主調(diào)函數(shù)放在被調(diào)函數(shù)的后面,就像變量先定義后使用一樣。 如果自定義函數(shù)在主調(diào)函數(shù)的后面,就需要在函數(shù)調(diào)用前,加上函數(shù)原型聲明。 函數(shù)聲明:說明函數(shù)的類型和參數(shù)的情況,以保證程序編譯時(shí)能判斷對(duì)該函數(shù)的調(diào)用是否正確,只寫函數(shù)定義中的第1行(函數(shù)首部),并以分號(hào)結(jié)束,2021/1/28,第26頁,例1-3 #include int add(int x,int y); main( ) int a,b,c; printf(“please input value of a and b:n”); scanf(“%d%d”,函數(shù)聲明,函數(shù)調(diào)用,函數(shù)定義,20

15、21/1/28,第27頁,* / * 程 序:6_4.c(驗(yàn)證素?cái)?shù)程序) * / * 主要功能:可驗(yàn)證某數(shù)是否為素?cái)?shù) * / * #include / 預(yù)編譯命令 #include / 預(yù)編譯命令 int checkprime( int b); / 子函數(shù)聲明 int main()/ 主函數(shù) int a=0;/ 定義整型變量,初始化為0 printf(請(qǐng)輸入一個(gè)整數(shù):a=“);/ 提示信息 scanf(“%d” / 主函數(shù)結(jié)束,2021/1/28,第28頁,include / 預(yù)編譯命令 #include / 預(yù)編譯命令 int checkprime( int b );/ 子函數(shù)聲明 int

16、main()/ 主函數(shù) int a=0;/ 定義整型變量,初始化為0 printf(請(qǐng)輸入一個(gè)整數(shù):a=“);/ 提示信息 scanf(“%d” / 鍵盤輸入一個(gè)整數(shù),2021/1/28,第29頁,用實(shí)參 a 調(diào)用子函數(shù),該子函數(shù)的 / 返回值作為 if 語句的分支條件 if ( checkprime( a ) ) / checkprime( a ) 為 1 printf( 是素?cái)?shù)“); else / checkprime( a ) 為 0 printf( “不是素?cái)?shù)“); / 主函數(shù)結(jié)束,2021/1/28,第30頁,int checkprime(int b)/ 子函數(shù),b為形式參數(shù) int

17、 k=0; / 定義整型變量,并初始化 for (k=2; k=sqrt(double)b); k+)/ 循環(huán) if (b%k = 0)/ 如果b能夠被k整除,則返回0 / 可理解為“搶先”返回0,有了 return 0, / 后面的 return 1 不起作用了 return 0; return 1;/ b不能被k整除,則返回1,2021/1/28,第31頁,int checkprime(int b) int k=0; for (k=2; k=sqrt(double)b); k+) if (b%k = 0) return 0; return 1,2021/1/28,第32頁,int chec

18、kprime( int b ) /* 子函數(shù)*/ int k=0; 形式參數(shù) for ( k=2; k=sqrt( (double) b ); k=K+1 ) if ( b % k = 0 ) return 0; return 1; /* b不能被k整除,則返回1*/ /*說明 b 是質(zhì)數(shù)*,2021/1/28,第33頁,基本概念: 如何定義一個(gè)函數(shù) 主函數(shù)怎樣調(diào)用子函數(shù) 實(shí)在參數(shù)和形式參數(shù) 返回值是什么意思,2021/1/28,第34頁,主函數(shù)與子函數(shù)的配合: 主函數(shù)通過實(shí)參去調(diào)用子函數(shù)將實(shí)參賦給子函數(shù)中的形參; 子函數(shù)運(yùn)算之后,又將調(diào)用結(jié)果返回給主函數(shù)一個(gè)值,這個(gè)值作為主函數(shù)判斷該實(shí)參是素

19、數(shù)與否的根據(jù)。 兩者配合得天衣無縫,2021/1/28,第35頁,在checkprime( int b ) 函數(shù)中,有return 0 和 return 1 兩處不同。如果先有return 0了,后面一條return 1 就不起作用了。不會(huì)既執(zhí)行 return 0 又執(zhí)行 return 1,2021/1/28,第36頁,函數(shù)的聲明 放在主函數(shù)之前,告訴系統(tǒng)有 自定義的子函數(shù)可以被調(diào)用。 例: int checkprime( int b,2021/1/28,第37頁,函數(shù)的定義 返回值的類型 函數(shù)名(類型名 形式參數(shù)1,類型名 形式參數(shù)2,. . . ) /* 函數(shù)體*/ 說明部分 語句部分,2

20、021/1/28,第38頁,形式參數(shù)和實(shí)在參數(shù) int checkprime( int b ); /*定義 b 是形式參數(shù), 特點(diǎn): 1.未被調(diào)用不占內(nèi)存單元; 2.被調(diào)用后系統(tǒng)為其分配內(nèi)存單元; 3.調(diào)用結(jié)束釋放內(nèi)存單元; 4.作用域限定在子函數(shù)內(nèi),屬于局部變量,2021/1/28,第39頁,被調(diào)用函數(shù)嵌套在 if 語句中,a 是實(shí)在參數(shù) if ( checkPrime( a ) )主函數(shù) 調(diào)用 checkPrime( b ) 子函數(shù) 形式參數(shù),2021/1/28,第40頁,實(shí)在參數(shù)是一個(gè)具有確定值的表達(dá)式 一個(gè)函數(shù)在調(diào)用子函數(shù)時(shí),要將實(shí)在參數(shù)賦給形式參數(shù) 調(diào)用時(shí) 17 17 實(shí)在參數(shù) a

21、形式參數(shù) b,2021/1/28,第41頁,調(diào)用 輸入a 子函數(shù) if (checkPrime(a) checkPrime(b) 執(zhí)行 if 語句 for: i=2,3 =1 =0 b%i=0 !=0 輸出 輸出 return 0 return 1 a是質(zhì)數(shù) a不是質(zhì)數(shù) 返回,2021/1/28,第42頁,int main() int a=0;printf( 請(qǐng)輸入一個(gè)整數(shù):); a=; scanf(“%d”,2021/1/28,第43頁,6.1.3 函數(shù)的傳值方式,函數(shù)的傳值方式: 采用實(shí)參表將每一個(gè)實(shí)參的值相應(yīng)地傳遞給每一個(gè)形參變量,形參變量在接收到實(shí)參表傳過來的值時(shí),會(huì)在內(nèi)存臨時(shí)開辟新的

22、空間,以保留形參變量的值,當(dāng)函數(shù)執(zhí)行完畢時(shí),這些臨時(shí)開辟的內(nèi)存空間會(huì)被釋放,并且形參的值在函數(shù)中不論是否發(fā)生變化,都不會(huì)影響到實(shí)參變量的值的變化,這就是函數(shù)的傳值方式,自定義函數(shù)在程序中的使用順序有兩種形式,先進(jìn)行函數(shù)聲明,再進(jìn)行函數(shù)調(diào)用,函數(shù)定義放在函數(shù)調(diào)用之后。函數(shù)聲明在函數(shù)調(diào)用之前。 函數(shù)定義放在函數(shù)調(diào)用之前,2021/1/28,第44頁,例6-1】 編程序,通過調(diào)用函數(shù)abs-sum(),求任意兩個(gè)整數(shù)的絕對(duì)值的和,include int abs_sum(int m,int n); main() int x,y,z; scanf(%d%d,2021/1/28,第45頁,int abs_

23、sum(int m,int n) if(m0) m=-m; if(n0) n=-n; return m+n;,程序運(yùn)行結(jié)果: 7 12 sum is 19,2021/1/28,第46頁,用傳值方式調(diào)用函數(shù)時(shí),實(shí)參也可以是函數(shù)調(diào)用語句,例6-2】求任意三個(gè)數(shù)的絕對(duì)值的和,include int abs_sum(int m,int n); main() int x,y,z,sum; scanf(%d%d%d,2021/1/28,第47頁,int abs_sum(int m,int n) if(m0) m=-m; if(n0) n=-n; return m+n;,程序運(yùn)行結(jié)果: 7 12 5 sum

24、 is 24,2021/1/28,第48頁,注意,對(duì)于有返回值的函數(shù),調(diào)用時(shí)若沒有把它賦給某個(gè)變量,仍然是可以的,只是函數(shù)的返回值有可能會(huì)被丟失,例6-5】 求任意兩數(shù)的乘積,自定義一個(gè)函數(shù)mul(),用于求兩數(shù)的乘積,程序: #include float mul(float a,float b); main() float x,y,z; scanf(%f %f, /* *,2021/1/28,第49頁,x=x*2; y=y*2; printf(z=%f,mul(%f,%f)=%fn,z,x,y,mul(x,y); /* */ float mul(float a,float b) return

25、 a*b;,程序運(yùn)行結(jié)果: 5 6 z=30.000000,mul(30.000000,-8.000000)=-240.000000,2021/1/28,第50頁,6.2 變量作用域和存儲(chǔ)類型,一變量的作用域,變量的作用域:指的是變量的有效范圍,針對(duì)變量不同的作用域,可把變量分為局部變量和全局變量,局部變量:在函數(shù)內(nèi)部或某個(gè)控制塊的內(nèi)部定義的變量為局部變量,局部變量的有效范圍只限于本函數(shù)內(nèi)部,退出函數(shù),該變量自動(dòng)失效,全局變量:在函數(shù)外面定義的變量稱為全局變量,全局變量的作用域是從該變量定義的位置開始,直到源文件結(jié)束。在同一文件中的所有函數(shù)都可以引用全局變量,2021/1/28,第51頁,局部

26、變量,主函數(shù)main中定義的變量,也只能在主函數(shù)內(nèi)使用和有效。 不同函數(shù)中可以使用相同名字的變量,且互不干擾。 形式參數(shù)也是局部變量,也只能在所在函數(shù)內(nèi)使用和有效。 可以在一個(gè)函數(shù)內(nèi)的復(fù)合語句中定義變量,且這些變量只在本復(fù)合語句中有效。 這種復(fù)合語句也稱為“分程序”或“子模塊,2021/1/28,第52頁,全局變量,全局變量增加了函數(shù)間數(shù)據(jù)聯(lián)系的渠道。由于同一文件中的所有函數(shù)都能引用全局變量的值,當(dāng)需要從一個(gè)函數(shù)中帶回多個(gè)值時(shí),就能克服函數(shù)調(diào)用只能返回一個(gè)值的局限性。 如無必要,不要使用全局變量。因?yàn)槿肿兞考冉档统绦虻那逦院秃瘮?shù)的通用性,且又在程序的全部執(zhí)行過程中都占用存儲(chǔ)空間。 在文件開

27、頭定義的外部變量才可在整個(gè)文件范圍內(nèi)使用,若在定義點(diǎn)之前的函數(shù)需引用外部變量,則可用關(guān)鍵字“extern”作“外部變量說明,2021/1/28,第53頁,局部變量和全局變量的作用域如圖所示,2021/1/28,第54頁,例6-5】 變量作用域應(yīng)用舉例,閱讀下面的程序,注意區(qū)分局部變量和全局變量的作用域,*exam6_4.c 變量作用域舉例*/ #include void a( void );/函數(shù)聲明 void b( void ); void c( void ); int x = 1; main() int x = 5; printf(local x in outer scope of mai

28、n is %dn, x,2021/1/28,第55頁,int x = 7; printf( local x in inner scope of main is %dn, x ); printf( local x in outer scope of main is %dn, x ); a();/函數(shù)調(diào)用 b(); c(); a(); b(); c(,前三次輸出結(jié)果: local x in outer scope of main is 5 local x in inner scope of main is 7 local x in outer scope of main is 5,2021/1/2

29、8,第56頁,printf( local x in main is %dn, x ); getchar(); return 0; /*MAIN函數(shù)結(jié)束 void a( void )/函數(shù)定義 int x = 25; printf( nlocal x in a is %d after entering an, x ); +x; printf( local x in a is %d before exiting an, x );,2021/1/28,第57頁,void b( void ) static int x = 50; printf( nlocal static x is %d on ent

30、ering bn, x ); +x; printf( local static x is %d on exiting bn, x ); void c( void ) printf( nglobal x is %d on entering cn, x ); x *= 10; printf( global x is %d on exiting cn, x );,2021/1/28,第58頁,程序運(yùn)行結(jié)果: 后6次函數(shù)調(diào)用,local x in a is 25 after entering a local x in a is 26 before exiting a local static x is

31、 50 on entering b local static x is 51 on exiting b global x is 1 on entering c global x is 10 on exiting c local x in a is 25 after entering a local x in a is 26 before exiting a local static x is 51 on entering b local static x is 52 on exiting b global x is 10 on entering c global x is 100 on exi

32、ting c,最后一次輸出: local x in main is 5,2021/1/28,第59頁,1變量的存儲(chǔ)類別 靜態(tài)變量在程序的運(yùn)行期間占用固定的存儲(chǔ)空間,直到程序的終止而釋放;而動(dòng)態(tài)變量是在程序的運(yùn)行期間隨著函數(shù)的調(diào)用隨時(shí)動(dòng)態(tài)地占用和釋放存儲(chǔ)空間。 存儲(chǔ)方式是根據(jù)變量的存儲(chǔ)類別決定的。 C的存儲(chǔ)類別有四種: 自動(dòng)的(auto)、靜態(tài)的(static)、寄存器的(register)、外部的(extern,二 變量存儲(chǔ)類別,2021/1/28,第60頁,變量作用范圍與生命周期,局部變量 作用范圍:函數(shù)(復(fù)合語句)內(nèi)部 生命周期:從函數(shù)調(diào)用開始函數(shù)調(diào)用結(jié)束 全局變量 作用范圍:從定義處到源

33、文件結(jié)束 生命周期:從程序執(zhí)行開始程序運(yùn)行結(jié)束 靜態(tài)局部變量 作用范圍:局部變量 生命周期:全局變量,2021/1/28,第61頁,存儲(chǔ)類型: 動(dòng)態(tài)存儲(chǔ):自動(dòng)變量 靜態(tài)存儲(chǔ):外部變量、靜態(tài)局部變量 用戶存儲(chǔ)空間,2局部變量的存儲(chǔ)方式函數(shù)中的局部變量若未專門說明,都是由編譯系統(tǒng)自動(dòng)動(dòng)態(tài)分配存儲(chǔ)空間,這類局部變量稱為自動(dòng)變量,其類型說明前不論是否有關(guān)鍵字“auto”,都屬于動(dòng)態(tài)存儲(chǔ)類別,2021/1/28,第62頁,若希望被調(diào)函數(shù)在結(jié)束后,其局部變量占用的存儲(chǔ)空間不釋放,以便保留其變量的值,用于下次調(diào)用該函數(shù),則用“static”說明為 “局部靜態(tài)變量”。 局部靜態(tài)變量在靜態(tài)存儲(chǔ)區(qū)分配存儲(chǔ)單元,在

34、程序的整個(gè)運(yùn)行期間都不釋放。而動(dòng)態(tài)變量在動(dòng)態(tài)存儲(chǔ)區(qū)分配存儲(chǔ)單元,函數(shù)調(diào)用結(jié)束后即釋放,2021/1/28,第63頁,*求n?。ǘ?用static型變量保留上次階乘的值*/ #include long fac(int n) static int f=1; f=f*n; return f; main() int i; for(i=1;i=5;i+) printf(%d!=%ldn,i,fac(i);,程序運(yùn)行結(jié)果: 1!=1 2!=2 3!=6 4!=24 5!=120,2021/1/28,第64頁,6.3 內(nèi)部函數(shù)與外部函數(shù),外部函數(shù) 函數(shù)能夠被程序中的其他程序文件模塊調(diào)用 在其他文件模塊中調(diào)

35、用該函數(shù)前,聲明為外部函數(shù) extern 函數(shù)類型 函數(shù)名(參數(shù)表說明,extern int f1(); int main(void) f1( );,文件名 file1.c,int f1( ),文件名 file2.c,調(diào)用另一模塊中的函數(shù),2021/1/28,第65頁,extern int f1(); int main(void) f1( );,static int f1( ),內(nèi)部函數(shù) 使函數(shù)只能在本程序文件模塊中被調(diào)用 static 函數(shù)類型 函數(shù)名(參數(shù)表說明,文件名 file1.c,文件名 file2.c,無法調(diào)用,2021/1/28,第66頁,例如:有兩個(gè)源文件file1.c和fil

36、e2.c如下所示,* file1.c 調(diào)用外部函數(shù)*/ # include int mod(int a, int b); extern int add (int m, int n); /*外部函數(shù)聲明* main() int x, y, result; scanf (“%d%d”,2021/1/28,第67頁,int mod(int a, int b) return(a%d); /* file2.c外部函數(shù)*/ extern int add(int m, int n) return(m+n);,說明,1在文件1(file1.c)中的函數(shù)聲明: int mod(int a, int b); 實(shí)際

37、上相當(dāng)于:extern int mod(int a, int b,2021/1/28,第68頁,2在文件2(file2.c)中的函數(shù)定義: extern int add(int m, int n) return(m+n); 實(shí)際上相當(dāng)于:int add(int m, int n) return(m+n);,3由多個(gè)源文件組成一個(gè)程序時(shí),main()函數(shù)只能出現(xiàn)在一個(gè)源文件中,2021/1/28,第69頁,4多個(gè)源文件的連接方式有三種,將各源文件分別編譯成目標(biāo)文件,得到多個(gè)目標(biāo)文件(.obj后綴),然后用連接命令(tlink)把多個(gè).obj文件連接起來,在Turbo c上用如下命令: tlink

38、 file1.obj+file2.obj+filen.obj 生成一個(gè)file1.exe的可執(zhí)行文件,建立項(xiàng)目文件(.prj后綴),具體操作可參閱各種C編譯手冊(cè),使用文件包含命令,2021/1/28,第70頁,6.4 遞歸函數(shù)設(shè)計(jì)和調(diào)用,C語言中一個(gè)函數(shù)中的語句可以是對(duì)另一個(gè)函數(shù)的調(diào)用,函數(shù)嵌套調(diào)用圖例,調(diào)用過程按圖中箭頭所示的方向和順序進(jìn)行,屬于一種線性調(diào)用關(guān)系,每次調(diào)用后,最終返回到原調(diào)用點(diǎn),繼續(xù)執(zhí)行以下語句,2021/1/28,第71頁,函數(shù)的遞歸調(diào)用,1. 定義: 在調(diào)用一個(gè)函數(shù)的過程中直接或間接地調(diào)用該函數(shù)本身。 直接調(diào)用 int f(x) int x; int y,z; . z=f

39、(x); return (2*z);,f 函數(shù),調(diào)用 f函數(shù),2021/1/28,第72頁,int f1(x) int x; int y,z; . z=f2( y); return (2*z);,int f2(t) int t; int a,c; . c=f1(a); return (3+c);,間接調(diào)用,2021/1/28,第73頁,遞歸算法在可計(jì)算性理論中占有重要地位,它是算法設(shè)計(jì)的有力工具,對(duì)于拓展編程思路非常有用。就遞歸算法而言并不涉及高深數(shù)學(xué)知識(shí),只不過初學(xué)者要建立起遞歸概念不十分容易。 我們先從一個(gè)最簡(jiǎn)單的例子導(dǎo)入,遞歸及其實(shí)現(xiàn),用遞歸算法求n! 定義:函數(shù) fact( n ) =

40、 n! fact( n-1 ) = ( n-1 )! 則有fact( n ) = n fact( n-1 ) 已知fact( 1 ) = 1,2021/1/28,第74頁,遞歸式,遞歸出口,分析,求n! 遞歸定義 n! = n * (n-1)! (n 1) n! = 1 (n = 0,1,include double fact(int n); int main(void) int n; scanf (%d,fact(n)=n*fact(n-1,2021/1/28,第75頁,main() fact(3) fact(2) fact(1) . . . . printf(fact(3) f=3*fac

41、t(2) f=2*fact(1) f=1 return(f) return(f) return(f),遞歸函數(shù) fact( n )的實(shí)現(xiàn)過程,fact(3)= 3*fact(2) 2*fact(1) fact(1)1,2*1=2,3*2=6,同時(shí)有4個(gè)函數(shù)在運(yùn)行,且都未完成,2021/1/28,第76頁,遞歸程序設(shè)計(jì),用遞歸實(shí)現(xiàn)的問題,滿足兩個(gè)條件: 問題可以逐步簡(jiǎn)化成自身較簡(jiǎn)單的形式(遞歸式) n! = n * (n-1)! n n-1 i = n + i i=1 i=1 遞歸最終能結(jié)束(遞歸出口) 兩個(gè)條件缺一不可 解決遞歸問題的兩個(gè)著眼點(diǎn),2021/1/28,第77頁,漢諾塔故事: 相傳

42、在古代印度的 Bramah 廟中,有位僧人整天把三根柱子上的金盤倒來倒去,原來他是想把64個(gè)一個(gè)比一個(gè)小的金盤從一根柱子上移到另一根柱子上去。移動(dòng)過程中恪守下述規(guī)則:每次只允許移動(dòng)一只盤,且大盤不得落在小盤上面。有人會(huì)覺得這很簡(jiǎn)單,真的動(dòng)手移盤就會(huì)發(fā)現(xiàn),如以每秒移動(dòng)一只盤子的話,按照上述規(guī)則將64只盤子從一個(gè)柱子移至另一個(gè)柱子上,所需時(shí)間約為5800億年,2021/1/28,第78頁,怎樣編寫這種程序?思路上還是先從最簡(jiǎn)單的情況分析起,搬一搬看,慢慢理出思路,1、在A柱上只有一只盤子,假定盤號(hào)為1,這時(shí)只需將該盤從A搬至C,一次完成,記為move 1 from A to C (演示,1,202

43、1/1/28,第79頁,2、在A柱上有二只盤子,1為小盤,2為大盤。 第(1)步將1號(hào)盤從A移至B,這是為了讓2號(hào)盤能移動(dòng); 第(2)步將2號(hào)盤從A移至C; 第(3)步再將1號(hào)盤從B移至C; 這三步記為(演示,2,1,move 1 from A to B; move 2 from A to C; move 1 from B to C,2021/1/28,第80頁,3、在A柱上有3只盤子,從小到大分別為1號(hào),2號(hào),3號(hào) 第(1)步 將1號(hào)盤和2號(hào)盤視為一個(gè)整體;先將二者作為整體從A移至B,給3號(hào)盤創(chuàng)造能夠一次移至C的機(jī)會(huì)。這一步記為 move( 2, A, C, B) 意思是將上面的2只盤子作為

44、整體從A借助C移至B。 第(2)步 將3號(hào)盤從A移至C,一次到位。記為 move 3 from A to C 第(3)步 處于B上的作為一個(gè)整體的2只盤子,再移至C。這一步記為 move( 2, B, A, C) 意思是將2只盤子作為整體從B借助A移至C。 所謂借助是什么意思,等這件事做完了不言自明,2021/1/28,第81頁,move (3, A, B, C,3,演示:移動(dòng)3個(gè)盤子的分解,2021/1/28,第82頁,move (3, A, B, C,2,1,3,2021/1/28,第83頁,4、從題目的約束條件看,大盤上可以隨便摞小盤,相反則不允許。在將1號(hào)和2號(hào)盤當(dāng)整體從A移至B的過程

45、中 move(2, A, C, B) 實(shí)際上是分解為以下三步 第(1).1步:move 1 form A to C; 第(1).2步:move 2 form A to B; 第(1).3步:move 1 form C to B,2021/1/28,第84頁,經(jīng)過以上步驟,將 1 號(hào)和 2 號(hào)盤作為整體從 A 移至 B,為 3 號(hào)盤從 A 移至 C 創(chuàng)造了條件。同樣,3號(hào)盤一旦到了 C,就要考慮如何實(shí)現(xiàn)將 1 號(hào)和 2 號(hào)盤當(dāng)整體從 B 移至 C 的過程了。實(shí)際上 move(2, B, A, C) 也要分解為三步: 第(3).1步:move 1 form B to A; 第(3).2步:move

46、 2 form B to C; 第(3).3步:move 1 form A to C,2021/1/28,第85頁,5、看 move(2, A, C, B) 是說要將 2 只盤子從 A 搬至 B,但沒有 C 是不行的,因?yàn)榈冢?).1步就要將 1 盤從 A 移到 C,給 2 盤創(chuàng)造條件從 A 移至 B,然后再把 1 盤從 C 移至 B??吹竭@里就能明白借助 C 的含義了。因此,在構(gòu)思搬移過程的參量時(shí),要把 3 個(gè)柱子都用上,2021/1/28,第86頁,這3步是相關(guān)的,相互依存的,而且是有序的,從左至右執(zhí)行。 move(n, A, B, C) 分解為3步 (1)move(n-1, A, C,

47、B)理解為將上面的n-1只盤子作為一個(gè)整體從A經(jīng)C移至B; (2)輸出n:A to C,理解將n號(hào)盤從A移至C,是直接可解的; (3)Move(n-1, B, A, C)理解為將上面的n-1只盤子作為一個(gè)整體從B經(jīng)A移至C,2021/1/28,第87頁,這里顯然是一種遞歸定義,當(dāng)解 move(n-1, A, C, B)時(shí)又可想到,將其分解為 3 步: 第1步:將上面的n-2只盤子作為一個(gè)整體從A經(jīng)B到C,move(n-2, A, B, C); 第2步:第n-1號(hào)盤子從A直接移至B,即n-1:A to B; 第3步:再將上面的n-2只盤子作為一個(gè)整體從C經(jīng)A移至B,move(n-2, C, A,

48、 B,2021/1/28,第88頁,void move(int m, char A, char B, char C) /*自定義函數(shù)體開始*/ if (m=1)/*如果m為1,則為直接可解*/ /*輸出移盤信息*/ printf(%d move 1 from %c to %cn,step,A,C); step+;/* 步數(shù)加1*/ else/*如果不為1,則要調(diào)用move(m-1)*/ move(m-1,A,C,B);/* 遞歸調(diào)用move(m-1)*/ /*輸出移盤信息*/ printf(%d move %d from %c to %cn,step,m,A,C); step+;/* 步數(shù)加1

49、*/ move(m-1,B,A,C);/* 遞歸調(diào)用move(m-1)*/,2021/1/28,第89頁,include /* 預(yù)編譯命令*/ int step=1; /*定義全局變量step*/ void move(int m,char A,char B,char C); /* 聲明要用到的被調(diào)用函數(shù)*/ void main()/* 主函數(shù)*/ /*主程序開始*/ int n;/* 整型變量,n為盤數(shù)*/ printf(請(qǐng)輸入盤數(shù) n=);/* 提示信息*/ scanf(%d,/* 調(diào)用函數(shù) move(n,a,b,c)*/,2021/1/28,第90頁,2021/1/28,第91頁,例6-7

50、】 求Fibonacci數(shù)列第i項(xiàng)的值。 Fibonacci數(shù)列:0, 1, 1, 2, 3, 5, 8, 13, 21,其數(shù)字表達(dá)式為: fibonacci(0)=0 fibonacci(1)=1 fibonacci(n)=fibonacci(n-1)+fibonacci(n-2) (n1,設(shè)計(jì)一個(gè)函數(shù):long fibonacci (int n)用于計(jì)算數(shù)列中第n項(xiàng)的值,2021/1/28,第92頁,程序如下所示,*exam6_7.c 求第n項(xiàng)Fibonacci數(shù)列的值*/ #include long fibonacci(int n); main() int x=0; long resul

51、t; do result=fibonacci(x); printf(fibonacci(%d)=%ldn,x,result); scanf(%d,2021/1/28,第93頁,long fibonacci(int n) if(n=0|n=1) return n; else return fibonacci(n-1)+fibonacci(n-2);,程序運(yùn)行結(jié)果: fibonacci(0)=0 3 fibonacci(3)=2 4 fibonacci(4)=3 6,2021/1/28,第94頁,以x=4為例,下圖說明了fibonacci函數(shù)是怎樣計(jì)算fibonacci(4)的。圖中把fibona

52、cci簡(jiǎn)寫成f,2021/1/28,第95頁,編譯預(yù)處理是語言編譯程序的組成部分,它用于解釋處理語言源程序中的各種預(yù)處理指令。 文件包含(#include)和宏定義(#define)都是編譯預(yù)處理指令 在形式上都以“#”開頭,不屬于C語言中真正的語句 增強(qiáng)了C語言的編程功能,改進(jìn)語言程序設(shè)計(jì)環(huán)境,提高編程效率,6.10 編譯預(yù)處理,2021/1/28,第96頁,C程序的編譯處理,目的是把每一條C語句用若干條機(jī)器指令來實(shí)現(xiàn),生成目標(biāo)程序。 由于#define等編譯預(yù)處理指令不是C語句,不能被編譯程序翻譯,需要在真正編譯之前作一個(gè)預(yù)處理,解釋完成編譯預(yù)處理指令,從而把預(yù)處理指令轉(zhuǎn)換成相應(yīng)的C程序段

53、,最終成為由純粹C語句構(gòu)成的程序,經(jīng)編譯最后得到目標(biāo)代碼,編譯預(yù)處理,2021/1/28,第97頁,編譯預(yù)處理的主要功能: 文件包含(#include) 宏定義(#define) 條件編譯,編譯預(yù)處理功能,2021/1/28,第98頁,1. 宏定義 1) 不帶參數(shù)的宏定義 用指定的標(biāo)識(shí)符(宏名)代表一個(gè)常量或字符串。 #define 標(biāo)識(shí)符 常量/字符串,2021/1/28,第99頁,例6.8 求圓的周長、面積和圓球的體積。 #define PI 3.1415926 / 宏名PI用大寫,行末無分號(hào) / main( ) float l, s, r, v ; scanf(“%f ”,2021/1/

54、28,第100頁,進(jìn)行宏定義時(shí),可以引用已定義的宏名,層層置換。 對(duì)程序中用雙引號(hào)括起來的字符串,即使與宏名相同,也不會(huì)被置換,宏名的有效范圍為該宏定義命令之后至本源文件結(jié)束。通常,宏定義命令一般寫在文件開頭或函數(shù)之前作為該文件的一部分,可以用 #undef 命令終止宏定義的作用域。如:#define G 9.8main( )#undef Gfloat f( ),G 的作用范圍,2021/1/28,第101頁,2帶參數(shù)的宏定義,語句形式: #define 宏名(形參表) 表達(dá)式,例6.9 #define PI 3.1415926 #define S(r) PI r r main( ) floa

55、t a, area; a=3.6; area=S(a); / area=3.1415926aa,但不會(huì)置換a為3.6 / printf(“r=%f narea=%f n”,a,area);,2021/1/28,第102頁,若將area=S(a) 改寫成 area=S(a+2),將置換為: area=PI a+2a+2,而不是: area=PI (a+2)(a+2)。 若要達(dá)到后者之目的,則應(yīng)將宏定義命令改寫為: #define S(r) PI (r) (r) 宏名與括號(hào)之間不得有空格,因?yàn)楹昝c表達(dá)式之間的分隔符為空格。如果用#define S (r) PI r r 的話,則被置換為 area

56、=(r) PI r r(a) 宏展開并不進(jìn)行值的傳遞,即不求表達(dá)式的值,也沒有“返回值”的概念。 宏不存在類型問題,宏名無類型,參數(shù)也無類型,表達(dá)式可以是任何類型,對(duì)帶參數(shù)的宏定義的置換展開是用“表達(dá)式”對(duì)等的置換“形參表”中的參數(shù)。上例中的“”是不會(huì)被置換的,2021/1/28,第103頁,注:這里的 t 展開后為 t = (a+b)(c+d)?(a+b):(c+d) 如果第一行寫成: #define MAX(x,y) xy ? x : y 則這里的 t 展開后為 t = a+bc+d?a+b:c+d 因?yàn)橹脫Q展開是用“表達(dá)式”對(duì)等的置換“形參表”中的參數(shù),定義帶參數(shù)的宏,可以實(shí)現(xiàn)一些簡(jiǎn)單的

57、函數(shù)功能,如:#define MAX(x,y) (x)(y)?(x) : (y) main( ) int a, b, c, t ; t = MAX(a+b, c+d);,2021/1/28,第104頁,6.11 “文件包含” 處理,程序文件模塊 為了避免一個(gè)文件過長,可以把程序分別保存為幾個(gè)文件。 一個(gè)大程序會(huì)由幾個(gè)文件組成,每一個(gè)文件又可能包含若干個(gè)函數(shù)。 保存有一部分程序的文件稱為程序文件模塊。 程序文件函數(shù) 大程序若干程序文件模塊 各程序文件模塊分別編譯,再連接 整個(gè)程序只允許有一個(gè)main()函數(shù),2021/1/28,第105頁,格式 # include # include “需包含的

58、文件名” 作用 把指定的文件模塊內(nèi)容插入到 #include 所在的位置,當(dāng)程序編譯連接時(shí),系統(tǒng)會(huì)把所有 #include 指定的文件拼接生成可執(zhí)行代碼。 注意 編譯預(yù)處理命令,以#開頭。 在程序編譯時(shí)起作用,不是真正的C語句,行尾沒有分號(hào),文件包含,2021/1/28,第106頁,5個(gè)函數(shù)分別存儲(chǔ)在2個(gè).C文件上,要求通過文件包含把它們聯(lián)結(jié)起來,例6-10,2021/1/28,第107頁,ctype.h 字符處理 math.h 與數(shù)學(xué)處理函數(shù)有關(guān)的說明與定義 stdio.h 輸入輸出函數(shù)中使用的有關(guān)說明和定義 string.h 字符串函數(shù)的有關(guān)說明和定義 stddef.h 定義某些常用內(nèi)容

59、stdlib.h 雜項(xiàng)說明 time.h 支持系統(tǒng)時(shí)間函數(shù),常用標(biāo)準(zhǔn)頭文件,2021/1/28,第108頁,6.6 綜合范例,2021/1/28,第109頁,例6-13】 在屏幕上畫一個(gè)1818大小的棋盤,程序如下,*exam6_12.c 在屏幕上畫一個(gè)棋盤*/ #include #include #include /*定義畫棋盤所需的制表符*/ #define LU 0 xda /*左上角*/ #define RU 0 xbf /*右上角*/ #define LD 0 xc0 /*左下角*/ #define RD 0 xd9 /*右下角*/ #define L 0 xc3 /*左邊*/ #d

60、efine R 0 xb4 /*右邊*,2021/1/28,第110頁,define U 0 xc2 /*上邊*/ #define D 0 xc1 /*下邊*/ #define CROSS 0 xc5 /*十字叉*/ /*棋盤左上角坐標(biāo)*/ #define MAP_X 5 #define MAP_Y 5 void draw_cross(int x,int y); void draw_map(); main() textmode(C40); draw_map();,2021/1/28,第111頁,*函數(shù)定義:*/ void draw_map() /*畫棋盤*/ int i,j; for(i=0;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論