c語言第7章教學課件_第1頁
c語言第7章教學課件_第2頁
c語言第7章教學課件_第3頁
c語言第7章教學課件_第4頁
c語言第7章教學課件_第5頁
已閱讀5頁,還剩92頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

c語言第7章本章目錄第7章函數(shù)7.1函數(shù)概述7.2函數(shù)的定義與調(diào)用7.3函數(shù)調(diào)用中的數(shù)據(jù)傳遞方式7.4函數(shù)的嵌套調(diào)用7.5函數(shù)的遞歸調(diào)用7.6數(shù)組作函數(shù)的參數(shù)7.7變量的作用域與存儲類型7.8內(nèi)部函數(shù)和外部函數(shù)7.9多文件程序的運行

本章小結(jié)習題c語言第7章第7章函數(shù)學習目標:返回目錄了解模塊化程序設(shè)計思想。掌握函數(shù)的概念與分類。掌握函數(shù)的定義與調(diào)用。掌握遞歸函數(shù)的編寫及調(diào)用方法。掌握數(shù)組作為函數(shù)參數(shù)的用法,變量的作用域與存儲類型。了解內(nèi)部函數(shù)和外部函數(shù)的使用,工程文件的編寫與調(diào)試。c語言第7章7.1函數(shù)概述(1)C源程序是由函數(shù)組成的,C語言中的函數(shù)相當于其它高級語言的子程序。函數(shù)是C源程序的基本模塊,通過對函數(shù)模塊的調(diào)用實現(xiàn)特定的功能。由于C程序的全部工作都是由各式各樣的函數(shù)完成的,所以也把C語言稱為函數(shù)式的模塊化語言。7.1.1C程序的模塊化設(shè)計模塊化程序設(shè)計,是現(xiàn)代程序設(shè)計的基礎(chǔ)。在進行程序設(shè)計時,最好的辦法是根據(jù)結(jié)構(gòu)化程序設(shè)計思想,把復雜問題按照自頂向下、逐步細化的方法劃分為功能相對獨立的若干模塊,然后再用同樣的方法把各個模塊劃分為功能更獨立的子模塊,直到不需要細分為止。這是一個從抽象到具體的過程。劃分子模塊時要做到:內(nèi)聚性強(指模塊的獨立性要強,一個模塊完成一個功能),耦合性弱(模塊間的關(guān)聯(lián)度要小,最好沒有關(guān)聯(lián)關(guān)系)。返回目錄c語言第7章可以看出,模塊化程序設(shè)計的思想實際上是一種“分而治之”的思想,將一個大任務(wù)(復雜問題)分解為若干個小任務(wù)甚至于更小的任務(wù)(簡單問題),每個小任務(wù)實現(xiàn)起來就相對容易了。這里的每個任務(wù)對應(yīng)一個模塊,相當于C語言中的函數(shù)。函數(shù)是C語言程序的基本組成單位,因此,可以很方便地用函數(shù)作為程序模塊來實現(xiàn)C語言程序的模塊化。返回目錄7.1函數(shù)概述(2)c語言第7章7.1.2函數(shù)的概念與分類(1)1.函數(shù)的概念函數(shù)是一個可以反復使用的、功能相對獨立的程序段。在一個用戶程序中,如果在不同地方需多次執(zhí)行某些操作,則可以把完成這些操作的程序段從程序中獨立出來,定義成函數(shù),需要時再進行調(diào)用它。建立函數(shù)的過程稱為“定義函數(shù)”,使用函數(shù)的過程稱為“調(diào)用函數(shù)”。由于函數(shù)可以被其它函數(shù)調(diào)用,通常把調(diào)用其它函數(shù)的函數(shù)稱為“主調(diào)函數(shù)”,而被調(diào)用的函數(shù)稱為“被調(diào)函數(shù)”。在C語言中,所有的函數(shù)定義,包括主函數(shù)main在內(nèi),都是平行的。也就是說,在一個函數(shù)的函數(shù)體內(nèi),不允許再定義另外一個函數(shù),即不能嵌套定義。但是函數(shù)之間允許相互調(diào)用,也允許嵌套調(diào)用。甚至還允許函數(shù)自己調(diào)用自己(遞歸調(diào)用)。但不允許調(diào)用main函數(shù)(主函數(shù))。C程序的執(zhí)行總是從main函數(shù)開始,完成對其它函數(shù)的調(diào)用后再返回到main函數(shù),最后由main函數(shù)結(jié)束整個程序。一個C源程序必須有也只能有一個主函數(shù)main。返回目錄c語言第7章2.函數(shù)的分類在C語言中,可從不同的角度對函數(shù)進行分類。(1)從函數(shù)定義的角度看,函數(shù)可分為庫函數(shù)和用戶定義函數(shù)兩種。(2)從主調(diào)函數(shù)和被調(diào)函數(shù)之間數(shù)據(jù)傳送的角度看又可分為無參函數(shù)和有參函數(shù)兩種。(3)從有無返回值的角度看,又可把函數(shù)分為有返回值函數(shù)和無返回值函數(shù)兩種。(4)從使用范圍來看又可分為內(nèi)部函數(shù)和外部函數(shù)。返回目錄7.1.2函數(shù)的概念與分類(2)c語言第7章7.2函數(shù)的定義與調(diào)用7.2.1函數(shù)的定義7.2.2函數(shù)的參數(shù)與返回值7.2.3函數(shù)的調(diào)用返回目錄c語言第7章7.2.1函數(shù)的定義(1)函數(shù)的定義,就是確定該函數(shù)完成什么功能以及如何完成此功能的過程,相當于其它程序設(shè)計語言的子程序。函數(shù)的定義從形式上可以分為以下三種:1.無參函數(shù)無參函數(shù)的定義形式如下:存儲類型數(shù)據(jù)類型函數(shù)名()/*函數(shù)首部*{聲明部分/*說明部分*/語句序列/*執(zhí)行部分*/}返回本節(jié)目錄c語言第7章2.有參函數(shù)有參函數(shù)的一般形式如下:存儲類型數(shù)據(jù)類型函數(shù)名(形式參數(shù)表){聲明部分/*說明部分*/語句序列/*執(zhí)行部分*/}存儲類型:可以是extern或static兩種。extern表示定義的函數(shù)是外部函數(shù),它可以被其它編譯單位中的函數(shù)調(diào)用;static表示定義的函數(shù)是內(nèi)部函數(shù),只能被本程序單位中的函數(shù)調(diào)用。存儲類型可以省略,省略時,默認為外部函數(shù)。返回本節(jié)目錄7.2.1函數(shù)的定義(2)c語言第7章數(shù)據(jù)類型:規(guī)定了該函數(shù)的類型,函數(shù)的類型實際上就是函數(shù)返回值的類型,可以是以前介紹過的各種基本數(shù)據(jù)類型,也可以是指針型。缺省時,函數(shù)類型為int型。此外,數(shù)據(jù)類型符還可以是void(空類型),它表示本函數(shù)沒有返回值。函數(shù)名:是由用戶定義的標識符。在同一個編譯單位中,不允許函數(shù)同名。形式參數(shù)表:用逗號分隔的若干個形式參數(shù)(簡稱形參,也稱虛參),每個形式參數(shù)可以是變量名、數(shù)組名、指針變量名、指針數(shù)組名等。注意:當形式參數(shù)是數(shù)組時,只需寫出數(shù)組名。返回本節(jié)目錄7.2.1函數(shù)的定義(3)c語言第7章形式參數(shù)表只出現(xiàn)在有參函數(shù)中,無參函數(shù)沒有形式參數(shù),但括號不可少。對形式參數(shù)的聲明有兩種方式:傳統(tǒng)方式和現(xiàn)代方式。傳統(tǒng)方式在函數(shù)名后的括號中只列出用逗號分隔的形參變量名,緊接著在其后再定義形參變量的數(shù)據(jù)類型;現(xiàn)代方式采用合二為一的方法,即在函數(shù)名后的括號中聲明形參變量名的同時,指出其數(shù)據(jù)類型。返回本節(jié)目錄7.2.1函數(shù)的定義(4)c語言第7章【例7-1】用傳統(tǒng)方式和現(xiàn)代方式分別定義求兩個數(shù)中較大數(shù)的函數(shù)。程序清單如下:

方式一:傳統(tǒng)方式intmax(a,b)inta,b;{if(a>b)returna;elsereturnb;}方式二:現(xiàn)代格式intmax(inta,intb){if(a>b)returna;elsereturnb;}

等價TurboC和目前流行的C版本都允許使用這兩種方法,它們是等價的。但ANSI推薦使用現(xiàn)代方式。因為傳統(tǒng)方式不利于編譯系統(tǒng)檢查,會引起一些非常細微而且難于跟蹤的錯誤。而現(xiàn)代方式在函數(shù)定義和函數(shù)聲明(后面將要介紹)時,給出了形式參數(shù)及其類型,在編譯時易于對它們進行查錯,從而保證了函數(shù)說明和定義的一致性。返回本節(jié)目錄7.2.1函數(shù)的定義(5)c語言第7章【例7-2】定義求三個整型數(shù)最大值的函數(shù)。程序清單如下:

