版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
在結(jié)構(gòu)化程序設(shè)計(jì)中,函數(shù)是將任務(wù)進(jìn)行模塊劃分的基本單位。第四章函數(shù)
要掌握函數(shù)的使用,必須理解函數(shù)調(diào)用時(shí)的內(nèi)部實(shí)現(xiàn)機(jī)制,以及與此相關(guān)的內(nèi)存分配機(jī)制、變量生命期和作用域。本章還將介紹關(guān)于函數(shù)重載的概念,介紹遞歸算法、內(nèi)聯(lián)函數(shù)、默認(rèn)參數(shù)函數(shù)以及多文件組織、編譯預(yù)處理、工程文件的概念和運(yùn)行庫(kù)函數(shù)。第四章函數(shù)
4.1函數(shù)的定義與調(diào)用
4.5作用域與存儲(chǔ)類型
4.4函數(shù)調(diào)用機(jī)制
4.3全局變量和局部變量
4.2函數(shù)的參數(shù)傳遞,返回值及函數(shù)原型說(shuō)明
4.9編譯預(yù)處理4.8頭文件與多文件結(jié)構(gòu)4.7函數(shù)的一些高級(jí)議題
4.6函數(shù)的遞歸調(diào)用
4.1
函數(shù)的定義與調(diào)用4.1.1
函數(shù)概述4.1.2
函數(shù)的定義4.1.3
函數(shù)的調(diào)用
4.1C++的系統(tǒng)庫(kù)函數(shù)C++提供了一個(gè)很大的常用函數(shù)庫(kù),該函數(shù)庫(kù)本身并不是C++語(yǔ)言的組成部分,所有庫(kù)中的函數(shù)用戶都可以自己定義,但直接使用庫(kù)函數(shù)能給編程帶來(lái)很大方便。系統(tǒng)函數(shù)庫(kù)實(shí)際上是一系列源程序文件,每個(gè)文件中定義了若干常用函數(shù)及標(biāo)識(shí)符,具有相同或相似功能的函數(shù)和標(biāo)識(shí)符集中放在一個(gè)文件中。這些文件均以.h的形式命名,存放在系統(tǒng)目錄的include子目錄下。例如文件iostream.h中定義了與控制臺(tái)輸入輸出和文件輸入輸出相關(guān)對(duì)象和成員函數(shù),math.h中定義了大量數(shù)學(xué)函數(shù),string.h中定義了大量與字符串操作相關(guān)的函數(shù)。
4.1C++的系統(tǒng)庫(kù)函數(shù)C++提供了一個(gè)很大的常用函數(shù)庫(kù),該函數(shù)庫(kù)本身并不是C++語(yǔ)言的組成部分,所有庫(kù)中的函數(shù)用戶都可以自己定義,但直接使用庫(kù)函數(shù)能給編程帶來(lái)很大方便。系統(tǒng)函數(shù)庫(kù)實(shí)際上是一系列源程序文件,每個(gè)文件中定義了若干常用函數(shù)及標(biāo)識(shí)符,具有相同或相似功能的函數(shù)和標(biāo)識(shí)符集中放在一個(gè)文件中。這些文件均以.h的形式命名,存放在系統(tǒng)目錄的include子目錄下。例如文件iostream.h中定義了與控制臺(tái)輸入輸出和文件輸入輸出相關(guān)對(duì)象和成員函數(shù),math.h中定義了大量數(shù)學(xué)函數(shù),string.h中定義了大量與字符串操作相關(guān)的函數(shù)。
math.h中幾個(gè)常用的數(shù)學(xué)函數(shù)
函數(shù)原型說(shuō)明intabs(intn);n的絕對(duì)值doublecos(doublex);x(弧度)的余弦doubleexp(doublex);指數(shù)函數(shù)exdoublefabs(doublex);x的絕對(duì)值doublefmod(doublex,doubley);x/y的浮點(diǎn)余數(shù)doublelog(doublex);x的自然對(duì)數(shù)(以e為底)doublelog10(doublex);x的對(duì)數(shù)(以10為底)doublepow(doublex,doubley);x的y次方(xy)doublesin(doublex);x(弧度)的正弦doublesqrt(doublex);x的平方根doubletan(doublex);x(弧度)的正切4.1.1函數(shù)概述main()fun2()fun1()fun3()fun1_1()fun2_1()fun2_2()圖4.1函數(shù)調(diào)用層次關(guān)系4.1.1函數(shù)概述函數(shù)按是否帶有參數(shù),分為:
無(wú)參函數(shù)和有參函數(shù)4.1.1結(jié)束
函數(shù)按其是否系統(tǒng)預(yù)定義分為兩類:一類是編譯系統(tǒng)預(yù)定義的,稱為庫(kù)函數(shù)或標(biāo)準(zhǔn)函數(shù),如一些常用的數(shù)學(xué)計(jì)算函數(shù)、字符串處理函數(shù)、圖形處理函數(shù)、標(biāo)準(zhǔn)輸入輸出函數(shù)等。這些庫(kù)函數(shù)都按功能分類,集中說(shuō)明在不同的頭文件中。用戶只需在自己的程序中包含某個(gè)頭文件,就可直接使用該文件中定義的函數(shù)。另一類是用戶自定義函數(shù),用戶可以根據(jù)需要將某個(gè)具有相對(duì)獨(dú)立功能的程序定義為函數(shù)。4.1.2函數(shù)的定義1.無(wú)參函數(shù)2.有參函數(shù)1
無(wú)參函數(shù)
定義格式為:《數(shù)據(jù)類型》函數(shù)名(《void》){函數(shù)體}例:下面函數(shù)的功能是打印一個(gè)表頭voidTableHead(){cout<<″****************″<<endl;cout<<″*example*″<<endl;cout<<″****************″<<endl;}有參函數(shù)有參函數(shù)的定義格式為《數(shù)據(jù)類型》函數(shù)名(參數(shù)類型1形式參數(shù)1《,參數(shù)類型2形式參數(shù)2,…》{函數(shù)體}例:下面函數(shù)的功能是返回兩個(gè)整數(shù)中較大一個(gè)的值intmax(inta,intb){return(a>=b?a:b);}定義函數(shù)時(shí)可能會(huì)涉及若干個(gè)變量,究竟哪些變量應(yīng)當(dāng)作為函數(shù)的參數(shù)?哪些應(yīng)當(dāng)定義在函數(shù)體內(nèi)?這有一個(gè)原則:作為一個(gè)相對(duì)獨(dú)立的模塊,函數(shù)在使用時(shí)完全可以被看成“黑匣子”,除了輸入輸出外,其他部分可不必關(guān)心。從函數(shù)的定義看出,函數(shù)頭正是用來(lái)反映函數(shù)的功能和使用接口,它所定義的是“做什么”,在這部分必須明確“黑匣子”的輸入輸出部分,輸出就是函數(shù)的返回值,輸入就是參數(shù)。因此,只有那些功能上起自變量作用的變量才必須作為參數(shù)定義在參數(shù)表中;函數(shù)體中具體描述“如何做”,因此除參數(shù)之外的為實(shí)現(xiàn)算法所需用的變量應(yīng)當(dāng)定義在函數(shù)體內(nèi)。C++中不允許函數(shù)的嵌套定義,即在一個(gè)函數(shù)中定義另一個(gè)函數(shù)。提示4.1.3
函數(shù)的調(diào)用在C++中,除了主函數(shù)外,其他任何函數(shù)都不能單獨(dú)作為程序運(yùn)行。任何函數(shù)功能的實(shí)現(xiàn)都是通過(guò)被主函數(shù)直接或間接調(diào)用進(jìn)行的。所謂函數(shù)調(diào)用,就是使程序轉(zhuǎn)去執(zhí)行函數(shù)體。無(wú)參函數(shù)的調(diào)用格式為:函數(shù)名();有參函數(shù)的調(diào)用格式為:函數(shù)名(實(shí)際參數(shù)表);其中實(shí)際參數(shù)簡(jiǎn)稱實(shí)參,用來(lái)將實(shí)際參數(shù)的值傳遞給形參,因此可以是常量、具有值的變量或表達(dá)式。4.1.3
函數(shù)的調(diào)用main()函數(shù)調(diào)用max(2.5,4.7)函數(shù)max(2.5,4.7)return4.7
主程序后續(xù)語(yǔ)句【例4.1】輸入兩個(gè)實(shí)數(shù),輸出其中較大的數(shù)。其中求兩個(gè)實(shí)數(shù)中的較大數(shù)用函數(shù)完成。程序如下:#include<iostream.h>floatmax(floatx,floaty){ return(x>=y?x:y);}voidmain(){ floatx,y; cout<<"輸入兩個(gè)實(shí)數(shù):"<<endl; cin>>x>>y; cout<<x<<"和"<<y<<"中較大數(shù)為"<<max(x,y)<<endl;}4.2
函數(shù)的參數(shù)傳遞、返回值及
函數(shù)原型說(shuō)明
4.2.1函數(shù)的參數(shù)傳遞及傳值調(diào)用
4.2.3函數(shù)原型說(shuō)明4.2.2
函數(shù)返回值
函數(shù)調(diào)用首先要進(jìn)行參數(shù)傳遞,參數(shù)傳遞的方向是由實(shí)參傳遞給形參。傳遞過(guò)程是,先計(jì)算實(shí)參表達(dá)式的值,再將該值傳遞給對(duì)應(yīng)的形參變量。一般情況下,實(shí)參和形參的個(gè)數(shù)和排列順序應(yīng)一一對(duì)應(yīng),并且對(duì)應(yīng)參數(shù)應(yīng)類型匹配(賦值兼容),即實(shí)參的類型可以轉(zhuǎn)化為形參類型。而對(duì)應(yīng)參數(shù)的參數(shù)名則不要求相同。
4.2.1函數(shù)的參數(shù)傳遞及傳值調(diào)用
按照參數(shù)形式的不同,C++有兩種調(diào)用方式:傳值調(diào)用和引用調(diào)用。顧名思義,傳值調(diào)用傳遞的是實(shí)參的值,本章主要介紹傳值調(diào)用。
4.2.1函數(shù)的參數(shù)傳遞及傳值調(diào)用
調(diào)用power(4.6,3)函數(shù)power(4.6,3)return97.336
主程序后續(xù)語(yǔ)句n=3x=4.6c=‘a(chǎn)’【例4.2】
說(shuō)明實(shí)參和形參對(duì)應(yīng)關(guān)系的示例。#include<iostream.h>#include<math.h>floatpower(floatx,intn){//求x的n次冪floatpow=1;while(n--)pow*=x;returnpow;}voidmain(){intn=3;floatx=4.6;charc='a';cout<<"power("<<x<<','<<n<<")="<<power(x,n)<<endl;cout<<"power("<<c<<','<<n<<")="<<power(c,n)<<endl;cout<<"power("<<n<<','<<x<<")="<<power(n,x)<<endl;}
4.2.1函數(shù)的參數(shù)傳遞及傳值調(diào)用
調(diào)用power('a',3)函數(shù)power('a',3)return912673
主程序后續(xù)語(yǔ)句n=3x=4.6c=‘a(chǎn)’【例4.2】
說(shuō)明實(shí)參和形參對(duì)應(yīng)關(guān)系的示例。#include<iostream.h>#include<math.h>floatpower(floatx,intn){//求x的n次冪floatpow=1;while(n--)pow*=x;returnpow;}voidmain(){intn=3;floatx=4.6;charc='a';cout<<"power("<<x<<','<<n<<")="<<power(x,n)<<endl;cout<<"power("<<c<<','<<n<<")="<<power(c,n)<<endl;cout<<"power("<<n<<','<<x<<")="<<power(n,x)<<endl;}
4.2.1函數(shù)的參數(shù)傳遞及傳值調(diào)用
調(diào)用power(3,4.6)函數(shù)power(3,4.6)return81主程序后續(xù)語(yǔ)句n=3x=4.6c=‘a(chǎn)’【例4.2】
說(shuō)明實(shí)參和形參對(duì)應(yīng)關(guān)系的示例。#include<iostream.h>#include<math.h>floatpower(floatx,intn){//求x的n次冪floatpow=1;while(n--)pow*=x;returnpow;}voidmain(){intn=3;floatx=4.6;charc='a';cout<<"power("<<x<<','<<n<<")="<<power(x,n)<<endl;cout<<"power("<<c<<','<<n<<")="<<power(c,n)<<endl;cout<<"power("<<n<<','<<x<<")="<<power(n,x)<<endl;}4.2.2函數(shù)返回值return語(yǔ)句的一般格式為:
return表達(dá)式;函數(shù)的計(jì)算結(jié)果通過(guò)該語(yǔ)句傳遞回主調(diào)函數(shù)?!纠?.3】設(shè)計(jì)函數(shù),根據(jù)三角形的三邊長(zhǎng)求面積。如果不能構(gòu)成三角形,給出提示信息。分析:函數(shù)為計(jì)算三角形面積,一般三角形返回面積值,若不能構(gòu)成三角形則返回-1。設(shè)計(jì)一個(gè)主函數(shù)完成函數(shù)測(cè)試。根據(jù)返回值情況輸出相應(yīng)結(jié)果。程序見下頁(yè):#include<iostream.h>#include<math.h>floatTriangleArea(floata,floatb,floatc){if((a+b<=c)||(a+c<=b)||(b+c<=a))return-1;floats;s=(a+b+c)/2;
returnsqrt(s*(s-a)*(s-b)*(s-c));}voidmain(){floata,b,c,area;cout<<"輸入三角形三邊a,b,c:"<<endl;cin>>a>>b>>c;
area=TriangleArea(a,b,c);if(area==-1)cout<<'('<<a<<','<<b<<','<<c<<')'<<"不能構(gòu)成三角形!"<<endl;else cout<<"三角形("<<a<<','<<b<<','<<c<<")面積為:"<<area<<endl;}4.2.2函數(shù)返回值函數(shù)可以有返回值,也可以沒(méi)有返回值。對(duì)于沒(méi)有返回值的函數(shù),功能只是完成一定操作,應(yīng)將返回值類型定義為void,函數(shù)體內(nèi)可以沒(méi)有return語(yǔ)句,當(dāng)需要在程序指定位置退出時(shí),可以在該處放置一個(gè):return;4.2.2結(jié)束4.2.3
函數(shù)原型說(shuō)明
函數(shù)原型是一條以分號(hào)結(jié)束的語(yǔ)句,實(shí)際上就是所定義函數(shù)的函數(shù)頭,形如:《函數(shù)返回值類型》函數(shù)名(《形參表》);
語(yǔ)法上對(duì)程序文件中函數(shù)的排列次序是沒(méi)有固定要求的,只要滿足先定義后使用即可。但從結(jié)構(gòu)化程序設(shè)計(jì)的角度,通常是先調(diào)用后定義。使用函數(shù)原型,則既符合由粗到精的思維方式,又滿足了語(yǔ)法要求。
其中形參表可以逐個(gè)列出每個(gè)參數(shù)的類型和參數(shù)名,也可以列出每個(gè)形參的類型,參數(shù)名可省略,各形參之間以逗號(hào)分隔。函數(shù)原型和所定義的函數(shù)必須在返回值類型、函數(shù)名、形參個(gè)數(shù)和類型及次序等方面完全對(duì)應(yīng)一致,否則將導(dǎo)致編譯錯(cuò)誤。
下面是一個(gè)使用結(jié)構(gòu)化程序設(shè)計(jì)思想開發(fā)的企業(yè)管理報(bào)表程序的框架。它使用了函數(shù)原型說(shuō)明。#include<iostream.h>voidmenu_print();voidaccount_report();voidengineering_report();voidmarketing_report();voidmain(){intchoice;do{
menu_print(); cin>>choice;}while(choice<=0||choice>=4);switch(choice){case1:account_report();break;case2:engineering_report();break;case3:marketing_report();break;}}voidmenu_print(){cout<<”系統(tǒng)功能:”<<endl;cout<<”1 財(cái)務(wù)報(bào)表”<<endl;cout<<”2 工程報(bào)表”<<endl;cout<<”3 市場(chǎng)報(bào)表”<<endl;cout<<”選擇業(yè)務(wù)序號(hào):”;}voidaccount_report(){//生成財(cái)務(wù)報(bào)表}voidengineering_report(){//生成工程報(bào)表}voidmarketing_report(){//生成市場(chǎng)報(bào)表;}4.2.3
函數(shù)原型說(shuō)明【例4.4】
輸出所有滿足下列條件的正整數(shù)m:10<m<1000且m、m2、m3均為回文數(shù)。分析:回文指左右對(duì)稱的序列。如121、353等就是回文數(shù)。判斷整數(shù)是否回文數(shù)用函數(shù)實(shí)現(xiàn),其思想是將該數(shù)各位拆開后反向組成新的整數(shù),如果該整數(shù)與原數(shù)相等則為回文數(shù)。程序如下:#include<iostream.h>#include<iomanip.h>boolpalindrome(int);//函數(shù)原型voidmain(){ cout<<setw(10)<<'m'<<setw(20)<<"m*m“ <<setw(20)<<"m*m*m"<<endl; for(intm=11;m<1000;m++)
if(palindrome(m)&&palindrome(m*m) &&palindrome(m*m*m))
cout<<setw(10)<<m<<setw(20)<<m*m <<setw(20)<<m*m*<<endl;}boolpalindrome(intn){ intdigit[10]; intm=n,i=0; do{ digit[i]=n%10;n/=10;i++; }while(n>0); for(intj=0;j<i;j++)n=n*10+digit[j]; return(n==m);}4.2.3
函數(shù)原型說(shuō)明mm*mm*m*m111211331101102011030301111123211367631
運(yùn)行結(jié)果:4.3全局變量和局部變量4.3.1變量的存儲(chǔ)機(jī)制與C++的內(nèi)存布局
4.3.2全局變量
4.3.3局部變量
4.3.1變量的存儲(chǔ)機(jī)制與C++的內(nèi)存布局堆區(qū)(動(dòng)態(tài)數(shù)據(jù))棧區(qū)(函數(shù)局部數(shù)據(jù))(main()函數(shù)局部數(shù)據(jù))全局?jǐn)?shù)據(jù)區(qū)(全局、靜態(tài))代碼區(qū)(程序代碼)
操作系統(tǒng)為一個(gè)C++程序的運(yùn)行所分配的內(nèi)存分為四個(gè)區(qū)域,如圖,程序在內(nèi)存中的區(qū)域所示:(1)代碼區(qū)(Codearea):存放程序代碼,即程序中各個(gè)函數(shù)的代碼塊;(2)全局?jǐn)?shù)據(jù)區(qū)(Dataarea):存放全局?jǐn)?shù)據(jù)和靜態(tài)數(shù)據(jù);分配該區(qū)時(shí)內(nèi)存全部清零。(3)棧區(qū)(Stackarea):存放局部變量,如函數(shù)中的變量等;分配棧區(qū)時(shí)內(nèi)存不處理。(4)堆區(qū)(Heaparea):存放與指針相關(guān)的動(dòng)態(tài)數(shù)據(jù)。分配堆區(qū)時(shí)內(nèi)存不處理。4.3.1變量的存儲(chǔ)機(jī)制與C++的內(nèi)存布局
4.3.2全局變量在所有函數(shù)之外定義的變量稱為全局變量。全局變量在編譯時(shí)建立在全局?jǐn)?shù)據(jù)區(qū),在未給出初始化值時(shí)系統(tǒng)自動(dòng)初始化為全0。全局變量可定義在程序開頭,也可定義在中間位置,該全局變量在定義處之后的任何位置都是可以訪問(wèn)的,稱為可見的。請(qǐng)看下例:4.3.2全局變量打印200調(diào)用func()函數(shù)func()200*2=400打印400n=100n=100*2=200【例4.5】多個(gè)函數(shù)使用全局變量的例子。#include<iostream.h>intn=100;voidfunc(){ n*=2;}voidmain(){ n*=2; cout<<n<<endl; func(); cout<<n<<endl;}4.3.3局部變量
定義在函數(shù)內(nèi)或塊內(nèi)的變量稱為局部變量。程序中使用的絕大多數(shù)變量都是局部變量。局部變量在程序運(yùn)行到它所在的塊時(shí)建立在棧中,該塊執(zhí)行完畢局部變量占有的空間即被釋放。局部變量在定義時(shí)可加修飾詞auto,但通常省略。局部變量在定義時(shí)若未初始化,其值為隨機(jī)數(shù)。4.3.3局部變量打印main()中的t=3.5調(diào)用fun()函數(shù)fun()打印fun()中的t=5
打印main()中的t=3.5t=3.5t=5【例4.9】使用局部變量的例子。#include<iostream.h>voidfun(){autointt=5;//fun()中的局部變量,auto可省略cout<<"fun()中的t="<<t<<endl;}voidmain(){floatt=3.5;//main()函數(shù)中的局部變量cout<<"main()中的t="<<t<<endl;fun();cout<<"main()中的t="<<t<<endl;}4.4函數(shù)調(diào)用機(jī)制
局部變量占用的內(nèi)存是在程序執(zhí)行過(guò)程中“動(dòng)態(tài)”地建立和釋放的。這種“動(dòng)態(tài)”是通過(guò)棧由系統(tǒng)自動(dòng)管理進(jìn)行的。當(dāng)任何一個(gè)函數(shù)調(diào)用發(fā)生時(shí),系統(tǒng)都要作以下工作:(1)建立棧空間;(6)恢復(fù)現(xiàn)場(chǎng):取主調(diào)函數(shù)運(yùn)行狀態(tài)及返回地址,釋放棧空間;(7)繼續(xù)主調(diào)函數(shù)后續(xù)語(yǔ)句。(5)釋放被調(diào)函數(shù)中局部變量占用的棧空間;(4)執(zhí)行被調(diào)函數(shù)函數(shù)體;(3)為被調(diào)函數(shù)中的局部變量分配空間,完成參數(shù)傳遞;(2)保護(hù)現(xiàn)場(chǎng):主調(diào)函數(shù)運(yùn)行狀態(tài)和返回地址入棧;4.4函數(shù)調(diào)用機(jī)制voidfun1(int,int);voidfun2(float);voidmain(){intx=1;y=2;fun1(x,y);}voidfun1(inta,intb){floatx=3;fun2(x);}voidfun2(floaty){intx;…}x棧頂棧底y3fun2()fun1()運(yùn)行狀態(tài)及返回地址x3b2a1fun1()main()運(yùn)行狀態(tài)及返回地址y2x1main()操作系統(tǒng)運(yùn)行狀態(tài)及返回地址此圖例說(shuō)明在程序執(zhí)行過(guò)程中怎樣通過(guò)?!皠?dòng)態(tài)”地建立和釋放局部變量占用的內(nèi)存的
4.5作用域與存儲(chǔ)類型4.5.1
作用域4.5.2變量的存儲(chǔ)類型4.5.3外部存儲(chǔ)類型與靜態(tài)存儲(chǔ)類型
4.5.4生命期與可見性
4.5.1作用域
1塊作用域
3文件作用域
2函數(shù)原型作用域
作用域指標(biāo)識(shí)符能夠被使用的范圍。只有在作用域內(nèi)標(biāo)識(shí)符才可以被訪問(wèn)(稱為可見)。本節(jié)只討論局部域和文件域(全局域),其中局部域包括塊域和函數(shù)原型域。任何標(biāo)識(shí)符作用域的起始點(diǎn)均為標(biāo)識(shí)符說(shuō)明處。下面分別介紹:參和函數(shù)體中定義的局部變量,作用域都在該函數(shù)內(nèi),也稱作函數(shù)域。塊域塊指一對(duì)大括號(hào)括起來(lái)的程序段。塊中定義的標(biāo)識(shí)符,作用域在塊內(nèi)。復(fù)合語(yǔ)句是一個(gè)塊。函數(shù)也是一個(gè)塊。復(fù)合語(yǔ)句中定義的標(biāo)識(shí)符,作用域僅在該復(fù)合語(yǔ)句中。函數(shù)中定義的標(biāo)識(shí)符,包括形塊域a=3b=535a=3b=5a=5b=3【例4.7】輸入兩數(shù),按從大到小的順序保存,并輸出結(jié)果。結(jié)果棧t=3#include<iostream.h>voidmain(){inta,b; //具有函數(shù)域
cout<<"輸入兩整數(shù):"<<endl;
cin>>a>>b;
cout<<“a="<<a<<'\t'<<"b="<<b<<endl;
if(b>=a){ intt;
//具有塊域
t=a;
a=b;b=t;//交換a,b的值
}cout<<"a="<<a<<'\t'<<"b="<<b<<endl;}【例4.8】設(shè)計(jì)函數(shù)完成兩數(shù)交換,用主函數(shù)進(jìn)行測(cè)試。#include<iostream.h>voidswap(int,int);voidmain(){inta,b;//a,b作用域?yàn)閙ain()cout<<"輸入兩整數(shù):"<<endl;cin>>a>>b;cout<<"調(diào)用前:實(shí)參a="<<a<<','<<"b="<<b<<endl;swap(a,b);//傳值cout<<"調(diào)用后:實(shí)參a="<<a<<','<<"b="<<b<<endl;}voidswap(inta,intb){//a,b作用域?yàn)閟wap()cout<<"調(diào)用中…"<<endl;cout<<"交換前:形參a=“<<a<<','<<"b="<<b<<endl;intt;t=a;a=b;b=t; //交換swap()中的a,b的值cout<<"交換后:形參a="<<a<<','<<"b="<<b<<endl;}塊作用域由VC++平臺(tái)運(yùn)行,結(jié)果如下:輸入兩整數(shù):35調(diào)用前:實(shí)參a=3,b=5調(diào)用中…交換前:形參a=3,b=5交換后:形參a=5,b=3調(diào)用后:實(shí)參a=3,b=5
交換失敗局部變量具有局部作用域使得程序在不同塊中可以使用同名變量。這些同名變量各自在自己的作用域中可見,在其它地方不可見。塊作用域
對(duì)于塊中嵌套其它塊的情況,如果嵌套塊中有同名局部變量,服從局部?jī)?yōu)先原則,即在內(nèi)層塊中屏蔽外層塊中的同名變量,換句話說(shuō),內(nèi)層塊中局部變量的作用域?yàn)閮?nèi)層塊;外層塊中局部變量的作用域?yàn)橥鈱映グ兞康膬?nèi)層塊部分。如果塊內(nèi)定義的局部變量與全局變量同名,塊內(nèi)仍然局部變量?jī)?yōu)先,但與塊作用域不同的是,在塊內(nèi)可以通過(guò)域運(yùn)算符“::”訪問(wèn)同名的全局變量。全局n=100200300內(nèi)i=500內(nèi)j=600內(nèi)n=500+600=11001100500600100200+300=500500
500200300外部i=200外部j=300【例4.9】
顯示同名變量可見性。intn=100;#include<iostream.h>voidmain(){inti=200,j=300;cout<<n<<'\t'<<i<<'\t'<<j<<endl;{ //內(nèi)部塊inti=500,j=600,n;n=i+j;cout<<n<<'\t'<<i<<'\t'<<j<<endl;//輸出局部變量ncout<<::n<<endl;//輸出全局變量n}n=i+j; //修改全局變量cout<<n<<'\t'<<i<<'\t'<<j<<endl;}函數(shù)原型作用域
函數(shù)原型不是定義函數(shù),在作函數(shù)原型聲明時(shí),其中的形參作用域只在原型聲明中,即作用域結(jié)束于右括號(hào)。正是由于形參不能被程序的其他地方引用,所以通常只要聲明形參個(gè)數(shù)和類型,形參名可省略。3文件作用域
文件作用域也稱全局作用域。定義在所有函數(shù)之外的標(biāo)識(shí)符,具有文件作用域,作用域?yàn)閺亩x處到整個(gè)源文件結(jié)束。文件中定義的全局變量和函數(shù)都具有文件作用域。如果某個(gè)文件中說(shuō)明了具有文件作用域的標(biāo)識(shí)符,該文件又被另一個(gè)文件包含,則該標(biāo)識(shí)符的作用域延伸到新的文件中。如cin和cout是在頭文件iostream.h中說(shuō)明的具有文件作用域的標(biāo)識(shí)符,它們的作用域也延伸到嵌入iostream.h的文件中。存儲(chǔ)類型決定了變量的生命期,變量生命期指從獲得空間到空間釋放之間的時(shí)期。4.5.2變量的存儲(chǔ)類型
存儲(chǔ)類型的說(shuō)明符有四個(gè):auto,register,static和extern。前兩者稱為自動(dòng)類型,后兩者分別為靜態(tài)和外部類型。本節(jié)重點(diǎn)掌握static和extern這兩種類型的使用和區(qū)別。具體說(shuō),區(qū)分局部變量和靜態(tài)局部變量,全局變量和靜態(tài)全局變量。auto:前面提到的局部變量都是自動(dòng)類型。其空間分配于塊始,空間釋放于塊終,且由系統(tǒng)自動(dòng)進(jìn)行。自動(dòng)變量保存在棧中,且是在程序運(yùn)行過(guò)程中獲得和釋放空間,未初始化時(shí)值為隨機(jī)數(shù)。4.5.2變量的存儲(chǔ)類型
register:為提高程序運(yùn)行效率,可以將某些變量保存在寄存器中,即說(shuō)明為寄存器變量,但不提倡使用。static:靜態(tài)變量。根據(jù)被修飾變量的位置不同,分為局部(內(nèi)部)靜態(tài)變量和全局(外部)靜態(tài)變量。所有靜態(tài)變量均存放在全局?jǐn)?shù)據(jù)區(qū),編譯時(shí)獲得存儲(chǔ)空間,未初始化時(shí)自動(dòng)全0,且只初始化一次。局部靜態(tài)變量的作用域?yàn)閴K域,但生命期為整個(gè)文件。即當(dāng)塊結(jié)束時(shí),局部靜態(tài)變量空間仍然保持,直到整個(gè)程序文件結(jié)束時(shí)該局部靜態(tài)變量空間才釋放,生命期結(jié)束。局部靜態(tài)變量
【例4.10】自動(dòng)變量與局部靜態(tài)變量的區(qū)別。(演示)#include<iostream.h>st(){staticintt=100;//局部靜態(tài)變量t++;returnt;}at(){intt=100;//自動(dòng)變量t++;returnt;}voidmain(){inti;for(i=0;i<5;i++)cout<<at()<<'\t';cout<<endl;for(i=0;i<5;i++)cout<<st()<<'\t';cout<<endl;}4.5.2變量的存儲(chǔ)類型
i=0t=100123451011011011011014.5.2變量的存儲(chǔ)類型
i=0t=10012101345102103104105#include<iostream.h>st(){staticintt=100;//局部靜態(tài)變量t++;returnt;}at(){intt=100;//自動(dòng)變量t++;returnt;}voidmain(){inti;for(i=0;i<5;i++)cout<<at()<<'\t';cout<<endl;for(i=0;i<5;i++)cout<<st()<<'\t';cout<<endl;}全局靜態(tài)變量全局靜態(tài)變量是指用static修飾的全局變量。有關(guān)內(nèi)容在下節(jié)靜態(tài)存儲(chǔ)類型中介紹。4.5.3
外部存儲(chǔ)類型與靜態(tài)存儲(chǔ)類型1.
外部存儲(chǔ)類型2.
靜態(tài)存儲(chǔ)類型一個(gè)C++程序可以由多個(gè)源程序文件組成,編譯系統(tǒng)將這若干個(gè)文件連接在一起,產(chǎn)生可執(zhí)行程序。外部存儲(chǔ)類型和靜態(tài)存儲(chǔ)類型確定了變量和函數(shù)在多文件程序中的聯(lián)絡(luò)關(guān)系。
1外部存儲(chǔ)類型
外部存儲(chǔ)類型包括外部變量和外部函數(shù)。在由多個(gè)源程序文件組成的程序中,如果一個(gè)文件要使用另一個(gè)文件中定義的全局變量或函數(shù),這些源程序文件之間通過(guò)外部類型的變量和函數(shù)進(jìn)行溝通。在一個(gè)文件中定義的全局變量和函數(shù)都缺省為外部的,即其作用域可以延伸到程序的其他文件中。但其他文件如果要使用這個(gè)文件中定義的全局變量和函數(shù),必須在使用前用“extern”作外部聲明,外部聲明通常放在文件的開頭。變量定義時(shí)編譯器為其分配存儲(chǔ)空間,而變量聲明指明該全局變量已在其他地方說(shuō)明過(guò),編譯系統(tǒng)不再分配存儲(chǔ)空間,直接使用變量定義時(shí)所分配的空間。函數(shù)聲明缺省為外部的,因此修飾詞extern通常省略。1外部存儲(chǔ)類型
【例4.11】外部存儲(chǔ)類型的例子。假定程序包含兩個(gè)源程序文件Ex4_11_1.cpp和Ex4_11_2.cpp,程序結(jié)構(gòu)如下:/*Ex4_11_1.cpp,由main()組成*/#include<iostream.h>voidfun2();//外部函數(shù)聲明,等價(jià)于externvoidfun2();intn; //全局變量定義voidmain(){n=1;fun2(); //fun2()定義在文件Ex4_11_2.cpp中cout<<″n=″<<n<<endl;}/*Ex4_11_2.cpp,由fun2()組成*/externintn;//外部變量聲明,n定義在文件Ex4_11_1.cpp中voidfun2(){//fun2()被文件Ex4_11_1.cpp中的函數(shù)調(diào)用n=3;}
運(yùn)行結(jié)果:n=32靜態(tài)存儲(chǔ)類型
靜態(tài)存儲(chǔ)類型包括靜態(tài)全局變量和靜態(tài)函數(shù)。在定義全局變量或函數(shù)時(shí)加說(shuō)明符static,就成為靜態(tài)變量或靜態(tài)函數(shù)。靜態(tài)存儲(chǔ)類型的作用域與外部存儲(chǔ)類型相反,一旦定義為靜態(tài)存儲(chǔ)類型,就限制該變量或函數(shù)只能在定義它的文件中使用。靜態(tài)全局變量在編譯時(shí)分配存儲(chǔ)空間,如果定義時(shí)不指定初值,則編譯系統(tǒng)將其初始化為全0。一個(gè)全局變量和一個(gè)靜態(tài)全局變量在使用上是不同的,其他文件通過(guò)外部變量聲明可以使用一個(gè)全局變量,但卻無(wú)法使用靜態(tài)全局變量,靜態(tài)全局變量只能被定義它的文件所獨(dú)享。函數(shù)與靜態(tài)函數(shù)之間的區(qū)別是相同的。4.5.4
生命期與可見性1.生命期2.可見性
1
生命期
(1)靜態(tài)生命期
(2)局部生命期
(3)動(dòng)態(tài)生命期
生命期(Lifetime)也叫生存期。生命期與存儲(chǔ)區(qū)域相關(guān),存儲(chǔ)區(qū)域分為代碼區(qū)、靜態(tài)數(shù)據(jù)區(qū)、棧區(qū)和堆區(qū),相應(yīng)地,生命期分為靜態(tài)生命期、局部生命期和動(dòng)態(tài)生命期。(1)靜態(tài)生命期
靜態(tài)生命期指的是標(biāo)識(shí)符從程序開始運(yùn)行時(shí)存在,即具有存儲(chǔ)空間,到程序運(yùn)行結(jié)束時(shí)消亡,即釋放存儲(chǔ)空間。具有靜態(tài)生命期的標(biāo)識(shí)符存放在靜態(tài)數(shù)據(jù)區(qū),屬于靜態(tài)存儲(chǔ)類型,如全局變量、靜態(tài)全局變量、靜態(tài)局部變量。具有靜態(tài)生命期的標(biāo)識(shí)符在未被用戶初始化的情況下,系統(tǒng)會(huì)自動(dòng)將其初始化為全0。
函數(shù)駐留在代碼區(qū),也具有靜態(tài)生命期。所有具有文件作用域的標(biāo)識(shí)符都具有靜態(tài)生命期。(2)局部生命期
在函數(shù)內(nèi)部或塊中定義的標(biāo)識(shí)符具有局部生命期,其生命期開始于執(zhí)行到該函數(shù)或塊的標(biāo)識(shí)符聲明處,結(jié)束于該函數(shù)或塊的結(jié)束處。具有靜態(tài)生命期的標(biāo)識(shí)符存放在棧區(qū)。具有局部生命期的標(biāo)識(shí)符如果未被初始化,其內(nèi)容是隨機(jī)的,不可用。
具有局部生命期的標(biāo)識(shí)符必定具有局部作用域;但反之不然,靜態(tài)局部變量具有局部作用域,但卻具有靜態(tài)生命期。(3)動(dòng)態(tài)生命期
具有動(dòng)態(tài)生命期的標(biāo)識(shí)符由特定的函數(shù)調(diào)用或運(yùn)算來(lái)創(chuàng)建和釋放,如調(diào)用malloc()或用new運(yùn)算符為變量分配存儲(chǔ)空間時(shí),變量的生命期開始,而調(diào)用free()或用delete運(yùn)算符釋放空間或程序結(jié)束時(shí),變量生命期結(jié)束。具有動(dòng)態(tài)生命期的變量存放在堆區(qū)。關(guān)于new運(yùn)算和delete運(yùn)算將在指針一章中介紹??梢娦?/p>
可見性從另一個(gè)角度說(shuō)明標(biāo)識(shí)符的有效性,可見性與作用域具有一定的一致性。標(biāo)識(shí)符的作用域包含可見范圍,可見范圍不會(huì)超過(guò)作用域??梢娦栽诶斫馔麡?biāo)識(shí)符的作用域嵌套時(shí)十分直觀。對(duì)于外層塊與內(nèi)層塊定義了同名標(biāo)識(shí)符的,在外層作用域中,內(nèi)層所定義的標(biāo)識(shí)符是不可見的,即外層引用的是外層所定義的標(biāo)識(shí)符;同樣,在內(nèi)層作用域中,外層的標(biāo)識(shí)符將被內(nèi)層的同名標(biāo)識(shí)符屏蔽,變得不可見,即外層中同名標(biāo)識(shí)符的可見范圍為作用域中挖去內(nèi)層塊的范圍。圖4.6顯示下面程序段中變量的作用域與可見性??梢娦?/p>
下面的程序段和圖示顯示作用域與可見性。
intm=1;floatx;{floatm=3.5;X=5.5;}m++;
intm,floatx作用域intm可見floatm不可見x可見floatm作用域floatm可見intm不可見x可見4.6
函數(shù)的遞歸調(diào)用
遞歸是一種描述問(wèn)題的方法,或稱算法。遞歸的思想可以簡(jiǎn)單地描述為“自己調(diào)用自己”。例如用如下方法定義階乘:可以看出是用階乘定義階乘,這種自己定義自己的方法稱為遞歸定義。在函數(shù)調(diào)用中,有這樣兩種情況,一種是在函數(shù)A的定義中有調(diào)用函數(shù)A的語(yǔ)句,即自己調(diào)用自己;另一種是函數(shù)A的定義中出現(xiàn)調(diào)用函數(shù)B的語(yǔ)句,而函數(shù)B的定義中也出現(xiàn)調(diào)用函數(shù)A的語(yǔ)句,即相互調(diào)用。前者稱直接遞歸,后者稱間接遞歸。本節(jié)只介紹直接遞歸。遞歸函數(shù)必須定義遞歸終止條件(Stoppingcondition),避免無(wú)窮遞歸(InfiniteRecursion)。遞歸定義的階乘算法用函數(shù)描述為:fac(intn){if(n==0||n==1)return1;elsereturnn*fac(n-1);}只要設(shè)計(jì)主函數(shù)調(diào)用階乘函數(shù),即可實(shí)現(xiàn)計(jì)算階乘。4.6
函數(shù)的遞歸調(diào)用【例4.12】求4!#include<iostream.h>intfac(intn){ inty;cout<<n<<'\t'; if(n==0||n==1)y=1;elsey=n*fac(n-1); cout<<y<<'\t'; returny;}voidmain(){ cout<<"\n4!="<<fac(4)<<endl;}n=4cout<<4;y=4*fac(3);fac(4)=cout<<2;y=2*fac(1);
n=2cout<<1;y=1;cout<<1;return1;
n=1n=3cout<<3;y=3*fac(2);cout<<24;return24;cout<<6;return6;cout<<2;return2;24遞歸函數(shù)的執(zhí)行分為“遞推”和“回歸”兩個(gè)過(guò)程,這兩個(gè)過(guò)程由遞歸終止條件控制,即逐層遞推,直至遞歸終止條件,然后逐層回歸。每次調(diào)用發(fā)生時(shí)都首先判斷遞歸終止條件。遞歸調(diào)用同普通的函數(shù)調(diào)用一樣,每當(dāng)調(diào)用發(fā)生時(shí),在棧中分配單元保存返回地址以及參數(shù)和局部變量;而與普通的函數(shù)調(diào)用不同的是,由于遞推的過(guò)程是一個(gè)逐層調(diào)用的過(guò)程,因此存在一個(gè)逐層連續(xù)的參數(shù)入棧過(guò)程,直至遇到遞歸終止條件時(shí),才開始回歸,這時(shí)才逐層釋放??臻g,返回到上一層,直至最后返回到主調(diào)函數(shù)。4.6函數(shù)的遞歸調(diào)用4.6
函數(shù)的遞歸調(diào)用【例4.13】
漢諾塔問(wèn)題。有A、B、C三根柱子,A柱上有n個(gè)大小不等的盤子,大盤在下,小盤在上。要求將所有盤子由A柱搬動(dòng)到C柱上,每次只能搬動(dòng)一個(gè)盤子,搬動(dòng)過(guò)程中可以借助任何一根柱子,但必須滿足大盤在下,小盤在上。打印出搬動(dòng)的步驟。
A柱B柱C柱分析:1A柱只有一個(gè)盤子的情況:A柱
C柱;2A柱有兩個(gè)盤子的情況:小盤A柱
B柱,大盤A柱
C柱,小盤B柱
C柱。3A柱有n個(gè)盤子的情況:將此問(wèn)題看成上面n-1個(gè)盤子和最下面第n個(gè)盤子的情況。n-1個(gè)盤子A柱
B柱,第n個(gè)盤子A柱
C柱,n-1個(gè)盤子B柱
C柱。問(wèn)題轉(zhuǎn)化成搬動(dòng)n-1個(gè)盤子的問(wèn)題,同樣,將n-1個(gè)盤子看成上面n-2個(gè)盤子和下面第n-1個(gè)盤子的情況,進(jìn)一步轉(zhuǎn)化為搬動(dòng)n-2個(gè)盤子的問(wèn)題,……,類推下去,一直到最后成為搬動(dòng)一個(gè)盤子的問(wèn)題。這是一個(gè)典型的遞歸問(wèn)題,遞歸結(jié)束于只搬動(dòng)一個(gè)盤子。4.6函數(shù)的遞歸調(diào)用4.6
函數(shù)的遞歸調(diào)用算法可以描述為:1n-1個(gè)盤子A柱
B柱,借助于C柱;2第n個(gè)盤子A柱
C柱;3n-1個(gè)盤子B柱
C柱,借助于A柱;其中步驟1和步驟3繼續(xù)遞歸下去,直至搬動(dòng)一個(gè)盤子為止。由此,可以定義兩個(gè)函數(shù),一個(gè)是遞歸函數(shù),命名為hanoi(intn,charsource,chartemp,chartarget),實(shí)現(xiàn)將n個(gè)盤子從源柱source借助中間柱temp搬到目標(biāo)柱target;另一個(gè)命名為move(charsource,chartarget),用來(lái)輸出搬動(dòng)一個(gè)盤子的提示信息。#include<iostream.h>voidmove(charsource,chartarget){cout<<source<<"->"<<target<<endl;}voidhanoi(intn,charsource,chartemp,chartarget){if(n==1)move(source,target);else{
hanoi(n-1,source,target,temp);
//將n-1個(gè)盤子搬到中間柱
move(source,target);
//將最后一個(gè)盤子搬到目標(biāo)柱
hanoi(n-1,temp,source,target);}}
//將n-1個(gè)盤子搬到目標(biāo)柱
voidmain(){ intn; cout<<"輸入盤子數(shù):"<<endl; cin>>n; hanoi(n,'A','B','C');}【例4.14】
輸入一個(gè)整數(shù),用遞歸算法將整數(shù)倒序輸出。分析:在遞歸過(guò)程的遞推步驟中用求余運(yùn)算將整數(shù)的各個(gè)位分離,并打印出來(lái)。#include<iostream.h>voidbackward(intn){ cout<<n%10; if(n<10)return; elsebackward(n/10);}voidmain(){ intn;
cout<<"輸入整數(shù):"<<endl; cin>>n; cout<<"原整數(shù):"<<n<<endl<<"反向數(shù):"; backward(n); cout<<endl;}4.6
函數(shù)的遞歸調(diào)用n=247cout<<7;backward(24);n=2cout<<2;return;n=24cout<<4;backward(2);backward(247)
return;
return;
cout<<endl;
求余總是取當(dāng)前整數(shù)的最右一位,所以先輸出余數(shù)后遞歸可實(shí)現(xiàn)倒序輸出。如果先遞歸后輸出余數(shù),則是在回歸的過(guò)程中輸出,實(shí)現(xiàn)的就是正序輸出。從以上幾例可以看出,遞歸算法一般不需要借助循環(huán),但通過(guò)不斷遞推和回歸的過(guò)程實(shí)現(xiàn)了其他算法用循環(huán)完成的功能。因此,遞歸的終止條件非常重要,否則將會(huì)無(wú)休止地遞歸下去,陷入死循環(huán)狀態(tài)。【例4.15】在【例3.11】中采用遞推法求解Fibonacii數(shù)列,本例用遞歸法求解。本例的遞歸調(diào)用過(guò)程參見圖4.11。#include<iostream.h>#include<iomanip.h>intfib(intn){ if(n==0)return0; elseif(n==1)return1; elsereturnfib(n-1)+fib(n-2);}voidmain(){ for(inti=0;i<=19;i++){
//將19改為69,可以看出計(jì)算到后面越來(lái)越緩慢。 if(i%5==0)cout<<endl; cout<<setw(6)<<fib(i);} cout<<endl;}4.6
函數(shù)的遞歸調(diào)用圖4.11遞歸求解斐波那契數(shù)列調(diào)用樹同其他算法相比,用遞歸算法編制的程序非常簡(jiǎn)潔易讀,但缺點(diǎn)是增加了內(nèi)存的開銷,在遞推的過(guò)程中會(huì)占用大量??臻g,且連續(xù)的調(diào)用返回操作占用較多CPU時(shí)間。因此是否選擇使用遞歸算法取決于所解決的問(wèn)題及應(yīng)用的場(chǎng)合。4.6
函數(shù)的遞歸調(diào)用C++不允許對(duì)函數(shù)作嵌套定義,也就是說(shuō)在一個(gè)函數(shù)中不能完整地包含另一個(gè)函數(shù)。在一個(gè)程序中每一個(gè)函數(shù)的定義都是互相平行和獨(dú)立的。雖然C++不能嵌套定義函數(shù),但可以嵌套調(diào)用函數(shù),也就是說(shuō),在調(diào)用一個(gè)函數(shù)的過(guò)程中,又調(diào)用另一個(gè)函數(shù)。見下圖4。函數(shù)的嵌套調(diào)用在程序中實(shí)現(xiàn)函數(shù)嵌套調(diào)用時(shí),需要注意的是:在調(diào)用函數(shù)之前,需要對(duì)每一個(gè)被調(diào)用的函數(shù)作聲明(除非定義在前,調(diào)用在后)。例4.9用弦截法求方程f(x)=x3-5x2+16x-80=0的根。這是一個(gè)數(shù)值求解問(wèn)題,需要先分析用弦截法求根的算法。根據(jù)數(shù)學(xué)知識(shí),可以列出以下的解題步驟:(1)取兩個(gè)不同點(diǎn)x1,x2,如果f(x1)和f(x2)符號(hào)相反,則(x1,x2)區(qū)間內(nèi)必有一個(gè)根。如果f(x1)與f(x2)同符號(hào),則應(yīng)改變x1,x2,直到f(x1),f(x2)異號(hào)為止。注意x1、x2的值不應(yīng)差太大,以保證(x1,x2)區(qū)間內(nèi)只有一個(gè)根。(2)連接(x1,f(x1))和(x2,f(x2))兩點(diǎn),此線(即弦)交x軸于x,見圖4.7。x點(diǎn)坐標(biāo)可用下式求出:x=x1·f(x2)-x2·f(x1)f(x2)-f(x1)再?gòu)膞求出f(x)。(3)若f(x)與f(x1)同符號(hào),則根必在(x,x2)區(qū)間內(nèi),此時(shí)將x作為新的x1。如果f(x)與f(x2)同符號(hào),則表示根在(x1,x)區(qū)間內(nèi),將x作為新的x2。(4)重復(fù)步驟(2)和(3),直到|f(x)|<ξ為止,ξ為一個(gè)很小的正數(shù),例如10-6。此時(shí)認(rèn)為f(x)≈0。這就是弦截法的算法,在程序中分別用以下幾個(gè)函數(shù)來(lái)實(shí)現(xiàn)以上有關(guān)部分功能:(1)用函數(shù)f(x)代表x的函數(shù):x3-5x2+16x-80。(2)用函數(shù)xpoint(x1,x2)來(lái)求(x1,f(x1))和(x2,f(x2))的連線與x軸的交點(diǎn)x的坐標(biāo)。(3)用函數(shù)root(x1,x2)來(lái)求(x1,x2)區(qū)間的那個(gè)實(shí)根。顯然,執(zhí)行root函數(shù)的過(guò)程中要用到xpoint函數(shù),而執(zhí)行xpoint函數(shù)的過(guò)程中要用到f函數(shù)。根據(jù)以上算法,可以編寫出下面的程序:#include<iostream>#include<iomanip>#include<cmath>usingnamespacestd;doublef(double);//函數(shù)聲明doublexpoint(double,double);//函數(shù)聲明doubleroot(double,double);//函數(shù)聲明intmain(){doublex1,x2,f1,f2,x;do{cout<<″inputx1,x2:″;cin>>x1>>x2;f1=f(x1);f2=f(x2);}while(f1*f2>=0);x=root(x1,x2);cout<<setiosflags(ios∷fixed)<<setprecision(7);//指定輸出7位小數(shù)cout<<″Arootofequationis″<<x<<endl;return0;}doublef(doublex)//定義f函數(shù),以實(shí)現(xiàn)f(x){doubley;y=x*x*x-5*x*x+16*x-80;returny;}doublexpoint(doublex1,doublex2)//定義xpoint函數(shù),求出弦與x軸交點(diǎn){doubley;y=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1));//在xpoint函數(shù)中調(diào)用f函數(shù)returny;}doubleroot(doublex1,doublex2)//定義root函數(shù),求近似根{doublex,y,y1;y1=f(x1);do{x=xpoint(x1,x2);//在root函數(shù)中調(diào)用xpoint函數(shù)y=f(x);//在root函數(shù)中調(diào)用f函數(shù)if(y*y1>0){y1=y;x1=x;}elsex2=x;}while(fabs(y)>=0.00001);returnx;}運(yùn)行情況如下:inputx1,x2:2.56.7↙Arootofequationis5.0000000對(duì)程序的說(shuō)明:(1)在定義函數(shù)時(shí),函數(shù)名為f,xpoint和root的3個(gè)函數(shù)是互相獨(dú)立的,并不互相從屬。這3個(gè)函數(shù)均定為雙精度型。(2)3個(gè)函數(shù)的定義均出現(xiàn)在main函數(shù)之后,因此在main函數(shù)的前面對(duì)這3個(gè)函數(shù)作聲明。習(xí)慣上把本程序中用到的所有函數(shù)集中放在最前面聲明。(3)程序從main函數(shù)開始執(zhí)行。函數(shù)的嵌套調(diào)用見圖4.8。圖4.8(4)在root函數(shù)中要用到求絕對(duì)值的函數(shù)fabs,它是對(duì)雙精度數(shù)求絕對(duì)值的系統(tǒng)函數(shù)。它屬于數(shù)學(xué)函數(shù)庫(kù),故在文件開頭用#include<cmath>把有關(guān)的頭文件包含進(jìn)來(lái)。4.7函數(shù)的一些高級(jí)議題4.7.1函數(shù)重載
4.7.2
4.7.3函數(shù)模板缺省變?cè)?.7.1函數(shù)重載在C++中,如果需要定義幾個(gè)功能相似,而參數(shù)類型不同的函數(shù),那么這樣的幾個(gè)函數(shù)可以使用相同的函數(shù)名,這就是函數(shù)重載。例如求和函數(shù),對(duì)應(yīng)不同的參數(shù)類型,可以定義如下幾個(gè)重載函數(shù):sum(inta,intb)//不寫返回類型,返回整型doublesum(doublea,doubleb)floatsum(floata,floatb,floatc)當(dāng)某個(gè)函數(shù)中調(diào)用到重載函數(shù)時(shí),編譯器會(huì)根據(jù)實(shí)參的類型去對(duì)應(yīng)地調(diào)用相應(yīng)的函數(shù)。匹配過(guò)程按如下步驟進(jìn)行:(1)如果有嚴(yán)格匹配的函數(shù),就調(diào)用該函數(shù);(2)參數(shù)內(nèi)部轉(zhuǎn)換后如果匹配,調(diào)用該函數(shù);(3)通過(guò)用戶定義的轉(zhuǎn)換尋求匹配。因此在定義重載函數(shù)時(shí)必須保證參數(shù)類型不同或參數(shù)個(gè)數(shù)不同,僅僅返回值類型不同是不行的。函數(shù)重載的好處在于,可以用相同的函數(shù)名來(lái)定義一組功能相同或類似的函數(shù),程序的可讀性增強(qiáng)。4.7.1函數(shù)重載3+5=調(diào)用sum(3,5)函數(shù)sum(3,5)return82.2+5.6=調(diào)用sum(2.2,5.6)函數(shù)doublesum(2.2,5.6)return7.83.5+4+8=調(diào)用sum(3.5,4,8)函數(shù)floatsum(3.5,4,8)return15.5結(jié)束87.815.5【例4.16】
重載函數(shù)的應(yīng)用。#include<iostream.h>sum(inta,intb){ returna+b;}Doublesum(doublea,doubleb){ returna+b;}floatsum(floata,floatb,floatc){ returna+b+c;}voidmain(){ cout<<"3+5="<<sum(3,5) <<endl; cout<<"2.2+5.6=“ <<sum(2.2,5.6)<<endl; cout<<"3.5+4+8=“ <<sum(3.5,4,8)<<endl;}4.7.2模板
為了代碼重用,代碼就必須是通用的;通用的代碼就必須不受數(shù)據(jù)類型的限制。那么我們可以把數(shù)據(jù)類型改為一個(gè)設(shè)計(jì)參數(shù)。這種類型的程序設(shè)計(jì)稱為參數(shù)化(parameterize)程序設(shè)計(jì)。軟件模塊由模板(template)構(gòu)造。包括函數(shù)模板(functiontemplate)和類模板(classtemplate)。
4.7.3函數(shù)模板及應(yīng)用
4.7.2
函數(shù)模板及應(yīng)用
函數(shù)模板可以用來(lái)創(chuàng)建一個(gè)通用功能的函數(shù),以支持多種不同形參,簡(jiǎn)化重載函數(shù)的設(shè)計(jì)。函數(shù)模板定義如下:template<模板參數(shù)表>返回類型函數(shù)名(形式參數(shù)表){……;}//函數(shù)體<模板參數(shù)表>(templateparameterlist)尖括號(hào)中不能為空,參數(shù)可以有多個(gè),用逗號(hào)分開。模板參數(shù)主要是模板類型參數(shù)。模板類型參數(shù)(templatetypeparameter)代表一種類型,由關(guān)鍵字class或typename(建議用typename)后加一個(gè)標(biāo)識(shí)符構(gòu)成,在這里兩個(gè)關(guān)鍵字的意義相同,它們表示后面的參數(shù)名代表一個(gè)潛在的內(nèi)置或用戶定義的類型。#include<iostream>usingnamespacestd;template<typenameT>//模板聲明,其中T為類型參數(shù)Tmax(Ta,Tb,Tc)//定義一個(gè)通用函數(shù),用T作虛擬的類型名{if(b>a)a=b;if(c>a)a=c;returna;}intmain(){inti1=185,i2=-76,i3=567,i;doubled1=56.87,d2=90.23,d3=-3214.78,d;longg1=67854,g2=-912456,g3=673456,g;i=max(i1,i2,i3);//調(diào)用模板函數(shù),此時(shí)T被int取代d=max(d1,d2,d3);//調(diào)用模板函數(shù),此時(shí)T被double取代g=max(g1,g2,g3);//調(diào)用模板函數(shù),此時(shí)T被long取代cout<<″i_max=″<<i<<endl;cout<<″f_max=″<<f<<endl;cout<<″g_max=″<<g<<endl;return0;}程序第3~8行是定義模板。定義函數(shù)模板的一般形式為template<typenameT>或template<classT>通用函數(shù)定義通用函數(shù)定義在建立函數(shù)模板時(shí),用虛擬的類型名T代替具體的數(shù)據(jù)類型。在對(duì)程序進(jìn)行編譯時(shí),遇到第13行調(diào)用函數(shù)max(i1,i2,i3),編譯系統(tǒng)會(huì)將函數(shù)名max與模板max相匹配,將實(shí)參的類型取代了函數(shù)模板中的虛擬類型T。此時(shí)相當(dāng)于已定義了一個(gè)函數(shù):intmax(inta,intb,intc){if(b>a)a=b;if(c>a)a=c;returna;}然后調(diào)用它。后面兩行(14,15行)的情況類似。類型參數(shù)可以不只一個(gè),可以根據(jù)需要確定個(gè)數(shù)。如template<classT1,typenameT2>可以看到,用函數(shù)模板比函數(shù)重載更方便,程序更簡(jiǎn)潔。但應(yīng)注意它只適用于函數(shù)的參數(shù)個(gè)數(shù)相同而類型不同,且函數(shù)體相同的情況,如果參數(shù)的個(gè)數(shù)不同,則不能用函數(shù)模板。
一般情況下,函數(shù)調(diào)用時(shí)的實(shí)參個(gè)數(shù)應(yīng)與形參相同,但為了更方便地使用函數(shù),C++也允許定義具有缺省參數(shù)的函數(shù),這種函數(shù)調(diào)用時(shí)實(shí)參個(gè)數(shù)可以與形參不相同。4.7.3缺省參數(shù)缺省參數(shù)指在定義函數(shù)時(shí)為形參指定缺省值(默認(rèn)值)。這樣的函數(shù)在調(diào)用時(shí),對(duì)于缺省參數(shù),可以給出實(shí)參值,也可以不給出參數(shù)值。如果給出實(shí)參,將實(shí)參傳遞給形參進(jìn)行調(diào)用,如果不給出實(shí)參,則按缺省值進(jìn)行調(diào)用。缺省參數(shù)的函數(shù)調(diào)用:缺省實(shí)參并不一定是常量表達(dá)式,可以是任意表達(dá)式,甚至可以通過(guò)函數(shù)調(diào)用給出。如果缺省實(shí)參是任意表達(dá)式,則函數(shù)每次被調(diào)用時(shí)該表達(dá)式被重新求值。但表達(dá)式必須有意義;
例4.8求2個(gè)或3個(gè)正整數(shù)中的最大數(shù),用帶有默認(rèn)參數(shù)的函數(shù)實(shí)現(xiàn)。#include<iostream>usingnamespacestd;intmain(){intmax(inta,intb,intc=0);//函數(shù)聲明,形參c有默認(rèn)值inta,b,c;cin>>a>>b>>c;cout<<″max(a,b,c)=″<<max(a,b,c)<<endl;//輸出3個(gè)數(shù)中的最大者cout<<″max(a,b)=″<<max(a,b)<<endl;//輸出2個(gè)數(shù)中的最大者return0;}intmax(inta,intb,intc)//函數(shù)定義{if(b>a)a=b;if(c>a)a=c;returna;}缺省參數(shù)通過(guò)表達(dá)式給出,所以可以使用函數(shù)調(diào)用,如:
intfun1(inta=rand());參數(shù)a缺省時(shí),可由隨機(jī)數(shù)發(fā)生函數(shù)當(dāng)場(chǎng)產(chǎn)生,編譯時(shí)定的是調(diào)什么函數(shù)。4.7.3缺省參數(shù)缺省參數(shù)可以有多個(gè),但所有缺省參數(shù)必須放在參數(shù)表的右側(cè),即先定義所有的非缺省參數(shù),再定義缺省參數(shù)。這是因?yàn)樵诤瘮?shù)
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030汽車尾氣凈化技術(shù)行業(yè)催化劑材料研發(fā)及產(chǎn)業(yè)化分析報(bào)告
- 2025-2030汽車變速箱行業(yè)產(chǎn)品升級(jí)市場(chǎng)競(jìng)爭(zhēng)現(xiàn)狀行業(yè)標(biāo)準(zhǔn)制定投資機(jī)會(huì)規(guī)劃分析研究報(bào)告
- 2025-2030汽車制造行業(yè)現(xiàn)狀技術(shù)革新投資機(jī)會(huì)發(fā)展前景研究報(bào)告
- 2025-2030汽油供應(yīng)市場(chǎng)發(fā)展確認(rèn)分析及投資布局的系統(tǒng)瓶頸評(píng)價(jià)
- 2026年跨境營(yíng)銷策劃公司海外經(jīng)銷商合作管理制度
- 學(xué)生綜合素質(zhì)考核制度
- 中國(guó)敘事策略的國(guó)際傳播倫理研究課題申報(bào)書
- 2025年醫(yī)療廢物管理考試試題與答案
- 18 天下第一樓2025-2026學(xué)年統(tǒng)編版語(yǔ)文九年級(jí)下冊(cè)
- 區(qū)塊鏈在支付領(lǐng)域的應(yīng)用-第1篇-洞察及研究
- 2025至2030中國(guó)生物芯片(微陣列和和微流控)行業(yè)運(yùn)營(yíng)態(tài)勢(shì)與投資前景調(diào)查研究報(bào)告
- 結(jié)核性支氣管狹窄的診治及護(hù)理
- 2025年鐵嶺衛(wèi)生職業(yè)學(xué)院?jiǎn)握新殬I(yè)適應(yīng)性考試模擬測(cè)試卷附答案
- 急腹癥的識(shí)別與護(hù)理
- 凈菜加工工藝流程與質(zhì)量控制要點(diǎn)
- 2025年新能源電力系統(tǒng)仿真技術(shù)及應(yīng)用研究報(bào)告
- 第02講排列組合(復(fù)習(xí)講義)
- 大型商業(yè)綜合體消防安全應(yīng)急預(yù)案
- 《砂漿、混凝土用低碳劑》
- 無(wú)人機(jī)性能評(píng)估與測(cè)試計(jì)劃
- 2025年保安員(初級(jí))考試模擬100題及答案(一)
評(píng)論
0/150
提交評(píng)論