第5章 函數、函數與運算符重載-03_第1頁
第5章 函數、函數與運算符重載-03_第2頁
第5章 函數、函數與運算符重載-03_第3頁
第5章 函數、函數與運算符重載-03_第4頁
第5章 函數、函數與運算符重載-03_第5頁
已閱讀5頁,還剩246頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

高級語言程序設計C++張海威南開大學信息技術科學學院第5章函數與重載函數的說明與使用1函數的嵌套與遞歸2函數與運算符重載3函數與C++程序結構42Database&InformationSystemLab函數的使用與說明【例5.1】求三次方程的根。計算三次方程x3+px+q=0的一個實根的公式為Database&InformationSystemLab3xr=將計算公式分解為如下步驟令實數xr=A+B令實數A,B分別為實數R,S的立方根令R=-q/2+a,S=-q/2-a令a=sqrt((q/2)*(q/2)+(q/3)*(q/3)*(q/3))函數的使用與說明程序設計步驟輸入方程的參數p和q,輸出方程計算變量a的值計算變量R和變量S的值計算變量A和變量B的值分別對R和S求三次方根求y的三次方根的迭代公式計算Xr的值Database&InformationSystemLab4函數的使用與說明程序代碼Database&InformationSystemLab5#include<iostream>//program5-1#include<cmath>//usefunctionsqrtusingnamespace

std;voidmain(void){

floatp,q,xr; cout<<″Inputparameters:p=″;

cin>>P;

cout<<″Inputparameters:q=″; cin>>q;

cout<<"TheEquationis:"; cout<<"x3+"<<p<<"x+"<<q<<"=0"<<endl;

floata=sqrt((q/2)*(q/2)+(q/3)*(q/3)*(q/3));

float

R,S,A,B;

constfloat

eps=1e-6;//設置精確度

R=-q/2+a;

S=-q/2-a;函數的使用和說明Database&InformationSystemLab6

float

root,croot=R;

do{

root=croot;

croot=(2*root+R/(root*root))/3;

}while(fabs(croot-root)>eps);

A=croot;

croot=S;

do{

root=croot;

croot=(2*root+S/(root*root))/3;

}while(fabs(croot-root)>eps);

B=croot; xr

=A+B; cout<<endl<<″Therealrootoftheequationis″<<xr;}函數的使用和說明程序分析程序中包含兩段類似的代碼,完成相同的功能:Database&InformationSystemLab7float

root,croot=R;do{ root=croot;

croot=(2*root+R/(root*root))/3;}while(fabs(croot-root)>eps);A=croot;croot=S;do{

root=croot;

croot=(2*root+S/(root*root))/3;}while(fabs(croot-root)>eps);B=croot;函數的使用和說明函數的引入程序中功能相同,結構相似的代碼段可以用函數進行描述程序的功能相對獨立,用來解決某個問題具有明顯的入口和出口入口:參數出口:返回值Database&InformationSystemLab8函數的使用和說明Database&InformationSystemLab9函數的使用和說明聲明函數cuberoot參數為待求根的變量函數cuberoot的定義如下:Database&InformationSystemLab10floatcuberoot(floatx){//精確到小數點后6位

floatroot,croot;

constfloateps=1e-6; croot=x;

do{

root=croot;

croot=(2*root+x/(root*root))/3;

}while(fabs(croot-root)>eps);

returncroot;}函數的使用和說明函數的作用實現程序功能的模塊化實現程序結構的簡化實現程序代碼的重用函數的應用場景包含多處功能相同的代碼處理數據的類型、處理過程相同或相似代碼段具有代表性或特殊含義Database&InformationSystemLab11函數的使用和說明用函數的思想實現最簡單的C++程序Database&InformationSystemLab12#inlcude<iostream>usingnamespacestd;voidprintString();//函數原型intmain(){printString();//調用函數printString

return0;}voidpirntString(){//函數定義cout<<“Hello!”<<endl;

return;//函數返回}函數的說明與使用函數的使用步驟先說明,后調用程序中必須包含函數的說明及定義函數的說明方式函數原型函數定義可以出現在程序的任何合適的地方函數定義函數定義必須出現在調用函數之前Database&InformationSystemLab13從函數形式劃分,可分為無參函數與有參函數兩類從使用角度劃分,可將函數分為:系統(tǒng)預定義的標準庫函數(如,sin,abs等),以及由用戶自定義的函數函數分類方法14Database&InformationSystemLab函數的說明與使用函數的說明與使用標準庫函數程序中可直接使用(調用)系統(tǒng)預定義的標準庫函數,但要求在調用前使用編譯預處理指令include將對應的頭文件包含進來用戶自定義函數由用戶自定義的函數與系統(tǒng)預定義的標準庫函數的不同點在于,自定義函數的函數名、參數個數、函數返回值類型以及函數所實現的功能等都完全由用戶程序來規(guī)定(指定)Database&InformationSystemLab15函數的說明與使用標準庫函數標準輸入輸出流標準文件流標準字符串類標準數學函數Database&InformationSystemLab16函數的說明與使用用戶自定義函數普通函數內聯(lián)函數類的成員函數類的友元函數虛函數……Database&InformationSystemLab17函數的說明與使用無參函數調用它們時不需要提供實際參數函數原型的一般形式<返回值類型><函數名>();函數定義的一般形式<返回值類型><函數名>(){<函數體>}通常用來實現某種特定的功能不需要進行數據的傳遞處理的數據通常與主調函數無關Database&InformationSystemLab18函數的說明與使用無參函數【例5.2】定義一個函數,實現打印10個“*”的功能Database&InformationSystemLab19voidprintStar(){

for(inti=0;i<10;i++) cout<<“*”;cout<<endl;}

