譚浩強(qiáng)C語言全書10--指針_第1頁
譚浩強(qiáng)C語言全書10--指針_第2頁
譚浩強(qiáng)C語言全書10--指針_第3頁
譚浩強(qiáng)C語言全書10--指針_第4頁
譚浩強(qiáng)C語言全書10--指針_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、10指針1地址指針的基本概念1變量的指針和指向變量的指針變量2定義一個(gè)指針變量3指針變量的引用3指針變量作為函數(shù)參數(shù)7指針變量幾個(gè)問題的進(jìn)一步說明10數(shù)組指針和指向數(shù)組的指針變量13指向數(shù)組元素的指針13通過指針引用數(shù)組元素14數(shù)組名作函數(shù)參數(shù)16指向多維數(shù)組的指針和指針變量22字符串的指針指向字符串的針指變量25字符串的表示形式25使用字符串指針變量與字符數(shù)組的區(qū)別28函數(shù)指針變量29指針型函數(shù)30指針數(shù)組和指向指針的指針31指針數(shù)組的概念31指向指針的指針34main函數(shù)的參數(shù)36有關(guān)指針的數(shù)據(jù)類型和指針運(yùn)算的小結(jié)37有關(guān)指針的數(shù)據(jù)類型的小結(jié)37指針運(yùn)算的小結(jié)37void指針類型3810

2、指針 指針是語言中廣泛使用的一種數(shù)據(jù)類型。運(yùn)用指針編程是語言最主要的風(fēng)格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu);能很方便地使用數(shù)組和字符串;并能象匯編語言一樣處理內(nèi)存地址,從而編出精練而高效的程序。指針極大地豐富了語言的功能。學(xué)習(xí)指針是學(xué)習(xí)語言中最重要的一環(huán),能否正確理解和使用指針是我們是否掌握語言的一個(gè)標(biāo)志。同時(shí),指針也是語言中最為困難的一部分,在學(xué)習(xí)中除了要正確理解基本概念,還必須要多編程,上機(jī)調(diào)試。只要作到這些,指針也是不難掌握的。10.1 地址指針的基本概念在計(jì)算機(jī)中,所有的數(shù)據(jù)都是存放在存儲(chǔ)器中的。一般把存儲(chǔ)器中的一個(gè)字節(jié)稱為一個(gè)內(nèi)存單元,不同的數(shù)據(jù)類型所占用的內(nèi)存單元數(shù)不等,如整型

3、量占2個(gè)單元,字符量占1個(gè)單元等,在前面已有詳細(xì)的介紹。為了正確地訪問這些內(nèi)存單元,必須為每個(gè)內(nèi)存單元編上號。根據(jù)一個(gè)內(nèi)存單元的編號即可準(zhǔn)確地找到該內(nèi)存單元。內(nèi)存單元的編號也叫做地址。 既然根據(jù)內(nèi)存單元的編號或地址就可以找到所需的內(nèi)存單元,所以通常也把這個(gè)地址稱為指針。 內(nèi)存單元的指針和內(nèi)存單元的內(nèi)容是兩個(gè)不同的概念。 可以用一個(gè)通俗的例子來說明它們之間的關(guān)系。我們到銀行去存取款時(shí), 銀行工作人員將根據(jù)我們的帳號去找我們的存款單, 找到之后在存單上寫入存款、取款的金額。在這里,帳號就是存單的指針, 存款數(shù)是存單的內(nèi)容。對于一個(gè)內(nèi)存單元來說,單元的地址即為指針,其中存放的數(shù)據(jù)才是該單元的內(nèi)容。在

4、語言中,允許用一個(gè)變量來存放指針,這種變量稱為指針變量。因此,一個(gè)指針變量的值就是某個(gè)內(nèi)存單元的地址或稱為某內(nèi)存單元的指針。圖中,設(shè)有字符變量C,其內(nèi)容為“K”(ASCII碼為十進(jìn)制數(shù) 75),C占用了011A號單元(地址用十六進(jìn)數(shù)表示)。設(shè)有指針變量P,內(nèi)容為011A,這種情況我們稱為P指向變量C,或說P是指向變量C的指針。嚴(yán)格地說,一個(gè)指針是一個(gè)地址,是一個(gè)常量。而一個(gè)指針變量卻可以被賦予不同的指針值,是變量。但常把指針變量簡稱為指針。為了避免混淆,我們中約定:“指針”是指地址,是常量,“指針變量”是指取值為地址的變量。定義指針的目的是為了通過指針去訪問內(nèi)存單元。 既然指針變量的值是一個(gè)地

5、址,那么這個(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ì)使程序的概念十分清楚,程序本身也精練,高效。在語言中,一種數(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)的,因