#include<stdio.h>intmax_number(intx,inty,intz){intmax;max=x>y?x:y;

max=max>z?max:z;return(max);

}返回本節(jié)目錄7.2.1函數(shù)的定義(6)c語言第7章【例7-3】定義“判斷m是否是素數(shù)”的函數(shù)。【分析】素數(shù)是只能被1和本身整除的數(shù)。判斷一個數(shù)是否是素數(shù),可把數(shù)m用從①2~m-1②2~m/2③2~sqrt(m)范圍內(nèi)的數(shù)逐個去除,若某次除盡則說明m不是素數(shù);否則,m就是素數(shù)。上述判素數(shù)的三種方法中,第三個方法效率最高,第一個方法效率最差,第二個方法居中。下面給出第三個方法的函數(shù),其余兩個方法的函數(shù),請讀者自己完成。在此約定:若m是素數(shù),返回值為1;否則,返回值為0。程序清單如下:intisprime(intm){inti;for(i=2;i<m;++i)if(m%i==0)return(0);return(1);}返回本節(jié)目錄7.2.1函數(shù)的定義(7)c語言第7章【例7-4】定義一個求xn的函數(shù)power,其中x是整數(shù),n是無符號整數(shù)。程序清單如下:longpower(intx,unsignedn){inti;longp;for(i=1,p=1;i<=n;i++)p*=x;returnp;}思考:這里為什么要將p定義成長整型?如果當x和n的值都比較大時,p的類型應(yīng)如何修改?返回本節(jié)目錄7.2.1函數(shù)的定義(8)c語言第7章3.空函數(shù)C語言中,函數(shù)允許有“空函數(shù)”,即函數(shù)體為空的沒有任何作用的函數(shù)。這往往是在程序開發(fā)的開始階段,為了能使編譯、連接順利通過,將該函數(shù)置成一個空函數(shù),僅起占位作用,等以后編寫好函數(shù)后替代它。這樣做的目的,能使程序結(jié)構(gòu)清晰,可讀性好,便于功能擴充,空函數(shù)在程序設(shè)計中經(jīng)常用到??蘸瘮?shù)的一般形式如下:存儲類型數(shù)據(jù)類型函數(shù)名()/*函數(shù)首部*/{}/*函數(shù)體為空*/如dump(){}返回本節(jié)目錄7.2.1函數(shù)的定義(9)c語言第7章7.2.2函數(shù)的參數(shù)與返回值(1)

1.形式參數(shù)和實際參數(shù)函數(shù)的參數(shù)分為形參和實參兩種。定義函數(shù)時函數(shù)名后面括號中的變量名稱為“形式參數(shù)”(簡稱“形參”或“虛參”),調(diào)用函數(shù)時,函數(shù)名后面括號中的參數(shù)稱為“實際參數(shù)”(簡稱“實參”)。形參和實參的作用是數(shù)據(jù)傳送。當發(fā)生函數(shù)調(diào)用時,主調(diào)函數(shù)把實參的值傳送給被調(diào)函數(shù)的形參,從而實現(xiàn)主調(diào)函數(shù)向被調(diào)函數(shù)的數(shù)據(jù)傳送。形參和實參的特點:(1)形參只有在發(fā)生函數(shù)調(diào)用時,系統(tǒng)才為其分配存儲單元。調(diào)用結(jié)束時,即刻釋放所分配的存儲單元。可見,形參只有在函數(shù)內(nèi)部有效。(2)形參可以是變量名、數(shù)組名、指針變量名、指針數(shù)組名等,實參可以是常量、變量、表達式、函數(shù)等。不論實參以何種形式和類型出現(xiàn),但在進行函數(shù)調(diào)用時,要求它們必須具有確定的值,以便把這些值傳送給形參(如果形參是數(shù)組名,則傳遞的是數(shù)組首地址而不是數(shù)組的值。請參閱7.6節(jié))。(3)要求實參和形參數(shù)量相等,順序一致,類型相容或相同。如果類型不相容(或不相同),則按第2章介紹的不同類型數(shù)值的賦值規(guī)則進行轉(zhuǎn)換。返回本節(jié)目錄c語言第7章2.函數(shù)的返回值(1)函數(shù)的值只能通過return語句返回給主調(diào)函數(shù)。return語句的一般形式為:return表達式;或return(表達式);該語句的功能是計算表達式的值,退出被調(diào)函數(shù),返回到主調(diào)處,同時將此表達式的值作為函數(shù)值返回給主調(diào)函數(shù)。注意:在函數(shù)中允許有多個return語句,執(zhí)行到那一個return,那一個return語句起作用,因此只能返回一個函數(shù)值。(2)函數(shù)值的類型和函數(shù)定義中函數(shù)的類型應(yīng)保持一致。如果兩者不一致,則以函數(shù)類型為準,自動進行類型轉(zhuǎn)換。函數(shù)值的類型可以是C語言數(shù)據(jù)類型中的任何一種(如int、char、float、結(jié)構(gòu)體、指針等)。返回本節(jié)目錄7.2.2函數(shù)的參數(shù)與返回值(2)

c語言第7章【例7-5】函數(shù)值類型轉(zhuǎn)換。max(floatx,floaty){floatz;z=x>y?x:y;return(z);}main()圖7-1{floata,b;intc;scanf("%f,%f",&a,&b);c=max(a,b);printf("maxis%d\n",c);getch();}運行結(jié)果如圖7-1所示。圖7-1在C語言中,凡不加類型說明的函數(shù),一律自動按整型處理。例7-5中的函數(shù)max在定義時未加類型說明。故為為整型,而return語句中的z為實型,二者類型不一致。按上述規(guī)定,先將實型z轉(zhuǎn)換為整型,然后由max(x,y)帶回主調(diào)函數(shù)main的max(x,y)處,將此整型值賦給變量C。返回本節(jié)目錄7.2.2函數(shù)的參數(shù)與返回值(3)

c語言第7章(3)不返回函數(shù)值的函數(shù),可以定義為“空類型”,類型說明符為“void”。例如:voids(intn){……}

注意:一旦函數(shù)被定義為空類型后,就不能在主調(diào)函數(shù)中使用被調(diào)函數(shù)的函數(shù)值了。例如,在定義s為空類型后,在主函數(shù)中寫下述語句sum=s(n);就是錯誤的。(4)利用return語句只能向主調(diào)函數(shù)返回一個值,如需要返回多個值,這時用return語句就不能滿足要求了。此時可以考慮用地址傳遞方式(見7.3.2節(jié))或全局外部變量的傳遞方式(見7.3.5節(jié))來實現(xiàn)。返回本節(jié)目錄7.2.2函數(shù)的參數(shù)與返回值(4)

c語言第7章7.2.3函數(shù)的調(diào)用(1)一個函數(shù)被定義后,只有通過調(diào)用該函數(shù)才能實現(xiàn)其功能,否則,函數(shù)在程序中只是一段靜態(tài)程序代碼,永遠不可能被執(zhí)行。1.函數(shù)調(diào)用的一般形式使用已經(jīng)定義好的函數(shù)稱為函數(shù)調(diào)用。在程序中是通過對函數(shù)的調(diào)用來執(zhí)行函數(shù)體,其過程與其它語言的子程序調(diào)用相似。函數(shù)調(diào)用的一般形式是:

函數(shù)名(實際參數(shù)表)/*有參函數(shù)調(diào)用*/或函數(shù)名()/*無參函數(shù)調(diào)用*/實際參數(shù)表中的參數(shù)可以是常數(shù),變量或其它構(gòu)造類型數(shù)據(jù)及表達式。各實參之間用逗號分隔,且要求實參與形參個數(shù)要相等,類型要相容,順序要一致。進行函數(shù)調(diào)用時,應(yīng)注意:(1)被調(diào)函數(shù)必須存在;(2)被調(diào)函數(shù)的定義位置正確。(3)在函數(shù)調(diào)用中,如果實際參數(shù)表中包含多個互相關(guān)聯(lián)的實參,就要特別注意實參表的求值順序問題。所謂求值順序是指對實參表中各量是自左至右求值呢,還是自右至左求值。對此,各系統(tǒng)的規(guī)定不盡相同。大多數(shù)系統(tǒng)(包括TurboC)是右結(jié)合。返回本節(jié)目錄c語言第7章【例7-6】檢驗在TurboC上函數(shù)調(diào)用時實參的求值順序。#include<stdio.h>voidfcall(intx,inty,intz){printf("%d,%d,%d\n",x,y,z);圖7-2printf("%d,%d,%d\n",++x,x++,x);}voidmain(){intx=1;fcall(++x,++x,++x);getch();}運行結(jié)果如圖7-2所示。由此可以看出,TurboC對實參的求值順序是右結(jié)合。編程時應(yīng)盡量避免如本例所舉的這種用法,如果希望按左結(jié)合的順序求實參的值,則可將主程序main()修改如下:圖7-2返回本節(jié)目錄7.2.3函數(shù)的調(diào)用(2)c語言第7章voidmain(){intx=1,i,j,k;