函數的說明與使用有參函數(有參數的用戶自定義函數)進行調用時,必須提供所需個數的且具有相匹配數據類型的實際參數定義的一般形式<函數類型><函數名>(<以逗號分割的形參類型及名字表>){<函數體>}通過調用處提供的不同實參值來計算出其對應的函數值、或實現某種與傳遞過來的那些不同值有關的某種功能。Database&InformationSystemLab20函數的說明與使用有參函數【例5.3】定義一個函數,控制輸出“*”的個數Database&InformationSystemLab21voidprintStar(intk){

for(inti=0;i<k;i++) cout<<“*”;cout<<endl;}

函數的使用調用說明與定義參數重載返回內聯(lián)函數22Database&InformationSystemLab函數的說明與使用函數的說明與使用Database&InformationSystemLab23函數的說明與使用函數的說明和定義在C++程序中,函數有兩種說明方式函數原型在調用函數之前說明函數原型函數定義在調用函數之前對函數進行定義Database&InformationSystemLab24函數的說明與使用函數原型也稱為函數聲明用來指明函數的名稱、參數以及返回值類型函數原型格式為:[<屬性說明>]<返回值類型><函數名>([<參數表>]);例如intadd(inta,intb);inlinevoidswap(float&s,float&t);voidprint(char*);Database&InformationSystemLab25函數的說明與使用函數原型屬性說明:可缺省,一般可以是下面的關鍵字之一inline:表示該函數為內聯(lián)函數static:表示該函數為靜態(tài)函數virtual:表示該函數為虛函數friend:表示該函數為某類(class)的友元函數返回值類型函數處理得到的結果的類型函數名標識符Database&InformationSystemLab26函數的說明與使用函數原型參數表空參數表voidprintroot();void型參數voidprintroot(void);<數據類型>[<參數>][,<數據類型>[<參數>]]*

floatcuberoot(float);floatcuberoot(floatx);Database&InformationSystemLab27函數的說明與使用函數定義函數定義與函數原型的主要區(qū)別是它還包括函數體,其格式為[<屬性說明>]<返回值類型><函數名>([<參數表>]){<函數體>}函數體復合語句即程序塊,由完成函數功能所需的全部語句構成Database&InformationSystemLab28函數的說明與使用函數的說明和定義“函數原型”的說明方式“函數定義”的說明方式Database&InformationSystemLab29#include……usingnamespacestd;voidprintStar(int);//函數原型intmain(){printStar(10);}//調用函數voidprintStar(intk){}//函數定義#include……usingnamespacestd;voidprintStar(intk){}//函數定義intmain(){printStar(10);}//調用函數函數的說明與使用函數的說明和定義兩種說明方式的區(qū)別函數原型的參數表中,參數名可以省略;函數定義的參數表中,必須給出參數名(省略參數名為無名參數)函數原型的函數體,可以出現在函數調用之后;函數定義的函數體,必須出現在調用之前函數原型的參數表后面加分號“;”,函數定義的參數表后面是函數體,即花括號“{”函數定義不能出現在任何函數體中,函數原型可以出現在其它函數體中Database&InformationSystemLab30函數的說明與使用函數的調用函數調用是已定義函數的一次實際運行,與某類型的一個變量和后文中某類的一個對象類似,函數調用是函數定義的一個“實例”在C++程序中,除main函數外,其它任一函數的執(zhí)行都是通過在main函數中直接或間接地調用該函數而引發(fā)的。調用一個函數就是去執(zhí)行該函數之函數體的過程Database&InformationSystemLab31函數的說明與使用函數的調用函數調用過程Database&InformationSystemLab32函數的說明與使用函數的調用函數調用的執(zhí)行順序根據調用語句中的函數名在整個程序中搜索同名函數定義;對實參數的參數個數,類型,順序進行核對,判定是否與函數定義中的形參表對應一致根據參數的類型(值參數或引用參數)進行值參數的值傳遞或引用參數的換名運行函數體代碼返回調用點,并返回所要求的函數值Database&InformationSystemLab33函數的說明與使用函數的調用無參函數調用格式<函數名>()例如:printStar();

有參函數調用格式<函數名>(<以逗號分割的實參表>)例如:printStar(26);Database&InformationSystemLab34函數的說明與使用函數的返回函數的返回表示函數執(zhí)行結束,將執(zhí)行結果(無論是否有具體的數據)返回到調用函數的地方函數返回時完成的任務把運行控制從函數體返回到函數調用點根據返回值要求,返回所需要的數據值返回值類型void數值型引用類型Database&InformationSystemLab35函數的說明與使用函數的返回返回值類型空型(void)如果函數無值返回,應說明為void類型。未作類型說明的函數,系統(tǒng)認為是int類型函數,應返回一整型值值型:返回一個具有類型的值,包括int、float、char、bool等當函數要返回的值不止一個時,情況比較復雜,一般它可以以結構或類的形式,也可以以結構,數組或對象指針類型方式實現,這樣的實例在后面的章節(jié)可以見到引用類型:詳見第6章Database&InformationSystemLab36函數的說明與使用函數的返回函數返回用return語句表示return語句有如下幾種寫法return;//函數返回值類型為空(void)return<表達式>;//與函數返回值的類型一致return

