亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

手拉手教你如何理解c/c++中的指針

 更新時(shí)間:2021年10月15日 11:24:56   作者:劉亞曦  
當(dāng)你對(duì)C越來(lái)越熟悉時(shí),你會(huì)發(fā)現(xiàn)把與指針攪和在一起的"類(lèi)型"這個(gè)概念分成"指針的類(lèi)型"和"指針?biāo)赶虻念?lèi)型"兩個(gè)概念,是精通指針的關(guān)鍵點(diǎn)之一,這篇文章主要給大家介紹了關(guān)于c/c++中指針的相關(guān)資料,需要的朋友可以參考下

前言

指針是c語(yǔ)言為什么如此流行的一個(gè)重要原因,正是有了指針的存在,才使得c/c++能夠可以比使用其他語(yǔ)言編寫(xiě)出更為緊湊和有效的程序,可以說(shuō),沒(méi)有掌握指針,就沒(méi)有權(quán)利說(shuō)自己會(huì)用c/c++.然而。然而對(duì)于大多數(shù)初學(xué)者,面對(duì)指針這個(gè)概念簡(jiǎn)直是望而生畏,如果前期指針運(yùn)用的不熟練,后期編寫(xiě)的程序隨時(shí)都有可能成為一顆定時(shí)炸彈,因此今天我就花點(diǎn)時(shí)間給大家解釋一下我自己對(duì)c/c++中指針的理解。

一,內(nèi)存和地址

我們知道,計(jì)算機(jī)內(nèi)存的每個(gè)字節(jié)都有一個(gè)唯一的地址,CPU每次尋址就是通過(guò)固定的步長(zhǎng)(這就解釋了為什么需要內(nèi)存對(duì)齊)來(lái)跳躍進(jìn)行尋址的。舉個(gè)例子,我們可以把內(nèi)存看做是一條長(zhǎng)街上的一排房屋,每個(gè)房屋都有自己固定的門(mén)牌號(hào),每座房屋里面都可以容納數(shù)據(jù),為了讀取到某個(gè)房屋里面的數(shù)據(jù),我們必須知道這個(gè)房屋的門(mén)牌號(hào),根據(jù)這個(gè)門(mén)牌號(hào)來(lái)打開(kāi)這個(gè)房間,取走數(shù)據(jù)。同樣,計(jì)算機(jī)也必須為每個(gè)內(nèi)存字節(jié)都編上號(hào)碼,就像門(mén)牌號(hào)一樣,每個(gè)字節(jié)的編號(hào)是唯一的,根據(jù)編號(hào)可以準(zhǔn)確地找到某個(gè)字節(jié)。

二,指針的本質(zhì)就是地址

當(dāng)我們?cè)诔绦蛑新暶饕粋€(gè)變量并給這個(gè)變量賦值的時(shí)候,編譯器做了什么呢?實(shí)際上,變量名代表內(nèi)存中的一個(gè)存儲(chǔ)單元,在編譯器對(duì)程序編譯連接的時(shí)候由系統(tǒng)給變量分配一個(gè)地址:

int a = 10;

上面這行代碼我們定義并初始化了這個(gè)變量a,系統(tǒng)會(huì)為a分配一塊內(nèi)存單元,a只是這塊內(nèi)存單元的別名,在程序中從變量中取值,實(shí)際上是通過(guò)變量名找到相應(yīng)的內(nèi)存單元,從其中讀取數(shù)據(jù)。

假如系統(tǒng)為變量 a 分配的內(nèi)存地址為0xFF00, 那么我們可以說(shuō)這個(gè)地址就是變量 a 的門(mén)牌號(hào)。一個(gè)變量的地址稱為該變量的指針。所以說(shuō),指針的本質(zhì)就是地址,指針變量是一種特殊的變量,它專門(mén)保存指針(也即地址),當(dāng)我們說(shuō)這個(gè)地址對(duì)應(yīng)的內(nèi)存單元的時(shí)候,我們可以說(shuō)這個(gè)指針指向這塊內(nèi)存單元。

例如:

int a = 10;  
int* p = &a;  //定義指針變量 p
*p = 20;      //將指針p指向的值修改為 20

上面兩行代碼中,我們首先定義了一個(gè)整型變量 a ,然后又定義了一個(gè)指針變量 p 指向 a .第二行代碼中,符號(hào)&代表取地址,相當(dāng)于把變量a的地址賦值給了指針變量p(p指向a),*加在指針變量前面代表解引用,意思找到指針p指向的值,因此,第三行代碼的意思就是講p指向的值也就是a修改為20.總之一定要記住,符號(hào)&代表取值,符號(hào)*代表解引用:

