學(xué)習(xí)C語言指針應(yīng)注意的幾個(gè)問題
摘要:指針是C語言中的一個(gè)重要概念。指針的引入增強(qiáng)了C語言的靈活性和高效性,同時(shí)由于指針的用法過于靈活也使得初學(xué)者經(jīng)常感到難以駕馭,甚至經(jīng)常出現(xiàn)理解錯(cuò)誤和應(yīng)用錯(cuò)誤。本文對(duì)學(xué)習(xí)C語言指針應(yīng)注意的幾個(gè)問題進(jìn)行了探討。
關(guān)鍵詞:指針 C語言 空指針
指針的引入增強(qiáng)了C語言的靈活性和高效性,同時(shí)由于指針的用法過于靈活也使得初學(xué)者經(jīng)常感到難以駕馭,甚至經(jīng)常出現(xiàn)理解錯(cuò)誤和應(yīng)用錯(cuò)誤。筆者認(rèn)為初學(xué)C語言指針應(yīng)注意以下幾個(gè)問題。
一、正確理解定義指針基類型的必要性
指針變量是存放地址的,但在定義指針變量時(shí)必須指明其基類型。例如:對(duì)指針變量p的定義(char * p;)這里的char即是指針變量p的基類型,也就是說定義p為指向字符型數(shù)據(jù)的指針類型。
在定義指針時(shí)指明其基類型是非常有必要的。雖然C語言中允許定義通用指針類型(*void類型),但這種通用類型應(yīng)被理解為指向空類型的數(shù)據(jù)或不能指向確定類型的數(shù)據(jù),而不應(yīng)被理解成可以指向任何類型的數(shù)據(jù)。在具體使用通用類型的指針時(shí)一般要通過顯式強(qiáng)制類型轉(zhuǎn)換將其轉(zhuǎn)換成一個(gè)有確定類型的指針。例如,在C語言中通常利用malloc函數(shù)(該函數(shù)的原型為:void* malloc(unsigned int size);)來實(shí)現(xiàn)內(nèi)存的動(dòng)態(tài)分配。該函數(shù)的返回值就是一個(gè)通用型指針,該指針不指向任何特定數(shù)據(jù)類型的數(shù)據(jù),它只是返回malloc函數(shù)所分配的內(nèi)存空間的第一個(gè)字節(jié)的地址。在真正利用這段內(nèi)存空間存儲(chǔ)數(shù)據(jù)時(shí),一般還要通過顯式強(qiáng)制類型轉(zhuǎn)換將其轉(zhuǎn)換成一個(gè)有確定類型的指針,例如:p=(int*)malloc(100*sizeof(int)),這樣就在內(nèi)存中開辟出了能存放100個(gè)整型數(shù)字的空間,而基類型為整型的指針p指向這段內(nèi)存空間的第一個(gè)字節(jié)。
C語言初學(xué)者普遍存在一個(gè)疑惑,那就是既然指針變量中存放的是內(nèi)存地址,為什么還要設(shè)定類型,內(nèi)存地址只不過是一個(gè)數(shù)字難道還有類型之分嗎?必須為指針變量設(shè)定類型的原因有二。(1)不同數(shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中占據(jù)的存儲(chǔ)空間的大小不同,比如一個(gè)整型數(shù)需要占用4個(gè)字節(jié)而一個(gè)字符只需占用1個(gè)字節(jié)。如果不指定指針的類型,通過指針引用該指針?biāo)赶虻淖兞繒r(shí),就無從知道應(yīng)該取從該指針?biāo)赶虻膬?nèi)存地址開始的幾個(gè)字節(jié)的數(shù)據(jù);(2)在指針進(jìn)行加減運(yùn)算時(shí),如果不指定指針的類型,就無法判斷指針具體應(yīng)該加減的數(shù)值。例如int * p;p++;這里指針p的值加1,實(shí)際上意味著指針p中存儲(chǔ)的地址值要加4,因?yàn)橐粋(gè)整型數(shù)在內(nèi)存中要占據(jù)4個(gè)字節(jié)的存儲(chǔ)空間。這里如果不指定指針p的類型,就無法判斷指針p中存儲(chǔ)的地址值具體應(yīng)該加減的數(shù)值。
二、正確理解空指針
空指針不指向任何對(duì)象。應(yīng)特別注意空指針并不是指*void類型(通用指針類型)的指針。把一個(gè)指針定義為空指針通常采用給其賦值為NULL的方式(例如int * p;p=NULL;)。在使用malloc函數(shù)動(dòng)態(tài)分配內(nèi)存時(shí),如果返回值是NULL則意味著該函數(shù)執(zhí)行失敗,原因一般是由于內(nèi)存空間不足,無法分配malloc函數(shù)所要求數(shù)量的內(nèi)存空間(例如:int * p;p=(int*)malloc(1000000000000*sizeof(int));)。
NULL的本質(zhì)即為常數(shù)0,在C語言編譯器的頭文件stdio.h或stddef.h中把NULL以宏的形式定義為常數(shù)0,也就是說int*p;p=NULL;與int*p;p=0;是等效的。
在C語言中對(duì)一個(gè)值為NULL的指針變量進(jìn)行間接訪問操作是非法的。例如,運(yùn)行如下程序由于對(duì)值為NULL的指針變量進(jìn)行了間接訪問,將會(huì)導(dǎo)致程序終止。
#include
void main()
{int*p; p=NULL; printf("%d",*p);}
三、注意指針變量賦值的類型匹配原則
對(duì)任何類型的變量賦值都應(yīng)遵循類型匹配的原則,給指針變量進(jìn)行賦值時(shí)賦值運(yùn)算符兩邊的類型往往不容易準(zhǔn)確辨識(shí),所以更容易犯賦值類型不匹配的錯(cuò)誤,故而在對(duì)指針變量進(jìn)行賦值時(shí)應(yīng)認(rèn)真檢查賦值運(yùn)算符左右兩側(cè)類型是否匹配。例如int*p,a[10];p=&a;中a作為數(shù)組名本身就代表數(shù)組首元素的地址即&a[0],在a前由加了一個(gè)去地址符&就導(dǎo)致表達(dá)式p=&a;賦值運(yùn)算符左右兩側(cè)類型不匹配。
另外需要注意雖然指針變量是存放地址值的,但不可以將具體的數(shù)字賦值給指針變量,例如int*p,p=0x1234cdef;在編譯時(shí)會(huì)給出“cannot convert from 'const int' to 'int *'”的錯(cuò)誤提示。但有一個(gè)例外,可以將0賦值給指針變量,例如int*p, p=0;,這里是將p定義為空指針,以上語句相當(dāng)于int*p, p=NULL;。
參考 文獻(xiàn):
[1] Kenneth A. Reek著,許波譯.C和指針[M].北京:人民郵電出版社,2008.
[2] 譚浩強(qiáng).C程序設(shè)計(jì)(第四版)[M].北京:清華大學(xué)出版社,2010.