函數(shù)和編譯預(yù)處理第5章_第1頁
函數(shù)和編譯預(yù)處理第5章_第2頁
函數(shù)和編譯預(yù)處理第5章_第3頁
函數(shù)和編譯預(yù)處理第5章_第4頁
函數(shù)和編譯預(yù)處理第5章_第5頁
已閱讀5頁,還剩87頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

函數(shù)和編譯預(yù)處理第5章引言函數(shù)的定義和調(diào)用函數(shù)的原型說明與值調(diào)用函數(shù)的嵌套和遞歸調(diào)用作用域和存儲(chǔ)類內(nèi)聯(lián)函數(shù)具有缺省參數(shù)值的函數(shù)函數(shù)重載編譯預(yù)處理程序的多文件組織本章學(xué)習(xí)要求掌握函數(shù)定義的格式;掌握函數(shù)原形的概念及其與頭文件的關(guān)系;掌握兩種形式的函數(shù)調(diào)用(表達(dá)式中的函數(shù)調(diào)用和語句中的函數(shù)調(diào)用);掌握函數(shù)調(diào)用過程中參數(shù)傳遞的原理;掌握函數(shù)重載的方法;掌握保留字inline的含義與使用;了解函數(shù)和變量的作用域與生存期;掌握和應(yīng)用宏定義、條件編譯、文件包含。引言隨著模擬對(duì)象的復(fù)雜性增加,程序?qū)?huì)變得越來越復(fù)雜和冗長。在編寫一個(gè)較大的程序時(shí),為了便于管理,可以采用一些較好的編程策略,常用的方法是按功能或操作將程序分割成一些具有特定功能的、相對(duì)獨(dú)立的且便于管理和閱讀的小模塊。本章主要介紹這種分割工具之一:函數(shù),包括函數(shù)的定義、函數(shù)的調(diào)用、參數(shù)的傳遞方法、內(nèi)聯(lián)函數(shù)、函數(shù)的重載、變量的作用域等,另外簡要介紹編譯預(yù)處理以及程序多文件組織的編譯和連接方法。

函數(shù)的定義和調(diào)用函數(shù)概述

函數(shù)定義

函數(shù)調(diào)用

5.1函數(shù)概述C++中的函數(shù)就是具有特定功能的模塊。函數(shù)是構(gòu)成C++程序的基本單位,C++程序的運(yùn)行都是由主函數(shù)(main())開始,然后通過一系列函數(shù)調(diào)用來實(shí)現(xiàn)各種功能。從用戶角度看,函數(shù)包括用戶自定義函數(shù)和系統(tǒng)庫函數(shù)。從函數(shù)的形式來看,函數(shù)可以分為無參函數(shù)、有參函數(shù)、無返回值函數(shù)和有返回值函數(shù)等。除了main()函數(shù)以外,一個(gè)函數(shù)既可以被其它函數(shù)調(diào)用,也可以調(diào)用其它函數(shù)。圖5-l反映了函數(shù)的層次組織結(jié)構(gòu)以及相互之間的調(diào)用關(guān)系。5.1.1系統(tǒng)庫函數(shù)庫函數(shù)也稱為標(biāo)準(zhǔn)函數(shù),是在C++編譯系統(tǒng)中已經(jīng)預(yù)先定義的函數(shù)。C++把一些常用的操作以庫函數(shù)的方式提供給用戶,包括常用的數(shù)學(xué)計(jì)算函數(shù)(如:sqrt()、fabs()等)、圖形處理函數(shù)、標(biāo)準(zhǔn)輸入/輸出函數(shù)等。按功能對(duì)庫函數(shù)進(jìn)行分類,將同類庫函數(shù)集中在一個(gè)頭文件中,用戶只要在程序中包含相應(yīng)的頭文件,就可以使用該頭文件中的所有庫函數(shù)。

用戶自定義函數(shù)在程序設(shè)計(jì)過程中,用戶可根據(jù)自己的需要將一段完成功能相對(duì)獨(dú)立的代碼定義為一個(gè)函數(shù),這類函數(shù)稱為用戶自定義函數(shù)。本章將主要介紹用戶自定義函數(shù)的定義和調(diào)用方法。

圖5-1函數(shù)調(diào)用和被調(diào)用的層次關(guān)系main()Func1()Func5()Func3()Func2()Func4()函數(shù)定義對(duì)于庫函數(shù),在頭文件中已經(jīng)定義好了,調(diào)用函數(shù)前只需包含相應(yīng)的頭文件即可;對(duì)于用戶自定義的函數(shù),要先完成函數(shù)的定義,然后才可以調(diào)用它。根據(jù)函數(shù)定義和使用時(shí)參數(shù)的不同,可將函數(shù)分為兩類:無參函數(shù)和有參函數(shù)。

無參函數(shù)

有參函數(shù)

函數(shù)返回值和return語句

5.1.2無參函數(shù)定義無參函數(shù)的一般格式為:

《<類型>》<函數(shù)名>(《void》) {…}//函數(shù)體

