小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

深入剖析C/C++函數(shù)的參數(shù)傳遞機(jī)制 (轉(zhuǎn)-有修正)作者:leeyeafu(明經(jīng)CAD社區(qū) 編程申請版塊 版主) - hairi的專欄

 accesine 2005-11-09
深入剖析C/C++函數(shù)的參數(shù)傳遞機(jī)制 (轉(zhuǎn)-有修正)作者:leeyeafu(明經(jīng)CAD社區(qū) 編程申請版塊 版主)

首先,這篇文章針對近期網(wǎng)友在ARX版塊的提問,很多都是在調(diào)用ARX函數(shù)或者設(shè)計自定義函數(shù)時出現(xiàn)的困惑,為方便大家分析和理解問題,進(jìn)而正確解決問題,我將個人的一些理解寫成文字,希望對大家在做ARX程序設(shè)計時有所幫助。同時,這篇文章也為“ObjectARX程序設(shè)計入門(2)”作些準(zhǔn)備工作。

這篇文章與普通的C/C++教材相比,可能要深入得多,閱讀時應(yīng)該細(xì)心。而對于未接觸過C語言的讀者來說,大概需要先閱讀一般的C++教材。我的看法,《C++編程思想》和《深入淺出MFC》一類的書對于初學(xué)者太過深入,而類似《Visual C++ 6.0從入門到精通》的書籍主要篇幅在介紹VC軟件的使用方法而不是講解C++程序設(shè)計方法,它們都不適宜作C++ARX程序設(shè)計入門學(xué)習(xí)用書。我個人學(xué)習(xí)C++使用的是南京大學(xué)出版社的書名就是《C++教程》,它是為C程序員編寫的C++教材,全書僅130多頁,內(nèi)容淺顯但基本夠用。不過那是上世紀(jì)90年代初出版的,現(xiàn)在大概不好找了,不過類似的(比如說大學(xué)教材)我想書店里還是有的。

文章中的大部分內(nèi)容是我個人的看法,一般的C++書籍上找不到類似的說法與其比較,對于其正確性,我沒有十足的把握。各位網(wǎng)友可以對此進(jìn)行討論或者批評。(只是不要真的用磚頭砸,那樣對于我英勇而忙碌的醫(yī)護(hù)人員太不尊重,別再給他們添亂了。)

C語言的函數(shù)入口參數(shù),可以使用值傳遞和指針傳遞方式,C++又多了引用(reference)傳遞方式。引用傳遞方式在使用上類似于值傳遞,而其傳遞的性質(zhì)又象是指針傳遞,這是C++初學(xué)者經(jīng)常感到困惑的。為深入介紹這三種參數(shù)傳遞方式,我們先把話題扯遠(yuǎn)些:

1、 C/C++函數(shù)調(diào)用機(jī)制及值傳遞:

在結(jié)構(gòu)化程序設(shè)計方法中,先輩們告訴我們,采用“自頂向下,逐步細(xì)化”的方法將一個現(xiàn)實(shí)的復(fù)雜問題分成多個簡單的問題來解決。而細(xì)化到了最底層,就是“實(shí)現(xiàn)單一功能”的模塊,在C/C++中,這個最小的單元模塊就是函數(shù)。然而,這些單個的模塊(或者說函數(shù))組合起來要能完成一項(xiàng)復(fù)雜的功能,這就注定各個函數(shù)之間必然要有這樣或那樣的聯(lián)系(即耦合)。而參數(shù)耦合是各個函數(shù)之間最為常見的耦合方式,也就是說,各個函數(shù)之間通常通過參數(shù)傳遞的方式來實(shí)現(xiàn)通訊。

當(dāng)我們設(shè)計或者調(diào)用一個函數(shù)時,首先要注意的是函數(shù)的接口,也就是函數(shù)的參數(shù)和返回值。調(diào)用一個函數(shù)就是將符合函數(shù)接口要求的參數(shù)傳遞給函數(shù)體,函數(shù)執(zhí)行后返回一個值給調(diào)用者。(當(dāng)然,C/C++允許void類型的參數(shù)和返回值。當(dāng)返回值為void時,函數(shù)類似BasicSub子過程或者PascalProcedure過程。)

