App下載

從零開(kāi)始學(xué)習(xí)C語(yǔ)言丨淺談指針類型

三玹 2022-10-31 14:42:29 瀏覽數(shù) (1968)
反饋
原文: https://mp.weixin.qq.com/s?__biz=Mzg3OTc3MjcyOQ==&mid=2247483771&idx=1&sn=6ac2a45bcc2b4da37eda0b5e04619351&chksm=cf7e142df8099d3b8918c4dbf7bfe0328683ea20aab2d146f9a8afae5f1d18d1cf30208b3d06&scene=178&cur_album_id=2588823761982849025#rd

  本文發(fā)布于微信公眾號(hào):三玹
昨天不知道是怎么回事,大抵上是腦子突然抽了,竟選了C語(yǔ)言中公認(rèn)難啃的硬骨頭——指針。
一晚上,看了許多關(guān)于指針的內(nèi)容,好像懂了,但是到了今天,想要輸出文章的時(shí)候又總覺(jué)得不得要領(lǐng),于是又花了一些時(shí)間進(jìn)行研究。


內(nèi)存
沒(méi)有內(nèi)存,指針就沒(mé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)存,外存的讀寫(xiě)速度會(huì)比較慢,而CPU的速度又是極快的,如果直接從硬盤(pán)拿數(shù)據(jù),就很浪費(fèi)CPU高速的運(yùn)算能力。
前面在學(xué)習(xí)變量的時(shí)候,我們可以知道,每創(chuàng)建一個(gè)變量,都會(huì)在內(nèi)存開(kāi)辟一個(gè)空間,空間大小根據(jù)變量聲明的類型決定。例如一個(gè)字符char類型,所占空間大小為 1 Byte;一個(gè)整型int類型,所占空間大小為 4 Byte。
每個(gè)空間都有一個(gè)自己的編號(hào),系統(tǒng)可以根據(jù)編號(hào)快速定位,從而拿到想要的數(shù)據(jù)。如果沒(méi)有這個(gè)編號(hào),計(jì)算機(jī)要怎么拿到相應(yīng)的數(shù)據(jù)?想象一下,一個(gè)外賣員送外賣,如果不知道你是第幾層第幾戶,那么就要一層一層,一家一戶地敲開(kāi)門(mén)確認(rèn)。那就相當(dāng)麻煩。
這個(gè)編號(hào),就是內(nèi)存地址,也就是接下來(lái)我們要說(shuō)的指針。
指針
之前說(shuō)過(guò),如果沒(méi)有變量名,就要記住內(nèi)存地址,而內(nèi)存地址都是十六進(jìn)制的一組數(shù)字,看起來(lái)非常抽象。對(duì)程序員來(lái)說(shuō),寫(xiě)代碼沒(méi)有變量是一件極其痛苦的事情。
但現(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;
}
運(yùn)行結(jié)果:0061FF1C
由此可見(jiàn),內(nèi)存地址也是一個(gè)數(shù)據(jù)。既然作為一個(gè)數(shù)據(jù),那么就可以使用變量將其存儲(chǔ)起來(lái)。而作為一個(gè)變量,是需要聲明其是屬于什么類型的變量。因此,就有了指針變量和指針類型。
聲明一個(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)存地址,如果沒(méi)有區(qū)分類型,當(dāng)需要從內(nèi)存中取值的時(shí)候,系統(tǒng)就不知道你要從當(dāng)前指向的地址取幾個(gè)字節(jié)。如果字節(jié)數(shù)沒(méi)取好,那么取得的數(shù)據(jù)就會(huì)產(chǎn)生錯(cuò)誤。
下面模擬一下如果沒(méi)有類型,任意取值的結(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;
}
運(yùn)行結(jié)果:
只取1個(gè)字節(jié)的值:21只取2個(gè)字節(jié)的值:-13035取了4個(gè)字節(jié)的值:123456789
指定了指針的類型,很大程度上給程序員解決了很多不必要的麻煩和問(wèn)題。
指針類型除了可以根據(jù)指向的變量的類型進(jìn)行分類,還有一種按級(jí)別分類,而這種分類我更愿意稱之為終極之無(wú)敵套娃。
先來(lái)看一個(gè)比喻:
有一天,一個(gè)快遞員跟你說(shuō),你買(mǎi)的快遞已經(jīng)送達(dá)了,請(qǐng)注意簽收,然后發(fā)給你一個(gè)取件碼。于是,你拿著取件碼,來(lái)到快遞架,打開(kāi)柜子,發(fā)現(xiàn)里面只有一張紙條,上面寫(xiě)著:你的快遞放在了第3排第5個(gè)。
你找到了紙條上的位置,打開(kāi)一看,又是一張紙條,上面寫(xiě)著:你的快遞放在了第8排第4個(gè)。緊接著你有按照上面說(shuō)的找到了相應(yīng)位置,打開(kāi)柜子,總算是拿到了快遞了。
這個(gè)比喻說(shuō)的就是一個(gè)二級(jí)指針。
快遞架相當(dāng)于是內(nèi)存,每一個(gè)快遞柜子都是存儲(chǔ)單元。紙條上面的信息,即指向的內(nèi)存地址??爝f物件是想要數(shù)據(jù)。而你,就是計(jì)算機(jī)系統(tǒng)。
由此可知,一級(jí)指針,存放著普通變量的內(nèi)存地址。
二級(jí)指針,存放著一級(jí)指針的變量的內(nèi)存地址。
三級(jí)指針……
要這么多的套娃級(jí)別的指針是為了什么呢?
這就和數(shù)據(jù)結(jié)構(gòu)的知識(shí)有關(guān)聯(lián)了,這部分就到后面有用到了再詳細(xì)展開(kāi)。這會(huì)兒學(xué)習(xí)這些,純屬是為了自己找麻煩。
最后
本篇文章就講到了這里,關(guān)于指針的內(nèi)容也僅僅是淺嘗而止。下一篇文章就回歸輕松一點(diǎn)的知識(shí)點(diǎn),運(yùn)算符。
最后,感謝各位朋友們的支持。如果有什么疑惑的地方或者文中謬誤之處,可以在評(píng)論指出一起討論學(xué)習(xí)。
C

0 人點(diǎn)贊