(<表達式>);//與前一種寫法等價Database&InformationSystemLab37第一種格式的return用于立即從被調函數中返回,當函數類型為void時,應使用這種格式的返回語句。當函數類型為非void型時,應使用第二或第三種格式的return語句,此兩種格式的語句效果完全相同(可將第二種格式看成是第三種格式的省略形式),系統(tǒng)此時都將計算出表達式的值,并“攜帶”該值立即從被調函數中返回函數的說明與使用函數應用舉例【例5.4】設f(x)=(x*x+x+1)/2-5.5求z=(f(2.5)+2*f(6))/f(4.3),并顯示結果z。對任意輸入的一個實數a,求出f(a)并顯示分析:輸入(參數):x輸出(返回):函數的運算結果函數原型:doublef(double);Database&InformationSystemLab38函數的說明與使用函數應用舉例【例5.4】函數定義

doublef(doublex){

doubley; y=(x*x+x+1)/2-5.5;

returny;

//對非void類型的函數,必須有一個//return語句,由它返回函數值

}

Database&InformationSystemLab39函數的說明與使用函數應用舉例【例5.4】程序#include<iostream>usingnamespacestd;doublef(double);intmain(){

doublez,a; z=(f(2.5)+2*f(6))/f(4.3);//調用自定義函數f cout<<"z="<<z<<endl; cout<<"Inputa="; //提示用戶輸入

cin>>a; cout<<"f(a)="<<f(a)<<endl;//算出f(a)并輸出

return0;} doublef(doublex){……}//函數f的定義Database&InformationSystemLab40函數的說明與使用函數應用舉例【例5.4】程序(不帶函數原型)#include<iostream>usingnamespacestd;doublef(doublex){……}//函數f的定義intmain(){

doublez,a; z=(f(2.5)+2*f(6))/f(4.3);//調用自定義函數f cout<<"z="<<z<<endl; cout<<"Inputa="; //提示用戶輸入

cin>>a; cout<<"f(a)="<<f(a)<<endl;//算出f(a)并輸出

return0;} Database&InformationSystemLab41函數的說明與使用函數應用舉例【例5.4】點評f()函數體內的3行也可用如下的一行來代替

return((x*x+x+1)/2-5.5);return句括號內表達式的值,即為整個函數的返回值。return句也可使用另一格式,即可以不括起表達式:

return(x*x+x+1)/2-5.5;//OK!Database&InformationSystemLab42①

f=(x*x+x+1)/2-5.5;

不可給函數名f賦值。②

return(f);

返回值類型應該是double,而非指針類型(函數名相當于一個指針)。③

f(x)=(x*x+x+1)/2-5.5;

賦值號左端非變量(也即f(x)非左值)。

函數的說明與使用函數的參數C++語言的函數分為無參函數和有參函數函數的參數無參數一個參數多個參數函數參數表的寫法一般寫法省略參數名(無名參數)參數賦初值Database&InformationSystemLab43函數的說明與使用函數的參數形參和實參函數說明中的參數稱為形式參數(形參),函數調用中的參數稱為實際參數(實參)實參表在參數個數、參數順序、以及參數類型等方面要與被調函數的形參表之間有一個一一對應的相互匹配關系編譯器將根據參數的順序,來逐一實現實參與對應形參的“結合”,而后執(zhí)行一遍函數體(而完成本次的函數調用)Database&InformationSystemLab44函數的說明與使用函數的參數無名參數函數定義中,只有類型,沒有名稱的參數 intf(inta,intb){returna+b*b;} intf(inta,intb,int){returna*a+b;}兩個不同的函數同名,但由于第二個函數包含一無名參數,使得在調用時能夠被區(qū)分,f(x,y)是第一個函數的調用,f(x,y,0)是第二個函數的調用Database&InformationSystemLab45函數的說明與使用函數的參數可缺省參數(參數的默認值)允許在函數定義處為其中最后面的連續(xù)若干個參數設置默認值(也稱缺省值)若調用處缺省了某個或某些實參的情況下,系統(tǒng)將自動使用那些在函數定義處給定的參數默認值例如,在定義函數func時為其最后三個參數設置默認值:Database&InformationSystemLab46#include<iostream>usingnamespacestd;voidfunc(inta=11,intb=22,intc=33){

//為參數a、b、c設置了默認值11、22與33