函數(shù)的參數(shù)傳遞,就是將在函數(shù)體外部已賦值(或者至少已經(jīng)定義并初始化)的變量通過函數(shù)接口傳遞到函數(shù)體內(nèi)部。根據(jù)變量種類的不同,有不同的參數(shù)傳遞方式:

若傳遞的參數(shù)是一個類對象(包括象Intfloat這樣的C/C++內(nèi)部數(shù)據(jù)類型),這種傳遞方式為值傳遞。C/C++這種以函數(shù)為主體的語言中,幾乎所有的功能都是通過函數(shù)調(diào)用來實(shí)現(xiàn)的。<不是嗎?你說C/C++運(yùn)算符操作?還有變量聲明?你先等等,接下來我們就看看C++中這些操作是怎么實(shí)現(xiàn)的。>以下的C/C++代碼是如此的簡單,可能你從未想過還有什么要分析的,但它確實(shí)是函數(shù)值傳遞方式的典型例子。

float x = 0.254;
float y = 3.1415;
float z = x + y;

以上代碼編譯執(zhí)行時,第一步float x,即聲明一個實(shí)數(shù)變量。即將標(biāo)志符x認(rèn)為是一個實(shí)數(shù)變量,并調(diào)用float類的初始化函數(shù)。當(dāng)然你可能感覺不到它的存在,因?yàn)楝F(xiàn)在的CPU都直接支持浮點(diǎn)運(yùn)算,它只是一條匯編指令而已。

初始化完成后,調(diào)用賦值函數(shù):

x.operator = (0.254); 

不要奇怪以上函數(shù)的寫法,它實(shí)際上與 x = 0.254; 效果完全相同,會產(chǎn)生同樣的匯編代碼。

該函數(shù)首先根據(jù)變量x的數(shù)據(jù)類型分配合適的內(nèi)存空間,并將該內(nèi)存地址與標(biāo)志符x關(guān)聯(lián)。然后將立即數(shù)0.254寫入分配的內(nèi)存。(這里借用匯編語言的術(shù)語,立即數(shù)可以理解為程序已指定的具體數(shù)值。)然而,賦值函數(shù)的設(shè)計者并不能獲知立即數(shù)0.254的數(shù)值,調(diào)用該函數(shù)時就必須通過參數(shù)傳遞的方法將數(shù)值通知給函數(shù)體。賦值函數(shù)接口大致是這樣:

float float::operator = (register float a);

變量a是在CPU寄存器中使用的臨時變量。調(diào)用賦值函數(shù)時,將0.254送到寄存器變量a中,再將a值送到變量x所在的內(nèi)存位置中。以上函數(shù)的返回值用于類似這樣的鏈?zhǔn)奖磉_(dá)式的實(shí)現(xiàn):

x = y = z;

說了許多,好象十分復(fù)雜,其實(shí)賦值操作僅僅只是兩條匯編代碼:

mov AX, 0.254 

mov [x], AX

事實(shí)上,它之所以簡單,僅僅是因?yàn)?/STRONG>floatCPU能直接處理的數(shù)據(jù)類型。若以上代碼中不是float類型數(shù)據(jù)賦值,而是更復(fù)雜的(比如說自定義)類型數(shù)據(jù),同樣的賦值操作盡管是相同的步驟,但實(shí)際情況要復(fù)雜得多。因?yàn)榧拇嫫魅萘肯拗?,可能變?/SPAN>a無法作為寄存器變量存放,這樣即使是簡單的賦值操作也要為函數(shù)的臨時變量分配內(nèi)存并初始化,在函數(shù)的返回時,臨時變量又要析構(gòu)(或者說從內(nèi)存中釋放),這也就是參數(shù)值傳遞方式的弱點(diǎn)之一:效率低。以后我們還可以看到,值傳遞方式還有其力所不能及的時候。

上面的代碼段中加法調(diào)用這樣的函數(shù),其參數(shù)傳遞方式同樣是值傳遞:

float::operator + (float a, float b);

下面看一個稍微復(fù)雜的類,Complex復(fù)數(shù)類。ObjectARX程序設(shè)計中使用的大部份對象類型都將比這個類復(fù)雜。

