為了正確地訪問內(nèi)存單元,必須為每個(gè)內(nèi)存單元編上號(hào)。根據(jù)一個(gè)內(nèi)存單元的編號(hào)即可準(zhǔn)確地找到該內(nèi)存單元。內(nèi)存單元的編號(hào)也叫做地址。既然根據(jù)內(nèi)存單元的編號(hào)或地址就可以找到所需的內(nèi)存單元,所以通常也把這個(gè)地址稱為指針。內(nèi)存單元的指針和內(nèi)存單元的內(nèi)容是兩個(gè)不同的概念。
對(duì)于一個(gè)內(nèi)存單元來說,單元的地址即為指針, 其中存放的數(shù)據(jù)才是該單元的內(nèi)容。在C語言中, 允許用一個(gè)變量來存放指針,這種變量稱為指針變量。因此, 一個(gè)指針變量的值就是某個(gè)內(nèi)存單元的地址或稱為某內(nèi)存單元的指針。
嚴(yán)格地說,一個(gè)指針是一個(gè)地址, 是一個(gè)常量。而一個(gè)指針變量卻可以被賦予不同的指針值,是變量。既然指針變量的值是一個(gè)地址,那么這個(gè)地址不僅可以是變量的地址,也可以是其它數(shù)據(jù)結(jié)構(gòu)的地址。在一個(gè)指針變量中存放一個(gè)數(shù)組或一個(gè)函數(shù)的首地址有何意義呢? 因?yàn)閿?shù)組或函數(shù)都是連續(xù)存放的。通過訪問指針變量取得了數(shù)組或函數(shù)的首地址, 也就找到了該數(shù)組或函數(shù)。這樣一來,凡是出現(xiàn)數(shù)組,函數(shù)的地方都可以用一個(gè)指針變量來表示,只要該指針變量中賦予數(shù)組或函數(shù)的首地址即可。這樣做,將會(huì)使程序的概念十分清楚,程序本身也精練,高效。在C語言中,一種數(shù)據(jù)類型或數(shù)據(jù)結(jié)構(gòu)往往都占有一組連續(xù)的內(nèi)存單元。 用“地址”這個(gè)概念并不能很好地描述一種數(shù)據(jù)類型或數(shù)據(jù)結(jié)構(gòu),而“指針”雖然實(shí)際上也是一個(gè)地址,但它卻是一個(gè)數(shù)據(jù)結(jié)構(gòu)的首地址,它是“指向”一個(gè)數(shù)據(jù)結(jié)構(gòu)的,因而概念更為清楚,表示更為明確。這也是引入“指針”概念的一個(gè)重要原因。
對(duì)指針變量的類型說明包括三個(gè)內(nèi)容:
(1)指針類型說明,即定義變量為一個(gè)指針變量;
(2)指針變量名;
(3)變量值(指針)所指向的變量的數(shù)據(jù)類型。
其一般形式為: 類型說明符 *變量名;
其中,*表示這是一個(gè)指針變量,變量名即為定義的指針變量名,類型說明符表示本指針變量所指向的變量的數(shù)據(jù)類型。
應(yīng)該注意的是,一個(gè)指針變量只能指向同類型的變量,如float *p只能指向浮點(diǎn)變量,不能時(shí)而指向一個(gè)浮點(diǎn)變量, 時(shí)而又指向一個(gè)字符變量。
指針變量同普通變量一樣,使用之前不僅要定義說明, 而且必須賦予具體的值。未經(jīng)賦值的指針變量不能使用, 否則將造成系統(tǒng)混亂,甚至死機(jī)。指針變量的賦值只能賦予地址, 決不能賦予任何其它數(shù)據(jù),否則將引起錯(cuò)誤。在C語言中, 變量的地址是由編譯系統(tǒng)分配的,對(duì)用戶完全透明,用戶不知道變量的具體地址。 C語言中提供了地址運(yùn)算符&來表示變量的地址。其一般形式為: & 變量名; 如&a變示變量a的地址,&b表示變量b的地址。 變量本身必須預(yù)先說明。
指針變量可以進(jìn)行某些運(yùn)算,但其運(yùn)算的種類是有限的。 它只能進(jìn)行賦值運(yùn)算和部分算術(shù)運(yùn)算及關(guān)系運(yùn)算。
1.指針運(yùn)算符
(1)取地址運(yùn)算符&
取地址運(yùn)算符&是單目運(yùn)算符,其結(jié)合性為自右至左,其功能是取變量的地址。
(2)取內(nèi)容運(yùn)算符*
取內(nèi)容運(yùn)算符*是單目運(yùn)算符,其結(jié)合性為自右至左,用來表示指針變量所指的變量。在*運(yùn)算符之后跟的變量必須是指針變量。需要注意的是指針運(yùn)算符*和指針變量說明中的指針說明符* 不是一回事。在指針變量說明中,“*”是類型說明符,表示其后的變量是指針類型。而表達(dá)式中出現(xiàn)的“*”則是一個(gè)運(yùn)算符用以表示指針變量所指的變量。
使用字符串指針變量與字符數(shù)組的區(qū)別
用字符數(shù)組和字符指針變量都可實(shí)現(xiàn)字符串的存儲(chǔ)和運(yùn)算。 但是兩者是有區(qū)別的。在使用時(shí)應(yīng)注意以下幾個(gè)問題:
1. 字符串指針變量本身是一個(gè)變量,用于存放字符串的首地址。而字符串本身是存放在以該首地址為首的一塊連續(xù)的內(nèi)存空間中并以‘\0’作為串的結(jié)束。字符數(shù)組是由于若干個(gè)數(shù)組元素組成的,它可用來存放整個(gè)字符串。
2. 對(duì)字符數(shù)組作初始化賦值,必須采用外部類型或靜態(tài)類型,如: static char st[]={“C Language”};而對(duì)字符串指針變量則無此限制,如: char *ps="C Language";
3. 對(duì)字符串指針方式 char *ps="C Language";可以寫為: char *ps; ps="C Language";而對(duì)數(shù)組方式:
static char st[]={"C Language"};
不能寫為:
char st[20];st={"C Language"};
而只能對(duì)字符數(shù)組的各元素逐個(gè)賦值。
從以上幾點(diǎn)可以看出字符串指針變量與字符數(shù)組在使用時(shí)的區(qū)別,同時(shí)也可看出使用指針變量更加方便。前面說過,當(dāng)一個(gè)指針變量在未取得確定地址前使用是危險(xiǎn)的,容易引起錯(cuò)誤。但是對(duì)指針變量直接賦值是可以的。因?yàn)镃系統(tǒng)對(duì)指針變量賦值時(shí)要給以確定的地址。因此,
char *ps="C Langage";
或者 char *ps;
ps="C Language";都是合法的。
函數(shù)指針變量
在C語言中規(guī)定,一個(gè)函數(shù)總是占用一段連續(xù)的內(nèi)存區(qū), 而函數(shù)名就是該函數(shù)所占內(nèi)存區(qū)的首地址。 我們可以把函數(shù)的這個(gè)首地址(或稱入口地址)賦予一個(gè)指針變量, 使該指針變量指向該函數(shù)。然后通過指針變量就可以找到并調(diào)用這個(gè)函數(shù)。 我們把這種指向函數(shù)的指針變量稱為“函數(shù)指針變量”。
函數(shù)指針變量定義的一般形式為:
類型說明符 (*指針變量名)();
其中“類型說明符”表示被指函數(shù)的返回值的類型。“(* 指針變量名)”表示“*”后面的變量是定義的指針變量。 最后的空括號(hào)表示指針變量所指的是一個(gè)函數(shù)。
使用函數(shù)指針變量還應(yīng)注意以下兩點(diǎn):
a. 函數(shù)指針變量不能進(jìn)行算術(shù)運(yùn)算,這是與數(shù)組指針變量不同的。數(shù)組指針變量加減一個(gè)整數(shù)可使指針移動(dòng)指向后面或前面的數(shù)組元素,而函數(shù)指針的移動(dòng)是毫無意義的。
b. 函數(shù)調(diào)用中"(*指針變量名)"的兩邊的括號(hào)不可少,其中的*不應(yīng)該理解為求值運(yùn)算,在此處它只是一種表示符號(hào)。
指針型函數(shù)
所謂函數(shù)類型是指函數(shù)返回值的類型。 在C語言中允許一個(gè)函數(shù)的返回值是一個(gè)指針(即地址), 這種返回指針值的函數(shù)稱為指針型函數(shù)。
定義指針型函數(shù)的一般形式為:
類型說明符 *函數(shù)名(形參表)
{
…… /*函數(shù)體*/
}
其中函數(shù)名之前加了“*”號(hào)表明這是一個(gè)指針型函數(shù),即返回值是一個(gè)指針。類型說明符表示了返回的指針值所指向的數(shù)據(jù)類型。
main函數(shù)可以帶參數(shù),這個(gè)參數(shù)可以認(rèn)為是 main函數(shù)的形式參數(shù)。C語言規(guī)定main函數(shù)的參數(shù)只能有兩個(gè), 習(xí)慣上這兩個(gè)參數(shù)寫為argc和argv。因此,main函數(shù)的函數(shù)頭可寫為: main (argc,argv)C語言還規(guī)定argc(第一個(gè)形參)必須是整型變量,argv( 第二個(gè)形參)必須是指向字符串的指針數(shù)組。加上形參說明后,main函數(shù)的函數(shù)頭應(yīng)寫為:
main (argc,argv)
int argv;
char *argv[];或?qū)懗桑?br>main (int argc,char *argv[])
由于main函數(shù)不能被其它函數(shù)調(diào)用, 因此不可能在程序內(nèi)部取得實(shí)際值。那么,在何處把實(shí)參值賦予main函數(shù)的形參呢? 實(shí)際上,main函數(shù)的參數(shù)值是從操作系統(tǒng)命令行上獲得的。當(dāng)我們要運(yùn)行一個(gè)可執(zhí)行文件時(shí),在DOS提示符下鍵入文件名,再輸入實(shí)際參數(shù)即可把這些實(shí)參傳送到main的形參中去。
通過指針訪問變量稱為間接訪問, 簡(jiǎn)稱間訪。由于指針變量直接指向變量,所以稱為單級(jí)間訪。 而如果通過指向指針的指針變量來訪問變量則構(gòu)成了二級(jí)或多級(jí)間訪。在C語言程序中,對(duì)間訪的級(jí)數(shù)并未明確限制, 但是間訪級(jí)數(shù)太多時(shí)不容易理解解,也容易出錯(cuò),因此,一般很少超過二級(jí)間訪。 指向指針的指針變量說明的一般形式為:
類型說明符** 指針變量名;
小結(jié)
1. 指針是C語言中一個(gè)重要的組成部分,使用指針編程有以下優(yōu)點(diǎn):
(1)提高程序的編譯效率和執(zhí)行速度。
(2)通過指針可使用主調(diào)函數(shù)和被調(diào)函數(shù)之間共享變量或數(shù)據(jù)結(jié)構(gòu),便于實(shí)現(xiàn)雙向數(shù)據(jù)通訊。
(3)可以實(shí)現(xiàn)動(dòng)態(tài)的存儲(chǔ)分配。
(4)便于表示各種數(shù)據(jù)結(jié)構(gòu),編寫高質(zhì)量的程序。
2. 指針的運(yùn)算
(1)取地址運(yùn)算符&:求變量的地址
(2)取內(nèi)容運(yùn)算符*:表示指針?biāo)傅淖兞?br>(3)賦值運(yùn)算
·把變量地址賦予指針變量
·同類型指針變量相互賦值
·把數(shù)組,字符串的首地址賦予指針變量
·把函數(shù)入口地址賦予指針變量
(4)加減運(yùn)算
對(duì)指向數(shù)組,字符串的指針變量可以進(jìn)行加減運(yùn)算,如p+n,p-n,p++,p--等。對(duì)指向同一數(shù)組的兩個(gè)指針變量可以相減。對(duì)指向其它類型的指針變量作加減運(yùn)算是無意義的。
(5)關(guān)系運(yùn)算
指向同一數(shù)組的兩個(gè)指針變量之間可以進(jìn)行大于、小于、 等于比較運(yùn)算。指針可與0比較,p==0表示p為空指針。
3. 與指針有關(guān)的各種說明和意義見下表。
int *p; p為指向整型量的指針變量
int *p[n]; p為指針數(shù)組,由n個(gè)指向整型量的指針元素組成。
int (*p)[n]; p為指向整型二維數(shù)組的指針變量,二維數(shù)組的列數(shù)為n
int *p() p為返回指針值的函數(shù),該指針指向整型量
int (*p)() p為指向函數(shù)的指針,該函數(shù)返回整型量
int **p p為一個(gè)指向另一指針的指針變量,該指針指向一個(gè)整型量。
4. 有關(guān)指針的說明很多是由指針,數(shù)組,函數(shù)說明組合而成的。
但并不是可以任意組合,例如數(shù)組不能由函數(shù)組成,即數(shù)組元素不能是一個(gè)函數(shù);函數(shù)也不能返回一個(gè)數(shù)組或返回另一個(gè)函數(shù)。例如
int a[5]();就是錯(cuò)誤的。
5. 關(guān)于括號(hào)
在解釋組合說明符時(shí), 標(biāo)識(shí)符右邊的方括號(hào)和圓括號(hào)優(yōu)先于標(biāo)識(shí)符左邊的“*”號(hào),而方括號(hào)和圓括號(hào)以相同的優(yōu)先級(jí)從左到右結(jié)合。但可以用圓括號(hào)改變約定的結(jié)合順序。
6. 閱讀組合說明符的規(guī)則是“從里向外”。
從標(biāo)識(shí)符開始,先看它右邊有無方括號(hào)或園括號(hào),如有則先作出解釋,再看左邊有無*號(hào)。 如果在任何時(shí)候遇到了閉括號(hào),則在繼續(xù)之前必須用相同的規(guī)則處理括號(hào)內(nèi)的內(nèi)容。例如:
int*(*(*a)())[10]
↑ ↑↑↑↑↑↑
7 6 4 2 1 3 5
上面給出了由內(nèi)向外的閱讀順序,下面來解釋它:
(1)標(biāo)識(shí)符a被說明為;
(2)一個(gè)指針變量,它指向;
(3)一個(gè)函數(shù),它返回;
(4)一個(gè)指針,該指針指向;
(5)一個(gè)有10個(gè)元素的數(shù)組,其類型為;
(6)指針型,它指向;
(7)int型數(shù)據(jù)。
因此a是一個(gè)函數(shù)指針變量,該函數(shù)返回的一個(gè)指針值又指向一個(gè)指針數(shù)組,該指針數(shù)組的元素指向整型量。