




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第六章第六章 函數函數1.為什么要使用函數?函數如何定義和調用?為什么要使用函數?函數如何定義和調用?2.函數參數如何傳遞?如何獲得函數的返回值?函數參數如何傳遞?如何獲得函數的返回值?3.如何使用局部變量與全局變量?變量有幾種存如何使用局部變量與全局變量?變量有幾種存儲類型?儲類型? 4.C提供的預處理功能主要有哪幾種?如何定義提供的預處理功能主要有哪幾種?如何定義帶參數的宏?帶參數的宏? 本章內容6.1 問題的提出與程序示例問題的提出與程序示例6.2 函數的定義與調用函數的定義與調用6.3 函數的參數傳遞與返回值函數的參數傳遞與返回值6.4 變量的作用域和存儲類型變量的作用域和存儲類型6.
2、5 編譯預處理編譯預處理6.6 函數的應用舉例函數的應用舉例 * 6.7 函數的嵌套與遞歸調用函數的嵌套與遞歸調用6.1 問題的提出與程序示例為什么要使用函數?為什么要使用函數?大型程序多人合作大型程序多人合作模塊化,功能清晰,便于編寫、閱模塊化,功能清晰,便于編寫、閱讀和調試讀和調試減少重復編寫的工作量,如減少重復編寫的工作量,如#include long factorial(int x) /*定義函數定義函數factorial計算計算n的的階乘階乘*/ int i; long result=1; for(i=2;i=x;i+)result*=i; return result; /*將將re
3、sult作為作為factorial的函的函數值返回到主調函數中數值返回到主調函數中*/!() !nmmCnmnvoid main() int m, n; long c; printf(Please input m,n:); scanf(%d,%d, &m,&n); c=factorial(m)/(factorial(n)*factorial(m-n);/*調調用函數用函數factorial并作為運算對象并作為運算對象*/printf(“c=%ldn”,c); 例例2:double add(double a,double b) double s; s=a+b; return s;
4、 void main() x=add(3.0,4.0); for(y=0,i=1;i=5;i+) y=add(y,i);函數參數函數參數實際值代入實際值代入這是函這是函數返回數返回值值例例3:計算計算1!+2!+3!+n! 用函數完成用函數完成 #include “stdio.h” fun( int n) int s=0,t=1; int i; for(i=1;i=n;i+) t=t*i; s=s+t; return (s); void main( ) int n; int s=0; scanf(“%d”,&n); s=fun(n); printf(“s=%dn”,s); 6.2 函數
5、的定義與調用6.2.1函數的分類函數的分類函數定義的角度函數定義的角度(1)庫函數)庫函數 庫函數是由庫函數是由C系統提供的,可以直接使用它系統提供的,可以直接使用它們。如:們。如:scanf,printf,getchar,putchar等。等。(2)用戶自定義函數)用戶自定義函數 用戶自定義函數就是由用戶自己定義和設計用戶自定義函數就是由用戶自己定義和設計的函數。的函數。主調函數和被調函數之間數據傳遞的角度主調函數和被調函數之間數據傳遞的角度(1)無參函數)無參函數(2)有參函數)有參函數6.2 函數的定義與調用6.2.2函數的定義函數的定義 C語言中的語言中的函數和變量一樣函數和變量一樣,
6、具有一定的,具有一定的存儲類型和存儲類型和數據類型數據類型。一般情況下,函數也應先定義,后調用一般情況下,函數也應先定義,后調用 1.無參函數的定義形式無參函數的定義形式 類型說明符類型說明符 函數名(函數名( ) 聲明部分聲明部分 語句部分語句部分 例如,定義一個打印一行例如,定義一個打印一行語句的函數。語句的函數。void printfline( ) printf(This is a C program!n);6.2 函數的定義與調用2. 有參函數的定義形式有參函數的定義形式類型說明符類型說明符 函數名(形式參數表列)函數名(形式參數表列) 聲明部分聲明部分語句部分語句部分 例如:定義一個
7、例如:定義一個average函數,用來函數,用來計算兩個整數的平均數。計算兩個整數的平均數。float average(int x, int y) float result; /* 定義變量定義變量result*/result=(x+y)/2.0;return result; /*函數返回值函數返回值*/6.2 函數的定義與調用 有參函數注意事項有參函數注意事項: (1)為每一個參數指定數據類型,)為每一個參數指定數據類型, 如如 float average(int x, int y)。任何不指定參數。任何不指定參數類型的寫法都是錯誤的。如:類型的寫法都是錯誤的。如:float average
8、(int x, y)編譯時會出錯,參數編譯時會出錯,參數 y 未指定數據類型。未指定數據類型。 (2)不允許在函數內部再次定義與參數同名的)不允許在函數內部再次定義與參數同名的變量。但不同函數內部允許定義同名的變量。變量。但不同函數內部允許定義同名的變量。6.2 函數的定義與調用6.2.3函數的調用函數的調用1.函數調用的形式函數調用的形式函數調用的形式為:函數調用的形式為:函數名(實參表列);函數名(實參表列);或或函數名();函數名();【例6-2】編寫程序計算兩個整數的平均數。要求調用printfline和average函數。#include void printfline( ) /*函
9、數定義函數定義*/printf(This is a C program!n); float average(int x,int y) /*函數定義函數定義*/float result;result=(x + y)/2.0; return result;void main( )int a,b;float ave;printfline( ); /*調用調用printfline函數輸出一行語句函數輸出一行語句*/printf(Please input a,b:);scanf(“%d,%d”, &a,&b); ave=average(a,b); /*調用調用average函數求兩個整數
10、函數求兩個整數a和和b的平均數的平均數*/ printf(Average of %d and %d is %f.n, a, b, ave); 按函數調用在程序中出現的位置來分,按函數調用在程序中出現的位置來分,函數調用函數調用大致可大致可分為以下幾種形式:分為以下幾種形式: (1)函數語句函數語句:把函數作為語句來使用把函數作為語句來使用,一般不需要返回一般不需要返回值值,只是通過函數調用完成某些操作。只是通過函數調用完成某些操作。 如如printfline( ); (2)函數表達式函數表達式:函數作為表達式中的一項出現在表:函數作為表達式中的一項出現在表達式中,以函數返回值參與表達式的運算,
11、如達式中,以函數返回值參與表達式的運算,如 ave=average(a,b); (3)函數實參函數實參:函數作為另一個函數調用的實際參數:函數作為另一個函數調用的實際參數出現。這種形式是把該函數的返回值作為實參進行傳送,出現。這種形式是把該函數的返回值作為實參進行傳送,因此要求該函數必須是有返回值的因此要求該函數必須是有返回值的 6.2 函數的定義與調用6.2函數的定義與調用2.被調函數的聲明被調函數的聲明 函數聲明的一般形式為:函數聲明的一般形式為: 函數類型函數類型 函數名函數名(參數類型參數類型1, 參數類型參數類型2,); 或或 函數類型函數類型 函數名函數名(參數類型參數類型1 參數
12、名參數名1, 參數類型參數類型2 參數名參數名2,); 自定義函數自定義函數一般應一般應定義在前,調用在后定義在前,調用在后。如果用戶在編制。如果用戶在編制程序時都按這個規律來進行,則不需要進行函數的聲明。程序時都按這個規律來進行,則不需要進行函數的聲明。但由于但由于C語言中的函數定義是各自獨立的。函數與函數之間語言中的函數定義是各自獨立的。函數與函數之間的排放位置并沒有先后順序關系,只有調用與被調用的關的排放位置并沒有先后順序關系,只有調用與被調用的關系。當出現調用在前,定義在后的情況,系。當出現調用在前,定義在后的情況,即即被調函數放置被調函數放置在主調函數之后,則應在主調函數的適當位置,
13、在主調函數之后,則應在主調函數的適當位置,加上函數加上函數原型聲明原型聲明 6.3 函數的參數傳遞和返回值6.3.1 函數的參數傳遞函數的參數傳遞參數傳遞方式分為:參數傳遞方式分為:(1)值傳遞方式(單向傳遞)值傳遞方式(單向傳遞) 所謂所謂“值傳遞方式值傳遞方式”是指將實參的具體數值單向傳是指將實參的具體數值單向傳遞給形參的一種方式。遞給形參的一種方式。 注意:值單向傳遞是指只能由實參傳遞給形參,而注意:值單向傳遞是指只能由實參傳遞給形參,而不能由形參傳遞給實參。如下例中,只能由實參不能由形參傳遞給實參。如下例中,只能由實參a,b依次對應傳遞給形參依次對應傳遞給形參x,y,反之則不行。,反之
14、則不行。6.3 函數的參數傳遞和返回值例:例:#includevoid main()void swap(int x,int y); /* 函數原型說明聲明函數原型說明聲明*/ int a,b;a=2,b=6;printf(調用前:調用前:a=%d,b=%dn,a,b);swap(a,b); /*函數調用函數調用*/printf(調用后:調用后:a=%d,b=%dn,a,b);函數在后函數在后,調用調用在前在前,所以要在所以要在調用前加說明調用前加說明6.3 函數的參數傳遞和返回值void swap(int x,int y) /*函數定義函數定義*/ int temp;printf(交換前:交換
15、前:x=%d,y=%dn,x,y);temp=x;x=y;y=temp;printf(交換后:交換后:x=%d,y=%dn,x,y);6.3 函數的參數傳遞和返回值上例運行結果:上例運行結果:最后交換最后交換成功了嗎成功了嗎?為什么為什么?在語言中,數據只能從實參單向傳遞給形參,在語言中,數據只能從實參單向傳遞給形參,稱為稱為“按值按值” 傳遞,即當簡單變量作為實參傳遞,即當簡單變量作為實參時,用戶時,用戶不能不能在在函數函數中中改變改變對應實參的值對應實參的值6.3 函數的參數傳遞和返回值(2)地址傳遞方式)地址傳遞方式 所謂所謂“地址傳遞方式地址傳遞方式”是指將實參的地址傳遞給形參是指將實
16、參的地址傳遞給形參的一種方式。在函數調用時,通過對形參所指地址單的一種方式。在函數調用時,通過對形參所指地址單元中的內容進行操作,從而引起與形參指向同一地址元中的內容進行操作,從而引起與形參指向同一地址單元的實參的內容發生變化。但這種變化并不是由形單元的實參的內容發生變化。但這種變化并不是由形參傳回實參引起的。參傳回實參引起的。 采用這種方式時,實參可以是變量的地址、也可以是采用這種方式時,實參可以是變量的地址、也可以是后續章節要介紹的數組名、相關指針變量,形參通常后續章節要介紹的數組名、相關指針變量,形參通常是數組或指針變量。是數組或指針變量。6.3 函數的參數傳遞和返回值6.3.2 函數的
17、返回值函數的返回值在在C語言中,可以在被調函數內采用語言中,可以在被調函數內采用return語句獲得函語句獲得函數的返回值。一個函數利用數的返回值。一個函數利用return語句只能返回一個值。語句只能返回一個值。return語句的形式為:(以下兩種寫法均可)語句的形式為:(以下兩種寫法均可)return(表達式);(表達式);或或return 表達式;表達式;需注意的是:函數名前面的函數類型說明符是用來指定需注意的是:函數名前面的函數類型說明符是用來指定本函數返回值的數據類型。在進行函數定義時,應使本函數返回值的數據類型。在進行函數定義時,應使return語句中的表達式的類型與函數類型說明一致
18、。當語句中的表達式的類型與函數類型說明一致。當return語句中的表達式的類型與函數類型說明不一致時,語句中的表達式的類型與函數類型說明不一致時,則以函數類型說明為準,系統自動將則以函數類型說明為準,系統自動將return語句中的表達語句中的表達式的值轉換為函數類型說明所指定的類型。式的值轉換為函數類型說明所指定的類型。 #include void main() int average(int x,int y); /* 函數聲明函數聲明*/ int a,b; float ave; printf(Please input a,b:); scanf(“%d,%d”, &a,&b);
19、 ave=average(a,b); /*調用調用average函數求兩函數求兩個整數個整數a和和b的平均數的平均數*/ printf(Average of %d and %d is %f.n, a, b, ave); int average(int x,int y) /*將將average函數的類型改為函數的類型改為int型型*/float result;result=(x + y)/2.0; return result;本例中,因為函數本例中,因為函數average的返回類型為的返回類型為int型,所以要將型,所以要將return的實型值的實型值3.5轉化為轉化為int型。固結果為型。固結
20、果為3.000000當函數沒有返回值時,為了使程序有良好的可讀性并減當函數沒有返回值時,為了使程序有良好的可讀性并減少出錯,在函數定義時,函數類型說明符應為少出錯,在函數定義時,函數類型說明符應為void(“空類型空類型”)。)。注意:注意:(1)調用函數時,函數名不能有錯。)調用函數時,函數名不能有錯。(2)實參和形參要一一對應,個數一致,類實參和形參要一一對應,個數一致,類型匹配。型匹配。(3)函數必須先定義,后調用函數必須先定義,后調用,除非函數返,除非函數返回值類型為回值類型為int或或char。(4)函數可以自己調用自己,即遞歸調用。)函數可以自己調用自己,即遞歸調用。例:例:dou
21、ble add(double,double);函數說明的形式函數說明的形式類型名類型名 函數名(參數類型函數名(參數類型1,參數類型,參數類型2,) 對于用戶定義的函數要對于用戶定義的函數要“先定義,后使用先定義,后使用”的的規則。凡是未在調用前定義的函數,默認函數規則。凡是未在調用前定義的函數,默認函數的返回值為的返回值為int類型。類型。對于返回值為其它類型的函數,對于返回值為其它類型的函數,若把函數的定若把函數的定義放在調用之后,義放在調用之后,應該在調用之間對應該在調用之間對函數進行函數進行說明說明(稱為函數原型說明)(稱為函數原型說明)可放在所有函數可放在所有函數外部外部,在此后的所
22、有位置,在此后的所有位置上都可以上都可以調用調用該函數。該函數。也可放在某函數內的說明部分,則只有在也可放在某函數內的說明部分,則只有在某函數內能識別該函數。某函數內能識別該函數。71513114#include#includevoid main( ) float e,pi; double funpi(double t); scanf(“%lf”,&e); pi=funpi(e); printf(“pi=%fn”,pi);補充補充: 編寫函數編寫函數isprime(int a) 用來判斷自變量用來判斷自變量a是否為素是否為素數,若是素數,函數返回數,若是素數,函數返回1,否則返回,否則
23、返回0#include “math.h”int isprime (int ); void main()int x;printf(“Enter a integer number: ”);scanf(“%d”,&x);if(isprime(x) printf(“%d is primen”,x);else printf(“%d is not primen”,x); 編寫函數編寫函數isprime(int a) 用來判斷自變量用來判斷自變量a是否為是否為素數,若是素數,函數返回素數,若是素數,函數返回1,否則返回,否則返回0int isprime( int a) int i; for(i=2;
24、 i=(int)sqrt(double)a); i+) if(a%i=0) return 0; return 1;補充例子補充例子:編寫函數編寫函數myupper(ch),把把ch中的小寫字母轉換中的小寫字母轉換成大寫字母作為函數值返回成大寫字母作為函數值返回,其它字符不變其它字符不變,用字符用字符#結束結束輸入。輸入。#include char myupper(char);void main( ) char c; while(c=getchar()!=#) c=myupper(c); putchar(c);char myupper(char ch) if(ch=a & ch=z) c
25、h=ch-32; return ch;程序舉例程序舉例:補充補充: 編寫函數編寫函數sum( int n ) 求求 。 和值作為和值作為函數返回。函數返回。f(x)=x2+1#includeint sum (int);函數要先定義它的原型,后調用函數要先定義它的原型,后調用int f(int);void main( )int n,s;printf(“Enter a integer number: ”);scanf(“%d”,&n);s=sum(n);printf(“n=%d sum=%dn”,n,s); nxxf0)(int sum( int n) int x,s=0; for(x=0
26、; x=n; x+) s+=f(x); return s; int f(int x)return x*x+1; 補充補充: 用梯形法求函數用梯形法求函數f(x)=sin(x)在在0,1.5區間的區間的定積分,定積分,n選選100。近似公式。近似公式近似公式近似公式s=h*(f(a)+f(b)/2+ )#include “math.h”double integ(double a,double b) (函數先定義后函數先定義后調用調用)double s,x,h; int n=100,i; h=fabs(b-a)/n; s=(sin(a)+sin(b)/2.0; 11)*(nihiaffor(i=1
27、; i=n-1;i+) x=a+i*h; s=s+sin(x); s=s*h; return s;void main() double s; s=integ(0.0,1.5); printf(“s=%fn”,s);6.4 變量的作用域與存儲類型6.4.1 變量的作用域變量的作用域: 1局部變量局部變量(1)在函數體內定義的變量,在本函數范圍內有效,)在函數體內定義的變量,在本函數范圍內有效,作用域局限于函數體內。作用域局限于函數體內。(2)在復合語句內定義的變量,在本復合語句范圍)在復合語句內定義的變量,在本復合語句范圍內有效,作用域局限于復合語句內。內有效,作用域局限于復合語句內。(3)有參
28、函數的形式參數也是局部變量,只在其所)有參函數的形式參數也是局部變量,只在其所在的函數范圍內有效。在的函數范圍內有效。 注注:(:(1)主函數中定義的變量只能在主函數中使用,不)主函數中定義的變量只能在主函數中使用,不能在其它函數中使用。同時,主函數中也不能使用其它函能在其它函數中使用。同時,主函數中也不能使用其它函數中定義的變量。(數中定義的變量。(2)不同函數中和不同的復合語句中不同函數中和不同的復合語句中可以使用(即定義)相同的變量名。可以使用(即定義)相同的變量名。因為它們的作用域不因為它們的作用域不同,程序運行時在內存中占據不同的存儲單元,各自代表同,程序運行時在內存中占據不同的存儲
29、單元,各自代表不同的對象,所以它們之間互不干預。不同的對象,所以它們之間互不干預。6.4 變量的作用域與存儲類型 2全局變量全局變量全局變量也稱為外全局變量也稱為外部變量,它是在任部變量,它是在任何函數之外定義的何函數之外定義的變量。變量。它的有效范它的有效范圍為從定義變量的圍為從定義變量的位置開始到本源文位置開始到本源文件結束。件結束。例如:例如: int x,y,z;/* x,y,z均是全局變量均是全局變量 */ float f1(float a,float b) char ch1,ch2; /* ch1,ch2均是均是全局變量全局變量 */ int f2( int m) double t
30、,p;/* t,p均是全局變量均是全局變量 */ void main( ) 6.4 變量的作用域與存儲類型全局變量和局部變量同名的應用例子。全局變量和局部變量同名的應用例子。 #include int a=3,b=5; /* a,b為為 變量變量*/ int max (int a, int b) /*a,b為為 變量變量 */ int c; c=ab?a:b; return (c); void main ( ) int a=8; /*a為為 變量變量 */ printf (max=%dn, max (a,b); 運行結果:運行結果:如果同一個源文件中,如果同一個源文件中,全局變量與局部變量全局
31、變量與局部變量同名,當局部變量有同名,當局部變量有效時,效時,同名的全局變同名的全局變量不起作用。量不起作用。 6.4 變量的作用域與存儲類型6.4.2 變量的存儲類型變量的存儲類型動態存儲方式和靜態存儲方式。動態存儲方式和靜態存儲方式。根據這兩類存儲方式,變量又可具體分為四種:根據這兩類存儲方式,變量又可具體分為四種:自動變量自動變量(auto)、寄存器變量、寄存器變量(register)、靜態變、靜態變量量(static)、 外部變量外部變量(extern)。在在C語言中,每個變量和函數有兩個屬性:數據語言中,每個變量和函數有兩個屬性:數據類型和存儲類型。定義變量的完整形式為:類型和存儲類
32、型。定義變量的完整形式為:存儲類型存儲類型 數據類型數據類型 變量名變量名1,變量名,變量名2,;其中,其中,存儲類型可以是存儲類型可以是auto、register、extern或或static。6.4 變量的作用域與存儲類型1auto變量變量auto說明符常常省略說明符常常省略,系統默認為沒有存儲類型說,系統默認為沒有存儲類型說明符的變量為自動存儲類型的變量,前面各章中所明符的變量為自動存儲類型的變量,前面各章中所有程序中所用到的各個變量,都未說明存儲方式,有程序中所用到的各個變量,都未說明存儲方式,都是自動變量。都是自動變量。在函數體內定義變量時,下面兩種寫法是等價的。在函數體內定義變量時
33、,下面兩種寫法是等價的。int x,y,z;auto int x,y,z;6.4 變量的作用域與存儲類型2register變量變量一般情況下,變量的值都是存儲在內存中的。對于一般情況下,變量的值都是存儲在內存中的。對于一些頻繁使用的變量,可以放在一些頻繁使用的變量,可以放在CPU內部的寄存器內部的寄存器中,以提高訪問這些變量的速度。這種變量就稱為中,以提高訪問這些變量的速度。這種變量就稱為寄存器變量。寄存器變量也屬于局部變量范疇。寄存器變量。寄存器變量也屬于局部變量范疇。(1)只有局部變量和形參可以作為寄存器變量,)只有局部變量和形參可以作為寄存器變量,其他變量不可以(全局變量、局部靜變量不可
34、以)。其他變量不可以(全局變量、局部靜變量不可以)。(2)由于計算機的寄存器數目有限,不宜定義太)由于計算機的寄存器數目有限,不宜定義太多寄存器變量。不同的系統允許使用的寄存器個數多寄存器變量。不同的系統允許使用的寄存器個數是不同的。是不同的。 6.4 變量的作用域與存儲類型3static變量變量靜態變量在程序開始運行時就分配了固定的內存靜態變量在程序開始運行時就分配了固定的內存空間,在程序運行過程中不釋放,直到程序運行空間,在程序運行過程中不釋放,直到程序運行結束才釋放它所占的存儲空間,因此靜態變量的結束才釋放它所占的存儲空間,因此靜態變量的生存期是整個程序。由于變量分為局部變量和全生存期是
35、整個程序。由于變量分為局部變量和全局變量,所以靜態變量也分為靜態局部變量和靜局變量,所以靜態變量也分為靜態局部變量和靜態全局變量。態全局變量。(1)靜態局部變量)靜態局部變量靜態局部變量仍然是定義在函數內部的局部變量,靜態局部變量仍然是定義在函數內部的局部變量,它的作用域仍然局限于函數內部。它的作用域仍然局限于函數內部。例如:例如:static int m=10,n;6.4 變量的作用域與存儲類型【例例6-7】編寫程序計算編寫程序計算1!5!的值。!的值。 #include int fac(int n) /*函數定義函數定義*/ static int f=1; /* 靜態局部變量靜態局部變量
36、*/ f=f*n; return(f); void main() int i; for (i=1;i=5;i+) printf(%d! =%dn,i,fac(i); 在函數在函數fac內部定義內部定義了靜態局部變量了靜態局部變量 f,每次調用都保留了上每次調用都保留了上一次計算的結果一次計算的結果例如:例如:static int m=10,n;說明:說明:(1) 靜態局部變量的存儲空間是在程序編譯時由系統分靜態局部變量的存儲空間是在程序編譯時由系統分配的,且在程序運行的整個期間都固定不變。配的,且在程序運行的整個期間都固定不變。(2)靜態局部變量編譯時賦初值,每次調用時不再賦初靜態局部變量編譯
37、時賦初值,每次調用時不再賦初值,只保留調用結束時變量的值。值,只保留調用結束時變量的值。(3)對靜態局部變量,如果定義時不賦初值的話,編譯)對靜態局部變量,如果定義時不賦初值的話,編譯時系統會自動賦值為時系統會自動賦值為0或空字符(對字符變量)。或空字符(對字符變量)。如上例在程序編譯時給變量如上例在程序編譯時給變量m賦予賦予10,對未給定,對未給定初值的變量初值的變量n,C 編譯系統自動給它賦編譯系統自動給它賦0值。值。(2)靜態全局變量)靜態全局變量在在C語言中,全局變量的存儲都采用靜態存儲方式。語言中,全局變量的存儲都采用靜態存儲方式。6.4 變量的作用域與存儲類型4extern變量變量
38、 全局變量(即外部變量)的作用域是從定義的位置起到本全局變量(即外部變量)的作用域是從定義的位置起到本文件的末尾止。采用文件的末尾止。采用extern來聲明全局變量可以擴大全局來聲明全局變量可以擴大全局變量的作用域。變量的作用域。 (1) 在多個文件中聲明全局變量在多個文件中聲明全局變量 一個一個C程序可以由多個文件組成。如果一個文件中要引用程序可以由多個文件組成。如果一個文件中要引用另外一個文件中所定義的全局變量,需要在此文件中,用另外一個文件中所定義的全局變量,需要在此文件中,用extern進行聲明。進行聲明。 (2) 在一個文件中聲明全局變量在一個文件中聲明全局變量 同一個文件中,在全局
39、變量定義點之前的函數想引用該全同一個文件中,在全局變量定義點之前的函數想引用該全局變量,應該在引用之前用局變量,應該在引用之前用extern對該變量作對該變量作“全局變量全局變量聲明聲明”。全局變量未被初始化,系統自動賦初值。全局變量未被初始化,系統自動賦初值0。6.4 變量的作用域與存儲類型 【例例6-8】同一個文件中聲明全局變量的應用例子。同一個文件中聲明全局變量的應用例子。 #include void main() 結果示例:結果示例: int min(int a,int b); extern x,y;/* 聲明全局變量聲明全局變量x,y */ printf(%dn,min(x,y);
40、int x=22,y=11;/* 定義全局變量定義全局變量x,y */ int min(int a,int b) int c; c=ab?a:b; return(c); 6.5 編譯預處理 編譯預處理是指,在對源程序進行編譯之前,先編譯預處理是指,在對源程序進行編譯之前,先對源程序中的編譯預處理命令進行處理,然后再對源程序中的編譯預處理命令進行處理,然后再將處理的結果,和源程序一起進行編譯,以得到將處理的結果,和源程序一起進行編譯,以得到目標代碼。目標代碼。 提供的預處理功能主要有宏定義、文件包含和提供的預處理功能主要有宏定義、文件包含和條件編譯。這些功能分別用宏定義命令、文件包條件編譯。這些
41、功能分別用宏定義命令、文件包含命令、條件編譯命令來實現。預處理命令是以含命令、條件編譯命令來實現。預處理命令是以號開頭的代碼行。號開頭的代碼行。6.5 編譯預處理 6.5.1 宏定義宏定義 宏定義是用指定標識符(宏名)來代表一個字符串。宏定義是用指定標識符(宏名)來代表一個字符串。1不帶參數的宏定義不帶參數的宏定義 其定義的一般形式:其定義的一般形式: define 宏名宏名 字符串字符串 字符串可以是常數、表達式、格式串等。字符串可以是常數、表達式、格式串等。宏定義可出現在宏定義可出現在程序中的任何位置。程序中的任何位置。 可以用可以用#undef命令終止宏名的作用域,其一般形式為命令終止宏
42、名的作用域,其一般形式為 undef 標識符標識符 一、無參數的宏定義一、無參數的宏定義 格式:格式:#define 宏名宏名 替換文本替換文本 or #define 宏名宏名 (說明宏名已被說明宏名已被”定義定義“)如如 :#define SIZE 100 替換文本中可以包含已定義過的宏名替換文本中可以包含已定義過的宏名如:如: #define PI 3.14#define ADDPI (PI+1)#define TWO_ADDPI (2*ADDPI) 若程序中有表達式若程序中有表達式:x=TWO_ADDPI/2,替換后替換后,表達式將表達式將成為成為: x=(2*(3.14+1)/2若寫成
43、若寫成 #define PI 3.14 #define ADDPI PI+1 (無括號無括號) #define TWO_ADDPI 2*ADDPI (無括號無括號)則以上表達式成為則以上表達式成為:x=2*3.14+1/2 二、有參數的宏定義二、有參數的宏定義 格式:格式: #define 宏名(參數表)宏名(參數表) 替換文本替換文本如:如: #define MU(X,Y) (X)*(Y) a=MU(5,2);/*引用帶參的宏名引用帶參的宏名*/b=6/MU(a+3,a);注意:同一宏名也不能重復定義注意:同一宏名也不能重復定義圓括號不能少圓括號不能少6.5 編譯預處理對于帶參數的宏定義有以
44、下問題需要說明:對于帶參數的宏定義有以下問題需要說明:(1)定義帶參數的宏時,宏名與左圓括號之間)定義帶參數的宏時,宏名與左圓括號之間不能留有空格。否則將空格以后的所有字符均作不能留有空格。否則將空格以后的所有字符均作為替換字符串,用來替換不帶參數的宏名。為替換字符串,用來替換不帶參數的宏名。(2)帶參數的宏展開時,用實參字符串替換形)帶參數的宏展開時,用實參字符串替換形參字符串,而不做任何語法檢查。參字符串,而不做任何語法檢查。讀者可能已經讀者可能已經體會到,帶參數的宏在程序中使用時,它的使用體會到,帶參數的宏在程序中使用時,它的使用形式和特性和函數很相似。但是在本質上它們是形式和特性和函數
45、很相似。但是在本質上它們是完全不同的。完全不同的。6.5 編譯預處理 帶參數的宏和函數的區別有以下幾點:帶參數的宏和函數的區別有以下幾點: (1)函數調用時,先求出實參表達式的值,然后將值代函數調用時,先求出實參表達式的值,然后將值代入形參;而宏調用時只是用實參簡單地替換形參。入形參;而宏調用時只是用實參簡單地替換形參。 (2)函數調用是在程序運行時進行的,為形參分配臨時函數調用是在程序運行時進行的,為形參分配臨時的內存單元,占用運行時間;而宏調用則是在編譯時由編的內存單元,占用運行時間;而宏調用則是在編譯時由編譯預處理程序完成的,僅僅是一種簡單的替換,并不分配譯預處理程序完成的,僅僅是一種簡
46、單的替換,并不分配內存單元,不進行值的傳遞處理,也沒有內存單元,不進行值的傳遞處理,也沒有“返回值返回值”的概的概念,因此宏調用不占用運行時間。念,因此宏調用不占用運行時間。 (3)在函數定義時,必須指定每一個形式參數的類型,在函數定義時,必須指定每一個形式參數的類型,而宏定義中只給出形式參數,宏不存在類型問題,宏名無而宏定義中只給出形式參數,宏不存在類型問題,宏名無類型,它的參數也沒有類型,只是一個符號代表。類型,它的參數也沒有類型,只是一個符號代表。 (4)調用函數只可以得到一個返回值,而用宏可以設法調用函數只可以得到一個返回值,而用宏可以設法得到幾個結果。得到幾個結果。 6.5 編譯預處
47、理6.5.2 文件包含文件包含一般形式為:一般形式為:include “文件名文件名” 或或 include 它的功能是把指定的文件插入該命令行位置取代它的功能是把指定的文件插入該命令行位置取代該命令行,從而把指定的文件和當前的源程序文該命令行,從而把指定的文件和當前的源程序文件連成一個源文件。件連成一個源文件。 6.5 編譯預處理 6.5.3 條件編譯條件編譯 為了提高程序的可移植性,增加程序的靈活性,有時只希為了提高程序的可移植性,增加程序的靈活性,有時只希望對其中某一部分在滿足一定條件時才進行編譯,即對部望對其中某一部分在滿足一定條件時才進行編譯,即對部分內容指定編譯條件,這就是條件編譯
48、。分內容指定編譯條件,這就是條件編譯。 條件編譯命令有以下幾種形式:條件編譯命令有以下幾種形式: (1)ifdef 標識符標識符 程序段程序段1 else 程序段程序段2 endif 它的功能是它的功能是:當所指定的標識符被當所指定的標識符被#define命令命令定義過,程定義過,程序在編譯時只編譯程序段序在編譯時只編譯程序段1;否則,只編譯程序段;否則,只編譯程序段2,或不,或不編譯。編譯。6.5 編譯預處理 (2)ifndef 標識符標識符 程序段程序段1 else 程序段程序段2 endif 它的功能是當所指定的標識符沒有被它的功能是當所指定的標識符沒有被 #define命令定義過,命令
49、定義過,則在程序編譯時只編譯程序段則在程序編譯時只編譯程序段1;否則編譯程序段;否則編譯程序段2,或不,或不編譯。這種形式與第一種形式的功能正好相反。編譯。這種形式與第一種形式的功能正好相反。 (3)if 表達式表達式 程序段程序段1 else 程序段程序段2 endif 它的功能是當指定的表達式的值為真(非零)時,程序在它的功能是當指定的表達式的值為真(非零)時,程序在編譯時只編譯程序段編譯時只編譯程序段1;否則編譯程序段;否則編譯程序段2,或不編譯。,或不編譯。 6.6函數應用舉例 【例例6-14】由鍵盤任意輸入兩個整數,求這兩個整數的最由鍵盤任意輸入兩個整數,求這兩個整數的最大公約數和最
50、小公倍數。大公約數和最小公倍數。 分析:設兩個整數用變量分析:設兩個整數用變量m、n表示,最大公約數用表示,最大公約數用“輾輾轉相除法轉相除法”求解,其思路是:首先用兩個數中的大數求解,其思路是:首先用兩個數中的大數m除除以小數以小數n,得到一個余數,得到一個余數r,若,若r的值為的值為0,則此時的除數,則此時的除數n就是最大公約數;若就是最大公約數;若r的值不為的值不為0,則把除數作為被除數,則把除數作為被除數,余數作為除數,再相除,直到余數為余數作為除數,再相除,直到余數為0為止。從數學知識為止。從數學知識可知道,任何兩個整數的最小公倍數等于這兩個數之積再可知道,任何兩個整數的最小公倍數等
51、于這兩個數之積再除以這兩個數的最大公約數。即最小公倍數除以這兩個數的最大公約數。即最小公倍數=m*n/最大公最大公約數。定義一個函數約數。定義一個函數maxdivisor來實現最大公約數。來實現最大公約數。6.6函數應用舉例 #include main( ) int maxdivisor(int m,int n); /* 函數的聲明函數的聲明*/ int a,b,divisor,multiple; printf(input two integer numbers:); scanf(%d%d,&a,&b);divisor= maxdivisor(a,b); /* 調用函數,求最大公約數調用函數,求最大公約數*/ multiple=a*b/divisor; /*求最小公倍數求最小公倍數 */ printf(The largest common divisor:%dn,divisor);printf(The small common multiple:%dn,multiple); 6.6函數應用舉例int maxdivisor(int m,int n)/* 定義求出最大公約定義求出最大公
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 腦血管意外觀察及護理
- 新疆鐵道職業技術學院《車輛工程專業課程》2023-2024學年第二學期期末試卷
- 石棉縣2025屆數學四年級第二學期期末綜合測試模擬試題含解析
- 遼寧特殊教育師范高等專科學校《學科科技英語寫作:安全》2023-2024學年第二學期期末試卷
- 天津城市職業學院《相對論與量子力學》2023-2024學年第一學期期末試卷
- 山東特殊教育職業學院《中醫內科學理論》2023-2024學年第一學期期末試卷
- 遼寧城市建設職業技術學院《藝術衍生品策劃與創意(文創方向)》2023-2024學年第二學期期末試卷
- 鄭州財經學院《中藥商品學》2023-2024學年第一學期期末試卷
- 吉林省白城市洮南市2024-2025學年三下數學期末教學質量檢測試題含解析
- 天津輕工職業技術學院《合唱指揮1》2023-2024學年第二學期期末試卷
- 第九屆全國大學生測井技能大賽備賽試題庫-下(判斷題)
- 2025屆江蘇省南京市六區初三第二學期期中考試英語試題試卷含答案
- icu手冊第一部分-常見病診療規范
- 《住宅室內防水工程技術規范JGJ298-2013》
- 腫瘤專科護士考試題附有答案
- 酒店工程部培訓課件
- 省級一網統管網格化社會治理指揮手冊(含事項清單)
- 知道智慧網課《科技倫理》章節測試答案
- 工程居間合同范本電子版
- 中醫超聲霧化療法臨床應用標準
- 8.4 AutoCAD拼畫滑動軸承裝配圖
評論
0/150
提交評論