實驗三-第4章函數與預處理_第1頁
實驗三-第4章函數與預處理_第2頁
實驗三-第4章函數與預處理_第3頁
實驗三-第4章函數與預處理_第4頁
實驗三-第4章函數與預處理_第5頁
免費預覽已結束,剩余89頁可下載查看

下載本文檔

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

文檔簡介

第4章函數與預處理概述函數的定義函數參數和函數的值函數的調用內置函數函數重載函數模板有默認參數的函數函數調用機制函數的遞歸調用局部變量和全局變量變量的關于變量的類別和定義函數和外部函數預處理命令4.1

概述程序通常是非常復雜而冗長的,在編寫一個很長的程序時,往往將之分割成一些相對獨立而且便于管理和閱讀的小塊程序。把實現某能的相關語句組織在一起,并給之注明相應的名稱,這種形式的組合就稱為函數。任何一個C++程序都是由若干函數組成的。函數按其是否為系統預定義的可分為二類:①庫函數(或標準函數)。②用戶自定義函數。函數按是否帶有參數可分為有參函數和無參函數。在一個程序文件中可以包含若干個函數。無論把一個程序劃分為多少個程序模塊,只能有一個main函數。程序總是從main函數開始執行的。在程序運行過程中,由主函數調用其他函數,其他函數也可以互相調用。在實際應用的程序中,主函數寫得很簡單,它的作用就是調用各個函數,程序各部分的功能全部都是由各函數實現的。主函數相當于總調度,調動各函數依次實現各項功能。例在主函數中調用其他函數。//輸出30個“*”#include

<iostream>using

namespacestd;void

printstar()

//定義printstar函數{cout<<"******************************"<<endl;}cout<<" e

toC++!"<<endl; //輸出一行文字void

print_message()//定義print_message函數{}//調用printstar

函數//調用print_message函數//調用printstar

函數intmain(){printstar();print_message();printstar();return

0;}*函數機制一是指程序運行過程中對函數調用的數據管理和處理過程。二是指編程中函數的使用規范。它包括:;函數參數的屬性和傳遞規則;函數返回類型的匹配與函數名字的識別原則;函數體效率的選擇;函數體中數據的

權限等。4.2

函數的定義一個函數包括函數頭和函數體兩部分。①函數頭定義函數功能和接口的全部要素,包括函數名、函數參數和函數返回值類型。②函數體則定義函數的算法實現。函數必須先定義后使用。格式:<數據類型>函數名(參數類型1

形式參數1<,參數類型2

形式參數2…>){函數體}#include<iostream>using

namespace

std;double

max(double

a,

double

b){return

(a>=b?

a:

b);}int

main(

){double

x,

y,

z;cin>>x>>y;z=max(x,

y);cout<<z<<endl;return

0;}C++中不允許函數的嵌套定義,即不允許在一個函數中定義另一個函數。4.3

函數參數和函數的值形式參數和實際參數在調用函數時,大多數情況下,函數是帶參數的。主調函數和被調用函數之間有數據傳遞關系。在定義函數時函數名后面括號中的變量名稱為形式參數(formal

parameter,簡稱形參),在主調函數中調用一個函數時,函數名后面括號中的參數(可以是一個表達式)稱為實際參數(actualparameter,簡稱實參)。例調用函數時的數據傳遞。//定義有參函數max#include

<iostream>using

namespace

std;int

max(int

x,int

y){int

z;z=x>y?x:y;return

z;}c=max(a,b);

//調用max函數,給定實參為a,b。函數值賦給ccout<<"max="<<c<<endl;return

0;int

