溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++指針與引用的區(qū)別是什么

發(fā)布時(shí)間:2022-10-14 14:42:11 來(lái)源:億速云 閱讀:160 作者:iii 欄目:編程語(yǔ)言

這篇“C++指針與引用的區(qū)別是什么”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“C++指針與引用的區(qū)別是什么”文章吧。

1、指針的聲明

指針和其所指向的變量就像硬幣的兩面,因此通過(guò)取址符號(hào)"&"我們可以找到變量的地址,通過(guò)解引用符號(hào)"*"可以找到地址內(nèi)存放的變量值。

int data = 10; //聲明了一個(gè)變量data,并賦初始值10,存儲(chǔ)的值是int類型
int* p_data = &data; //找到 data 在內(nèi)存中存放的位置,即p_data
cout << "地址為:" << int(p_data) << "	 存放的值為:" << data << endl;

輸出結(jié)果為:

地址為:8191436  存放的值為:10

地址默認(rèn)是16進(jìn)制,我們?cè)谳敵鰰r(shí)將其轉(zhuǎn)換成了int 類型,因此以十進(jìn)制輸出。輸出結(jié)果翻譯過(guò)來(lái)就是:在地址編碼為8191436的位置存放了值為10的變量data,再進(jìn)一步地說(shuō),data與*p_data 表示同一個(gè)東西。為了更有助于理解,我們繪制了下圖:

C++指針與引用的區(qū)別是什么

因此從本質(zhì)上看,指針與普通的變量并沒有什么太大的區(qū)別,只是指針變量可以通過(guò)解引用的方式找到指針?biāo)鶎?duì)應(yīng)的地址中存放的數(shù)值。假如定義如下:

int data = 10;
int* p_data = &data;  //定義指向 int 類型的指針 p_data, 存儲(chǔ)的是 int 類型的變量 data的地址,其
int** p_p_data = &p_data; //定義指向 int* 類型的指針 p_p_data, 存儲(chǔ)的是 int* 類型的變量 p_data的地址

cout << "p_data:" << p_data << "	 存放的值為:" << *p_data << endl;
cout << "p_p_data:" << p_p_data << "	 存放的值為:" << *p_p_data << endl;

輸出結(jié)果為:

p_data:00EFF96C         存放的值為:10
p_p_data:00EFF960       存放的值為:00EFF96C

從輸出結(jié)果可以看出,p_p_data中存儲(chǔ)的值就是p_data,而p_data中存儲(chǔ)的值就是data,很像”我愛她,她愛他“的這種橋段。下面我們就重點(diǎn)分析一下變量與指針之間的關(guān)系:我們?cè)谏鲜隼又邪阎羔槼跏蓟癁樽兞康牡刂?,而變量是在編譯時(shí)分配的有名稱的內(nèi)存,指針只是為可以通過(guò)名稱直接訪問的內(nèi)存提供了一個(gè)別名。還拿上面這個(gè)例子:對(duì)程序員來(lái)說(shuō),變量10的名字就是data;而對(duì)于計(jì)算機(jī)來(lái)說(shuō),變量10就是存在 8191436 地址的數(shù)據(jù);實(shí)現(xiàn)程序員與計(jì)算機(jī)溝通的方式就是指針,通過(guò)對(duì)data取址讓程序員能夠明白計(jì)算機(jī)的存儲(chǔ)結(jié)構(gòu),同樣,通過(guò)對(duì)地址解引用,也能輕松地找到該地址中存儲(chǔ)的數(shù)據(jù)。在上述情況下,指針的出現(xiàn)顯得有些多余,然而指針的真正用武之地在于,在運(yùn)行階段分配未命名的內(nèi)存以存儲(chǔ)值,在這種情況下,只能通過(guò)指針來(lái)訪問內(nèi)存。

最后關(guān)于指針聲明的一點(diǎn)建議:在聲明一個(gè)指針變量時(shí),必須要指定一個(gè)確定的地址,否則聲明的指針變量不知道指向哪里,因此容易造成系統(tǒng)崩潰。

2、使用new來(lái)分配內(nèi)存

內(nèi)存四區(qū)之代碼區(qū),全局區(qū),棧區(qū)和堆區(qū)中提到過(guò),new 會(huì)在堆區(qū)創(chuàng)建一個(gè)內(nèi)存空間,其返回值就是該內(nèi)存空間的地址,因此程序員的責(zé)任就是將該地址賦給一個(gè)指針。下面是一個(gè)示例:

