您的位置:首頁>正文

C|指標和引用的差別,及有了變數、指標,為什麼還需要引用

指標指向一塊記憶體, 它的內容是所指記憶體的位址;而引用則是某塊記憶體的別名, 引用初始化後不能改變指向。 使用時, 引用更加安全, 指針更加靈活。

1 非空區別

在任何情況下都不能使用指向空值的引用。 一個引用必須總是指向某些物件。 因此如果你使用一個變數並讓它指向一個物件, 但是該變數在某些時候也可能不指向任何物件, 這時你應該把變數聲明為指標, 因為這樣你可以賦空值給該變數。 相反, 如果變數肯定指向一個物件, 例如你的設計不允許變數為空, 這時你就可以把變數聲明為引用。

不存在指向空值的引用這個事實意味著引用的代碼效率比使用指標高。 (引用和指標指向一個物件時, 引用的創建和銷毀不會調用類的拷貝構造函數和析構函數。 delete一個指標會調用該物件的析構函數, 注意防止二次析構。 )

2 可修改區別

指標可以被重新賦值以指向另一個不同的物件。 但是引用則總是指向在初始化時被指定的物件, 以後不能改變, 但是指定的物件其內容可以改變。

3 合法性區別

在使用引用之前不需要測試它的合法性。 相反, 指標則應該總是被測試, 防止其為空。 引用必須初始化, 指標可以不必初始化。

4 引用、指針與const。

存在常量指標和常量引用指標, 表示指向的物件是常量, 不能通過指標或者常量修改常量;存在指標常量,

不存在引用常量, 因為引用本身不能修改指向的特性和與指標常量的特性相同, 不需要引用常量。

5 應用區別

總的來說, 在以下情況下應該使用指標:一是考慮到存在不指向任何物件的可能(在這種情況下, 能夠設置指標為空), 二是需要能夠在不同的時刻指向不同的物件(在這種情況下, 你能改變指標的指向)。 如果總是指向一個物件並且一旦指向一個物件後就不會改變指向, 那麼應該使用引用。

6 其它區別

函數參數傳遞時使用指標或者引用的效果是相同的, 都是簡潔操作主調函數中的相關變數, 當時引用會更加的安全, 因為指標一些修改指向, 將不能影響主調函數中的相關變數。

所以參數傳遞時盡可能使用引用。 這也是引用之所以被引入的厚因。 雖然引用只是變數的一個別名, 但在函數的參數傳遞中, 變數只能傳值, 而引用卻可以傳址且比指標更簡潔。

sizeof引用的時候是物件的大小, sizeof指標是指標本身的大小;

指標和引用的自增(++)運算意義不一樣;

引用使用時無需解引用(*), 指標需要解引用;

在重載操作符並為防止不必要的語義誤解時, 通常使用引用;

7 代碼說明

int a,b,*p,&r=a; //正確

r=3; //正確:等價於a=3

int &rr; //出錯:引用必須初始化

p=&a; //正確:p中存儲a的位址, 即p指向a

*p=4; //正確:p中存的是a的位址, 對a所對應的存儲空間存入值4

p=&b; //正確:p可以多次賦值, p存儲b的位址

通俗化說明

在C和C++中, 指標一般指的是某塊記憶體的位址, 通過這個位址, 我們可以定址到這塊記憶體;而引用是一個變數的別名,

例如我們給小明起了個外號:明明, 那我們說明明的時候, 就是說小明。

對於指標來說, 它是一個位址, 這個位址是一個數值, 那麼就意味這個數值可以為0(空指標), 也可以為其他, 即指標可以不指向任何東西。

而對於引用來說, 他是一個外號, 外號一定是“某個存在物體”的外號, 所以引用不能為空, 即不能存在空引用。

根據以上可知指標和引用的一個重要不同:指標可以為空, 引用不能為空。 這就意味著我們拿到一個引用的時候, 是不需要判斷引用是否為空的, 而拿到一個指標的時候, 我們則需要判斷它是否為空。 這點經常在判斷函數參數是否有效的時候使用。

