引用傳遞和值傳遞的區別

2021-06-03 00:53:50 字數 2854 閱讀 7025

有這麼一道面試題,題目如下:

view plain

using

system;  

public

class

test1  

,", p.name, num);  

}  static

void

a1(person p, 

intnum)  

}  public

class

person  

}  說說上面的程式產生的結果,以及產生這個結果的原因是什麼?

我在以前過過一篇關於引用傳遞和值傳遞的部落格,位址如下:

今天再就上面的面試題說一說,一方面鞏固自己,另一方面方便心裡沒底的面試者徹底了解;

首先我們得清楚,在c#中,資料型別分為引用型別和值型別,值型別儲存在堆疊中,引用型別稍微複雜點,引用型別分為兩部分儲存,引用型別的值儲存在託管堆中,對該值的引用儲存在堆疊中,值和值引用構成了乙個完整的引用型別變數;我們經常使用下面的語法宣告變數:

view plain

inti=0;  

string

str = 

"new string"

;  

在i的宣告過程中,系統做了兩件事情,一件事情是在記憶體的堆疊中找到乙個4位元組的位置(int型別的長度為4位元組),轉換成**應該這麼表示:int i= new int();第二件事情是將0賦予i,轉換成**應該這麼表示:i=0;綜合下來實際**應該如下所示:

view plain

inti=

newint

();  

i=0;  

在str的宣告過程中,系統也是做了兩件事情,只不過兩件事情的手段不一致,第一件事情是在記憶體中找了兩個地方,乙個地方在託管堆中,用於儲存str的值,另外乙個地方在堆疊中,用於指向託管堆的儲存位置;轉換成**也是一句話:string str=new string();第二件事也是將new sting這個字串賦予變數值,但是new string是記錄在託管堆中的,這是與值型別的區別,轉換成**應該這麼表示:str=「new string」;綜合下來**是一樣的,但是在分配記憶體時存在的差異就比較大了:

view plain

string

str=

newstriing();  

str="new string"

;  

弄清楚了值型別和引用在記憶體中的儲存方式,我們再來看看方法的引數傳遞,在c#中,所有的引數都是通過值來傳遞的,被呼叫的方法得到的都是該值的副本;這裡一定要注意:被呼叫的方法得到的都是該值的副本,也就是說,我們看下面這個方法:

view plain

public

void

methdouble(

inti)    

下面我們在程式中呼叫該方法,**如下:

int i=3;

methdouble(i);

在以上的**中,系統做了如下事情:首先將變數在記憶體堆疊中copy乙個副本,這個副本的變數名我們假設稱為copy_i,得到副本後,再將副本copy_i傳遞給方法methdouble執行;所以在以上的過程中,methdouble方法內部所做的任何事情都不會對變數i產生任何影響;我們再來看看下面的方法:

view plain

"white-space:pre"

>    

public

void

strdouble(

string

str)    

下面我們在程式中呼叫該方法,**如下:

view plain

string

str = 

"mystring"

;  strdouble(str);  

同理,在以上的**中,系統做了如下事情:首先將str在堆疊中的值引用變數copy乙個副本,這個副本變數名我們假設稱為copy_str,這個副本是乙個引用,該引用指向的位址就是str引用指向的託管堆的位址,也就是託管堆中「mystring」值,得到副本後,再將副本copy_str傳遞給方法執行,所以在操作過程中,方法對副本所做的修改都會直接修改託管堆中的值,從而影響方法外的str變數;

明白了以上的原理,我們再來看看開篇的面試題:

view plain

intnum = 0;  

person p = new

person(

"li"

);  

宣告了值型別變數num,引用型別變數p;

view plain

a1(p, num);  

將num的副本和p的引用副本傳遞給方法;

這裡我們可能有疑問了,p的引用傳遞進去了,那麼對p所做的修改應該會影響託管堆中的值啊,我們這裡看看方法a1方法的實現

view plain

static

void

a1(person p, 

intnum)    

view plain

static

void

a1(person person, 

intnum)    

沒改之前的方法裡面一句p=new person("wang");大家就以為p在堆疊中的值改變了,其實不然,p僅僅是乙個堆疊中的副本,在方法a1中,是用了p=new person("wang"),此時系統做了兩件事情:一件是在託管堆中找乙個地方,用於儲存p(實際上是下面方法的person)的值,然後將a1方法中的p引用指向該堆疊的位置,此時對a1方法的p所做的任何修改都是在修改第一件事情中找到的託管堆,因為a1方法中的引用指向更改了,所以主函式內的變數p此時指向的託管堆與a1方法內p指向的託管堆分別為不同的位置;所以此時a1方法所做的任何事情對主函式內的變數p都不會造成影響;

所以面試題的結果應該為:li,0

值傳遞和引用傳遞的區別

以值傳遞引數 當實參當作值來傳遞時,就產生了乙個新的拷貝。class test x static void fo int p p p 1 console.writeline p p 程式執行結果為 p 9,x 8 即x的值不會受p影響,給p賦乙個新值並不會改變x的內容,因為p和x存在於記憶體中不同的...

值傳遞和引用傳遞的區別

public class test 執行 得到的當前的結果如下 int1 10int2 10改變之後 int1 10int2 20process finished with exit code 0根據結果會發現int型別的傳遞,當int2值改變的時候,int1的值是沒有任何變化的,所以基本型別都是根...

值傳遞和引用傳遞的區別

值傳遞 值傳遞是指在呼叫函式時將實際引數複製乙份傳遞到函式中,這樣在函式中如果對引數進行修改,將不會影響到實際引數。引用傳遞 引用傳遞是指在呼叫函式時將實際引數的位址傳遞到函式中,那麼在函式中對引數所進行的修改,將影響到實際引數。陣列作為方法引數傳遞時,傳遞的引數是陣列記憶體的位址.陣列作為方法的返...