<類型>為函數(shù)返回值的類型,它可以是任一標(biāo)準(zhǔn)數(shù)據(jù)類型或?qū)С鰯?shù)據(jù)類型,當(dāng)沒有返回值時(shí),《類型》必須為void。函數(shù)名為用戶給函數(shù)起的名字,其命名規(guī)則與標(biāo)識(shí)符相同。<函數(shù)名>后的括號(hào)”()”稱為函數(shù)調(diào)用運(yùn)算符,對(duì)于無參函數(shù),函數(shù)調(diào)用運(yùn)算符內(nèi)可以為空,也可以為void。函數(shù)返回值為整型時(shí),可省略類型標(biāo)識(shí)符int。當(dāng)函數(shù)無返回值時(shí),必須規(guī)定其類型為void。示例示例voidMessage(void){

cout<<”*************\n”;

cout<<”verygood!\n”;

cout<<”*************\n”;}該函數(shù)完成輸出一些問候語。像這類與外部環(huán)境之間沒有任何數(shù)據(jù)交換的函數(shù),通常將其定義為無參函數(shù)。

有參函數(shù)定義有參函數(shù)的一般格式為:

《類型》<函數(shù)名>(<形參表>) {…}//函數(shù)體

有參函數(shù)中《類型》與<函數(shù)名>的含義和要求與無參函數(shù)一致。<形參表>為該函數(shù)的參數(shù)的類型和名字,<形參表>中的參數(shù)稱為形式參數(shù)或形參,形參的個(gè)數(shù)是沒有限制的,當(dāng)超過一個(gè)參數(shù)時(shí),參數(shù)間一定要用逗號(hào)”,”分隔開,且每個(gè)參數(shù)都要有類型說明。示例

在定義有參函數(shù)時(shí),必須標(biāo)明每個(gè)參數(shù)的類型,即使參數(shù)的數(shù)據(jù)類型相同,也不能將參數(shù)合在一起用一個(gè)類型說明符。

示例例如,求兩個(gè)整數(shù)中的大數(shù),函數(shù)可定義為:

intMax(intx,inty) //A {return(x>y?x:y);}該函數(shù)有兩個(gè)整型參數(shù)x,y,函數(shù)的返回值是整型。

如上例A行寫成以下形式就是錯(cuò)誤的:

Max(intx,y)函數(shù)返回值和return語句函數(shù)的返回值也稱為函數(shù)值。當(dāng)函數(shù)有返回值時(shí),在函數(shù)體中必須使用return語句來返回該函數(shù)的值。return語句的一般格式為:

return<表達(dá)式>;或

return(<表達(dá)式>);這里<表達(dá)式>可以為任意合法的表達(dá)式。當(dāng)執(zhí)行該語句時(shí),首先求出表達(dá)式的值,再將該值轉(zhuǎn)換成函數(shù)定義時(shí)規(guī)定的返回值的類型后,將其作為函數(shù)的返回值。

【例5.1】

求三角形的面積

函數(shù)調(diào)用C++中,函數(shù)的功能是通過在程序中對(duì)其調(diào)用來實(shí)現(xiàn)的。調(diào)用一個(gè)函數(shù),就是把控制權(quán)轉(zhuǎn)去執(zhí)行該函數(shù)的函數(shù)體,函數(shù)體執(zhí)行完之后,再將控制權(quán)轉(zhuǎn)到調(diào)用函數(shù)處。

無參函數(shù)的調(diào)用格式

有參函數(shù)的調(diào)用格式

函數(shù)調(diào)用的使用方式

關(guān)于形參和實(shí)參的幾點(diǎn)說明

【例5.2】

輸入三個(gè)實(shí)數(shù),求出其中的最大數(shù)圖5-25.1.3無參函數(shù)的調(diào)用格式無參函數(shù)的調(diào)用格式一般為:

<函數(shù)名>()在調(diào)用無參函數(shù)前,必須先定義與它同名的無參函數(shù)。如:Message函數(shù)定義過之后,可以使用Message();來調(diào)用。

有參函數(shù)的調(diào)用格式有參函數(shù)的調(diào)用格式一般為:

<函數(shù)名>(<實(shí)參表>)<實(shí)參表>中的參數(shù)稱為實(shí)際參數(shù)或?qū)崊?,每個(gè)實(shí)參可以是任一合法的表達(dá)式。實(shí)參與形參不同,在實(shí)參前沒有數(shù)據(jù)類型說明符。在調(diào)用有參函數(shù)前,也必須先定義,另外,調(diào)用有參函數(shù)時(shí)實(shí)參表和形參表的參數(shù)類型、個(gè)數(shù)必須匹配。

如:Max(4,9);及Max(a*4,b);函數(shù)的調(diào)用過程是:先計(jì)算各實(shí)參表達(dá)式的值(對(duì)有參函數(shù)),然后將所求的值傳遞給相應(yīng)的形參,執(zhí)行函數(shù)體,執(zhí)行完畢再返回到函數(shù)的調(diào)用處,繼續(xù)執(zhí)行其后繼語句。

函數(shù)調(diào)用的使用方式對(duì)于有返回值的函數(shù),可以用兩種方式調(diào)用:一種方式是函數(shù)調(diào)用出現(xiàn)在表達(dá)式中,其值(也稱為函數(shù)值)參與表達(dá)式的運(yùn)算;另一種方式是用一個(gè)語句來實(shí)現(xiàn)調(diào)用,即在調(diào)用格式后加上一個(gè)分號(hào),構(gòu)成函數(shù)調(diào)用語句,在這種情況下,函數(shù)返回值不起任何的作用。

對(duì)于沒有返回值的函數(shù),函數(shù)調(diào)用只能通過函數(shù)調(diào)用語句實(shí)現(xiàn)。

關(guān)于形參和實(shí)參的幾點(diǎn)說明定義函數(shù)時(shí)指定的形參,在未出現(xiàn)函數(shù)調(diào)用時(shí),它們不占用內(nèi)存中的存儲(chǔ)單元。只有在函數(shù)調(diào)用時(shí),形參才被分配內(nèi)存單元,在調(diào)用結(jié)束后,形參所占的內(nèi)存單元也被釋放。