6、而概念更為清楚,表示更為明確。 這也是引入“指針”概念的一個(gè)重要原因。10.2 變量的指針和指向變量的指針變量變量的指針就是變量的地址。存放變量地址的變量是指針變量。即在語言中,允許用一個(gè)變量來存放指針,這種變量稱為指針變量。因此,一個(gè)指針變量的值就是某個(gè)變量的地址或稱為某變量的指針。為了表示指針變量和它所指向的變量之間的關(guān)系,在程序中用“*”符號表示“指向”,例如,i_pointer代表指針變量,而*i_pointer是i_pointer所指向的變量。因此,下面兩個(gè)語句作用相同:i=3;*i_pointer=3;第二個(gè)語句的含義是將3賦給指針變量i_pointer所指向的變量。10.2.1

7、定義一個(gè)指針變量對指針變量的定義包括三個(gè)內(nèi)容:(1) 指針類型說明,即定義變量為一個(gè)指針變量;(2) 指針變量名;(3) 變量值(指針)所指向的變量的數(shù)據(jù)類型。其一般形式為:類型說明符 *變量名;其中,*表示這是一個(gè)指針變量,變量名即為定義的指針變量名,類型說明符表示本指針變量所指向的變量的數(shù)據(jù)類型。例如: int *p1;表示p1是一個(gè)指針變量,它的值是某個(gè)整型變量的地址?;蛘哒fp1指向一個(gè)整型變量。至于p1究竟指向哪一個(gè)整型變量,應(yīng)由向p1賦予的地址來決定。再如:int *p2; /*p2是指向整型變量的指針變量*/ float *p3; /*p3是指向浮點(diǎn)變量的指針變量*/char *p

8、4; /*p4是指向字符變量的指針變量*/應(yīng)該注意的是,一個(gè)指針變量只能指向同類型的變量,如P3 只能指向浮點(diǎn)變量,不能時(shí)而指向一個(gè)浮點(diǎn)變量,時(shí)而又指向一個(gè)字符變量。10.2.2 指針變量的引用指針變量同普通變量一樣,使用之前不僅要定義說明,而且必須賦予具體的值。未經(jīng)賦值的指針變量不能使用,否則將造成系統(tǒng)混亂,甚至死機(jī)。指針變量的賦值只能賦予地址, 決不能賦予任何其它數(shù)據(jù),否則將引起錯(cuò)誤。在語言中,變量的地址是由編譯系統(tǒng)分配的,對用戶完全透明,用戶不知道變量的具體地址。兩個(gè)有關(guān)的運(yùn)算符:1) &:取地址運(yùn)算符。2) *:指針運(yùn)算符(或稱“間接訪問” 運(yùn)算符)。語言中提供了地址運(yùn)算符&a

9、mp;來表示變量的地址。其一般形式為: &變量名;如&a表示變量a的地址,&b表示變量b的地址。變量本身必須預(yù)先說明。設(shè)有指向整型變量的指針變量p,如要把整型變量a 的地址賦予p可以有以下兩種方式:(1) 指針變量初始化的方法 int a; int *p=&a;(2) 賦值語句的方法 int a; int *p;p=&a;不允許把一個(gè)數(shù)賦予指針變量,故下面的賦值是錯(cuò)誤的:int *p;p=1000;被賦值的指針變量前不能再加“*”說明符,如寫為*p=&a 也是錯(cuò)誤的。假設(shè):int i=200, x;int *ip;我們定義了兩個(gè)整型變量i,x,還

10、定義了一個(gè)指向整型數(shù)的指針變量ip。i,x中可存放整數(shù),而ip中只能存放整型變量的地址。我們可以把i的地址賦給ip:ip=&i;此時(shí)指針變量ip指向整型變量i,假設(shè)變量i的地址為1800,這個(gè)賦值可形象理解為下圖所示的聯(lián)系。 以后我們便可以通過指針變量ip間接訪問變量i,例如:     x=*ip;運(yùn)算符*訪問以ip為地址的存貯區(qū)域,而ip中存放的是變量i的地址,因此,*ip訪問的是地址為1800的存貯區(qū)域(因?yàn)槭钦麛?shù),實(shí)際上是從1800開始的兩個(gè)字節(jié)),它就是i所占用的存貯區(qū)域, 所以上面的賦值表達(dá)式等價(jià)于   &

11、#160; x=i;另外,指針變量和一般變量一樣,存放在它們之中的值是可以改變的,也就是說可以改變它們的指向,假設(shè)int i,j,*p1,*p2;  i='a'  j='b'p1=&i;p2=&j;則建立如下圖所示的聯(lián)系:這時(shí)賦值表達(dá)式:p2=p1就使p2與p1指向同一對象i,此時(shí)*p2就等價(jià)于i,而不是j,圖所示:如果執(zhí)行如下表達(dá)式: *p2=*p1;則表示把p1指向的內(nèi)容賦給p2所指的區(qū)域, 此時(shí)就變成圖所示通過指針訪問它所指向的一個(gè)變量是以間接訪問的形式進(jìn)行的,所以比直接訪問一個(gè)變量要費(fèi)時(shí)間,而且不直觀,因?yàn)橥ㄟ^指針要訪

