深入剖析C C 函式的引數傳遞機制

2021-06-10 05:10:32 字數 3763 閱讀 2810

先看一下簡單的例子。

void func1(int x) //

這個函式的引數使用值傳遞方式

//當引數型別更複雜時,指標和引用傳遞方式在效率等方面的優勢更為明顯

//不過那樣例子就不夠「簡單」了

void func2(int *x) //

這個函式的引數使用指標傳遞方式

void func3(int &x) //

這個函式的引數使用引用傳遞方式

以下**呼叫這些函式:

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

以上**段中,當程式呼叫

func1()

函式時,首先在棧

(stack)

內分配一塊記憶體用於複製變數

n。若變數

n的型別複雜,甚至過載了該類的預設拷貝建構函式:

cmyclass(const cmyclass &obj);

這個過程可能會比較複雜。

<

類的預設拷貝建構函式使用「位拷貝」而非「值拷貝」,若類中包括指標成員,不過載該函式幾乎注定程式會出錯。關於這個問題以後再深入**。

>

程式進入函式

func1()

體內後,操作的是棧中的臨時變數,當函式結束

(或者說返回

)時,棧內變數被釋放。而對於函式

func1()

來說的外部變數

n並未起任何變化,因此隨後的

acutprintf

函式將輸出

n = 0

。程式呼叫函式

func2()

時,在棧內分配記憶體用於存放臨時的指標變數

x。然後用

&運算取得變數

n的位址,並拷貝給臨時指標變數x作為

x的值。此時,指標

x就成了指向變數

n的指標。在函式體內,

*x運算得到的是指標

x指向的內容,即變數n。對

*x操作實際上就是對

n操作。因此,在函式

func2()

中變數n

的值起了變化。在分析

func2()

函式時應該注意到,臨時指標變數

x要指向的記憶體位址,也就是說變數

x的「值」仍然是採用了值傳遞方式從函式外部

(或者說函式呼叫者

)獲得,那麼「值」也就應該具有值傳遞方式的特點,它要在棧中複製臨時變數,它在函式體內被修改不會影響到函式外部。比如說,在上面的**段中,函式

func2()

內可以讓指標

x指向另外的變數,但函式結束或返回後,在函式外部是無法得到這樣的指向另外變數的指標。

程式呼叫函式

func3()

時,臨時變數

x是乙個變數

n的引用,此時變數

x就是變數

n本身,對

x操作的同時,外部變數

n也起了變化。實際上,引用能做的事,指標也能做到。

以上的**段確實簡單,以至還不能充分顯示指標和引用在傳遞函式引數時的許多其他功能。下面我們設計這樣乙個函式,函式需要兩個引數,在函式內將兩個引數的值互換。由於值傳遞方式儘管能通過返回值賦值的方法修改乙個引數值,但不能同時修改兩個引數值,因此這個函式不能使用值傳遞方式。使用指標傳遞方式,函式可以寫成這樣:

bool swap(int *x, int *y)

以下**呼叫該函式:

/*原文如此

int *a = 10;

int *b = 15;

*/int a1 = 10 ;

int b1 =15 ;

int *a = &a1 ;

int *b = &b1 ;

if (swap(a, b))

在以上**中,

swap()

函式設計成與常見的

arx函式一致的風格,用乙個

bool

型別返回函式執行狀態。

<

在arx

中,這個返回值通常使用

acad::errorstatus

類。>

在呼叫函式時,由於變數a和

b已經宣告為指標,使用識別符號a和

b訪問的是

int型別變數的記憶體位址。

使用引用傳遞引數,可以這樣設計

swap()

函式:bool swap(int &x, int &y)

使用**

swap(int a, int b)

呼叫以上函式時,進入函式體內,x、

y分別是變數a、

b的引用,對x、

y操作就是操作變數a、

b。函式返回後,變數a、

b的值互相交換了。

注意:以上**只是交換兩個變數

(或者指標指向的變數

)的值。即將變數a、

b(或指標a、

b指向的變數

)的修改為b、

a(或指標b、

a指向的變數

)的值,而不是將指標

a指向原來指標

b指向的變數。也就是說,

swap()

函式呼叫前後,指標a和

b的值(位址

)並沒有發生任何變化。

(當然,引用關係在任何時候都不能修改。)

bool swap(int **x, int **y); //

使用指向指標的指標傳遞引數

int *a = 10;//

原文如此,不可

int *b = 15;// //

原文如此,不可

swap(&a, &b);

或者:bool swap(int *&x, int *&y); //

使用對指標的引用傳遞引數

int *a = 10; //

原文如此,不可

int *b = 15; //

原文如此,不可

swap(a,b);

在以上的兩個

swap()

函式以交換兩個指標的值,使指標

a指向原來指標

b指向的變數,指標

b指向原來指標

a指向的變數。

另外,由於引用關係不可修改,指向引用的指標和引用乙個引用沒有實際意義。若編譯器允許它們存在,實際上也會退化為普通指標

(或對指標的引用

)和引用。這一點請讀者自行分析。

最後,我們看乙個

arx程式中使用指標和引用傳遞引數的函式例子:

acdbdatabase *pdb = new acdbdatabase();

acdbblocktable *pblktbl;

pdb->getblocktable(pblktbl, acdb::kforread);

從arx

幫助中可以檢視到,

getblocktable()

函式的原型是:

acad::errorstatus getblocktable( acdbblocktable*& ptable, acdb::openmode mode);

其中可以看到,函式的第乙個引數是對乙個acdbblocktable型別指標的引用,從而可以在函式體內部對指標pblktbl進行修改,使之指向pdb指標指向的圖形資料庫的塊表

C C 函式引數傳遞機制

c c 的基本引數傳遞機制有兩種 值傳遞和引用傳遞,我們分別來看一下這兩種的區別。1 值傳遞過程中,需在堆疊中開闢記憶體空間以存放由主調函式放進來的實參的值,從而成為了實參的乙個副本。值傳遞的特點是被調函式對形參的任何操作都是作為區域性變數進行,不會影響主調函式的實參變數的值。2 引用傳遞過程中,被...

C C 中的函式引數傳遞機制

一 函式引數傳遞機制的基本理論 函式引數傳遞機制問題在本質上是呼叫函式 過程 和被呼叫函式 過程 在呼叫發生時進行通訊的方法問題。基本的引數傳遞機制有兩種 值傳遞和引用傳遞。以下討論稱呼叫其他函式的函式為主調函式,被呼叫的函式為被調函式。值傳遞 passl by value 過程中,被調函式的形式引...

C C 中的函式引數傳遞機制

一 函式引數傳遞機制的基本理論 函式引數傳遞機制問題在本質上是呼叫函式 過程 和被呼叫函式 過程 在呼叫發生時進行通訊的方法問題。基本的引數傳遞機制有兩種 值傳遞和引用傳遞。以下討論稱呼叫其他函式的函式為主調函式,被呼叫的函式為被調函式。值傳遞 passl by value 過程中,被調函式的形式引...