調(diào)用時(shí)是將實(shí)參的值傳遞給形參,只是一個(gè)單向的傳遞關(guān)系。這是我們所說的“值傳遞”,形參值的改變不會(huì)影響實(shí)參的值。

實(shí)參與形參的類型應(yīng)相同。當(dāng)類型不一致時(shí),則它們應(yīng)該兼容,即按照不同類型數(shù)值的賦值規(guī)則,將實(shí)參轉(zhuǎn)換為形參的數(shù)據(jù)類型后再傳遞給形參。

圖5-2

函數(shù)的調(diào)用過程main()函數(shù)調(diào)用函數(shù)Max(a,b)函數(shù)Max(int,int)執(zhí)行函數(shù)Max(int,int)的函數(shù)體將Max(a,b)的返回值賦給t調(diào)用函數(shù)Max(c,t)…結(jié)束向Max函數(shù)傳遞實(shí)參a,b向Max函數(shù)傳遞實(shí)參c,t函數(shù)的原型說明與值調(diào)用函數(shù)的原型說明

函數(shù)的值調(diào)用

5.2函數(shù)的原型說明C++中,與變量一樣,函數(shù)的定義和使用也必須遵循先定義后使用的原則。如果函數(shù)的調(diào)用在函數(shù)的定義之前,就會(huì)出現(xiàn)編譯錯(cuò)誤。

如果函數(shù)調(diào)用在前、定義在后,則在函數(shù)調(diào)用之前,必須要對(duì)被調(diào)用的函數(shù)作原型說明。函數(shù)原型說明是一條語句,它必須以分號(hào)結(jié)束。函數(shù)原型說明的一般格式函數(shù)原型說明的目的是告訴編譯程序,該函數(shù)的參數(shù)個(gè)數(shù)、各參數(shù)的類型和返回值類型。函數(shù)原型說明可以出現(xiàn)在程序中的任何位置,只要在調(diào)用前即可,且對(duì)函數(shù)原型說明的次數(shù)沒有限制。

5.2.1函數(shù)原型說明的一般格式《類型》<函數(shù)名>(<形參表>);

《類型》<函數(shù)名>(<形參類型說明表>);

函數(shù)原型說明的形參和返回值的類型必須與對(duì)應(yīng)的函數(shù)定義一致,對(duì)于第一種格式,原型說明中形參表的形參名可以和定義時(shí)的形參名不一致,又由于形參在原型說明中并不起任何作用,因此可以省略形參名(即第二種格式)。

函數(shù)的值調(diào)用C++中,形參與實(shí)參的結(jié)合方式有三種:傳值調(diào)用、傳地址調(diào)用和引用調(diào)用。

傳值調(diào)用簡稱為值調(diào)用。值調(diào)用的特點(diǎn)是:在被調(diào)用函數(shù)的執(zhí)行過程中,只能改變形參,不能改變實(shí)參?!纠?.3】值傳遞應(yīng)用——兩數(shù)交換

圖5-3值傳遞的好處是使得函數(shù)具有完全的獨(dú)立性,函數(shù)的執(zhí)行對(duì)其外界的變量沒有影響。在值傳遞的情況下,函數(shù)只能通過return語句返回一個(gè)值或不返回任何值。要用函數(shù)實(shí)現(xiàn)兩個(gè)數(shù)參數(shù)的交換,值傳遞是無法實(shí)現(xiàn)的,可以用地址傳遞或引用傳遞的方法。

5.2.2圖5-3兩數(shù)交換函數(shù)調(diào)用過程示意圖35353553axbyybxa(a)交換前(b)交換后執(zhí)行函數(shù)Swap(int,int)函數(shù)的嵌套和遞歸調(diào)用函數(shù)的嵌套調(diào)用

函數(shù)的遞歸調(diào)用

5.3函數(shù)的嵌套調(diào)用C++語言的函數(shù)之間是相互平行、獨(dú)立的,在定義一個(gè)函數(shù)時(shí),不允許在其函數(shù)體內(nèi)再定義另一個(gè)函數(shù),即函數(shù)不允許嵌套定義。但是函數(shù)之間的嵌套調(diào)用是可以的,即在定義一個(gè)函數(shù)時(shí),在函數(shù)體內(nèi)又調(diào)用另一個(gè)函數(shù)。圖5-4【例5.4】求一元二次方程ax2+bx+c=0的根

5.3.1圖5-4嵌套調(diào)用⑤⑥④③⑦②⑧main函數(shù)b函數(shù)a函數(shù)調(diào)用a函數(shù)結(jié)束調(diào)用b函數(shù)⑨①函數(shù)的遞歸調(diào)用在函數(shù)A的定義中調(diào)用函數(shù)A,或在函數(shù)A的定義中調(diào)用函數(shù)B,而在函數(shù)B的定義中又調(diào)用了函數(shù)A,這類函數(shù)的自調(diào)用關(guān)系稱為遞歸調(diào)用。前一種情況稱為直接遞歸,而后一種情況稱為間接遞歸。在C++語言中,這兩種遞歸調(diào)用都是允許的。

【例5.5】用函數(shù)遞歸調(diào)用方法求5!

【例5.6】將參數(shù)逐位正序和反序輸出

【例5.7】Hanoi(漢諾塔)問題