cout<<"a="<<a<<",b="<<b<<",c="<<c<<endl;}函數的說明與使用Database&InformationSystemLab47intmain(){func();//調用時缺省了3個實參,將使用 //定義處給定的那3個相對應的參數默認值

func(55);//調用時缺省了后2個實參,將使用 //定義處給定的那后2個對應參數默認值

func(77,99);//調用時缺省了最后1個實參,將使用 //定義處給定的那最后1個參數默認值

func(8,88,888);//調用時沒缺省任一個實參, //系統(tǒng)將不使用定義處給定的任一個參數默認值 return0;}函數的說明與使用運行結果:a=11,b=22,c=33a=55,b=22,c=33a=77,b=99,c=33a=8,b=88,c=888Database&InformationSystemLab48函數的說明與使用函數的參數可缺省參數(參數的默認值)只能為函數最后面的連續(xù)若干個參數設置默認值,且在調用處也只能缺省后面的連續(xù)若干個實參例如:Database&InformationSystemLab49voidfunc(inta,intb=2,intc=3);

//OK!voidfunc(inta=1,intb,intc=3);

//ERROR!

對第一個函數說明,采用如下的調用語句:

func(1,22,333);

//OK!調用時給出所有實參

func();

//ERROR!參數a沒有默認值

func(10,20);

//OK!參數c默認為3

func(5,,9);//ERROR!調用處也只能缺省后面的連續(xù)若干個實參

函數的說明與使用函數調用過程中參數的傳遞一般傳遞過程(賦值傳遞)發(fā)生函數調用,轉到函數體執(zhí)行根據函數的形參,分配內存空間將實參賦值給形參,即為形參分配的存儲空間賦值,此時實參在函數體內失效,形參有效函數執(zhí)行完畢,返回到主調函數,形參所占的空間自動回收,形參失效Database&InformationSystemLab50函數的說明與使用函數調用過程中參數的傳遞按地址傳遞過程發(fā)生函數調用,轉到函數體執(zhí)行根據代表地址的參數,在以該參數為首地址的空間中進行各種處理函數執(zhí)行完畢,無論是否有返回值,函數體對內存空間進行的修改將保留,對主調函數仍然有效Database&InformationSystemLab51函數的說明與使用函數的參數能夠作為函數參數的數據類型基本類型及其派生類型賦值參數傳遞數組、指針、引用等導出類型、按地址傳遞參數類類型、結構類型、聯(lián)合類型等用戶定義類型賦值參數傳遞按地址參數傳遞Database&InformationSystemLab52函數的說明與使用函數的參數一維數組作為函數的參數,數組大小可以指定,也可以不指定,但是多維數組除了第一維之外,其它維的大小必須指定函數原型intsearchArray(int[],int);intsearchArray(int[10],int);函數定義intsearchArray(inta[],intb){//寫為a[10]也可以

returna[b];}Database&InformationSystemLab53函數的說明與使用函數的參數多維數組(以二維數組為例)作為函數的參數,參數表的數組參數可以寫為inta[][10]inta[10][10]

但不可以寫為:inta[][];inta[20][];一維數組以及多維數組的第一維大小,形參、實參可以不對應實參為a[10],形參可以定義為x[6]Database&InformationSystemLab54函數的說明與使用函數的參數數組作為函數參數,是將實參數組的首地址傳遞給形參,而不是將數組的所有元素傳遞給形參在函數體中,根據形參數組首地址和下標指示的偏移量訪問數組元素能夠表示地址的數據類型數組首地址(第一個元素的地址)指針引用Database&InformationSystemLab55函數的說明與使用函數的參數【例5.5】一維數組作參數舉例:設計函數,實現兩個字符數組的連接。Database&InformationSystemLab56#include<iostream>usingnamespacestd;voidstrcat(chars[],charct[]){

inti=0,j=0;

while(s[i]!=0)i++;

while(ct[j]!=0)s[i++]=ct[j++];s[i]='\0';}函數的說明與使用函數的參數【例5.5】主函數部分Database&InformationSystemLab57intmain(void){

chara[40]="李明";

charb[20]="是東南大學學生";strcat(a,b);//實參為數組名cout<<a<<endl;//打印字符數組a

return0;}函數的說明與使用函數的參數【例5.6】多維數組做函數參數舉例:設計函數,實現矩陣的轉置和矩陣乘法,并在主函數中驗證用二維數組存儲矩陣由于數組作為參數,傳遞的是數組的首地址,因此,在函數中對作為形參的數組進行的操作,能夠直接反映到實參數組中Database&InformationSystemLab58函數的說明與使用【例5.6】函數原型及主函數Database&InformationSystemLab59#include<iostream>usingnamespacestd;voidinverse(int[3][6],int[6][3]);//轉置矩陣voidmulti(int[6][3],int[3][4],int[6][4]);//矩陣乘法voidoutput(int[6][4]);//矩陣輸出intmain(){

intmiddle[6][3],result[6][4];

intmatrix1[3][6]={8,10,12,23,1,3,5,7,9,2,4,6, 34,45,56,2,4,6};

intmatrix2[3][4]={3,2,1,0,-1,-2,9,8,7,6,5,4};inverse(matrix1,middle);//實參為數組名multi(middle,matrix2,result);output(result);

return0;}函數的說明與使用【例5.6】轉置和乘法函數定義Database&InformationSystemLab60void

inverse(intmatrix1[3][6],intmiddle[6][3]){//轉置

int

i,j;

for

(i=0;i<3;i++)

for(j=0;j<6;j++)

middle[j][i]=matrix1[i][j];

return;}void