12、問哪一個(gè)變量,取決于指針的值(即指向),例如"*p2=*p1;"實(shí)際上就是"j=i;",前者不僅速度慢而且目的不明。但由于指針是變量,我們可以通過改變它們的指向,以間接訪問不同的變量,這給程序員帶來靈活性,也使程序代碼編寫得更為簡潔和有效。指針變量可出現(xiàn)在表達(dá)式中, 設(shè)int x,y,*px=&x;指針變量px指向整數(shù)x,則*px可出現(xiàn)在x能出現(xiàn)的任何地方。例如:y=*px+5;  /*表示把x的內(nèi)容加5并賦給y*/y=+*px;  /*px的內(nèi)容加上1之后賦給y,+*px相當(dāng)于+(*px)*/y=*px+;  /*

13、相當(dāng)于y=*px; px+*/ 【例10.1】main() int a,b; int *pointer_1, *pointer_2; a=100;b=10; pointer_1=&a;pointer_2=&b; printf("%d,%dn",a,b); printf("%d,%dn",*pointer_1, *pointer_2); 對程序的說明:1) 在開頭處雖然定義了兩個(gè)指針變量pointer_1和pointer_2,擔(dān)它們并未指向任何一個(gè)整型變量。只是提供兩個(gè)指針變量,規(guī)定它們可以指向整型變量。程序第5、6行的作用就是使point

14、er_1指向a,pointer_2指向b。2) 最后一行的*pointer_1和*pointer_2就是變量a和b。最后兩個(gè)printf函數(shù)作用是相同的。3) 程序中有兩處出現(xiàn)*pointer_1和*pointer_2,請區(qū)分它們的不同含義。4) 程序第5、6行的“pointer_1=&a”和 “pointer_2=&b”不能寫成“*pointer_1=&a”和 “*pointer_2=&b”。請對下面再的關(guān)于“&”和“*”的問題進(jìn)行考慮:1) 如果已經(jīng)執(zhí)行了“pointer_1=&a;”語句,則&*pointer_1是什么含義?2) *

15、&a含義是什么?3) (pointer_1)+和pointer_1+的區(qū)別?【例10.2】輸入a和b兩個(gè)整數(shù),按先大后小的順序輸出a和b。main() int *p1,*p2,*p,a,b; scanf("%d,%d",&a,&b); p1=&a;p2=&b; if(a<b) p=p1;p1=p2;p2=p; printf("na=%d,b=%dn",a,b); printf("max=%d,min=%dn",*p1, *p2); 10.2.3 指針變量作為函數(shù)參數(shù)函數(shù)的參數(shù)不僅可以是整型

16、、實(shí)型、字符型等數(shù)據(jù),還可以是指針類型。它的作用是將一個(gè)變量的地址傳送到另一個(gè)函數(shù)中?!纠?0.3】題目同例10.2,即輸入的兩個(gè)整數(shù)按大小順序輸出。今用函數(shù)處理,而且用指針類型的數(shù)據(jù)作函數(shù)參數(shù)。swap(int *p1,int *p2)int temp; temp=*p1; *p1=*p2; *p2=temp;main() int a,b;int *pointer_1,*pointer_2; scanf("%d,%d",&a,&b); pointer_1=&a;pointer_2=&b; if(a<b) swap(pointer_1,

17、pointer_2); printf("n%d,%dn",a,b); 對程序的說明:swap是用戶定義的函數(shù),它的作用是交換兩個(gè)變量(a和b)的值。swap函數(shù)的形參p1、p2是指針變量。程序運(yùn)行時(shí),先執(zhí)行main函數(shù),輸入a和b的值。然后將a和b的地址分別賦給指針變量pointer_1和pointer_2,使pointer_1指向a,pointer_2指向b。接著執(zhí)行if語句,由于ab,因此執(zhí)行swap函數(shù)。注意實(shí)參pointer_1和pointer_2是指針變量,在函數(shù)調(diào)用時(shí),將實(shí)參變量的值傳遞給形參變量。采取的依然是“值傳遞”方式。因此虛實(shí)結(jié)合后形參p1的值為&

18、;a,p2的值為&b。這時(shí)p1和pointer_1指向變量a,p2和pointer_2指向變量b。接著執(zhí)行執(zhí)行swap函數(shù)的函數(shù)體使*p1和*p2的值互換,也就是使a和b的值互換。函數(shù)調(diào)用結(jié)束后,p1和p2不復(fù)存在(已釋放)如圖。最后在main函數(shù)中輸出的a和b的值是已經(jīng)過交換的值。請注意交換*p1和*p2的值是如何實(shí)現(xiàn)的。請找出下列程序段的錯(cuò)誤:swap(int *p1,int *p2)int *temp; *temp=*p1; /*此語句有問題*/ *p1=*p2; *p2=temp;請考慮下面的函數(shù)能否實(shí)現(xiàn)實(shí)現(xiàn)a和b互換。swap(int x,int y)int temp; te