5.3.2【例5.5】用函數(shù)遞歸調(diào)用方法求4!分析:由遞推公式n!=n*(n-1)!,所以求n!的問題可以轉(zhuǎn)化為求(n-1)!的問題,(n-1)!=(n-1)*(n-2)!,因此求(n-1)!的問題可以轉(zhuǎn)化為求(n-2)!的問題,依此類推,直到轉(zhuǎn)化為求1!的問題,根據(jù)定義,1!=1,則從1!=1開始將上述過程逆向求解,就可以求出n!。這種求解問題的方法可用函數(shù)遞歸調(diào)用方法實(shí)現(xiàn)算法演示程序代碼算法演示程序代碼#include<iostream.h>int

f(intn){ if(n==0||n==1)return1; //A elsereturnn*f(n-1); //B }voidmain(void){cout<<<<f(4)<<'\n';}【例5.6】將參數(shù)逐位正序和反序輸出設(shè)計(jì)兩個(gè)函數(shù),其參數(shù)都為整型,分別將參數(shù)逐位正序和反序輸出。要求用遞歸函數(shù)實(shí)現(xiàn)。

分析:要實(shí)現(xiàn)逐位正序或反序輸出一個(gè)整數(shù),則須獲取它的各位數(shù)字。如1234,則用1234%10獲得它的個(gè)位數(shù),求十位數(shù),則須先將個(gè)位數(shù)去掉,即1234/10,結(jié)果為123,再求個(gè)位數(shù)即可,依此類推。求一個(gè)整數(shù)K的各位數(shù)字時(shí)其遞推關(guān)系為:

f1=Ktn=fn%10fn+1=fn/10

其中tn為整數(shù)K的第n位數(shù)字(從右數(shù)起),fn為去掉K的右邊n-1位數(shù)后剩下的數(shù)。而該遞推關(guān)系的結(jié)束條件為fn=0。程序代碼

【例5.7】Hanoi(漢諾塔)問題這是一個(gè)經(jīng)典的數(shù)學(xué)問題:有三個(gè)塔A、B、C,開始時(shí)A塔上有n個(gè)盤子,盤子大小不等,大的在下,小的在上,如圖5-6所示。要求將這n個(gè)盤子從A塔移到C塔,但每次只允許移一個(gè)盤子,而且在移動(dòng)過程中始終保持大盤子在下,小盤子在上,在移動(dòng)過程中可以利用B塔。分析移動(dòng)步驟遞歸公式程序代碼圖5-6漢諾塔問題分析可以用遞歸的思想來考慮這個(gè)問題。假設(shè)能將A塔中最上面的n-1個(gè)盤子借助于C塔移動(dòng)到B塔,然后將A塔中剩下的一個(gè)盤子移動(dòng)到C塔,再將B塔中的n-1個(gè)盤子借助于A塔移動(dòng)到C塔,這樣問題就解決了。因此接下來就要考慮如果一個(gè)塔內(nèi)有n-1個(gè)盤子,如何借助于另一個(gè)塔移動(dòng)到C塔,與n個(gè)盤子的思考方法一樣,此時(shí)可考慮先移動(dòng)n-2個(gè)盤子,依次類推,當(dāng)變成移動(dòng)一個(gè)盤子時(shí),遞歸結(jié)束。

移動(dòng)步驟將n個(gè)盤子從A塔移到C塔上,可以分解為以下3個(gè)步驟:

將A塔上的n-1個(gè)盤子借助C塔先移到B塔上;

將A塔上剩下的1個(gè)盤子移到C塔上;

將n-1個(gè)盤子從B塔借助于A塔移到C塔上。

其中第一步和第三步又可以分解為類似的三步,依次類推,直到A中只剩下一個(gè)盤子時(shí),遞歸結(jié)束。

遞歸公式將k-1個(gè)盤子從一個(gè)塔借助于另一個(gè)塔移動(dòng)到第三個(gè)塔上(k>1),它是一個(gè)遞歸的過程。用函數(shù)Hanoi(intk,charA,charB,charC)表示,其中第一個(gè)參數(shù)k為要移動(dòng)盤子的個(gè)數(shù),第二個(gè)參數(shù)A為初始塔,第三個(gè)參數(shù)B為中間塔,第四參數(shù)C為目標(biāo)塔。該函數(shù)的功能是將A塔中的k個(gè)盤子通過B塔移動(dòng)到C塔。

將1個(gè)盤子從一個(gè)塔移到另一塔上。用Move(charA,charB)實(shí)現(xiàn),即將A塔中的盤子移動(dòng)到B塔中去。

作用域和存儲(chǔ)類作用域是指程序中所說明的標(biāo)識(shí)符的適用范圍。C++中的作用域共分為:塊作用域、文件作用域、函數(shù)原型作用域、函數(shù)作用域和類作用域。存儲(chǔ)類型決定了變量的生存期,即何時(shí)為變量分配存儲(chǔ)空間以及何時(shí)撤消存儲(chǔ)空間。在定義變量時(shí),通常根據(jù)該變量的不同用途,為其指定相應(yīng)的存儲(chǔ)類型。作用域

存儲(chǔ)類型

5.4作用域作用域描述的是標(biāo)識(shí)符起作用的范圍,這里的標(biāo)識(shí)符可以泛指變量、常量或函數(shù)原型說明等。但對(duì)編譯預(yù)處理中宏定義中的宏名卻不適用。

塊作用域

函數(shù)原型作用域

函數(shù)作用域

文件作用域

5.4.1塊作用域用花括號(hào)括起來的程序段構(gòu)成一個(gè)塊(即復(fù)合語句),在塊內(nèi)說明的標(biāo)識(shí)符只能在該塊內(nèi)使用,其作用域就稱為塊作用域。具有塊作用域的標(biāo)識(shí)符的有效范圍是從聲明處開始,到塊結(jié)束處為止,該作用域的范圍是具有局部性的。因此,在塊內(nèi)定義的變量稱為局部變量。

示例對(duì)于塊作用域,C++語言做如下的規(guī)定:

塊嵌套問題

對(duì)一些特殊情況,C++作不同的處理

塊嵌套問題塊嵌套問題。當(dāng)塊A包含塊B,則在塊B中可以使用在塊A中定義的標(biāo)識(shí)符,反過來則不行。另外當(dāng)在塊A中定義的標(biāo)識(shí)符與塊B中定義的標(biāo)識(shí)符同名時(shí),則在塊B中的標(biāo)識(shí)符將屏蔽塊A中的同名標(biāo)識(shí)符,即局部優(yōu)先

【例5.8】塊嵌套中標(biāo)識(shí)符的使用

對(duì)一些特殊情況,C++作不同的處理對(duì)if語句或switch語句的表達(dá)式中定義的標(biāo)識(shí)符,其作用域在該語句內(nèi)。例如在for語句的第一個(gè)表達(dá)式中聲明的標(biāo)識(shí)符,其作用域?yàn)榘揻or循環(huán)語句的那個(gè)塊。例如