i=++x;j=++x;k=++x;fcall(i,j,k);

getch();}運行結(jié)果如圖7-3所示。

注意:無論是從左至右求值,還是自右至左求值,其輸出順序都是不變的,即輸出順序總是和實參表中實參的順序相同。返回本節(jié)目錄7.2.3函數(shù)的調(diào)用(3)c語言第7章2.函數(shù)調(diào)用的方式在C語言中,按照函數(shù)在程序中出現(xiàn)的位置來分,調(diào)用函數(shù)可以有如下幾種方式:①函數(shù)語句把函數(shù)調(diào)用作為一個語句。格式為:函數(shù)名(實際參數(shù)表);這種方式適用于無返回值的函數(shù)。如printf("%d",a);scanf("%d",&b);等都是以函數(shù)語句的方式調(diào)用函數(shù)。②函數(shù)表達式函數(shù)作為表達式中的一項出現(xiàn)在表達式中,以函數(shù)返回值參與表達式的運算。這種方式要求函數(shù)有返回值。其一般形式為:變量名=函數(shù)表達式;例如:c=max(a,b)是一個賦值表達式,把max的返回值賦予變量c。返回本節(jié)目錄c語言第7章3.調(diào)用函數(shù)的過程③函數(shù)實參

函數(shù)作為另一個函數(shù)調(diào)用的實際參數(shù)出現(xiàn)。這種情況是把該函數(shù)的返回值作為實參進行傳送,因此要求該函數(shù)必須有返回值。例如:printf(“%d”,max(x,y));,是把max調(diào)用的返回值又作為printf函數(shù)的實參來使用的。又如,調(diào)用【例7-1】的max(a,b)函數(shù),求x、y、z的最大值m可寫成:m=max(max(x,y),z)。3.調(diào)用函數(shù)的過程首先,為函數(shù)的所有形式參數(shù)分配存儲單元,再計算所有實參的值,依次賦予對應(yīng)的形參。如果是無參函數(shù),則不執(zhí)行上述工作。然后進入函數(shù)體,為函數(shù)體中的變量分配存儲單元,再執(zhí)行函數(shù)體中的可執(zhí)行語句。當執(zhí)行到“返回語句”時,計算返回值(對無返回值的函數(shù),不存在計算返回值問題),釋放本函數(shù)體中定義的變量(包括形參變量,但靜態(tài)變量不釋放),返回主調(diào)函數(shù)繼續(xù)運行。返回本節(jié)目錄c語言第7章4.對被調(diào)函數(shù)的聲明(1)(1)在調(diào)用系統(tǒng)函數(shù)時,除了少數(shù)系統(tǒng)函數(shù)(如scanf、printf等)外,都要求在程序的開頭用包含命令#include“頭文件名.h”將定義系統(tǒng)函數(shù)的庫文件包含在本程序中。(2)如果主調(diào)函數(shù)和被調(diào)函數(shù)在一個編譯單位中,在書寫順序上被調(diào)函數(shù)在主調(diào)函數(shù)之前出現(xiàn);或者被調(diào)函數(shù)雖然在主調(diào)函數(shù)之后出現(xiàn),但被調(diào)函數(shù)的數(shù)據(jù)類型是字符型或整型,可以不對被調(diào)函數(shù)進行聲明;除上述兩種情況外(即調(diào)用函數(shù)在前,定義函數(shù)在后),都必須對被調(diào)函數(shù)進行聲明。聲明的位置可以在主調(diào)函數(shù)的函數(shù)體開頭的數(shù)據(jù)定義部分,也可以在所有函數(shù)的開頭。返回本節(jié)目錄c語言第7章對被調(diào)函數(shù)的聲明也有兩種格式:①傳統(tǒng)格式,其一般形式為:數(shù)據(jù)類型被調(diào)函數(shù)名();

這種格式只給出函數(shù)返回值的類型,被調(diào)函數(shù)名及一個空括號。這種格式由于在括號中沒有任何參數(shù)信息,因此不便于編譯系統(tǒng)進行錯誤檢查,易于發(fā)生錯誤。②現(xiàn)代格式,其一般形式為:數(shù)據(jù)類型被調(diào)函數(shù)名(類型形參,類型形參…);

或數(shù)據(jù)類型被調(diào)函數(shù)名(類型,類型…);

現(xiàn)代格式的括號內(nèi)給出了形參的類型和形參名,或只給出形參類型。這便于編譯系統(tǒng)進行檢錯,以防止可能出現(xiàn)的錯誤。返回本節(jié)目錄4.對被調(diào)函數(shù)的聲明(2)c語言第7章注意:①對函數(shù)的“定義”和“聲明”不是一回事。“定義”是指確定函數(shù)功能,包括指定函數(shù)名,函數(shù)值類型、形參及其類型、函數(shù)體等,它是一個完整的、獨立的函數(shù)單位。而“聲明”則是對函數(shù)的形參及其類型、個數(shù)、順序、函數(shù)的返回值等(不包括函數(shù)體)通知編譯系統(tǒng),以便在調(diào)用該函數(shù)時系統(tǒng)按此進行對照檢查(例如函數(shù)名是否正確,實參與形參的類型和個數(shù)是否一致)。函數(shù)首部加一個分號→函數(shù)的“聲明”。②在一般情況下,不管主調(diào)函數(shù)和被調(diào)函數(shù)的位置關(guān)系如何,都可以在源程序一開始列出所有函數(shù)的原形聲明,以保證程序結(jié)構(gòu)的一致性。技巧:在程序設(shè)計中,常常將函數(shù)原形聲明和符號常量等存入一個用戶自定義的頭文件中,當別的源程序中需要對這些函數(shù)進行原形聲明時,可以簡單的用#include包含進來(#include的用法見8.1節(jié))。返回本節(jié)目錄4.對被調(diào)函數(shù)的聲明(3)c語言第7章(3)如果主調(diào)函數(shù)和被調(diào)函數(shù)不在一個編譯單位中,則在定義該函數(shù)時用下列方式將該函數(shù)定義成外部函數(shù):extern數(shù)據(jù)類型函數(shù)名(形式參數(shù)表);同時在主調(diào)函數(shù)的函數(shù)體中,或所在編譯單位的開頭將要調(diào)用的函數(shù)聲明成外部函數(shù),聲明格式為:extern數(shù)據(jù)類型被調(diào)函數(shù)名();外部函數(shù)的定義及調(diào)用詳見7.8節(jié)。返回本節(jié)目錄4.對被調(diào)函數(shù)的聲明(4)c語言第7章【例7-7】函數(shù)的定義及調(diào)用。max(floatx,floaty){floatz;z=x>y?x:y;return(z);}voidmain()/*定義主函數(shù)main()*/{floatx,y,z;clrscr();/*清屏*/printf("\ninputtwonumbers:\n");scanf("%4f%4f",&x,&y);z=max(x,y);/*調(diào)用子函數(shù)max*/printf("maxnum=%f",z);getch();}返回本節(jié)目錄4.對被調(diào)函數(shù)的聲明(5)c語言第7章7.3函數(shù)調(diào)用中的數(shù)據(jù)傳遞方式7.3.1值傳遞方式7.3.2地址傳遞方式7.3.3值傳遞方式和地址傳遞方式的差異7.3.4返回值方式7.3.5全局外部變量的傳遞方式函數(shù)調(diào)用中的數(shù)據(jù)傳遞是函數(shù)使用中比較困難的問題。在C語言中,函數(shù)間的數(shù)據(jù)傳遞有四種方式:值傳遞方式、地址傳遞方式、返回值方式和全局變量傳遞方式。其中前兩種是利用函數(shù)的參數(shù)來傳遞數(shù)據(jù)的;后兩種方式不是利用函數(shù)參數(shù)來傳遞數(shù)據(jù)的。返回目錄c語言第7章7.3.1值傳遞方式(1)值傳遞方式是在形式參數(shù)和實際參數(shù)之間傳遞數(shù)據(jù)的一種方式。值傳遞方式所傳遞的是參數(shù)值。當形參是變量名時,實參可以是常數(shù)、已賦值的變量名或數(shù)組元素名、表達式、函數(shù)等。在調(diào)用函數(shù)時,系統(tǒng)為形參自動分配存儲單元,并將實參對應(yīng)的值傳遞給形參,在函數(shù)體中對形參的加工與實際參數(shù)已完全脫離關(guān)系。調(diào)用結(jié)束后,形參單元被釋放,其值將丟失,實參單元仍保留并維持原值。因此,在執(zhí)行一個被調(diào)用函數(shù)時,形參的值如果發(fā)生改變,并不會改變主調(diào)函數(shù)中實參的值??梢姡祩鬟f的特點是參數(shù)值的單向傳遞,即只能由實參傳給形參,而不能由形參傳回給實參,在內(nèi)存中,實參單元與形參單元是不同的單元。

