您好,登錄后才能下訂單哦!
原文鏈接:https://www.cnblogs.com/l-hh/p/12288613.html
本文章文字有點(diǎn)多,會(huì)有點(diǎn)枯燥,配合圖文一起看可以緩解枯燥,耐心閱讀哦?。?!
先了解內(nèi)存地址,才更好的理解指針!
我們可以把內(nèi)存想象為成一列很長(zhǎng)很長(zhǎng)的貨運(yùn)火車(chē),有很多大小相同的車(chē)廂,而每個(gè)車(chē)廂正好相當(dāng)于在內(nèi)存中表示一個(gè)字節(jié)
。這些車(chē)廂裝著不同的貨物,就像我們的內(nèi)存要存著各式各樣的數(shù)據(jù)。
我們平時(shí)在電腦上能夠聽(tīng)音樂(lè)、看視頻和文章,其實(shí)看到的這些東西就是內(nèi)存中每個(gè)“車(chē)廂”里面的數(shù)據(jù),這些數(shù)據(jù)最終還是由二進(jìn)制0/1演變而成。
雖然視頻、文章、音樂(lè)等這些信息在我們眼里是不同的,但對(duì)于計(jì)算機(jī)來(lái)說(shuō)它們?cè)趦?nèi)存中都是以二進(jìn)制的形式來(lái)表示。
因?yàn)槲覀円廊ツ拇婊蛉?shù)據(jù),所以?xún)?nèi)存中每個(gè)字節(jié)都有對(duì)應(yīng)的編號(hào),就像火車(chē)上的車(chē)廂編號(hào)一樣。而這個(gè)內(nèi)存中每個(gè)字節(jié)的編號(hào)就是我們常說(shuō)的內(nèi)存地址,是按一個(gè)字節(jié)接著一個(gè)字節(jié)的次序進(jìn)行編址。如下圖所示:
1. 為什么內(nèi)存地址都有0x開(kāi)頭?
0x 開(kāi)頭代表以十六進(jìn)制來(lái)表示的意思。
2. 為什么我們平時(shí)看到內(nèi)存地址是這樣的呢?如圖:
因?yàn)閮?nèi)存容量很大,容量大字節(jié)數(shù)自然也多了,所以需要更多位來(lái)編址內(nèi)存地址。上圖的(0x00 ...)內(nèi)存地址這里只是便于理解!
3. 為什么我那么菜呢?
哈哈哈......你心里沒(méi)點(diǎn)*數(shù)嗎?
可以使用sizeof進(jìn)行驗(yàn)證:
#include<stdio.h> int main () { printf("sizeof(char)=%u\n",sizeof(char)); printf("sizeof(int)=%u\n",sizeof(int)); return 0; }
結(jié)果如下:
不要把指針想得太復(fù)雜,指針的實(shí)質(zhì)就是內(nèi)存“地址”,可以說(shuō)指針就是地址,其實(shí)指針就是保存地址的變量。
拿普通變量跟指針變量做比較:
char a; // 定義一個(gè)變量a,用于保存char類(lèi)型的數(shù)據(jù); char *b; // 定義一個(gè)指針變量b,用于保存一個(gè)內(nèi)存地址,這個(gè)內(nèi)存地址上的數(shù)據(jù)必須是char類(lèi)型的。
舉個(gè)例子,給指針變量進(jìn)行賦值:
#include<stdio.h> int main () { char a = 5; // char 類(lèi)型占一個(gè)字節(jié); char *b = &a; // “&”是取變量的地址,取出a在內(nèi)存中的地址; // 賦值給b指針,此時(shí)b變量存儲(chǔ)的就是a地址。 printf("我是a變量的值:%d\n",*b); // *b表示輸出b里面存儲(chǔ)的地址上的數(shù)據(jù); // 證明b上存儲(chǔ)的是a的地址; printf("我是a的地址:%p\n",&a); printf("我是b變量的值:%p\n",b); return 0; }
輸出結(jié)果為:
我是a變量的值:5 我是a的地址:000000000062FE17 我是b變量的值:000000000062FE17
通過(guò)畫(huà)圖來(lái)理解:
通過(guò)指針間接性修改變量的值
char a = 5; char *b = &a; printf("初始值:a=%d,*b=%d\n",a,*b); *b = 12; // 其實(shí)操作的就是變量a本身的值; printf("修改后:a=%d,*b=%d\n",a,*b); ------------------------------------------ 輸出結(jié)果為: 初始值:a=5,*b=5 修改后:a=12,*b=12
我們知道char類(lèi)型的數(shù)據(jù)只占一個(gè)字節(jié),有很多類(lèi)型是需要多個(gè)字節(jié)來(lái)存儲(chǔ)的,像int類(lèi)型的數(shù)據(jù)就需要四個(gè)字節(jié)來(lái)存儲(chǔ)(根據(jù)平臺(tái)不同,長(zhǎng)度也有可能不一致)。
對(duì)于int類(lèi)型的指針從當(dāng)前字節(jié)(地址)開(kāi)始共四個(gè)字節(jié)(地址)都是屬于該變量的值, 而對(duì)于char類(lèi)型則只表示當(dāng)前字節(jié)(地址)。代碼如下:
int a = 259; int * p1 = &a; char * p2 = (char *)&a; // 這里需要強(qiáng)制轉(zhuǎn)換一下類(lèi)型 printf("*p1=%d,*p2=%d\n",*p1,*p2); ----------------------- 輸出:*p1=259,*p2=3
通過(guò)畫(huà)圖來(lái)便于理解:
通過(guò)上文我們已經(jīng)對(duì)int類(lèi)型指針有所了解了,*p1的輸出是在我們預(yù)算范圍之內(nèi)的,但是為什么*p2輸出的值是3呢?
因?yàn)橛?jì)算機(jī)是使用二進(jìn)制來(lái)表示數(shù)字的,上面(259)十進(jìn)制轉(zhuǎn)換二進(jìn)制是 [100000011],由于一個(gè)int類(lèi)型變量占用四個(gè)字節(jié),8位二進(jìn)制為一個(gè)字節(jié),補(bǔ)齊高位的0后,則 [00000000 00000000 00000001 00000011],每8位二進(jìn)制(一個(gè)字節(jié))換算為十進(jìn)制,則 [0 0 1 3]。
此時(shí)你應(yīng)該差不多明白*p2為什么輸出的值為3了吧,但是內(nèi)存地址中有個(gè)概念叫"大小端模式",就會(huì)有兩種不同的排序:[0 0 1 3] or [3 1 0 0]。
由于計(jì)算機(jī)讀取*p2的地址是0x00,所以直接輸出這個(gè)地址上的數(shù)據(jù),你也可以試著改一下,把259換成258/257等,看看是否正如所說(shuō)。
驗(yàn)證它們存儲(chǔ)地址,代碼如下:
int a = 259; int * p1 = &a; char * p2 = (char *)&a; printf("*p1=%d,*p2=%d\n",*p1,*p2); printf("&a=0x%p\n",&a); printf("p1=0x%p\n",p1); printf("p2=0x%p\n",p2);
輸出結(jié)果正如我們預(yù)想的:
當(dāng)你看到這里的時(shí)候,你只是剛剛認(rèn)識(shí)指針而已,以上是我們俗稱(chēng)的一級(jí)指針,一級(jí)指針是比較簡(jiǎn)單的,還有二級(jí)指針和多級(jí)指針,更繞、更難理解,接下來(lái)介紹一下二級(jí)指針。
在講二級(jí)指針前,我們是否有疑問(wèn):什么是一級(jí)指針?什么是二級(jí)指針呢??jī)烧哂惺裁磪^(qū)別呢?
一級(jí)指針存儲(chǔ)變量的地址,通過(guò)這個(gè)地址"直接獲取"變量的數(shù)據(jù)。二級(jí)指針存儲(chǔ)一級(jí)指針的地址,二級(jí)指針通過(guò)一級(jí)指針"間接獲取"獲取變量的數(shù)據(jù)。多級(jí)指針以此類(lèi)推,個(gè)人理解,講的不對(duì)歡迎指正。
再堅(jiān)持一下,精彩在"下面"?。?![/滑稽]
“指針的指針”也就是我們俗稱(chēng)的二級(jí)指針。
什么是“指針的指針”,例如下面代碼:
char a = 5; char * p1 = &a; char ** p2= &p1; printf("*p=%d,**p2=%d\n",*p1,**p2); // 輸出:*p1=5,**p2=5
通過(guò)畫(huà)圖來(lái)理解:
多級(jí)指針也就是指針的指針的指針.....,以此類(lèi)推即可。
指針運(yùn)算是根據(jù)指針的類(lèi)型不同而進(jìn)行運(yùn)算的,因類(lèi)型的不同,在加1/減1操作時(shí),內(nèi)存分配的空間也不同。
又拿int類(lèi)型和char類(lèi)型來(lái)作比較,代碼如下:
char類(lèi)型+1:從輸出結(jié)果可以看出地址是遞增1的,正符合char類(lèi)型占一個(gè)字節(jié)的說(shuō)法。
char c = 'h'; char *a = &c; for (int i=0;i<3;i++){ printf("a+1=0x%p\n",a + i); } -------------------------------- 輸出結(jié)果: a+1=0x000000000062FE0F a+1=0x000000000062FE10 a+1=0x000000000062FE11
int類(lèi)型+1:輸出的地址之間相差為4,正是int類(lèi)型占據(jù)空間。
int c = 259; int *a = &c; for (int i=0;i<3;i++){ printf("a+1=0x%p\n",a + i); } -------------------------------- 輸出結(jié)果: a+1=0x000000000062FE0C a+1=0x000000000062FE10 a+1=0x000000000062FE14
char類(lèi)型和int類(lèi)型分別+1在內(nèi)存中地址分配,如圖:
指針就介紹到這里,這只是指針的基礎(chǔ),還有數(shù)組指針、指針數(shù)組、null指針、void指針等等知識(shí),還需要學(xué)習(xí),后續(xù)繼續(xù)更新。
以上有不恰當(dāng)或者講得不對(duì)的地方,希望各位留言指正,謝謝!
站在巨人的肩膀上!
總結(jié)
以上所述是小編給大家介紹的C語(yǔ)言指針及占據(jù)內(nèi)存空間,希望對(duì)大家有所幫助!
免責(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)容。