版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
C語言程序設(shè)計(jì)周屹第8章函數(shù)8.1函數(shù)定義
8.2函數(shù)參數(shù)和返回值
8.2.1形式參數(shù)和實(shí)際參數(shù)
8.2.2函數(shù)返回值
8.3函數(shù)調(diào)用
8.3.1調(diào)用方式
8.3.2函數(shù)說明
8.3.3函數(shù)嵌套調(diào)用
8.3.4函數(shù)遞歸調(diào)用
8.4數(shù)組作為函數(shù)參數(shù)
8.5局部變量和全局變量
8.5.1局部變量
8.5.2全局變量
8.6存儲(chǔ)類型
8.6.1auto存儲(chǔ)類型
8.6.2extern存儲(chǔ)類型
8.6.3register存儲(chǔ)類型
8.6.4static存儲(chǔ)類型8.7內(nèi)部函數(shù)和外部函數(shù)
C語言不僅提供了極為豐富的庫函數(shù)(如TurboC,MSC都提供了三百多個(gè)庫函數(shù)),還允許用戶建立自己定義的函數(shù)。用戶編寫一個(gè)個(gè)相對獨(dú)立的函數(shù)模塊算法,然后用調(diào)用的方法來使用函數(shù)。例8-1帶參函數(shù)程序main(){inta,b,c;scanf(“%d,%d”,&a,&b);c=fun(a,b);printf(“funis%d”,c);}fun(intx,inty){intz;if(x>y)z=x;elsez=y;return(z);}說明:(1)一個(gè)源程序文件由一個(gè)或多個(gè)函數(shù)組成。一個(gè)源程序文件是一個(gè)編譯單位,即以源文件為單位進(jìn)行編譯,而不是以函數(shù)為單位進(jìn)行編譯。(2)一個(gè)C語言程序由一個(gè)或多個(gè)源程序文件組成。對于較大的程序,一般不希望全放在一個(gè)文件中,而是將函數(shù)和其他內(nèi)容(如預(yù)編譯命令)分別放到若干個(gè)源文件中,再由若干個(gè)源文件組成一個(gè)C語言程序。這樣可以分別編寫、分別編譯,提高調(diào)試效率。一個(gè)源文件可以為多個(gè)C語言程序共用。(3)C語言程序的執(zhí)行從main函數(shù)開始,調(diào)用其它函數(shù)后流程回到main函數(shù),在main函數(shù)中結(jié)束整個(gè)程序的運(yùn)行。(4)所有函數(shù)都是平行的,即在定義函數(shù)時(shí)是相互獨(dú)立的,一個(gè)函數(shù)并不從屬于另一個(gè)函數(shù),即函數(shù)不能嵌套定義,但可以相互調(diào)用,甚至嵌套調(diào)用、遞歸調(diào)用(不能調(diào)用main函數(shù))。
(5)從用戶使用角度看,函數(shù)有兩種?!駱?biāo)準(zhǔn)函數(shù),即庫函數(shù)。這是由系統(tǒng)提供的,用戶無須定義,也不必在程序中作類型說明,只需在程序前包含有該函數(shù)原型的頭文件即可在程序中直接調(diào)用?!裼脩糇约憾x的函數(shù),以解決用戶的專門需要。(6)從函數(shù)的形式看,函數(shù)分兩類?!駸o參函數(shù)。在調(diào)用無參函數(shù)時(shí),主調(diào)函數(shù)并不將數(shù)據(jù)傳送給被調(diào)用函數(shù),一般用來執(zhí)行指定的一組操作。無參函數(shù)可以帶回也可以不帶回函數(shù)值,但一般以不帶回函數(shù)值居多?!裼袇⒑瘮?shù)。在調(diào)用函數(shù)時(shí),在主調(diào)函數(shù)和被調(diào)函數(shù)之間有參數(shù)傳遞,也就是說,主調(diào)函數(shù)可以將數(shù)據(jù)傳給被調(diào)函數(shù)使用,被調(diào)用函數(shù)中的數(shù)據(jù)也可以帶回來供主調(diào)函數(shù)使用。8.1函數(shù)的定義1.函數(shù)的定義(1)無參函數(shù)的一般形式類型說明符函數(shù)名(){類型說明;語句;}(2)有參函數(shù)的一般形式
類型說明符函數(shù)名(形式參數(shù)表){類型說明;
語句;}voidHello(){printf("Hello,world\n");}intmax(a,b)inta,b;{if(a>b)returna;elsereturnb;}8.2.1形式參數(shù)和實(shí)際參數(shù)
函數(shù)的形參和實(shí)參具有以下特點(diǎn):1.形參變量只有在被調(diào)用時(shí)才分配內(nèi)存單元,在調(diào)用結(jié)束時(shí),即刻釋放所分配的內(nèi)存單元,因此,形參只有在函數(shù)內(nèi)部有效。函數(shù)調(diào)用結(jié)束返回主調(diào)函數(shù)后則不能再使用該形參變量。2.實(shí)參可以是常量、變量、表達(dá)式、函數(shù)等,無論實(shí)參是何種類型的量,在進(jìn)行函數(shù)調(diào)用時(shí),它們都必須具有確定的值,以便把這些值傳送給形參。3.實(shí)參和形參在數(shù)量上、類型上、順序上應(yīng)嚴(yán)格一致,否則會(huì)發(fā)生“類型不匹配”的錯(cuò)誤。4.函數(shù)調(diào)用中發(fā)生的數(shù)據(jù)傳送是單向的。即只能把實(shí)參的值傳送給形參,而不能把形參的值反向地傳送給實(shí)參,因此在函數(shù)調(diào)用過程中,形參的值發(fā)生改變,而實(shí)參中的值不會(huì)變化。8.2函數(shù)參數(shù)和返回值
例8-3求兩整數(shù)中的較大值。#include<stdio.h>intmax(inta,intb);voidmain(){ inta,bmax; printf("輸入兩整數(shù):"); scanf("%d%d",&a,&b); max=max(a,b);/*調(diào)用max函數(shù),在表達(dá)式中出現(xiàn)*/ printf("\n兩整數(shù)中的較大值是%d\n",max);}intmax(inta,intb)/*求兩整數(shù)中的較大值函數(shù)定義*/{ if(a>b)returna; elsereturnb;}函數(shù)的值是指函數(shù)被調(diào)用之后,執(zhí)行函數(shù)體中的程序段所取得的并返回給主調(diào)函數(shù)的值,這就是函數(shù)的返回值。說明:(1)函數(shù)的值只能通過return語句返回主調(diào)函數(shù)。return語句的一般形式為:
return表達(dá)式;
return(表達(dá)式);return;該語句的功能是計(jì)算表達(dá)式的值,并返回給主調(diào)函數(shù)。在函數(shù)中允許有多個(gè)return語句,但每次調(diào)用只能有一個(gè)return語句被執(zhí)行,因此只能返回一個(gè)函數(shù)值。8.2.2函數(shù)返回值
(2)函數(shù)值得類型。既然函數(shù)可以有返回值,這個(gè)值當(dāng)然應(yīng)屬于某一個(gè)確定的類型,應(yīng)當(dāng)在定義函數(shù)時(shí)指定函數(shù)值的類型。例如:intmax(inti,inty)charletter(charc1,charc2)floatf(floatx)doublemin(doublex,doubley)C語言還規(guī)定,凡不加類型聲明的函數(shù),一律自動(dòng)按整型處理。(3)函數(shù)值的類型和函數(shù)定義中函數(shù)的類型應(yīng)保持一致。如果兩者不一致,則以函數(shù)類型為準(zhǔn),自動(dòng)進(jìn)行類型轉(zhuǎn)換。(4)不返回函數(shù)值的函數(shù),可以明確定義為“空類型”,類型說明符為“void”。voids(intn){…}一旦函數(shù)被定義為空類型后,就不能在主調(diào)函數(shù)中使用被調(diào)函數(shù)的函數(shù)值了。例如,在定義s為空類型后,在主函數(shù)中寫下述語句sum=s(n);就是錯(cuò)誤的。為了使程序有良好的可讀性并減少出錯(cuò),不要求返回值的函數(shù)都應(yīng)定義為空類型。函數(shù)調(diào)用的一般形式為
被調(diào)用函數(shù)名([參數(shù)表達(dá)式1,參數(shù)表達(dá)式2,…,參數(shù)表達(dá)式n]);其中,參數(shù)前不加數(shù)據(jù)類型說明,參數(shù)表達(dá)式可以是常量、變量或表達(dá)式。各個(gè)參數(shù)表達(dá)式之間用逗號(hào)分割。參數(shù)表示式的個(gè)數(shù)與該函數(shù)定義時(shí)形式參數(shù)的個(gè)數(shù)、數(shù)據(jù)類型都應(yīng)該匹配,否則會(huì)出現(xiàn)預(yù)料不到的結(jié)果。如果被調(diào)用函數(shù)是無參函數(shù),即[]中沒有內(nèi)容時(shí),函數(shù)名后面的括號(hào)不要省略。使用C語言的庫函數(shù)就是函數(shù)簡單調(diào)用的方法。例如:
main()
{
printf(“******\n”);
}8.3函數(shù)調(diào)用
8.3.1調(diào)用方式
(1)函數(shù)表達(dá)式
函數(shù)作為表達(dá)式中的一項(xiàng)出現(xiàn)在表達(dá)式中,以函數(shù)返回值參與表達(dá)式的運(yùn)算。這種方式要求函數(shù)有返回值。例如:
z=max(x,y)*8;其中,函數(shù)max是賦值表達(dá)式的一部分,它的值乘以8后在賦予變量z(2)函數(shù)語句函數(shù)調(diào)用的一般形式加上分號(hào)即構(gòu)成函數(shù)語句。例如:
printf(“%d”,m);
max(x,y);等都是以函數(shù)語句的方式調(diào)用函數(shù)。(3)函數(shù)實(shí)參函數(shù)作為另一個(gè)函數(shù)調(diào)用的實(shí)際參數(shù)出現(xiàn)。這種情況是把該函數(shù)的返回值作為實(shí)參傳遞給調(diào)用函數(shù),因此要求該函數(shù)必須有返回值。例如:
printf(“%d”,max(m,n));上述語句是把max函數(shù)的返回值又作為printf函數(shù)的實(shí)參來使用。對被調(diào)函數(shù)的說明也有兩種格式,一種為傳統(tǒng)格式。其格式為:類型說明符被調(diào)函數(shù)名();這種格式只給出函數(shù)返回值的類型,被調(diào)函數(shù)名及一個(gè)空括號(hào)。這種格式由于在括號(hào)中沒有任何參數(shù)信息,因此不便于編譯系統(tǒng)進(jìn)行錯(cuò)誤檢查,容易發(fā)生錯(cuò)誤。另一種為現(xiàn)代格式,其一般形式為:類型說明符被調(diào)函數(shù)名(類型形參,類型形參…);
或?yàn)椋侯愋驼f明符被調(diào)函數(shù)名(類型,類型…);
現(xiàn)代格式的括號(hào)內(nèi)給出了形參的類型和形參名,或只給出形參類型。這便于編譯系統(tǒng)進(jìn)行檢錯(cuò),以防止可能出現(xiàn)的錯(cuò)誤。max函數(shù)的說明若用傳統(tǒng)格式可寫為:intmax();用現(xiàn)代格式可寫為:intmax(inta,intb);或?qū)憺椋篿ntmax(int,int);8.3.2函數(shù)說明
注意:(1)被調(diào)用的函數(shù)必須是已經(jīng)存在的函數(shù)(是庫函數(shù)或用戶自己定義的函數(shù))(2)在調(diào)用系統(tǒng)函數(shù)時(shí),需要用包含命令#include“頭文件名.h”將定義系統(tǒng)函數(shù)的庫文件包含在本程序中,有關(guān)包含命令的相關(guān)知識(shí)在后面章節(jié)中詳細(xì)介紹。(3)如果調(diào)用函數(shù)和主函數(shù)在一個(gè)編譯單元中,則在書寫順序上被調(diào)用函數(shù)比主函數(shù)先出現(xiàn);或者被調(diào)用函數(shù)雖然在主函數(shù)之后出現(xiàn),而被調(diào)用函數(shù)的數(shù)據(jù)類型是整型或字符型,可以不對被調(diào)函數(shù)加以說明,除了上述兩種情況以外,都要對被調(diào)用函數(shù)加以說明。函數(shù)的原型說明8.3.3函數(shù)嵌套調(diào)用
例8-5用以下近似公式編程計(jì)算ex的值,ex=1+x+x2/2!+x3/3!+…(前20項(xiàng)的和)。#include<stdio.h>floatf2(intn) {if(n==1)return1;elsereturn(f2(n-1)*n);}floatf1(intx,intn){inti;floatj=1;for(i=1;i<=n;i++)j=j*x;returnj;}voidmain(){floatexp=1.0;intn,x;printf(“Inputanumber:”);scanf(“%d”,&x);printf(“%\n”,x);exp=exp+x;for(n=2;n<=19;n++)exp=exp+f1(x,n)/f2(n);printf(“\nTheisexp(%d)=%8.4f\n”,x,exp);}一個(gè)函數(shù)在它的函數(shù)體內(nèi)調(diào)用它自身稱為遞歸調(diào)用。這種特殊的函數(shù)稱為遞歸函數(shù)。遞歸調(diào)用有兩種:直接遞歸調(diào)用和間接遞歸調(diào)用。8.3.4函數(shù)遞歸調(diào)用
例8-6用遞歸法計(jì)算n!。#include<stdio.h>longff(intn){longf;if(n<0)printf("n<0,inputerror");elseif(n==0||n==1)f=1;elsef=ff(n-1)*n;return(f);}voidmain(){intn;longy;printf("\ninputainteagernumber:\n");scanf("%d",&n);y=ff(n);printf("%d!=%ld",n,y);}例8-7Hanoi塔問題。一塊板上有三根針,A,B,C。A針上套有64個(gè)大小不等的圓盤,大的在下,小的在上。要把這64個(gè)圓盤從A針移動(dòng)C針上,每次只能移動(dòng)一個(gè)圓盤,移動(dòng)可以借助B針進(jìn)行。但在任何時(shí)候,任何針上的圓盤都必須保持大盤在下,小盤在上。求移動(dòng)的步驟:#include<stdio.h>move(intn,intx,inty,intz){if(n==1)printf("%c-->%c\n",x,z);else{move(n-1,x,z,y);printf("%c-->%c\n",x,z);move(n-1,y,x,z);}}voidmain(){inth;printf("\ninputnumber:\n");scanf("%d",&h);printf("thesteptomoving%2ddiskes:\n",h);move(h,'a','b','c');}
數(shù)組名能作為函數(shù)的形參,但不能作為函數(shù)的返回值類型。數(shù)組名作為實(shí)參時(shí)是傳遞數(shù)組首地址。形參數(shù)組實(shí)質(zhì)是一個(gè)指針變量,占2字節(jié),存實(shí)參數(shù)組的首地址。傳址(傳地址值)是C函數(shù)參數(shù)傳遞的第二種方法,效率高,用途廣;但難度比傳值(傳數(shù)據(jù)值)大。8.4數(shù)組作為函數(shù)參數(shù)
2.數(shù)組名作為函數(shù)參數(shù)例8-8一維數(shù)組的數(shù)組元素值減2。#include<stdio.h>#defineN5 voidadd1(intx[],intn);voidmain(){inta[N]={6,7,8,9,10},i;printf("數(shù)組A[%d]:\n",N);for(i=0;i<N;i++)printf("a[%d]:%x%5d\n",i,&a[i],a[i]);add1(a,N);printf("\n數(shù)組A[%d:\n",N);for(i=0;i<N;i++)printf("a[%d]:%x%5d\n",i,&a[i],a[i]);}voidadd1(intx[],intn) {inti;printf("x中的值(地址):%x\n",x);printf("數(shù)組x[%d]:\n",n);for(i=0;i<n;i++)printf("x[%d]:%x%5d\n",i,&x[i],x[i]);for(i=0;i<n;i++) x[i]=x[i]-2;}例8-9有一個(gè)一維數(shù)組score,內(nèi)放10個(gè)學(xué)生成績,求平均成績。#include<stdio.h>floataverage(floatarray[10]);voidmain(){floatscore[10],aver;inti;printf(“input10scores:\n”);for(i=0;i<10;i++)scanf(“%f”,&score[i]);printf(“\n”);aver=average(score);printf(“averagescoreis%5.2f”,aver);}floataverage(floatarray[10]){inti;floataver,sum=array[0];for(i=1;i<10;i++)sum=sum+array[i];aver=sum/10;return(aver);}局部變量也稱為內(nèi)部變量。局部變量是在函數(shù)內(nèi)作定義說明的。它只在該函數(shù)范圍內(nèi)有效。也就是說,只有在包含變量說明的函數(shù)內(nèi)部,才能使用被說明的變量,在此函數(shù)之外就不能使用這些變量了,離開該函數(shù)后再使用這種變量是非法的。例如:intf1(inta)/*函數(shù)f1*/{intb,c;……}a、b、c作用域。intf2(intx)/*函數(shù)f2*/{inty,z;}x、y、z作用域。voidmain(){intm,n;}m、n作用域。8.5局部變量和全局變量
8.5.1局部變量
關(guān)于局部變量的作用域還要說明以下幾點(diǎn):(1)主函數(shù)main()中定義的變量,也只能在主函數(shù)中使用,其它函數(shù)不能使用。同時(shí),主函數(shù)中也不能使用其它函數(shù)中定義的變量。因?yàn)橹骱瘮?shù)也是一個(gè)函數(shù),與其它函數(shù)是平行關(guān)系。這一點(diǎn)是與其它語言不同的,應(yīng)予以注意。(2)形參變量也是內(nèi)部變量,屬于被調(diào)用函數(shù);實(shí)參變量,則是調(diào)用函數(shù)的內(nèi)部變量。(3)允許在不同的函數(shù)中使用相同的變量名,它們代表不同的對象,分配不同的單元,互不干擾,也不會(huì)發(fā)生混淆。(4)在復(fù)合語句中也可定義變量,其作用域只在復(fù)合語句范圍內(nèi)。第8章函數(shù)8.5局部變量和全局變量例8-10定義變量的作用域。inta,b;/*外部變量*/voidf1()/*函數(shù)f1*/{……}floatx,y;/*外部變量*/intfz()/*函數(shù)fz*/{……}voidmain()/*主函數(shù)*/{……}/*全局變量x、y作用域,全局變量a、b作用域*/8.5.2全局變量
例8-11有一個(gè)一維數(shù)組,內(nèi)放10個(gè)學(xué)生成績,寫一個(gè)函數(shù),求出平均分,最高分和最低分。#include<stdio.h>floatMax,Min;floataverage(floatarray[],intn){inti;floataver,sum=array[0];Max=Min=array[0];for(i=1;i<n;i++){if(array[i]>Max)Max=array[i];elseif(array[i]<Min)Min=array[i];sum=sum+array[i];}aver=sum/n;return(aver);}voidmain(){floatave,score[10];inti;for(i=0;i<10;i++)scanf("%f",&score[i]);ave=average(score,10);printf("max=%6.2f\nmin=%6.2f\naverage=%6.2f\n",Max,Min,ave);}對于全局變量還有以下幾點(diǎn)說明:
(1)外部變量可加強(qiáng)函數(shù)模塊之間的數(shù)據(jù)聯(lián)系,但降低這些函數(shù)的獨(dú)立性。
(2)在同一源文件中,允許外部變量和內(nèi)部變量同名。在內(nèi)部變量的作用域內(nèi),外部變量將被屏蔽而不起作用。
(3)外部變量的作用域是從定義點(diǎn)到本文件結(jié)束。如果定義點(diǎn)之前的函數(shù)需要引用這些外部變量時(shí),需要在函數(shù)內(nèi)對被引用的外部變量進(jìn)行說明。外部變量說明的一般形式為:extern數(shù)據(jù)類型
外部變量[,外部變量2……];注意:外部變量的定義和外部變量的說明是兩回事。外部變量的定義,必須在所有的函數(shù)之外,且只能定義一次。而外部變量的說明,出現(xiàn)在要使用該外部變量的函數(shù)內(nèi),而且可以出現(xiàn)多次。
#include<stdio.h>voidtestauto();voidmain(){inti;for(i=0;i<4;i++)testauto();printf("\n");}/*測試自動(dòng)類局部變量的特性*/voidtestauto(){autointva=0;/*或intva=0;*/printf("%d”,va);va++;/*值不保留*/}自動(dòng)變量的類型說明符為auto。這種存儲(chǔ)類型是C語言程序中使用最廣泛的一種類型。C語言規(guī)定,函數(shù)內(nèi)凡未加存儲(chǔ)類型說明的變量均視為自動(dòng)變量。例8-12測試自動(dòng)類型局部變量的特性。8.6.1auto存儲(chǔ)類型
8.6存儲(chǔ)類型
自動(dòng)變量具有以下特點(diǎn):(1)自動(dòng)變量的作用域僅限于定義該變量的區(qū)域內(nèi)。在函數(shù)中定義的自動(dòng)變量,只在該函數(shù)內(nèi)有效。在復(fù)合語句中定義的自動(dòng)變量只在該復(fù)合語句中有效。
例如:intkv(inta){autointx,y;{autocharc;}/*c的作用域*/……}/*a、x、y的作用域*/(2)自動(dòng)變量屬于動(dòng)態(tài)存儲(chǔ)方式,只有在定義該變量的函數(shù)被調(diào)用時(shí)才給它分配存儲(chǔ)單元,開始它的生存期。函數(shù)調(diào)用結(jié)束,釋放存儲(chǔ)單元,結(jié)束生存期。因此函數(shù)調(diào)用結(jié)束之后,自動(dòng)變量的值不能保留。在復(fù)合語句中定義的自動(dòng)變量,在退出復(fù)合語句后也不能再使用,否則將引起錯(cuò)誤。例8-13變量的作用域自動(dòng)變量。voidmain(){autointa,s=1,p=2; printf("\ninputanumber:\n");scanf("%d",&a);if(a>0){autos,p;s=a+a;p=a*a;}printf("s=%dp=%d\n",s,p);}(3)由于自動(dòng)變量的作用域和生存期都局限于定義它的個(gè)體內(nèi)(函數(shù)或復(fù)合語句內(nèi)),因此不同的個(gè)體中允許使用同名的變量而不會(huì)混淆。即使在函數(shù)內(nèi)定義的自動(dòng)變量也可與該函數(shù)內(nèi)部的復(fù)合語句中定義的自動(dòng)變量同名。外部變量的幾個(gè)特點(diǎn):(1)外部變量和全局變量是對同一類變量的兩種不同角度的提法。全局變量是從它的作用域提出的,外部變量從它的存儲(chǔ)方式提出的,表示了它的生存期。(2)當(dāng)一個(gè)源程序由若干個(gè)源文件組成時(shí),在一個(gè)源文件中定義的外部變量在其它的源文件中也有效。例如F1.C:inta,b;/*外部變量定義*/charc;/*外部變量定義*/voidmain(){……}F2.C:externinta,b;/*外部變量說明*/externcharc;/*外部變量說明*/func(intx,y){……}8.6.2extern存儲(chǔ)類型
寄存器變量存放在CPU的寄存器中,使用時(shí),不需要訪問內(nèi)存,而直接從寄存器中讀寫,這樣可提高效率。變量的作用域寄存器變量。#include<stdio.h>voidmain(){registerk,sum=0;for(k=1;k<=1000;k++)sum=sum+k;printf("sum=%d\n",sum);}8.6.3register存儲(chǔ)類型
1.靜態(tài)局部變量在局部變量的說明前再加上static說明符就構(gòu)成靜態(tài)局部變量。例如:staticinta,b;staticfloatarray[5]={1,2,3,4,5};靜態(tài)局部變量屬于靜態(tài)存儲(chǔ)方式,它具有以下特點(diǎn):(1)靜態(tài)局部變量在函數(shù)內(nèi)定義,但不象自動(dòng)變量那樣,當(dāng)調(diào)用時(shí)就存在,退出函數(shù)時(shí)就消失。靜態(tài)局部變量始終存在著,也就是說它的生存期為整個(gè)源程序。(2)靜態(tài)局部變量的生存期雖然為整個(gè)源程序,但是其作用域仍與自動(dòng)變量相同,即只能在定義該變量的函數(shù)內(nèi)使用該變量。退出該函數(shù)后,盡管該變量還繼續(xù)存在,但不能使用它。(3)允許對構(gòu)造類靜態(tài)局部量賦初值。(4)對基本類型的靜態(tài)局部變量若在說明時(shí)未賦以初值,則系統(tǒng)自動(dòng)賦予0值。8.6.4static存儲(chǔ)類型靜態(tài)變量的作用域。#include<stdio.h>voidmain(){inti;voidf();/*函數(shù)說明*/for(i=1;i<=10;i++)f();/*函數(shù)調(diào)用*/}voidf()/*函數(shù)定義*/{staticintj=0;++j;printf("%d\n",j);}2.靜態(tài)全局變量在函數(shù)外部定義變量時(shí),用static修飾的變量是靜態(tài)類全局變量。它分配在數(shù)據(jù)區(qū),作用范圍也是從定義點(diǎn)開始到該文件結(jié)束,或稱為文件作用域;但只限于該源文件,不能被其它源文件引用。靜態(tài)類全局變量在執(zhí)行main之前初始化;未初始化,其值為0。變量的作用域——靜態(tài)全局變量。#include<stdio.h>staticinta=20;/*靜態(tài)全局變量定義*/voidtest();voidmain(){inti;for(i=0;i<3;i++)
test();
printf(“\n”);}voidtest(){intb=20;printf("%d,%d\n",a,b);++a;b++;}8.7內(nèi)部函數(shù)和外部函數(shù)1.內(nèi)部函數(shù)的一般形式是:static類型說明符函數(shù)名(形參表);
例如:staticintf(inta,intb);關(guān)鍵字“static”,譯成中文就是“靜態(tài)的”,所以內(nèi)部函數(shù)又稱靜態(tài)函數(shù)。但此處“static”的含義不是指存儲(chǔ)方式,而是指對函數(shù)的作用域僅局限于本文件。使用內(nèi)部函數(shù)的好處是:不同的人編寫不同的函數(shù)時(shí),不用擔(dān)心自己定義的函數(shù),是否會(huì)與其它文件中的函數(shù)同名,因?yàn)橥矝]有關(guān)系。2.外部函數(shù)(又稱全局函數(shù))外部函數(shù)在整個(gè)源程序中都有效。其定義的一般形式為:extern類型說明符函數(shù)名(形參表);例如:externintfun(inta,floatx);缺省extern隱含為外部函數(shù)。因此,前面所見到的函數(shù)都是外部函數(shù)。外部函數(shù)允許被其他源程序文件調(diào)用,但必須先聲明。例如:externintf(inta,intb);如在函數(shù)定義中沒有說明extern或static則隱含為extern。在一個(gè)源文件的函數(shù)中調(diào)用其它源文件中定義的外部函數(shù)時(shí),應(yīng)用extern說明被調(diào)函數(shù)為外部函數(shù)。F1.C(源文件一)voidmain(){externintf1(inti);/*外部函數(shù)說明,表示f1函數(shù)在其它源文件中*/…}
F2.C(源文件二)externintf1(inti)/*外部函數(shù)定義*/{…}本章小結(jié)
C語言程序總是從主函數(shù)開始執(zhí)行,在主函數(shù)中結(jié)束。函數(shù)是程序的基本組成單位,C程序是由各式各樣的函數(shù)完成的。利用函數(shù),不僅可以實(shí)現(xiàn)程序的模塊化,而且提高了程序的易讀性和可維護(hù)性,由于采用了函數(shù)模塊式的結(jié)構(gòu),C語言易于實(shí)現(xiàn)結(jié)構(gòu)化程序設(shè)計(jì),使程序的層次結(jié)構(gòu)清晰,便于程序的編寫、閱讀、調(diào)試。
函數(shù)定義和函數(shù)調(diào)用是一個(gè)問題的兩個(gè)方面。函數(shù)定義是解決“怎么做”問題,而函數(shù)調(diào)用是解決“做什么”問題。函數(shù)只能定義一次,但可多次聲明和多次調(diào)用,在函數(shù)調(diào)用時(shí),一般都要傳入和傳出數(shù)據(jù)。C語言程序設(shè)計(jì)周屹第9章編譯預(yù)處理9.1宏定義
9.1.1符號(hào)常量宏定義
9.1.2帶參數(shù)宏定義
9.2文件包含命令
9.3條件編譯
9.3.1條件編譯概念
9.3.2條件編譯優(yōu)點(diǎn)
9.1宏定義
1.不帶參數(shù)宏定義一般格式: #define標(biāo)識(shí)符字符串
其中:“define”為宏定義命令;“標(biāo)識(shí)符”為所定義的宏名,通常用大寫字母表示,以便與變量區(qū)別;“語言符號(hào)字符串”可以是常數(shù)、表達(dá)式、格式串等。與其配對使用的是#undef,表示結(jié)束標(biāo)志符的定義。9.1.1符號(hào)常量宏定義
用一個(gè)指定的標(biāo)識(shí)符(即名字)來代表一個(gè)字符串。2.使用宏定義的優(yōu)點(diǎn)(1)可提高源程序的可維護(hù)性。(2)可提高源程序的可移植性。
(3)減少源程序中重復(fù)書寫字符串的工作量。例9-1宏定義應(yīng)用。#include<stdio.h>
#definePR10voidmain(){inti=6;printf(“i+PR=%d\n”,i+PR);
#undefPR
#definePR50
printf(“i+PR=%d\n”,i+PR);}運(yùn)行結(jié)果:i+PR=16i+PR=56(1)宏名一般用大寫字母表示,用來與變量區(qū)別。(2)宏定義不是C語句,所以不能在行尾加分號(hào)。否則,宏展開時(shí),會(huì)將分號(hào)作為字符串的一個(gè)字符,用于替換宏名。(3)在宏展開時(shí),預(yù)處理程序僅以按宏定義簡單替換宏名,而不作任何檢查。如果有錯(cuò)誤,只能由編譯程序在編譯宏展開后的源程序時(shí)發(fā)現(xiàn)。(4)宏定義命令#define出現(xiàn)在函數(shù)的外部,宏名的有效范圍是:從定義命令之后,到本文件結(jié)束。通常,宏定義命令放在文件開頭處。
(5)在進(jìn)行宏定義時(shí),可以引用已定義的宏名。(6)對雙引號(hào)括起來的字符串內(nèi)的字符,即使與宏名同名,也不進(jìn)行宏展開。應(yīng)用宏可編寫通用性強(qiáng)的程序;可減少書寫錯(cuò)誤。3.說明:(7)宏名常用在以下兩方面:用一個(gè)有意義的名字去代替含義不清的一串?dāng)?shù)字,比如用PI代表圓周率,用PAGE_SIZE代表每頁打印的行數(shù)等,如:#definePI3.14159265358979#definePAGE_SIZE66這樣在程序中使用PI和PAGE_SIZE比用3.14159265358979和66的含義明確多了,既簡單又清楚,既便于修改又可避免出錯(cuò)。用一個(gè)短的名字去代替較長的名字如:#defineSTUstructstudentSTUstud1,stud2;即等價(jià)于structstudentstud1,stud2;(8)程序設(shè)計(jì)中常見的錯(cuò)誤是宏定義時(shí)在宏值的后面加分號(hào)如:#definePI3.14159;則對s=2*PI*r;會(huì)替換成s=2*3.14159;*r;這會(huì)產(chǎn)生編譯錯(cuò)誤。1.帶參數(shù)宏的一般格式:#define宏名(參數(shù)表)替換串2.帶參數(shù)宏的調(diào)用和宏展開調(diào)用格式:宏名(實(shí)參表);宏展開:用宏調(diào)用提供的實(shí)參字符串,直接置換宏定義命令行中、相應(yīng)形參字符串,非形參字符保持不變。3.說明:(1)定義有參宏時(shí),宏名與左圓括號(hào)之間不能留有空格。否則,C編譯系統(tǒng)將空格以后的所有字符均作為替代字符串,而將該宏視為無參宏。(2)有參宏的展開,只是將實(shí)參作為字符串,簡單地置換形參字符串,而不做任何語法檢查。在定義有參宏時(shí),在所有形參外和整個(gè)字符串外,均加一對圓括號(hào)。宏值中間的參數(shù)要用圓括號(hào)括起來。9.1.2帶參數(shù)宏定義
例9-3帶參數(shù)宏的應(yīng)用。#include<stdio.h>#definePI3.141592/*宏定義
定義符號(hào)常量圓周率PI*/#defineS(r)(PI)*(r)*(r)/*宏定義
定義計(jì)算圓面積*/voidmain(){doubleR,area1,area2;printf("輸入圓半徑:");scanf("%lf",&R);area1=S(R);area2=S(R+5);printf("圓面積(r=%0.1f):%0.4f\n",R,area1);printf("圓面積(r=%0.1f+5):%0.4f\n",R,area2);}9.2文件包含命令功能:一個(gè)源文件可將另一個(gè)源文件的內(nèi)容全部包含進(jìn)來一般形式:#include“文件名”或#include<文件名>處理過程:預(yù)編譯時(shí),用被包含文件的內(nèi)容取代該預(yù)處理命令,再對“包含”后的文件作一個(gè)源文件編譯<>直接按標(biāo)準(zhǔn)目錄搜索“”先在當(dāng)前目錄搜索,再搜索標(biāo)準(zhǔn)目錄可指定路徑#include“file2.c”file1.cfile2.cfile1.cfile2.cABA9.2文件包含命令文件包含的優(yōu)點(diǎn):一個(gè)大程序,通常分為多個(gè)模塊,并由多個(gè)程序員分別編程。有了文件包含處理功能,就可以將多個(gè)模塊共用的數(shù)據(jù)(如符號(hào)常量和數(shù)據(jù)結(jié)構(gòu))或函數(shù),集中到一個(gè)單獨(dú)的文件中。這樣,凡是要使用其中數(shù)據(jù)或調(diào)用其中函數(shù)的程序員,只要使用文件包含處理功能,將所需文件包含進(jìn)來即可,不必再重復(fù)定義它們,從而減少重復(fù)勞動(dòng)。即file1.c把file2.c的拷貝包含到自己的內(nèi)部,成為一個(gè)大文件,然后再一塊編譯,所以被包含文件file2.c應(yīng)當(dāng)是源文件,不應(yīng)當(dāng)是目標(biāo)(.obj)文件。頭文件不能單獨(dú)編譯,它只能和C源程序文件一起進(jìn)行編譯。9.2文件包含命令注意:(1)一個(gè)#include指令只能包含一個(gè)文件,要包含多個(gè)文件就要用多個(gè)#include指令。(2)文件包含可以嵌套#include“file2.c”file1.cAfile3.cC#include“file3.c”file2.c
Bfile1.cAfile3.cfile2.c9.2文件包含命令注意:(3)被包含文件中的全局變量也是包含文件中的全局變量,因此在包含文件中對這些量不必再加extern說明即可加以引用。(4)被包含文件的擴(kuò)展名一般用.h,表示是在文件開頭加進(jìn)來的,其內(nèi)容可以是程序文件或數(shù)據(jù)文件,也可以是宏定義、全局變量聲明等。這些數(shù)據(jù)有相對的獨(dú)立性,可被多個(gè)文件使用,不必在多個(gè)文件中都去定義,而只在一個(gè)文件中定義,其他文件中包含這個(gè)定義文件即可。9.3條件編譯條件編譯可有效地提高程序的可移植性,并廣泛地應(yīng)用在商業(yè)軟件中,為一個(gè)程序提供各種不同的版本。利用條件編譯,還可使同一源程序即適合于調(diào)試(進(jìn)行程序跟蹤、打印較多的狀態(tài)或錯(cuò)誤信息),又適合高效執(zhí)行要求。條件編譯主要有以下用途:(1)忽略程序的某一部分。(2)幫助程序調(diào)試9.3.1條件編譯概念
9.3條件編譯條件編譯格式條件編譯命令常常應(yīng)用在頭文件中,防止標(biāo)識(shí)符重定義。條件編譯命令有以下形式:格式1:
#ifdef標(biāo)識(shí)符程序段1#else
程序段2#endif
或
#ifdef標(biāo)識(shí)符 程序段1#endif標(biāo)識(shí)符已經(jīng)#define定義,執(zhí)行程序段1;否則,執(zhí)行程序段2。格式2:
#ifndef標(biāo)識(shí)符程序段1#else
程序段2#endif
或
#ifndef標(biāo)識(shí)符 程序段1#endif標(biāo)識(shí)符未經(jīng)#define定義,執(zhí)行程序段1;否則,執(zhí)行程序段2。9.3條件編譯條件編譯格式(1)提高了C源程序的通用性。(2)使調(diào)試程序等過程變得靈活。(3)使用條件編譯可以減少目標(biāo)程序的長度例
輸入一行字母字符,根據(jù)需要設(shè)置條件編譯,使之能將字母全改為大寫字母輸出,或全改為小寫字母輸出。#defineLETTER1main(){charstr[20]=“CLanguage”,c;inti=0;while((c=str[i])!=’\0’){i++;#ifLETTERif(c>=’a’&&c<=’z’)c=c-32;#elseif(c>=’A’&&c<=’Z’)c=c+32;#endifprintf(“%c”,c);}}9.3.2條件編譯優(yōu)點(diǎn)
C標(biāo)準(zhǔn)規(guī)定可以在C源程序中加入一些“預(yù)處理命令”,以改進(jìn)程序環(huán)境,提高編程效率。對于預(yù)處理命令,必須在程序編譯之前,先對這些特殊命令進(jìn)行“預(yù)處理”。
C語言提供的預(yù)處理功能主要有以下三種:宏定義、文件包含、條件編譯,分別用宏定義命令,文件包含命令,條件編譯命令來實(shí)現(xiàn)。
為了與一般C語句相區(qū)別,這些命令以符號(hào)“#”開頭。本章小結(jié)C語言程序設(shè)計(jì)周屹第10章指針10.1指針概念
10.1.1指針定義
10.1.2指針初始化
10.1.3指針運(yùn)算符
10.2指針變量運(yùn)算
10.2.1指針變量賦值運(yùn)算
10.2.2指針變量的算術(shù)運(yùn)算
10.2.3指針變量間的關(guān)系運(yùn)算
10.3指針和數(shù)組
10.3.1數(shù)組指針變量
10.3.2指針與一維數(shù)組
10.3.3指針與二維數(shù)組
10.3.4指針數(shù)組
10.4指針和函數(shù)
10.4.1指針作為函數(shù)參數(shù)
10.4.2指針作為函數(shù)返回值
10.4.3指針型函數(shù)
10.4.4函數(shù)指針變量
10.5指針與字符串
10.5.1字符串表示方法
10.5.2字符串處理函數(shù)的實(shí)現(xiàn)
10.6多重指針
10.6.1指向指針的指針
10.6.2命令行參數(shù)
內(nèi)存單元的編號(hào)也叫做地址。根據(jù)內(nèi)存單元的編號(hào)即地址就可以找到所需的內(nèi)存單元,通常也把這個(gè)地址稱為指針。2.變量的“直接訪問”方式10.1指針概念
直接訪問:按變量地址存取變量值間接訪問:通過存放變量地址的變量去訪問變量例
i=3;直接訪問指針變量…...…...2000200420062005整型變量i10變量i_pointer20012002200320003例*i_pointer=20;間接訪問20指針變量…...…...2000200420062005整型變量i10變量i_pointer2001200220032000整型變量k例
k=i;--直接訪問
k=*i_pointer;--間接訪問10例
k=i;k=*i_pointer;與簡單變量一樣,指針變量也必須先定義后使用.指針變量定義的一般格式:類型名*變量名;例如:
int*pa;(pa是指向整型變量的指針變量)
char*pb;(pb是指向字符型變量的指針變量)
定義了名字為pa、pb的兩個(gè)指向不同類型數(shù)據(jù)的指針變量。
10.1.1指針定義
指針變量的初始化的一般形式為數(shù)據(jù)類型*指針變量名=初始地址值;例如:
int*pa=&i;在指針變量初始化中,通常用“&變量名”來表示一個(gè)基本類型變量的地址。在定義指針變量pa的同時(shí),把變量i的地址作為初值來初始化pa。應(yīng)注意的是,初始化中的“*pa=&i”不是運(yùn)算表達(dá)式,而是一個(gè)說明語句。在這里將變量i的地址值賦給指針變量pa,而不是*pa。10.1.2指針初始化
注意:(1)指針目標(biāo)變量的數(shù)據(jù)類型必須與指針的數(shù)據(jù)類型相一致。類型不一致將引起致命錯(cuò)誤。例如,下面的初始化方式就是錯(cuò)誤的,導(dǎo)致錯(cuò)誤的原因就是類型不一致。
doublea:
int*pa=&a;(2)當(dāng)把一個(gè)變量的地址作為初值賦給指針變量時(shí),這個(gè)變量必須在這個(gè)指針初始化之前定義過。注意:(3)可以將一個(gè)指針的值賦給另一個(gè)指針變量。例如:
intb;
int*pb=&b;
int*q=pb;(4)可以把一個(gè)指針初的化為一個(gè)空指針。例如:
int*px=NULL;/*px是指針變量,初值為NULL,不指向任何目標(biāo)*/(1)取地址運(yùn)算符&取地址運(yùn)算符&是單目運(yùn)算符,其結(jié)合性為自右至左,其功能是取變量所占用的存儲(chǔ)單元的首地址。例如,
inti,*i_pointer;
i_pointer=&i;將變量i的地址(注意不是i的值)賦給i_pointer。這個(gè)賦值語句可以理解為i_pointer接受i的地址。如果給i分配的地址是2000開始的單元,則賦值后i_pointer的值是200010.1.3指針運(yùn)算符
(2)取內(nèi)容運(yùn)算符*取內(nèi)容運(yùn)算符*是單目運(yùn)算符,其結(jié)合性為自右至左,它的作用是通過指針變量來訪問它所指向的變量(存數(shù)據(jù)或取數(shù)據(jù))。故在*運(yùn)算符之后跟的變量必須是指針變量。i_pointer中存放i的地址,現(xiàn)賦值i=5;i_pointer=&i;j=*i_pointer;這個(gè)賦值語句可以理解為把i_pointer中存放的值當(dāng)做地址,然后取那個(gè)地址(i的地址)中的值賦給變量j,結(jié)果是把“5”賦給j。常見的指針賦值運(yùn)算有以下幾種形式。(1)把一個(gè)變量的地址賦給指向相同數(shù)據(jù)類型的指針變量。例如:
inta,*pa;
pa=&a;(2)相同數(shù)據(jù)類型的指針變量間可以相互賦值。例如:
int*p,*q;
q=p;(3)把數(shù)組的地址賦給指向相同數(shù)據(jù)類型的指針變量。例如:
doublex[10],*pa,*pb;
pa=x;
pb=&x[0];10.2指針變量運(yùn)算
10.2.1指針變量賦值運(yùn)算
(4)把數(shù)組的首地址賦予指向數(shù)組元素的指針變量。例如:
inta[5],*pa;
pa=a;數(shù)組名表示數(shù)組的首地址,故可賦予指向數(shù)組元素的指針變量pa。(5)把字符串的首地址賦予指向字符類型的指針變量。例如:
char*pc;
pc="clanguage";或用初始化賦值的方法寫為:char*pc="CLanguage";(6)把函數(shù)的入口地址賦予指向函數(shù)的指針變量。例如:int(*pf)();
pf=f;/*f為函數(shù)名*/在使用賦值運(yùn)算時(shí),不要將一個(gè)整數(shù)(整數(shù)0除外)或其他類型的數(shù)是不合法的。
inta,*p1;
float*p;
p1=100;
p1=a;另外,賦值語句p=p1;也是錯(cuò)誤的。p和p1雖然都是指針變量,但分別指向不同類型的目標(biāo)變量??梢詫⒄麛?shù)0賦予一個(gè)指針變量例如:pa=0;這時(shí)指針變量pa的值為0,表示該指針為空指針??罩羔槻⒉皇侵羔樀拇鎯?chǔ)空間為空。而是有著特定的值0,它表示指針的一種狀態(tài),即該指針不指向任何目標(biāo)變量。
注意:在程序中使用指針變量之前,一定要給該指針賦予確定的地址值。一個(gè)沒有賦值的指針其指向是不定的。在使用指向不定的指針處理數(shù)據(jù)時(shí),常常會(huì)破壞內(nèi)存中其他領(lǐng)域的內(nèi)容,嚴(yán)重時(shí)會(huì)造成系統(tǒng)失控。因此在程序中不要使用指向不定的指針。加減算術(shù)運(yùn)算指針變量作為地址量加上或減去一個(gè)整數(shù)n,表示指針變量當(dāng)前位置前移或后移n個(gè)存儲(chǔ)單元。例如:int*pn;不妨設(shè)pn=0x0000,那么pn+n=pn+n*sizeof(int)=0x0000+n*2。一般說來,對于“type*pn;”來說,“pn+n”表示的地址是“pn+n*sizeof(type)”,其中Type是某種數(shù)據(jù)類型,如整型、實(shí)型或字符型等。10.2.2指針變量的算術(shù)運(yùn)算
指針變指針變量自增(++)、自減(--)運(yùn)算指針變量自增(++)和自減(--)運(yùn)算也是地址運(yùn)算,指針變量自增(++)運(yùn)算后就指向內(nèi)存中下一個(gè)數(shù)據(jù)位置,指針變量自減(--)運(yùn)算后就指向內(nèi)存中上一個(gè)數(shù)據(jù)位置。運(yùn)算后指針變量地址值也取決于它所指向的數(shù)據(jù)類型。指針變量的“++”、“--”運(yùn)算也分為前置運(yùn)算和后置運(yùn)算,當(dāng)它們和其他運(yùn)算符出現(xiàn)在—個(gè)表達(dá)式中的時(shí)候,要注意它們之間的結(jié)合規(guī)則和運(yùn)算順序。例如:y=*p++;
y=*++p;y=(*p)++;
y=++(*p);設(shè)指針變量p1和p2指向同類型的數(shù)據(jù),則“p2-p1”運(yùn)算的結(jié)果是兩個(gè)指針變量所指向的地址位置之間的數(shù)據(jù)個(gè)數(shù)。例如:type*p1,*p2;則p2-p1=(p2-p1)/sizeof(type)兩個(gè)指針變量相減也是地址計(jì)算,但結(jié)果值不是地址量,是按公式計(jì)算得到的一個(gè)整數(shù)。其中,“sizeof(type)”是表示指針變量的數(shù)據(jù)類型所占的字節(jié)數(shù)。10.2.3指針變量間的關(guān)系運(yùn)算
指向相同數(shù)據(jù)類型的指針變量之間可以進(jìn)行各種關(guān)系運(yùn)算。兩個(gè)指針變量之間的關(guān)系運(yùn)算表示它們的目標(biāo)變量的地址位置之間的關(guān)系。假設(shè)數(shù)據(jù)在內(nèi)存中的存儲(chǔ)邏輯是由前向后,則指向后方的指針變量大于前方的指針變量。例如:p<qp=q指向不同數(shù)據(jù)類型的指針變量之間的關(guān)系運(yùn)算是沒有意義的。指針變量與一般整數(shù)變量之間的關(guān)系運(yùn)算也是沒有意義的。但是指針變量可以和整數(shù)0之間進(jìn)行等于或不等于的關(guān)系運(yùn)算,用以判斷指針變量是否為空指針,即無效指針。例如:p==0或p!=010.3指針和數(shù)組
10.3.1數(shù)組指針變量定義一個(gè)指向數(shù)組元素的指針變量的方法,與以前介紹的指向變量的指針變量相同。inta[10];/*定義a為包含10個(gè)整型數(shù)據(jù)的數(shù)組*/int*p;/*定義p為指向整型變量的指針變量*/p=&a[0];/*把a(bǔ)[0]素的地址賦給指針變量p*/注意:
因?yàn)閿?shù)組為int型,所以指針變量也應(yīng)為指向int型的指針變量。通過指針引用數(shù)組元素C語言規(guī)定:如果指針變量p指向數(shù)組中的一個(gè)元素,則p+1指向同一數(shù)組中的下一個(gè)元素。例如,若p的初值為&a[0],則:
①p+i和a+i就是a[i]的地址,或者說它們指向a數(shù)組的第i個(gè)元素。
②*(p+i)或*(a+i)就是p+i或a+i所指向的數(shù)組元素,即a[i]。例如,*(p+5)或*(a+5)就是a[5]。
③指向數(shù)組的指針變量也可以帶下標(biāo),如p[i]與*(p+i)等價(jià)。
引用一個(gè)數(shù)組元素方法:
①下標(biāo)法,即用a[i]形式訪問數(shù)組元素。在前面介紹數(shù)組時(shí)都是采用這種方法。
②指針法,即采用*(a+i)或*(p+i)形式,用間接訪問的方法來訪問數(shù)組元素,其中a是數(shù)組名,p是指向數(shù)組的指針變量,其初值p=a。用3種方法比較如下:(1)第①和②兩種方法執(zhí)行效率相同。C編譯系統(tǒng)將a[i]轉(zhuǎn)換成*(a+i)進(jìn)行處理。即先計(jì)算元素地址。因此用這兩種方法找出數(shù)組元素比較費(fèi)時(shí)。(2)用第③種方法比第①、第②方法快,用指針變量直接指向元素,不需要每次都重新計(jì)算地址,像p++這樣的自加是比較快的,能大大提高執(zhí)行效率。(3)用下標(biāo)法比較直觀,能直接知道是第幾個(gè)元素。例如,a[5]是數(shù)組中的第6個(gè)元素。用地址法或指針變量的方法不直觀,難以很快判斷出當(dāng)前處理的是哪個(gè)元素。例10-2用指針訪問數(shù)組元素。voidmain(){inta[10],i,*p;p=a;for(i=0;i<10;i++){*p=i;p++;}}注意:(1)指針變量可以實(shí)現(xiàn)本身的值的改變。如p++是合法的;而a++是錯(cuò)誤的。(2)要注意指針變量的當(dāng)前值。(3)雖然定義數(shù)組時(shí),指定它包含10個(gè)元素,但指針變量可以指到數(shù)組以后的內(nèi)存單元,系統(tǒng)并不認(rèn)為非法。(4)*p++,由于++和*同優(yōu)先級(jí),結(jié)合方向自右而左,等價(jià)于*(p++)(5)*(p++)與*(++p)作用不同。若p的初值為a,則*(p++)等價(jià)于a[0],*(++p)等價(jià)a[1]。(6)(*p)++表示p所指向的元素值加1。(7)如果p當(dāng)前指向a數(shù)組中的第i個(gè)元素,則:
*(p--)相當(dāng)于a[i--];
*(++p)相當(dāng)于a[++i];
*(--p)相當(dāng)于a[--i]。10.3.2指針與一維數(shù)組一維數(shù)組和指針定義如下:inta[4]={1,2,3,4};int*p=a; /*p是指向一維數(shù)組元素的指針*/應(yīng)用指針運(yùn)算符+、*、[]建立指針與一維數(shù)組的關(guān)系,如圖10-4所示。a[i]、*(a+i)、*(p+i)、p[i]是等價(jià)表達(dá)式,均表示數(shù)組元素。a+i、p+i也是等價(jià)表達(dá)式,均表示數(shù)組元素的地址。要特別注意,p[i]表達(dá)式中的p不是數(shù)組名,是指針;這是一種下標(biāo)表示法。10.3.3指針與二維數(shù)組1.指向二維數(shù)組元素的指針變量例10-4用指針變量輸出二維數(shù)組元素的值#include<stdio.h>voidmain(){inta[3][4]={1,2,,3,4,5,6,7,8,9,10,11,12};int*p;for(p=a[0];p<a[0]+12;p++){if((p-a[0])%4==0)printf(“\n”);printf(“%4d”,*p);}}
二維數(shù)組元素在內(nèi)存中是以一維方式存儲(chǔ)。應(yīng)用指向二維數(shù)組元素的指針,可以很方便地對二維數(shù)組實(shí)現(xiàn)一維運(yùn)算從上圖可以看到有兩個(gè)方向的控制:①a、a+i、&a[i]控制的是行,或者說它們是行控制。②*(a+i)+j或a[i]+j控制的是列,即列控制。③雖然a+1和a[1]的值均是1020,但含義(屬性)是不一樣的。a+1指向a[1],是向縱向移動(dòng);a[1]指向a[1][0],是向橫向移動(dòng)。
10.3.4指針數(shù)組
一個(gè)數(shù)組的元素為指針則是指針數(shù)組。指針數(shù)組是一組有序的指針的集合。指針數(shù)組的所有元素都必須是具有相同存儲(chǔ)類型和指向相同數(shù)據(jù)類型的指針變量。數(shù)組的元素是指針類型的,指針數(shù)組定義的一般格式:
類型*數(shù)組名[常量表達(dá)式];其中類型說明符為指針值所指向的變量的類型。例如:int*pa[3];表示pa是一個(gè)指針數(shù)組,它有三個(gè)數(shù)組元素,每個(gè)元素值都是一個(gè)指針,指向整型變量。10.4指針和函數(shù)
例10-7交換兩個(gè)整數(shù)—指針與函數(shù)。#include<stdio.h>/*形參不是指針,無法修改實(shí)參,達(dá)不到交換兩個(gè)整數(shù)的目的*/voidswapa(intx,inty);/*形參是指針,由于是修改指針本身,也達(dá)不到交換兩個(gè)整數(shù)的目的*/voidswapb(int*px,int*py);/*形參是指針,由于是修改指針?biāo)赶虻哪繕?biāo),能達(dá)到交換兩個(gè)整數(shù)的目的*/
10.4.1指針作為函數(shù)參數(shù)
voidswapc(int*px,int*py);voidmain() {intx=10,y=20;printf("源數(shù)據(jù)(地址和值):\n");printf("x:%x%d\n",&x,x);printf("y:%x%d\n",&y,y);printf("調(diào)用swap1:\n");swapa(x,y);printf("在main函數(shù)內(nèi)x=%dy=%d\n",x,y);printf("調(diào)用swapb:\n");swapb(&x,&y);printf("在main函數(shù)內(nèi)x=%dy=%d\n",x,y);printf("調(diào)用swapc:\n");swapc(&x,&y);printf("在main函數(shù)內(nèi)x=%dy=%d\n",x,y);}/*交換兩個(gè)整數(shù)--交換形參值*/voidswapa(intx,inty){ inttemp;temp=x;x=y;y=temp; printf("在swap1函數(shù)內(nèi)x=%dy=%d\n",x,y);}/*交換兩個(gè)整數(shù)--交換形參值(地址)*/voidswapb(int*px,int*py){ int*temp;temp=px;px=py;py=temp; printf("在swapb函數(shù)內(nèi)x=%dy=%d\n",*px,*py);}/*交換兩個(gè)整數(shù)--交換實(shí)參值*/voidswapc(int*px,int*py){ inttemp; temp=*px;*px=*py;*py=temp; printf("在swapc函數(shù)內(nèi)x=%dy=%d\n",*px,*py);}
指針可作為函數(shù)的返回值類型。在處理動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu)時(shí),經(jīng)常遇到返回指針的函數(shù)。必須十分明確,數(shù)組不可作為函數(shù)的返回值類型。返回指針類型函數(shù)的一般格式:類型名*函數(shù)名(形參表); (有參函數(shù))類型名*函數(shù)名(); (無參函數(shù))return語句中,返回局部變量的地址是不允許的。因?yàn)楹瘮?shù)返回,局部變量自動(dòng)撤消。動(dòng)態(tài)變量的地址、全局變量的地址和靜態(tài)變量的地址都可作為函數(shù)的返回值。
返回指針的函數(shù),在字符串一小節(jié)和結(jié)構(gòu)一章可看到實(shí)用的例題。這里借用一個(gè)無意義的例題說明概念。10.4.2指針作為函數(shù)返回值
例10-8返回局部變量的地址。#include<stdio.h>int*getint();/*指針函數(shù)*/voidmain() {int*p;p=getint();printf("p:%x(地址)%d(值)\n",p,*p);}/*返回局部變量的地址*/int*getint(){intvalue=20; /*局部變量*/printf("value:%x(地址)%d(值)\n",&value,value);return&value;/*警告錯(cuò)誤!返回局部變量的地址*/}定義指針型函數(shù)的一般形式為:
類型說明符*函數(shù)名(形參表){……/*函數(shù)體*/}其中函數(shù)名之前加了“*”號(hào)表明這是一個(gè)指針型函數(shù),即返回值是一個(gè)指針。類型說明符表示了返回的指針值所指向的數(shù)據(jù)類型。如:int*ap(intx,inty){…/*函數(shù)體*/}
10.4.3指針型函數(shù)
例10-9指針函數(shù)應(yīng)用舉例,輸出對應(yīng)的星期幾。
voidmain(){inti;char*day_name(intn);printf("inputDayNo:\n");scanf("%d",&i);if(i<0)exit(1);printf("DayNo:%2d-->%s\n",i,day_name(i));}char*day_name(intn){staticchar*name[]={"Illegalday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};return((n<1||n>7)?name[0]:name[n]);}10.4.4函數(shù)指針變量指向函數(shù)的指針稱為函數(shù)指針。函數(shù)指針是函數(shù)的入口地址??捎煤瘮?shù)指針調(diào)用函數(shù)。函數(shù)指針也可作為函數(shù)的形參。函數(shù)指針的一般定義格式:類型名(*指針變量名)(); (無參數(shù)表)類型名(*指針變量名)(類型名表); (有參數(shù)表)類型名是指函數(shù)返回值的類型。調(diào)用函數(shù)的一般格式:(*指針變量名)(實(shí)參表);(*指針變量名)表示“*”后面的變量是定義的指針變量。最后的空括號(hào)表示指針變量所指的是一個(gè)函數(shù)。例如:int(*pf)();表示pf是一個(gè)指向函數(shù)入口的指針變量,該函數(shù)的返回值(函數(shù)值)是整型。
10.4.4函數(shù)指針變量例10-10求a和b中較大者,用函數(shù)指針實(shí)現(xiàn)。
#include<stdio.h>intmax(inta,intb){if(a>b)returna;elsereturnb;}voidmain(){intmax(inta,intb);int(*pmax)();intx,y,z;pmax=max;printf("inputtwonumbers:\n");scanf("%d%d",&x,&y);z=(*pmax)(x,y);printf("maxmum=%d",z);}10.5指針與字符串10.5.1
字符串表示方法字符指針初始化的方法有如下兩種形式:在定義字符型指針時(shí),可以用字符串常量初始化。例如:char*strp="VC++";字符串常量可以賦給字符型指針變量。例如:char*strp;strp="VC++";字符串表示方法例10-11通過字符指針輸出一個(gè)字符串。#include<stdio.h>voidmain(){char*ps;ps="CLanguage";printf("%s",ps);}首先定義ps是一個(gè)字符指針變量,然后把字符串的首地址賦予ps(應(yīng)寫出整個(gè)字符串,以便編譯系統(tǒng)把該串裝入連續(xù)的一塊內(nèi)存單元),并把首地址送入ps。程序中的:char*ps;ps="CLanguage";等效于:char*ps="CLanguage";輸出字符串中的所有字符。字符串表示方法例10-12在輸入的字符串中查找有無'k'字符。#include<stdio.h>voidmain(){charst[20],*ps;inti;printf("inputastring:\n");ps=st;scanf("%s",ps);for(i=0;ps[i]!='\0';i++)if(ps[i]=='k'){printf("thereisa'k'inthestring\n");break;}if(ps[i]=='\0')printf("Thereisno'k'inthestring\n");}10.5.2字符串處理函數(shù)的實(shí)現(xiàn)1.求字符串長度函數(shù)原型unsignedintstrlen(constchar*s); unsignedintstrlen(constchar*s) { intlen=0; while(*s++)len++;
returnlen; }執(zhí)行*s++表達(dá)式等價(jià)于:
*s 先取s指針?biāo)赶虻淖址?/p>
s++ 再s指針加1,指向下一字符。2.字符串復(fù)制函數(shù)原型char*strcpy(char*dest,constchar*src);字符串復(fù)制是將原字符串src一個(gè)字符一個(gè)字符地復(fù)制到目標(biāo)串dest,包含'\0'字符。最后返回指針temp,即返回dest原指針值。*dest++和*src++是左值表達(dá)式。執(zhí)行*dest++=*src++表達(dá)式等價(jià)于:*dest=*src 先將指針src指向的字符復(fù)制到指針dest指向的存儲(chǔ)單元。src++ src 指針加1,指向下一字符。dest++ des 指針加1,指向下一字符。注意,由于先執(zhí)行賦值,然后src指針和des指針再加1,所以’\0’字符能復(fù)制。3.字符串連接
函數(shù)原型 char*strcat(char*dest,constchar*src);字符串連接是先將指針dest移到字符'\0'處,然后將src串復(fù)制到指針dest指向的存儲(chǔ)單元。最后返回指針temp,即返回dest原指針。圖7-12描述了字符串連接過程。
4.字符串比較
函數(shù)原型 int strcmp(constchar*s1,constchar*s2);兩個(gè)字符串比較是對應(yīng)字符一一比較。當(dāng)兩個(gè)字符不等或兩個(gè)字符均為'\0'時(shí),結(jié)束比較,返回*s1-*s2。當(dāng)前兩個(gè)字符的值決定了兩個(gè)字符串比較關(guān)系與返回值:*s1==*s2,*s1=='\0',*s2=='\0' 串1==串2 返回值
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(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ǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 基于人工智能的智慧校園智能學(xué)習(xí)環(huán)境中教育工具對學(xué)生學(xué)習(xí)效果的影響研究教學(xué)研究課題報(bào)告
- 北京體育大學(xué)北京興奮劑檢測實(shí)驗(yàn)室2025年專業(yè)技術(shù)檢測人員公開招聘備考題庫(非事業(yè)編)及參考答案詳解一套
- 2025年漢中市新華書店招聘財(cái)務(wù)人員備考題庫及參考答案詳解1套
- 簡約風(fēng)工作計(jì)劃模板
- 平?jīng)鍪惺兄睂W(xué)校公開招聘2026屆協(xié)議培養(yǎng)師范生23人備考題庫(第二批)及一套完整答案詳解
- 2025年山東外國語職業(yè)技術(shù)大學(xué)教師招聘105人備考題庫完整答案詳解
- 重慶市開州區(qū)事業(yè)單位2025年面向應(yīng)屆高校畢業(yè)生考核招聘工作人員備考題庫及一套參考答案詳解
- 2025年中國江西國際經(jīng)濟(jì)技術(shù)合作有限公司公開招聘44人備考題庫及一套答案詳解
- 2025年東電三公司社會(huì)招聘備考題庫-工程管理部及1套參考答案詳解
- 2025年國家空間科學(xué)中心空間環(huán)境探測重點(diǎn)實(shí)驗(yàn)室空間環(huán)境探測載荷工程技術(shù)人員招聘備考題庫及參考答案詳解1套
- 混合型高脂血癥基層診療中國專家共識(shí)(2024年)解讀課件
- 市政道路設(shè)計(jì)技術(shù)標(biāo)投標(biāo)方案(技術(shù)方案)
- 2024-2025學(xué)年成都市高一上英語期末考試題(含答案和音頻)
- 發(fā)熱中醫(yī)護(hù)理查房
- 物業(yè)公司業(yè)主投訴處理和回訪制度(3篇)
- 團(tuán)員證明模板(周五)
- 住宅小區(qū)綠化保潔及垃圾收集方案
- DL∕T 5097-2014 火力發(fā)電廠貯灰場巖土工程勘測技術(shù)規(guī)程
- 兼職醫(yī)生勞務(wù)協(xié)議
- 達(dá)托霉素完整版本
- 科研方法論智慧樹知到期末考試答案章節(jié)答案2024年南開大學(xué)
評(píng)論
0/150
提交評(píng)論