返回本節(jié)目錄c語言第7章【例7-8】值傳遞舉例。下面的代碼試圖實現(xiàn)數(shù)據(jù)的交換,請分析程序特點,指出能否實現(xiàn)數(shù)據(jù)交換。#include"stdio.h"voidsf1,floatf2);main(){floatx,y;x=3.0;y=5.0;

printf("\nBeforecall:x=%fy=%f",x,y);s);圖7-4printf("\nAftercall:x=%fy=%f\n",x,y);getch();}voidsf1,floatf2){floattemp;temp=f1;f1=f2;f2=temp;}運行結(jié)果如圖7-4所示。圖7-4返回本節(jié)目錄7.3.1值傳遞方式(2)c語言第7章【分析】本程序中定義了一個函數(shù)swap,該函數(shù)的功能是交換兩個變量的值。但從運行結(jié)果看,變量x和y的值并沒有被交換,這是由于本程序采用的是值傳遞方式,所以不能實現(xiàn)數(shù)據(jù)的交換。因為當發(fā)生函數(shù)調(diào)用時,系統(tǒng)為形參開辟存儲單元,然后將實參傳遞給對應(yīng)的形參,形參和實參分別占用不同的存儲單元,被調(diào)函數(shù)對形參的操作只在這些臨時分配的存儲單元上進行,調(diào)用結(jié)束時,形參所占用的存儲單元將被立即釋放,不會影響實參的值。所以,盡管函數(shù)swap確實交換了形參f1和f2的值,但對實參x和y沒有絲毫影響,最終未能實現(xiàn)數(shù)據(jù)交換??梢姡瑢崊⒆兞繉π螀⒆兞康臄?shù)據(jù)傳遞都是“值傳遞”,即單向傳遞,只由實參傳給形參,而不能由形參傳回來給實參。本程序的詳細執(zhí)行如圖7-5所示。

返回本節(jié)目錄7.3.1值傳遞方式(3)c語言第7章圖7-5返回本節(jié)目錄7.3.1值傳遞方式(4)c語言第7章7.3.2地址傳遞方式(1)地址傳遞方式也是在形式參數(shù)和實際參數(shù)之間傳遞數(shù)據(jù)的一種方式。地址傳遞方式所傳遞的是地址。當形參是地址(如數(shù)組名、指針變量)時,實參只能是變量的地址、數(shù)組名(數(shù)組首地址)或指針變量等,此時,參數(shù)的傳遞按地址傳遞方式進行,即調(diào)用函數(shù)時,將實參地址傳遞給對應(yīng)的形參。由于形參和實參的地址相同(即它們占用相同的內(nèi)存單元),所以對形參的操作相當于對實參的操作,故可以這樣認為:調(diào)用時,可以看成是將實參的值傳給形參;返回時,可以看成是將形參的值帶給對應(yīng)的實參??梢姡刂穫鬟f方式的特點是參數(shù)值是雙向傳遞的。返回本節(jié)目錄c語言第7章【例7-9】地址傳遞舉例。下面的代碼試圖實現(xiàn)數(shù)據(jù)的交換,請分析程序特點,指出能否實現(xiàn)數(shù)據(jù)交換。#include"stdio.h"voidswap1(float*f1,float*f2);main(){floatx,y;x=3.0;y=5.0;

printf("\nBeforecall:x=%fy=%f",x,y);swap1(&x,&y);printf("\nAftercall:x=%fy=%f\n",x,y);getch();}voidswap1(float*f1,float*f2)/*形參為實型指針變量,以便接受地址值*/{floattemp;temp=*f1;*f1=*f2;*f2=temp;}運行結(jié)果如圖7-6所示。圖7-6返回本節(jié)目錄7.3.2地址傳遞方式(2)c語言第7章【分析】本例與例7-8的最大區(qū)別在于:本程序中定義的函數(shù)swap1,其形參為指針變量(詳見第9章),故參數(shù)的傳遞方式為地址傳遞方式。調(diào)用函數(shù)時,將實參地址&x和&y傳遞給對應(yīng)的形參f1和f2。由于形參和實參共用相同的存儲單元,所以對形參的操作相當于對實參的操作。調(diào)用結(jié)束后,盡管形參被釋放,但其值通過實參保留下來,實現(xiàn)了數(shù)據(jù)的雙向傳遞,最終完成了數(shù)據(jù)交換。本程序的詳細執(zhí)行如圖7-7所示。圖7-7返回本節(jié)目錄7.3.2地址傳遞方式(3)c語言第7章7.3.3值傳遞方式和地址傳遞方式的差異值傳遞和地址傳遞方式都是在實際參數(shù)和形式參數(shù)之間傳遞數(shù)據(jù)。惟一的區(qū)別是值傳遞方式傳遞的是數(shù)值,而地址傳遞方式傳遞的是地址值。值傳遞方式是將實際參數(shù)的值傳遞給對應(yīng)的形式參數(shù),形式參數(shù)應(yīng)分配存儲單元,數(shù)據(jù)的傳遞是單向的,只能從主調(diào)函數(shù)向被調(diào)函數(shù)傳遞,其形式參數(shù)一般是變量,實際參數(shù)是變量或表達式。地址傳遞方式是將實際參數(shù)的地址值傳遞給對應(yīng)的形式參數(shù)(必須能接受地址值),如果形式參數(shù)是數(shù)組將不再分配內(nèi)存單元。接受地址值的形式參數(shù)一般是指針變量或數(shù)組名,實際參數(shù)可以是地址、數(shù)組名或存放地址值的指針變量。形式參數(shù)的地址等于實際參數(shù)對應(yīng)的地址,即它們對應(yīng)的變量或數(shù)組將占用相同的內(nèi)存單元。在被調(diào)函數(shù)中使用的是形式參數(shù)的名稱,在主調(diào)函數(shù)中使用的是實際參數(shù)的名稱。由于我們關(guān)心的傳遞對象是數(shù)據(jù),所以可以理解成(相同內(nèi)存中的)數(shù)據(jù)傳遞是雙向的。返回本節(jié)目錄c語言第7章7.3.4返回值方式返回值方式不是在形參和實參之間傳遞數(shù)據(jù),而是通過函數(shù)調(diào)用后直接返回一個值到主調(diào)函數(shù)中。因此這種方式通常適用于從被調(diào)函數(shù)中將一個值傳回到主調(diào)函數(shù)。利用返回值方式傳遞數(shù)據(jù),在定義函數(shù)時一定要注意如下兩點:函數(shù)頭(首部)中要有“數(shù)據(jù)類型說明符”,說明該函數(shù)返回值的數(shù)據(jù)類型。函數(shù)體中要有“return(表達式);”語句,其中表達式的值就是函數(shù)的返回值。返回本節(jié)目錄c語言第7章7.3.5全局外部變量的傳遞方式全局外部變量的傳遞方式也不是在形參和實參之間傳遞數(shù)據(jù),而是借助在主調(diào)函數(shù)和被調(diào)函數(shù)均有效的全局外部變量,完成數(shù)據(jù)在主調(diào)函數(shù)和被調(diào)函數(shù)之間的數(shù)據(jù)傳遞。所謂全局變量是指從定義點開始到整個程序結(jié)束均有效的變量。具體來說,全局變量有兩種:一種是在任何函數(shù)外定義的變量,它的作用域覆蓋了定義點到程序結(jié)尾之間的所有函數(shù),這種全局變量叫做“外部變量”;另一種是在函數(shù)體內(nèi)定義為“靜態(tài)型”的變量,這種變量在從函數(shù)返回后,仍保留所分配的內(nèi)存單元,但是不能使用,它的作用域仍為該函數(shù)體內(nèi),這種全局變量叫做“內(nèi)部變量”。由此可以看出:在函數(shù)之間利用全局變量傳遞數(shù)據(jù),只能使用“外部變量”。返回本節(jié)目錄c語言第7章全局外部變量在函數(shù)間是如何傳遞數(shù)據(jù)的【例7-10】輸入球的半徑,計算球的體積V及表面積S。程序清單如下:floatV,S;/*定義全局外部變量V和S*/main(){voidf(floatx);floatr;clrscr();printf("\nr=");scanf("%f",&r);f(r);printf("r=%6.2f,v=%6.2f,s=%6.2f",r,V,S);getch();}voidf(floatx){V=4*3.14*x*x*x/3;S=4*3.14*x*x;return;}運行結(jié)果在本程序中,定義了兩個外部變量V和S,分別用來存放球的體積和表面積,其作用域為整個程序。函數(shù)f用來求球的體積V及表面積S。由主函數(shù)完成球的半徑的輸入及結(jié)果的輸出。由于C語言規(guī)定通過函數(shù)的調(diào)用只能帶回一個返回值,因此,當需要從函數(shù)得到一個以上的返回值時,用外部變量就是一種很好的選擇。本例中,由于將計算球的體積V及表面積S的函數(shù)f定義成無返回值的函數(shù),如不使用外部變量,在主函數(shù)中就不可能取得V和S兩個值。而用外部變量,在函數(shù)f中求得的V和S值在main中仍然有效。因此外部變量是實現(xiàn)函數(shù)之間數(shù)據(jù)傳遞的有效手段之一。當然,如果將函數(shù)f的類型定義成float,則V和S兩個值中的一個可通過return返回給主調(diào)函數(shù),另一個只需通過一個外部變量傳回其值,從而可以減少一個外部變量。注意:如果將定義全局外部變量的語句(程序中的第一條語句)移到主函數(shù)和f函數(shù)之間,由于它們的作用域只是定義點到程序末尾,則主函數(shù)中出現(xiàn)的V和S變量將沒有定義,程序會出現(xiàn)錯誤。在同一源文件中,如果全局外部變量和局部變量重名,則C語言規(guī)定局部變量優(yōu)先,即在局部變量的作用域內(nèi),全局外部變量不起作用。返回本節(jié)目錄c語言第7章【例7-11】全局外部變量和局部變量重名的例子?!痉治觥吭诒境绦蛑校旱?行定義了兩個外部變量x、y,并對其初始化。第2行開始定義了一個名為min的函數(shù),x和y是其形參且屬于局部變量。函數(shù)min中的x、y不是外部變量x、y,它們的值是由實參傳給形參的,外部變量x、y在min函數(shù)范圍內(nèi)不起作用。在main函數(shù)中,定義了一個局部變量x,因此全局變量x在main函數(shù)范圍內(nèi)不起作用,而全局變量y在此范圍內(nèi)有效。因此printf函數(shù)中的min(x,y)相當于min(-1,3),程序運行后得到結(jié)果為min=-1。雖然利用全局外部變量可以在函數(shù)間傳遞數(shù)據(jù),但從結(jié)構(gòu)化程序設(shè)計的角度來說,并不推薦使用這種方式,因為:①全局變量在程序的全部執(zhí)行過程中都占用存儲單元,而不是僅在需要時才開辟單元。②它破壞了程序的模塊化結(jié)構(gòu),不滿足程序設(shè)計中模塊劃分原則——內(nèi)聚性強、耦合性弱,在程序模塊(函數(shù))中無法確定某些全局外部變量的屬性,必須在模塊(函數(shù))之外去尋找,造成了程序的可讀性差的缺點。因此,在C程序設(shè)計中,要盡量限制使用全局變量。返回本節(jié)目錄c語言第7章C語言中,函數(shù)的定義是互相平行的、獨立的,不存在上一級函數(shù)和下一級函數(shù)的問題,也就是說,不允許有嵌套的函數(shù)定義。但允許在一個函數(shù)的定義中出現(xiàn)對另一個函數(shù)的調(diào)用,我們把這種情況稱為函數(shù)的嵌套調(diào)用。這和其它高級語言中的子程序嵌套調(diào)用的情形相類似。其調(diào)用關(guān)系如圖7-9所示。圖7-97.4函數(shù)的嵌套調(diào)用(1)返回目錄c語言第7章【例7-12】編寫函數(shù)mysum,用以求其中f(i)=i+5。程序清單如下:intmysum(intn);intmyf(inti);main(){intn;clrscr();printf("\ninputn=?");scanf("%d",&n);printf("n=%d,s=%d\n",n,mysum(n));getch();}intmysum(intn){inti,s=0;for(i=0;i<=n;i++)

s=s+myf(i);returns;}