class Complex
{
  public:
  Complex operator = (Complex others); //
賦值函數(shù),事實(shí)上不聲明系統(tǒng)也會默認(rèn)

  Complex operator + (Complex c1, Complex c2); //
加法
  void Complex (float Re, float Im); //
帶參數(shù)的構(gòu)造函數(shù)
  //
當(dāng)然,真正的復(fù)數(shù)類接口遠(yuǎn)比這復(fù)雜,為了說明問題,僅寫出這三個接口函數(shù)。
  private:
  float Re; //
復(fù)數(shù)的實(shí)部
  float Im; //
復(fù)數(shù)的虛部
} //
類接口函數(shù)的實(shí)現(xiàn)應(yīng)該并不復(fù)雜,在此略過。

類的接口函數(shù)的參數(shù)仍然用值傳遞方式。當(dāng)執(zhí)行下列代碼中的加法和賦值操作時,程序?qū)⒁啻螆?zhí)行Complex類的構(gòu)造函數(shù)和析構(gòu)函數(shù)。

Complex A(2.5, 3);

Complex B(0.4, 2.5);

Complex C = A + B;

最后一句代碼,首先聲明一個Complex類對象C,然后根據(jù)運(yùn)算符優(yōu)先級,執(zhí)行加法運(yùn)算,將對象AB傳遞給加法函數(shù),這時C++調(diào)用Complex類的默認(rèn)構(gòu)造函數(shù)聲明兩個臨時變量,再調(diào)用默認(rèn)的“拷貝構(gòu)造函數(shù)”采用位拷貝的方法將對象A,B復(fù)制到臨時變量,加法操作返回時,再將臨時變量析構(gòu),返回值再用值傳遞方式傳遞給賦值函數(shù)。

從以上執(zhí)行過程可以看出,值傳遞方式效率低的關(guān)鍵在于臨時變量的建立和析構(gòu)。于是考慮,因?yàn)樵谡{(diào)用函數(shù)時該變量已經(jīng)在內(nèi)存中存在,將這個已經(jīng)存在的變量直接傳遞給函數(shù)體而不去聲明和拷貝臨時變量。這樣,臨時變量的構(gòu)造、拷貝、析構(gòu)等工作都被省略,從而大大提高了函數(shù)效率。這便是使用C/C++指針和引用傳遞機(jī)制的主要原因。另外,使用這樣的函數(shù)參數(shù)傳遞機(jī)制,在函數(shù)體內(nèi)部可以很輕易地修改變量的內(nèi)容。(而使用值傳遞方式,函數(shù)體內(nèi)部只能修改臨時變量,沒有辦法修改這些外部變量本身的值。)這樣一方面增加了程序設(shè)計的靈活性,同時也給程序帶來了安全隱患。當(dāng)然,我們可以使用const聲明防止變量的內(nèi)容在函數(shù)體內(nèi)部被修改,但這需要編程者有良好的編程風(fēng)格和編程習(xí)慣。在介紹函數(shù)參數(shù)的指針和引用傳遞方式之前,先說一說指針和引用這兩個概念。

2、指針和引用

在解釋指針和引用之前,先看看普通變量是怎樣在內(nèi)存中存放的。聲明變量后,編譯程序要維護(hù)一張包括各種標(biāo)識符的表。在這張表內(nèi),每一個標(biāo)識符,比如說變量名都應(yīng)該有它的類型和在內(nèi)存中的位置。

在這要進(jìn)一步說明幾個問題,這些問題可能涉及多個計算機(jī)專業(yè)領(lǐng)域,我也不想在這作深入介紹,看不明白沒有關(guān)系,不會影響您繼續(xù)閱讀這篇文章。

首先,C/C++的內(nèi)存分配有靜態(tài)分配和動態(tài)分配兩種機(jī)制。靜態(tài)分配內(nèi)存是由編譯程序?yàn)闃?biāo)識符分配固定的內(nèi)存地址,而動態(tài)分配機(jī)制是應(yīng)用程序在進(jìn)入內(nèi)存后再根據(jù)程序使用內(nèi)存的實(shí)際情況決定變量存放地址。這個話題非常復(fù)雜,不過進(jìn)行ObjectARX程序設(shè)計好象不必太在意內(nèi)存分配機(jī)制,讓編譯程序和Windows去管這件事吧。而且內(nèi)存分配機(jī)制對于我們理解指針和引用不會造成影響。