19、mp=x; x=y; y=temp;如果在main函數(shù)中用“swap(a,b);”調(diào)用swap函數(shù),會(huì)有什么結(jié)果呢?請看下圖所示。【例10.4】請注意,不能企圖通過改變指針形參的值而使指針實(shí)參的值改變。swap(int *p1,int *p2)int *p; p=p1; p1=p2; p2=p;main() int a,b;int *pointer_1,*pointer_2; scanf("%d,%d",&a,&b); pointer_1=&a;pointer_2=&b; if(a<b) swap(pointer_1,pointer_2

20、); printf("n%d,%dn",*pointer_1,*pointer_2); 其中的問題在于不能實(shí)現(xiàn)如圖所示的第四步(d)?!纠?0.5】輸入a、b、c3個(gè)整數(shù),按大小順序輸出。swap(int *pt1,int *pt2)int temp; temp=*pt1; *pt1=*pt2; *pt2=temp;exchange(int *q1,int *q2,int *q3) if(*q1<*q2)swap(q1,q2);if(*q1<*q3)swap(q1,q3);if(*q2<*q3)swap(q2,q3);main() int a,b,c,*p

21、1,*p2,*p3; scanf("%d,%d,%d",&a,&b,&c); p1=&a;p2=&b; p3=&c; exchange(p1,p2,p3); printf("n%d,%d,%d n",a,b,c); 10.2.4 指針變量幾個(gè)問題的進(jìn)一步說明指針變量可以進(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é)合性為自右至左,其功能是取變量的地址。在scanf函數(shù)及前面介紹指針變量賦

22、值中,我們已經(jīng)了解并使用了&運(yùn)算符。2) 取內(nèi)容運(yùn)算符*:取內(nèi)容運(yùn)算符*是單目運(yùn)算符,其結(jié)合性為自右至左,用來表示指針變量所指的變量。在*運(yùn)算符之后跟的變量必須是指針變量。需要注意的是指針運(yùn)算符*和指針變量說明中的指針說明符*不是一回事。在指針變量說明中,“*”是類型說明符,表示其后的變量是指針類型。而表達(dá)式中出現(xiàn)的“*”則是一個(gè)運(yùn)算符用以表示指針變量所指的變量?!纠?0.6】main() int a=5,*p=&a; printf ("%d",*p); 表示指針變量p取得了整型變量a的地址。printf("%d",*p)語句表示輸出變量

23、a的值。2. 指針變量的運(yùn)算1) 賦值運(yùn)算:指針變量的賦值運(yùn)算有以下幾種形式。 指針變量初始化賦值,前面已作介紹。 把一個(gè)變量的地址賦予指向相同數(shù)據(jù)類型的指針變量。例如:int a,*pa;pa=&a; /*把整型變量a的地址賦予整型指針變量pa*/ 把一個(gè)指針變量的值賦予指向相同類型變量的另一個(gè)指針變量。如: int a,*pa=&a,*pb; pb=pa; /*把a(bǔ)的地址賦予指針變量pb*/由于pa,pb均為指向整型變量的指針變量,因此可以相互賦值。 把數(shù)組的首地址賦予指向數(shù)組的指針變量。例如: int a5,*pa; pa=a; (數(shù)組名表示數(shù)組的首地址,故可賦予指向數(shù)組

24、的指針變量pa)也可寫為: pa=&a0; /*數(shù)組第一個(gè)元素的地址也是整個(gè)數(shù)組的首地址, 也可賦予pa*/當(dāng)然也可采取初始化賦值的方法: int a5,*pa=a; 把字符串的首地址賦予指向字符類型的指針變量。例如: char *pc; pc="C Language"或用初始化賦值的方法寫為: char *pc="C Language"這里應(yīng)說明的是并不是把整個(gè)字符串裝入指針變量,而是把存放該字符串的字符數(shù)組的首地址裝入指針變量。在后面還將詳細(xì)介紹。 把函數(shù)的入口地址賦予指向函數(shù)的指針變量。例如: int (*pf)(); pf=f; /*f為

25、函數(shù)名*/2) 加減算術(shù)運(yùn)算 對于指向數(shù)組的指針變量,可以加上或減去一個(gè)整數(shù)n。設(shè)pa是指向數(shù)組a的指針變量,則pa+n,pa-n,pa+,+pa,pa-,-pa運(yùn)算都是合法的。指針變量加或減一個(gè)整數(shù)n的意義是把指針指向的當(dāng)前位置(指向某數(shù)組元素)向前或向后移動(dòng)n個(gè)位置。應(yīng)該注意,數(shù)組指針變量向前或向后移動(dòng)一個(gè)位置和地址加1或減1在概念上是不同的。因?yàn)閿?shù)組可以有不同的類型,各種類型的數(shù)組元素所占的字節(jié)長度是不同的。如指針變量加1,即向后移動(dòng)1 個(gè)位置表示指針變量指向下一個(gè)數(shù)據(jù)元素的首地址。而不是在原地址基礎(chǔ)上加1。例如: int a5,*pa; pa=a; /*pa指向數(shù)組a,也是指向a0*/

