C 中傳值呼叫和傳引用呼叫的理解

2021-09-21 19:50:28 字數 3878 閱讀 8410

驗證示例的**如下:

using

system;    

public

class

argsbyreforvalue    

static

void

changebyint(

inti)    

static

void

changebystruct(person_val p_val)    

static

void

changebyclass(person_ref p_ref)    

static

void

changebyclassref(

refperson_ref p)    

}    

public

struct

person_val    

public

class

person_ref    

執行結果如下:

看起來似乎上面**中實驗3實驗4是一樣的,即對於類(class)來說,不管加不加ref或out,都是傳引用呼叫。

其實,這只是表面的現象,只要稍微改一下**,結果就不一樣了。

修改上面**,再增加兩個實驗。

using

system;    

public

class

argsbyreforvalue    

static

void

changebyint(

inti)    

static

void

changebystruct(person_val p_val)    

static

void

changebyclass(person_ref p_ref)    

static

void

changebyclassref(

refperson_ref p)    

static

void

changebyclassnew(person_ref p_ref_new)    

static

void

changebyclassrefnew(

refperson_ref p_new)    

}    

public

struct

person_val    

public

class

person_ref    

則執行結果為:

實驗5的執行結果似乎說明即使引數是類(class),只要不加ref,也是傳值呼叫。

下面就引出了我的理解。

2. 沒有ref時,即使引數為引用型別(class)時,也可算是一種傳值呼叫

引數為引用型別時,傳遞的是該引用型別的位址的乙份拷貝,「該引用型別的位址的乙份拷貝」即為傳值呼叫的「值」。

注意這裡說傳遞的是該引用型別的位址的乙份拷貝,而不是引用型別的位址。

下面將用圖的形式來說明以上實驗3,實驗5和實驗6中記憶體的情況。

2.1 首先是實驗3

實驗3的記憶體圖如下,實參是函式changebyclass外的person_ref物件,形參是函式changebyclass內的person_ref物件。

從圖中我們可以看出實參new出來之後就在託管堆上分配了記憶體,並且在棧上儲存了物件的指標。

呼叫函式changebyclass後,由於沒有ref引數,所以將棧上的實參p_val拷貝了乙份作為形參,注意這裡p_val(實參)p_val(形參)是指向託管堆上的同一位址。

所以說沒有ref時,即使引數為引用型別(class)時,也可算是一種傳值呼叫,這裡的值就是託管堆中物件的位址(0x1000)。

呼叫函式changebyclass後,通過p_val(形參)修改了name屬性的值,由於p_val(實參)p_val(形參)是指向託管堆上的同一位址,所以函式外的p_val(實參)的name屬性也被修改了。

2.2 然後是實驗5

上面的實驗3從執行結果來看似乎是傳引用呼叫,因為形參的改變導致了實參的改變。

下面的實驗5就可以看出,p_val(形參)p_val(實參)並不是同乙個變數,而是p_val(實參)的乙個拷貝。

從圖中可以看出第一步還是和實驗3一樣,但是在呼叫函式changebyclassnew後,就不一樣了。

函式changebyclassnew中,對p_val(形參)重新分配了記憶體(new操作),使其指向了新的位址(0x1100),如下圖:

所以p_val(形參)的name屬性改了時候,p_val(實參)的name屬性還是沒變。

2.3 最後是實驗6

我覺得實驗6是真正的傳引用呼叫。不廢話了,直接上第乙個圖。

引數中加了ref關鍵字之後,其實傳遞的不是託管堆中物件的位址(0x1000),而是棧上p_val(實參)的位址(0x0001)。

所以這裡實參和形參都是棧上的同乙個東西,沒有什麼區別了。我覺得這才是真正的傳引用呼叫。

然後呼叫了函式changebyclassrefnew,函式中對p_val(形參)重新分配了記憶體(new操作),使其指向了新的位址(0x1100)。

由於p_val(形參)就是p_val(實參),所以p_val(形參)的name屬性改變後,函式changebyclassrefnew外的p_val(實參)的name屬性也被改變了。

而原先分配的物件(位址0x1000)其實已經沒有被引用了,隨時會被gc**。

3. 結論

如果呼叫的函式中對引數重新進行了位址分配(new操作),那麼執行結果類似傳值呼叫

如果呼叫的函式中沒有對引數重新進行了位址分配,直接就是使用了傳遞的引數,那麼執行結果類似傳引用呼叫

深刻理解C 的傳值呼叫和傳引用呼叫

值呼叫和傳引用呼叫是幾乎所有主流語言都會涉及到的問題,下面我談談我對c 中傳值呼叫和傳引用呼叫的理解。1.一般對c 中傳值呼叫和傳引用呼叫的理解 如果傳遞的引數是基元型別 int,float等 或結構體 struct 那麼就是傳值呼叫。如果傳遞的引數是類 class 那麼就是傳引用呼叫。如果傳遞的引...

傳值呼叫和引用呼叫

值呼叫是指當發生函式呼叫時候,給形參分配記憶體空間,並用實參來初始化形參 直接將實參的值傳遞給形參 這一過程是引數值的單向傳遞過程,一旦形參獲得了值,便於實參脫離了關係,此後無論形參發生了什麼變化,都不影響實參了.引用呼叫將引用作為形參,在執行主調函式中的呼叫語句時候,系統自動用實參來初始化形參.這...

引用呼叫和傳值呼叫

1.傳值呼叫又分為資料傳值呼叫和位址傳值呼叫。資料傳值呼叫方式是將實參的資料值傳遞給形參。實參和形參在棧空間內的位址不相同,改變形參值不影響實參值 位址傳值呼叫方式是將實參的位址值傳遞給形參,實參和形參在棧空間內共用同一位址,改變形參值就可改變實參值。2.引用呼叫是將實參變數值傳遞給形參,而形參是實...