版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、大連理工大學出版社C語言程序設(shè)計案例教程項目五 使用函數(shù)調(diào)用各功能模塊教學目的:通過本章的學習,要求能熟練掌握函數(shù)的定義和調(diào)用方法,掌握函數(shù)的嵌套調(diào)用和遞歸調(diào)用,理解變量的作用域和存儲類別,掌握內(nèi)部函數(shù)和外部函數(shù),并能夠在不同情況下靈活選擇函數(shù)來解決實際問題。掌握編譯預(yù)處理命令的使用方法。函數(shù)和預(yù)處理命令是編寫模塊化程序的重要方法,這將為編寫比較復(fù)雜的程序設(shè)計的學習打下基礎(chǔ)。教學內(nèi)容 項目五 使用函數(shù)調(diào)用各功能模塊函數(shù)編譯預(yù)處理函數(shù)的定義函數(shù)調(diào)用變量的作用域和存儲類別內(nèi)部函數(shù)和外部函數(shù)文件包含命令宏定義條件編譯項目五 使用函數(shù)調(diào)用各功能模塊重點:()函數(shù)的定義和函數(shù)調(diào)用(2)函數(shù)的參數(shù)傳遞難點
2、 : 、函數(shù)的參數(shù)傳遞、遞歸調(diào)用、變量的作用域和存儲特性重點和難點任務(wù)使用函數(shù)統(tǒng)計課程分數(shù)信息1)問題情景與實現(xiàn)輔導員張老師在使用小王設(shè)計的程序時,發(fā)現(xiàn)他分別要對每門課程學生成績的總分及平均分進行計算,如果這樣的計算過程需要重復(fù)使用或者在其他場合中多次使用,使用以前的方法將使得程序代碼重復(fù)書寫,在本任務(wù)中我們使用函數(shù)來統(tǒng)計課程分數(shù)信息,可以減少編程工作量,完善了原來的程序,幫助張老師解決了該問題。任務(wù)使用函數(shù)統(tǒng)計課程分數(shù)信息/* 功能:使用函數(shù)統(tǒng)計課程分數(shù)信息*/#include #define MAX 1000#define M 100float sumM,aveM;int i,j;int
3、count;int course;float aMAXM;void input()printf(請輸入課程的門數(shù):);scanf(%d,&course); printf(請輸入學生總?cè)藬?shù):);scanf(%d,&count);printf(“請輸入每個學生的課程成績:”);任務(wù)使用函數(shù)統(tǒng)計課程分數(shù)信息for(i=0;icount;i+) for(j=0;jcourse;j+) scanf(%f,&aij);void sum_ave(int s,int r)for(i=0;ir;i+) sumi=0.0; for(j=0;js;j+) 任務(wù)使用函數(shù)統(tǒng)計課程分數(shù)信息 sumi=sumi+aji;
4、avei=sumi/s;void output()for(i=0;i0) return(1); if(x=0) return(0); if(x b) c=1;else if(a=b) c=0;else c=-1;return c;編譯、連接、和運行程序。程序運行后,屏幕顯示:5.4 函數(shù)調(diào)用 5.4.1 函數(shù)調(diào)用的一般形式如果按自左向右順序求實參的值,則函數(shù)調(diào)用相當于compare(2,3),程序運行的結(jié)果應(yīng)為”-1”。若按自右向左順序求實參的值,則相當于compare(3,3),程序運行結(jié)果為”0”。如果不清楚自己所用的編譯器對實參的求值順序,用上述代碼上機一試就清楚了。注意:由于不同的編譯
5、器對實參的求值順序不一樣,為了使程序的通用性不受影響以及避免大家對同一段代碼產(chǎn)生不同的理解,應(yīng)盡量避免使用這種容易混淆的用法。5.4 函數(shù)調(diào)用函數(shù)出現(xiàn)在一個表達式中,這種表達式稱為函數(shù)表達式。這時要求函數(shù)帶回一個確定的值以參加表達式的運算。例如:s=sum(a,b)+sum(x,y);5.4.2 函數(shù)調(diào)用的方式1.函數(shù)語句按函數(shù)在程序中出現(xiàn)的位置來分,可以有一下三種函數(shù)調(diào)用的方式。把函數(shù)調(diào)用作為一個語句。如例5.1中的printstart();這時不要求函數(shù)帶返回值,只要求函數(shù)完成一些操作。2.函數(shù)表達式5.4 函數(shù)調(diào)用 5.4.2 函數(shù)調(diào)用的方式 函數(shù)調(diào)用作為一個函數(shù)的參數(shù),例如:s=sum
6、(a,sum(b,c);其中,sum(b,c)是一次函數(shù)調(diào)用,它的值作為sum另一次調(diào)用的參數(shù)。s的值為a,b,c三數(shù)的總和。其實,函數(shù)調(diào)用作為函數(shù)的參數(shù),也是函數(shù)表達式調(diào)用的一種形式,因為函數(shù)參數(shù)本身就是一個表達式的形式。3.函數(shù)參數(shù)函數(shù)sum是表達式的一部分,將sum(a,b)的值加上sum(x,y)的和賦值給s。5.4 函數(shù)調(diào)用如果一個函數(shù)要調(diào)用另外一個函數(shù),首先是被調(diào)用的函數(shù)必須存在。其次還應(yīng)在主調(diào)函數(shù)中對所有被調(diào)函數(shù)加以說明,否則,在連接時會出現(xiàn)找不到所調(diào)用函數(shù)的錯誤信息。同變量一樣,函數(shù)的調(diào)用也應(yīng)遵循“先定義后使用”的原則。 對被調(diào)函數(shù)的聲明分為兩種情況:(1)如果被調(diào)函數(shù)是C語言
7、系統(tǒng)提供的標準庫函數(shù),則在源程序文件的開頭處,使用#include命令,將存放所調(diào)用庫函數(shù)的有關(guān)“頭文件”包含到該程序文件中來。 5.4.3 對被調(diào)用函數(shù)的聲明和函數(shù)原型5.4 函數(shù)調(diào)用 5.4.3 對被調(diào)用函數(shù)的聲明和函數(shù)原型#include命令的一般形式為: #include或#include stdio.h(2)如果被調(diào)用函數(shù)為用戶自己定義的函數(shù),一般情況下,應(yīng)在主調(diào)函數(shù)中對被調(diào)用函數(shù)(返回值)的類型進行說明。函數(shù)的說明方法是:在主調(diào)函數(shù)的聲明部分對被調(diào)函數(shù)進行聲明。在主調(diào)函數(shù)中對被調(diào)函數(shù)作說明的目的是使編譯系統(tǒng)知道被調(diào)函數(shù)返回值的類型,以便在主調(diào)函數(shù)中按此種類型對返回值作相應(yīng)的處理。5
8、.4 函數(shù)調(diào)用 5.4.3 對被調(diào)用函數(shù)的聲明和函數(shù)原型其一般形式為:類型說明符 被調(diào)函數(shù)名(類型 形參,類型 形參); 或者:類型說明符 被調(diào)函數(shù)名(類型,類型); 括號內(nèi)給出了形參的類型和形參名,或只給出形參類型。這便于編譯系統(tǒng)進行檢錯,以防止可能出現(xiàn)的錯誤。5.4 函數(shù)調(diào)用 5.4.3 對被調(diào)用函數(shù)的聲明和函數(shù)原型例5.1 main函數(shù)對printstart()函數(shù)的說明為:void printstart();例5.2 main函數(shù)對sum()函數(shù)的說明為:int sum(int x,int y);也可以寫成:int sum(int ,int);5.4 函數(shù)調(diào)用 5.4.3 對被調(diào)用函數(shù)
9、的聲明和函數(shù)原型語言中規(guī)定在以下幾種情況時可以省去在主調(diào)函數(shù)中對被調(diào)函數(shù)的函數(shù)說明。1) 當被調(diào)函數(shù)的返回值是整型或字符型時,可以不對被調(diào)函數(shù)作說明。這時系統(tǒng)會自動對被調(diào)函數(shù)返回值按整型處理。例5.3的主函數(shù)中把函數(shù)聲明語句int compare(int a,int b);注釋掉而直接調(diào)用就屬于這種情況。5.4 函數(shù)調(diào)用 5.4.3 對被調(diào)用函數(shù)的聲明和函數(shù)原型2) 當被調(diào)函數(shù)的函數(shù)定義出現(xiàn)在主調(diào)函數(shù)之前時,在主調(diào)函數(shù)中也可以不對被調(diào)函數(shù)再作說明而直接調(diào)用。例如例5.1中,函數(shù)printstart()的定義放在 menu() 函數(shù)之前,因此可在 menu()函數(shù)中省去對printstart()
10、函數(shù)的函數(shù)說明void printstart();3) 如在所有函數(shù)定義之前,在函數(shù)外預(yù)先說明了各個函數(shù)的類型,則在以后的各主調(diào)函數(shù)中,可以不再對被調(diào)函數(shù)作說明。例如: long factor (int a); long sum(int b);5.4 函數(shù)調(diào)用 5.4.3 對被調(diào)用函數(shù)的聲明和函數(shù)原型void main() long factor (int a) long sum(int b) 其中第一、二行對factor函數(shù)和sum函數(shù)預(yù)先作了說明。因此在以后各函數(shù)中無須對factor和sum函數(shù)再作說明就可直接調(diào)用。5.5 函數(shù)的嵌套調(diào)用和遞歸調(diào)用 【例5.4】計算 = 1!+2!+ +
11、n!(n1,20的整數(shù),從鍵盤輸入)。算法設(shè)計要點:本案例可以設(shè)計2個函數(shù):factor( )用于求n??;sum( )通過調(diào)用factor( )來實現(xiàn)求。5.5.1 函數(shù)的嵌套調(diào)用實例 /*源文件名:Li5_4.c 功能:求階乘和 */ #include stdio.h long factor(int n)/*定義求階乘函數(shù)factor()*/ int i;long f=1;for(i=1;i=n;i+)f=f*i;return f; 5.5 函數(shù)的嵌套調(diào)用和遞歸調(diào)用 5.5.1 函數(shù)的嵌套調(diào)用實例long sum(int m)/*定義求和函數(shù)sum()*/int i;long s=0;for
12、(i=1;i1)f=n*factor(n-1);else f=1;return f;void main()int n;long s;printf(please input a number:);scanf(%d,&n);s=factor(n);/*調(diào)用factor()函數(shù)*/printf(%d!=%ldn,n,s);5.5 函數(shù)的嵌套調(diào)用和遞歸調(diào)用其中,factor函數(shù)在定義的過程中調(diào)用了本身,這種情況叫做函數(shù)的遞歸調(diào)用。5.5.3 函數(shù)的遞歸調(diào)用實例編譯、連接、和運行程序。程序運行后,屏幕顯示:5.5 函數(shù)的嵌套調(diào)用和遞歸調(diào)用一個函數(shù)在它的函數(shù)體內(nèi)調(diào)用它自身稱為遞歸調(diào)用。這種函數(shù)稱為遞歸函數(shù)
13、。語言允許函數(shù)的遞歸調(diào)用。在遞歸調(diào)用中,主調(diào)函數(shù)又是被調(diào)函數(shù)。執(zhí)行遞歸函數(shù)將反復(fù)調(diào)用其自身,每調(diào)用一次就進入新的一層。下面以例5.5說明一下遞歸的執(zhí)行過程。設(shè)執(zhí)行本程序時輸入為5,即求5!。在主函數(shù)中的調(diào)用語句即為s=factor(5);,進入factor函數(shù)后,由于n=5,大于1,故應(yīng)執(zhí)行f=n*factor(n*1),即f=factor(5-1)*5。該語句對factor函數(shù)作遞歸調(diào)用即factor(4)。5.5.4 函數(shù)的遞歸調(diào)用說明進行四次遞歸調(diào)用后,factor函數(shù)形參取得的值變?yōu)?,故不再繼續(xù)遞歸調(diào)用而開始逐層返回主調(diào)函數(shù)。factor(1)的函數(shù)返回值為1,factor(2)的返
14、回值為2*1=2,factor(3)的返回值為3*2=6,factor(4)的返回值為4*6=24,最后返回值factor(5)為5*24=120。注意:為了防止遞歸調(diào)用無終止地進行,必須在函數(shù)內(nèi)有終止遞歸調(diào)用的手段。常用的方法是加條件對遞歸是否繼續(xù)進行判斷,滿足某種條件后就不再作遞歸調(diào)用,而是逐層返回。如例5.5中的條件if(n1)就是控制遞歸繼續(xù)的條件,當n不小于1的時候遞歸就終止,開始回朔的過程。5.5 函數(shù)的嵌套調(diào)用和遞歸調(diào)用 5.5.4 函數(shù)的遞歸調(diào)用說明5.6 內(nèi)部函數(shù)和外部函數(shù)一個函數(shù)如果只能被本文件中其它函數(shù)所調(diào)用,稱為內(nèi)部函數(shù),內(nèi)部函數(shù)又稱靜態(tài)函數(shù)。在定義內(nèi)部函數(shù)時在函數(shù)名和
15、函數(shù)類型前面加static。即:static 函數(shù)類型 函數(shù)名(形參列表)函數(shù)體5.6.1 內(nèi)部函數(shù)5.5 內(nèi)部函數(shù)和外部函數(shù) 5.1 內(nèi)部函數(shù)例:static int fun(int a,int b)特點:只能被本文件中的函數(shù)所調(diào)用。優(yōu)點:不用擔心與其它源文件中的函數(shù)同名,因為即使同名也沒關(guān)系。一個函數(shù)可以被其它文件中其它函數(shù)所調(diào)用,就稱為外部函數(shù)。在定義函數(shù)時可冠以關(guān)鍵字extern(省略也可),表示此函數(shù)是外部函數(shù)。即:extern 函數(shù)類型 函數(shù)名(形參列表)函數(shù)體如:extern int fun(int a,int b)5.5 內(nèi)部函數(shù)和外部函數(shù)5.6.2 外部函數(shù)5.6 內(nèi)部函數(shù)和
16、外部函數(shù) 5.6.2 外部函數(shù)特點:允許被所有源文件中的函數(shù)所調(diào)用。注意:調(diào)用其它源文件中的外部函數(shù)時,需要對其進行說明?!纠?.6】以多文件的形式實現(xiàn)加、減、乘、除和求余數(shù)運算程序說明:將實現(xiàn)加、減、乘、除和求余數(shù)運算的程序段分別作為1個獨立的函數(shù)、存儲在1個獨立的源文件中。5.6 內(nèi)部函數(shù)和外部函數(shù) 5.6.2 外部函數(shù)程序框架如下(完整程序詳見【例5.6】源代碼):分別創(chuàng)建addition.c源文件、subtraction.c源文件、multiplication.c源文件、division.c源文件、remainder.c源文件,分別在各源文件中實現(xiàn)相應(yīng)的加、減、乘、除和求余數(shù)函數(shù)的功能
17、。編譯、連接、和運行程序。程序運行后,屏幕顯示:5.6 內(nèi)部函數(shù)和外部函數(shù) 5.6.2 外部函數(shù)5.6 內(nèi)部函數(shù)和外部函數(shù)在軟件工程項目中,采用結(jié)構(gòu)化方法進行程序設(shè)計與編程,通常會產(chǎn)生多個源文件(例如源程序文件、數(shù)據(jù)結(jié)構(gòu)定義文件等)。那么,如何將這些源文件編譯、連接成一個統(tǒng)一的可執(zhí)行文件呢?5.6.3 多個源文件的編譯與連接5.6 內(nèi)部函數(shù)和外部函數(shù) 5.6.3 多個源文件的編譯與連接一般有兩種方法:1. 分別編譯、一并連接C編譯程序是以源文件為編譯單位。當一個程序中的函數(shù)和數(shù)據(jù)結(jié)構(gòu)分放在多個源文件中時,先將各文件分別編譯,再通過link命令產(chǎn)生一個可執(zhí)行文件(.exe) 。 2. 集中編譯、
18、連接利用編譯預(yù)處理命令#include,將其它源文件包含到主函數(shù)main( )所在的源文件的開頭,然后直接編譯該文件即可。 5.6 內(nèi)部函數(shù)和外部函數(shù) 5.6.3 多個源文件的編譯與連接【例5.7】先通過添加源文件的操作將addition.c源文件,subtraction.c源文件,multiplication.c源文件,division.c源文件,remainder.c源文件添加到本工程(加減乘除求余)來,然后在其主函數(shù)main()里添加如下幾行:/* 源文件名:Li5_7.c 功能:以多文件的形式實現(xiàn)加、減、乘、除和求余數(shù)運算*/*將其它各源文件包含進來*/#include additio
19、n.c#include subtraction.c#include multiplication.c#include division.c#include remainder.c void main( ) 5.7變量的作用域 局部變量也稱為內(nèi)部變量。局部變量是在函數(shù)內(nèi)(包括函數(shù)說明和函數(shù)體)作定義說明的,其作用域僅限于函數(shù)內(nèi), 離開該函數(shù)后再使用這種變量是非法的。5.7.1 局部變量 【例5.8】局部變量的作用域 /* 源文件名:Li5_8.c 功能:測試局部變量的作用域 */#include stdio.hvoid test(int a)int b=20;printf(%dn,a+b);5.
20、7變量的作用域 5.7.1 局部變量void main() int i=2,j=3,k; k=i+j; int k=8; printf(%dn,k); printf(%dn,k);test(k);5.7變量的作用域 5.7.1 局部變量在函數(shù)test內(nèi)定義了三個變量,a為形參,b為一般變量。在 test的范圍內(nèi)a、b有效,或者說a、b變量的作用域限于test內(nèi)。同理,i,j,k的作用域限于main內(nèi)。編譯、連接、和運行程序。程序運行后,屏幕顯示:5.7變量的作用域 5.7.1 局部變量關(guān)于局部變量的作用域還要說明以下幾點:(1) 主函數(shù)中定義的變量只能在主函數(shù)中使用,不能在其它函數(shù)中使用。同時
21、,主函數(shù)中也不能使用其它函數(shù)中定義的變量。因為主函數(shù)也是一個函數(shù),它與其它函數(shù)是平行關(guān)系。這一點是與其它語言不同的,應(yīng)予以注意。(2) 形參變量是屬于被調(diào)函數(shù)的局部變量,實參變量是屬于主調(diào)函數(shù)的局部變量。(3) 允許在不同的函數(shù)中使用相同的變量名,它們代表不同的對象,分配不同的單元,互不干擾,也不會發(fā)生混淆。(4) 在復(fù)合語句中也可定義變量,其作用域只在復(fù)合語句范圍內(nèi)。6.7變量的作用域全局變量也稱為外部變量,它是在函數(shù)外部定義的變量。它不屬于哪一個函數(shù),它屬于整個源程序文件。其作用域是整個源程序。在函數(shù)中使用全局變量,一般應(yīng)作全局變量說明。 只有在函數(shù)內(nèi)經(jīng)過說明的全局變量才能使用。全局變量的
22、說明符為extern。但在一個函數(shù)之前定義的全局變量,在該函數(shù)內(nèi)使用可不再加以說明。5.7.2 全局變量5.7變量的作用域 5.7.2 全局變量【例5.9】要求設(shè)計一個函數(shù)cuboid(double length, double width, double height)(3個參數(shù)依次為長方體的長、寬、高),用于求長方體的體積及正、側(cè)、頂三個面的面積。行數(shù)據(jù)共享。 /* 源文件名:Li5_9.c 功能:求長方體的體積及正、側(cè)、頂三個面的面積 */#include stdio.hdouble area1, area2, area3;/*定義3個外部變量,用于數(shù)據(jù)共享*/double cuboid
23、 (double length, double width, double height);/*函數(shù)說明*/5.7變量的作用域 5.7.2 全局變量void main( )double volume,length,width,height; printf(please input the cuboids length、width and height:);scanf(%lf%lf%lf,&length,&width,&height);volume = cuboid (length, width, height);printf(“n volume = %.2lf, area1 = %.2lf,
24、area2 = %.2lf, area3 = %.2lfn , volume, area1, area2, area3);double cuboid (double length, double width, double height)double volume;volume = length * width * height;/*計算體積*/area1= length * width; /*計算3個面的面積*/5.7變量的作用域 5.7.2 全局變量area2= width * height; area3= length * height;return( volume);/*返回體積值*/
25、編譯、連接、和運行程序。程序運行后,屏幕顯示:5.7變量的作用域 5.7.2 全局變量注意:(1)外部變量的作用域:從定義點到本文件結(jié)束。為方便使用,建議將外部變量的定義放在文件開頭,如例.9所示。(2)在同一源文件中,允許外部變量和內(nèi)部變量同名。在內(nèi)部變量的作用域內(nèi),外部變量不起作用。(3)外部變量可實現(xiàn)函數(shù)之間的數(shù)據(jù)共享,但又使這些函數(shù)依賴這些外部變量,因而使得這些函數(shù)的獨立性降低。從模塊化程序設(shè)計觀點來看,這是不利的。因此不是非用不可時,不要使用外部變量。5.8 變量的存儲類別 語言中的變量,不僅有類型特性,還有存儲特性,從變量值存在的時間(即生存期)角度來分,可以分為靜態(tài)存儲方式和動態(tài)
26、存儲方式。1動態(tài)存儲方式:是在程序運行期間根據(jù)需要進行動態(tài)的分配存儲空間的方式。自動內(nèi)部變量(auto)、寄存器變量(register)5.8.1 動態(tài)存儲和靜態(tài)存儲5.8 變量的存儲類別 5.8.1 動態(tài)存儲和靜態(tài)存儲2靜態(tài)存儲方式:是指在程序運行期間分配固定的存儲空間的方式。靜態(tài)內(nèi)部變量(static)、外部變量(extern) 。用戶存儲空間可以分為三個部分:(1) 程序區(qū);(2) 靜態(tài)存儲區(qū);(3) 動態(tài)存儲區(qū);5.8 變量的存儲類別 5.8.1 動態(tài)存儲和靜態(tài)存儲全局變量全部存放在靜態(tài)存儲區(qū),在程序開始執(zhí)行時給全局變量分配存儲區(qū),程序運行結(jié)束就釋放。在程序執(zhí)行過程中它們占據(jù)固定的存儲
27、單元,而不動態(tài)地進行分配和釋放;動態(tài)存儲區(qū)存放以下數(shù)據(jù):1) 函數(shù)形式參數(shù);2)自動變量(未加static聲明的局部變量);3) 函數(shù)調(diào)用時的現(xiàn)場保護和返回地址;對以上這些數(shù)據(jù),在函數(shù)開始調(diào)用時分配動態(tài)存儲空間,函數(shù)結(jié)束時釋放這些空間。5.8 變量的存儲類別5.8.2 動態(tài)存儲 【例5.10】動態(tài)存儲舉例 /* 源文件名:Li5_10.c 功能:測試動態(tài)存儲變量的空間分配情況 */#include stdio.hvoid test()int m=10;m+;printf(m=%dn,m);5.8 變量的存儲類別 5.8.2 動態(tài)存儲void main()printf(the first tim
28、e :);test();printf(the second time :);test();printf(the third time :);test();5.8 變量的存儲類別 5.8.2 動態(tài)存儲編譯、連接、和運行程序。程序運行后,屏幕顯示:5.8 變量的存儲類別 5.8.2 動態(tài)存儲函數(shù)中的局部變量,如不特別聲明為static存儲類別,都是動態(tài)地分配存儲空間的,數(shù)據(jù)存儲在動態(tài)存儲區(qū)中。函數(shù)中的形參和在函數(shù)中定義的變量(包括在復(fù)合語句中定義的變量)都屬此類,在調(diào)用該函數(shù)時系統(tǒng)會給它們分配存儲空間,在函數(shù)調(diào)用結(jié)束時就自動釋放這些存儲空間。這類局部變量稱為自動變量。自動變量用關(guān)鍵字auto(au
29、to可以省略)作存儲類別的聲明。5.8 變量的存儲類別 5.8.2 動態(tài)存儲如例5.10中,test函數(shù)中的m沒有用static聲明,說明它就是一個自動變量,所以,在主函數(shù)中調(diào)用了三次的test函數(shù),每次得到的m的輸出值都是一樣的,這是因為自動變量只有在函數(shù)被調(diào)用的時候分配空間,當函數(shù)調(diào)用結(jié)束,空間也就自動釋放了,所以每次調(diào)用m都是被重新賦初始值10。5.8 變量的存儲類別5.8.3 用static聲明的局部變量 【例5.11】靜態(tài)局部變量例題 /*源文件名:Li5_11.c功能:測試靜態(tài)局部變量的空間分配情況 */#include stdio.hvoid test()static int m
30、=10; /定義m為靜態(tài)局部變量m+;printf(m=%dn,m);5.8 變量的存儲類別 5.8.3 用static聲明的局部變量void main()printf(the first time :);test();printf(the second time :);test();printf(the third time :);test();5.8 變量的存儲類別 5.8.3 用static聲明的局部變量有時希望函數(shù)中的局部變量的值在函數(shù)調(diào)用結(jié)束后不消失而保留原值,這時就應(yīng)該指定局部變量為“靜態(tài)局部變量”,用關(guān)鍵字static進行聲明。如例6.11中test函數(shù)中的m變量被用static
31、聲明位靜態(tài)局部變量。由于靜態(tài)變量在程序運行期間的被分配的存儲空間是固定的。所以第一次調(diào)用test函數(shù)的時候,m變量空間被分配,并且賦予初值10,然后執(zhí)行m+操作,所以m的值就為11.但調(diào)用結(jié)束的時候m的空間仍然存在,沒有因函數(shù)調(diào)用結(jié)束而被釋放。所以在test函數(shù)第二次被調(diào)用的時候,m不再重新分配空間和初始化為10,而是使用原來的空間,沿用上一次的值11,故第二次調(diào)用的時候輸出的m值為12,第三次為13。5.8 變量的存儲類別 5.8.3 用static聲明的局部變量對靜態(tài)局部變量的說明:(1)靜態(tài)局部變量屬于靜態(tài)存儲類別,在靜態(tài)存儲區(qū)內(nèi)分配存儲單元。在程序整個運行期間都不釋放。而自動變量(即動
32、態(tài)局部變量)屬于動態(tài)存儲類別,占動態(tài)存儲空間,函數(shù)調(diào)用結(jié)束后即釋放。(2)靜態(tài)局部變量在編譯時賦初值,即只賦初值一次;而對自動變量賦初值是在函數(shù)調(diào)用時進行,每調(diào)用一次函數(shù)重新給一次初值,相當于執(zhí)行一次賦值語句。(3)如果在定義局部變量時不賦初值的話,則對靜態(tài)局部變量來說,編譯時自動賦初值0(對數(shù)值型變量)或空字符(對字符變量)。而對自動變量來說,如果不賦初值則它的值是一個不確定的值。5.8 變量的存儲類別為了提高效率,C語言允許將局部變量的值放在CPU的寄存器中,這種變量叫“寄存器變量”,用關(guān)鍵字register作聲明。5.8.4 register變量 /* 源文件名:Li5_12.c 功能:
33、測試寄存器存儲變量的空間分配情況*/#include stdio.hint factor(int n)register int i,f=1; for(i=1;i=n;i+)f=f*i; return f;5.8 變量的存儲類別 5.8.4 register變量void main()int i; for(i=0;i=5;i+) printf(%d!=%dn,i,factor(i);5.8 變量的存儲類別 5.8.4 register變量編譯、連接、和運行程序。程序運行后,屏幕顯示:5.8 變量的存儲類別 5.8.4 register變量注意: (1)只有局部動態(tài)變量和形式參數(shù)可以作為寄存器變量;
34、 (2)一個計算機系統(tǒng)中的寄存器數(shù)目有限,不能定義任意多個寄存器變量; (3)局部靜態(tài)變量不能定義為寄存器變量; (4)register型變量不能為long, double, float型。5.8 變量的存儲類別前面介紹過,在函數(shù)外部定義的變量稱為外部變量。如果一個程序由多個源文件構(gòu)成,根據(jù)某個源文件中定義的外部變量能否被其它源文件中的函數(shù)所引用,將外部變量分為兩個作用域級別:(1)文件級外部變量只允許被本源文件中的函數(shù)引用,其定義方式如下:static 數(shù)據(jù)類型 外部變量表;(2)程序級外部變量允許被程序中各源文件內(nèi)的函數(shù)引用,其定義方式如下: extern 數(shù)據(jù)類型 外部變量表;5.8.5
35、 文件級外部變量和程序級外部變量5.8 變量的存儲類別 5.8.5 文件級外部變量和程序級外部變同一程序中的其它源文件內(nèi)的函數(shù)如果想引用程序級外部變量時,需要對其進行說明。有效范圍:從定義變量的位置開始到本源文件結(jié)束,及有extern說明的其它源文件。注意:(1)extern不是變量定義,但可擴展外部變量作用域。(2)若外部變量與局部變量同名,則外部變量被屏蔽。5.8 變量的存儲類別 5.8.5 文件級外部變量和程序級外部變下面用圖表對變量的存儲類型進行一個系統(tǒng)的歸納:5.9 編譯預(yù)處理在前面各章中,已多次使用過以“#”開頭的預(yù)處理命令。如包含命令#include,宏定義命令#define等。
36、在源程序中這些命令都放在函數(shù)之外,而且一般都放在源文件的前面,它們稱為編譯預(yù)處理部分。所謂編譯預(yù)處理是指在進行編譯的第一遍掃描(詞法掃描和語法分析)之前所作的工作。預(yù)處理是語言的一個重要功能,它由預(yù)處理程序負責完成。當對一個源文件進行編譯時,系統(tǒng)將自動引用預(yù)處理程序?qū)υ闯绦蛑械念A(yù)處理部分作處理,處理完畢自動進入對源程序的編譯。語言提供了多種預(yù)處理功能,如宏定義、文件包含、條件編譯等。合理地使用預(yù)處理功能編寫的程序便于閱讀、修改、移植和調(diào)試,也有利于模塊化程序設(shè)計。本節(jié)主要介紹常用的幾種預(yù)處理功能。.8 變量的存儲類別文件包含由#include 命令來說明,編譯預(yù)處理時,系統(tǒng)將包含文件的內(nèi)容插入
37、到程序中引用它的地方,即程序中相應(yīng)的#include命令所在處.文件包含是指一個源文件可以將另一個源文件的全部內(nèi)容包含進來.有兩種形式:#include 和#include ”文件名”。1) 每行寫一句,只能寫一個文件名,結(jié)尾不加分號;。被包含的文件必須是源文件而不能是目標文件。 2) 一個include命令只能指定一個被包含文件,若有多個文件要包含,則需用多個include命令。5.9.1 #include命令5.9 編譯預(yù)處理 5.9.1 #include 命令3) 文件包含可以嵌套。 即一個被包含文件中,可以包含另一個被包含文件。4) 在#include命令中,文件名可以用尖括號或雙引號
38、括起來,二者都是合法的。其區(qū)別是用尖括號時,系統(tǒng)到存放C庫函數(shù)頭文件所在的目錄中去尋找要包含的文件。用雙引號時,系統(tǒng)先在用戶當前目錄中尋找要包含的文件,若找不到,再按標準方式查找。在程序設(shè)計中,文件包含是很有用的。一個大的程序可以分為多個模塊,由多個程序員分別編程。有些公用的符號常量或宏定義等可單獨組成一個文件,在其它文件的開頭用包含命令包含該文件即可使用。這樣可避免在每個文件開頭都去書寫那些公用量,從而節(jié)省時間,并減少出錯。在語言源程序中允許用一個標識符來表示一個字符串,稱為”宏”。被定義為“宏”的標識符稱為”宏名”。在編譯預(yù)處理時,對程序中所有出現(xiàn)的”宏名”,都用宏定義中的字符串去代換,這
39、稱為”宏代換”或”宏展開”。宏定義是由源程序中的宏定義命令完成的,宏代換是由預(yù)處理程序自動完成的。在語言中,”宏”分為有參數(shù)和無參數(shù)的兩種。下面分別討論這兩種“宏”的定義和調(diào)用。5.9.2 宏定義5.9 編譯預(yù)處理5.9 編譯預(yù)處理 5.9.2 宏定義1無參宏定義無參宏的宏名后不帶參數(shù)。其定義的一般形式為:#define 標識符 字符串其中的”#”表示這是一條預(yù)處理命令,凡是以”#”開頭的均為預(yù)處理命令,”define”為宏定義命令,”標識符”為所定義的宏名,”字符串”可以是常數(shù)、表達式、格式串等。5.9 編譯預(yù)處理 5.9.2 宏定義【例6.13】不帶參數(shù)的宏的使用舉例/*源文件名:Li6_
40、13.c功能:利用無參宏求圓的周長和面積*/#include stdio.h#define PI 3.1415926void main( )double r, circle, area;printf(nPlease input radius: );scanf(%lf,&r);circle = 2 * PI * r;area = PI * r * r;printf(ncircle=%lf,area=%lfn,circle, area);5.9 編譯預(yù)處理 5.9.2 宏定義編譯、連接、運行程序。程序運行后,屏幕顯示:5.9 編譯預(yù)處理 5.9.2 宏定義使用中應(yīng)注意下面幾點:(1) 習慣上宏名一
41、般用大寫字母表示;(2) 宏定義不是C語句,書寫時行末不應(yīng)加分號;(3) 在進行宏定義時,可以引用已定義的宏名;(4) 當宏體是表達式時,為穩(wěn)妥起見常將它用括弧括起來; (5) 宏名在源程序中若用引號括起來,則預(yù)處理程序不對其作宏代換。5.9 編譯預(yù)處理 5.9.2 宏定義上例中定義宏名OK表示100,但在printf語句中OK被引號括起來,因此不作宏代換。程序的運行結(jié)果為:OK 而不是100.這表示把”O(jiān)K”當字符串處理。#include ”stdio.h”#define OK 100void main() printf(OK); printf(n);5.9 編譯預(yù)處理 5.9.2 宏定義(
42、6) 若宏名字出現(xiàn)在標識符內(nèi),則預(yù)處理時它也不被替換。(7) 同一個宏名可以重復(fù)定義,如果不一致,編譯時會發(fā)出警告,并以最后一次定義為準。(8) 當宏定義在一行中寫不下時,可在行尾用反斜杠“”進行續(xù)行。(9) 宏定義通常放在源程序文件的開頭,其作用域是整個源程序.也可以在函數(shù)內(nèi)部作宏定義,這時宏名字的作用域只在本函數(shù).可用#undef終止宏定義的作用域。5.9 編譯預(yù)處理 5.9.2 宏定義(10) 與變量定義不同,宏定義只作字符替換,不分配內(nèi)存空間,也不做正確性檢查。(11) 宏定義時可以不包含宏體,即寫成:#define 宏名這種寫法也是合法的,此時僅說明宏名已被定義。5.9 編譯預(yù)處理
43、5.9.2 宏定義2帶參宏定義語言允許宏帶有參數(shù)。在宏定義中的參數(shù)稱為形式參數(shù),在宏調(diào)用中的參數(shù)稱為實際參數(shù)。對帶參數(shù)的宏,在調(diào)用中,不僅要宏展開,而且要用實參去代換形參。帶參宏定義的一般形式為:#define 宏名(形參表) 字符串 在字符串中含有各個形參。帶參宏調(diào)用的一般形式為:宏名(實參表);5.9 編譯預(yù)處理 5.9.2 宏定義 【例5.14】帶參數(shù)的宏的使用舉例 /* 源文件名:Li6_14.c 功能:利用有參宏求兩個數(shù)中的最大值 */#include stdio.h#define MAX(a,b) (ab)?a:bvoid main()int x,y,max;printf(inpu
44、t two numbers: );scanf(%d%d,&x,&y);max=MAX(x,y);printf(max=%dn,max); 5.9 編譯預(yù)處理 5.9.2 宏定義例5.14中的的第二行進行帶參宏定義,用宏名MAX表示條件表達式(ab)?a:b,形參a,b均出現(xiàn)在條件表達式中。程序中語句max=MAX(x,y)為宏調(diào)用,實參x,y,將代換形參a,b。宏展開后該語句為:max=(xy)?x:y;用于計算x,y中的大數(shù)。編譯、連接、和運行程序。程序運行后,屏幕顯示:5.9 編譯預(yù)處理 5.9.2 宏定義對于帶參的宏定義有以下問題需要說明:(1)帶參宏定義中,宏名和形參表之間不能有空格出
45、現(xiàn)。例如把#define MAX(a,b) (ab)?a:b寫為:#define MAX (a,b) (ab)?a:b將被認為是無參宏定義,宏名MAX代表字符串 (a,b) (ab)?a:b。宏展開時,宏調(diào)用語句:max=MAX(x,y);將變?yōu)閙ax=(a,b)(ab)?a:b(x,y);這顯然是錯誤的。5.9 編譯預(yù)處理 5.9.2 宏定義(2) 在帶參宏定義中,形式參數(shù)不分配內(nèi)存單元,因此不必作類型定義。而宏調(diào)用中的實參有具體的值。要用它們?nèi)ゴ鷵Q形參,因此必須作類型說明。這是與函數(shù)中的情況不同的。在函數(shù)中,形參和實參是兩個不同的量,各有自己的作用域,調(diào)用時要把實參值賦予形參,進行”值傳遞
46、”。而在帶參宏中,只是符號代換,不存在值傳遞的問題。(3) 在宏定義中的形參是標識符,而宏調(diào)用中的實參可以是表達式。5.9 編譯預(yù)處理 5.9.2 宏定義 【例6.15】用宏來實現(xiàn)平方 /* 源文件名:Li6_15.c 功能:利用有參宏求數(shù)的平方 */#include stdio.h#define TEST(y) (y)*(y) /*用宏來實現(xiàn)平方*/void main()int a,test;printf(input a number: );scanf(%d,&a);test=TEST(a+1);printf(test=%dn,test); 5.9 編譯預(yù)處理 5.9.2 宏定義上例中第二行
47、為宏定義,形參為y。語句test=TEST(a+1);宏調(diào)用中實參為a+1,是一個表達式,在宏展開時,用a+1代換y,再用(y)*(y) 代換TEST,得到如下語句:test=(a+1)*(a+1);這與函數(shù)的調(diào)用是不同的,函數(shù)調(diào)用時要把實參表達式的值求出來再賦予形參。而宏代換中對實參表達式不作計算直接原樣替換。編譯、連接、和運行程序。程序運行后,屏幕顯示:5.9 編譯預(yù)處理 5.9.2 宏定義(4)在宏定義中,字符串內(nèi)的形參通常要用括號括起來以避免出錯。在上例中的宏定義中(y)*(y)表達式的y都用括號括起來,因此結(jié)果是正確的。如果去掉括號,把程序改為以下形式: 【例5.16】在帶參數(shù)宏的定
48、義中不使用括號 /* 源文件名:Li5_16.c 功能:說明有參宏中括號的重要性 */#include stdio.h#define TEST(y) y*yvoid main()int a,test;printf(input a number: );scanf(%d,&a);test=TEST(a+1);printf(test=%dn,test);5.9 編譯預(yù)處理 5.9.2 宏定義同樣輸入3,但結(jié)果卻是不一樣的。問題在哪里呢? 這是由于代換只作符號代換而不作其它處理而造成的。宏代換后將得到以下語句:test=a+1*a+1;由于a為3故test的值為5。這顯然與題意相違,因此參數(shù)兩邊的括號
49、是不能少的。即使在參數(shù)兩邊加括號還是不夠的,請看下面程序:編譯、連接、和運行程序。程序運行后,屏幕顯示:5.9 編譯預(yù)處理 5.9.2 宏定義 【例5.17】在宏定義的參數(shù)兩邊加括號 /* 源文件名:Li6_17.c 功能:說明有參宏中括號的重要性 */#include stdio.h#define TEST(y) (y)*(y) /*用宏來實現(xiàn)平方*/void main()int a,test;printf(input a number: );scanf(%d,&a);test=160/TEST(a+1);printf(test=%dn,test); 5.9 編譯預(yù)處理 5.9.2 宏定義本
50、程序與前例相比,只把宏調(diào)用語句改為:test=160/TEST(a+1);運行本程序如輸入值仍為3時,希望結(jié)果為10。但實際運行的結(jié)果如下:5.9 編譯預(yù)處理 5.9.2 宏定義為什么會得到這樣的結(jié)果呢?分析宏調(diào)用語句,在宏代換之后變?yōu)椋簍est=160/(a+1)*(a+1);a為3時,由于“/”和“*”運算符優(yōu)先級和結(jié)合性相同,則先作160/(3+1)得40,再作40*(3+1)最后得160。5.9 編譯預(yù)處理 5.9.2 宏定義 【例5.18】在宏定義的整個字符串外加括號 /* 源文件名:Li5_18.c 功能:說明有參宏中括號的重要性 */#include stdio.h#define
51、 TEST(y) (y)*(y) /*用宏來實現(xiàn)平方*/void main()int a,test;printf(input a number: );scanf(%d,&a);test=160/TEST(a+1);printf(test=%dn,test); 5.9 編譯預(yù)處理 5.9.2 宏定義以上討論說明,對于宏定義不僅應(yīng)在參數(shù)兩側(cè)加括號,也應(yīng)在整個字符串外加括號。編譯、連接、和運行程序。程序運行后,屏幕顯示:5.9 編譯預(yù)處理 5.9.2 宏定義(5)帶參的宏和帶參函數(shù)很相似,但有本質(zhì)上的不同,除上面已談到的各點外,把同一表達式用函數(shù)處理與用宏處理兩者的結(jié)果有可能是不同的。 【例5.19
52、】用帶參數(shù)的函數(shù)求某個數(shù)的平方 /* 源文件名:Li6_19.c 功能:利用帶參數(shù)的函數(shù)求平方*/#include ”stdio.h”void main() int i=1; while(i=5) printf(%dn,test(i+);5.9 編譯預(yù)處理 5.9.2 宏定義編譯、連接、運行程序。程序運行后,屏幕顯示:test(int y) return(y)*(y);5.9 編譯預(yù)處理 5.9.2 宏定義 【例5.20】帶參數(shù)的宏求平方 /* 源文件名:Li5_20.c 功能:利用帶參數(shù)的宏求平方 */#include ” stdio.h”#define TEST(y) (y)*(y)void main()int i=1;while
溫馨提示
- 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)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 論公共危機中的政府責任
- 高齡婦女孕期管理專家共識
- 2026年重慶三峽學院單招綜合素質(zhì)筆試備考試題帶答案解析
- 某軟件園區(qū)十五五多Agent智能體協(xié)同開發(fā)與自動化運維平臺可行性分析研究報告
- 全城攤主活動策劃方案(3篇)
- 法庫開店活動策劃方案(3篇)
- 2026 年高職應(yīng)用電子技術(shù)教育(電子技術(shù)教育)試題及答案
- 甘肅省蘭州市新區(qū)多校2025-2026學年高一上學期期末學業(yè)水平質(zhì)量測試政治試卷(含解析)
- 2026年房地產(chǎn)檔案管理與客戶關(guān)系維護
- 2026重慶永川法院招聘書記員2人備考題庫附答案
- 公務(wù)用車車輛安全培訓課件
- 牛津譯林版七年級英語上冊詞組背誦版
- 奧林巴斯微單相機E-PL8說明書
- 中醫(yī)臨床路徑18脾胃科
- 零星維修合同模板
- 九三學社申請入社人員簡歷表
- 聚氨酯門窗研究匯報
- 醫(yī)院電子病歷四級建設(shè)需求
- 上海2023屆高三二模數(shù)學卷匯總(全)
- 《銳角三角函數(shù)》復(fù)習(公開課)課件
- 計算機視覺PPT完整全套教學課件
評論
0/150
提交評論