符號(hào)
意義
&
取地址
*
解引用

這三行代碼的內(nèi)存模型如下:

我們假設(shè)系統(tǒng)給變量 a 分配的內(nèi)存首地址為2000,我們又聲明了一個(gè)指針變量p,這個(gè)p也是要占用內(nèi)存空間的(32位系統(tǒng)占用4個(gè)字節(jié),64位系統(tǒng)占用8個(gè)字節(jié),請(qǐng)思考為什么),只不過(guò)這個(gè)變量p保存的內(nèi)容是變量a的地址,也就是2000,當(dāng)我們想通過(guò)p來(lái)操縱a的話,首先要根據(jù)p保存的地址找到它指向的內(nèi)容,也就是解引用*p,當(dāng)*p的內(nèi)容放生改變的時(shí)候,首地址為2000的內(nèi)存單元存儲(chǔ)的值也會(huì)做出改變,因此變量當(dāng)*p被重新賦值為20的時(shí)候,變量a的值也會(huì)做出改變,變?yōu)?0.

由此擴(kuò)展到二級(jí)指針,如果我們?cè)俣x一個(gè)指針變量q來(lái)指向p,那么q就是一個(gè)二級(jí)指針,因?yàn)樗赶虻膶?duì)象還是一個(gè)指針,只不過(guò)比他自己低一級(jí),是一級(jí)指針,那么二級(jí)指針如何定義呢,請(qǐng)看下面的代碼:

int a = 10;
int* p = &a;
int** q = &p;

上面第三行代碼就是定義了一個(gè)二級(jí)指針q,它指向的是一級(jí)指針p,而一級(jí)指針p又指向了變量a,它的內(nèi)存模型如下圖所示:

二級(jí)指針q保存的內(nèi)容為一級(jí)指針p的地址而非內(nèi)容,注意p地址是2008,p的內(nèi)容為2000. 因此對(duì)q進(jìn)行解引用也即*q得出的是p,也就是2008,再對(duì)(*q)進(jìn)行解引用也即*(*q)得出的才是變量a的值,由于運(yùn)算符的結(jié)合性自右向左,因此括號(hào)可以省略,也即**q才是a的值。我們可以編寫(xiě)代碼試一下:

cout <<"a的值為:"<< **q << endl;

我們觀察一下輸出結(jié)果:

沒(méi)錯(cuò),輸出的結(jié)果完全正確。

由此再擴(kuò)充到多級(jí)指針,二級(jí)指針是指向一級(jí)指針的指針,那么n級(jí)指針便是指向n-1級(jí)指針的指針,以此類(lèi)推。

三,常量指針與指針常量

請(qǐng)看下面兩行代碼:

int a = 10;
const int * p1 = &a;    //常量指針
int * const p2 = &a;    //指針常量

上面第二行代碼中的p1是一個(gè)常量指針,就是指向常量的指針變量。意味著它指向的值不可以修改,但是指針的指向可以修改:

int a = 10;
int b = 20;
const int * p1 = &a;    //常量指針
*p1 = 100;  //錯(cuò)誤,常量指針指向的值不可以修改
p1 = &b;   //正確

而對(duì)于指針常量,它本質(zhì)是一個(gè)常量,但是由指針修飾。意味著它指向的值可以修改,但是指針的指向不可修改,與常量指針剛剛相反:

int a = 10;
int b = 20;
int * const p1 = &a;    //指針常量
*p1 = 100;  //正確
p1 = &b;   //錯(cuò)誤,指針的指向不可以修改

因此,我們總結(jié)下:


名稱
意義
特點(diǎn)
const int * p
常量指針
指向可修改,指向的值不可修改
int * const p
指針常量
指向不可修改,指向的值可修改

四,指針與數(shù)組

我們知道,一維數(shù)組名本身就是一個(gè)指針,但是在使用的過(guò)程中要小心,因?yàn)檫@個(gè)指針?lè)譃橹赶驍?shù)組首元素的指針與指向整個(gè)數(shù)組的指針,那么如何區(qū)分它們呢?我們來(lái)看下面幾行代碼:

int arr[] = {1, 2, 3, 4, 5};
int* p1 = arr;
int* p2 = &arr[0];
int* p3 = &arr;    //報(bào)錯(cuò)

