第5章 C++函數(shù)與程序結(jié)構(gòu) 本章要點(diǎn): 1、掌握函數(shù)的概念、定義和調(diào)用方法。 2、理解C++函數(shù)參數(shù)傳遞的方法:值傳遞和引用傳遞。掌握函數(shù)參數(shù)值傳遞的3、過程,并能夠靈活運(yùn)用。后面的章節(jié)中,將進(jìn)一步學(xué)習(xí)引用傳遞。 4、理解內(nèi)聯(lián)函數(shù)的概念、作用,會(huì)定義內(nèi)聯(lián)函數(shù)。 5、理解函數(shù)重載的概念、作用,能夠熟練地定義和運(yùn)用重載的函數(shù)。 6、理解遞歸的概念,并能運(yùn)用遞歸的方法解決一些實(shí)際問題。 7、理解變量的作用域與生存期的概念,能夠理解全局變量、局部變量、靜態(tài)變量的概念和用法。 C++語言認(rèn)為函數(shù)是一個(gè)能完成某一獨(dú)立功能的子程序,也就是程序模塊。 函數(shù)就是對(duì)復(fù)雜問題的一種“自頂向下,逐步求精”思想的體現(xiàn)。編程者可以將一個(gè)大而復(fù)雜的程序分解為若干個(gè)相對(duì)獨(dú)立而且功能單一的小塊程序(函數(shù))進(jìn)行編寫,并通過在各個(gè)函數(shù)之間進(jìn)行調(diào)用,來實(shí)現(xiàn)總體的功能。 5.1函數(shù)概述 使用函數(shù)的優(yōu)點(diǎn): (1)可讀性好; (2)易于查錯(cuò)和修改; (3)便于分工編寫,分階段調(diào)試; (4)各個(gè)函數(shù)之間接口清晰,便于相互間交換信息和使用; (5)節(jié)省程序代碼和存儲(chǔ)空間; (6)減少用戶總的工作量; (7)成為實(shí)現(xiàn)結(jié)構(gòu)程序設(shè)計(jì)思想的重要工具; (8)擴(kuò)充語言和計(jì)算機(jī)的原設(shè)計(jì)能力; (9)便于驗(yàn)證程序正確性。 設(shè)計(jì)C++程序的過程,實(shí)際上就是編寫函數(shù)的過程,至少也要編寫一個(gè)main()函數(shù)。執(zhí)行C++程序,也就是執(zhí)行相應(yīng)的main()函數(shù)。即從main()函數(shù)的第一個(gè)左花括號(hào)“{”開始,依次執(zhí)行后面的語句,直到最后一個(gè)右花括號(hào)“}”為止。 如果在執(zhí)行過程中遇到其他的函數(shù),則調(diào)用其他函數(shù)。調(diào)用完后,返回到剛才調(diào)用函數(shù)的下一條語句繼續(xù)執(zhí)行。而其他函數(shù)也只有在執(zhí)行main()函數(shù)的過程中被調(diào)用時(shí)才會(huì)執(zhí)行。 函數(shù)可以被一個(gè)函數(shù)調(diào)用,也可以調(diào)用另一個(gè)函數(shù),它們之間可以存在著調(diào)用上的嵌套關(guān)系。但是,C++不允許函數(shù)的定義嵌套,即在函數(shù)定義中再定義一個(gè)函數(shù)是非法的。 C++函數(shù)是一個(gè)獨(dú)立完成某個(gè)功能的語句塊,函數(shù)與函數(shù)之間通過輸入和輸出來聯(lián)系。 在C++程序中調(diào)用函數(shù)之前,首先要對(duì)函數(shù)進(jìn)行定義。如果調(diào)用此函數(shù)在前,函數(shù)定義在后,就會(huì)產(chǎn)生編譯錯(cuò)誤。 為了使函數(shù)的調(diào)用不受函數(shù)定義位置的影響,可以在調(diào)用函數(shù)前進(jìn)行函數(shù)的聲明。這樣,不管函數(shù)是在哪里定義的,只要在調(diào)用前進(jìn)行函數(shù)的聲明,就可以保證函數(shù)調(diào)用的合法性。 函數(shù)定義的一般形式如下: 返回類型 函數(shù)名(參數(shù)表列) { 語句系列 return 合適類型數(shù)值 } 函數(shù)的定義包括以下幾個(gè)部分: 1. 函數(shù)名 2. 參數(shù)表列 3. 返回類型 4. 函數(shù)體 l
函數(shù)名: 一個(gè)符合C++語法要求的標(biāo)識(shí)符,定義函數(shù)名與定義變量名的規(guī)則是一樣的,但應(yīng)盡量避免用下劃線開頭,因?yàn)榫幾g器常常定義一些下劃線開頭的變量或函數(shù)。函數(shù)名應(yīng)盡可能反映函數(shù)的功能,它常常由幾個(gè)單詞組成。如VC中的按下鼠標(biāo)左鍵的響應(yīng)函數(shù)為:OnLButtonDown,這樣就較好的反映了函數(shù)的功能。 l
參數(shù)表列:0個(gè)或多個(gè)變量,用于向函數(shù)傳送數(shù)值或從函數(shù)帶回?cái)?shù)值,每一個(gè)參數(shù)都有自己的類型,它不同于變量定義,因?yàn)閹讉€(gè)變量可以定義在一起,例如quot;int i,j,k;"。如果參數(shù)表列中參數(shù)個(gè)數(shù)為0,我們稱之為無參函數(shù),無參函數(shù)可以定義為: "返回類型 函數(shù)名( ){…}"或"返回類型 函數(shù)名(void){…}" l
返回類型:指定函數(shù)用return返回的函數(shù)值的類型,如果函數(shù)沒有返回值,返回類型應(yīng)為void。 l
函數(shù)體:花括號(hào)中的語句稱為函數(shù)體,一個(gè)函數(shù)的功能,通過函數(shù)體中的語句來完成。 例如: 函數(shù)dec求兩個(gè)數(shù)的差值。
int dec(int x,int y)
{ return(x-y); } 例如: 函數(shù)out用于輸出兩個(gè)數(shù)的差值以及和值。
void out(int x,int y)
//用void表示無返回值
{ cout<<x-y;
cout<<x+y;
} 例如: int max(int a,int b) { int
t;
if(a>b) t=a;
else t=b; return t; } 5.2 函數(shù)的定義與聲明 在C++程序中調(diào)用函數(shù)之前,首先要對(duì)函數(shù)進(jìn)行定義。如果調(diào)用此函數(shù)在前,函數(shù)定義在后,就會(huì)產(chǎn)生編譯錯(cuò)誤。 為了使函數(shù)的調(diào)用不受函數(shù)定義位置的影響,可以在調(diào)用函數(shù)前進(jìn)行函數(shù)的聲明。這樣,不管函數(shù)是在哪里定義的,只要在調(diào)用前進(jìn)行函數(shù)的聲明,就可以保證函數(shù)調(diào)用的合法性。
C++中的每一個(gè)函數(shù)都是從四個(gè)方面來進(jìn)行定義:類型、函數(shù)名、形式參數(shù)表、函數(shù)體。 定義一個(gè)函數(shù)的語法格式為: 類型 函數(shù)名(形式參數(shù)表) { 函數(shù)體; } 例如: int max(int a,int b) {
int t;
if(a>b) t=a;
else t=b;
return t; } 類型就是該函數(shù)的類型,也就是該函數(shù)的返回值的類型,此類型可以是C++中除函數(shù)、數(shù)組類型之外的任何一個(gè)合法的數(shù)據(jù)類型,包括普通類型、指針類型和引用類型等。 函數(shù)的返回值通常指明了該函數(shù)處理的結(jié)果,由函數(shù)體中的return語句給出。一個(gè)函數(shù)可以有返回值,也可以無返回值(稱為無返回值函數(shù)或無類型函數(shù))。此時(shí)需要使用保留字void作為類型名,而且函數(shù)體中也不需要再寫return語句,或者return的后面什么也沒有。 每個(gè)函數(shù)都有類型,如果在函數(shù)定義時(shí)沒有明確指定類型,則默認(rèn)類型為int。 函數(shù)名是一個(gè)有效的C++標(biāo)識(shí)符,遵循一般的命名規(guī)則。在函數(shù)名后面必須跟一對(duì)小括號(hào)“()”,用來將函數(shù)名與變量名或其他用戶自定義的標(biāo)識(shí)符區(qū)分開來。在小括號(hào)中可以沒有任何信息,也可以包含形式參數(shù)表。C++程序通過使用這個(gè)函數(shù)名和實(shí)參表可以調(diào)用該函數(shù)。 主函數(shù)的名稱規(guī)定取編譯器默認(rèn)的名稱main()。 形式參數(shù)表又稱參數(shù)表,寫在函數(shù)名后面的一對(duì)圓括號(hào)內(nèi)。它可包含任意多個(gè)(含0個(gè),即沒有)參數(shù)說明項(xiàng),當(dāng)多于一個(gè)時(shí)其前后兩個(gè)參數(shù)說明項(xiàng)之間必須用逗號(hào)分開。 每個(gè)參數(shù)說明項(xiàng)由一種已定義的數(shù)據(jù)類型和一個(gè)變量標(biāo)識(shí)符組成,該變量標(biāo)識(shí)符稱為該函數(shù)的形式參數(shù),簡(jiǎn)稱形參,形參前面給出的數(shù)據(jù)類型稱為該形參的類型。每個(gè)形參的類型可以為任一種數(shù)據(jù)類型,包括普通類型、指針類型、數(shù)組類型、引用類型等。 一個(gè)函數(shù)定義中的<參數(shù)表>可以被省略,表明該函數(shù)為無參函數(shù),若<參數(shù)表>用void取代,則也表明是無參函數(shù),若<參數(shù)表>不為空,同時(shí)又不是保留字void,則稱為帶參函數(shù)。 <函數(shù)體>是一條復(fù)合語句,它以左花括號(hào)開始,到右花括號(hào)結(jié)束,中間為一條或若干條C++語句,用于實(shí)現(xiàn)函數(shù)執(zhí)行的功能。 注意:在一個(gè)函數(shù)體內(nèi)允許有一個(gè)或多個(gè)return語句,一旦執(zhí)行到其中某一個(gè)return語句時(shí),return后面的語句就不再執(zhí)行,直接返回調(diào)用位置繼續(xù)向下執(zhí)行。
函數(shù)形參也可以在函數(shù)體外說明。如下例: func1(int a, int b) { … } 也可寫成: func1(a,b) int a; int b; { … } 例5-1:給出以下程序的運(yùn)行結(jié)果。 #include
"iostream.h" int func(int n) {if(n>0) return 1; else if(n==0) return 0; else return -1; } void main() { int n; cout<<"Please input
n:"<<endl; cin>>n; cout<<"\nthe
result:"<<func(n)<<endl; }此程序的運(yùn)行結(jié)果為: Please input n: 2
the result:1 Please input n: -2
the
result:-1 請(qǐng)注意:C++中不允許函數(shù)定義嵌套,即在函數(shù)定義中再定義一個(gè)函數(shù)是非法的。一個(gè)函數(shù)只能定義在別的函數(shù)的外部,函數(shù)定義之間都是平行的,互相獨(dú)立的。 例如:下面的代碼在主函數(shù)中非法嵌套了一個(gè)f()函數(shù)定義: void main() {
void f()
{ //…
} } 5.3 函數(shù)原型 函數(shù)聲明也稱函數(shù)模型(或函數(shù)原型)。在主調(diào)函數(shù)中,如果要調(diào)用另一個(gè)函數(shù),則須在本函數(shù)或本文件中的開頭將要被調(diào)用的函數(shù)事先作一聲明。聲明函數(shù),就是告訴編譯器函數(shù)的返回類型、名稱和形參表構(gòu)成,以便編譯系統(tǒng)對(duì)函數(shù)的調(diào)用進(jìn)行檢查。 函數(shù)聲明的一般格式為: 函數(shù)類型 函數(shù)名(形式參數(shù)表); 除了需在函數(shù)聲明的末尾加上一個(gè)分號(hào)“;”之外,其他的內(nèi)容與函數(shù)定義中的第一行(稱函數(shù)頭)的內(nèi)容一樣。 例如:設(shè)有一函數(shù)的定義為:
double func1(double a, int b, float c) { 函數(shù)體 } 正確完整的函數(shù)聲明應(yīng)為:
double
func1(double x, int y, float z);
//末尾要加上分號(hào)
也可以寫為如下形式:
double
func1(double,int,float); //函數(shù)聲明中省略了形參名 或?qū)憺槿缦滦问剑?span lang="EN-US">
double func1(double a, int b, float c); //函數(shù)聲明中的形參名與 函數(shù)定義中的形參名不同
不能寫為如下形式: double
func1(x,y,z); //函數(shù)聲明中省略了形參類型
或: func1(double x, int y, float z);
//函數(shù)聲明中省略了函數(shù)類型
或: double func1(int y, float z, double x);
//函數(shù)聲明中形參順序調(diào)換了
5.4 函數(shù)的調(diào)用
在C++中,除了主函數(shù)main由系統(tǒng)自動(dòng)調(diào)用外,其他函數(shù)都是由主函數(shù)直接或間接調(diào)用的。函數(shù)調(diào)用的語法格式為: 函數(shù)名 (實(shí)際參數(shù)表); 實(shí)參應(yīng)該與函數(shù)定義中的形參表中的形參一一對(duì)應(yīng),即個(gè)數(shù)相等、次序一致且對(duì)應(yīng)參數(shù)的數(shù)據(jù)類型相同或相容
。每個(gè)實(shí)參是一個(gè)表達(dá)式,并且必須有確定的值。 如: g1(25)
//實(shí)參是一個(gè)整數(shù)
g2(x)
//實(shí)參是一個(gè)變量
g3(a,2*b+3) //第一個(gè)為變量,第二個(gè)運(yùn)算表達(dá)式
g4(sin(x),’@’) //第一個(gè)為函數(shù)調(diào)用表達(dá)式,第二個(gè)為字符常量 g5(&d,*p,x/y-1)
//分別為取地址運(yùn)算、間接訪問和一般運(yùn)算表達(dá)式
常見的函數(shù)調(diào)用方式有下列兩種: 方式一:將函數(shù)調(diào)用作為一條表達(dá)式語句使用,只要求函數(shù)完成一定的操作,而不使用其返回值。若函數(shù)調(diào)用帶有返回值,則這個(gè)值將會(huì)自動(dòng)丟失。例如: max(3,5); 方式二:對(duì)于具有返回值的函數(shù)來說,把函數(shù)調(diào)用語句看作語句一部分,使用函數(shù)的返回值參與相應(yīng)的運(yùn)算或執(zhí)行相應(yīng)的操作。例如: int
a=max(3,5); int
a=max(3,5)+1; cout<<max(3,5)<<endl; if(f1(a,b))
cout<<”true”<<endl; int
a=2; a=max(max(a,3),5); 1.C++的函數(shù)調(diào)用過程,需要調(diào)用初始化和善后處理的環(huán)節(jié)。函數(shù)調(diào)用的整個(gè)過程就是??臻g操作的過程。 2.函數(shù)的棧操作原理是一樣的,但具體的實(shí)現(xiàn)因編譯器不同而不同。
#include<iostream.h> int max(int a,int b,int c) { int t; t=a; if(b>t) t=b; if(c>t) t=c; return t; } void main() { int x,y,z;
cout<<"input x y z:" <<endl; cin>>x>>y>>z; int m=max(x,y,z); cout<<”The max is:” <<m <<endl; } 當(dāng)調(diào)用一個(gè)函數(shù)時(shí),整個(gè)調(diào)用過程分為三步進(jìn)行,第一步是參數(shù)傳遞,第二步是函數(shù)體執(zhí)行,第三步是返回,即返回到函數(shù)調(diào)用表達(dá)式的位置。
參數(shù)傳遞稱為“實(shí)虛結(jié)合”,即實(shí)參向形參傳遞信息,使形參具有確切地含義(即具有對(duì)應(yīng)的存儲(chǔ)空間和初值)。這種傳遞又分為兩種不同的方式,一種是按值傳遞,另一種是地址傳遞或引用傳遞。
1. 按值傳遞 以
按值傳遞方式進(jìn)行參數(shù)傳遞的過程為:首先計(jì)算出實(shí)參表達(dá)式的值,接著給對(duì)應(yīng)的形參變量分配一個(gè)存儲(chǔ)空間,該空間的大小等于該形參類型的長(zhǎng)度,然后把已求出
的實(shí)參表達(dá)式的值一一存入到為形參變量分配的存儲(chǔ)空間中,成為形參變量的初值,供被調(diào)用函數(shù)執(zhí)行時(shí)使用。這種傳遞是把實(shí)參表達(dá)式的值傳送給對(duì)應(yīng)的形參變
量,故稱這種傳遞方式為“按值傳遞”。這種方式被調(diào)用函數(shù)本身不對(duì)實(shí)參進(jìn)行操作,也就是說,即使形參的值在函數(shù)中發(fā)生了變化,實(shí)參的值也完全不會(huì)受到影響,仍為調(diào)用前的值。
例5-3:按值傳遞。
#include "iostream.h" void swap(int,int); void main() {
int a=3,b=4;
cout<<"a="<<a<<",b=“ <<b<<endl; swap(a,b);
cout<<"a="<<a<<",b=" <<b
<<endl; } void
swap(int x,int y) { int t=x; x=y; y=t; }
此程序的運(yùn)行結(jié)果為: a=3,b=4 a=3,b=4 2. 地址傳遞 如
果在函數(shù)定義時(shí)將形參的類型說明成指針,對(duì)這樣的函數(shù)進(jìn)行調(diào)用時(shí)就需要指定地址值形式的實(shí)參。這時(shí)的參數(shù)傳遞方式即為地址傳遞方式。這種地址傳遞與上述的
按值傳遞不同,它把實(shí)參的存儲(chǔ)地址傳送給對(duì)應(yīng)的形參,從而使得形參指針和實(shí)參指針指向同一個(gè)地址。因此,被調(diào)用函數(shù)中對(duì)形參指針?biāo)赶虻牡刂分袃?nèi)容的任何
改變都會(huì)影響到實(shí)參。
例5-4:地址傳遞。
#include "iostream.h" void swap(int *,int *); void main() { int a=3,b=4; cout<<"a="<<a<<",b=“ <<b<<endl; swap(&a,&b); cout<<"a="<<a<<",b=“ <<b<<endl; }
void
swap(int *x,int *y) { int t=*x; *x=*y; *y=t; }
此程序的運(yùn)行結(jié)果為: a=3,b=4 a=4,b=3 3. 引用傳遞 按
值傳遞方式容易理解,但形參值的改變不能對(duì)實(shí)參產(chǎn)生影響;地址傳遞方式雖然可以使得形參的改變對(duì)相應(yīng)的實(shí)參有效,但如果在函數(shù)中反復(fù)利用指針進(jìn)行間接訪
問,會(huì)使程序容易產(chǎn)生錯(cuò)誤且難以閱讀。如果以引用作為參數(shù),則既可以使得對(duì)形參的任何操作都能改變相應(yīng)的實(shí)參的數(shù)據(jù),又使函數(shù)調(diào)用顯得方便、自然。引用傳
遞方式是在函數(shù)定義時(shí)在形參前面加上引用運(yùn)算符“&”。
例5-5:引用傳遞。
#include "iostream.h" void swap(int &,int &); void main() { int a=3,b=4; cout<<"a="<<a<<",b=“ <<b<<endl; swap(a,b); cout<<"a="<<a<<",b=“ <<b<<endl; } void
swap(int &x,int &y) { int t=x; x=y; y=t; }
此程序的運(yùn)行結(jié)果為: a=3,b=4 a=4,b=3 由前述可知,C++函數(shù)不能嵌套定義,即一個(gè)函數(shù)不能在另一個(gè)函數(shù)體中進(jìn)行定義。但在使用時(shí),允許嵌套調(diào)用,即在調(diào)用一個(gè)函數(shù)的過程中又調(diào)用另一個(gè)函數(shù)。 例如: func1(int a, float b)
{ float c; c=func2(b-1,b+1);
} int func2(float x, float y)
{ 函數(shù)體
} func1和func2是分別獨(dú)立定義的函數(shù),互不從屬。
一個(gè)函數(shù)直接或間接地調(diào)用自身,這種現(xiàn)象就是函數(shù)的遞歸調(diào)用。 遞歸調(diào)用有兩種方式:直接遞歸調(diào)用和間接遞歸調(diào)用。直接遞歸調(diào)用即在一個(gè)函數(shù)中調(diào)用自身,間接遞歸調(diào)用即在一個(gè)函數(shù)中調(diào)用了其他函數(shù),而在該其他函數(shù)中又調(diào)用了本函數(shù)。
利用函數(shù)的遞歸調(diào)用,可將一個(gè)復(fù)雜問題分解為一個(gè)相對(duì)簡(jiǎn)單且可直接求解的子問題(“遞推”階段);然后將這個(gè)子問題的結(jié)果逐層進(jìn)行回代求值,最終求得原來復(fù)雜問題的解(“回歸”階段)。 例5-12:求n的階乘。(函數(shù)遞歸調(diào)用的例程。)
#include "iostream.h" long f(int n) {if(n<0) {cout<<“error!“ <<endl;
return(-1);} else if(n<=1)
return(1); else return (n*f(n-1)); } void
main() {long f(int n); int n; cout<<"input n:" <<endl; cin>>n; cout<<"n!="<<f(n) <<endl; } 此程序的運(yùn)行結(jié)果為: please input n: 5 n!=120 5.5變量的作用域與生存期
1.程序的內(nèi)存區(qū)域。 一個(gè)程序?qū)⒉僮飨到y(tǒng)分配給其運(yùn)行的內(nèi)存塊分為4個(gè)區(qū)域。 (1)代碼區(qū),存放程序的代碼,即程序中各個(gè)函數(shù)中的代碼塊。 (2)全局?jǐn)?shù)據(jù)區(qū),存放程序全局?jǐn)?shù)據(jù)和靜態(tài)數(shù)據(jù)。 (3)堆區(qū),存放程序的動(dòng)態(tài)數(shù)據(jù)。 (4)棧區(qū),存放程序的局部數(shù)據(jù),即各個(gè)函數(shù)中的數(shù)據(jù)。 2.局部變量。 在一個(gè)函數(shù)內(nèi)部說明的變量是內(nèi)部變量,它只在該函數(shù)范圍內(nèi)有效。也就是說,只有在包含變量說明的函數(shù)內(nèi)部,才能使用被說明的變量,在此函數(shù)之外就不能使用這些變量了。所以內(nèi)部變量也稱“局部變量”。
P83
ch5_1.cpp 關(guān)于局部變量的作用域還要說明以下幾點(diǎn): 1.主函數(shù)main()中定義的內(nèi)部變量,也只能在主函數(shù)中使用,其它函數(shù)不能使用。同時(shí),主函數(shù)中也不能使用其它函數(shù)中定義的內(nèi)部變量。因?yàn)橹骱瘮?shù)也是一個(gè)函數(shù),與其它函數(shù)是平行關(guān)系。這一點(diǎn)是與其它語言不同的,應(yīng)予以注意。 2.形參變量也是內(nèi)部變量,屬于被調(diào)用函數(shù);實(shí)參變量,則是調(diào)用函數(shù)的內(nèi)部變量。 3.允許在不同的函數(shù)中使用相同的變量名,它們代表不同的對(duì)象,分配不同的單元,互不干擾,也不會(huì)發(fā)生混淆。 4.在復(fù)合語句中也可定義變量,其作用域只在復(fù)合語句范圍內(nèi)。 3.全局變量 (1)在函數(shù)外部定義的變量稱為外部變量。以此類推,在函數(shù)外部定義的數(shù)組就稱為外部數(shù)組。 (2)外部變量不屬于任何一個(gè)函數(shù),其作用域是:從外部變量的定義位置開始,到本文件結(jié)束為止。 (3)外部變量可被作用域內(nèi)的所有函數(shù)直接引用,所以外部變量又稱全局變量。 例:輸入長(zhǎng)方體的長(zhǎng)(l)、寬(w)、高(h),求長(zhǎng)方體體積及正、側(cè)、頂三個(gè)面的面積。 int s1,s2,s3; int vs(int a,int b,int c) { int v;
v=a*b*c; s1=a*b; s2=b*c; s3=a*c;
return v; } main()
{int v,l,w,h;
clrscr();
printf("\ninput length,width and height: ");
scanf("%d%d%d",&l,&w,&h);
v=vs(l,w,h);
printf("v=%d
s1=%d s2=%d s3=%d\n",v,s1,s2,s3);
getch();
} 對(duì)于全局變量還有以下幾點(diǎn)說明: (1)外部變量可加強(qiáng)函數(shù)模塊之間的數(shù)據(jù)聯(lián)系,但又使這些函數(shù)依賴這些外部變量,因而使得這些函數(shù)的獨(dú)立性降低。 從模塊化程序設(shè)計(jì)的觀點(diǎn)來看這是不利的,因此不是非用不可時(shí),不要使用外部變量。 (2)在同一源文件中,允許外部變量和內(nèi)部變量同名。在內(nèi)部變量的作用域內(nèi),外部變量將被屏蔽而不起作用。 (3)外部變量的作用域是從定義點(diǎn)到本文件結(jié)束。如果定義點(diǎn)之前的函數(shù)需要引用這些外部變量時(shí),需要在函數(shù)內(nèi)對(duì)被引用的外部變量進(jìn)行說明。外部變量說明的一般形式為: extern 數(shù)據(jù)類型 外部變量[,外部變量2……]; 注意:外部變量的定義和外部變量的說明是兩回事。外部變量的定義,必須在所有的函數(shù)之外,且只能定義一次。而外部變量的說明,出現(xiàn)在要使用該外部變量的函數(shù)內(nèi),而且可以出現(xiàn)多次。
1.定義格式: static 數(shù)據(jù)類型 內(nèi)部變量表; 2.存儲(chǔ)特點(diǎn) (1)靜態(tài)局部變量屬于靜態(tài)存儲(chǔ)。在程序執(zhí)行過程中,即使所在函數(shù)調(diào)用結(jié)束也不釋放。換句話說,在程序執(zhí)行期間,靜態(tài)內(nèi)部變量始終存在,但其它函數(shù)是不能引用它們的。 (2)定義但不初始化,則自動(dòng)賦以"0"(整型和實(shí)型)或'\0'(字符型);且每次調(diào)用它們所在的函數(shù)時(shí),不再重新賦初值,只是保留上次調(diào)用結(jié)束時(shí)的值! (3)何時(shí)使用靜態(tài)局部變量 需要保留函數(shù)上一次調(diào)用結(jié)束時(shí)的值。 變量只被引用而不改變其值。
1.構(gòu)成一個(gè)程序的多個(gè)源文件之間,通過聲明數(shù)據(jù)或函數(shù)為外部的(extern)來進(jìn)行溝通。
2.所有函數(shù)聲明一般都放在源文件的開始位置。
3.帶extern的是變量聲明,不是變量定義。
1.靜態(tài)全局變量 (1)在全局變量前加一個(gè)static,使該變量只在這個(gè)源文件中可用,稱之為全局靜態(tài)變量。全局靜態(tài)變量就是靜態(tài)全局變量。
(2)靜態(tài)全局變量對(duì)組成該程序的其他源文件是無效的。 2.靜態(tài)函數(shù) 函數(shù)的聲明和定義默認(rèn)情況下在整個(gè)程序中是extern的。有時(shí)候,你可能需要使某個(gè)函數(shù)只在一個(gè)源文件中有效,不能被其他源文件所用,這時(shí)在函數(shù)前面加上static。
1.靜態(tài)生命期 這種生命期與程序的運(yùn)行期相同,只要程序一開始運(yùn) 行,這種生命期的變量就存在,當(dāng)程序結(jié)束時(shí),其生 命期就結(jié)束。 2.局部生命期 在函數(shù)內(nèi)部聲明的變量或者是塊中聲明的變量具有局 部生命期。 3.動(dòng)態(tài)生命期 這種生命期由程序中特定的函數(shù)調(diào)用(malloc()和 free())或操作符(new和delete)來創(chuàng)建和釋放。 隨機(jī)產(chǎn)生1~9之間的整數(shù)
#include<iostream.h> #include<stdlib.h> #include<iomanip.h> #include<time.h> void main() { srand(time(0)); for(int
i=1;i<=10;i++) { cout<<setw(10)<<1+rand()%9; if(i%5==0) cout<<endl; } } 5.6 函數(shù)的作用域
1.局部作用域 當(dāng)標(biāo)識(shí)符的聲明出現(xiàn)在由一對(duì)花括號(hào)所括起來的一段程序(塊)內(nèi)時(shí),該標(biāo)識(shí)符的作用域從聲明點(diǎn)開始,到塊結(jié)束處為止,該作用域的范圍具有局部性。 2.函數(shù)作用域 標(biāo)號(hào)是唯一具有函數(shù)作用域的標(biāo)識(shí)符。 3.函數(shù)原型作用域 函數(shù)原型聲明中所作的參數(shù)聲明在該作用域中。這個(gè)作用域開始于函數(shù)原型聲明的左括號(hào),結(jié)束于函數(shù)聲明的右括號(hào)。 4.文件作用域 文件作用域是在所有函數(shù)定義之外說明的,其作用域從說明點(diǎn)開始,一直延伸到源文件結(jié)束。
可見性從另一角度表現(xiàn)標(biāo)識(shí)符的有效性,標(biāo)識(shí)符在某個(gè)位置可見,表示該標(biāo)識(shí)符可以被引用??梢娦耘c作用域是一致的。作用域指的是標(biāo)識(shí)符有效的范圍,而可見性是分析在某一位置標(biāo)識(shí)符的有效性。 5.7 多文件結(jié)構(gòu) 每個(gè)標(biāo)準(zhǔn)庫都有相應(yīng)的“頭文件”,頭文件中包含對(duì)應(yīng)庫中所有函數(shù)的函數(shù)原型和這些函數(shù)所需的各種數(shù)據(jù)類型和常量的定義。 程序員也可以自己定義頭文件,自定義的頭文件應(yīng)以.h結(jié)尾。自定義的頭文件可以用#include來包含。
大程序傾向于分成多個(gè)源文件,其理由為: (1)避免重復(fù)編譯函數(shù)。 (2)使程序更加容量管理。 (3)把相關(guān)函數(shù)放到一特定源文件中。
1.#include包含指令 (1)文件包含是指,一個(gè)源文件可以將另一個(gè)源文件的全部?jī)?nèi)容包含進(jìn)來。 (2)文件包含的格式 #include “包含文件名” 或 #include <包含文件名> 兩種格式的區(qū)別僅在于: ①使用雙引號(hào):系統(tǒng)首先到當(dāng)前目錄下查找被包含文件,如果沒找到,再到系統(tǒng)指定的“包含文件目錄”(由用戶在配置環(huán)境時(shí)設(shè)置)去查找。 ②使用尖括號(hào):直接到系統(tǒng)指定的“包含文件目錄”去查找。一般地說,使用雙引號(hào)比較保險(xiǎn)。
(3)文件包含的優(yōu)點(diǎn) 一個(gè)大
程序,通常分為多個(gè)模塊,并由多個(gè)程序員分別編程。有了文件包含處理功能,就可以將多個(gè)模塊共用的數(shù)據(jù)(如符號(hào)常量和數(shù)據(jù)結(jié)構(gòu))或函數(shù),集中到一個(gè)單獨(dú)的
文件中。這樣,凡是要使用其中數(shù)據(jù)或調(diào)用其中函數(shù)的程序員,只要使用文件包含處理功能,將所需文件包含進(jìn)來即可,不必再重復(fù)定義它們,從而減少重復(fù)勞動(dòng)。
(4)說明 ①編譯預(yù)處理時(shí),預(yù)處理程序?qū)⒉檎抑付ǖ谋话募⑵鋸?fù)制到#include命令出現(xiàn)的位置上。 ②常用在文件頭部的被包含文件,稱為“標(biāo)題文件”或“頭部文件”,常以“h”(head)作為后綴,簡(jiǎn)稱頭文件。在頭文件中,除可包含宏定義外,還可包含外部變量定義、結(jié)構(gòu)類型定義等。 ③一條包含命令,只能指定一個(gè)被包含文件。如果要包含n個(gè)文件,則要用n條包含命令。 ④文件包含可以嵌套,即被包含文件中又包含另一個(gè)文件。
2.#define宏定義指令 (1) #define最常用的方法是建立常量,但已被C++的const定義語句所代替。 (2) #define還可以定義帶參的宏,但也已被C++的inline內(nèi)嵌函數(shù)所代替。 (3) #define的一個(gè)有效的使用是在條件編譯指令中。
3.條件編譯指令 條件編譯可有效地提高程序的可移植性,并廣泛地應(yīng)用在商業(yè)軟件中,為一個(gè)程序提供各種不同的版本。 (1)一般格式
#ifdef 標(biāo)識(shí)符
程序段1; [#else
程序段2;] #endif
(2)功能:當(dāng)“標(biāo)識(shí)符”已經(jīng)被#define命令定義過,則編譯程序段1,否則編譯程序段2。 ①在不同的系統(tǒng)中,一個(gè)int 型數(shù)據(jù)占用的內(nèi)存字節(jié)數(shù)可能是不同的。 ②利用條件編譯,還可使同一源程序即適合于調(diào)試(進(jìn)行程序跟蹤、打印較多的狀態(tài)或錯(cuò)誤信息),又適合高效執(zhí)行要求。
(3)關(guān)于#ifndef ~ #endif命令 格式與#ifdef ~ #endif命令一樣,功能正好與之相反。
5.8 內(nèi)聯(lián)函數(shù) 內(nèi)聯(lián)擴(kuò)展(inline expansion)簡(jiǎn)稱為內(nèi)聯(lián)(inline),內(nèi)聯(lián)函數(shù)也稱為內(nèi)嵌函數(shù)。當(dāng)在一個(gè)函數(shù)的定義或聲明前加上關(guān)鍵字inline則就把該函數(shù)定義為內(nèi)聯(lián)函數(shù),它主要是解決程序的運(yùn)行效率。 計(jì)
算機(jī)在執(zhí)行一般函數(shù)的調(diào)用時(shí),無論該函數(shù)多么簡(jiǎn)單或復(fù)雜,都要經(jīng)過參數(shù)傳遞、執(zhí)行函數(shù)體和返回等操作,這些操作都需要一定的時(shí)間開銷。若把一個(gè)函數(shù)定義為
內(nèi)聯(lián)函數(shù)后,在程序編譯階段,編譯器就會(huì)把每次調(diào)用該函數(shù)的地方都直接替換為該函數(shù)體中的代碼,由此省去函數(shù)的調(diào)用及相應(yīng)的保存現(xiàn)場(chǎng)、參數(shù)傳遞和返回操
作,從而加快整個(gè)程序的執(zhí)行速度。
例5-6: #include "iostream.h" inline int abs(int x) { return x<0?-x:x; } void main() { int a,b=3,c,d=-4; a=abs(b); c=abs(d); cout<<"a="<<a<<",c="<<c<<endl; } 此程序的運(yùn)行結(jié)果為:a=3,c=4 5.9 函數(shù)重載 函數(shù)重載又稱為函數(shù)的多態(tài)性,是指同一個(gè)函數(shù)名對(duì)應(yīng)著多個(gè)不同的函數(shù)。所謂“不同”是指這些函數(shù)的形參表必須互不相同,或者是形參的個(gè)數(shù)不同,或者是形參的類型不同,或者是兩者都不相同,否則將無法實(shí)現(xiàn)函數(shù)重載。例如,下面是合法的重載函數(shù): int
func1(int,int); int
func1(int); double
func1(int,long); double
func1(long); 重載函數(shù)的類型,即函數(shù)的返回類型可以相同,也可以不同。但如果僅僅是返回類型不同而函數(shù)名相同、形參表也相同,則是不合法的,編譯器會(huì)報(bào)“語法錯(cuò)誤”。如: int
func1(int a, int b); double
func1(int a, int b); 除形參名外都相同的情況 ,編譯器不認(rèn)為是重載函數(shù) ,只認(rèn)為是對(duì)同一個(gè)函數(shù)原型的多次聲明
。 在調(diào)用一個(gè)重載函數(shù)func1()時(shí),編譯器必須判斷函數(shù)名func1到底是指哪個(gè)函數(shù)。它是通過編譯器,根據(jù)實(shí)參的個(gè)數(shù)和類型對(duì)所有func1()函數(shù)的形參一一進(jìn)行比較,從而調(diào)用一個(gè)最匹配的函數(shù)。
5.10 帶默認(rèn)形參值的函數(shù) 在C++語言中調(diào)用函數(shù)時(shí),通常要為函數(shù)的每個(gè)形參給定對(duì)應(yīng)的實(shí)參。若沒有給出實(shí)參,則按指定的默認(rèn)值進(jìn)行工作。
當(dāng)一個(gè)函數(shù)既有定義又有聲明時(shí),形參的默認(rèn)值必須在聲明中指定,而不能放在定義中指定。只有當(dāng)函數(shù)沒有聲明時(shí),才可以在函數(shù)定義中指定形參的默認(rèn)值。
默認(rèn)值的定義必須遵守從右到左的順序,如果某個(gè)形參沒有默認(rèn)值,則它左邊的參數(shù)就不能有默認(rèn)值。
如: void func1(int a, double b=4.5, int c=3);
//合法
void func1(int a=1, double b, int
c=3); //不合法 在進(jìn)行函數(shù)調(diào)用時(shí),實(shí)參與形參按從左到右的順序進(jìn)行匹配,當(dāng)實(shí)參的數(shù)目少于形參時(shí),如果對(duì)應(yīng)位置形參又沒有設(shè)定默認(rèn)值,就會(huì)產(chǎn)生編譯錯(cuò)誤;如果設(shè)定了默認(rèn)值,編譯器將為那些沒有對(duì)應(yīng)實(shí)參的形參取默認(rèn)值。 注意:形參的默認(rèn)值可以是全局常量、全局變量、表達(dá)式、函數(shù)調(diào)用,但不能為局部變量。 例如,下例不合法: void func1() {
int k; void g(int x=k); //k為局部變量 } |
|