定義有參函數(shù)時(shí),形式參數(shù)的作用域?yàn)閴K作用域,即它的適用范圍為整個(gè)函數(shù)體

例如voidBlock4(){

if(inti=2) //i的作用域從此行開始

i+=1; else i+=2;

//i的作用域到此行結(jié)束

cout<<i<<endl; //錯(cuò)誤,i沒有定義}例如voidBlack5(){ for(inti,j=0;i<10;i++)//A {

intj=9; //與A行定義的j沒有沖突,

cout<<i+j<<’\t’; }

inti=10; //錯(cuò)誤,與A行定義的i同名

cout<<”i=”<<i<<’\n’; }函數(shù)原型作用域函數(shù)原型聲明(沒有函數(shù)體)中參數(shù)的作用域稱為函數(shù)原型作用域。此時(shí),參數(shù)的作用域開始于函數(shù)原型聲明的左括號(hào),結(jié)束于函數(shù)原型聲明的右括號(hào)。比如:

voidFun(intx,inty); x=2;//錯(cuò)誤,x沒有定義

由于函數(shù)原型聲明中的參數(shù)名與函數(shù)定義以及函數(shù)調(diào)用均無關(guān),因此,函數(shù)原型聲明中參數(shù)的標(biāo)識(shí)符可以與函數(shù)定義中參數(shù)的標(biāo)識(shí)符不同,甚至在函數(shù)原型聲明時(shí)可以只列出參數(shù)的類型,而沒有參數(shù)名。比如:

voidFun(int,int);函數(shù)作用域函數(shù)作用域是指在函數(shù)體內(nèi)定義的標(biāo)識(shí)符在其定義的函數(shù)內(nèi)均有效。該標(biāo)識(shí)符在函數(shù)的任何位置都可以使用它,不受先定義后使用的限制,也不受函數(shù)體中嵌套塊的限制。C++中,只有標(biāo)號(hào)具有函數(shù)作用域,即在一個(gè)函數(shù)體內(nèi)定義的標(biāo)號(hào),在該函數(shù)的任何位置都可以調(diào)用該標(biāo)號(hào)(條件語句、循環(huán)語句、switch語句中的特殊情形除外)。且正是由于標(biāo)號(hào)為函數(shù)作用域,因此在一個(gè)函數(shù)中不能用goto語句調(diào)用另一個(gè)函數(shù)中的標(biāo)號(hào)。例如

例如voidFun(intx){

inty;lab1: cout<<”輸入y:”<<’\n’;//A

cin>>y;

{ lab1:y+=x;//錯(cuò)誤,與A行的標(biāo)號(hào)同名,盡管它們屬于不同的塊

if(!y)gotolab1; elsegotolab2; //錯(cuò)誤,不能調(diào)用其它函數(shù)中的標(biāo)號(hào)

}}voidFun1(intx){lab2:cout<<x<<’\n’;}文件作用域具有文件作用域的標(biāo)識(shí)符是在所有函數(shù)定義之外定義的,即該標(biāo)識(shí)符不隸屬于任何塊。它的作用域從標(biāo)識(shí)符聲明處開始,一直到文件結(jié)束。具有文件作用域的變量稱為全局變量。當(dāng)在塊作用域內(nèi)的變量與全局變量同名時(shí),局部變量優(yōu)先。此時(shí)若想在該塊中調(diào)用全局變量,可通過作用域運(yùn)算符“::”來實(shí)現(xiàn)。

【例5.9】在塊作用域內(nèi)引用文件作用域同名變量

存儲(chǔ)類型作用域是從空間上對(duì)標(biāo)識(shí)符進(jìn)行劃分的,而存儲(chǔ)類型則是從變量存在的時(shí)間(即生存期)來劃分變量。變量的存儲(chǔ)類型可以分為靜態(tài)存儲(chǔ)方式和動(dòng)態(tài)存儲(chǔ)方式兩大類。

在C++中,變量的存儲(chǔ)類型分為四種:自動(dòng)(auto)類型、寄存器(register)類型、靜態(tài)(static)類型和外部(extern)類型。