上面三行代碼中,其中p1與p2是等價(jià)的,因?yàn)閿?shù)組名arr本身就是一個(gè)指針,但是這個(gè)指針不是指向整個(gè)數(shù)組,而是指向數(shù)組的首元素的地址。第四行直接報(bào)錯(cuò),因?yàn)?amp;arr指的是整個(gè)數(shù)組的指針,不能把數(shù)組指針賦值給整形指針。雖然arr與&arr在數(shù)值上是相同的,但是兩者意義不同。意味著&arr它的步長(zhǎng)為整個(gè)數(shù)組,而對(duì)于arr,步長(zhǎng)為單個(gè)元素。

所以,我們得出結(jié)論,對(duì)于一維數(shù)組arr:

名稱
意義
步長(zhǎng)
arr
指向數(shù)組首元素
單個(gè)元素
&arr[0]
指向數(shù)組首元素 單個(gè)元素
&arr
指向整個(gè)數(shù)組
整個(gè)數(shù)組

在定義了指向數(shù)組首元素的指針變量后,我們可以通過(guò)這個(gè)指針變量來(lái)訪問(wèn)數(shù)組元素:

  int arr[] = { 1,2,3,4,5 };
  int* p1 = arr;
  int length = sizeof(arr) / sizeof(int);
  for (int i = 0; i < length; i++)
  {
    cout << p1[i] << endl;
    cout << *(p1 + i) << endl;
  }

上面幾行代碼中,p1[i]與*(p1+i)兩者是等價(jià)的,所以輸出的結(jié)果一樣。但是要注意,當(dāng)用sizeof操作符操作arr的時(shí)候,這個(gè)時(shí)候不能把a(bǔ)rr當(dāng)做一個(gè)指針來(lái)對(duì)待,因?yàn)閟izeof操作數(shù)組的時(shí)候它返回的是數(shù)組的字節(jié)長(zhǎng)度,而單個(gè)指針變量只占用四個(gè)字節(jié)。上面循環(huán)體中,我們也可以通過(guò)下面方式訪問(wèn):

cout << *p1++ << endl;  
cout << *(p1++) << endl;

*p1++與*(p1++)是等價(jià)的,這是因?yàn)?+的運(yùn)算符優(yōu)先級(jí)比*要高,因此不管你加不加括號(hào),都會(huì)優(yōu)先執(zhí)行p++,然而p++是先返回p的值,再與*結(jié)合,最后p再向后移動(dòng)一位。

不過(guò)在這里要特別注意,有一種情況下我們是不能通過(guò)sizeof操作符來(lái)計(jì)算數(shù)組的長(zhǎng)度的,就是當(dāng)數(shù)組名作為函數(shù)參數(shù)傳遞的時(shí)候:

void test(int arr[])
{
  int lenth = sizeof(arr) / sizeof(int);
}

上面這行代碼語(yǔ)法上沒(méi)有問(wèn)題,但是得出的結(jié)果卻不是我們想要的結(jié)果,為什么呢,這是因?yàn)閿?shù)組名作為函數(shù)傳遞的時(shí)候,會(huì)退化成一個(gè)指針,如果是二維數(shù)組的話,會(huì)退化成指向一維數(shù)組的指針,所以sizeof(arr)計(jì)算出來(lái)的結(jié)果就不是數(shù)組的字節(jié)長(zhǎng)度了。所以說(shuō),在c/c++中傳遞數(shù)組的時(shí)候,一般我們也會(huì)把數(shù)組的長(zhǎng)度作為形參傳遞過(guò)去。

但是我們不能通過(guò)下面方式去訪問(wèn)數(shù)組元素:

cout << *arr++ << endl;    //報(bào)錯(cuò)

這是因?yàn)閍rr本身是一個(gè)指針常量,指針的指向不可更改,因此編譯器直接報(bào)錯(cuò)。

五,數(shù)組指針與指針數(shù)組

數(shù)組指針顧名思義,本質(zhì)就是一個(gè)指針,這個(gè)指針指向整個(gè)數(shù)組;指針數(shù)組本質(zhì)上是一個(gè)數(shù)組,但是數(shù)組的每個(gè)元素都是指針。請(qǐng)看下面兩行代碼:

int *p1[10];    //指針數(shù)組
int (*p2)[10];  //數(shù)組指針