26、pa=pa+2; /*pa指向a2,即pa的值為&pa2*/指針變量的加減運(yùn)算只能對數(shù)組指針變量進(jìn)行,對指向其它類型變量的指針變量作加減運(yùn)算是毫無意義的。3) 兩個(gè)指針變量之間的運(yùn)算:只有指向同一數(shù)組的兩個(gè)指針變量之間才能進(jìn)行運(yùn)算,否則運(yùn)算毫無意義。 兩指針變量相減:兩指針變量相減所得之差是兩個(gè)指針?biāo)笖?shù)組元素之間相差的元素個(gè)數(shù)。實(shí)際上是兩個(gè)指針值(地址)相減之差再除以該數(shù)組元素的長度(字節(jié)數(shù))。例如pf1和pf2是指向同一浮點(diǎn)數(shù)組的兩個(gè)指針變量,設(shè)pf1的值為2010H,pf2的值為2000H,而浮點(diǎn)數(shù)組每個(gè)元素占4個(gè)字節(jié),所以pf1-pf2的結(jié)果為(2000H-2010H)/4=4

27、,表示pf1和 pf2之間相差4個(gè)元素。兩個(gè)指針變量不能進(jìn)行加法運(yùn)算。 例如,pf1+pf2是什么意思呢?毫無實(shí)際意義。 兩指針變量進(jìn)行關(guān)系運(yùn)算:指向同一數(shù)組的兩指針變量進(jìn)行關(guān)系運(yùn)算可表示它們所指數(shù)組元素之間的關(guān)系。例如:pf1=pf2表示pf1和pf2指向同一數(shù)組元素;pf1>pf2表示pf1處于高地址位置;pf1<pf2表示pf2處于低地址位置。指針變量還可以與0比較。設(shè)p為指針變量,則p=0表明p是空指針,它不指向任何變量;p!=0表示p不是空指針??罩羔樖怯蓪χ羔樧兞抠x予0值而得到的。例如:#define NULL 0int *p=NULL;對指針變量賦0值和不賦值是不同的

28、。指針變量未賦值時(shí),可以是任意值,是不能使用的。否則將造成意外錯(cuò)誤。而指針變量賦0值后,則可以使用,只是它不指向具體的變量而已?!纠?0.7】main() int a=10,b=20,s,t,*pa,*pb; /*說明pa,pb為整型指針變量*/ pa=&a; /*給指針變量pa賦值,pa指向變量a*/ pb=&b; /*給指針變量pb賦值,pb指向變量b*/ s=*pa+*pb; /*求a+b之和,(*pa就是a,*pb就是b)*/ t=*pa*pb; /*本行是求a*b之積*/ printf("a=%dnb=%dna+b=%dna*b=%dn",a,b,

29、a+b,a*b); printf("s=%dnt=%dn",s,t);【例10.8】main() int a,b,c,*pmax,*pmin; /*pmax,pmin為整型指針變量*/ printf("input three numbers:n"); /*輸入提示*/ scanf("%d%d%d",&a,&b,&c); /*輸入三個(gè)數(shù)字*/ if(a>b) /*如果第一個(gè)數(shù)字大于第二個(gè)數(shù)字*/ pmax=&a; /*指針變量賦值*/ pmin=&b; /*指針變量賦值*/ else pma

30、x=&b; /*指針變量賦值*/ pmin=&a; /*指針變量賦值*/ if(c>*pmax) pmax=&c; /*判斷并賦值*/ if(c<*pmin) pmin=&c; /*判斷并賦值*/ printf("max=%dnmin=%dn",*pmax,*pmin); /*輸出結(jié)果*/10.3 數(shù)組指針和指向數(shù)組的指針變量一個(gè)變量有一個(gè)地址,一個(gè)數(shù)組包含若干元素,每個(gè)數(shù)組元素都在內(nèi)存中占用存儲(chǔ)單元,它們都有相應(yīng)的地址。所謂數(shù)組的指針是指數(shù)組的起始地址,數(shù)組元素的指針是數(shù)組元素的地址。10.3.1 指向數(shù)組元素的指針一個(gè)數(shù)組是由

31、連續(xù)的一塊內(nèi)存單元組成的。數(shù)組名就是這塊連續(xù)內(nèi)存單元的首地址。一個(gè)數(shù)組也是由各個(gè)數(shù)組元素(下標(biāo)變量)組成的。每個(gè)數(shù)組元素按其類型不同占有幾個(gè)連續(xù)的內(nèi)存單元。一個(gè)數(shù)組元素的首地址也是指它所占有的幾個(gè)內(nèi)存單元的首地址。定義一個(gè)指向數(shù)組元素的指針變量的方法,與以前介紹的指針變量相同。例如: int a10; /*定義a為包含10個(gè)整型數(shù)據(jù)的數(shù)組*/int *p; /*定義p為指向整型變量的指針*/應(yīng)當(dāng)注意,因?yàn)閿?shù)組為int型,所以指針變量也應(yīng)為指向int型的指針變量。下面是對指針變量賦值:p=&a0;把a(bǔ)0元素的地址賦給指針變量p。也就是說,p指向a數(shù)組的第0號元素。C語言規(guī)定,數(shù)組名代表數(shù)