我們根據前面的描述,

還可以知道指標可以多次賦值, 即在某時刻可以指向位址1, 換個時候可以指向位址2, 例如:

int a = 0;

int b = 1;

int *point = NULL;

point = &a; // 在某個時刻, 指標可以指向a

point = &b; // 換個時刻, 指標可以指向b

而引用則不同, 引用只能在初始化的時候就賦好值, 之後就不能改變了, 用外號的例子來說就是"明明"這個外號在出現的時候就是代指小明, 之後“明明”這個外號就綁在小明身上了, 它不能過段時間換成小暗的外號。 代碼如下:

int xiaoming = 1;

int &refence_mingming = xiaoming;

int xiaoan = 2;

refence_mingming = xiaoan; // error,引用不能換了

由以上可以, 當我們需要某個是否指向為空的時候, 我們就需要使用指標了, 還有指向的物件需要變化的時候, 我們也需要使用指標。 其他地方一般推薦引用。

共同點

都是位址的概念, 指標與引用都是讓你間接引用其他物件;

指標指向一塊記憶體, 它的內容是所指記憶體的位址;而引用則是某塊記憶體的別名。

從物件的角度理解指標

C++primer中對 物件的定義:物件是指一塊能存儲資料並具有某種類型的記憶體空間

一個物件a,它有值和位址&a,運行程式時,電腦會為該物件分配存儲空間,來存儲該物件的值,我們通過該物件的位址,來訪問存儲空間中的值

指標p也是物件,它同樣有位址&p和存儲的值p,只不過,p存儲的資料類型是資料的位址。如果我們要以p中存儲的資料為位址,來訪問物件的值,則要在p前加解引用操作符"*",即*p。

物件有常量(const)和變數之分,既然指標本身是物件,那麼指標所存儲的位址也有常量和變數之分,常量指標是指,指標這個物件所存儲的位址是不可以改變的,而指向常量的指標的意思是,不能通過該指標來改變這個指標所指向的物件。

我們可以把引用理解成變數的別名。定義一個引用的時候,程式把該引用和它的初始值綁定在一起,而不是拷貝它。電腦必須在聲明r的同時就要對它初始化,並且,r一經聲明,就不可以再和其它物件綁定在一起了。

實際上,你也可以把引用看做是通過一個常量指標來實現的,它只能綁定到初始化它的物件上。

也可以理解引用是操作受限了的指標(僅容許取內容操作)。

引用的主要功能是傳遞函數的參數和返回值。

C++語言中,函數的參數和返回值的傳遞方式有三種:值傳遞、 指針傳遞和引用傳遞。

以下是“值傳遞”的示例程式:

void Func1(int x) {

x = x + 10;

}

int n = 0;

Func1(n);

cout << “n = ” << n << endl; // n = 0

由於Func1 函數體內的x 是外部變數n 的一份拷貝, 改變x 的值不會影響n, 所以n 的值仍然是0。

以下是“指標傳遞”的示例程式:

void Func2(int *x) {

(* x) = (* x) + 10;

}

int n = 0;

Func2(&n);

cout << “n = ” << n << endl; // n = 10

由於Func2 函數體內的x 是指向外部變數n 的指標,改變該指標的內容將導致n 的值改變,所以n 的值成為10。

以下是“引用傳遞”的示例程式:

void Func3(int &x) {

x = x + 10;

}

int n = 0;

Func3(n);

cout << “n = ” << n << endl; // n = 10

由於Func3 函數體內的x 是外部變數n 的引用,x 和n 是同一個東西,改變x 等於改變n,所以n 的值成為10。

所以,如果要修改當前被傳遞的參數的話,要麼加一級指針,要麼用引用。

對比上述三個示例程式,會發現“引用傳遞”的性質象“指標傳遞”,而書寫方式象 “值傳遞”。實際上“引用”可以做的任何事情“指標”也都能夠做,為什麼還要“引用” 這東西?

指標能夠毫無約束地操作記憶體中的如何東西,儘管指標功能強大,但是非常危險。