main(

){int

a,b,c;cout<<"please

enter

two

integer

numbers:";cin>>a>>b;}運行情況如下:please

enter

two

integer

numbers:2

3↙max=3有關形參與實參的說明:(1)在定義函數時指定的形參,在未出現函數調用時,它們并不占內存中的

單元,因此稱它們是形式參數或虛擬參數,表示它們并不是實際存在的數據,只有在發生函數調用時,函數max中的形參才被分配內存單元,以便接收從實參傳來的數據。在調用結束后,形參所占的內存單元也被

。(2)

實參可以是常量、變量或表達式,如max(3,a+b);但要求a和b有確定的值。以便在調用函數時將實參的值賦給形參。(3)

在定義函數時,必須在函數首部指定形參的類型。(4)實參與形參的類型應相同或賦值兼容。(5)函數參數的傳遞方式可分為按值傳遞和按傳遞兩種!!!按值傳遞:將實參的值

給形參,在函數中參加運算的是形參,而實參不會發生任何改變。#include<iostream>using

namespace

std;int

fun(int

a){

++a;return

a;}int

main(

){int

x=1,y;y=fun(x);cout<<y<<endl;return

0;}11xa22y4.3.2

函數的返回值(1)函數的返回值是通過函數中的return語句獲得的。return語句將被調用函數中的一個確定值帶回主調函數中去。格式:return

表達式;或return(表達式);(2)函數值的類型。既然函數有返回值,這個值當然應屬于某一個確定的類型,應當在定義函數時指定函數值的類型。(3)如果函數值的類型和return語句中表達式的值不一致,則以函數類型為準,即函數類型決定返回值的類型。對數值型數據,可以自動進行類型轉換。注意:對于有返回值的函數,在函數的出口處必須

用“return”語句將要返回的值返回給調用者。函數一旦執行到“return”語句便會終止執行,返回調用單元。#include<iostream>using

namespace

std;char

toColor(int

n){switch(n){case

0:

return('R');case

1:

return('G');case

2:

return('B');}}int

main(){int

a=1,b=0;cout<<"a:

"<<toColor(a)<<endl;cout<<"b:

"<<toColor(b)<<endl;return

0;}輸出a:

Gb:R4.4

函數的調用函數調用的一般形式格式:函數名([實參表列])如果是調用無參函數,則“實參表列”可以沒有,但括號不能省略。如果實參表列包含多個實參,則各參數間用逗號隔開。實參與形參的個數應相等,類型應匹配(相同或賦值兼容)。實參與形參按順序對應,一對一地傳遞數據。但應說明,如果實參表列包括多個實參,對實參求值的順序并不是確定的。4.4.2

函數調用的方式按函數在語句中的作用來分,可以有以下3種函數調用方式:1.函數語句把函數調用單獨作為一個語句,并不要求函數帶回一個值,只是要求函數完成一定的操作。如例4.1中的printstar();2.函數表達式函數出現在一個表達式中,這時要求函數帶回一個確定的值以參加表達式的運算。如c=2*max(a,b);3.函數參數函數調用作為一個函數的實參。如m=max(a,max(b,c));

//max(b,c)是函數調用,其值作為外層max函數調用的一個實參4.4.3

對被調用函數的

和函數原型C++中,對函數之間的排列順序沒有固定的要求,但一定要滿足先定義后使用的原則。對于標準函數,在程序開頭用“#include”指令將所需頭文件包含進來即可;而對于自定義函數,只要在調用之前做函數

,則無論函數定義放在什么位置,程序都能正確編譯、運行。函數

也稱為函數原型。格式:<數據類型>函數名(參數類型1

形式參數1<,參數類型2

形式參數2…>);…<數據類型>函數名(參數類型1

形式參數1<,參數類型2

形式參數2…>){函數體}例:#include<iostream>using

namespace

std;double

max(double

a,double

b);int

main(){double

x,y,z;cin>>x>>y;z=max(x,y);cout<<z<<endl;return

0;}double

max(double

a,

double

b){return

(a>=b?a:b);}注意:對函數的定義和不是同一件事情。定義是指對函數功能的確立,包括指定函數名、函數類型、形參及其類型、函數體等,它是一個完整的、獨立的函數單位。

的作用則是把函數的名字、函數類型以及形參的個數、類型和順序(注意,不包括函數體)通知編譯系統,以便在對包含函數調用的語句進行編譯時,據此對其進行對照檢查(例如函數名是否正確,實參與形參的類型和個數是否一致)。4.5

內置函數函數調用需要建立棧內存環境,進行參數傳遞,并

產生程序執行轉移,這些工作都需要一些時間開銷。有些函數使用頻率高,但代碼卻很短,程序頻繁調用該函數造成執行效率降低。為了提高效率,解決方法之一是不使用函數,直接將函數代碼嵌入到程序中。但這個方法的缺點是相同代碼段需要重復書寫,另外,程序的可讀性往往也沒有使用函數時好。為了協調效率和可讀性之間的 ,C++提供了另法,即定義內聯函數方法是在定義函數時使用修飾詞inline。#include<iostream>using

namespace

std;inline

boolisNumber(char);int

main(){char

c;while(cin>>c&&c!='q'){if(isNumber(c))cout<<"digit"<<endl;elsecout<<"not

digit"<<endl;}}bool

isNumber(char

ch){return

(ch>='0'&&ch<='9')?1:0;}內聯函數的調用機制與一般函數不同,編譯器在編譯過程中遇到inline時,將為該函數建立一段代碼,然后在每次調用時直接將該代碼嵌入到調用函數中,從而函數調用方式變為順序執行方式,這一過程稱為內聯函數的擴展。注意:①內聯函數必須在被調用之前

或定義。②內聯函數中,不能含有復雜的結構控制語句,如switch、while及遞歸函數等。③內聯函數只適合于1~5行的小函數,對于含有許多語句的大函數,函數調用和返回的開銷相對來說微不足道,所以也沒有必要用內聯函數實現。4.6

函數重載在C++中,如果需要定義幾個功能相似而參數類型不同的函數,那么這幾個函數可以使用相同的函數名,這就是函數重載。例:返回一個數的絕對值。#include<iostream>using

namespace

std;int

ABS(int);double

ABS(double);float

ABS(float);int

main(){int

x1=-12;double

x2=-12.0;float

x3=-12.0;cout<<ABS(x1)<<endl;cout<<ABS(x2)<<endl;cout<<ABS(x3)<<endl;}int

ABS(int

a){return

(a>0?a:-a);}double

ABS(double

a){return

(a>0?a:-a);}float

ABS(float

a){return

(a>0?a:-a);}只要參數個數不同,參數類型不同,參數順序不同,函數就可以重載。然而,只是返回類型不同則不允許重載。void

func(int

a);

√void

func(char

a);

√void

func(char

a,

int

b);

√void

func(int

a,

char

b);

√char

func(int

a);

×C++按下列三個步驟的先后順序找到匹配的函數并調用之。①尋找一個嚴格匹配,如果找到了,就調用那個函數。②通過相容類型的隱式轉換尋求一個匹配。③通過用戶定義的轉換尋求一個匹配,若能查出唯一的一組轉換,就用那個函數。#include<iostream>using

namespace

std;void

print(int);void

print(double);int

main(){print(1);print(1.0);print('a');print(3.14f);}void

print(int

a){cout<<"int:

"<<a<<endl;}void

print(double

a){cout<<"double:

"<<a<<endl;}輸出:int:

1double:

1int:

97double:3.14函數重載例:編程求圓、矩形、梯形的面積。#include<iostream>using

namespace

std;double

area(doubler);double

area(double

h,double

w);double

area(double

a,double

b,double

h);int

main(){double

r=23.3;double

h1=12,w=5;double

a=7,b=8,

h2=3;cout<<area(r)<<endl;cout<<area(h1,w)<<endl;cout<<area(a,b,h2);}double

area(doubler){return

3.14*r*r;}double

area(double

h,double

w){return

h*w;}double

area(double

a,double

b,double

h){return

(a+b)*h/2;}4.7

函數模板C++提供了函數模板(function

template)。所謂函數模板,實際上是建立一個通用函數,其函數類型和形參類型不具體指定,用一個

虛擬的類型來代表。這個通用函數就稱為函

數模板。凡是函數體相同的函數都可以用這

個模板來代替,不必定義多個函數,只需在

模板中定義一次即可。在調用函數時系統會

根據實參的類型來取代模板中的虛擬類型,

從而實現了不同函數的功能。//模板

,其中T為類型參數//定義一個通用函數,用T作虛擬的類型名#include

<iostream>using

namespacestd;template<typenameT>T

max(T

a,T

b,T

c){if(b>a)a=b;if(c>a)a=c;return

a;}i=max(i1,i2,i3);d=max(d1,d2,d3);g=max(g1,g2,g3);//調用模板函數,此時T被int取代//調用模板函數,此時T被double取代//調用模板函數,此時T被long取代cout<<"i_max="<<i<<endl;cout<<"f_max="<<d<<endl;cout<<"g_max="<<g<<endl;return

0;int

main(

){int

i1=185,i2=-76,i3=567,i;double

d1=56.87,d2=90.23,d3=-3214.78,d;long

g1=67854,g2=-912456,g3=673456,g;}定義函數模板的一般形式為template

<typename

T>或template

<class

T>類型參數可以不只一個,可以根據需要確定個數。如:template<typename

T1,typenameT2>可以看到,用函數模板比函數重載更方便,程序更簡潔。但應注意它只適用于函數的參數個數相同而類型不同,且函數體相同的情況,如果參數的個數不同,則不能用函數模板。4.8

有默認參數的函數C++可以給函數

中的參數使用默認值,這樣在函數調用時,對應的實參就可以省略。#include<iostream>using

namespace

std;int

func(int

a=2);int

main(){cout<<func(5)<<endl;cout<<func()<<endl;}int

func(int

a){return

a;}默認參數規則:①一般來說,默認參數總是在函數

時描述。②函數參數默認值只能從后往前設置,而實參只能從前往后給出。例:void

func(inta=1,int

b,

intc=3);

×void

func(int

a,int

b=2,

intc=3);

√func(10,15,20);func(

);func(12,13);func(2,

,

20);√×√×一個函數不能既作為重載函數,又作為有默認參數的函數。(P105)?#include

<iostream>using

namespace

std;void

p(int

a,int

b=4);void

p(int

a,char

b);//voidp(inta,char

b='f');?int

main(

){p(2);p(3,'s');return0;}void

p(int

a,int

b){cout<<a<<'\t'<<b<<endl;}void

p(int

a,char

b){cout<<a<<'\t'<<b<<endl;}函數調用機制程序的內存區域一個程序要運行,就要先將可執行程序文件裝載到內存中,此過程由操作系統管理,操作系統將為程序分配一個空間。程序將操作系統分配給其的運行的內存塊分為四個區域:①代碼區,存放程序的代碼,即程序中的各個函數代碼塊。②全局數據區(靜態區),存放程

序的全局數據和靜態數據。靜態區

的內容在整個程序的生命周期內都

存在,由編譯器在編譯的時候分配。③堆區(動態內存分配區),存放程序的動態數據。由malloc系列函數或new操作符分配的內存,其生命周期由free或delete決定。在沒有

之前一直存在,直到程序結束。程序內存空間代碼區全局數據區堆區棧區④棧區,存放程序的局部數據,即各個函數中的數據。棧中的內容只在函數的范圍內存在,當函數運行結束,這些內容也會自動被銷毀。4.9.2

棧機制與函數調用棧是一種數據結構,棧中存取數據的原則是后進先出。C++的函數調用過程,需要初始化和善后處理環節。函數調用的整個過程就是棧空間的操作過程。函數調用時,C++做以下工作:

①建立被調用函數的棧空間,棧空間的大小由函數定義體中的數據量多少決定。②保護調用函數的運行狀態和返回地址。③傳遞參數。④將控制權轉交給被調函數。⑤函數運行完成后,

返回值到函數數據塊的底部。⑥恢復調用函數的運行狀態。⑦返回到調用函數。int

funcA(int

x,

int

y);int

main(

){int

a=6,b=12;a=funcA(a,

b);}int

funcA(int

x,

int

y){int

n=5;n=x+y;return

n;}main(

)b12a6操作系統運行狀態及返回地址返回值0運行程序,執行main()funcA(

)n5y12x6main()運行狀態及返回地址返回值main(

)b12a6操作系統運行狀態及返回地址返回值0調用函數funcA(a,

b)main函數的臨時空間funcA(

)n5 →

18y12x6main()運行狀態及返回地址返回值main(

)b12a6操作系統運行狀態及返回地址返回值0調用函數funcA(a,

b),執行n=x+y;funcA(

)n18y12x6main()運行狀態及返回地址返回值18main(

)b12a6操作系統運行狀態及返回地址返回值0調用函數funcA(a,

b),執行return

n;18126main()運行狀態及返回地址18main(

)b12a6 →

18操作系統運行狀態及返回地址返回值0返回到main()函數中a=funcA(a,b);4.10

函數的遞歸調用在函數體中出現調用自身的函數稱為遞歸函數。例:階乘n!的數學函數描述為其對應的C++函數描述為:unsigned

f(unsigned

n){if(n==1)return

1;return

n*f(n-1);}注意:n的取值范圍1≤n≤12

1f

n

nf n

1n

1n

1例:Fibonacci數列的數學描述為unsigned

int

f(unsigned

int

n){if(n==1||n==2)return

1;return

f(n-1)+f(n-2);}n的取值范圍1≤n≤461f

n

1n

1n

2

f

n

1

f

n

2

n

3其等價的C++函數為:遞歸函數在運行中,其調用與被調函數的指令代碼是同一個函數副本,只不過各個不同運行中的調用點,作為狀態的一部分,在棧中被分別保護起來。因此,是C++的函數機制決定了遞歸操作的可能性與形式。例:n!的函數,當調用f(3)時,其運行棧描述f(1)n=1f(2)函數的狀態及返回地址f(2)返回值1n=2f(3)函數的狀態及返回地址f(3)返回值2*f(1)n=3調用函數的狀態及返回地址返回值3*f(2)遞歸條件:①遞歸不能

地調用下去,因為棧空間是有限的,所以遞歸函數是有條件地調用自身。例如階乘函數中的“if(n==1)return1;”當n為1時,函數就不再遞歸了。②是遞歸函數就有遞歸調用語句,且遞歸調用應有參數,參數值應該是逐漸近停止條件。例如f(n-1)相對f(n)來說,是逐漸近了停止條件。③遞歸條件應先測試,后遞歸調用。無條件遞歸的邏輯錯誤,編譯器是檢查不出來的。4.11

局部變量和全局變量4.11.1

局部變量在一個函數

定義的變量是變量,它只在本函數范圍內有效。同樣,在復合語句中定義的變量只在本復合語句范圍內有效。這稱為局部變量(local

variable)。在函數開始運行時,局部數據在棧區分配空間,函數退出時,局部數據隨之!!!如果局部變量不被顯式初始化,其內容是不可預料的。#include

<iostream>using

namespace

std;double

f1(int

a);

//a只在這一行有效char

f2(int);

//函數

里的形參可省略int

main(){int

m=34,n=67;double

p;{char

p;p=f2(n);cout<<p<<endl;}p=f1(m);cout<<p<<endl;}double

f1(int

a){double

b=a;return

b;}char

f2(int

a){char

c=a;return

c;}p有效p有效m,

n有效b有效a有效c有效a有效4.11.2

全局變量在函數內定義的變量是局部變量,而在函數之外定義的變量是外部變量,稱為全局變量(globalvariable,也稱全程變量)。全局變量的有效范圍為從定義變量的位置開始到本源文件結束。全局數據使得若干個模塊在程序范圍內能共享(讀與寫)數據,也是若干程序文件溝通數據的一種形式。全局數據存放在內存的全局數據區,全局數據區的整個區域在程序啟動時初始化為0。注意:模塊的獨立性由數據的封閉性來支持。全局

數據破壞了數據的封閉性,因而對小程序而

言簡單可行,對規范化程序則不登大雅之堂。函數之間用參數傳遞數據,盡量避免使用全局數據。4.12

變量的

類別在C++中變量除了有數據類型的屬性之外,還有

類別(storage

class)

的屬性。類別指的是數據在內存中方法分為靜態

和動態的方法。兩大類。具體包含4種:自動的(auto)、靜態的(static)、寄存器的(register)和外部的(extern)。4.12.1

自動變量程序內存空間代碼區全局數據區堆區棧區函數中的局部變量,如果不用關鍵字static加以

,編譯系統對它們是動態地分配空間的。自動變量用關鍵字auto作存儲類別的

(可以省略)。4.12.2

用static靜態局部變量程序內存空間代碼區全局數據區堆區棧區有時希望函數中的局部變量的值在函數調用結束后不消失而保留原值,即其占用的單元不

,在下一次該函數調用時,該變量保留上一次函數調用結束時的值。這時就應該指定該局部變量為靜態局部變量(static

localvariable)。對靜態局部變量的說明:區內分配(1)靜態局部變量在靜態程序整個運行期間都不,

在動態

區區空間),函數調用結束后即局部變量)屬于動態空間(而不是靜態。(2)為靜態局部變量賦初值是在編譯時進行的,即只賦初值一次,在程序運行時它已有初值。以后每次調用函數時不再重新賦初值而只是保留上次函數調用結束時的值。而為自動變量賦初值,不是在編譯時進行的,而是在函數調用時進行,每調用一次函數重新給一次初值,相當于執行一次賦值語句。(3)如果在定義局部變量時不賦初值的話,對靜態局部變量來說,編譯時自動賦初值0(對數值型變量)或空字符(對字符型變量)。而對自動變量來說,如果不賦初值,則它的值是一個不確定的值。這是由于每次函數調用結單元已

,下次調用時又重新另單元,而所分配的單元中的值是不束后分配確定的。(4)雖然靜態局部變量在函數調用結束后仍然存在,但其他函數是不能

它的,也就是說,在其他函數中它是“不可見”的。例:void

func(){static

int

a=2;a++;int

b=5;b++;cout<<"a="<<a<<",

b="<<b<<endl;}int

main(){func();func();}//

a=3,

b=6//

a=4,

b=6例輸出1~5的階乘值(即1!,2!,3!,4!,5!)。//函數for(i=1;i<=5;i++)cout<<i<<"!="<<fac(i)<<endl;return

0;#include

<iostream>using

namespacestd;intfac(int);int

main(

){inti;}//f為靜態局部變量,函數結束時f的值不//在f原值基礎上乘以nf=f*n;return

f;intfac(intn){static

int

f=1;}*4.12.3

用register

寄存器變量一般情況下,變量的值是存放在內存中的。當程序中用到哪一個變量的值時,由控制器發出指令將內存中該變量的值送到CPU中的運算器。經過運算器進行運算,如果需要存數,再從運算器將數據送到內存存放。為提高執行效率,C++允許將局部變量的值放在CPU中的寄存器中,需要用時直接從寄存器取出參加運算,不必再到內存中去存取。這種變量叫做寄存器變量,用關鍵字register作

。在程序中定義寄存器變量對編譯系統只是建議性(而不是強制性)的。的優化編譯系統能夠識別使用頻繁的變量,自動地將這些變量放在寄存器中。4.12.4

用extern

外部變量全局變量(外部變量)是在函數的外部定義的,它的作用域為從變量的定義處開始,到本程序文件的末尾。在此作用域內,全局變量可以為本文件中各個函數所

。編譯時將全區。全局變量,以擴展局變量分配在靜態有時需要用extern來全局變量的作用域。1.

在一個文件內

全局變量如果外部變量不在文件的開頭定義,其有效的作用范圍只限于定義處到文件終了。如果在定義點之前的函數想該全局變量,則應該在

外部變量之前用關鍵字extern對該變量作,表示該變量是一個將在下面定義的全局變量。有了此,就可以從聲明處起,合法地稱為提前該全局變量,這種。,以擴例用extern對外部變量作提前展程序文件中的作用域。//函數//對全局變量a,b作提前cout<<max(a,b)<<endl;#include

<iostream>using

namespace

std;int

max(int,int);int

main(

){extern

int

a,b;}int

a=15,b=-7;//定義全局變量a,bint

max(int

x,int

y){int

z;z=x>y?x:y;return

z;}2.在多文件的程序中外部變量如果一個程序包含兩個文件,在兩個文件中都要用到同一個

外部變量num,不能分別在兩個文件中各自定義一個外部變

量num。正確的做法是:在任一個文件中定義外部變量num,。即而在另一文件中用extern對num作外部變量extern

int

num;編譯系統由此知道num是一個已在別處定義的外部變量,它先在本文件中找有無外部變量num,如果有,則將其作用域擴展到本行開始(如上節所述),如果本文件中無此外部變量,則在程序連接時從其他文件中找有無外部變量num,如果有,則把在另一文件中定義的外部變量num的作用域擴展到本文件,在本文件中可以合法地

該外部變量num。file2.cppinta=3,b=4;┆例:file1.cppextern

int

a,b;int

main(

){cout<<a<<","<<b<<endl;return0;}用extern擴展全局變量的作用域,雖然能為程序設計帶來方便,但應十分慎重,因為在執行一個文件中的函數時,可能會改變了該全局變量的值,從而會影響到另一文件中的函數執行結果。4.12.5

用static

靜態外部變量有時在程序設計中希望某些外部變量只限于被本文件

,而不能被其他文件外部變量時加一個staticfile1.cppstatic

int

a=3;int

main

(

){…}。這時可以在定義。例如:file2.cppextern

int

a;int

fun(intn){a=a*n;…}這種加上static

、只能用于本文件的外部變量(全局變量)稱為靜態外部變量。這就為程序的模塊化、通用性提供了方便。如果已知其他文件不需要

本文件的全局變量,可以對本文件中的全局變量都加上static,成為靜態外部變量,以免被其他文件誤用。需要用靜態,不要誤認為用static方式(存放在靜態的外部變量才采區中),而不加static的是動態

(存放在動態區)。實際上,兩種形式的外部變量都用靜態

方式,只是作用范圍不同而已,都是在編譯時分配內存的。4.13

關于變量的和定義一個函數一般由兩部分組成:

(1)

部分;

(2)執行語句。

部分的作用是對有關的標識符(如變量、函數、結構體、共用體等)的屬性進行說明。對于函數,

和定義的區別是明顯的,在本章4.4.3節中已說明,函數的

是函數的原型,而函數的定義是函數功能的確立。對函數的

是可以放在

部分中的,而函數的定義顯然不在函數的部分范圍內,它是一個文件中的獨立模塊。對變量而言,與定義的關系稍微復雜一些。在部分出現的變量有兩種情況:一種是需要建立空間的(如inta;);另一種是不需要建立空間的(如externinta;)。前者稱為定義性(definingdeclaration),或簡稱為定義(definition)。后者稱為性(referenceing

declaration)。廣義地說,

包括定義,但并非所有的都是定義。對“int

a;”而言,它是定義性,既可說,又可說是定義。而對“extern

int

a;”而言,是它是而不是定義。一般為了敘述方便,把建立空間的稱為定義,而把不需要建立

空間的

稱為是狹義的,即非定義性。顯然這里指的。例如://這是不是定義。a是一個已定義的外部變量int

main(

){extern

int

a;…}int

a;

//是定義,定義a為整型外部變量外部變量定義和外部變量

的含義是不同的。外部變量的定義只能有一次,它的位置在所有函數之外,而同一文件中的外部變量的

可以有多次,它的位置可以在函數之內,也可以在函數之外。系統根據外部變量的定義分配對外部變量的初始化只能在定義時進行,而不能在行。所謂

,其作用是向編譯系統發出一個信息,變量是一個在后面定義的外部變量,僅僅是為了提前單元。中進該該變量而作的

。extern只用作

,而不用于定義。4.14

函數和外部函數函數本質上是全局的,因為一個函數要被另外的函數調用,但是,也可以指定函數只能被本文件調用,而不能被其他文件調用。根據函數能否被其他源文件調用,將函數區分為函數和外部函數。4.14.1

函數如果一個函數只能被本文件中其他函數所調用,它稱為函數。在定義函數時,在函數名和函數類型的前面加static。函數首部的一般格式為static

類型標識符函數名(形參表)如static

int

fun(int

a,int

b)函數又稱靜態(static)函數。使用函數,可以使函數只局限于所在文件。如果在不同的文件中有同名的

函數,互不干擾。通常把只能由同一文件使用的函數和外部變量放在一個文件中,在它們前面都冠以static使之局部化,其他文件不能。4.14.2

外部函數(1)在定義函數時,如果在函數首部的最左端冠以關鍵字extern,則表示此函數是外部函數,可供其他文件調用。如函數首部可以寫為extern

int

fun

(int

a,

int

b)這樣,函數fun就可以為其他文件調用。如果在定義函數時省略extern,則默認為外部函數。本書前面所用的函數都是外部函數。(2)

在需要調用此函數的文件中,用extern

所用的函數是外部函數。例輸入兩個整數,要求輸出其中的大者。用外部函數實現。file1.cpp(文件1)#include

<iostream>using

namespace

std;extern

int

max(int,int);//

在本函數中將要調用在其他文件中定義的max函數int

main(

){int

a,b;cin>>a>>b;cout<<max(a,b)<<endl;return

0;}file2.cpp(文件2)int

max(int

x,inty){int

z;z=x>y?x:y;returnz;}*4.15

預處理命令可以在C++源程序中加入一些“預處理命

令”(preprocessor

directives),以改進程序設計環境,提高編程效率。預處理命令是C++

規定的,但是它不是C++語言本身的組成部分,不能直接對它們進行編譯(因為編譯程序不能識別它們)。預處理命令語句不是C++語句,不以“;”作為語句結束標志!C++提供的預處理功能主要有以下3種:(1)

宏定義(2)

文件包含(3)條件編譯分別用宏定義命令、文件包含命令、條件編譯命令來實現。為了與一般C++語句相區別,這些命令以符號“#”開頭,而且末尾不包含分號。4.15.1

宏定義可以用#define命令將一個指定的標識符(即宏名)來代表一個字符串。定義宏的作用一般是用一個短的名字代表一個長的字符串。它的一般形式為#define標識符字符串這就是已經介紹過的定義符號常量。如#define

PI

3.1415926還可以用#define命令定義帶參數的宏定義。其定義的一般形式為#define

宏名(參數表)字符串如#define

S(a,b)a*b

//定義宏S(矩形面積),a、b為宏的參數使用的形式如下:area=S(3,2)用3、2分別代替宏定義中的形式參數a和b,即用3*2代替S(3,2)。因此賦值語句展開為area=3*2;intw=s(2+3,4);

//w的值為多少?由于C++增加了內置函數(inline),比用帶參數的宏定義更方便,因此在C++中基本上已不再用#define命令定義宏了,主要用于條件編譯中。4.15.2“文件包含”處理1.“文件包含”的作用所謂“文件包含”處理是指一個源文件可以將另外一個源文件的全部內容包含進來,即將另外的文件包含到本文件之中。C++提供了#include命令用來實現“文件包含”的操作。如在file1.cpp中有以下#include命令:#include

"file2.cpp"它的作用見下圖示意。“文件包含”命令是很有用的,它可以節省程序設計的重復勞動。#include命令的應用很廣泛,絕大多數C++程序中都包括#include命令。現在,庫函數的開發者把這些信息寫在一個文件中,用戶只需將該文件“包含”進來即可(如調用數學函數的,應包含cmath文件),這就大大簡化了程序,寫一行#include命令的作用相當于寫幾十行、幾百行甚至

行的內容。這種常用在文件頭部的被包含的文件稱為“標題文件”或“頭部文件”。頭文件一般包含以下幾類內容:(1)

對類型的

。(2)

函數

。(3)

內置(inline)函數的定義。(4)宏定義。用#define定義的符號常量和用const的常變量。(5)

全局

溫馨提示

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

評論

0/150

提交評論