其次,標(biāo)識符可以標(biāo)識變量,也可以標(biāo)識函數(shù)入口。從而它的類型可以是CPU能直接處理的內(nèi)部數(shù)據(jù)類型<例如int類型>,也可以是用戶自定義類型,還可以是函數(shù)類型。

另外,由于標(biāo)識符的類型不同,它占用內(nèi)存的大小也各有差異。“在內(nèi)存中的位置”實(shí)際上指的是它占用的內(nèi)存塊的首地址。對于80286以上的計算機(jī)<這句話是不是多余?>,內(nèi)存地址由基址(或段地址)加上偏移地址組成?;肥菓?yīng)用程序被調(diào)入內(nèi)存時由操作系統(tǒng)分配,當(dāng)然,編譯程序把應(yīng)用程序編譯成多個段,從而要求操作系統(tǒng)對于不同的段分配不同的基址。而編譯程序(哪怕是使用靜態(tài)地址分配)只能決定標(biāo)識符存放的偏移地址,也就是說,“在內(nèi)存中的位置”只是標(biāo)識符占用內(nèi)存的第一個字節(jié)的偏移地址。說了這么多,有一點(diǎn)需要記住,無論是程序設(shè)計者還是編譯程序都無法確知變量的內(nèi)存中的實(shí)際位置。

最后,這個標(biāo)識符表要比上面說的復(fù)雜,我只選擇了與目前討論的問題有關(guān)的內(nèi)容。

好了,準(zhǔn)備工作做了許多,讓我們正式進(jìn)入C/C++指針和引用的神秘世界。

指針變量其實(shí)質(zhì)類似一個int整型變量。我們在源程序中這樣聲明一個指針變量:

float *px;

此時,標(biāo)識符px指示的內(nèi)存位置上存放的就是一個int類型整數(shù),或者說,通過變量px可以訪問到一個int類型整數(shù),并且這個整數(shù)與指針指向的數(shù)據(jù)類型<在此例中為float浮點(diǎn)數(shù)>無關(guān)。在ARX程序中,甚至可以用這樣的方式打印一個指針變量:

acutPrintf(“指針變量px的值為%d, px);

當(dāng)然,這個整數(shù)值到底意味著什么,可以只有計算機(jī)(或者說操作系統(tǒng))自己知道,因?yàn)檫@個值表示的是指針指向的數(shù)據(jù)在內(nèi)存中的位置。也就是說,不應(yīng)該將指針變量與普通int整型混淆,例如,對指針進(jìn)行四則運(yùn)算將使用結(jié)果變得計算機(jī)和程序員都無法理解,盡管編譯器允許你這樣做。<實(shí)際上,計算數(shù)組下標(biāo)就要使用指針的加法。>

與普通變量不同,若在程序中聲明指針變量的同時不進(jìn)行初始化,系統(tǒng)會自動將指針變量初始化為NULL<NULL的值與0相同,但好的編程風(fēng)格是使用NULL而非0,以與普通int類型區(qū)別。>而聲明普通變量,系統(tǒng)僅為其分配內(nèi)存,而不做自動初始化,從而未初始化的變量值是不可預(yù)測的。當(dāng)然,直接使用未初始化的指針決不是一個好程序(此時編譯器會發(fā)出警告信息),其危害或隱患以后在說明內(nèi)存管理技術(shù)時再討論。<ObjectARX程序設(shè)計連載能堅持寫下去,我想會要涉及到內(nèi)存管理的。>
在聲明時初始化指針變量可以這樣:

//float *px = 0.254;原文如此

float f = 0.254 ;

float *px = &f ;

這是初始化同時賦值,也可以使用new運(yùn)算符進(jìn)行初始化:

float *px = new float;

這種初始化方式經(jīng)常用于不方便或不能直接賦值的復(fù)雜數(shù)據(jù)類型。

上述語句執(zhí)行時,首先分配一塊可存放數(shù)據(jù)的內(nèi)存區(qū)域<大小與數(shù)據(jù)類型有關(guān)>,若要同時賦值,就調(diào)用賦值函數(shù)將數(shù)值寫入剛分配的內(nèi)存中。然后為標(biāo)識符px分配一個int整型要占用的(通常為4字節(jié))內(nèi)存空間,最后將分配的用于存放數(shù)據(jù)的內(nèi)存首地址寫入內(nèi)存。