如果的確只需要借用一下某個物件的“別名”,那麼就用“引用”,而不要用“指針”。

無論你傳值還是傳指標,函數都會生成一個臨時變數,但傳引用時,不會生成臨時變數,當你傳值時,只可以引用值而不可以改變值,但傳值引用時,可以改變值,當你傳指標時,只可以改變指標所指的內容,不可以改變指標本身,但傳指標引用時,既可以改變指標所指的內容,又可以改變指標本身,但傳引用主要是它不生成臨時變數,不進行返回值copy等,速度快。

-End-

它的內容是所指記憶體的位址;而引用則是某塊記憶體的別名。

從物件的角度理解指標

C++primer中對 物件的定義:物件是指一塊能存儲資料並具有某種類型的記憶體空間

一個物件a,它有值和位址&a,運行程式時,電腦會為該物件分配存儲空間,來存儲該物件的值,我們通過該物件的位址,來訪問存儲空間中的值

指標p也是物件,它同樣有位址&p和存儲的值p,只不過,p存儲的資料類型是資料的位址。如果我們要以p中存儲的資料為位址,來訪問物件的值,則要在p前加解引用操作符"*",即*p。

物件有常量(const)和變數之分,既然指標本身是物件,那麼指標所存儲的位址也有常量和變數之分,常量指標是指,指標這個物件所存儲的位址是不可以改變的,而指向常量的指標的意思是,不能通過該指標來改變這個指標所指向的物件。

我們可以把引用理解成變數的別名。定義一個引用的時候,程式把該引用和它的初始值綁定在一起,而不是拷貝它。電腦必須在聲明r的同時就要對它初始化,並且,r一經聲明,就不可以再和其它物件綁定在一起了。

實際上,你也可以把引用看做是通過一個常量指標來實現的,它只能綁定到初始化它的物件上。

也可以理解引用是操作受限了的指標(僅容許取內容操作)。

引用的主要功能是傳遞函數的參數和返回值。

C++語言中,函數的參數和返回值的傳遞方式有三種:值傳遞、 指針傳遞和引用傳遞。

以下是“值傳遞”的示例程式:

void Func1(int x) {

x = x + 10;

}

int n = 0;

Func1(n);

cout << “n = ” << n << endl; // n = 0

由於Func1 函數體內的x 是外部變數n 的一份拷貝, 改變x 的值不會影響n, 所以n 的值仍然是0。

以下是“指標傳遞”的示例程式:

void Func2(int *x) {

(* x) = (* x) + 10;

}

int n = 0;

Func2(&n);

cout << “n = ” << n << endl; // n = 10

由於Func2 函數體內的x 是指向外部變數n 的指標,改變該指標的內容將導致n 的值改變,所以n 的值成為10。

以下是“引用傳遞”的示例程式:

void Func3(int &x) {

x = x + 10;

}

int n = 0;

Func3(n);

cout << “n = ” << n << endl; // n = 10

由於Func3 函數體內的x 是外部變數n 的引用,x 和n 是同一個東西,改變x 等於改變n,所以n 的值成為10。

所以,如果要修改當前被傳遞的參數的話,要麼加一級指針,要麼用引用。

對比上述三個示例程式,會發現“引用傳遞”的性質象“指標傳遞”,而書寫方式象 “值傳遞”。實際上“引用”可以做的任何事情“指標”也都能夠做,為什麼還要“引用” 這東西?

指標能夠毫無約束地操作記憶體中的如何東西,儘管指標功能強大,但是非常危險。

如果的確只需要借用一下某個物件的“別名”,那麼就用“引用”,而不要用“指針”。

無論你傳值還是傳指標,函數都會生成一個臨時變數,但傳引用時,不會生成臨時變數,當你傳值時,只可以引用值而不可以改變值,但傳值引用時,可以改變值,當你傳指標時,只可以改變指標所指的內容,不可以改變指標本身,但傳指標引用時,既可以改變指標所指的內容,又可以改變指標本身,但傳引用主要是它不生成臨時變數,不進行返回值copy等,速度快。

-End-

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示