multi(intmiddle[6][3],intmatrix2[3][4],intresult[6][4]){

int

i,j,k;

//矩陣乘法

for

(i=0;i<6;i++){

for

(j=0;j<4;j++){

result[i][j]=0;

for

(k=0;k<3;k++) result[i][j]+=middle[i][k]*matrix2[k][j];}}

return;}函數的說明與使用【例5.6】矩陣輸出函數定義Database&InformationSystemLab61voidoutput(intresult[6][4]){//矩陣輸出

cout<<"result"<<'\n';

inti,j;

for(i=0;i<6;i++){

for(j=0;j<4;j++)cout<<setw(4)<<result[i][j]<<"";cout<<'\n';}

return;}函數的說明與使用函數的參數變量的引用作為函數的形式參數賦值形參:未被說明為引用(&)的參數賦值形參和實參直觀上是一致的,實際是不同的在內存中的地址不同引用形參——變量的引用為變量起“別名”在作為形參的變量前加符號“&”與變量的內存地址相同需要在函數中改變實參值并將變化反映到主調函數的時候,用作為實參的變量引用是一種方法還可以用指針做形參操作變量地址Database&InformationSystemLab62函數的說明與使用函數的參數賦值形參賦值形參的函數調用過程和參數傳遞機制在執(zhí)行函數調用時,在檢查函數名及參數表之后,為賦值參數分配內存計算各對應的實參表達式,并把計算的值賦給剛剛創(chuàng)建的參數變量開始函數體的運行。凡是賦值形參,在函數的每次調用時,都必須為每一個賦值形參創(chuàng)建一個新的參數變量。Database&InformationSystemLab63函數的說明與使用函數的參數賦值形參實參表達式:函數調用語句中,與賦值形參相對應的實參可以是指定類型的常量、變量或表達式。在執(zhí)行函數調用時應把該表達式的值計算出來,作為初值賦給剛剛為賦值形參創(chuàng)建的參數變量。這是賦值調用方式名稱的由來。為賦值形參創(chuàng)建的參數變量是局限于函數體運行的局部變量,它作為該形參的一個實例,參加函數體程序塊的這次運行,一旦運行完畢,這個參數變量就被撤消Database&InformationSystemLab64函數的說明與使用函數的參數實參表達式作參數例如,函數原型:intadd(inta,intb);調用函數時,可以采用如下方式:……intmain(){

intx=5; intc=add(1,4*x+2);//實參為表達式 ……}Database&InformationSystemLab65函數的使用和說明函數的參數【例5.7】編寫函數,實現兩個整數的交換輸入兩個整數輸出初始值交換輸出交換后的值Database&InformationSystemLab66voidswap(intx,inty){

inttemp=x;x=y;y=temp;}函數的說明和使用【例5.7】主函數部分#inlcude<iostream>usingnamespacestd;voidswap(intx,inty){.....}intmain(){

inta,b; cin>>a>>b; cout<<“a=“<<a<<“b=“<<b<<endl; swap(a,b); cout<<“a=“<<a<<“b=“<<b<<endl;

return0;}Database&InformationSystemLab67函數的說明與使用【例5.7】分析程序運行結果顯示,a和b的值沒有進行交換!主函數運行時,為變量a和b分配存儲空間調用函數swap時,為變量x和y分配存儲空間函數體中交換了x和y存儲單元的值a和b所在存儲單元的值沒有交換輸出的仍然是a和b所在存儲單元的值Database&InformationSystemLab68函數的說明與使用函數的參數引用形參函數定義的參數表中,名字前加上符號&的參數為引用形參。例如voidswap(int&a,int&b);引用形參在調用過程中的參數傳遞機制函數的調用語句中對應于引用形參的實參必須是同一類型的變量,非變量的表達式則不允許。參數傳遞的內容不是實參的值,而是地址,其實際的效果是令對應的引用形參在調用過程中,作為一個變量名指向作為實參的這個變量,在引用調用過程中并不創(chuàng)建新的參數變量。這一點有別于賦值調用Database&InformationSystemLab69函數的說明與使用函數的參數引用形參引用形參在調用過程中的參數傳遞機制在函數體程序塊的運行中,引用形參的每次出現,由于它現在已經是指向實參變量,因此相當于全用實參變量所代替。即起到了所謂的“換名”的作用。在函數體程序運行結束,控制轉回調用點時,該引用形參與實參變量的對應關系也就終止了。但是在調用過程中對于這個實參變量的所有處理和操作的結果,卻保留下來。這一點也是區(qū)別于賦值調用的

Database&InformationSystemLab70函數的說明與使用函數的參數引用形參設計函數在下面兩種情形時,建議采用引用參數需要改變某些變量的值(上述函數swap就是一例)對于占內存較多的數據參數,為了不另建新的參數變量以節(jié)省內存為了保證實參不在函數中被修改,可在形參說明中加上const說明,例如:

complexadd(constcomplex&

a,constcomplex&

b);而對于賦值形參,則無此必要。Database&InformationSystemLab71函數的說明與使用函數的參數賦值調用所調用的函數參數為賦值參數引用調用所調用的函數參數為引用參數舉例 voidprintStar(intk,intn);

//它所用的兩個參數均為賦值參數

voidswap(int&x,int&y);

//它所用的兩個參數均為引用參數

intmyFunc(inta,float&b);

//它所用的第一個參數為賦值參數,另一個為引用參數Database&InformationSystemLab72函數的說明與使用函數的參數【例5.7】中的交換函數,采用引用作為參數 voidswap(int&x,int&y){

inttemp=x;x=y;y=temp; }引用參數&x和&y是實參的別名,函數中對引用形參的操作實際上就是對實參的操作

Database&InformationSystemLab73函數的說明與使用函數的參數引用調用方式,實際上傳遞的是參數的地址(實參的地址),函數體中對形參的操作實際上是對實參地址的操作希望在函數中修改實參值并反映到主調函數中的時候,采用引用調用方式指針、數組等能夠表示地址的數據類型作為形參,,可以起到與引用形參相同的作用【例5.5】和【例5.6】是數組作為參數,在函數體中修改數組并反映到主調函數的例子Database&InformationSystemLab74函數的說明與使用函數的參數從賦值或引用參數的角度看函數的調用過程判斷形參是賦值參數還是引用參數將對應實參表達式的值賦給賦值形參(若參數為賦值參數的話);用實參變量替換相應的形參(若參數為引用參數的話);按各形參的“當前值”(或已被“賦值”,或已被“換名”)去執(zhí)行一遍函數體并返回調用處Database&InformationSystemLab75函數的說明與使用函數的參數賦值調用和引用調用傳值方式的區(qū)別通過賦值參數來傳值的方式是一種“單向傳值”方式,它只可向被調函數的形參“傳入”值,而不可通過該形參“傳出”值