intmyf(inti){returni+5;}本例的程序段是一個典型的兩層嵌套調(diào)用,其執(zhí)行過程是:在執(zhí)行主函數(shù)時,遇到函數(shù)調(diào)用mysum(n)時,即轉(zhuǎn)去執(zhí)行mysum函數(shù),在mysum函數(shù)中調(diào)用myf(i)函數(shù)時,又轉(zhuǎn)去執(zhí)行myf函數(shù),myf函數(shù)執(zhí)行完畢返回mysum函數(shù)的斷點繼續(xù)執(zhí)行,mysum函數(shù)執(zhí)行完畢返回主函數(shù)的斷點繼續(xù)執(zhí)行,直至結(jié)束。執(zhí)行結(jié)果如右圖。返回目錄7.4函數(shù)的嵌套調(diào)用(2)c語言第7章原則上講,C語言不限制嵌套調(diào)用的層數(shù),嵌套調(diào)用的層數(shù)僅受計算機內(nèi)存的限制。函數(shù)嵌套調(diào)用時,如果使用不當,也會造成死循環(huán)。如【例7-13】中,主函數(shù)調(diào)用函數(shù)f1,函數(shù)f1調(diào)用函數(shù)f2,函數(shù)f2調(diào)用函數(shù)f3,而函數(shù)f3又調(diào)用函數(shù)f1,形成環(huán)路,但未給定退出循環(huán)調(diào)用的條件,因而造成死循環(huán)?!纠?-13】使用不當?shù)难h(huán)調(diào)用。voidf1(inta,intb);voidf2(inta,intb);voidf3(inta,intb);voidmain(){f1(5,10);}voidf1(inta,intb){f2(a,b);}voidf2(inta,intb){f3(a,b);}voidf3(inta,intb){f1(a,b);}返回目錄7.4函數(shù)的嵌套調(diào)用(3)c語言第7章函數(shù)除了可以調(diào)用別的函數(shù)之外,還可以自己調(diào)用自己(包括主函數(shù)),一個函數(shù)在它的函數(shù)體內(nèi)直接或間接的自己調(diào)用自己稱為遞歸調(diào)用,這種函數(shù)稱為遞歸函數(shù)。C語言允許函數(shù)遞歸調(diào)用。合理的使用遞歸調(diào)用,可以使求解的問題變得簡潔明了,易于理解。遞歸調(diào)用有直接遞歸調(diào)用和間接遞歸調(diào)用兩種。7.5函數(shù)的遞歸調(diào)用(1)返回目錄c語言第7章遞歸調(diào)用是嵌套調(diào)用的一種特殊情形,其本質(zhì)是一種“循環(huán)”,所以,當遞歸終止條件沒有設(shè)置或設(shè)置不當都會引起稱之為“無限遞歸”的死循環(huán)。因此在使用遞歸調(diào)用時,必須控制其遞歸調(diào)用的次數(shù)或給定終止調(diào)用的條件?!纠?-14】用遞歸法計算n!分析:根椐數(shù)學知識,0!=1,正整數(shù)n的階乘為:n*(n-1)*(n-2)*…*2*1,該階乘序列可轉(zhuǎn)換為求n*(n-1)!,而(n-1)!以可轉(zhuǎn)換為(n-1)*(n-2)!,……,直至轉(zhuǎn)換為1*0!,而0!=1。故求n!的遞歸定義可表示為:很明顯,在n!的定義中又用到了自身定義(n-1)!,因而這是一個遞歸定義。n!的遞歸定義說明了兩個事實:(1)(0!)=1是一個邊界條件,指出了遞歸過程的終結(jié)點;(2)要解n!,必須先求出(n-1)!的結(jié)果,要解(n-1)!又必須先求出(n-2)!的結(jié)果,……。這是一個遞歸公式,它將引起遞歸操作;根據(jù)階乘的遞歸定義,容易得到遞歸函數(shù)定義:其中fact是函數(shù)名,fact(n)表示n!。程序清單如下:#include<stdio.h>floatfact(inti);voidmain(){intn;floaty;

clrscr();printf("\ninputn=?");scanf("%d",&n);

y=fact(n);printf("%d!=%f",n,y);

getch();}floatfact(inti){floatnf;if(i<0){printf("n<0,dataerror!\n");exit(1);/*中止運行*/}elseif(i==0||i==1)nf=1;elsenf=fact(i-1)*i;returnnf;}遞歸求解分為兩個階段。第一個階段是“遞推”,第二個階段是“回推”。以本例為例,當n=5時,其求解過程如圖7-11所示(見下頁)。遞歸過程的關(guān)鍵在于每次遞歸時,參數(shù)的值都要趨向某個特定值(本例中此特定值為0)。當遞歸到參數(shù)值等于特定值時,遞推過程結(jié)束,此時一定要有返回值?;赝七^程比較簡單,由于最后一次遞歸有返回值,則回推到上一次遞歸時,就可以計算出該次遞歸的返回值。依此類推,回推到第一次遞歸,獲得返回值,則回推過程結(jié)束。圖7-11從程序設(shè)計的角度來講,遞歸過程必須解決兩個問題,一是遞歸計算公式,二是遞歸結(jié)束條件。在本例中,這兩個公式分別是:遞歸計算公式

fact(n)=n*fact(n-1)遞歸結(jié)束條件