int* p_data = new int; //在堆區(qū)開辟一個(gè)空間,并返回該內(nèi)存空間的地址
*p_data = 10; //將向該內(nèi)存中存儲(chǔ)數(shù)值10
cout << "p_data:	" << p_data << "	 *p_data: " << *p_data << endl;

通過(guò)比較會(huì)發(fā)現(xiàn),new 后面指定了數(shù)據(jù)類型 int,同樣地,p_data 也被聲明為指向 int 的指針。這是因?yàn)?,?jì)算機(jī)的內(nèi)存是以字節(jié)為存儲(chǔ)單位,不同類型的變量會(huì)占用不同的字節(jié),因此使用 new 時(shí)必須要告訴編譯器分配多少字節(jié)的存儲(chǔ)空間,并且接收的指針也必須與聲明的類型一致。輸出結(jié)果為:

p_data: 00D0D9A0         *p_data: 10

當(dāng)處理大型數(shù)據(jù),比如數(shù)組時(shí),通常會(huì)使用的一種方法是定義一個(gè)數(shù)組類型的數(shù)據(jù),在定義的時(shí)候分配足夠大的空間。但是這種做法太過(guò)于死板,但是當(dāng)使用 new 時(shí),如果在運(yùn)行階段需要數(shù)組,那么則創(chuàng)建它,如果不需要?jiǎng)t不創(chuàng)建,最重要的是可以在程序運(yùn)行時(shí)選擇數(shù)組的長(zhǎng)度。 下面就看一下如何使用 new 來(lái)創(chuàng)建動(dòng)態(tài)數(shù)組。在C++中,數(shù)組名被解釋為數(shù)組地址,即數(shù)組第一個(gè)元素的地址。下面是一個(gè)實(shí)例:

int Arr[10]; // 定義一個(gè)包含10個(gè)int類型元素的數(shù)組
cout << "Arr:" << Arr << "	&Arr[0]:" << &Arr[0] <<endl;

輸出結(jié)果為:

Arr:008FFAB4    &Arr[0]:008FFAB4

這種聲明方式只能在剛開始就聲明固定的數(shù)組長(zhǎng)度,在C++中創(chuàng)建動(dòng)態(tài)數(shù)組時(shí),只需要將數(shù)組的元素類型和元素?cái)?shù)目告訴給 new 即可,new 的返回值同樣是數(shù)組的首地址。

int ele_num = 10; //臨時(shí)指定數(shù)組內(nèi)元素的個(gè)數(shù)
int* p_arr = new int [ele_num]; //根據(jù)臨時(shí)指定的元素個(gè)數(shù)創(chuàng)建數(shù)組

通過(guò) new 在堆區(qū)開辟空間,由程序員管理釋放,因此當(dāng) new 的內(nèi)存不用后,需要通過(guò) delete 進(jìn)行變量,使用 delete [] 來(lái)釋放開辟的數(shù)組空間。代碼如下:

int* p_data = new int;
*p_data = 10;
cout << "p_data: " << p_data << "	*p_data:" << *p_data << endl;

int ele_num = 10;
int* p_arr = new int [ele_num];

for(int i = 0; i<9; i++)
 *(p_arr+i) = i+2;

cout << "p_arr:" << p_arr << "		*(p_array):";
for(int i = 0; i<9; i++)
 cout << *(p_arr + i) << " ";
cout << endl;

delete p_data;
delete [] p_arr;

cout << "
******使用delete釋放內(nèi)存后......*******" << endl;
cout << "p_data: " << p_data << "	*p_data:" << *p_data << endl;
cout << "p_arr:" << p_arr << "		*(p_array):";
for(int i = 0; i<9; i++)
cout << *(p_arr + i) << " ";
cout << endl;

輸出結(jié)果如下:

p_data: 0082B1C8        *p_data:10
p_arr:0082BB58          *(p_array):2 3 4 5 6 7 8 9 10

******使用delete釋放內(nèi)存后......*******
p_data: 0082B1C8        *p_data:-572662307
p_arr:0082BB58          *(p_array):-572662307 -572662307 -572662307 -572662307 -572662307 -572662307 -572662307 -572662307 -572662307

3、malloc 與 new 的區(qū)別

學(xué)過(guò)C語(yǔ)言的朋友都知道,在C語(yǔ)言中通過(guò)malloc函數(shù)開辟一塊內(nèi)存空間,malloc的函數(shù)原型如下:

void* malloc(unsigned int numbytes);

從函數(shù)原型的參數(shù)可以看出,malloc 函數(shù)以字節(jié)數(shù)為參數(shù),開辟固定字節(jié)的內(nèi)存空間。這與 new 就有了第一點(diǎn)不同:new 不需要自己計(jì)算字節(jié)數(shù),只需要給定內(nèi)存中存儲(chǔ)的數(shù)據(jù)類型與元數(shù)個(gè)數(shù)即可。