注意:使用new運(yùn)算符初始化指針,指針變量使用結(jié)束后應(yīng)該用delete運(yùn)算符釋放其占用的內(nèi)存。也就是說,new運(yùn)算符和delete運(yùn)算符最好能成對使用。

指針的初始化可以在程序的任何位置進(jìn)行,<當(dāng)然,最好在使用它之前初始化。>比如:

float x = 0.254;
float *px;
//
其它語句,請注意不要在這里使用px指針

px = &x; //
在這進(jìn)行px指針的初始化工作

上面最后一行代碼是將變量x的地址賦值給指針px。以上初始化指針的方法效率相差無幾,讀者可自行分析。&運(yùn)算符稍后討論。

下面看一個ObjectARX程序中最為普通的使用指針的代碼段:(注意,以下不是完整的代碼,不能進(jìn)行編譯或執(zhí)行。)

void Sample(void)
{
//
聲明指針變量同時調(diào)用AcDbLine類的構(gòu)造函數(shù)進(jìn)行初始化。

//
注意此時使用了new運(yùn)算符為AcDbLine類對象分配內(nèi)存。
AcDbLine *pLine = new AcDbLine(AcGePoint3d(10, 20, 0) ,
AcGePoint3d(50, 75, 0));

//
下面看看如何訪問指針變量及復(fù)雜類的接口函數(shù)。
pLine->setColorIndex(1); //
將線對象的顏色設(shè)置為紅色

//layer()
函數(shù)返回一個指向char類型的指針,先聲明一個指針變量用于接收返回值
char *pLayerName;
pLayerName = pLine->layer(); 
acutPrintf(
\n紅色的線對象在%s圖層上。”, pLayerName);
}

這段代碼不作深入分析,請讀者注意pLine指針的聲明和初始化過程以及pLayerName指針的賦值過程。

注意到我們在上面初始化px指針時使用了&運(yùn)算符,即取地址運(yùn)算符,這也是使用引用的一般方法之一。引用是C++概念,C++初學(xué)者容易將引用和指針混淆在一起。

以下代碼中,m就是n的一個引用:

int n;
int &m = n;

編譯程序編譯以上代碼時,在標(biāo)識符表中添加一個int引用類型的標(biāo)識符m,它使用與標(biāo)識符n相同的內(nèi)存位置。這樣對m的任何操作實(shí)際上就是對n的操作,反之亦然。注意,m既不是n的拷貝,(這樣的話,內(nèi)存中應(yīng)該的兩塊不同的區(qū)域,存放著完全相同的內(nèi)容。),也不是指向n的指針,其實(shí)m就是n本身,只不過使用了另外一個名稱而已。

盡管指針和引用都是利用內(nèi)存地址來使用變量,它們之間還是有本質(zhì)的區(qū)別:

首先,指針變量(包括函數(shù)調(diào)用時的臨時指針變量)在編譯和運(yùn)行時要分配相當(dāng)于一個int變量的內(nèi)存空間以存放指針變量的值,盡管這個值表示的是指針指向的變量的地址。而引用與普通變量一樣,標(biāo)識符所指示的內(nèi)存位置就是變量存放位置。這樣不僅不需要在內(nèi)存中分配一個int變量的內(nèi)存空間(盡管它可能微不足道),而且在使用中可以少一次內(nèi)存訪問。<僅就內(nèi)存使用效率而言,指針和引用所帶來的區(qū)別確實(shí)不大,完全可以不去在意它。>

其次,由于標(biāo)識符表在填寫后就不能再被修改,因此引用在創(chuàng)建就必須初始化,并且初始化后,不能改變引用的關(guān)系。另外,引用初始化時,系統(tǒng)不提供默認(rèn)設(shè)置,引用必須與合法的內(nèi)存位置相關(guān)聯(lián)。而這些特征對于指針而言都是不存在的。指針可以在程序任何時刻初始化,初始化的指針在程序中也可以根據(jù)需要隨時改變所指向的對象,(這只需要改寫指針變量的值就可以了。)當(dāng)然,未初始化的指針變量系統(tǒng)會初始化為NULL,而NULL引用是非法的。