32、組的首地址,也就是第0號元素的地址。因此,下面兩個(gè)語句等價(jià):p=&a0;p=a;在定義指針變量時(shí)可以賦給初值:int *p=&a0;它等效于:int *p; p=&a0;當(dāng)然定義時(shí)也可以寫成: int *p=a;從圖中我們可以看出有以下關(guān)系: p,a,&a0均指向同一單元,它們是數(shù)組a的首地址,也是0 號元素a0的首地址。應(yīng)該說明的是p是變量,而a,&a0都是常量。在編程時(shí)應(yīng)予以注意。數(shù)組指針變量說明的一般形式為:類型說明符 *指針變量名;其中類型說明符表示所指數(shù)組的類型。從一般形式可以看出指向數(shù)組的指針變量和指向普通變量的指針變量的說明是相同的。10.

33、3.2 通過指針引用數(shù)組元素C語言規(guī)定:如果指針變量p已指向數(shù)組中的一個(gè)元素,則p+1指向同一數(shù)組中的下一個(gè)元素。引入指針變量后,就可以用兩種方法來訪問數(shù)組元素了。如果p的初值為&a0,則:1) p+i和a+i就是ai的地址,或者說它們指向a數(shù)組的第i個(gè)元素。2) *(p+i)或*(a+i)就是p+i或a+i所指向的數(shù)組元素,即ai。例如,*(p+5)或*(a+5)就是a5。3) 指向數(shù)組的指針變量也可以帶下標(biāo),如pi與*(p+i)等價(jià)。根據(jù)以上敘述,引用一個(gè)數(shù)組元素可以用:1) 下標(biāo)法,即用ai形式訪問數(shù)組元素。在前面介紹數(shù)組時(shí)都是采用這種方法。2) 指針法,即采用*(a+i)或*(

34、p+i)形式,用間接訪問的方法來訪問數(shù)組元素,其中a是數(shù)組名,p是指向數(shù)組的指針變量,其處值p=a。【例10.9】輸出數(shù)組中的全部元素。(下標(biāo)法)main() int a10,i; for(i=0;i<10;i+) ai=i; for(i=0;i<5;i+) printf("a%d=%dn",i,ai);【例10.10】輸出數(shù)組中的全部元素。(通過數(shù)組名計(jì)算元素的地址,找出元素的值)main() int a10,i; for(i=0;i<10;i+) *(a+i)=i; for(i=0;i<10;i+) printf("a%d=%dn&qu

35、ot;,i,*(a+i);【例10.11】輸出數(shù)組中的全部元素。(用指針變量指向元素)main() int a10,I,*p; p=a; for(i=0;i<10;i+) *(p+i)=i; for(i=0;i<10;i+) printf("a%d=%dn",i,*(p+i);【例10.12】main() int a10,i,*p=a; for(i=0;i<10;) *p=i; printf("a%d=%dn",i+,*p+); 幾個(gè)注意的問題:1) 指針變量可以實(shí)現(xiàn)本身的值的改變。如p+是合法的;而a+是錯(cuò)誤的。因?yàn)閍是數(shù)組名,它是數(shù)

36、組的首地址,是常量。2) 要注意指針變量的當(dāng)前值。請看下面的程序?!纠?0.13】找出錯(cuò)誤。main() int *p,i,a10; p=a;for(i=0;i<10;i+) *p+=i; for(i=0;i<10;i+) printf("a%d=%dn",i,*p+);【例10.14】改正。main() int *p,i,a10; p=a;for(i=0;i<10;i+)*p+=i; p=a; for(i=0;i<10;i+) printf("a%d=%dn",i,*p+);3) 從上例可以看出,雖然定義數(shù)組時(shí)指定它包含10個(gè)元

37、素,但指針變量可以指到數(shù)組以后的內(nèi)存單元,系統(tǒng)并不認(rèn)為非法。4) *p+,由于+和*同優(yōu)先級,結(jié)合方向自右而左,等價(jià)于*(p+)。5) *(p+)與*(+p)作用不同。若p的初值為a,則*(p+)等價(jià)a0,*(+p)等價(jià)a1。6) (*p)+表示p所指向的元素值加1。7) 如果p當(dāng)前指向a數(shù)組中的第i個(gè)元素,則*(p-)相當(dāng)于ai-;*(+p)相當(dāng)于a+i;*(-p)相當(dāng)于a-i。10.3.3 數(shù)組名作函數(shù)參數(shù)數(shù)組名可以作函數(shù)的實(shí)參和形參。如:main()int array10; f(array,10); f(int arr,int n); array為實(shí)參數(shù)組名,arr為形參數(shù)組名。在學(xué)習(xí)指

38、針變量之后就更容易理解這個(gè)問題了。數(shù)組名就是數(shù)組的首地址,實(shí)參向形參傳送數(shù)組名實(shí)際上就是傳送數(shù)組的地址,形參得到該地址后也指向同一數(shù)組。這就好象同一件物品有兩個(gè)彼此不同的名稱一樣。 同樣,指針變量的值也是地址,數(shù)組指針變量的值即為數(shù)組的首地址,當(dāng)然也可作為函數(shù)的參數(shù)使用?!纠?0.15】float aver(float *pa);main() float sco5,av,*sp; int i; sp=sco; printf("ninput 5 scores:n"); for(i=0;i<5;i+) scanf("%f",&scoi); av