通過引用參數來傳值的方式是一種“雙向傳值”方式,它不僅可向被調函數的形參“傳入”值,而且還可通過該形參“傳出”值Database&InformationSystemLab76函數的說明與使用函數的參數【例5.8】賦值調用和引用調用舉例#include<iostream>usingnamespacestd;voidswap(int&a,int&b,intc,intd);//函數原型//前兩個為引用參數,可“雙向傳值”//后兩個為賦值參數Database&InformationSystemLab77函數的說明與使用intmain(){ inti=1,j=2,k=77,n=88;

cout<<“---Inmain,beforcallingf1---"<<endl; cout<<"i,j,k,n="<<i<<""<<j<<""<<k<<""<<n<<endl<<endl; swap(i,j,k,n);

//注意,調用后實參變量i、j的值進行了改變 //而k與n的值并不改變

cout<<"---Inmain,aftercallingf1---"<<endl; cout<<"i,j,k,n="<<i<<""<<j<<""<<k<<""<<n<<endl;}Database&InformationSystemLab78函數的說明與使用voidswap(int&a,int&b,intc,intd)

{

/*前兩個為引用參數,后兩個為賦值參數。對引用參數而言,調用時,將用對應實參變量來替換它們。即是說,被調函數中對形參值的使用與改變,就是對主調函數中調用語句處所對應實參變量值的直接使用與改變(“雙向傳值”)*/

cout<<"---Enterf1---"<<endl; cout<<"a,b,c,d="<<a<<""<<b<<""<<c<<""<<d<<endl<<endl; inttmp;

tmp=a;a=b;b=tmp; //交換a與b的值

tmp=c;c=d;d=tmp; //交換c與d的值

cout<<"---Intheendoff1---"<<endl; cout<<"a,b,c,d="<<a<<""<<b<<""<<c<<""<<d<<endl<<endl;}Database&InformationSystemLab79函數的說明與使用程序運行結果---Inmain,beforcallingf1---i,j,k,n=127788

---Enterf1---a,b,c,d=127788

---Intheendoff1---a,b,c,d=218877

---Inmain,aftercallingf1---i,j,k,n=217788Database&InformationSystemLab80函數的說明與使用函數的重載(后面具體講解)多個函數使用相同的函數名函數重載必須滿足下列條件之一參數表中對應的參數類型不同參數表中參數個數不同參數表中不同類型參數的次序不同例如,三個同名函數可以聲明為:printStar();printStar(int);printStar(int,int);Database&InformationSystemLab81函數的說明與使用內聯(lián)函數可在一般的函數說明前冠以關鍵字inline,稱這樣的函數為內聯(lián)函數。說明方式:

inline<函數類型><函數名>(<形參表>)

{ <函數體> }Database&InformationSystemLab82函數的說明與使用內聯(lián)函數在編譯過程中,凡內聯(lián)函數,系統(tǒng)均把它的執(zhí)行代碼插入到該函數的每個調用點處(以取代那一函數調用),從而使程序執(zhí)行過程中,每次對該函數調用時不需控制轉移,可節(jié)省執(zhí)行時間由于每個調用點處均出現那一函數的執(zhí)行代碼拷貝,相對來說使用內聯(lián)函數后會擴大其代碼空間Database&InformationSystemLab83函數的說明與使用內聯(lián)函數舉例#include<iostream.h>inlineintmax(intx,inty){//內聯(lián)函數max

return(x>y?x:y);}voidmain(){

inta,b; cout<<"Inputa,b:"; cin>>a>>b; cout<<"max(a,b)="<<max(a,b)<<endl;

//對內聯(lián)函數max的調用}Database&InformationSystemLab84函數的說明與使用內聯(lián)函數說明內聯(lián)函數的函數體一般講不宜過大,以1--5行為宜。凡在類體中定義的成員函數(見第7章)均隱含為內聯(lián)函數Database&InformationSystemLab85函數的說明與使用函數使用的其它問題(后面具體講解)函數的生存期與作用域函數中變量的生存期與作用域參數函數體內的局部變量函數體內的全局變量函數的存儲屬性外部存儲屬性靜態(tài)存儲屬性函數間的數據傳遞方式Database&InformationSystemLab86函數的說明與使用函數使用舉例【例5.9】三色冰淇淋程序由冰激凌商提出的問題:有28種顏色的原料,可以組合成多少種3色冰激凌問題歸結為計算排列數與組合數。本示例計算排列數A(elements,selections)及組合數C(elements,selections)。如:

A(3,2)=6,C(3,2)=3; A(28,3)=19656,C(28,3)=3276。Database&InformationSystemLab87函數的說明與使用【例5.9】分析求排列數的公式A(ele,sel):A(ele,sel)=ele!/(ele-sel)!求組合數的公式C(ele,sel):C(ele,sel)=A(ele,sel)/sel!設計階乘函數,求上述各階乘的值并可以實現排列數和組合數的求值Database&InformationSystemLab88函數的說明與使用【例5.9】計算階乘的函數定義longfactorial(intnumber){

longvalue=1;

while(number>1){ value*=number; number--; }

returnvalue;}Database&InformationSystemLab89函數的說明與使用【例5.9】主程序部分#include<iostream>usingnamespacestd;longfactorial(intnumber);//函數原型intmain(){ inti,selections,elements;

//計算A(elements,selections) //以及C(elements,selections)

cout<<"Numberofselections:"; cin>>selections;//輸入整數selections cout<<"Outofhowmanyelements:"; cin>>elements;//輸入整數elements doubleanswer=elements; intele=elements;Database&InformationSystemLab90函數的說明與使用

answer=factorial(elements)/factorial(elements-selects); cout<<“A(”<<elements<<“,”<<selections<<“)=”<<answer<<endl;//輸出排列數A(ele,sel)之結果

//組合數C的求法:

answer/=factorial(selections); cout<<"C("<<elements<<","<<selections<<")="<<answer<<endl;//輸出組合數C(ele,sel)之結果

return0;}