下面看一段類似文字游戲的程序:

int I = 6;
int J = 8;
int &K = I; //K
I的引用

K = J; //K
I的值都變成了8

注意,由于引用關(guān)系不能被修改,語句K = J;并不能將K修改為對J的引用,只是修改了K的值。實(shí)際上,聲明并初始化引用后,可以把引用當(dāng)作普通變量來使用,只不過在操作時會影響另外一個變量。

以上代碼僅僅只是解釋引用的定義,并不能體現(xiàn)引用的價值。引用的主要功能在于函數(shù)的參數(shù)(或者返回值)的傳遞。

注:下圖應(yīng)該是float *px = &x ;

3、 函數(shù)參數(shù)的指針和引用傳遞機(jī)制

先看一下簡單的例子。

void Func1(int x) //這個函數(shù)的參數(shù)使用值傳遞方式
{
  x = x + 10;
}
//
當(dāng)參數(shù)類型更復(fù)雜時,指針和引用傳遞方式在效率等方面的優(yōu)勢更為明顯
//
不過那樣例子就不夠“簡單”了
void Func2(int *x) //
這個函數(shù)的參數(shù)使用指針傳遞方式
{
  *x = *x + 10;
}

void Func3(int &x) //
這個函數(shù)的參數(shù)使用引用傳遞方式
{
  x = x + 10;
}

以下代碼調(diào)用這些函數(shù):

int n = 0;
Func1(n);
acutPrintf(
n = %d
, n); // n = 0
Func2(&n);
acutPrintf(
n = %d
, n); //n = 10
Func3(n);
acutPrintf(
n = %d, n); //n = 20

以上代碼段中,當(dāng)程序調(diào)用Func1()函數(shù)時,首先在棧(Stack)內(nèi)分配一塊內(nèi)存用于復(fù)制變量n。若變量n的類型復(fù)雜,甚至重載了該類的默認(rèn)拷貝構(gòu)造函數(shù):

CMyClass(const CMyClass &obj);

這個過程可能會比較復(fù)雜。<類的默認(rèn)拷貝構(gòu)造函數(shù)使用“位拷貝”而非“值拷貝”,若類中包括指針成員,不重載該函數(shù)幾乎注定程序會出錯。關(guān)于這個問題以后再深入探討。>

程序進(jìn)入函數(shù)Func1()體內(nèi)后,操作的是棧中的臨時變量,當(dāng)函數(shù)結(jié)束(或者說返回)時,棧內(nèi)變量被釋放。而對于函數(shù)Func1()來說的外部變量n并未起任何變化,因此隨后的acutPrintf函數(shù)將輸出n = 0

程序調(diào)用函數(shù)Func2()時,在棧內(nèi)分配內(nèi)存用于存放臨時的指針變量x。然后用&運(yùn)算取得變量n的地址,并拷貝給臨時指針變量x作為x的值。此時,指針x就成了指向變量n的指針。在函數(shù)體內(nèi),*x運(yùn)算得到的是指針x指向的內(nèi)容,即變量n。對*x操作實(shí)際上就是對n操作。因此,在函數(shù)Func2()中變量n的值起了變化。在分析Func2()函數(shù)時應(yīng)該注意到,臨時指針變量x要指向的內(nèi)存地址,也就是說變量x的“值”仍然是采用了值傳遞方式從函數(shù)外部(或者說函數(shù)調(diào)用者)獲得,那么“值”也就應(yīng)該具有值傳遞方式的特點(diǎn),它要在棧中復(fù)制臨時變量,它在函數(shù)體內(nèi)被修改不會影響到函數(shù)外部。比如說,在上面的代碼段中,函數(shù)Func2()內(nèi)可以讓指針x指向另外的變量,但函數(shù)結(jié)束或返回后,在函數(shù)外部是無法得到這樣的指向另外變量的指針。

程序調(diào)用函數(shù)Func3()時,臨時變量x是一個變量n的引用,此時變量x就是變量n本身,對x操作的同時,外部變量n也起了變化。實(shí)際上,引用能做的事,指針也能做到。