上面兩行代碼,p1是一個(gè)數(shù)組,而p2卻是一個(gè)指針,它指向一個(gè)匿名數(shù)組。為什么是這樣呢?這是因?yàn)閇]的優(yōu)先級(jí)比*要高。p1 先與[]結(jié)合,構(gòu)成一個(gè)數(shù)組的定義,數(shù)組名為p1,int *修飾的是數(shù)組的內(nèi)容,即數(shù)組的每個(gè)元素。那現(xiàn)在我們清楚,這是一個(gè)數(shù)組,其包含10 個(gè)指向int 類(lèi)型數(shù)據(jù)的指針,即指針數(shù)組。至于p2 就更好理解了,在這里括號(hào)的優(yōu)先級(jí)比[]高,*號(hào)和p2 構(gòu)成一個(gè)指針的定義,指針變量名為p2,int 修飾的是數(shù)組的內(nèi)容,即數(shù)組的每個(gè)元素。數(shù)組在這里并沒(méi)有名字,是個(gè)匿名數(shù)組。那現(xiàn)在我們清楚p2 是一個(gè)指針,它指向一個(gè)包含10 個(gè)int 類(lèi)型數(shù)據(jù)的數(shù)組,即數(shù)組指針。

p1為數(shù)組名,每個(gè)元素都是int型指針

p2為指針變量,指向一個(gè)匿名數(shù)組

如果我們定義:

int(*p)[10] = &arr;

那么如何訪問(wèn)數(shù)組的元素呢?且看,由于上行代碼中,p=&arr,那么對(duì)其解引用,*p就是arr,因此我們可以通過(guò)(*p)[]來(lái)進(jìn)行訪問(wèn)數(shù)組的元素:

for(int i = 0; i < 10; i++)
{
  cout<< (*p)[i] << endl;
}

六,指針函數(shù)與函數(shù)指針

指針函數(shù)顧名思義,他是一個(gè)函數(shù),但返回值是一個(gè)指針,例如下面這幾行代碼:

int* test()
{
  int a = 10;
  int* p = &a;
  return p;
}

這個(gè)test就是一個(gè)指針函數(shù),它返回的是一個(gè)int型的指針。

函數(shù)指針本質(zhì)是一個(gè)指針,這個(gè)指針指向一個(gè)函數(shù),那么我們?nèi)绾味x函數(shù)指針呢?請(qǐng)看下面代碼:

int myAdd(int a, int b)
{
  return a + b;
}
void test()
{
  int(*pFun)(int, int) = myAdd;    //定義一個(gè)函數(shù)指針
  cout << (*pFun)(2, 5) << endl;    //用函數(shù)指針調(diào)用函數(shù)
  cout << pFun(2, 5) << endl;      //用函數(shù)指針調(diào)用函數(shù)
}

上面test函數(shù)代碼中,我們定義了一個(gè)函數(shù)指針,在最后進(jìn)行調(diào)用函數(shù)的時(shí)候,有兩種方法,一種是用*pFun來(lái)調(diào)用,一種是直接用pFun來(lái)調(diào)用,可見(jiàn)兩種方法結(jié)果都一樣。

最后,我們來(lái)看個(gè)比較混合指針復(fù)雜的案例:

char *(* c[10])(int **p);

乍一看,讓人眼花繚亂,不知道是什么東西,在這里請(qǐng)大家記住一個(gè)規(guī)則:C語(yǔ)言標(biāo)準(zhǔn)規(guī)定,對(duì)于一個(gè)符號(hào)的定義,編譯器總是從它的名字開(kāi)始讀取,然后按照優(yōu)先級(jí)順序依次解析。注意是從名字開(kāi)始,不是從開(kāi)頭也不是從末尾,這是理解復(fù)雜指針的關(guān)鍵。

有了上面的規(guī)則,我們來(lái)逐步剖析上面哪行代碼的意義:

首先從*c[10]開(kāi)始,由于[]的優(yōu)先級(jí)比*高,因此,*c[10]代表一個(gè)指針數(shù)組,每個(gè)元素都是指針,但類(lèi)型還不知道。再看右邊的(int** p),它是一個(gè)函數(shù),參數(shù)為一個(gè)二級(jí)指針。最左邊char* 代表這個(gè)函數(shù)的返回類(lèi)型。因此,整行代碼的含義就是:c 是一個(gè)擁有 10 個(gè)元素的指針數(shù)組,數(shù)組每個(gè)元素指向一個(gè)原型為char *(int **p)的函數(shù)。

總結(jié)

