天天看點

傳值與傳位址的差別

傳值, 

是把實參的值指派給行參 

那麼對行參的修改,不會影響實參的值 

傳位址 

是傳值的一種特殊方式,隻是他傳遞的是位址,不是普通的如int 

那麼傳位址以後,實參和行參都指向同一個

對象

傳引用 

真正的以位址的方式傳遞參數 

傳遞以後,行參和實參都是同一個對象,隻是他們名字不同而已 

對行參的修改将影響實參的值

-----------------------------------------------------------------------------------

覺得從函數調用的角度了解比較好 

傳值: 

函數參數壓棧的是參數的副本。 

任何的修改是在副本上作用,沒有作用在原來的變量上。 

傳指針: 

壓棧的是指針變量的副本。 

當你對指針解指針操作時,其值是指向原來的那個變量,是以對原來變量操作。 

傳引用: 

壓棧的是引用的副本。由于引用是指向某個變量的,對引用的操作其實就是對他指向的變量的操作。(作用和傳指針一樣,隻是引用少了解指針的草紙)

函數參數傳遞機制的基本理論 

  函數參數傳遞機制問題在本質上是調用函數(過程)和被調用函數(過程)在調用發生時進行通信的

方法

問題。基本的參數傳遞機制有兩種:值傳遞和引用傳遞。以下讨論稱調用其他函數的函數為主調函數,被調用的函數為被調函數。 

  值傳遞(passl-by-value)過程中,被調函數的形式參數作為被調函數的局部變量處理,即在堆棧中開辟了記憶體空間以存放由主調函數放進來的實參的值,進而成為了實參的一個副本。值傳遞的特點是被調函數對形式參數的任何操作都是作為局部變量進行,不會影響主調函數的實參變量的值。 

  引用傳遞(pass-by-reference)過程中,被調函數的形式參數雖然也作為局部變量在堆棧中開辟了記憶體空間,但是這時存放的是由主調函數放進來的實參變量的位址。被調函數對形參的任何操作都被處理成間接尋址,即通過堆棧中存放的位址通路主調函數中的實參變量。正因為如此,被調函數對形參做的任何操作都影響了主調函數中的 

實參變量。  

僅讨論一下值傳遞和引用: 

所謂值傳遞,就是說僅将對象的值傳遞給目标對象,就相當于copy;系統将為目标對象重新開辟一個完全相同的記憶體空間。 

所謂引用,就是說将對象在記憶體中的位址傳遞給目标對象,就相當于使目标對象和原始對象對應同一個記憶體存儲空間。此時,如果對目标對象進行修改,記憶體中的資料也會改變。

參數傳值與傳址

2008年11月11日 星期二 10:52 A.M.

參數是調用函數的代碼,傳給函數的資料,在C,C++中,參數有兩種傳遞方式:傳值方式(它是程式中最常見的傳遞參數的方法)和傳址方式(函數對參數的操作,将直接改變實參的值)。這兩個名詞分别指:傳遞“參數的值”和傳遞“參數的位址”。
傳值與傳位址的差別
傳值與傳位址的差別

“參數的傳遞方式”,“參數的傳遞過程”,方式和過程有何差別?中學時我對前桌的女生“有意思”,想給人家傳遞點資訊,是往她家打個電話呢?還是來個“小紙條”?這就是“傳遞方式”的不同。我選擇了後者。至于傳遞過程:剛開始時我把紙條裹在她的頭發裡,下課時假裝關心地“喂,你的頭發裡掉了張紙……”。後來大家熟了,上課時我輕輕動一下她的後背,她就會不自在,然後在一個合适時機,自動把手别過來取走桌沿的紙條……這就是傳遞過程的不同吧?(以上故事純屬虛構)

程式是在記憶體裡運作的。是以無論參數以哪一種方式傳遞,都是在記憶體中“傳來傳去”。在一個程式運作時,程式會專門為參數開辟一個記憶體空間,稱為“棧”。棧所在記憶體空間位于整個程式所占記憶體的頂部(為了直覺,我們将位址較小的記憶體畫在示意圖頂部,如果依照記憶體位址由下而上遞增規則,則棧區應該在底部),如圖:

傳值與傳位址的差別

當程式需要傳遞參數時,将一個個參數“壓入”棧區記憶體的底部,然後,函數再從棧區一個個讀出參數。

如果一個函數需要傳回值,那麼調用者首先需要在棧區留出一個大小正好可以存儲傳回值的記憶體空間,然後再執行參數的入棧操作。

假設有一函數:int AddTwoNum(int n1, int n2)     然後在代碼某處調用:

....

int a = 1;

int b = 2;

int c = AddTwoNum(a,b);

當執行上面黑體部分,即調用函數的動作發生時,棧區出現下面的操作:

傳值與傳位址的差別

圖中标明為傳回值預留的空間大小是4個位元組,當然不是每個函數都這個大小。它由函數傳回值的資料類型決定,本函數AddTwoNum傳回值是int類型,是以為4個位元組。其它的a,b參數也是int類型,是以同樣各占4位元組大小的記憶體空間。

至于參數是a還是b先入棧,這依編譯器而定,大都數編譯器采用“從右到左的次序”将參數一個個壓入。是以本示意圖,參數b被先“壓”入在底部,然後才是a。這樣就完成了參數的入棧過程。根據前面講的不同“傳遞方式”,被實際壓入棧的資料也就不同。

一、如果是“傳值”,則棧中的a,b就是“複制品”,對二者的操作,僅僅是改變此處棧區的記憶體,和調用處的實參:a,b毫不關聯:

傳值與傳位址的差別
二、而在“傳址”方式時,編譯器會将調用處的a,b的記憶體位址寫入棧區,并且将函數中所有對該棧區記憶體的操作,都轉向調用處a,b的記憶體位址。請看:
傳值與傳位址的差別

看起來二的圖比一要複雜得多。其實實質的差別并不多。

在一圖中,傳給函數的是a,b的值,即1,2;

在二圖中,傳給函數的是a,b的位址,即:00129980,00129984。

“參數的傳遞過程”說到最後,還是和“參數的傳遞方式”糾纏在一起。我個人認為,在剛開始學習C++時,并不需要--或者甚至就是最好不要--去太糾纏語言内部實作的機制,而重在于運用。下面我們就來舉一個使用“傳址”方式的例子。

題目是:寫一函數,實作将兩個整型變量的值互換。

幸好實作它也非常的簡單和直覺。典型的方法是使用“第三者”你可能感到不解:交換兩個變量的值,就讓這兩個變量自個互換就得了,比如小明有個蘋果,小光有個梨子,兩人你給我給你就好了啊,要小兵來做什麼?

呵,你看吧:

int a = 1, b = 2;

//不要“第三者”的交換(失敗)

a = b;

b = a;

好好看看,好好想想吧。當執行交換的第一句:a = b;時,看去工作得不錯,a的值确實由1變成了2。然後再下去呢?等輪到b想要得到a的值時,a現在和b其實相等,都是2,結果b=a;後,b的值還是2.沒變。

隻好讓“第三者”插足了……反正程式沒有婚姻法。

int a = 1, b =2;

int c ; //“第三者”

//交換開始:

c = a;

b = c;