1. 程式人生 > >C++中指標和引用的區別、以及引用和取地址符&的區別

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");
}