自動(dòng)類型變量

靜態(tài)類型變量

寄存器類型變量

外部類型變量

5.4.2靜態(tài)存儲(chǔ)方式

在程序開始執(zhí)行時(shí)就為變量分配存儲(chǔ)空間,直到程序執(zhí)行結(jié)束時(shí),才收回為變量分配的存儲(chǔ)空間,這種變量稱為靜態(tài)存儲(chǔ)變量,其生命期為整個(gè)程序執(zhí)行過程。動(dòng)態(tài)存儲(chǔ)方式

在程序的執(zhí)行過程中,為其分配存儲(chǔ)空間的變量稱為動(dòng)態(tài)存儲(chǔ)變量。對(duì)于動(dòng)態(tài)存儲(chǔ)變量,當(dāng)程序運(yùn)行到該變量的定義處時(shí)為其分配存儲(chǔ)空間,而當(dāng)程序運(yùn)行到該變量所在作用域的結(jié)束處時(shí)自動(dòng)收回為其分配的存儲(chǔ)空間。因此動(dòng)態(tài)存儲(chǔ)類型的變量的生存期為其所在的作用域。

自動(dòng)類型變量用關(guān)鍵字auto修飾的變量稱為自動(dòng)類型的變量。在說明局部變量時(shí),編譯系統(tǒng)默認(rèn)其為自動(dòng)類型變量,因此通常省略關(guān)鍵字auto。自動(dòng)類型的變量只能是局部類型的變量,不可能為全局變量。示例自動(dòng)類型變量屬于動(dòng)態(tài)存儲(chǔ)類型變量。上例中的x,y的生存期為其所在的作用域。具體說,對(duì)x而言,在A行為其分配4個(gè)字節(jié)的存儲(chǔ)空間,到B行就收回該存儲(chǔ)空間。在使用自動(dòng)類型的變量之前必須對(duì)其賦初值。否則,其值為一個(gè)不確定的隨機(jī)數(shù)。

autointI;//錯(cuò)誤,全局變量不能用關(guān)鍵字 //auto修飾voidAu(void){autointx=1;//Ax為自動(dòng)類型變量

chary=’a’; //省略關(guān)鍵字auto系統(tǒng)默 //認(rèn)y為自動(dòng)類型變量} //B靜態(tài)類型變量靜態(tài)存儲(chǔ)類型的變量有兩種:全局變量和靜態(tài)類型變量。用關(guān)鍵字static修飾的變量稱為靜態(tài)類型變量。靜態(tài)類型變量可以為局部變量,也可以為全局變量。靜態(tài)類型變量屬于靜態(tài)存儲(chǔ)變量,即在程序開始運(yùn)行時(shí)就為其分配存儲(chǔ)空間,當(dāng)程序結(jié)束時(shí)才釋放其所占用的存儲(chǔ)空間。因此在整個(gè)程序執(zhí)行過程中,靜態(tài)變量都始終占用同一個(gè)存儲(chǔ)空間。

【例5.10】使用靜態(tài)類型的局部變量

寄存器類型變量用關(guān)鍵字register修飾的局部變量稱為寄存器類型變量,這類變量也采用動(dòng)態(tài)存儲(chǔ)的分配方式。在編譯過程中,編譯器不為寄存器類型的變量分配內(nèi)存空間,而是直接使用CPU中的寄存器,以便提高對(duì)這類變量的存取速度。寄存器類型變量主要用于控制循環(huán)次數(shù)等不需要長期保存值的變量。

【例5.11】利用寄存器類型變量求l~15的階乘。

#include<iostream.h>voidmain(void){ registerfloatFact=1; //定義實(shí)型寄存器變量Fact for(registerinti=1;i<=15;i++)//定義整型寄存器變量i { Fact*=i;

cout<<i<<"!="<<Fact<<'\n'; }}外部類型變量用關(guān)鍵字extern修飾的變量稱為外部類型變量,外部類型變量必須是全局變量。在C++中,有兩種情況下需要使用外部類型變量。

在同一個(gè)源程序文件中,當(dāng)在全局變量的定義之前使用該變量時(shí),在使用前要對(duì)該變量進(jìn)行外部類型變量聲明?!纠?.12】外部類型變量的聲明

當(dāng)程序由多個(gè)文件組成時(shí),若在一個(gè)源程序文件中要引用在另一個(gè)源程序中定義的全局變量,在引用前必須對(duì)所引用的變量進(jìn)行外部聲明?!纠?.13】文件間共享全局變量

【例5.12】外部類型變量的聲明#include<iostream.h>int

Max(int

x,inty){returnx>y?x:y;}