以上的代碼段確實(shí)簡單,以至還不能充分顯示指針和引用在傳遞函數(shù)參數(shù)時的許多其他功能。下面我們設(shè)計這樣一個函數(shù),函數(shù)需要兩個參數(shù),在函數(shù)內(nèi)將兩個參數(shù)的值互換。由于值傳遞方式盡管能通過返回值賦值的方法修改一個參數(shù)值,但不能同時修改兩個參數(shù)值,因此這個函數(shù)不能使用值傳遞方式。使用指針傳遞方式,函數(shù)可以寫成這樣:

bool swap(int *x, int *y)
{
  int temp;
  temp = *x;
  *x = *y;
  *y = temp;
  return true;
}

以下代碼調(diào)用該函數(shù):

/*原文如此

int *a = 10;
int *b = 15;

*/

int a1 = 10 ;

int b1 =15 ;

int *a = &a1 ;

int *b = &b1 ;
if (swap(a, b))
{
  acutPrintf(
“整數(shù)a1,b1已交換數(shù)據(jù),*a = %d, *b = %d
, *a, *b);
}

在以上代碼中,swap()函數(shù)設(shè)計成與常見的ARX函數(shù)一致的風(fēng)格,用一個bool類型返回函數(shù)執(zhí)行狀態(tài)。<ARX中,這個返回值通常使用Acad::ErrorStatus類。>在調(diào)用函數(shù)時,由于變量ab已經(jīng)聲明為指針,使用標(biāo)識符ab訪問的是int類型變量的內(nèi)存地址。

使用引用傳遞參數(shù),可以這樣設(shè)計swap()函數(shù):

bool swap(int &x, int &y)
{
int temp;
temp = x;
x = y;
y = temp;
return true;
}

使用代碼swap(int a, int b)調(diào)用以上函數(shù)時,進(jìn)入函數(shù)體內(nèi),xy分別是變量a、b的引用,對x、y操作就是操作變量a、b。函數(shù)返回后,變量ab的值互相交換了。

注意:以上代碼只是交換兩個變量(或者指針指向的變量)的值。即將變量a、b(或指針a、b指向的變量)的修改為b、a(或指針b、a指向的變量)的值,而不是將指針a指向原來指針b指向的變量。也就是說,swap()函數(shù)調(diào)用前后,指針ab的值(地址)并沒有發(fā)生任何變化。(當(dāng)然,引用關(guān)系在任何時候都不能修改。)要修改指針的地址值,應(yīng)該使用指向指針的指針或者使用對指針的引用。這樣設(shè)計和調(diào)用函數(shù):

bool swap(int **x, int **y); //使用指向指針的指針傳遞參數(shù)
int *a = 10;//
原文如此,不可
int *b = 15;// //
原文如此,不可
swap(&a, &b);

或者:

bool swap(int *&x, int *&y); //使用對指針的引用傳遞參數(shù)
int *a = 10; //
原文如此,不可
int *b = 15; //
原文如此,不可
swap(a,b);

在以上的兩個swap()函數(shù)以交換兩個指針的值,使指針a指向原來指針b指向的變量,指針b指向原來指針a指向的變量。
另外,由于引用關(guān)系不可修改,指向引用的指針和引用一個引用沒有實(shí)際意義。若編譯器允許它們存在,實(shí)際上也會退化為普通指針(或?qū)χ羔樀囊?/SPAN>)和引用。這一點(diǎn)請讀者自行分析。

最后,我們看一個ARX程序中使用指針和引用傳遞參數(shù)的函數(shù)例子:

AcDbDatabase *pDb = new AcDbDatabase();
AcDbBlockTable *pBlkTbl;
pDb->getBlockTable(pBlkTbl, AcDb::kForRead);

ARX幫助中可以查看到,getBlockTable()函數(shù)的原型是:

Acad::ErrorStatus getBlockTable( AcDbBlockTable*& pTable, AcDb::OpenMode mode);

其中可以看到,函數(shù)的第一個參數(shù)是對一個AcDbBlockTable類型指針的引用,從而可以在函數(shù)體內(nèi)部對指針pBlkTbl進(jìn)行修改,使之指向pDb指針指向的圖形數(shù)據(jù)庫的塊表

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多