本文發(fā)布于微信公眾號(hào):三玹
昨天不知道是怎么回事,大抵上是腦子突然抽了,竟選了C語(yǔ)言中公認(rèn)難啃的硬骨頭——指針。一晚上,看了許多關(guān)于指針的內(nèi)容,好像懂了,但是到了今天,想要輸出文章的時(shí)候又總覺得不得要領(lǐng),于是又花了一些時(shí)間進(jìn)行研究。
沒有內(nèi)存,指針就沒有意義。因此,在學(xué)習(xí)指針之間,對(duì)內(nèi)存有一定的了解,是有助于指針的學(xué)習(xí)。學(xué)習(xí)過(guò)計(jì)算機(jī)原理的朋友應(yīng)該都知道,計(jì)算機(jī)主要由硬件和軟件組成的。硬件的五個(gè)主要組成的部分:控制器、運(yùn)算器、存儲(chǔ)器、輸入設(shè)備、輸出設(shè)備。而內(nèi)存,是屬于存儲(chǔ)器部分,顧名思義是用來(lái)存儲(chǔ)的一個(gè)硬件。
內(nèi)存不僅是用來(lái)存儲(chǔ)信息的,同時(shí)也承擔(dān)了構(gòu)建CPU和外部存儲(chǔ)器之間溝通橋梁的作用。這是因?yàn)橥獯嫦鄬?duì)于內(nèi)存,外存的讀寫速度會(huì)比較慢,而CPU的速度又是極快的,如果直接從硬盤拿數(shù)據(jù),就很浪費(fèi)CPU高速的運(yùn)算能力。前面在學(xué)習(xí)變量的時(shí)候,我們可以知道,每創(chuàng)建一個(gè)變量,都會(huì)在內(nèi)存開辟一個(gè)空間,空間大小根據(jù)變量聲明的類型決定。例如一個(gè)字符char類型,所占空間大小為 1 Byte;一個(gè)整型int類型,所占空間大小為 4 Byte。
每個(gè)空間都有一個(gè)自己的編號(hào),系統(tǒng)可以根據(jù)編號(hào)快速定位,從而拿到想要的數(shù)據(jù)。如果沒有這個(gè)編號(hào),計(jì)算機(jī)要怎么拿到相應(yīng)的數(shù)據(jù)?想象一下,一個(gè)外賣員送外賣,如果不知道你是第幾層第幾戶,那么就要一層一層,一家一戶地敲開門確認(rèn)。那就相當(dāng)麻煩。
這個(gè)編號(hào),就是內(nèi)存地址,也就是接下來(lái)我們要說(shuō)的指針。
之前說(shuō)過(guò),如果沒有變量名,就要記住內(nèi)存地址,而內(nèi)存地址都是十六進(jìn)制的一組數(shù)字,看起來(lái)非常抽象。對(duì)程序員來(lái)說(shuō),寫代碼沒有變量是一件極其痛苦的事情。但現(xiàn)在我們想知道這個(gè)變量對(duì)應(yīng)的內(nèi)存地址是什么,那該怎么找呢?
C語(yǔ)言中提供了尋址運(yùn)算符,&。在變量名前面加上這個(gè)尋址運(yùn)算符,就可以找到了變量對(duì)應(yīng)的內(nèi)存地址。#include<stdio.h>
int main(){
int a;
printf("%p", &a);
return 0;
}
由此可見,內(nèi)存地址也是一個(gè)數(shù)據(jù)。既然作為一個(gè)數(shù)據(jù),那么就可以使用變量將其存儲(chǔ)起來(lái)。而作為一個(gè)變量,是需要聲明其是屬于什么類型的變量。因此,就有了指針變量和指針類型。type* var;
type 即指針要指向的變量的數(shù)據(jù)類型,如int、double、char,或者后面會(huì)講到的void類型、構(gòu)造類型等;var 即指針的變量名。指針類型和其他類型最大的區(qū)別就是,不同類型的指針?biāo)加玫目臻g大小都是一樣的(32位CPU是 4 Byte,64位CPU是 8 Byte)。
既然所有類型的指針?biāo)伎臻g都是一樣的,那為什么還要區(qū)分指針的類型呢?這是因?yàn)橹羔樧兞看鎯?chǔ)的只是指向的變量的內(nèi)存地址,如果沒有區(qū)分類型,當(dāng)需要從內(nèi)存中取值的時(shí)候,系統(tǒng)就不知道你要從當(dāng)前指向的地址取幾個(gè)字節(jié)。如果字節(jié)數(shù)沒取好,那么取得的數(shù)據(jù)就會(huì)產(chǎn)生錯(cuò)誤。下面模擬一下如果沒有類型,任意取值的結(jié)果:#include<stdio.h>
int main(){
int a = 123456789;
char *p1 = (char*)&a;
printf("只取1個(gè)字節(jié)的值:%d\n", *p1);
short *p2 = (short*)&a;
printf("只取2個(gè)字節(jié)的值:%d\n", *p2);
int *p3 = &a;
printf("取了4個(gè)字節(jié)的值:%d", *p3);
return 0;
}
只取1個(gè)字節(jié)的值:21只取2個(gè)字節(jié)的值:-13035取了4個(gè)字節(jié)的值:123456789
指定了指針的類型,很大程度上給程序員解決了很多不必要的麻煩和問題。指針類型除了可以根據(jù)指向的變量的類型進(jìn)行分類,還有一種按級(jí)別分類,而這種分類我更愿意稱之為終極之無(wú)敵套娃。有一天,一個(gè)快遞員跟你說(shuō),你買的快遞已經(jīng)送達(dá)了,請(qǐng)注意簽收,然后發(fā)給你一個(gè)取件碼。于是,你拿著取件碼,來(lái)到快遞架,打開柜子,發(fā)現(xiàn)里面只有一張紙條,上面寫著:你的快遞放在了第3排第5個(gè)。你找到了紙條上的位置,打開一看,又是一張紙條,上面寫著:你的快遞放在了第8排第4個(gè)。緊接著你有按照上面說(shuō)的找到了相應(yīng)位置,打開柜子,總算是拿到了快遞了。這個(gè)比喻說(shuō)的就是一個(gè)二級(jí)指針。快遞架相當(dāng)于是內(nèi)存,每一個(gè)快遞柜子都是存儲(chǔ)單元。紙條上面的信息,即指向的內(nèi)存地址。快遞物件是想要數(shù)據(jù)。而你,就是計(jì)算機(jī)系統(tǒng)。由此可知,一級(jí)指針,存放著普通變量的內(nèi)存地址。二級(jí)指針,存放著一級(jí)指針的變量的內(nèi)存地址。這就和數(shù)據(jù)結(jié)構(gòu)的知識(shí)有關(guān)聯(lián)了,這部分就到后面有用到了再詳細(xì)展開。這會(huì)兒學(xué)習(xí)這些,純屬是為了自己找麻煩。本篇文章就講到了這里,關(guān)于指針的內(nèi)容也僅僅是淺嘗而止。下一篇文章就回歸輕松一點(diǎn)的知識(shí)點(diǎn),運(yùn)算符。最后,感謝各位朋友們的支持。如果有什么疑惑的地方或者文中謬誤之處,可以在評(píng)論指出一起討論學(xué)習(xí)。