fact(0)=1在程序設(shè)計中,這兩個條件可采用雙分支語句來實現(xiàn):if(遞歸結(jié)束條件)return(遞歸結(jié)束條件中的返回值);elsereturn(遞歸計算公式);某些遞歸函數(shù)可以利用局部靜態(tài)變量設(shè)計成非遞歸調(diào)用函數(shù),如例7-15。返回目錄7.5函數(shù)的遞歸調(diào)用(2)c語言第7章【例7-15】不用遞歸調(diào)用方法,編一個計算n!的函數(shù),在主函數(shù)中調(diào)用該函數(shù)分別計算1!、2!、…、n!(n值通過鍵盤輸入)。程序清單如下:#include<stdio.h>floatfact(inti);voidmain()/*主函數(shù)*/{intn,i;floaty;clrscr();printf("\ninputn=?");scanf("%d",&n);/*輸入n*/if(n<0)/*判n的合法性*/{printf("\nn<0,dataerror!\n");getch();exit(1);/*中止運行*/}for(i=1;i<=n;i++){y=fact(i);/*調(diào)用fact(),輸出i!*/printf("%d!=%f\n",i,y);}getch();}floatfact(inti)/*非遞歸調(diào)用方式求n!的函數(shù)*/{staticfloatnf=1.0;/*定義局部靜態(tài)變量并初始化*/nf=nf*i;

/*計算nf*i的值并存儲在nf中*/returnnf;/*返回變量nf的值*/}當n=5時,運行結(jié)果如下返回目錄7.5函數(shù)的遞歸調(diào)用(3)c語言第7章本例中函數(shù)fact()沒有采用遞歸設(shè)計方法,而是利用主函數(shù)中的循環(huán)方式和靜態(tài)變量來計算n!。當然,如果不利用靜態(tài)變量來計算n!,也可以用如下的遞推法來計算n!,效果相同。floatfact(inti){floatnf=1.0;

intk;for(k=1;k<=i;k++)

nf=nf*k;returnnf;}思考:①上述兩種求n!的方法,哪種效率更高?為什么?②為何要將求階乘的函數(shù)類型設(shè)置成float?返回目錄7.5函數(shù)的遞歸調(diào)用(4)c語言第7章【例7-17】主函數(shù)的遞歸調(diào)用#include<stdio.h>voidmain(void){intc;if((c=getchar())!='\n'){main();printf("%c",c);}}本例執(zhí)行的結(jié)果是:將輸入的非Enter鍵所對應(yīng)的字符序列按反序輸出。返回目錄7.5函數(shù)的遞歸調(diào)用(5)c語言第7章

遞歸是程序設(shè)計中一個強有力的工具。使用該工具設(shè)計的程序,不僅算法簡單,結(jié)構(gòu)清晰,可讀性強,而且正確性容易得到驗證。但與此同時必須注意,遞歸技術(shù)的運用,是以犧牲計算機內(nèi)存空間和程序執(zhí)行速度為代價的,因此,解決同一問題時,可以用非遞歸方法實現(xiàn)的就盡量不用遞歸方法實現(xiàn),尤其是問題的規(guī)模大時,更是如此。返回目錄7.5函數(shù)的遞歸調(diào)用(6)c語言第7章7.6數(shù)組作函數(shù)的參數(shù)數(shù)組可以作為函數(shù)的參數(shù)使用,進行數(shù)據(jù)傳送。數(shù)組用作函數(shù)參數(shù)有兩種形式,一種是把數(shù)組元素(下標變量)作為實參使用(值傳遞);另一種是把數(shù)組名作為函數(shù)的形參和實參使用(地址傳遞)。7.6.1數(shù)組元素作函數(shù)實參7.6.2數(shù)組名作函數(shù)參數(shù)返回目錄c語言第7章7.6.1數(shù)組元素作函數(shù)實參(1)主調(diào)函數(shù)的參數(shù)可以是常量、變量、表達式等,而數(shù)組元素可以是表達式的組成部分,因此,數(shù)組元素當然可以作為函數(shù)的實參。與用變量作實參一樣,在發(fā)生函數(shù)調(diào)用時,把作為實參的數(shù)組元素的值傳送給形參,實現(xiàn)單向的值傳送。返回本節(jié)目錄c語言第7章【例7-18】數(shù)組元素作函數(shù)實參。voidadd(intx){x+=1;}main(){inti,a[4]={1,2,3,4};for(i=0;i<4;i++)add(a[i]);for(i=0;i<4;i++)printf("%d",a[i]);getch();}圖7-16可以看出:在數(shù)組元素作函數(shù)實參的情況下,所進行的值傳遞是單向的,即只能由實參傳給形參,不能從形參傳回實參,實參和形參的初值相同,當形參發(fā)生改變后,實參的值不會發(fā)生改變,因為實參和形參分屬于兩個不同的內(nèi)存單元。返回本節(jié)目錄7.6.1數(shù)組元素作函數(shù)實參(2)c語言第7章7.6.2數(shù)組名作函數(shù)參數(shù)(1)

數(shù)組名作函數(shù)參數(shù)時,要求實參和形參都使用數(shù)組名(或用指針變量,見第8章),且數(shù)組的類型必須相同。我們曾介紹過,數(shù)組名就是數(shù)組的首地址。因此,在數(shù)組名作函數(shù)參數(shù)時所進行的傳送是地址的傳送,也就是說把實參數(shù)組的首地址賦予形參數(shù)組名。形參數(shù)組名取得該首地址之后,也就等于有了實在的數(shù)組。實際上是形參數(shù)組和實參數(shù)組為同一數(shù)組,共同擁有同一段內(nèi)存空間,因此被調(diào)函數(shù)對形參數(shù)組元素的改變,在返回到主調(diào)函數(shù)時,將會影響到主調(diào)函數(shù)中數(shù)組元素的內(nèi)容。返回本節(jié)目錄c語言第7章【例7-19】數(shù)組名作函數(shù)參數(shù)。voidadd(intp[4]){inti;for(i=0;i<4;i++)p[i]+=1;}main()圖7-17{inti,a[4]={1,2,3,4};add(a);for(i=0;i<4;i++)printf("%d",a[i]);getch();}在本例中,實參和形參均為同類型的一維整型數(shù)組。當主函數(shù)以一維整型數(shù)組名a為實參調(diào)用add函數(shù)時,實參和形參之間進行了地址傳送,把實參參數(shù)組a的首地址傳送給形參數(shù)組名p,使得形參數(shù)組p和實參數(shù)組a為同一數(shù)組,共同擁有一段內(nèi)存空間,因此,在被調(diào)函數(shù)add中,對形參數(shù)組元素逐個增1,在返回到主調(diào)函數(shù)main()后,再輸出a數(shù)組元素的值,將不再是原來的1、2、3、4,而是2、3、4、5??梢?,數(shù)組名作函數(shù)參數(shù),由于實參和形參為同一數(shù)組,故當形參數(shù)組發(fā)生變化時,實參數(shù)組也隨之發(fā)生變化。這一點是與變量做函數(shù)參數(shù)的情況不相同的,務(wù)請注意。在程序設(shè)計中可以有意識地利用這一特點改變實參數(shù)組元素的值(如排序)。返回本節(jié)目錄7.6.2數(shù)組名作函數(shù)參數(shù)(2)c語言第7章【例7-20】定義一個用“冒泡排序法”按值從小到大的原則為一維數(shù)組中的元素排序的函數(shù)。冒泡排序算法見【例6-7】。“冒泡排序法”的函數(shù)定義如下:voidBubble_sort(inta[],intn){inti,j,t;for(i=0;i<n-1;i++)

/*通過i的變化,控制n-1輪比較過程*/for(j=0;j<(n-1)-i;j++)

/*通過0≤j<(n-1)-i來實現(xiàn)第i輪的比較過程*/

if(a[j]>a[j+1]){t=a[j];a[j]=a[j+1];a[j+1]=t;}

/*若a[j]>a[j+1],交換之*/}主函數(shù)如下:#defineN100voidmain(void){inti,a[N];/*a是有N個元素的”排序樣本”*/for(i=0;i<N;i++)scanf(“%d”,&a[i]);/*輸入數(shù)據(jù)*/Bubble_sort(a,N);/*對a數(shù)組進行排序操作*/printf("Thesortednumbers:");for(i=0;i<N;i++)printf("%d",a[i]);/*輸出排序好的數(shù)組*/printf("\n");}返回本節(jié)目錄7.6.2數(shù)組名作函數(shù)參數(shù)(3)c語言第7章用數(shù)組名作為函數(shù)參數(shù)時還應(yīng)注意以下幾點:(1)形參數(shù)組和實參數(shù)組的類型必須一致,否則將出錯。(2)形參數(shù)組和實參數(shù)組的大小可以相同,也可以不同,因為在調(diào)用時,c編譯程序?qū)π螀?shù)組的大小不做檢查,只是將實參數(shù)組的首地址傳給形參數(shù)組。故當形參數(shù)組的長度與實參數(shù)組不一致時,雖不至于出現(xiàn)語法錯誤(編譯能通過),但程序執(zhí)行結(jié)果將與實際不符,這是應(yīng)予以注意的。(3)可以不指定形參數(shù)組的大小,在定義數(shù)組時在數(shù)組名后面跟一個空的方括弧。為了適應(yīng)被調(diào)用函數(shù)中處理數(shù)組元素的需要,可以另設(shè)一個參數(shù),傳遞數(shù)組元素的個數(shù)。(4)多維數(shù)組名也可以作為函數(shù)的參數(shù)。在函數(shù)定義時對形參數(shù)組可以指定每一維的長度,也可省去第一維的長度。因此,以下寫法都是合法的。

