值 (value)、指標 (pointer/address)、參考 (reference)
前言
C 裡面其實只有值 (value) 和指標 (pointer),C++ 才增加了參考 (reference)。
C# 沒有指標 (pointer),有值 (value) 和參考 (reference)。
指標 (pointer/address)
就像是 int 只能儲存數字不能儲存字串一樣。指標,是一種變數的型別,只能用來儲存記憶體位址,也可以說是變數資料的地址。
指標 (pointer) 就是某變數的記憶體位址。而指標變數 (pointer variable),則是用來存放指標的變數。
a, b, p1, p2都是一般的變數,儲存在記憶體 (memory) 中。其中,p1 所儲存的值是 a 的記憶體 (memory) 位址,而 p2 則儲存 b 的記憶體位址,像這樣的狀況,我們就稱 p1 是一個指向 a 的指標,p2 是一個指向 b 的指標。
在 C/C++ 中,我們用下面的式子來表示這個關係:
1 | int a = 2, b = 5; |
符號*,代表的意義是指標。
int* p1 要由後往前閱讀來瞭解它的意義:p1 is a pointer points to an integer。p1是一個指標,指向整數。或是,p1 是一個儲存「整數記憶體位址」的變數。
符號&,稱為 address of (取址)。&a = address of a。
因此,int* p1 = &a;
這整行,我們可以看成:p1 is a pointer points to integer variable a,即:p1 是一個指標,指向整數變數 a。或是,p1 是一個儲存「整數變數 a 的記憶體位址」的變數。
但是我們有 p1 (a的地址) 可以做什麼呢?這時可以用「符號*」表示「取出內容」,這裡的「符號*」和宣告指標變數的 int* p1 的意義不一樣。
當我們在 C 中 printf(*p1);
時,代表取出「p1」的內容,也就是取出「a 的地址」的內容。可以把 *p1 當作 a 來使用,例子:
1 | //C |
宣告時「符號*」表示「宣告指標變數」。使用時「符號*」表示「取出內容」。
參考資料:
C語言: 超好懂的指標,初學者請進~
C/C++之指標 (pointer),參考 (reference) 觀念整理與常見問題 (轉貼)
參考 (reference)
參考,可以想像成是一個變數或物件的別名 (alias)。如同美國國父就是華盛頓一樣。取別名時一定要初始化,指明它是誰的別名。且初始化後不能再轉變成其他變數的別名。
在 C++ 中,我們用下面的式子來表示這個關係:
1 | //C++ |
C++ compiler 不會額外為 ref variables 分配記憶體空間。
配合指標時,「符號&」前面有 =,表示「取址」,如
int* p = &a;
「符號&」前面有資料型態,表示「參考、別名」,如int &r1 = a;
參考資料:
C++中引用(reference)的用法详解
指標和參考
1 | int a = 2, b = 5; |
Value types call/pass by value (C/C++/C#)
1 | int x = 5, y = 10; |
call by value:將 x, y 的值 copy 一份給 a, b。
swap() 執行完畢後 x, y 不會互換,a, b 會互換。
Value types call/pass by pointer/address (C/C++)
1 | int x = 5, y = 10; |
call by pointer/address:將 x, y 的位址 copy 一份給 a, b (a, b 是指標變數)。因為實際上是 copy,骨子裡是 call by value。
swap() 執行完畢後 x, y 會互換,a, b 不會互換。因為在 swap() 中操作 *a, *b 相當於操作 x, y。
Value types call/pass by reference (C++/C#)
1 | //C++ |
1 | //C# |
call by reference:為 x, y 取別名 a, b (取別名時一定要初始化,指明它是誰的別名)。C++ compiler 不會為 ref variables 分配內存空間。
swap() 執行完畢後 x, y 會互換。
參考資料:
Parameter passing in C#
總結
call by value、call by pointer/address 是 copy 複製一份變數的值或記憶體位址,傳入函式中操作。
call by reference 是直接取別名,直接操作該變數。