



版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
8.函數(shù)概述在前面已經(jīng)介紹過,c源程序是由函數(shù)組成的。雖然在前面各章的程序中大都只有一個主函數(shù)main(),但實用程序往往由多個函數(shù)組成。函數(shù)是C源程序的基本模塊,通過對函數(shù)模塊的調(diào)用實現(xiàn)特定的功能。C語言中的函數(shù)相當(dāng)于其它高級語言的子程序。C語言不僅提供了極為豐富的庫函數(shù)(如TurboC,MSC都提供了三百多個庫函數(shù)),還允許用戶建立自己定義的函數(shù)。用戶可把自己的算法編成一個個相對獨立的函數(shù)模塊,然后用調(diào)用的方法來使用函數(shù)??梢哉fC程序的全部工作都是由各式各樣的函數(shù)完成的,所以也把C語言稱為函數(shù)式語言。由于采用了函數(shù)模塊式的結(jié)構(gòu),C語言易于實現(xiàn)結(jié)構(gòu)化程序設(shè)計。使程序的層次結(jié)構(gòu)清晰,便于程序的編寫、閱讀、調(diào)試。在C語言中可從不同的角度對函數(shù)分類。.從函數(shù)定義的角度看,函數(shù)可分為庫函數(shù)和用戶定義函數(shù)兩種。1)庫函數(shù):由C系統(tǒng)提供,用戶無須定義,也不必在程序中作類型說明,只需在程序前包含有該函數(shù)原型的頭文件即可在程序中直接調(diào)用。在前面各章的例題中反復(fù)用到printf>scanf>getchar>putchar>gets>puts>strcat等函數(shù)均屬此類。2)用戶定義函數(shù):由用戶按需要寫的函數(shù)。對于用戶自定義函數(shù),不僅要在程序中定義函數(shù)本身,而且在主調(diào)函數(shù)模塊中還必須對該被調(diào)函數(shù)進(jìn)行類型說明,然后才能使用。.C語言的函數(shù)兼有其它語言中的函數(shù)和過程兩種功能,從這個角度看,又可把函數(shù)分為有返回值函數(shù)和無返回值函數(shù)兩種。1)有返回值函數(shù):此類函數(shù)被調(diào)用執(zhí)行完后將向調(diào)用者返回一個執(zhí)行結(jié)果,稱為函數(shù)返回值。如數(shù)學(xué)函數(shù)即屬于此類函數(shù)。由用戶定義的這種要返回函數(shù)值的函數(shù),必須在函數(shù)定義和函數(shù)說明中明確返回值的類型。2)無返回值函數(shù):此類函數(shù)用于完成某項特定的處理任務(wù),執(zhí)行完成后不向調(diào)用者返回函數(shù)值。這類函數(shù)類似于其它語言的過程。由于函數(shù)無須返回值,用戶在定義此類函數(shù)時可指定它的返回為“空類型”,空類型的說明符為“void〃。.從主調(diào)函數(shù)和被調(diào)函數(shù)之間數(shù)據(jù)傳送的角度看又可分為無參函數(shù)和有參函數(shù)兩種。1)無參函數(shù):函數(shù)定義、函數(shù)說明及函數(shù)調(diào)用中均不帶參數(shù)。主調(diào)函數(shù)和被調(diào)函數(shù)之間不進(jìn)行參數(shù)傳送。此類函數(shù)通常用來完成一組指定的功能,可以返回或不返回函數(shù)值。2)有參函數(shù):也稱為帶參函數(shù)。在函數(shù)定義及函數(shù)說明時都有參數(shù),稱為形式參數(shù)(簡稱為形參)。在函數(shù)調(diào)用時也必須給出參數(shù),稱為實際參數(shù)(簡稱為實參)。進(jìn)行函數(shù)調(diào)用時,主調(diào)函數(shù)將把實參的值傳送給形參,供被調(diào)函數(shù)使用。.C語言提供了極為豐富的庫函數(shù),這些庫函數(shù)又可從功能角度作以下分類。1)字符類型分類函數(shù):用于對字符按ASCH碼分類:字母,數(shù)字,控制字符,分隔符,大小寫字母等。2)轉(zhuǎn)換函數(shù):用于字符或字符串的轉(zhuǎn)換;在字符量和各類數(shù)字量(整型,實型等)之間進(jìn)行轉(zhuǎn)換;在大、小寫之間進(jìn)行轉(zhuǎn)換。3)目錄路徑函數(shù):用于文件目錄和路徑操作。4)診斷函數(shù):用于內(nèi)部錯誤檢測。5)圖形函數(shù):用于屏幕管理和各種圖形功能。6)輸入輸出函數(shù):用于完成輸入輸出功能。7)接口函數(shù):用于與DOS,BIOS和硬件的接口。8)字符串函數(shù):用于字符串操作和處理。9)內(nèi)存管理函數(shù):用于內(nèi)存管理。10)數(shù)學(xué)函數(shù):用于數(shù)學(xué)函數(shù)計算。11)日期和時間函數(shù):用于日期,時間轉(zhuǎn)換操作。12)進(jìn)程控制函數(shù):用于進(jìn)程管理和控制。13)其它函數(shù):用于其它各種功能。以上各類函數(shù)不僅數(shù)量多,而且有的還需要硬件知識オ會使用,因此要想全部掌握則需要一個較長的學(xué)習(xí)過程。應(yīng)首先掌握ー些最基本、最常用的函數(shù),再逐步深入。由于課時關(guān)系,我們只介紹了很少一部分庫函數(shù),其余部分讀者可根據(jù)需要查閱有關(guān)手冊。還應(yīng)該指出的是,在C語言中,所有的函數(shù)定義,包括主函數(shù)main在內(nèi),都是平行的。也就是說,在ー個函數(shù)的函數(shù)體內(nèi),不能再定義另ー個函數(shù),即不能嵌套定義。但是函數(shù)之間允許相互調(diào)用,也允許嵌套調(diào)用。習(xí)慣上把調(diào)用者稱為主調(diào)函數(shù)。函數(shù)還可以自己調(diào)用自己,稱為遞歸調(diào)用。main函數(shù)是主函數(shù),它可以調(diào)用其它函數(shù),而不允許被其它函數(shù)調(diào)用。因此,C程序的執(zhí)行總是從main函數(shù)開始,完成對其它函數(shù)的調(diào)用后再返回到main函數(shù),最后由main函數(shù)結(jié)束整個程序。ー個C源程序必須有,也只能有一個主函數(shù)main。函數(shù)定義的一般形式8.2.1無參函數(shù)的定義形式類型標(biāo)識符函數(shù)名(){聲明部分語句其中類型標(biāo)識符和函數(shù)名稱為函數(shù)首部。類型標(biāo)識符指明了本函數(shù)的類型,函數(shù)的類型實際上是函數(shù)返回值的類型。該類型標(biāo)識符與前面介紹的各種說明符相同。函數(shù)名是由用戶定義的標(biāo)識符,函數(shù)名后有ー個空括號,其中無參數(shù),但括號不可少。{}中的內(nèi)容稱為函數(shù)體。在函數(shù)體中聲明部分,是對函數(shù)體內(nèi)部所用到的變量的類型說明。在很多情況下都不要求無參函數(shù)有返回值,此時函數(shù)類型符可以寫為void。我們可以改寫ー個函數(shù)定義:voidHello(){printf(Z/Hello,world\n");)這里Hello函數(shù)是ー個無參函數(shù),當(dāng)被其它函數(shù)調(diào)用時,輸出Helloworld字符串。8.2.2有參函數(shù)定義的一般形式類型標(biāo)識符函數(shù)名(形式參數(shù)表列){聲明部分語句}有參函數(shù)比無參函數(shù)多了一個內(nèi)容,即形式參數(shù)表列。在形參表中給出的參數(shù)稱為形式參數(shù),它們可以是各種類型的變量,各參數(shù)之間用逗號間隔。在進(jìn)行函數(shù)調(diào)用時,主調(diào)函數(shù)將賦予這些形式參數(shù)實際的值。形參既然是變量,必須在形參表中給出形參的類型說明。例如,定義ー個函數(shù),用于求兩個數(shù)中的大數(shù),可寫為:intmax(intx,inty){intz;if(x>y)z二x;elsex=y;return(z);)第一行說明max函數(shù)是一個整型函數(shù),其返回的函數(shù)值是ー個整數(shù)。形參為x、y,均為整型量。x、y的具體值是由主調(diào)函數(shù)在調(diào)用時傳送過來的。在。中的函數(shù)體內(nèi),包括聲明部分和執(zhí)行部分。在max函數(shù)體中的return語句是把z的值作為函數(shù)的值返回給主調(diào)函數(shù)。有返回值函數(shù)中至少應(yīng)有一個return語句。在C程序中,在定義函數(shù)時不指定函數(shù)類型,系統(tǒng)隱含指定函數(shù)類型為int型,因此上面定義的max函數(shù)左端的int可以省略。ー個函數(shù)的定義可以放在任意位置,既可放在主函數(shù)main之前,也可放在main之后(放在后面時ー般要在主函數(shù)中或主函數(shù)前進(jìn)行聲明)。例如:可把max函數(shù)置在main之后,也可以把它放在main之前。修改后的程序如下所示?!纠?.1】#include<stdio.h>intmax(intx,inty)(intz;if(x>y)z=x;elsez=y;return(z);voidmain()inta,b,c;printf("inputtwonumbers:\n")scanf("%d%d",&a,&b);c=max(a,b);printf("maxmum=%d",c);現(xiàn)在我們可以從函數(shù)定義、函數(shù)說明及函數(shù)調(diào)用的角度來分析整個程序,從中進(jìn)一步了解函數(shù)的各種特點。程序的第1行至第7行為max函數(shù)定義。進(jìn)入主函數(shù)后,要調(diào)用max函數(shù)。程序第13行為調(diào)用max函數(shù),并把a,b中的值傳送給max的形參x,y。max函數(shù)執(zhí)行的結(jié)果z將返回給變量〇〇最后由主函數(shù)輸出c的值。注:可以有空函數(shù)8.3函數(shù)的參數(shù)和函數(shù)的值形式參數(shù)和實際參數(shù)前面已經(jīng)介紹過,函數(shù)的參數(shù)分為形參和實參兩種。在定義函數(shù)時函數(shù)名后面括弧中的變量名稱為形式參數(shù),在主調(diào)函數(shù)中調(diào)用ー個函數(shù)時,函數(shù)名后面括弧中的參數(shù)(可以是表達(dá)式)稱為實際參數(shù)。在本小節(jié)中,進(jìn)ー步介紹形參、實參的特點和兩者的關(guān)系。形參出現(xiàn)在函數(shù)定義中,在整個函數(shù)體內(nèi)都可以使用,離開該函數(shù)則不能使用。實參出現(xiàn)在主調(diào)函數(shù)中,進(jìn)入被調(diào)函數(shù)后,實參變量也不能使用。形參和實參的功能是作數(shù)據(jù)傳送。發(fā)生函數(shù)調(diào)用時,主調(diào)函數(shù)把實參的值傳送給被調(diào)函數(shù)的形參從而實現(xiàn)主調(diào)函數(shù)向被調(diào)函數(shù)的數(shù)據(jù)傳送。函數(shù)的形參和實參具有以下特點:.形參變量只有在被調(diào)用時才分配內(nèi)存單元,在調(diào)用結(jié)束時,即刻釋放所分配的內(nèi)存單元。因此,形參只有在函數(shù)內(nèi)部有效。函數(shù)調(diào)用結(jié)束返回主調(diào)函數(shù)后則不能再使用該形參變量。.實參可以是常量、變量、表達(dá)式、函數(shù)等,無論實參是何種類型的量,在進(jìn)行函數(shù)調(diào)用時,它們都必須具有確定的值,以便把這些值傳送給形參。因此應(yīng)預(yù)先用賦值、輸入等辦法使實參獲得確定值。.實參和形參在數(shù)量上、順序上應(yīng)嚴(yán)格一致,類型應(yīng)相同或賦值兼容。.函數(shù)調(diào)用中發(fā)生的數(shù)據(jù)傳送是單向的。即只能把實參的值傳送給形參,而不能把形參的值反向地傳送給實參。因此在函數(shù)調(diào)用過程中,形參的值發(fā)生改變,而實參中的值不會變化。但bH但bH【例8.2】可以說明這個問題。#include<stdio.h>voids(intn)inti;for(i=n-l;i>=l;i--)n=n+i;printf(〃n二%d\n,n);}voidmain(){intn;printf(inputnumber\nz,);scanf(〃刎〃,&n);s(n);printf(〃n二%d\n,n);本程序中定義了一個函數(shù)S,該函數(shù)的功能是求1+2+…+n的值。在主函數(shù)中輸入n值,并作為實參,在調(diào)用時傳送給s函數(shù)的形參量n(注意,本例的形參變量和實參變量的標(biāo)識符都為n,但這是兩個不同的量,各自的作用域不同)。在主函數(shù)中用printf語句輸出一次n值,這個n值是實參n的值。在函數(shù)s中也用printf語句輸出了一次n值,這個n值是形參最后取得的n值。從運行情況看,輸入n值為100。即實參n的值為100o把此值傳給函數(shù)s時,形參n的初值也為100,在執(zhí)行函數(shù)過程中,形參n的值變?yōu)?050o返回主函數(shù)之后,輸出實參n的值仍為!00o可見實參的值不隨形參的變化而變化。8.3.2函數(shù)的返回值函數(shù)的值是指函數(shù)被調(diào)用之后,執(zhí)行函數(shù)體中的程序段所取得的并返回給主調(diào)函數(shù)的值。如調(diào)用正弦函數(shù)取得正弦值,調(diào)用例8.1的max函數(shù)取得的最大數(shù)等。對函數(shù)的值(或稱函數(shù)返回值)有以下一些說明:1)函數(shù)的值只能通過return語句返回主調(diào)函數(shù)。return語句的一般形式為:return表達(dá)式;或者為:return(表達(dá)式);該語句的功能是計算表達(dá)式的值,并返回給主調(diào)函數(shù)。在函數(shù)中允許有多個return語句,但每次調(diào)用只能有一個return語句被執(zhí)行,因此只能返回一個函數(shù)值。2)函數(shù)值的類型和函數(shù)定義中函數(shù)的類型應(yīng)保持ー致。如果兩者不一致,則以函數(shù)類型為準(zhǔn),自動進(jìn)行類型轉(zhuǎn)換。但如果被調(diào)函數(shù)在調(diào)用函數(shù)后面定義,在調(diào)用處要對被調(diào)函數(shù)進(jìn)行聲明?!纠?.3】ftinclude<stdio.h>voidmain(){intmax(floatx,floaty);floata,b;intc;scanf(〃%f,%f",&a,&b);c=max(a,b);printf〈maxis%d〃,c);intmax(floatx,floaty)floatz;z=x>y?x:y;return(z);3)如函數(shù)值為整型,在tc2.0中函數(shù)定義時可以省去類型說明,但C++中是不允許省略類型說明。4)不返回函數(shù)值的函數(shù),可以明確定義為“空類型”,類型說明符為“void〃。如例8.2中函數(shù)s并不向主函數(shù)返函數(shù)值,因此可定義為:voids(intn)一旦函數(shù)被定義為空類型后,就不能在主調(diào)函數(shù)中使用被調(diào)函數(shù)的函數(shù)值了。例如,在定義s為空類型后,在主函數(shù)中寫下述語句sum=s(n);就是錯誤的。為了使程序有良好的可讀性并減少出錯,凡不要求返回值的函數(shù)都應(yīng)定義為空類型。8.4函數(shù)的調(diào)用函數(shù)調(diào)用的一般形式前面已經(jīng)說過,在程序中是通過對函數(shù)的調(diào)用來執(zhí)行函數(shù)體的,其過程與其它語言的子程序調(diào)用相似。C語言中,函數(shù)調(diào)用的一般形式為:函數(shù)名(實際參數(shù)表)對無參函數(shù)調(diào)用時則無實際參數(shù)表。實際參數(shù)表中的參數(shù)可以是常數(shù),變量或其它構(gòu)造類型數(shù)據(jù)及表達(dá)式,各實參之間用逗號分隔。但應(yīng)說明,如果實參表列包括多個實參,tc對實參的求值順序是從右到左?!纠?.4】ftinclude<stdio.h>voidmain(){intf(inta,intb);inti=2,p;P=f(i,++i);printf(''%d\n〃,p);}intf(inta,intb)intc;if(a>b)c=l;elseif(a=b)c=0;elsec二T;return(c);函數(shù)調(diào)用的方式在C語言中,可以用以下幾種方式調(diào)用函數(shù):.函數(shù)表達(dá)式:函數(shù)作為表達(dá)式中的一項出現(xiàn)在表達(dá)式中,以函數(shù)返回值參與表達(dá)式的運算。這種方式要求函數(shù)是有返回值的。例如:z二max(x,y)是ー個賦值表達(dá)式,把max的返回值賦予變量zo.函數(shù)語句:函數(shù)調(diào)用的一般形式加上分號即構(gòu)成函數(shù)語句。例如: printfa);scanf(級d〃,&b);都是以函數(shù)語句的方式調(diào)用函數(shù)。.函數(shù)實參:函數(shù)作為另ー個函數(shù)調(diào)用的實際參數(shù)出現(xiàn)。這種情況是把該函數(shù)的返回值作為實參進(jìn)行傳送,因此要求該函數(shù)必須是有返回值的。例如:printf(〃刎〃,max(a,b)); 即是把max調(diào)用的返回值又作為printf函數(shù)的實參來使用的。在函數(shù)調(diào)用中還應(yīng)該注意的ー個問題是求值順序的問題。所謂求值順序是指對實參表中各量是自左至右使用呢,還是自右至左使用。對此,各系統(tǒng)的規(guī)定不一定相同。介紹printf函數(shù)時已提到過,這里從函數(shù)調(diào)用的角度再強調(diào)一下?!纠?.5】#include<stdio.h>voidmain(){inti=8;printf(,z%d\n%d\n%d\n%d\n,z,++i,--i,i++,i--);}如按照從右至左的順序求值。運行結(jié)果應(yīng)為:8778如對printf語句中的++i,--i,i++,i--從左至右求值,結(jié)果應(yīng)為:988應(yīng)特別注意的是,無論是從左至右求值,還是自右至左求值,其輸出順序都是不變的,即輸出順序總是和實參表中實參的順序相同。由于TurboC現(xiàn)定是自右至左求值,所以結(jié)果為8,7,7,8〇上述問題如還不理解,上機(jī)一試就明白了。8.4.3被調(diào)用函數(shù)的聲明和函數(shù)原型在主調(diào)函數(shù)中調(diào)用某函數(shù)之前應(yīng)對該被調(diào)函數(shù)進(jìn)行說明(聲明),這與使用變量之前要先進(jìn)行變量說明是ー樣的。在主調(diào)函數(shù)中對被調(diào)函數(shù)作說明的目的是使編譯系統(tǒng)知道被調(diào)函數(shù)返回值的類型,以便在主調(diào)函數(shù)中按此種類型對返回值作相應(yīng)的處理。其一般形式為:類型說明符被調(diào)函數(shù)名(類型形參,類型形參…);或為:類型說明符被調(diào)函數(shù)名(類型,類型…);括號內(nèi)給出了形參的類型和形參名,或只給出形參類型。這便于編譯系統(tǒng)進(jìn)行檢錯,以防止可能出現(xiàn)的錯誤。例8.1main函數(shù)中對max函數(shù)的說明為:intmax(intx,inty);或?qū)憺?intmax(int,int);C語言中又規(guī)定在以下幾種情況時可以省去主調(diào)函數(shù)中對被調(diào)函數(shù)的函數(shù)說明。1)當(dāng)被調(diào)函數(shù)的函數(shù)定義出現(xiàn)在主調(diào)函數(shù)之前時,在主調(diào)函數(shù)中也可以不對被調(diào)函數(shù)再作說明而直接調(diào)用。例如例8.1中,函數(shù)max的定義放在main函數(shù)之前,因此可在main函數(shù)中省去對max函數(shù)的函數(shù)說明intmax(intx,inty)〇2)如在所有函數(shù)定義之前,在函數(shù)外預(yù)先說明了各個函數(shù)的類型,則在以后的各主調(diào)函數(shù)中,可不再對被調(diào)函數(shù)作說明。例如:charstr(inta);floatf(floatb);main()charstr(inta)floatf(floatb)其中第一,二行對str函數(shù)和f函數(shù)預(yù)先作了說明。因此在以后各函數(shù)中無須對str和f函數(shù)再作說明就可直接調(diào)用。3)對庫函數(shù)的調(diào)用不需要再作說明,但必須把該函數(shù)的頭文件用include命令包含在源文件前部。函數(shù)的嵌套調(diào)用c語言中不允許作嵌套的函數(shù)定義。因此各函數(shù)之間是平行的,不存在上一級函數(shù)和下ー級函數(shù)的問題。但是c語言允許在ー個函數(shù)的定義中出現(xiàn)對另ー個函數(shù)的調(diào)用。這樣就出現(xiàn)了函數(shù)的嵌套調(diào)用。即在被調(diào)函數(shù)中又調(diào)用其它函數(shù)。這與其它語言的子程序嵌套的情形是類似的。其關(guān)系可表示如圖。main函數(shù) a?函數(shù) b函數(shù)上圖表示了兩層嵌套的情形。其執(zhí)行過程是:執(zhí)行main函數(shù)中調(diào)用a函數(shù)的語句時,即轉(zhuǎn)去執(zhí)行a函數(shù),在a函數(shù)中調(diào)用b函數(shù)時,又轉(zhuǎn)去執(zhí)行b函數(shù),b函數(shù)執(zhí)行完畢返回a函數(shù)的斷點繼續(xù)執(zhí)行,a函數(shù)執(zhí)行完畢返回main函數(shù)的斷點繼續(xù)執(zhí)行?!纠?.6]計算s=22!+32!本題可編寫兩個函數(shù),ー個是用來計算平方值的函數(shù)fl,另ー個是用來計算階乘值的函數(shù)f2。主函數(shù)先調(diào)fl計算出平方值,再在fl中以平方值為實參,調(diào)用f2計算其階乘值,然后返回fl,再返回主函數(shù),在循環(huán)程序中計算累加和。#include<stdio.h>longfl(intp)intk;longr;longf2(intq);k=p*p;r=f2(k);returnr;1longf2(intq){longc=l;inti;for(i=l;i<=q;i++)c=c*i;returnc;1voidmain(){inti;longs=0;for(i=2;i<=3;i++)s=s+f1(i);printf(〃、ns=%ld\n,s);在程序中,函數(shù)fl和f2均為長整型,都在主函數(shù)之前定義,故不必再在主函數(shù)中對fl和f2加以說明。在主程序中,執(zhí)行循環(huán)程序依次把i值作為實參調(diào)用函數(shù)fl求iユ值。在fl中又發(fā)生對函數(shù)f2的調(diào)用,這時是把iユ的值作為實參去調(diào)f2,在f2中完成求i?!的計算。f2執(zhí)行完畢把C值(即i?!)返回給fl,再由fl返回主函數(shù)實現(xiàn)累加。至此,由函數(shù)的嵌套調(diào)用實現(xiàn)了題目的要求。由于數(shù)值很大,所以函數(shù)和一些變量的類型都說明為長整型,否則會造成計算錯誤。函數(shù)的遞歸調(diào)用在調(diào)用ー個函數(shù)的過程中又出現(xiàn)直接或間接地調(diào)用該函數(shù)本身,稱為函數(shù)的遞歸調(diào)用。c語言允許函數(shù)的遞歸調(diào)用。在遞歸調(diào)用中,主調(diào)函數(shù)又是被調(diào)函數(shù)。執(zhí)行遞歸函數(shù)將反復(fù)調(diào)用其自身,每調(diào)用ー次就進(jìn)入新的ー層。例如有函數(shù)f如下:intf(intx){inty,z;z=f(y);return(2*z);這個函數(shù)是ー個遞歸函數(shù)。但是運行該函數(shù)將無休止地調(diào)用其自身,這當(dāng)然是不正確的。為了防止遞歸調(diào)用無終止地進(jìn)行,必須在函數(shù)內(nèi)有終止遞歸調(diào)用的手段。常用的辦法是加條件判斷,滿足某種條件后就不再作遞歸調(diào)用,然后逐層返回。下面舉例說明遞歸調(diào)用的執(zhí)行過程?!纠?.7】有五個人坐在ー起,問第五個人有多少歲?他說比第四個人大2歲。問第四個人歲數(shù),他說比第三個人大2歲。問第三個人歲數(shù),他說比第二個人大2歲。問第二個人歲數(shù),他說比第一個人大2歲。最后問第一個人,他說是10歲。請問第五個人多大。age(n)二しこ;;:;1)按公式可編程如下:#include<stdio.h>intage(intn)(intc;if(nニニ1)c=10;elsec二age(nT)+2;return(c);voidmain()printf(、、%d〃,age(5));)【例8.8]用遞歸法計算n!用遞歸法計算n!可用下述公式表示:n!=l (n=0,1)nx(n-l)! (n>l)按公式可編程如下:#include<stdio.h>floatfac(intn)(floatf;if(n<0)printfCn<0,inputerror");elseif(n-0||n"l)f=l;elsef=fac(n-l)*n;return(f);}voidmain(){intn;floaty;printf(,z\ninputainteagernumber:\n,z);scanf&n);y=fac(n);printf(〃%d!二%n,y);}程序中給出的函數(shù)fac是一個遞歸函數(shù)。主函數(shù)調(diào)用fac后即進(jìn)入函數(shù)fac執(zhí)行,如果n<O,n=O或n=l時都將結(jié)束函數(shù)的執(zhí)行,否則就遞歸調(diào)用fac函數(shù)自身。由于每次遞歸調(diào)用的實參為n-1,即把n-1的值賦予形參n,最后當(dāng)n-1的值為1時再作遞歸調(diào)用,形參n的值也為1,將使遞歸終止。然后可逐層退回。下面我們再舉例說明該過程。設(shè)執(zhí)行本程序時輸入為5,即求5!。在主函數(shù)中的調(diào)用語句即為y=fac(5),進(jìn)入fac函數(shù)后,由于n二5,不等于?;?,故應(yīng)執(zhí)行f二fac(n-l)*n,即f=fac(5-1)*5。該語句對fac作遞歸調(diào)用即fac(4)〇進(jìn)行四次遞歸調(diào)用后,fac函數(shù)形參取得的值變?yōu)?,故不再繼續(xù)遞歸調(diào)用而開始逐層返回主調(diào)函數(shù)。fac⑴的函數(shù)返回值為1,fac(2)的返回值為1*2=2,fac⑶的返回值為2*3=6,fac(4)的返回值為6*4=24,最后返回值fac⑸為24*5=120。例8.8也可以不用遞歸的方法來完成。如可以用遞推法,即從1開始乘以2,再乘以3...直到n。遞推法比遞歸法更容易理解和實現(xiàn)。但是有些問題則只能用遞歸算法才能實現(xiàn)。典型的問題是Hanoi塔問題?!纠?.9]Hanoi塔問題ー塊板上有三根針,A,B,CoA針上套有64個大小不等的圓盤,大的在下,小的在上。如圖5.4所示。要把這64個圓盤從A針移動C針上,每次只能移動ー個圓盤,移動可以借助B針進(jìn)行。但在任何時候,任何針上的圓盤都必須保持大盤在下,小盤在上。求移動的步驟。本題算法分析如下,設(shè)A上有n個盤子。如果n=1,則將圓盤從A直接移動到Co如果n=2,貝リ:.將A上的n-l(等于!)個圓盤移到B±;.再將A上的一個圓盤移到C上;.最后將B上的nT(等于1)個圓盤移到C上。如果n=3,則:A,將A上的n-l(等于2,令其為ボ)個圓盤移到B(借助于C),步驟如下:(1)將A上的n'T(等于1)個圓盤移到C上。(2)將A上的ー個圓盤移到Bo(3)將C上的n'-l(等于1)個圓盤移到BoB,將A上的ー個圓盤移到C。C,將B上的n-l(等于2,令其為ボ)個圓盤移到C(借助船,步驟如下:⑴將B上的n'T(等于1)個圓盤移到Ao(2)將B上的ー個盤子移到C。(3)將A上的n'-l(等于1)個圓盤移到Co至リ此,完成了三個圓盤的移動過程。從上面分析可以看出,當(dāng)n大于等于2時,移動的過程可分解為三個步驟:第一步把A上的n-l個圓盤移到B上;第二步把A上的ー個圓盤移到C上;第三步把B上的n-l個圓盤移到C上;其中第一步和第三步是類同的。當(dāng)n=3時,第一步和第三步又分解為類同的三步,即把n'-l個圓盤從ー個針移到另ー個針上,這里的n-n-lo顯然這是ー個遞歸過程,據(jù)此算法可編程如下:#include<stdio.h>voidmove(intn,intx,inty,intz)(if(n==l)printf(%c一ー〉%c\n,x,z);elsemove(n-l,x,z,y);printf("猊-->%c\n,z,x,z);move(n-1,y,x,z);}}voidmain(){inth;printfC\ninputnumber:\n,z);scanf&h);printf(thesteptomoving%2ddiskes:\n,h);move(h,,a,,,b,,,c,);}從程序中可以看出,move函數(shù)是ー個遞歸函數(shù),它有四個形參n,x,y,Zon表示圓盤數(shù),x,y,z分別表示三根針。move函數(shù)的功能是把x上的n個圓盤移動到z±〇當(dāng)n=l時,直接把x上的圓盤移至z±,輸出x-z。如n!=!則分為三步:遞歸調(diào)用move函數(shù),把n-1個圓盤從x移到y(tǒng);輸出x->z;遞歸調(diào)用move函數(shù),把n-1個圓盤從y移到z。在遞歸調(diào)用過程中n=n-l,故n的值逐次遞減,最后n=l時,終止遞歸,逐層返回。當(dāng)n=4時程序運行的結(jié)果為:inputnumber:4thesteptomoving4diskes:a—ba一cb—ca—bc—ac—ba—ba—cb—cb—ac—ab—ca—ba—cb—c8.7數(shù)組作為函數(shù)參數(shù)數(shù)組可以作為函數(shù)的參數(shù)使用,進(jìn)行數(shù)據(jù)傳送。數(shù)組用作函數(shù)參數(shù)有兩種形式,ー種是把數(shù)組元素(下標(biāo)變量)作為實參使用;另ー種是把數(shù)組名作為函數(shù)的形參和實參使用。.數(shù)組元素作函數(shù)實參數(shù)組元素就是下標(biāo)變量,它與普通變量并無區(qū)別。因此它作為函數(shù)實參使用與普通變量是完全相同的,在發(fā)生函數(shù)調(diào)用時,把作為實參的數(shù)組元素的值傳送給形參,實現(xiàn)單向的值傳送。例5.4說明了這種情況?!纠?.10】有兩個數(shù)組a、b各有10個元素(整型),將它們對應(yīng)地元素逐個相比,如果a數(shù)組中的元素大于b數(shù)組中相應(yīng)元素的數(shù)目多于b數(shù)組中元素大于a數(shù)組中相應(yīng)元素的數(shù)目,則認(rèn)為a數(shù)組大于b數(shù)組,并分別統(tǒng)計出兩個數(shù)組相應(yīng)元素大于、等于、小于的次數(shù)。程序如下:ttinclude<stdio.h>voidmain(){intlarge(intx,inty);inta[10],b[10],i,n=0,m=0,k=0;for(i=0;i<10;i++)scanf(''%d〃,&a[i]);printf(''\n〃);for(i=0;i<10;i++)scanf(、ヽ%d〃,&b[i]);printf(''\n〃);for(i=0;i<10;i++)if(large(a[i],b[i])=l)n=n+l;elseif(large(a[i],b[i])==0)m=m+l;elsek=k+l;printf(''a[i]>b[i]%dtimes\na[i]=b[i]%dtimes\na|_i」くb[i[%dtimes\n〃,n,m,k);if(n>k)printf(''arrayaislargerthenarrayb\n〃);elseif(n<k)printf(''arrayaissmsllerthenarrayb\n〃);elseprintf(''arrayaisequaltoarrayb\n〃);}intlarge(intx,inty)intflag;if(x>y)flag=l;elseif(xくy)flag二T;elseflagニ〇;return(flag);.數(shù)組名作為函數(shù)參數(shù)用數(shù)組名作函數(shù)參數(shù)與用數(shù)組元素作實參有幾點不同:1)用數(shù)組元素作實參時,只要數(shù)組類型和函數(shù)的形參變量的類型一致,那么作為下標(biāo)變量的數(shù)組元素的類型也和函數(shù)形參變量的類型是一致的。因此,并不要求函數(shù)的形參也是下標(biāo)變量。換句話說,對數(shù)組元素的處理是按普通變量對待的。用數(shù)組名作函數(shù)參數(shù)時,則要求形參和相對應(yīng)的實參都必須是類型相同的數(shù)組,都必須有明確的數(shù)組說明。當(dāng)形參和實參二者不一致時,即會發(fā)生錯誤。2)在普通變量或下標(biāo)變量作函數(shù)參數(shù)時,形參變量和實參變量是由編譯系統(tǒng)分配的兩個不同的內(nèi)存單元。在函數(shù)調(diào)用時發(fā)生的值傳送是把實參變量的值賦予形參變量。在用數(shù)組名作函數(shù)參數(shù)時,不是進(jìn)行值的傳送,即不是把實參數(shù)組的每ー個元素的值都賦予形參數(shù)組的各個元素。因為實際上形參數(shù)組并不存在,編譯系統(tǒng)不為形參數(shù)組分配內(nèi)存。那么,數(shù)據(jù)的傳送是如何實現(xiàn)的呢?在C語言中數(shù)組名就是數(shù)組的首地址,在數(shù)組名作函數(shù)參數(shù)時所進(jìn)行的傳送只是地址的傳送,也就是說把實參數(shù)組的首地址賦予形參數(shù)組名。形參數(shù)組名取得該首地址之后,也就等于有了實在的數(shù)組。實際上是形參數(shù)組和實參數(shù)組為同一數(shù)組,共同擁有一段內(nèi)存空間。a[〇]a[l]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]?獨地址I2I4I6I81012I1411611820
b[0]b[l]b[2]b[3]b[4]b[5]b[6]b[7]b[8]b[9]上圖說明了這種情形。圖中設(shè)a為實參數(shù)組,類型為整型。a占有以2000為首地址的ー塊內(nèi)存區(qū)。b為形參數(shù)組名。當(dāng)發(fā)生函數(shù)調(diào)用時,進(jìn)行地址傳送,把實參數(shù)組a的首地址傳送給形參數(shù)組名b,于是b也取得該地址200〇。于是a,b兩數(shù)組共同占有以2000為首地址的一段連續(xù)內(nèi)存單元。從圖中還可以看出a和b下標(biāo)相同的元素實際上也占相同的兩個內(nèi)存單元(整型數(shù)組每個元素占二字節(jié))。例如a[〇]和b[〇]都占用2000和2001單元,當(dāng)然a[0]等于b[0]。類推則有a[i]等于b[i]?!纠?.11】有一個ー維數(shù)組score,內(nèi)放10學(xué)生成績,求平均成績。ttinclude<stdio.h>floataverage(floatarray[10])(inti;floataver,sum=array[〇];for(i=l;i<10;i++)sum=sum+array[i];aver=sum/10;returnaver;}voidmain()(floatscore[10],aver;inti;printfC\ninput10scores:\n,z);for(i=0;i<10;i++)scanf(,z%fz/,&score[i]);aver=average(score);printf(zzaveragescoreis%5.2エ,aver);}本程序首先定義了一個實型函數(shù)average,有一個形參為實型數(shù)組array,長度為10。在函數(shù)average中,把各元素值相加求出平均值,返回給主函數(shù)。主函數(shù)main中首先完成數(shù)組score的輸入,然后以score作為實參調(diào)用average函數(shù),函數(shù)返回值送aver,最后輸出aver值。從運行情況可以看出,程序?qū)崿F(xiàn)了所要求的功能。3)前面已經(jīng)討論過,在變量作函數(shù)參數(shù)時,所進(jìn)行的值傳送是單向的。即只能從實參傳向形參,不能從形參傳回實參。形參的初值和實參相同,而形參的值發(fā)生改變后,實參并不變化。而當(dāng)用數(shù)組名作函數(shù)參數(shù)時,情況則不同。由于實際上形參和實參為同一數(shù)組,因此當(dāng)形參數(shù)組發(fā)生變化時,實參數(shù)組也隨之變化。當(dāng)然這種情況不能理解為發(fā)生了“雙向”的值傳遞。但從實際情況來看,調(diào)用函數(shù)之后實參數(shù)組的值將由于形參數(shù)組值的變化而變化。4)形參數(shù)組和實參數(shù)組的長度可以不相同,因為在調(diào)用時,只傳送首地址而不檢查形參數(shù)組的長度。當(dāng)形參數(shù)組的長度與實參數(shù)組不一致時,雖不至于出現(xiàn)語法錯誤(編譯能通過),但程序執(zhí)行結(jié)果將與實際不符,這是應(yīng)予以注意的。5)在函數(shù)形參表中,允許不給出形參數(shù)組的長度,或用ー個變量來表示數(shù)組元素的個數(shù)。6)多維數(shù)組也可以作為函數(shù)的參數(shù)。在函數(shù)定義時對形參數(shù)組可以指定每ー維的長度,也可省去第一維的長度。因此,以下寫法都是合法的。intarray(inta[3][10])或intarray(inta[][10])〇【例8.12】、【例8.例】、【例8.14]見課本。8局部變量和全局變量在討論函數(shù)的形參變量時曾經(jīng)提到,形參變量只在被調(diào)用期間オ分配內(nèi)存單元,調(diào)用結(jié)束立即釋放。這一點表明形參變量只有在函數(shù)內(nèi)オ是有效的,離開該函數(shù)就不能再使用了。這種變量有效性的范圍稱變量的作用域。不僅對于形參變量,c語言中所有的量都有自己的作用域。變量說明的方式不同,其作用域也不同。c語言中的變量,按作用域范圍可分為兩種,即局部變量和全局變量。8.1局部變量局部變量也稱為內(nèi)部變量。局部變量是在函數(shù)內(nèi)作定義說明的。其作用域僅限于函數(shù)內(nèi),離開該函數(shù)后再使用這種變量是非法的。例如:
intfl(inta)/intfl(inta)/?函數(shù)fl*/intb,c;a,b,c在f!內(nèi)有效intf2(intx) /?函數(shù)f2*/{inty,z;x,y,z在f2內(nèi)有效main()(intm,n;m,n在main內(nèi)有效在函數(shù)fl內(nèi)定義了三個變量,a為形參,b,c為ー般變量。在fl的范圍內(nèi)a,b,c有效,或者說a,b,c變量的作用域限于fl內(nèi)。同理,x,y,z的作用域限于f2內(nèi)。m,n的作用域限于main函數(shù)內(nèi)。關(guān)于局部變量的作用域還要說明以下幾點:1)主函數(shù)中定義的變量也只能在主函數(shù)中使用,不能在其它函數(shù)中使用。同時,主函數(shù)中也不能使用其它函數(shù)中定義的變量。因為主函數(shù)也是ー個函數(shù),它與其它函數(shù)是平行關(guān)系。這一點是與其它語言不同的,應(yīng)予以注意。2)形參變量是屬于被調(diào)函數(shù)的局部變量,實參變量是屬于主調(diào)函數(shù)的局部變量。3)允許在不同的函數(shù)中使用相同的變量名,它們代表不同的對象,分配不同的單元,互不干擾,也不會發(fā)生混淆。如在前例中,形參和實參的變量名都為n,是完全允許的。4)在復(fù)合語句中也可定義變量,其作用域只在復(fù)合語句范圍內(nèi)。例如:main(){inta,b;/*c作用域?//*a,b作用域?/【例8.15】#include<stdio.h>voidmain()inti=2,j=3,k;k=i+j;(intk=8;printf(〃%d\n〃,k);}printf(〃%d\n〃,k);本程序在main中定義了i,j,k三個變量,其中k未賦初值。而在復(fù)合語句內(nèi)又定義了一個變量k,并賦初值為8〇應(yīng)該注意這兩個k不是同一個變量。在復(fù)合語句外由main定義的k起作用,而在復(fù)合語句內(nèi)則由在復(fù)合語句內(nèi)定義的k起作用。因此程序第4行的k為main所定義,其值應(yīng)為5。第7行輸出k值,該行在復(fù)合語句內(nèi),由復(fù)合語句內(nèi)定義的k起作用,其初值為8,故輸出值為8,第9行輸出i,k值。i是在整個程序中有效的,第7行對i賦值為3,故以輸出也為3〇而第9行已在復(fù)合語句之外,輸出的k應(yīng)為main所定義的k,此k值由第4行已獲得為5,故輸出也為5〇8.8.2全局變量全局變量也稱為外部變量,它是在函數(shù)外部定義的變量。它不屬于哪ー個函數(shù),它屬于ー個源程序文件。其作用域是整個源程序。在函數(shù)中使用全局變量,一般應(yīng)作全局變量說明。只有在函數(shù)內(nèi)經(jīng)過說明的全局變量才能使用。全局變量的說明符為extern。但在ー個函數(shù)之前定義的全局變量,在該函數(shù)內(nèi)使用可不再加以說明。例如:inta,b; /?外部變量?/voidfl() /?函數(shù)fl*/floatx,y; /?外部變量?/
intfz()/intfz()/?函數(shù)fz*/main() /?主函數(shù)?/{extern[int]c,d;....../*int可省略?/トintc,d;從上例可以看出a>b、x、y、c、d都是在函數(shù)外部定義的外部變量,都是全局變量。但x,y定義在函數(shù)fl之后,而在fl內(nèi)又無對x,y的說明,所以它們在fl內(nèi)無效。a,b定義在源程序最前面,因此在fl,f2及main內(nèi)不加說明也可使用。c、d定義在最后,但在main內(nèi)進(jìn)行了說明,所以。、d在fl和f2內(nèi)無效,在main內(nèi)可使用。說明:(1)設(shè)全局變量的作用是增加了函數(shù)間數(shù)據(jù)聯(lián)系的渠道??梢岳萌肿兞康倪@個性質(zhì)從函數(shù)中得到ー個以上的函數(shù)值。(2)如果同一個源文件中,外部變量與局部變量同名,則在局部變量的作用范圍內(nèi),外部變量被“屏蔽”,即它不起作用。(3)建議不在必要時不要使用全局變量?!纠?.16]輸入長方體的長寬高l,w,ho求體積及三個面x*y,x*z,y*z的面積。ftinclude<stdio.h>intsi,s2,s3;intvs(inta,intb,intc){intv;v=a*b*c;si=a*b;s2=b*c;s3=a*c;returnv;}voidmain(){intv,1,w,h;printf(〃、ninputlength,widthandheight\n〃);scanf(〃%d%d%d〃,&1,&w,&h);v=vs(1,w,h);printf(〃、nv=%d,sl=%d,s2二%d,s3二%d\n〃,v,si,s2,s3);【例8.17]外部變量與局部變量同名。tfinclude<stdio.h>inta=3,b=5; /*a,b為外部變量?/intmax(inta,intb)/*a,b為局部變量?/{intc;c=a>b?a:b;return(c);)voidmain(){inta=8;printf(〃%d\n,max(a,b));}8.9變量的存儲類別8.9.1動態(tài)存儲方式與靜態(tài)存儲方式前面已經(jīng)介紹了,從變量的作用域(即從空間)角度來分,可以分為全局變量和局部變量。從另ー個角度,從變量值存在的時間(即生存期)角度來分,可以分為靜態(tài)存儲方式和動態(tài)存儲方式。靜態(tài)存儲方式:是指在程序運行期間分配固定的存儲空間的方式。動態(tài)存儲方式:是在程序運行期間根據(jù)需要進(jìn)行動態(tài)的分配存儲空間的方式。用戶存儲空間可以分為三個部分:1)程序區(qū);2)靜態(tài)存儲區(qū);3)動態(tài)存儲區(qū);用戶區(qū)
丨程序區(qū)|
[靜態(tài)存儲區(qū)|
[動態(tài)存儲區(qū)|全局變量全部存放在靜態(tài)存儲區(qū),在程序開始執(zhí)行時給全局變量分配存儲區(qū),程序行完畢就釋放。在程序執(zhí)行過程中它們占據(jù)固定的存儲單元,而不動態(tài)地進(jìn)行分配和釋放;動態(tài)存儲區(qū)存放以下數(shù)據(jù):1)函數(shù)形式參數(shù);2)自動變量(未加static聲明的局部變量);3)函數(shù)調(diào)用時的現(xiàn)場保護(hù)和返回地址;對以上這些數(shù)據(jù),在函數(shù)開始調(diào)用時分配動態(tài)存儲空間,函數(shù)結(jié)束時釋放這些空間。在c語言中,每個變量和函數(shù)有兩個屬性:數(shù)據(jù)類型和數(shù)據(jù)的存儲類別。8.9.2auto變量函數(shù)中的局部變量,如不專門聲明為static存儲類別,都是動態(tài)地分配存儲空間的,數(shù)據(jù)存儲在動態(tài)存儲區(qū)中。函數(shù)中的形參和在函數(shù)中定義的變量(包括在復(fù)合語句中定義的變量),都屬此類,在調(diào)用該函數(shù)時系統(tǒng)會給
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 眾籌股東合同范例6
- 南匯食品運輸合同范例
- 三年級數(shù)數(shù)學(xué)解決問題教案
- 叉車裝卸合同范本
- 加工木門合同范本
- 單位用品批發(fā)合同范本
- 付款分期合同范本
- 制造師證書掛靠合同范本
- 《童年的秘密》讀書心得體會
- 司機(jī) 勞動合同范本
- 信息網(wǎng)絡(luò)安全與保密管理制度-
- 海運客服專員崗位職責(zé)
- 腹痛的診斷與鑒別診斷-課件
- 五年級道德與法治下冊全冊教案
- 110KV電纜敷設(shè)專項施工方案方案
- 配電箱巡視檢查記錄表
- GB/T 2624.3-2006用安裝在圓形截面管道中的差壓裝置測量滿管流體流量第3部分:噴嘴和文丘里噴嘴
- 豌豆栽培及病蟲害防治課件
- ISO45001職業(yè)健康安全管理體系培訓(xùn)
- 動物生產(chǎn)學(xué)(全套課件)
- 部編版四年級下冊道德與法治 第4課 買東西的學(xué)問(第2課時) 教學(xué)課件
評論
0/150
提交評論