39、=aver(sp); printf("average score is %",av);float aver(float *pa) int i; float av,s=0; for(i=0;i<5;i+) s=s+*pa+; av=s/5; return av;【例10.16】將數(shù)組a中的n個(gè)整數(shù)按相反順序存放。算法為:將a0與an-1對換,再a1與an-2 對換,直到將a(n-1/2)與an-int(n-1)/2)對換。今用循環(huán)處理此問題,設(shè)兩個(gè)“位置指示變量”i和j,i的初值為0,j的初值為n-1。將ai與aj交換,然后使i的值加1,j的值減1,再將ai與aj交換,

40、直到i=(n-1)/2為止,如圖所示。程序如下:void inv(int x,int n) /*形參x是數(shù)組名*/ int temp,i,j,m=(n-1)/2; for(i=0;i<=m;i+)j=n-1-i; temp=xi;xi=xj;xj=temp; return;main()int i,a10=3,7,9,11,0,6,7,5,4,2; printf("The original array:n"); for(i=0;i<10;i+) printf("%d,",ai); printf("n"); inv(a,10)

41、; printf("The array has benn inverted:n"); for(i=0;i<10;i+) printf("%d,",ai); printf("n");對此程序可以作一些改動(dòng)。將函數(shù)inv中的形參x改成指針變量?!纠?0.17】對例10.16可以作一些改動(dòng)。將函數(shù)inv中的形參x改成指針變量。程序如下:void inv(int *x,int n) /*形參x為指針變量*/ int *p,temp,*i,*j,m=(n-1)/2; i=x;j=x+n-1;p=x+m; for(;i<=p;i+,j

42、-)temp=*i;*i=*j;*j=temp; return;main()int i,a10=3,7,9,11,0,6,7,5,4,2; printf("The original array:n"); for(i=0;i<10;i+) printf("%d,",ai); printf("n"); inv(a,10); printf("The array has benn inverted:n"); for(i=0;i<10;i+) printf("%d,",ai); printf(

43、"n");運(yùn)行情況與前一程序相同?!纠?0.18】從0個(gè)數(shù)中找出其中最大值和最小值。調(diào)用一個(gè)函數(shù)只能得到一個(gè)返回值,今用全局變量在函數(shù)之間“傳遞”數(shù)據(jù)。程序如下:int max,min; /*全局變量*/void max_min_value(int array,int n)int *p,*array_end; array_end=array+n; max=min=*array; for(p=array+1;p<array_end;p+) if(*p>max)max=*p; else if (*p<min)min=*p; return;main()int i

44、,number10; printf("enter 10 integer umbers:n"); for(i=0;i<10;i+) scanf("%d",&numberi); max_min_value(number,10); printf("nmax=%d,min=%dn",max,min); 說明:1) 在函數(shù)max_min_value中求出的最大值和最小值放在max和min中。由于它們是全局,因此在主函數(shù)中可以直接使用。2) 函數(shù)max_min_value中的語句:max=min=*array;array是數(shù)組名,它

45、接收從實(shí)參傳來的數(shù)組numuber的首地址。*array相當(dāng)于*(&array0)。上述語句與 max=min=array0;等價(jià)。3) 在執(zhí)行for循環(huán)時(shí),p的初值為array+1,也就是使p指向array1。以后每次執(zhí)行p+,使p指向下一個(gè)元素。每次將*p和max與min比較。將大者放入max,小者放min。4) 函數(shù)max_min_value的形參array可以改為指針變量類型。實(shí)參也可以不用數(shù)組名,而用指針變量傳遞地址?!纠?0.19】程序可改為:int max,min; /*全局變量*/void max_min_value(int *array,int n)int *p,*a

46、rray_end; array_end=array+n; max=min=*array; for(p=array+1;p<array_end;p+) if(*p>max)max=*p; else if (*p<min)min=*p; return;main()int i,number10,*p; p=number; /*使p指向number數(shù)組*/ printf("enter 10 integer umbers:n"); for(i=0;i<10;i+,p+) scanf("%d",p); p=number; max_min_va