Database&InformationSystemLab91第5章函數與重載函數的說明與使用1函數的嵌套與遞歸2函數與運算符重載3函數與C++程序結構492Database&InformationSystemLab函數的嵌套與遞歸函數的嵌套一個函數的函數體中包含一個或多個函數調用語句,即稱為函數嵌套嵌套的含義是,如果函數A要調用函數B,也就是說,函數A的定義要依賴于函數B的定義。因此函數B的定義或函數B的原型必須出現在函數A的定義語句之前。另一方面,函數A調用函數B,在調用A的過程中,即執(zhí)行A的函數體過程中,調用B,也就是中途把程序控制轉到B的函數體,在執(zhí)行結束后再返回到A的函數體中Database&InformationSystemLab93函數的嵌套與遞歸函數的嵌套示意圖Database&InformationSystemLab94函數的嵌套與遞歸函數的嵌套函數嵌套調用所占用的內存空間(如賦值參數的創(chuàng)建等等)用堆棧(stack)的方式管理。一般這種堆棧所分配的空間是有限的,因此函數互相嵌套的層數也是有限的,依編譯系統(tǒng)不同,其允許的嵌套層數也可能不同Database&InformationSystemLab95函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構Database&InformationSystemLab96函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構主函數運行時,棧區(qū)的情況Database&InformationSystemLab97函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構Database&InformationSystemLab98函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構發(fā)生函數調用時(調用a函數),“保護”主函數當前的運行狀態(tài),記錄被調函數的返回地址Database&InformationSystemLab99函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構Database&InformationSystemLab100函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構運行a函數,記錄a函數的參數和局部變量的值Database&InformationSystemLab101函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構Database&InformationSystemLab102函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構調用b函數,保護a函數的當前狀態(tài),記錄b函數的返回地址Database&InformationSystemLab103函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構Database&InformationSystemLab104函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構運行b函數,記錄b函數的參數和局部變量的值Database&InformationSystemLab105函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構Database&InformationSystemLab106函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構b函數運行結束并返回,b函數的變量和參數失效,變量和參數由棧區(qū)“彈出”,根據b函數的返回地址返回,讀取a函數的運行狀態(tài)繼續(xù)運行a函數Database&InformationSystemLab107函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構Database&InformationSystemLab108函數的嵌套與遞歸函數的嵌套函數嵌套調用過程中的棧結構a函數運行結束并返回,a函數的變量和參數失效,變量和參數由棧區(qū)“彈出”,根據a函數的返回地址返回,讀取主函數的運行狀態(tài)繼續(xù)運行主函數Database&InformationSystemLab109函數的嵌套與遞歸函數的嵌套【例5.10】編寫程序,用冒泡排序的算法對數組中的元素按照由小到大的順序進行排序輸入數組調用排序函數進行排序參數:待排序的數組返回:空由于參數為數組,即數組的首地址,函數體中處理數組的地址,因此,對數組的修改可以直接反映到主調函數中輸出排序后的數組Database&InformationSystemLab110函數的嵌套與遞歸【例5.10】函數bubSort代碼voidbubSort(inta[],intn){

for(inti=0;i<n;i++){

for(intj=n-1;j>i;j--){

if(a[j]<a[j-1]){ swap(a[j],a[j-1]); } } }}Database&InformationSystemLab111函數的嵌套與遞歸【例5.10】函數swap代碼voidswap(int&x,int&y){ inttemp=x; x=y; y=temp;}Database&InformationSystemLab112函數的嵌套與遞歸【例5.10】主程序代碼#include<iostream>#include<stdlib>#include<time>#include<iomanip>usingnamespacestd;constintn=100;intmain(){

intb[n]; srand((unsigned)time(NULL));

for(inti=0;i<n;i++) b[i]=rand();Database&InformationSystemLab113函數的嵌套與遞歸 bubSort(b,n);

for(i=0;i<n;i++){ cout<<setw(5)<<b[i];

if(i%10==0) cout<<endl; }

