C語(yǔ)言中為什么要設(shè)計(jì)指針這個(gè)東西,這個(gè)東西的設(shè)計(jì)原理是什么,本來(lái)就是個(gè)很簡(jiǎn)單的東西,小學(xué)生思維就夠了。還有,這些原理之類(lèi)的,對(duì)于使用C來(lái)編程的人來(lái)說(shuō),也是必須完全了解的,了解的深度與你編程時(shí)的輕松度密切相關(guān),所以,弄清這個(gè)對(duì)你很重要。
總有人在問(wèn)指針是干什么用的,那我先說(shuō)說(shuō)我的理解:獲取某個(gè)數(shù)據(jù)所在單元的地址值,由此推算出其它數(shù)據(jù)所在單元的地址值,以用于找到這個(gè)數(shù)據(jù)所在的存儲(chǔ)位置。 計(jì)算機(jī)編程,可以說(shuō),基本就是對(duì)存于存儲(chǔ)器中的數(shù)據(jù)進(jìn)行操作,這就牽扯到一個(gè)最重要的問(wèn)題:你現(xiàn)在要操作的數(shù)據(jù),存在哪個(gè)地方? 想要弄清這個(gè)問(wèn)題,最根本的方法,是了解芯片的設(shè)計(jì)和工作基本原理與基本結(jié)構(gòu)組成。當(dāng)然,如果知道存儲(chǔ)器的大概結(jié)構(gòu),也算是有了一個(gè)基礎(chǔ)。這里我不講這么多,因?yàn)閷W(xué)單片機(jī)的人,基本的知識(shí)應(yīng)該還是有的,不是那種不與硬件打交道的程序員,所以不需我多講。
C與匯編有兩個(gè)根本的區(qū)別,造成了C中指針的產(chǎn)生:一個(gè)是數(shù)據(jù)所存儲(chǔ)的地址是由C編輯器自動(dòng)分配的,程序員沒(méi)自主權(quán),所以一個(gè)數(shù)據(jù)存儲(chǔ)的地址,程序員是不知道的;二是C編程中所用到的數(shù)據(jù)的長(zhǎng)度與存儲(chǔ)單元容量的不一致導(dǎo)致一個(gè)數(shù)據(jù)可能會(huì)占據(jù)數(shù)個(gè)存儲(chǔ)單元,由此造成數(shù)據(jù)存儲(chǔ)地址值的不連續(xù),這個(gè)現(xiàn)象造成的原因在于,不管你是8位機(jī)、16位機(jī)還是其它位機(jī),一個(gè)存儲(chǔ)單元的位數(shù)都是8位,這個(gè)是芯片設(shè)計(jì)就如此,原因自然主要是兼容問(wèn)題而不得不做出的選擇。本段所述的現(xiàn)象,在下面的比喻之中會(huì)進(jìn)行解釋。
用C語(yǔ)言編寫(xiě)的程序,在程序運(yùn)行中,你所要處理的數(shù)據(jù)存在哪,你是必須知道的,否則你找不到這個(gè)數(shù)據(jù)在哪,你的程序就沒(méi)法編下去了;如果你把數(shù)據(jù)所在的位置給弄錯(cuò)了,那這個(gè)程序在運(yùn)行中就得不到你想要的結(jié)果。
有關(guān)數(shù)據(jù)存在哪,及如何找到這個(gè)位置,我打如下一個(gè)比方: 我們知道,賓館的房間都是有編號(hào)的,而且是用數(shù)字來(lái)編寫(xiě)的,很統(tǒng)一,一個(gè)房間一個(gè)編號(hào);每個(gè)房間的大小都是一樣的,也就是說(shuō)其容量是一樣的。賓館來(lái)了一家一家的,住哪間?賓館前臺(tái)來(lái)安排,一家人數(shù)少,可能就是一間,人數(shù)多了,可能就得幾間了,也就是說(shuō),同樣是一家,可能他只占據(jù)一個(gè)房間編號(hào),也有可能占據(jù)數(shù)個(gè)房間編號(hào)(這就造成了地址編號(hào)的不連續(xù)),這個(gè)數(shù)據(jù),只有前臺(tái)知道。如果你想去找到哪一家,你怎么找?你一個(gè)房間一個(gè)房間地去看單子也好看現(xiàn)場(chǎng)也好,都不是個(gè)辦法,一般情況下,每一家都是有個(gè)名字的,如張家、李家、王家、陳家等等的,你告訴前臺(tái),前臺(tái)根據(jù)這個(gè)名字查一下,就會(huì)把這家的第一個(gè)房間的編號(hào)(首地址)給了你,而你在事先知道他們家人數(shù)及賓館每間房能住的人數(shù)的情況下,也就知道了他們家占幾間房。這個(gè)比方里,與C語(yǔ)言中的情況極其相似,就是存儲(chǔ)內(nèi)容物的位置都是用統(tǒng)一數(shù)字編號(hào)來(lái)標(biāo)識(shí)的,存儲(chǔ)內(nèi)容的每一個(gè)單元(房間)的容量都是固定一致的,每一個(gè)(組)數(shù)據(jù)(一個(gè)家庭)都是有一個(gè)名字的,單個(gè)數(shù)據(jù)的長(zhǎng)度(某個(gè)家庭人數(shù))你事先是知道的,內(nèi)容物的存儲(chǔ)位置分配是由他人分配而你事先是不知道的,其占據(jù)幾個(gè)存儲(chǔ)單元數(shù)量你是事先知道的。
同樣的原理,在C語(yǔ)言中,要找到一個(gè)數(shù)據(jù)的首地址,我們先要把這個(gè)數(shù)據(jù)的名字給編輯器(前臺(tái)),編輯器就會(huì)依據(jù)這個(gè)名字把這個(gè)數(shù)據(jù)存儲(chǔ)單元的首地址給你,這個(gè)動(dòng)作,就是在這個(gè)數(shù)據(jù)的名字前面加一個(gè)“&”,其首地址值就出來(lái)了。 然后這里就又有了一個(gè)問(wèn)題,這個(gè)查出的地址值,放在什么地方?賓館是可以將地址值寫(xiě)在紙上,那計(jì)算機(jī)呢?它能放這個(gè)數(shù)據(jù)的地方,還是只有存儲(chǔ)器,當(dāng)然,你也可以為存儲(chǔ)這些個(gè)地址而單獨(dú)在芯片中設(shè)計(jì)一個(gè)專(zhuān)門(mén)的區(qū)域,那你可以算是創(chuàng)新,但是,現(xiàn)有的芯片怎么辦?沒(méi)辦法,還是只能存于現(xiàn)有的存儲(chǔ)器之中,于是,C編輯器還得給一個(gè)房間(存儲(chǔ)單元)專(zhuān)門(mén)用于存儲(chǔ)這個(gè)地址值,然后,這個(gè)單元編號(hào)是多少?程序員又不知道了,因?yàn)橛质蔷庉嬈髯詣?dòng)分配的,所以,沒(méi)法,又得給這個(gè)取個(gè)名字以便查找利用,所以,在將要存入的內(nèi)容存入之前,得先對(duì)要存入的內(nèi)容進(jìn)行定義(取名)一個(gè)變量,這樣我們以后就可以用名字直接找到這個(gè)內(nèi)容了。
下面就談?wù)?/font>C中有關(guān)獲取地址與使用地址的一些規(guī)則,有關(guān)這個(gè)概念的名詞,現(xiàn)有教材都稱(chēng)之為指針,本人對(duì)這個(gè)名詞比較不感冒,這個(gè)名詞顯然沒(méi)能與“地址”一詞緊密聯(lián)系,于是不易理解不易記。ìF(xiàn)有計(jì)算機(jī)教材中,類(lèi)似槽點(diǎn)很多): 存放入單元的內(nèi)容要要先取個(gè)名字,也就是所謂的定義(前面已經(jīng)解釋過(guò)),這個(gè)因?yàn)橹羔樧兞康墓δ懿煌,所以定義變量名時(shí),也要給出區(qū)別,讓編輯器知道這個(gè)變量的用途,也讓讀程序的人知道這個(gè)變量是用于存儲(chǔ)地址的,也就是所謂的指針變量。其進(jìn)行區(qū)別的規(guī)則是變量名前面加一個(gè)“*”以示區(qū)別,如果不加會(huì)怎么樣?你照樣可以將取得的地址值存入其中,但是,你用這個(gè)變量去取這個(gè)地址所指向數(shù)據(jù)時(shí),程序在編譯時(shí)就報(bào)錯(cuò)了,這個(gè)現(xiàn)象,只是編輯器的硬性規(guī)定,也是有道理的。其實(shí)編輯器在分配指針變量在存儲(chǔ)器中的位置時(shí),也沒(méi)做什么特殊處理,它與其它變量都是統(tǒng)一分配地址的,基本也是順序分配,誰(shuí)先使用誰(shuí)先排前面(不是誰(shuí)先定義誰(shuí)先排前面),一點(diǎn)也不特殊。
在使用指針來(lái)取得存儲(chǔ)單元中的數(shù)據(jù)時(shí),C的規(guī)定也是在指針變量名前加一個(gè)“*”以示這個(gè)是用地址值來(lái)取得數(shù)據(jù),如a=*p,它的含意是:P所表示的存儲(chǔ)單元中的數(shù)據(jù),是一個(gè)地址值,a=*p就是把這個(gè)地址值所指向的單元中的數(shù)據(jù)送給a。其實(shí)吧,個(gè)人覺(jué)得這個(gè)“*”符號(hào)用得不好,改為“@”可能更讓人容易理解,這個(gè)“@”有“在”的意思,然后我們就可以理解為“把在這個(gè)p值所指向的單元中的值,把它給a”。如果是這樣,很多運(yùn)算公式就很容易理解了,如@p++就是操作“在”p值為地址所指向的單元中的數(shù)據(jù),這個(gè)具體操作就是將其加1,而p++就是p值加1個(gè)數(shù)據(jù)長(zhǎng)度值以將p值變?yōu)橄乱粋(gè)數(shù)據(jù)的地址值(不是地址值本身直接增加1,這個(gè)在后面再解釋?zhuān),也就是說(shuō),只要在p前面加了@,那要操作的對(duì)象就并不是p本身,而是它所指向的單元,這個(gè)一定要牢記不是操作p本身,這樣你在編程時(shí)就不容易出錯(cuò)了。
指針變量是可以直接賦一個(gè)常量值的,但是,這個(gè)值必須是你所要用到的單元的地址值,如果不是,程序編譯時(shí)不會(huì)報(bào)錯(cuò),但程序運(yùn)行時(shí)肯定是亂了,也就是說(shuō),前提是你知道這個(gè)數(shù)據(jù)的絕對(duì)地址值。
接下來(lái)的一個(gè)問(wèn)題,就是指針變量的長(zhǎng)度,既然是表示地址,那它就是一個(gè)沒(méi)有負(fù)號(hào)的整數(shù),其長(zhǎng)度最長(zhǎng)也就是存儲(chǔ)器地址值的長(zhǎng)度,如51機(jī)的RAM,其地址就只有八位,所以,在定義時(shí),它的指針長(zhǎng)度也就一個(gè)單元,多了浪費(fèi)。 還有一個(gè)規(guī)則,指針變量的加減運(yùn)算,是與其所指向的數(shù)據(jù)的長(zhǎng)度綁定的,這個(gè)是在編譯處理時(shí)用到的,意思是其盡管這個(gè)指針變量也是一個(gè)數(shù)據(jù),但它在做加減運(yùn)算時(shí),例如p=p+1,并不是p值直接加1,而是加一個(gè)其所指向的數(shù)據(jù)的長(zhǎng)度址,以直接變?yōu)橄乱粋(gè)數(shù)據(jù)的首地址值,這個(gè)處理,并不是在程序運(yùn)行中進(jìn)行的,而是在編譯時(shí)進(jìn)行的,所以指針變量在使用之前一定要先定義,定義之后,編輯器才會(huì)知道這個(gè)是個(gè)指針變量,然后這樣做處理。 還有一個(gè)教材中沒(méi)說(shuō)清楚的問(wèn)題,這個(gè)所謂的指針,到底是只針對(duì)RAM,還是包括ROM?這個(gè)有興趣的朋友可以研究一下,方法也不難。 以上所說(shuō),其實(shí)都可以用編輯器調(diào)試中的匯編窗口來(lái)證實(shí)。 以上純屬個(gè)人理解,如有錯(cuò)誤與不當(dāng),萬(wàn)請(qǐng)指出。
|