intma(inta[3][10])或intma(inta[][10])

返回本節(jié)目錄7.6.2數(shù)組名作函數(shù)參數(shù)(4)c語言第7章【例7-22】在被調(diào)函數(shù)中訪問主調(diào)函數(shù)中定義的二維數(shù)組的例子。#include<stdio.h>voidmodify(intx[3][4])/*x[3][4]還可以寫成x[][4]*/{inti,j;for(i=0;i<3;i++)for(j=0;j<4;j++)x[i][j]*=3;/*在被調(diào)函數(shù)中修改主調(diào)函數(shù)中定義的數(shù)組*/}main(){inti,j,a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};clrscr();modify(a);/*調(diào)用修改a數(shù)組元素值的函數(shù)*/for(i=0;i<3;i++){for(j=0;j<4;j++)printf("%-4d",a[i][j]);printf("\n");}getch();}圖7-18返回本節(jié)目錄7.6.2數(shù)組名作函數(shù)參數(shù)(5)c語言第7章(5)字符數(shù)組名也可以作為函數(shù)的參數(shù)。【例7-24】定義按ASCII碼值比較兩個字符串大小的函數(shù)strcmp(),當a串等于b串時,函數(shù)值等于0,當a串大于b串時,函數(shù)值大于0,當a串小于b串時,函數(shù)值小于0。程序清單如下:intstrcmp(chara[],charb[]){inti;for(i=0;a[i]&&b[i];i++)if(a[i]!=b[i])return(a[i]-b[i]);return(a[i]-b[i]);}圖7-20main(){charc1[10],c2[10];printf("Enterastring:\n");scanf("%s%s",c1,c2);printf("%d\n",strcmp(c1,c2));}運行結(jié)果如圖7-20所示。圖7-20返回本節(jié)目錄7.6.2數(shù)組名作函數(shù)參數(shù)(6)c語言第7章7.7變量的作用域與存儲類型(1)7.7.1變量的作用域與生存期在C語言中,變量的定義地點十分靈活,既可以在函數(shù)(或復合語句)內(nèi)部,也可以在函數(shù)外部。我們把在函數(shù)(或復合語句)內(nèi)定義的變量稱為內(nèi)部變量,把在函數(shù)外定義的變量稱為外部變量。每種變量都有一個從開始分配內(nèi)存單元(或寄存器單元)到最終的內(nèi)存單元(或寄存器單元)被釋放的過程,我們將此稱為變量的生存期。而把在生存期內(nèi)變量起作用的范圍稱為變量的作用域。任何變量只能在其作用域范圍內(nèi)使用,否則,在作用域外使用必將出錯。按作用域的范圍,可將變量分為局部變量和全局變量。凡是在函數(shù)內(nèi)部定義的變量都是局部變量,包括函數(shù)內(nèi)部復合語句中定義的變量和函數(shù)的形式參數(shù)。而在函數(shù)外部任何位置上定義的變量都屬于全局變量。局部變量的作用域從定義位置起至函數(shù)體或復合語句結(jié)束為止;全局變量的作用域從定義點開始到源文件結(jié)束為止。返回目錄c語言第7章顯然,變量的作用域不但與變量的性質(zhì)(局部還是全局)有關(guān),也與定義的具體位置有關(guān)。因此,不要誤以為局部變量的作用域范圍一定就比全局變量的作用域范圍小。作用域和生存期有聯(lián)系但不是同一回事,圖7-22是作用域的示意圖,圖7-23是生存期的示意圖。如果一個變量在某個文件或函數(shù)范圍內(nèi)是有效的,則稱該文件或函數(shù)為該變量的作用域,在此作用域內(nèi)可以引用該變量,所以又稱變量在此作用域內(nèi)“可見”,這種性質(zhì)又稱為變量的“可見性”,例如圖7-22中變量a、b在函數(shù)fl中“可見”。如果一個變量值在某一時刻是存在的,則認為這一時刻屬于該變量的“生存期”,或稱該變量在此時刻“存在”。自動變量和寄存器變量在函數(shù)內(nèi)外的“可見性”和“存在性”是一致的,即離開函數(shù)后,值不能被引用,值也不存在。靜態(tài)外部變量和外部變量的可見性和存在性也是一致的,在離開函數(shù)后變量值仍存在,且可被引用,而靜態(tài)局部變量的可見性和存在性不一致,離開函數(shù)后,變量值存在,但不能被引用。

返回目錄7.7變量的作用域與存儲類型(2)c語言第7章圖7-22圖7-23返回目錄7.7變量的作用域與存儲類型(3)c語言第7章7.7.2變量的存儲類型(1)存儲類別屬性規(guī)定了變量的存儲方式和存儲位置(內(nèi)存或寄存器),具體包括四種:auto(自動)、register(寄存器)、extern(外部)、static(靜態(tài))。內(nèi)存中供用戶使用的存儲空間可劃分為程序區(qū)和數(shù)據(jù)區(qū),數(shù)據(jù)區(qū)又可劃分為靜態(tài)存儲區(qū)和動態(tài)存儲區(qū)兩部分。存儲方式有靜態(tài)和動態(tài)兩種,靜態(tài)存儲方式是指在程序運行期間分配固定的存儲空間的方式,而動態(tài)存儲方式是指在程序運行期間根據(jù)需要進行動態(tài)的分配存儲空間的方式。用靜態(tài)方式存儲的變量稱為靜態(tài)變量;用動態(tài)方式存儲的變量稱為動態(tài)變量。系統(tǒng)總是將沒有賦初值的靜態(tài)變量初始化0,而不將動態(tài)變量初始化。因此,如果動態(tài)變量未賦初值,則其值是不確定的。自動變量和寄存器變量屬于動態(tài)存儲方式,外部變量和靜態(tài)變量屬于靜態(tài)存儲方式。返回目錄c語言第7章定義變量存儲類型的語句格式如下:

存儲類別說明符數(shù)據(jù)類型說明符變量名1,變量名2,…,變量名n;1.auto(自動)這種存儲類型是C語言程序中使用最廣泛的一種類型。C語言規(guī)定,函數(shù)內(nèi)凡未加存儲類型說明的變量均被視為自動變量,也就是說自動變量可省略說明符auto。前面程序中所定義的變量凡未加存儲類型說明符的都是自動變量。例如inta,b,c;/*默認為自動存儲類別的自動變量*/autointa,b,c;/*顯式聲明自動變量*/兩者是等價的。自動變量是動態(tài)變量,采用動態(tài)存儲方式,數(shù)據(jù)存儲在動態(tài)存儲區(qū)中,這決定了函數(shù)中聲明的自動變量,只在函數(shù)被調(diào)用時才生成,函數(shù)返回時就立即消失了。返回目錄7.7.2變量的存儲類型(2)c語言第7章2.register(寄存器)寄存器是計算機CPU中的重要部件,數(shù)量很少,計算機中的數(shù)據(jù)操作最終是在寄存器中完成的。如果將變量聲明成寄存器存儲類別,就可直接將變量存放在寄存器中,從而避免了因反復讀寫內(nèi)存而使得操作速度下降,提高了系統(tǒng)效率。故對于循環(huán)次數(shù)較多的循環(huán)控制變量及循環(huán)體內(nèi)反復使用的變量均可定義為寄存器變量。對現(xiàn)代C編譯器而言,寄存器存儲類別不是必須的,因為,編譯器會根據(jù)變量使用的頻繁程度自動安排變量的寄存器存儲類別。與自動變量一樣,寄存器變量也是動態(tài)變量,采用動態(tài)存儲方式。兩者的最大不同是它們存放的位置不同,一個存放在內(nèi)存中,而另一個存放在寄存器中。注意:只有局部自動變量和形式參數(shù)才可以定義為寄存器變量,凡需要采用靜態(tài)存儲方式的量不能定義為寄存器變量;在TurboC,MSC等C語言環(huán)境中,實際上是把寄存器變量當作自動變量處理的,因此速度并不能提高。返回目錄7.7.2變量的存儲類型(3)c語言第7章3.static(靜態(tài))1)靜態(tài)局部變量靜態(tài)局部變量采用靜態(tài)存儲方式,屬于靜態(tài)存儲類別,編譯時在靜態(tài)存儲區(qū)內(nèi)系統(tǒng)為其分配固定的存儲單元并賦初值,如果在定義靜態(tài)局部變量時未賦初值,則編譯系統(tǒng)自動賦初值0(對數(shù)值型變量)或空字符(對字符變量),且在在程序的運行過程中不釋放。需要注意的是:靜態(tài)局部變量屬于靜態(tài)存儲方式,但是屬于靜態(tài)存儲方式的量不一定就是靜態(tài)變量,例如外部變量雖屬于靜態(tài)存儲方式,但不一定是靜態(tài)變量,必須由static加以定義后才能成為靜態(tài)外部變量,或稱靜態(tài)全局變量。當多次調(diào)用一個函數(shù)且要求在調(diào)用期間保留某些變量的值時,可考慮采用靜態(tài)局部變量。雖然用全局變量也可以達到上述目的,但全局變量有時會造成意外的副作用,因此仍以采用局部靜態(tài)變量為宜。雖然靜態(tài)局部變量在函數(shù)調(diào)用結(jié)束后仍然存在,但其它函數(shù)是不能引用它的。返回目錄7.7.2變量的存儲類型(4)c語言第7章2)靜態(tài)全局變量