return0;}/*設計函數,分別按產生順序和排序后的順序輸出隨機數,輸出寬度為5,每輸出10個數換行*/Database&InformationSystemLab114函數的嵌套與遞歸函數的遞歸C++允許函數自己調用自己(如A函數可以調用A函數本身,稱為直接遞歸)。也允許A函數調用B函數,而后B函數又調用A函數(從而形成間接遞歸)。但不論使用哪種遞歸,程序員都應保障遞歸函數在執(zhí)行若干次后能夠“退出”遞歸(不再進行遞歸調用,也即能夠實現遞歸出口)Database&InformationSystemLab115函數的嵌套與遞歸函數的遞歸遞歸函數的執(zhí)行分為“遞推”和“回歸”兩個過程,這兩個過程由遞歸終止條件控制,即逐層遞推,直至遞歸終止條件,然后逐層回歸。每次調用發(fā)生時都首先判斷遞歸終止條件。Database&InformationSystemLab116函數的嵌套與遞歸函數的遞歸遞歸調用同普通的函數調用一樣,每當調用發(fā)生時,在棧中分配單元保存返回地址以及參數和局部變量;而與普通的函數調用不同的是,由于遞推的過程是一個逐層調用的過程,因此存在一個逐層連續(xù)的參數入棧過程,直至遇到遞歸終止條件時,才開始回歸,這時才逐層釋放??臻g,返回到上一層,直至最后返回到主調函數Database&InformationSystemLab117函數的嵌套與遞歸函數的遞歸【例5.11】計算年齡【例5.12】求階乘,三色冰淇淋程序【例5.13】反序輸出問題【例5.14】輸入一個整數,將數字反序輸出【例5.15】漢諾塔問題【例5.16】讀程序,寫結果Database&InformationSystemLab118函數的嵌套與遞歸函數的遞歸【例5.11】有5個人坐在一起,問第5個人多少歲?他說,比第4個人大兩歲。問第4個人多少歲?他說,比第3個人大兩歲。問第3個人多少歲?他說,比第2個人大兩歲。問第2個人多少歲?他說,比第1個人大兩歲。問第1個人多少歲?他說是十歲。請問,第5個人多大?欲求第5個人的年齡,就必須先知道第4個人的年齡,欲求第4個人的年齡,就必須先知道第3個人的年齡,欲求第3個人的年齡,就必須先知道第2個人的年齡,欲求第2個人的年齡,就必須先知道第1個人的年齡,而且每個人的年齡都比前一個人大兩歲Database&InformationSystemLab119函數的嵌套與遞歸【例5.11】分析5個人的年齡可以分別表示為age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10通項式為:age(1)=10age(n)=age(n-1)+2Database&InformationSystemLab120函數的嵌套與遞歸【例5.11】遞歸過程圖示Database&InformationSystemLab121函數的嵌套與遞歸【例5.11】求年齡的遞歸函數age()定義intage(intn){

intperson_age;

if(n==1) person_age=10;

else person_age=age(n-1)+2;

returnperson_age;}Database&InformationSystemLab122函數的嵌套與遞歸【例5.11】主程序部分#include<iostream>usingnamespacestd;intmain(){ cout<<“第5個人的年齡為:”<<age(5)<<“歲”; cout<<endl;

return0;}Database&InformationSystemLab123函數的嵌套與遞歸函數的遞歸【例5.12】用遞歸函數求整數n的階乘1!=1n!=n*(n-1)!遞歸函數定義longfac(intn){

if((n==1)||(n==0))

return1;

else

returnn*fac(n-1);}Database&InformationSystemLab124函數的嵌套與遞歸函數的遞歸【例5.13】反序輸出:從鍵盤輸入10個int型數,而后按輸入的相反順序輸出它們。例如:輸入:12345678910

輸出:10987654321Database&InformationSystemLab125函數的嵌套與遞歸【例5.13】分析遞推過程將輸入的10個數,由第10個推到第1個回歸過程由第1個數開始輸出后項依賴于前項的“輸出”,而不是像以前程序那樣依賴前一項的值Database&InformationSystemLab126函數的嵌套與遞歸【例5.13】遞歸過程圖示Database&InformationSystemLab127函數的嵌套與遞歸【例5.13】遞歸函數定義voidinv(intn){

inti; cin>>i;//輸入整數

if(n==1) cout<<“Theresult:”<<endl;

else inv(n-1); cout<<i<<““;//輸出整數,每次遞歸調用返 //回之后都要執(zhí)行}Database&InformationSystemLab128函數的嵌套與遞歸【例5.13】主程序部分#include<iostream>usingnamespacestd;intmain(){ cout<<“Input10integers:”<<endl; inv(10); cout<<endl;

return0;}Database&InformationSystemLab129函數的嵌套與遞歸函數的遞歸【例5.14】反序輸出一個正整數的各位數值,如輸入231,應輸出132遞歸函數定義如下: voidconv(intn){

if(n<10){ cout<<n;

return; }//遞歸出口 cout<<n%10; conve(n/10);//遞歸 }Database&InformationSystemLab130函數的嵌套與遞歸【例5.14】遞歸過程圖示Database&InformationSystemLab131函數的嵌套與遞歸【例5.14】用非遞歸函數實現intconv(intn){

if(n<0) cout<<“Pleaseinputapositivenumber!”;

else{

do{ cout<<n%10;

n=/10;

}while(n!=0); }}Database&InformationSystemLab132函數的嵌套與遞歸【例5.14】主程序部分#include<iostream>usingnamespacestd;voidmain(void){

intt;

cout<<”Inputapositivenumber:”;

cin>>t;

cout<<endl;

conv(t);

return0;}Database&InformationSystemLab133函數的嵌套與遞歸函數的遞歸【例5.15】古印度的著名智力測驗問題:有三個立柱A、B、C,在A柱上穿有大小不等的圓盤64個,較大的圓盤在下,較小者在上。要求借助于B柱將A柱上的64個圓盤移到C柱,規(guī)則為:(1)每次只能把一個柱上最上面的圓盤移至另一個柱的最上面;(2)每個柱上總保持較大的圓盤在下,較小者在上。編制程序,實現將任意n個圓盤從A柱借助于B柱移到C柱,并顯示出全部移動過程Database&InformationSystemLab134函數的嵌套與遞歸【例5.15】分析總任務(圓盤數為n的任務):把A柱上的n個圓盤,借助

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論