摘 要:指針是c語(yǔ)言的精華,拋開(kāi)指針的C語(yǔ)言是沒(méi)有生命力的。雖然如雷貫耳的Joel Spolsky曾說(shuō)過(guò)對(duì)指針的理解是一種天賦,不是通過(guò)訓(xùn)練就可以達(dá)到的。但鑒于其重要性和學(xué)生學(xué)習(xí)中關(guān)于該內(nèi)容理解程度普遍低下的不幸事實(shí),我認(rèn)為深入理解指針的本質(zhì)含義,對(duì)我們編寫(xiě)程序還是有很大幫助的。筆者從幾個(gè)方面來(lái)剖析指針的本質(zhì),并著重圍繞指針的一個(gè)重要應(yīng)用——?jiǎng)討B(tài)分配內(nèi)存來(lái)談?wù)勅绾位乇艹R?jiàn)錯(cuò)誤,形成科學(xué)正確的編程習(xí)慣。
關(guān)鍵詞:C語(yǔ)言;指針;應(yīng)用規(guī)律
1 C語(yǔ)言指針中的兩個(gè)概念區(qū)分
⑴數(shù)組指針和指針數(shù)組。指向數(shù)組的指針?lè)Q為數(shù)組指針,數(shù)組的特點(diǎn)是數(shù)組中每個(gè)元素類(lèi)型相同,且在內(nèi)存中連續(xù)存放,只要數(shù)組指針向一個(gè)成員,則可順次推算出其余成員的地址,因此通過(guò)數(shù)組指針可將數(shù)組中的所有元素間接訪問(wèn);指針數(shù)組是指一組類(lèi)型相同的指針組成的數(shù)組,其與數(shù)組指針最大的不同是,指針數(shù)組在指針的數(shù)量上有所改變,它由一個(gè)指針演變到一組同類(lèi)指針。
⑵指針函數(shù)與函數(shù)指針。指針函數(shù)是返回值為指針的函數(shù),指針函數(shù)打破了其它高級(jí)語(yǔ)言中的指針、數(shù)組不能作為返回值的局限,體現(xiàn)了C語(yǔ)言程序的靈活性。值得注意的是,若使用變量的地址作為函數(shù)的返回值,此地址所對(duì)應(yīng)的變量空間如果被釋放,其中的數(shù)據(jù)可能發(fā)生了變化,那么就不能達(dá)到正常的傳送數(shù)據(jù)的目的,另外在使用指針函數(shù)時(shí),接受函數(shù)值的變量也必須為指針,且應(yīng)與返回值的類(lèi)型相同。指針變量可以指向整型變量、字符串變量、也可以指向函數(shù)的入口地址和指針為函數(shù)指針。函數(shù)指針是一個(gè)高深的概念,函數(shù)指針的作用是函數(shù)間傳遞函數(shù),指針函數(shù)與函數(shù)指針的相似之處在于兩者都跟函數(shù)有關(guān),不同之處在于指針函數(shù)中的指針指向函數(shù)出口,而函數(shù)指針中的指針指向函數(shù)入口,二者指向方向的差異是兩者間的最大區(qū)別。
2 指針一些主要應(yīng)用的基本規(guī)律
我們已經(jīng)看到,所謂指針的概念跟內(nèi)存有著緊密的聯(lián)系。對(duì)指針的理解,本質(zhì)上是對(duì)內(nèi)存的理解,畢竟內(nèi)存是生命空間。而指針的一些主要應(yīng)用,也的確凸現(xiàn)了這一點(diǎn),讓無(wú)數(shù)學(xué)生頭痛不已的鏈表,結(jié)合一些內(nèi)存相關(guān)函數(shù),指針游走于內(nèi)存當(dāng)中,充分地表現(xiàn)自己。
⑴定義指針后,必須將其初始化。可以用做給指針變量初始化的有變量的地址,另一個(gè)指針變量,數(shù)組名,函數(shù)名等。需要注意的是動(dòng)態(tài)內(nèi)存分配時(shí),使用之前將其初始化為NULL。
指針在定義之后,如果沒(méi)有明確賦值,那么和其他變量類(lèi)似,其內(nèi)部的地址值是隨機(jī)的。此時(shí)指針指向的空間中的數(shù)據(jù)意義是不可預(yù)測(cè)的,一般成為野指針。我們知道在C語(yǔ)言中,指針是可以指向CPU可訪問(wèn)內(nèi)存的任意位置,這客觀上造成了錯(cuò)誤地指向系統(tǒng)數(shù)據(jù)或其他有用數(shù)據(jù)的可能。而且C語(yǔ)言一般不做諸如數(shù)組越界或野指針的檢查。NULL在一般的編譯器中都都在某編譯系統(tǒng)的頭文件的中做了宏定義,通常情況下被定義為0L。0L的含義是:“值為0的整數(shù)常量表達(dá)式”。大多數(shù)操作系統(tǒng)將0L開(kāi)始的一段內(nèi)存預(yù)留出來(lái)做為無(wú)用的空間,指針在沒(méi)有明確使用的情況下指向此處,可以保護(hù)系統(tǒng)。
⑵如果利用指針動(dòng)態(tài)申請(qǐng)內(nèi)存,使用過(guò)后注意釋放內(nèi)存,否則會(huì)造成內(nèi)存泄漏。程序的內(nèi)存空間一般分為四個(gè)邏輯區(qū)域,即代碼區(qū)、全局?jǐn)?shù)據(jù)區(qū)、棧區(qū)和堆區(qū)。當(dāng)程序執(zhí)行的時(shí)候,其可執(zhí)行文件作為二進(jìn)制機(jī)器指令被調(diào)入內(nèi)存順序存放,以實(shí)現(xiàn)所謂的自動(dòng)執(zhí)行。棧區(qū)主要是函數(shù)調(diào)用的活動(dòng)區(qū)域,為函數(shù)分配局部動(dòng)態(tài)變量等,函數(shù)調(diào)用結(jié)束后系統(tǒng)會(huì)自動(dòng)收回內(nèi)存。全局?jǐn)?shù)據(jù)區(qū)存放的是靜態(tài)和全局變量,隨著程序的消亡而自動(dòng)收收回內(nèi)存。一般我們常說(shuō)的內(nèi)存泄漏是指堆內(nèi)存的泄漏。堆內(nèi)存是指程序從堆區(qū)中分配的,大小任意的(內(nèi)存塊的大小可以在程序運(yùn)行期決定),是由程序員自己需要時(shí)申請(qǐng),使用完后也必須用程序代碼顯式釋放的內(nèi)存。應(yīng)用程序一般使用mal-loc,realloc,new等函數(shù)從堆中分配到一塊內(nèi)存(通過(guò)指針變量記錄 該段內(nèi)存的首地址來(lái)實(shí)現(xiàn)),使用完后,程序必須負(fù)責(zé)相應(yīng)的調(diào)用free或delete釋放該內(nèi)存塊,否則,這塊內(nèi)存就不能被再次使用,我們就說(shuō)這塊內(nèi)存泄漏了。使用指針時(shí),在賦值等重要操作之前要注意觀察指針的當(dāng)前指向, 做適當(dāng)?shù)娘@式判斷,動(dòng)態(tài)申請(qǐng)內(nèi)存塊,尤其要保留其指針初值,以便釋放內(nèi)存。
如下列代碼段:
如果缺少free(str)語(yǔ)句,將造成1000個(gè)字節(jié)的堆內(nèi)存泄漏。引起內(nèi)存泄漏的主要原因在于內(nèi)存分配后指向內(nèi)存的指針丟失了。在堆里動(dòng)態(tài)申請(qǐng)內(nèi)存以后,如果擅自修改指針的指向,就會(huì)早成野指針而迷失方向,無(wú)法回收內(nèi)存,引起泄漏。
⑶指針?biāo)赶虻膬?nèi)存回收以后,也要清除指針,安全起見(jiàn)將其重置為NULL。
如下列代碼段:
如果缺少語(yǔ)句str=NULL,后果無(wú)法預(yù)料,極度危險(xiǎn)。因?yàn)閒ree(str):之后,str成為野指針,其指向不明,if(str!=NULL)語(yǔ)句不起作用。此時(shí),str指向的存儲(chǔ)區(qū)里是什么?我們不知道。它有可能是一個(gè)非常重要的數(shù)據(jù),甚至可能是一條程序源代碼(指針指向代碼區(qū)某段)。如果此時(shí)指針不幸指向系統(tǒng)核心數(shù)據(jù)區(qū),給它賦值一個(gè)字符串“word”,將會(huì)引起整個(gè)計(jì)算機(jī)系統(tǒng)崩潰。在用指針訪問(wèn)數(shù)組的時(shí)候,也要注意不要超出數(shù)組的低端和高端界限,否則也會(huì)造成類(lèi)似的錯(cuò)誤。
[參考文獻(xiàn)]
[1]譚浩強(qiáng).C語(yǔ)言程序設(shè)計(jì)[M].北京:清華大學(xué)出版社,1999.
[2]趙森,李卓民.C程序設(shè)計(jì)[M].北京:冶金工業(yè)出版社,2005.