全局變量(外部變量)的說明之前再冠以static就構(gòu)成了靜態(tài)的全局變量。全局變量本身就是靜態(tài)存儲方式,靜態(tài)全局變量當然也是靜態(tài)存儲方式。這兩者在存儲方式上并無不同。這兩者的區(qū)別在于非靜態(tài)全局變量的作用域是整個源程序,當一個源程序由多個源文件組成時,非靜態(tài)的全局變量在各個源文件中都是有效的。而靜態(tài)全局變量則限制了其作用域,即只在定義該變量的源文件內(nèi)有效,在同一源程序的其它源文件中不能使用它。由于靜態(tài)全局變量的作用域局限于一個源文件內(nèi),只能為該源文件內(nèi)的函數(shù)公用,因此可以避免在其它源文件中引起錯誤。從以上分析可以看出,把局部變量改變?yōu)殪o態(tài)變量后是改變了它的存儲方式即改變了它的生存期。把全局變量改變?yōu)殪o態(tài)變量后是改變了它的作用域,限制了它的使用范圍。因此static這個說明符在不同的地方所起的作用是不同的,應(yīng)予以注意。返回目錄7.7.2變量的存儲類型(5)c語言第7章4.extern(外部)C語言允許將一個程序中各個函數(shù),以函數(shù)定義為單位分裝在多個不同的源文件中,每個源文件中可以有一個或多個函數(shù)定義。每個源文件都是一個獨立的編譯單位。外部變量就是專門用于多個編譯單位之間傳遞數(shù)據(jù)用的。當編譯單位甲要用到編譯單位乙中的定義的變量,則編譯單位甲就要說明該變量是外部變量,以便C語言編譯系統(tǒng)在編譯單位甲之外的其它編譯單位中尋找該變量的定義。如圖7-24所示。圖7-24中,在源文件main.c中定義了(分配存儲空間)全局變量A,在源文件abc.c中聲明了(不分配存儲空間)外部變量A。由于在源文件abc.c中,變量B定義在后,使用在前,為了能正確編譯,在使用之前須對B進行聲明。返回目錄7.7.2變量的存儲類型(6)c語言第7章圖7-24注意:外部變量的定義和外部變量的聲明并不是一回事。外部變量定義必須在所有的函數(shù)之外,且只能定義一次。其一般形式為:[extern]類型說明符變量名,變量名…其中方括號內(nèi)的extern可以省去不寫。例如:inta,b;等效于externinta,b;而同一文件中的外部變量的聲明可以出現(xiàn)多次,位置可以在函數(shù)之(那個函數(shù)需要就在那個函數(shù)中聲明)內(nèi),也可以在函數(shù)之外(在外部變量的定義點之前)。外部變量說明的一般形式為:

extern類型說明符變量名,變量名,…;

系統(tǒng)根據(jù)外部變量的定義(而不是根據(jù)外部變量的聲明)分配內(nèi)存單元,對外部變量的初始化只能在定義時進行,而不能在聲明中進行。聲明的作用只是表明該變量是一個已經(jīng)在后面定義過的外部變量,僅僅是為了提前引用而作的“聲明”而已。返回目錄7.7.2變量的存儲類型(7)c語言第7章用auto、register、static聲明變量時,是在定義變量的基礎(chǔ)上加上這些關(guān)鍵字,而不能單獨使用。下面的用法是錯誤的:inta;/*先定義整型變量a*/statica;/*再對變量a聲明為靜態(tài)變量*/編譯時會被認為“重新定義”。正確的寫法是:staticinta;但用extern聲明某變量時,類型可省略。返回目錄7.7.2變量的存儲類型(8)c語言第7章存儲類別小結(jié)定義對一個數(shù)據(jù),需要指定兩種屬性:數(shù)據(jù)類型和存儲類別,分別使用兩個關(guān)鍵字。如:staticinta;

(靜態(tài)內(nèi)部整型變量或靜態(tài)外部整型變量)autocharc;

(自動變量,在函數(shù)內(nèi)定義)registerintd;

(寄存器變量,在函數(shù)內(nèi)定義)此外,可以用extern聲明變量為已定義的外部變量,如:externb;

(聲明b是一個已被定義的外部變量)返回目錄7.7.2變量的存儲類型(9)c語言第7章下面從不同角度做些歸納:(1)從作用域角度分,有局部變量和全局變量。(2)從變量存在的時間來區(qū)分,有動態(tài)存儲和靜態(tài)存儲兩種類型。靜態(tài)存儲是程序整個運行時間都存在,而動態(tài)存儲則是在調(diào)用函數(shù)時臨時分配單元。(3)變量的生存期和作用域既取決于它是外部變量還是內(nèi)部變量,還取決于它的存儲類別。(4)static對局部變量和全局變量的作用不同。對局部變量來說,它使變量由動態(tài)存儲方式改變?yōu)殪o態(tài)存儲方式。而對全局變量來說,它使變量局部化(局部于本文件),但仍為靜態(tài)存儲方式。從作用域角度看,凡有static聲明的,其作用域都是局限的,或者是局限于本函數(shù)內(nèi)(靜態(tài)局部變量),或者局限于本文件內(nèi)(靜態(tài)外部變量)。返回目錄7.7.2變量的存儲類型(10)c語言第7章表7-1各類變量的生存期和作用域變量允許的存儲類型生存期作用域外部變量省略(稱無存儲類型)全局變量定義點到程序結(jié)束靜態(tài)型(static)內(nèi)部變量省略(默認為自動型auto)局部變量定義該變量的函數(shù)或復合語句內(nèi)部自動型(auto)寄存器型(register)靜態(tài)型(static)全局變量返回目錄7.7.2變量的存儲類型(11)c語言第7章7.8內(nèi)部函數(shù)和外部函數(shù)(1)函數(shù)一旦定義后就可被其它函數(shù)調(diào)用。但當一個源程序由多個源文件組成時,在一個源文件中定義的函數(shù)能否被其它源文件中的函數(shù)調(diào)用呢?據(jù)此,C語言又把函數(shù)分為內(nèi)部函數(shù)和外部函數(shù)兩類。7.8.1內(nèi)部函數(shù)如果在一個源文件中定義的函數(shù)只能被本文件中的函數(shù)調(diào)用,而不能被同一源程序其它文件中的函數(shù)調(diào)用,這種函數(shù)稱為內(nèi)部函數(shù)。定義內(nèi)部函數(shù)的一般形式是:

static類型說明符函數(shù)名(形參表)例如:staticintf(intx,inty)內(nèi)部函數(shù)也稱為靜態(tài)函數(shù)。但此處靜態(tài)static的含義已不是指存儲方式,而是指對函數(shù)的調(diào)用范圍只局限于本文件。因此在不同的源文件中,如果定義了同名的靜態(tài)函數(shù),是不會引起混淆的。通常把只能由同一文件使用的函數(shù)、外部變量放在一個文件中,在它們前面都加上static使之局部化,其他文件將不能引用它們。返回目錄c語言第7章7.8.2外部函數(shù)外部函數(shù)在整個源程序中都有效,可供其他文件調(diào)用。其定義的一般形式為:extern類型說明符函數(shù)名(形參表)例如:externintf(intx,inty)如在函數(shù)定義中沒有說明extern或static,則隱含為extern。本書前面所用的函數(shù)都是外部函數(shù)。在一個源文件的函數(shù)中需要調(diào)用其它源文件中定義的外部函數(shù)時,應(yīng)用extern聲明被調(diào)函數(shù)為外部函數(shù)。返回目錄7.8內(nèi)部函數(shù)和外部函數(shù)(2)c語言第7章【例7-26】外部函數(shù)的定義與調(diào)用。(源文件一)main(){externintmin(intx,inty);/*外部函數(shù)聲明,表示min函數(shù)在其它源文件中*/inta,b,c,d;printf("inputa,b,c=?");scanf("%d,%d,%d",&a,&b,&c);d=min(m

溫馨提示

  • 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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論