voidmain(void){ externinta,b; //A

cout<<Max(a,b); //B}inta=12,b=-4;【例5.13】文件間共享全局變量externfloatx; //A voidmain(void) { x++;cout<<x<<’\n’;}在文件c2.cpp中有:

floatx=100; //B

內(nèi)聯(lián)函數(shù)一般函數(shù)在調(diào)用時(shí),要花費(fèi)將實(shí)參和返回地址壓入棧,然后轉(zhuǎn)入執(zhí)行被調(diào)用函數(shù)等一系列開銷。

C++中的內(nèi)聯(lián)函數(shù),將省略這類的開銷。編譯系統(tǒng)對(duì)內(nèi)聯(lián)函數(shù)的處理與一般函數(shù)的處理方式不同,在編譯調(diào)用內(nèi)聯(lián)函數(shù)的語句時(shí),編譯器將內(nèi)聯(lián)函數(shù)的代碼插入到函數(shù)調(diào)用處,在運(yùn)行過程中,將直接運(yùn)行插入的代碼,從而可以提高程序運(yùn)行的速度。將一個(gè)函數(shù)聲明為內(nèi)聯(lián)函數(shù)時(shí),只要在函數(shù)定義前加關(guān)鍵字inline即可,聲明格式【例5.14】用內(nèi)聯(lián)函數(shù)計(jì)算立方體的體積

5.5內(nèi)聯(lián)函數(shù)聲明格式

inline<類型><函數(shù)名>(《參數(shù)表》) {

…//函數(shù)體

}【例5.14】用內(nèi)聯(lián)函數(shù)計(jì)算立方體的體積#include<iostream.h> inlinefloatCube(floata){returna*a*a;}

voidmain(){

cout<<”輸入立方體的邊長:”; floatside;

cin>>side;

cout<<”邊長為”<<side<<”的立方體的體積為:”

<<Cube(side)<<’\n’; //A}具有缺省參數(shù)值的函數(shù)在定義具有缺省參數(shù)值的函數(shù)時(shí),要為參數(shù)指定一個(gè)值。比如:

voidFun(intx=1,inty=2){…}【例5.15】具有缺省參數(shù)值的延時(shí)函數(shù)

【例5.16】求圓柱體的體積

5.6【例5.15】具有缺省參數(shù)值的延時(shí)函數(shù)#include<iostream.h>voidDelay(intn=1000) //A{ for(;n>0;n--); }

voidmain(void){cout<<"延時(shí)500個(gè)單位時(shí)間…\n";Delay(500); //Bcout<<"延時(shí)1000個(gè)單位時(shí)間…\n";Delay(); //C}【例5.16】求圓柱體的體積#include<iostream.h>#definePI3.1415926floatVolume(floatr,floath=10); //A

voidmain(void){ floatr,h;

cout<<"輸入第一個(gè)圓柱體的半徑和高度:";

cin>>r>>h;

cout<<"第一個(gè)圓柱體的體積為:"<<Volume(r,h)<<'\n';

cout<<"輸入第二個(gè)圓柱體的半徑:";

cin>>r;

cout<<"第二個(gè)圓柱體的體積為:"<<Volume(r)<<'\n'; floatVolume(float=5,float=20); //B

cout<<"第三個(gè)圓柱體的體積為:"<<Volume()<<'\n';//C}floatVolume(floatr,floath) //D { return(PI*r*r*h); }函數(shù)重載函數(shù)的重載又稱函數(shù)名重載,是指實(shí)現(xiàn)不同功能的函數(shù)可以具有相同的函數(shù)名。

C++編譯器在進(jìn)行函數(shù)調(diào)用時(shí)是根據(jù)函數(shù)名和函數(shù)的參數(shù)來決定調(diào)用哪一個(gè)函數(shù)的,因此,對(duì)于函數(shù)名重載問題,要區(qū)分函數(shù)名相同的函數(shù),只有從它們的參數(shù)上進(jìn)行區(qū)分。要實(shí)現(xiàn)函數(shù)名重載,它們的參數(shù)必須滿足下面兩個(gè)條件之一:參數(shù)的個(gè)數(shù)不同參數(shù)的類型不同【例5.17】利用參數(shù)類型的不同實(shí)現(xiàn)重載函數(shù)

【例5.18】利用參數(shù)個(gè)數(shù)不相同實(shí)現(xiàn)重載函數(shù)在定義重載函數(shù)時(shí)要注意的幾點(diǎn)

5.7【例5.17】利用參數(shù)類型的不同實(shí)現(xiàn)重載函數(shù)#include<iostream.h>

int

Abs(intx){ //A

cout<<”調(diào)用函數(shù)Abs(int).”<<’\n’; returnx>=0?x:-x; } doubleAbs(doublex) { //B

cout<<”調(diào)用函數(shù)Abs(double).”<<’\n’; returnx>=0?x:-x; } voidmain() {

cout<<”-20的絕對(duì)值是:”<<Abs(-20)<<endl;//C

cout<<”-111.11的絕對(duì)值是:”<<Abs(-111.11)<<endl;//D }【例5.18】利用參數(shù)個(gè)數(shù)不相同實(shí)現(xiàn)重載函數(shù)#include<iostream.h>int

max(int

a,intb);int

max(int

a,int

b,intc);int

max(int

a,int

b,int

c,intd);voidmain(){

cout<<max(3,5)<<endl;

cout<<max(-7,9,0)<<endl;

cout<<max(23,15,3,6)<<endl; }int

max(int

a,intb){ returna>b?a:b;}int

max(int

a,int

b,intc){ intt=max(a,b); returnmax(t,c);}int

max(int

a,int

b,int

c,intd){ intt1=max(a,b);

intt2=max(c,d); returnmax(t1,t2);}在定義重載函數(shù)時(shí)要注意的幾點(diǎn)定義的重載函數(shù)必須具有不同的參數(shù)個(gè)數(shù)或不同的參數(shù)類型,只有這樣編譯系統(tǒng)才能根據(jù)不同的參數(shù)決定調(diào)用哪一個(gè)函數(shù)版本

僅僅是函數(shù)返回值不同并不能區(qū)分兩個(gè)函數(shù),因此不能根據(jù)函數(shù)的返回值定義函數(shù)的重載。例如

int

sum(inta){…}voidsun(inta) {…}這兩個(gè)函數(shù)僅僅返回值不同,編譯時(shí)將發(fā)生二義性錯(cuò)誤。編譯預(yù)處理C++語言中使用一些特殊的命令,在編譯之前先對(duì)這些命令進(jìn)行“預(yù)處理”,然后將結(jié)果和源程序一起進(jìn)行編譯處理,得到目標(biāo)代碼,此過程稱為編譯預(yù)處理。這些命令稱為編譯預(yù)處理指令,它們不是C++語句,一律以#開頭,以回車符結(jié)束,每一條預(yù)處理指令獨(dú)占一行。

根據(jù)編譯預(yù)處理功能的不同,將其分為三類:宏定義#define、文件包含#include和條件編譯#if。

“文件包含”處理

宏定義

條件編譯

5.8所謂“文件包含”處理是指一個(gè)源文件可以將另一個(gè)源文件的全部內(nèi)容包含進(jìn)來。“文件包含”可通過#include編譯預(yù)處理指令來實(shí)現(xiàn),格式為:

#include<文件名>或

#include“文件名”

“文件包含”的處理過程

【例5.19】文件包含的應(yīng)用

關(guān)于#include編譯預(yù)處理指令需要說明的幾點(diǎn)

“文件包含”處理5.8.1這種格式是標(biāo)準(zhǔn)格式,主要用于包含C++系統(tǒng)所提供的頭文件。當(dāng)C++預(yù)處理器遇到該指令時(shí),就到C++系統(tǒng)目錄的include子目錄下搜索給出的文件,并把它嵌入到當(dāng)前文件中。

這種格式既適合于用戶自己建立的文件,也適合于C++系統(tǒng)提供的頭文件。當(dāng)C++預(yù)處理器遇到該指令后,首先在當(dāng)前工作目錄中查找所包含的文件,如果找不到,再按標(biāo)準(zhǔn)方式進(jìn)行搜索。

“文件包含”的處理過程包含#include“File2.h”ABBAFile1.cppFile2.hFile1.cpp(a)(b)(c)圖3-7“文件包含”示意圖編譯預(yù)處理【例5.19】文件包含的應(yīng)用設(shè)文件File1.h的內(nèi)容為:intx=200,y=100; floatx1=25.6,x2=28.9;設(shè)文件File2.cpp的內(nèi)容為:#include“File1.h”//A#include<iostream.h>voidmain(void) { cout<<x<<’\t’<<y<<’\n’;

cout<<x1<’\t’<<x2<<’\n’; }intx=200,y=100;floatx1=25.6,x2=28.9;#include<iostream.h>voidmain(void){cout<<x<<’\t’<<y<<’\n’;

cout<<x1<<’\t’<<x2<<’\n’;}關(guān)于#include編譯預(yù)處理指令需要說明的幾點(diǎn)被包含的文件通常是頭文件,也可以為其他類型的文件,如源程序文件或文本文件等;

一個(gè)#include命令只能指定一個(gè)被包含文件;一個(gè)被包含的文件中也可以包含其他文件,即文件的包含可以是嵌套的,嵌套的層次也沒有限制;

#include指令可以出現(xiàn)在程序中的任何位置,通常是放在程序的開頭

由于被包含的文件(File1.h)與其所在的文件(File2.cpp)在預(yù)編譯后已稱為合并到一個(gè)文件中,因此,F(xiàn)ile2.cpp可直接訪問File1.h中的全局變量,此時(shí)可不用extern聲明。同樣,F(xiàn)ile2.cpp中也能直接訪問File1.h中的函數(shù)

宏定義

宏定義用#define編譯預(yù)處理指令實(shí)現(xiàn),可分為不帶參數(shù)的宏定義和帶參數(shù)的宏定義。不帶參數(shù)的宏常用于定義標(biāo)識(shí)符常量,即可將一個(gè)常量指定給一個(gè)標(biāo)識(shí)符,它與const類型的變量類似;帶參數(shù)的宏可將一個(gè)表達(dá)式指定給一個(gè)帶參數(shù)的標(biāo)識(shí)符,它與函數(shù)的功能類似。

不帶參數(shù)的宏定義

【例5.20】不帶參數(shù)的宏的使用

帶參數(shù)的宏定義

【例5.21】帶參數(shù)的宏定義的使用

5.8.2不帶參數(shù)的宏定義定義不帶參數(shù)宏的一般格式為:

#define標(biāo)識(shí)符

字符序列

其中標(biāo)識(shí)符稱為宏名,它可以是任意合法的標(biāo)識(shí)符,通常為大寫。字符序列為一串字符,它可由任意的字符構(gòu)成,包括空格。例如:

#definePI3.1415926不帶參數(shù)的宏定義及其使用需說明的幾點(diǎn)

不帶參數(shù)的宏定義及其使用需說明的幾點(diǎn)宏名可以為任意的合法標(biāo)識(shí)符,常用大寫字母表示

宏定義中可以用已定義過的宏名,但對(duì)用雙引號(hào)括起來的字符序列中的字符,即使與宏名相同,也不進(jìn)行宏擴(kuò)展。例如

宏擴(kuò)展時(shí),只對(duì)宏名作簡單的代換,不作任何計(jì)算,也不作任何語法檢查;比如宏定義不是C++語句,不必在行末加分號(hào),如果加了分號(hào)則會(huì)連分號(hào)一起進(jìn)行宏擴(kuò)展,例如:一個(gè)宏通常在一行內(nèi)定義完,并以換行符結(jié)束。當(dāng)多于一行時(shí),須使用轉(zhuǎn)義字符“

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論