47、lue(p,10); printf("nmax=%d,min=%dn",max,min); 歸納起來,如果有一個(gè)實(shí)參數(shù)組,想在函數(shù)中改變此數(shù)組的元素的值,實(shí)參與形參的對應(yīng)關(guān)系有以下種:1) 形參和實(shí)參都是數(shù)組名。main()int a10; f(a,10) f(int x,int n) 和指的是同一組數(shù)組。2) 實(shí)用數(shù)組,形參用指針變量。main()int a10; f(a,10) f(int *x,int n) 3) 實(shí)參、型參都用指針變量。4) 實(shí)參為指針變量,型參為數(shù)組名?!纠?0.20】用實(shí)參指針變量改寫將n個(gè)整數(shù)按相反順序存放。void inv(int *x,in

48、t n)int *p,m,temp,*i,*j; m=(n-1)/2; i=x;j=x+n-1;p=x+m; for(;i<=p;i+,j-) temp=*i;*i=*j;*j=temp; return;main()int i,arr10=3,7,9,11,0,6,7,5,4,2,*p; p=arr; printf("The original array:n"); for(i=0;i<10;i+,p+) printf("%d,",*p); printf("n"); p=arr; inv(p,10); printf(&quo

49、t;The array has benn inverted:n"); for(p=arr;p<arr+10;p+) printf("%d,",*p); printf("n");注意:main函數(shù)中的指針變量p是有確定值的。即如果用指針變作實(shí)參,必須現(xiàn)使指針變量有確定值,指向一個(gè)已定義的數(shù)組?!纠?0.21】用選擇法對10個(gè)整數(shù)排序。main()int *p,i,a10=3,7,9,11,0,6,7,5,4,2; printf("The original array:n"); for(i=0;i<10;i+) pr

50、intf("%d,",ai); printf("n"); p=a; sort(p,10); for(p=a,i=0;i<10;i+) printf("%d ",*p);p+; printf("n");sort(int x,int n)int i,j,k,t; for(i=0;i<n-1;i+) k=i; for(j=i+1;j<n;j+) if(xj>xk)k=j; if(k!=i) t=xi;xi=xk;xk=t; 說明:函數(shù)sort用數(shù)組名作為形參,也可改為用指針變量,這時(shí)函數(shù)的首部可以

51、改為:sort(int *x,int n) 其他可一律不改。10.3.4 指向多維數(shù)組的指針和指針變量本小節(jié)以二維數(shù)組為例介紹多維數(shù)組的指針變量。1. 多維數(shù)組的地址設(shè)有整型二維數(shù)組a34如下:0 1 2 3 4 5 6 78 9 10 11它的定義為:int a34=0,1,2,3,4,5,6,7,8,9,10,11設(shè)數(shù)組a的首地址為1000,各下標(biāo)變量的首地址及其值如圖所示。前面介紹過,語言允許把一個(gè)二維數(shù)組分解為多個(gè)一維數(shù)組來處理。因此數(shù)組a可分解為三個(gè)一維數(shù)組,即a0,a1,a2。每一個(gè)一維數(shù)組又含有四個(gè)元素。例如a0數(shù)組,含有a00,a01,a02,a03四個(gè)元素。數(shù)組及數(shù)組元素的地

52、址表示如下:從二維數(shù)組的角度來看,a是二維數(shù)組名,a代表整個(gè)二維數(shù)組的首地址,也是二維數(shù)組0行的首地址,等于1000。a+1代表第一行的首地址,等于1008。如圖:a0是第一個(gè)一維數(shù)組的數(shù)組名和首地址,因此也為1000。*(a+0)或*a是與a0等效的, 它表示一維數(shù)組a00 號元素的首地址,也為1000。&a00是二維數(shù)組a的0行0列元素首地址,同樣是1000。因此,a,a0,*(a+0),*a,&a00是相等的。同理,a+1是二維數(shù)組1行的首地址,等于1008。a1是第二個(gè)一維數(shù)組的數(shù)組名和首地址,因此也為1008。&a10是二維數(shù)組a的1行0列元素地址,也是100

53、8。因此a+1,a1,*(a+1),&a10是等同的。由此可得出:a+i,ai,*(a+i),&ai0是等同的。此外,&ai和ai也是等同的。因?yàn)樵诙S數(shù)組中不能把&ai理解為元素ai的地址,不存在元素ai。語言規(guī)定,它是一種地址計(jì)算方法,表示數(shù)組a第i行首地址。由此,我們得出:ai,&ai,*(a+i)和a+i也都是等同的。另外,a0也可以看成是a0+0,是一維數(shù)組a0的0號元素的首地址,而a0+1則是a0的1號元素首地址,由此可得出ai+j則是一維數(shù)組ai的j號元素首地址,它等于&aij。由ai=*(a+i)得ai+j=*(a+i)+j。由于

54、*(a+i)+j是二維數(shù)組a的i行j列元素的首地址,所以,該元素的值等于*(*(a+i)+j)?!纠?0.22】main() int a34=0,1,2,3,4,5,6,7,8,9,10,11; printf("%d,",a); printf("%d,",*a); printf("%d,",a0); printf("%d,",&a0); printf("%dn",&a00); printf("%d,",a+1); printf("%d,",

55、*(a+1); printf("%d,",a1); printf("%d,",&a1); printf("%dn",&a10); printf("%d,",a+2); printf("%d,",*(a+2); printf("%d,",a2); printf("%d,",&a2); printf("%dn",&a20); printf("%d,",a1+1); printf("%dn",*(a+1)+1); printf("%d,%dn",*(a1+1),*(*(a+1)+1);2. 指向多維數(shù)組的指針變量把二維數(shù)組a分解為一維數(shù)組a0,a1,a2之后,設(shè)p為指向二維數(shù)組的指針變量。可定義為: in

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論