到此這篇關(guān)于c/c++中指針的文章就介紹到這了,更多相關(guān)c/c++中的指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言double和float 實(shí)例分析

    C語(yǔ)言double和float 實(shí)例分析

    本文主要介紹了C語(yǔ)言中的浮點(diǎn)數(shù)(float,double),并通過(guò)實(shí)例代碼進(jìn)行分析比較,希望能幫助學(xué)習(xí)相關(guān)知識(shí)的同學(xué)
    2016-07-07
  • C語(yǔ)言實(shí)現(xiàn)超市信息管理系統(tǒng)課程設(shè)計(jì)

    C語(yǔ)言實(shí)現(xiàn)超市信息管理系統(tǒng)課程設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)超市信息管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 馬爾可夫鏈算法(markov算法)的awk、C++、C語(yǔ)言實(shí)現(xiàn)代碼

    馬爾可夫鏈算法(markov算法)的awk、C++、C語(yǔ)言實(shí)現(xiàn)代碼

    這篇文章主要介紹了馬爾可夫鏈算法(markov算法)的awk、C++、C語(yǔ)言實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2014-08-08
  • Qt與Web混合開(kāi)發(fā)實(shí)現(xiàn)雙向通信的示例

    Qt與Web混合開(kāi)發(fā)實(shí)現(xiàn)雙向通信的示例

    本文主要介紹了Qt與Web混合開(kāi)發(fā)實(shí)現(xiàn)雙向通信的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C語(yǔ)言修煉之路數(shù)據(jù)類(lèi)型悟正法?解析存儲(chǔ)定風(fēng)魔上篇

    C語(yǔ)言修煉之路數(shù)據(jù)類(lèi)型悟正法?解析存儲(chǔ)定風(fēng)魔上篇

    使用編程語(yǔ)言進(jìn)行編程時(shí),需要用到各種變量來(lái)存儲(chǔ)各種信息。變量保留的是它所存儲(chǔ)的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個(gè)變量時(shí),就會(huì)在內(nèi)存中保留一些空間。您可能需要存儲(chǔ)各種數(shù)據(jù)類(lèi)型的信息,操作系統(tǒng)會(huì)根據(jù)變量的數(shù)據(jù)類(lèi)型,來(lái)分配內(nèi)存和決定在保留內(nèi)存中存儲(chǔ)什么
    2022-02-02
  • C++ GetDlgItem用法案例詳解

    C++ GetDlgItem用法案例詳解

    這篇文章主要介紹了C++ GetDlgItem用法案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • VC中刪除類(lèi)的兩種操作方法

    VC中刪除類(lèi)的兩種操作方法

    這篇文章主要介紹了VC中刪除類(lèi)的兩種操作方法,較為詳細(xì)的描述了在VC中實(shí)現(xiàn)刪除類(lèi)的具體步驟,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-05-05
  • C++中多才多藝的 const

    C++中多才多藝的 const

    在C++中,關(guān)鍵字const可以用來(lái)修飾任何作用域內(nèi)的變量、函數(shù)參數(shù)、函數(shù)本體、函數(shù)返回值、成員函數(shù)、迭代器,也可以用來(lái)修飾指針本身和指針目標(biāo),可謂多才多藝,我們要詳細(xì)了解其內(nèi)部細(xì)節(jié),以及邏輯奧秘,讓這把多功能瑞士軍刀盡情發(fā)揮其作用,需要的朋友可以參考一下
    2021-09-09
  • C++、Qt分別讀寫(xiě)xml文件的方法實(shí)例

    C++、Qt分別讀寫(xiě)xml文件的方法實(shí)例

    Qt提供了QDomElement 類(lèi)用于完成對(duì)xml文件的讀取和寫(xiě)入,這篇文章主要給大家介紹了關(guān)于C++、Qt分別讀寫(xiě)xml文件的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • C++實(shí)現(xiàn)RSA加密解密算法是示例代碼

    C++實(shí)現(xiàn)RSA加密解密算法是示例代碼

    非對(duì)稱加密方式可以使通信雙方無(wú)需事先交換密鑰就可以建立安全通信,因此被廣泛應(yīng)用于身份認(rèn)證、數(shù)字簽名、等信息交換領(lǐng)域。其中最具有代表性的非對(duì)稱加密方式就是RSA公鑰密碼體制。本文將用C++實(shí)現(xiàn)RSA加密解密算法,需要的可以參考一下
    2022-09-09

最新評(píng)論