對C指針的深入理解

指針是一片內存開始的地址,但是定義指針的時候卻往往要加上類型。

例如:int *p;

而且指針指向的數據的類型和聲明還要匹配(C標準不匹配可以編譯通過且可以運行;C++標準不匹配編譯報錯)。

於是就激發了我研究爲何要這樣規定的興趣。經過研究和實驗,發現了原因,並且也加深了對指針的理解!!!

下面一一道來。


先上結論:聲明指針所指向的數據的類型,其實就是告訴計算機一次讀多少字節以及如何解析這些數據。

例如:char *p,當你調用*p的時候,計算機會去找p所存的地址,由於聲明的是char,所以只會讀取一個字節,並且按照char進行解析數據;

例如:int *p,當你調用*p的時候,計算機會去找p所存的地址,由於聲明的是int,所以依次往下讀取四個字節,並且按照int進行解析數據;

例如:float *p,當你調用*p的時候,計算機會去找p所存的地址,由於聲明的是float,所以依次往下讀取四個字節,並且按照float對數據解析;(注意:雖然int和float都是4字節,但由於對數據的解析形式不同,因此不能混用)

例如:double *p,當你調用*p的時候,計算機會去找p所存的地址,由於聲明的是double,所以依次往下讀取八個字節,並且按照double對數據解析;

。。。。。。以此類推~~~


結論看着好像很簡單,其實裏面有很多耐人尋味、值得挖掘的東西!!!細看下文。


以下實驗均在win8-64位系統下虛擬機中的XP系統中進行,IDE爲VS2010版。


這個我們可以看到,char/int/double分別佔1/4/8個字節,而指針,無論指向什麼類型,都是佔4個字節。


【char】


看上面代碼以及運行情況!

(注意代碼的第7行,沒有寫成char **pp=&p,故意寫成char *pp=&p!要想編譯通過,需要把文件後綴名改爲.c



     ch  chx     ppp


他們的內存圖如下圖所示


ch和chx都是佔1個字節,存放A和B,p中此時存放ch的地址,pp中此時存放p的地址


然後把代碼中的註釋打開,繼續運行,得到下圖結果




代碼乍一看是錯的,但是結果以及內存分析來看,似乎又是正確的。~~~


再看一張圖


按%x打印*pp,此時沒有打印0x0012ff57,而僅僅打印了57,這點對下面的分析很重要。!

原因分析:在執行賦值語句*pp=&chx時,由於*pp是指向char類型,所以在執行*pp時只會讀取一個字節(這點很重要),*pp的值爲0x0012ff63,所以只讀取到了63而已,剩下的0012ff沒有讀到。而等式右邊&chx=0x0012ff57,用這個值給*pp也就是63賦值,會丟掉0x0012ff,僅僅把57賦值給63。此時指針p中存儲的值恰好就是0x0012ff63。此時p恰好可以正確指向chx,因此出現了正確的結果。很顯然,這是一種巧合(因爲chx的地址爲0x0012ff57,p的值一開始爲0x12ff63,兩者只有最低位的一個字節不一樣而已!)。

這一組拿的char做測試,下面咱拿int試試看!分析同理。


【int】

這次圖一起上



db1db2 p pp



結果也是正確的!

分析同char。這次指針指向一個int型,int型佔4個字節,剛好跟地址所佔的字節數相同,所以此時結果正確是一定的,而沒有那麼巧合(char類型時經過分析,只有當地址的最低位不同時纔會出現正確結果,而int則沒有這個問題)。


【double】

下面再來看double型




此時報錯啦!

爲什麼呢?請轉到本文一開始黑體字部分:

【“例如:double *p,當你調用*p的時候,計算機會去找p所存的地址,由於聲明的是double,所以依次往下讀取八個字節,並且按照double對數據解析;”】

出錯就出錯在這一句:*pp=&db2;

pp指向double型,8個字節;&db2是一個地址,4個字節。當你寫出*pp時,會去找pp所存地址的內存單元,然後往下讀取8個字節。而此時&db2只有4個字節。我本來要讀8個,你只給我了4個,當然報錯啦!(char的時候是,我要讀1個,你給我了4個,那我就讀最低位那個好了)。



最後上一個比較有意思的實驗




這個實驗也印證了前面的分析!


【寫在最後】指針博大精深,今天領教到了!!!

發佈了23 篇原創文章 · 獲贊 63 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章