C++中指標和引用的區別、以及引用和取地址符&的區別
一. 指標和引用的區別
對於指標來說,它是一個地址,這個地址是一個數值,那麼就意味這個數值可以為0(空指標),也可以為其他,即指標可以不指向任何東西。
而對於引用來說,他是一個外號,外號一定是“某個存在物體”的外號,所以引用不能為空,即不能存在空引用。例如我們給小明起了個外號:明明,那我們說明明的時候,就是說小明。對引用的操作與對變數直接操作完全一樣。
根據以上可知指標和引用的一個重要不同:指標可以為空,引用不能為空。這就意味著我們拿到一個引用的時候,是不需要判斷引用是否為空的,而拿到一個指標的時候,我們則需要判斷它是否為空。這點經常在判斷函式引數是否有效的時候使用。
例如:
void fun1(int *point) { // 為了程式碼的穩健和安全,我們需要判斷指標是否有效,通常做法是判斷指標是否為 // 空,其他的判斷就需要根據函式的具體功能來判斷了 if(!point) { return; } // 函式實現 } void fun2(int &refence) { // 在這裡,我們就不用擔心refence是否為空 }
引用修飾函式引數還可以提高效率,例子如下:
Class Object
{// 實現省略,只需要知道我們在這裡聲明瞭一個類,在下面我們要將這個類的物件作為
// 函式引數型別來使用};
void fun1(Object obj)
{
// 此函式宣告中,obj是值傳遞,會產生一個臨時物件
}
void fun2(Object &obj)
{
// 我們不用檢查obj是否為空,同時,使用引用傳遞,可以避免臨時物件
}
void fun3(Object* obj)
{
if(!obj)...
// 需要檢查obj是否為空,同時,可以避免臨時物件
}
我們根據前面的描述,還可以知道指標可以多次賦值,即在某時刻可以指向地址1,換個時候可以指向地址2,例如:
int a = 0;
int b = 1;
int *point = NULL;
point = &a; // 在某個時刻,指標可以指向a
point = &b; // 換個時刻,指標可以指向b
而引用則不同,引用只能在初始化的時候就賦好值,之後就不能改變了,用外號的例子來說就是"明明"這個外號在出現的時候就是代指小明,之後“明明”這個外號就綁在小明身上了,它不能過段時間換成小暗的外號。對reference_mingming(不是&reference_mingming)的操作,就是對xiaoming的操作。程式碼如下:
int xiaoming = 1; int &refence_mingming = xiaoming; int xiaoan = 2; refence_mingming = xiaoan; // error,引用不能換了
由以上可以,當我們需要某個是否指向為空的時候,我們就需要使用指標了,還有指向的物件需要變化的時候,我們也需要使用指標。其他地方一般推薦引用。
更多內容可以參見<more effective C++>第一條:引用和指標的區別。
二. 取地址符&和引用的關鍵字的區別:
作引用的關鍵字時:
型別名 & 別名 = var;
1.定義的時候必須初始化,即& 前面有類名或型別名,&別名後面一定帶 “=” (在= 左邊);
2.&後面的別名是新的名字,之前不存在。
3. 引用在使用的時候,只用別名,不再使用&,也就是說對於一個引用,其關鍵字&只出現一次(在定義的時候)。
4.C++中“引用”的概念就是要作為物件的別名,儘管其自身也會佔用記憶體(此處不同意匿名使用者,引用最終會被編譯為指標,因此佔用記憶體),但作為物件別名,它要擁有物件本身所有的功能,因此取地址時,取的是物件的地址而不是自己的地址——C++就是這樣設計的,要不然很多事情你都幹不了.
5.對引用的操作與對變數直接操作完全一樣,則對引用的取地址操作,等同於對變數的取地址,如下圖中所示cout<<&c和cout<<&a是一樣的。這個不太好理解(c本身也應該有地址吧,這是C++規定的),“&引用” 和“&取地址符”是一樣的。
&取地址時:
如果&是取址運算子,也就意味著取一個變數的地址並付給指標變數。&後面緊跟的是變數(已存在);
所以依據&後面的變數名是否已經存在,也很容易判斷是引用還是取地址符。
下面給出一個例子來說明引用和指標的區別,以及引用的地址的問題。
int a=1;
int &c=a;
int *b=&a;
int main()
{
cout<<c<<endl; //此時的c就是a,輸出1
cout<<&c<<endl; //輸出的是c的儲存地址也就是a的地址
cout<<&a<<endl; //和cout<<&c<<endl;和上一個程式碼一樣
cout<<*&c<<endl; //*直接取這個地址的結果,也就是輸出1,也就是a也是c
cout<<b<<endl; //b是指標,指向的是a的地址,輸出就是a的地址
cout<<*b<<endl; //指標指向地址裡面結果,也就是輸出1咯
system("pause");
}