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