從函數(shù)原型的返回類型可以看出,malloc 函數(shù)返回 void* 類型,需要我們?cè)谑褂脮r(shí)自己指定指針類型。比如:

int* p_malloc = nullptr; // 創(chuàng)建一個(gè)指向int的指針
p_malloc = (int*) malloc(10); //將 malloc 的返回值強(qiáng)制轉(zhuǎn)換為 int* 類型

而 new 在使用時(shí)則不需要??偨Y(jié)看來(lái),malloc 在使用時(shí)需要自己根據(jù)內(nèi)存中的數(shù)據(jù)類型以及內(nèi)存長(zhǎng)度計(jì)算處所需要的字節(jié)數(shù),然后返回 void* 類型,需要使用對(duì)應(yīng)類型的指針進(jìn)行接收。而 new 在使用時(shí)只需要給定內(nèi)存的長(zhǎng)度與內(nèi)存中數(shù)據(jù)的類型,編譯器會(huì)自動(dòng)計(jì)算所需要的字節(jié)數(shù)。

4、引用的聲明與本質(zhì)

C++中新增了引用作為已定義的變量的別名。引用的最主要用途是作為函數(shù)形參,這樣函數(shù)就可以使用原始數(shù)據(jù)而不是數(shù)據(jù)副本,這樣聽起來(lái)似乎與指針沒什么區(qū)別,我們還是從引用的聲明說(shuō)起。

int data = 10;
int& p_data = data; //創(chuàng)建一個(gè)引用變量 p_data
cout << "data:" << data << "	p_data:" << p_data << endl; //p_data 與 data 相當(dāng)于一個(gè)變量的兩個(gè)名字

輸出結(jié)果為:

data:10  p_data:10

從輸出結(jié)果來(lái)看,p_data 與 data 就是一個(gè)變量的兩個(gè)不同叫法而已。引用必須在聲明時(shí)就為其指定初始值,而不能像指針一樣可以先聲明,再賦值。下面將引用作為函數(shù)的參數(shù)來(lái)進(jìn)一步說(shuō)明引用與指針的區(qū)別:

template <typename T> //定義一個(gè)模板函數(shù)
void swap(T a, T b){
 int temp;
 temp = a;
 a = b;
 b = temp;
}
int main(void){
 int a = 10, b = 20; 
 swap_value<int>(a,b); //首先進(jìn)行值傳遞
 cout << "a:" << a << "		b:" << b << endl;
 swap_value<int&>(a,b); //然后進(jìn)行引用傳遞
 cout << "
a:" << a << "		b:" << b << endl;
}

從上述代碼中可以看到,值傳遞和引用傳遞的形參都是一樣的,不同的是引用傳遞時(shí),實(shí)參被聲明為引用,引用的用法與使用值一模一樣,輸出結(jié)果如下:

a:10            b:20
a:20            b:10

驚奇的發(fā)現(xiàn),引用傳遞改變了原始數(shù)據(jù)的值,這點(diǎn)與指針的用法一致,但是指針在書寫 swap 函數(shù)時(shí)應(yīng)該這樣寫:

void swap(int* a, int* b){
 int temp;
 temp = *a;
 *a = *b;
 *b = temp;
}
swap(&a, &b); //調(diào)用格式

綜上發(fā)現(xiàn),引用其實(shí)就是變量的另一個(gè)名稱,它的用法與變量一模一樣,但是能在作為形參傳遞時(shí),改變?cè)紨?shù)據(jù)的值。除了這些用法上的區(qū)別,引用的本質(zhì)其實(shí)就是一個(gè)指針常量,意味著指針指向的位置不可變,但是指針指向位置的值可變。即:

// 這兩者的語(yǔ)句是等效的,因此引用被當(dāng)作指針常量來(lái)處理
int& p_a = a;  
int* const p_a=&a;

再補(bǔ)充一點(diǎn)小知識(shí),關(guān)于 const 修飾符的問題,有些新手朋友來(lái)說(shuō)很容易弄不清楚 const 修飾下什么是可變的,什么是不可變的。具體實(shí)例如下:

int data = 10, data2 = 20;
const int* p_data = &data; //修飾的是int,即 p_data 所指向的值不可變,而p_data可變
p_data = &data2;

int* const p_data2 = &data; //修飾的是int*,即 p_data 所指向的值可變,而p_data不可變
*p_data2 = data2;

引用即是第二種用法。

以上就是關(guān)于“C++指針與引用的區(qū)別是什么”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI