C語言課件- 指針_第1頁
C語言課件- 指針_第2頁
C語言課件- 指針_第3頁
C語言課件- 指針_第4頁
C語言課件- 指針_第5頁
已閱讀5頁,還剩78頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、主要內(nèi)容:(1)指針變量的定義和使用;(2)用指針實(shí)現(xiàn)函數(shù)參數(shù)的引用傳遞;(3)用指針實(shí)現(xiàn)動(dòng)態(tài)存儲(chǔ)分配的方法;(4)用指針和結(jié)構(gòu)體管理單鏈表;(5)指針與數(shù)組的關(guān)系。第8章 指針 指針是C語言的一個(gè)重要概念, 它是C語言的精華之一。特點(diǎn)是:調(diào)用函數(shù)時(shí)可實(shí)現(xiàn)變量的引用傳遞。用間接訪問的方式改變數(shù)據(jù)的邏輯順序。它能直接對(duì)內(nèi)存地址操作, 使用靈活。實(shí)現(xiàn)動(dòng)態(tài)存儲(chǔ)管理。可以使程序簡(jiǎn)潔、緊湊、高效。容易產(chǎn)生副作用, 初學(xué)者容易出錯(cuò)。int i=3;float j=6;double k=9;3變量i變量j變量k2200220622022214程序中定義的變量, 系統(tǒng)根據(jù)它的類型給它分配一定長度的內(nèi)存單元,該

2、內(nèi)存單元的起始地址即為變量的地址。該內(nèi)存單元的內(nèi)容就是變量的值。變量的地址和變量的值9.1 地址和指針的概念內(nèi)存是編址連續(xù)的,基本單位是字節(jié)。用戶數(shù)據(jù)區(qū)直接訪問和間接訪問1.直接訪問:用變量名直接從它對(duì)應(yīng)的地址存取內(nèi)容。如: int x=5,y=8, z=0; z =x+y; 580變量x變量y變量z22002202220413直接從 x 和 y 對(duì)應(yīng)的地址2200和2202取出內(nèi)容5和8然后相加將結(jié)果13存入變量 z 對(duì)應(yīng)的地址2204的單元中。2.間接訪問:定義一個(gè)存放地址的變量p (p的地址1500), 將x的地址2200存放在變量 p 中。通過變量p取出地址2200, 再按此地址存取其

3、中的內(nèi)容, 就間接的完成了對(duì)x的存取。當(dāng)p的內(nèi)容改為2202時(shí), 通過變量p取出地址2202, 再按此地址, 存取的就是變量y的內(nèi)容。p就是指針變量580變量x變量y變量z22002202220422001500變量p2202地址稱為指針,變量的地址就是變量的指針。存放地址的變量,也就是存放指針的變量,稱之為指針變量。9.2 指針變量一般形式:基類型名 *指針變量名;說明:基類型名: 指針變量所指向的變量的類型名稱指針變量名: 所定義的指針變量的名稱*: 表示它后面的變量名是指針類型功能:(1)定義該指針變量名為指向基類型的指針變量,為該變量分配存儲(chǔ)單元, 其長度等于存儲(chǔ)地址的字節(jié)數(shù)。(2)

4、基類型確定用指針變量“間接”存取數(shù)據(jù)的存儲(chǔ)單元個(gè)數(shù)和存儲(chǔ)形式。該變量只能指向基類型數(shù)據(jù)。指針變量的定義char *p1;int *p2;指針變量的初始化用 =&變量名 來給指針變量賦初值。選項(xiàng)中的變量名必須是已定義過的,其類型必須與基類型一致。表示將它對(duì)應(yīng)的地址值賦給所定義的指針變量??梢杂觅x值語句給指針變量賦值:float y, *py; py=&y;例如: int x, *p=&x; /* p為指向整型變量x的指針變量 */ int px=&x; /* 不正確,缺指針定義符*號(hào) */ float *pf=&x; /* pf為指向?qū)嵭妥兞康闹羔樧兞?*/ /* 初值指向類型不匹配, x為整型

5、變量 */指針變量的引用1. 與指針相關(guān)的運(yùn)算符(1) &: 取地址運(yùn)算符, 取右邊變量的地址(2) * : 指向運(yùn)算符(間接訪問運(yùn)算符), 訪問*右邊的指針變量所指向的變量。&a是變量a的地址*p 是指針變量p指向的變量。說明: “&”和“*”都是單目運(yùn)算符, 它們的優(yōu)先級(jí) 相同, 按自右而左方向結(jié)合。如果已定義 float a, *p=&a ; 則 *p是變量 a&*p是變量a的地址 p&*p等價(jià)于 p而 &a是變量a的地址 p*&a是p所指向的變量 a*&a等價(jià)于a注意:指針變量定義的“*”(指針類型定義符)和引用指針變量的“*”(指向運(yùn)算符)含義不同。float a;float *p=

6、 &a;p=&a;*p=a;*p=&a正確正確正確錯(cuò)誤2. 指針變量的引用(1)引用指針變量的值(指針)與引用其它類型的變量一樣直接用它的變量名(2)引用指針變量所指向的變量時(shí), 用“*指針變量名”注意:指針變量的值與它所指向變量的值之間的差別指針變量只有正確賦值后才能通過它訪問指向的變量。xint x;pp=&x;&xint *p;*p*p=5;5注意事項(xiàng):(1). 指針變量定義和引用指向變量的“*”含義有差別。(2).不能引用沒有賦值的指針變量,不要誤認(rèn)為p定義后 變量*p就已存在,必須給p正確賦值后,變量*p才存在。 (3). p=&a;是給指針變量p 賦值, *p=3; 是給p指向的變

7、量賦值。兩者含義完全不同。(4).給指針變量賦值必須用同類型的指針。(5).指針變量只存放地址, 地址值是無符號(hào)整數(shù), 但不能直 接用整型量(或其它非地址量)賦值給指針變量。int *p1=2200; 錯(cuò)誤3. 兩種訪問變量的方式(1) 直接訪問:直接引用變量名如: int i; i=5;(2) 間接訪問: 通過指針變量和指向運(yùn)算符來引用如:int i, *p; p=&i; *p=5;pppiii&i&i5*p*pmain( ) int m, n; int *p=&m,*q=&n; printf(“input m,n:); scanf(%d %d,p,&n); printf(m=%d &m=%

8、Xn,m,&m); printf(*p=%d p=%Xn,*p,p); printf(n=%d &n=%Xn,n,&n); printf(*q=%d q=%Xn,*q,q);例9.1 取地址運(yùn)算符&和指向運(yùn)算符*的應(yīng)用input m,n:123 456 m=123 &m=FFD6*p=123 p=FFD6n=456 &n=FFD8*q=456 q= FFD8printf(“input m,n:);運(yùn)行結(jié)果:scanf(%d %d,p,&n);printf(m=%d &m=%Xn,m,&m);printf(*p=%d p=%Xn,*p,p); printf(n=%d &n=%Xn,n,&n);p

9、rintf(*q=%d q=%Xn,*q,q);實(shí)現(xiàn)引用傳遞函數(shù)調(diào)用時(shí),實(shí)參傳遞給形參采用單向的值傳遞,直接用變量名作實(shí)參,函數(shù)對(duì)形參的修改結(jié)果不會(huì)帶到主調(diào)函數(shù)。若希望將多個(gè)變量的修改結(jié)果返回給主調(diào)函數(shù),實(shí)現(xiàn)變量的“引用傳遞”,怎么辦?可將指針變量作形參,變量的地址作實(shí)參,就可以達(dá)到變量地址(指針)的值傳遞,即指向變量的引用傳遞。例9.2 用swap函數(shù)實(shí)現(xiàn)兩個(gè)整數(shù)的交換#include void swap(int x, int y) int z; z=x; x=y; y=z; printf(nx=%d,y=%d,x ,y);main( ) int a= 10,b=20; swap(a,b);

10、 printf(na=%d,b=%dn,a,b);程序輸出結(jié)果:x=20,y=10a=10,b=20mainswap20b10az10y20 x101020交換失敗int x,y;int *pt1;*pt2;x=8;y=6;pt1=&x;pt2=&y;if (xy) swap(pt1,pt2);printf(x=%d, y=%dn,x,y);swap(int *p1,int *p2)p=*p1;*p1=*p2;*p2=p; int p;p8pt1pt2xy main() &x&yp1p2&x&y8668運(yùn)行結(jié)果: x=6, y=8int x,y;int *pt1;*pt2;x=8;y=6;pt

11、1=&x;pt2=&y;if (xy) swap(pt1,pt2);swap(int *p1,int *p2)p=*p1;*p1=*p2;*p2=p; int p;printf(x=%d, y=%dn,x,y);9.3 指針與數(shù)組C語言中規(guī)定數(shù)組名是指針類型的符號(hào)常量, 該符號(hào)常量值等于數(shù)組首元素的地址 ( 簡(jiǎn)稱數(shù)組首地址) ,它的類型是指向數(shù)組元素的指針類型。即數(shù)組名是指向該數(shù)組首元素的指針常量。指向數(shù)組元素的指針1.定義指向數(shù)組元素的指針變量定義指向數(shù)組元素的指針變量與定義指向變量的指針變量的方法相同.如:由于數(shù)組名是指向0號(hào)元素的指針類型符號(hào)常量, 所以a與&a0相等。p=&a0; p=

12、a; 兩句等價(jià)p=a不是把a(bǔ)的各元素賦給p注意數(shù)組名與指針變量的區(qū)別int a10;int *p; p=&a0; /* p指向數(shù)組a的第0個(gè)元素*/p=&a4; /* p指向數(shù)組a的第4個(gè)元素*/ 2.指針運(yùn)算(1) 指針變量可以進(jìn)行指向運(yùn)算和賦值運(yùn)算(2) 指針變量可以加(減)一個(gè)整數(shù),指針變量每加(減)1, 地址值增(減)量(記為d字節(jié))等于所指向的變量類型(基類型)的字節(jié)數(shù)sizeof(type), 即d=sizeof(type)。當(dāng)指針變量指向數(shù)組元素時(shí), 指針變量每加(減)1,表示指針前(后)移動(dòng)1個(gè)元素, 地址值增(減)d字節(jié)。如: int a10, *p; /* 由于sizeof

13、(int)=2, 所以d=2 */ p=&a5; /* p指向數(shù)組a的第5個(gè)元素*/ p+; /* p加1后,p指向a6,地址字節(jié)數(shù)增2 */ p -= 3; /* p減3后,p指向a3,地址字節(jié)數(shù)減6 */int a10,*p;p=&a5;(3) 兩個(gè)同類型的指針變量可以相減,得到一個(gè)整數(shù),等于兩者指向變量的地址字節(jié)值之差除以基類型字節(jié)數(shù)。兩個(gè)指針變量之間不能進(jìn)行加法、乘法、除法等算術(shù)運(yùn)算。(4) 兩個(gè)同類型的指針變量可以進(jìn)行比較運(yùn)算,即進(jìn)行,=,=,!=運(yùn)算,比較是用它們指向的地址值進(jìn)行比較。(5) C語言設(shè)置了一個(gè)指針常量“NULL”,稱為空指針,空指針不指向任何存儲(chǔ)單元??罩羔樋梢再x值

14、給任何類型的指針變量,空指針也可以和任何類型的指針變量做等于或不等于的比較。int a10, *p=&a3,*q=&a6;printf(“q-p=%d”, q-p);int a10, *p=&a3,*q=&a6;printf(“The result is: %d”, qp);int a10, *p=&a3;if(p != NULL) 注意: 指針變量的運(yùn)算順序。+*p,*p+,*(+p),(*p)+ 四者之間的差別:+*p先給p指向的變量加1,然后取其值(*p)+先取p指向的變量值, 然后該變量值加1*p+取p所指向變量的值, 然后p增1*+pp先增1, 然后取p所指向變量的值main()in

15、t a4=1,2,3,4,b,c,d,e; int *p=a; b=*p+; printf(“n%d,%d,”,b,*p); c=*+p; d=+*p; printf(“%d,%d”,c,d);運(yùn)行結(jié)果:1,2,3,4p=&a0*(p+):取p指向變量的值賦給b,再p+,則b=a0=1,p=&a1b=1, *p=a1=2;*(+p):p先增1,然后取p指向變量的值,則p=&a2,c=a2=3+(*p):p指向變量的值加1,再取其值,則+a2,d=a2=43. 通過指針引用數(shù)組元素在 int a10,*p=a; 定義的情況下:(1) p+i或a+i就是ai的地址。都要進(jìn)行a+id的運(yùn)算。(2)

16、*(p+i)或*(a+i)就是p+i或a+i所指向的數(shù)組元素ai。 數(shù)組元素中的 “ ” 是變址運(yùn)算符, 相當(dāng)于*( + ) , ai 相當(dāng)于*(a+i)。(3) 指向數(shù)組元素的指針變量也可帶下標(biāo), 如 pi與*(p+i)等價(jià)。 所以, ai,*(a+i) ,pi,*(p+i) 四種表示法全部等價(jià)。(4) 注意p與a的差別,p是變量,a是符號(hào)常量,不能給a賦值, 語句a=p; a+; 都是錯(cuò)的。p &a0a9a1a2aia0p+1,a+1p+2,a+2 p+i,a+ip+9,a+9a引用數(shù)組元素可用:(1)下標(biāo)法,如ai,pi。(2) 指針法,如*(p+i)或*(a+i),其中p是指向數(shù)組a的

17、元素的指針變量。C語言對(duì)地址運(yùn)算不做越界檢查,程序員自己控制邊界(易出錯(cuò))main( ) int a10; int *p,i; for(p=a;p(a+10);p+) scanf(%d, p); printf(n); for(i=0;i10;i+) printf(%d, ai); for(i=0;i10;i+) printf(%d, *(a+i); p=a; /*不能省略*/ for(i=0;i10;i+,p+) printf(%d, *p); for(p=a;p(a+10);p+) printf(%d,*p); 例.輸入/輸出數(shù)組全部元素(下標(biāo)法和指針法)4. 數(shù)組或指針變量作函數(shù)參數(shù)函數(shù)調(diào)

18、用時(shí),實(shí)參用數(shù)組的首地址,形參定義為數(shù)組,對(duì)應(yīng)的形參和實(shí)參實(shí)際上代表同一個(gè)數(shù)組,實(shí)現(xiàn)整個(gè)數(shù)組的引用傳遞。例 通過調(diào)用一個(gè)函數(shù),將整型數(shù)組的所有元素都加3void add(int b , int n) int i; for(i=0;in;i+) bi+=3;main() int i, a8=1,2,3,4,5,6,7,8; add(a,8); for(i=0;i8;i+) printf(“%4d”,ai);運(yùn)行結(jié)果:4 5 6 7 8 9 10 11 a為實(shí)參數(shù)組名,b為形參數(shù)組名。函數(shù)調(diào)用時(shí),系統(tǒng)并未為b分配整個(gè)數(shù)組的存儲(chǔ)空間(故b稱為虛數(shù)組),而是為b分配一個(gè)存儲(chǔ)地址的單元,相當(dāng)于一個(gè)指針變

19、量,用來接收實(shí)參數(shù)組的首地址。即b指向了a0(b=&a0)函數(shù)中,對(duì)bi的訪問就是對(duì)ai的訪問,所有bi加3,相當(dāng)于所有ai加3,從而實(shí)現(xiàn)了整個(gè)數(shù)組的引用傳遞??梢詫?shí)參和形參的數(shù)組名改成對(duì)應(yīng)的指針變量,效果完全等價(jià)(四種形式)void add(int *b, int n) int i; for( i=0; in; i+) *(b+i) += 3;main() int a8=1,2,3,4,5,6,7,8,*p=a; add(p,8); for(p=a;pa+8;p+) printf(“%4d”,*p);歸納起來,如果有一個(gè)數(shù)組,想在被調(diào)用的函數(shù)中改變其元素的值,實(shí)參與形參的對(duì)應(yīng)關(guān)系有以下四種

20、:(1).實(shí)參和形參都用數(shù)組名。(2).實(shí)參用數(shù)組名, 形參用指針變量。(3).實(shí)參用指針變量, 形參用數(shù)組名。(4).實(shí)參和形參都用指針變量。實(shí)質(zhì)都是地址值的傳遞。字符指針、字符數(shù)組和字符串1. 用字符指針訪問字符數(shù)組和字符串例 用字符型數(shù)組名和字符指針變量?jī)煞N方法整體輸入/輸出字符串。 main() char s81=Hello!, *p=s; char *ps=“Welcome to you!”; printf(“%sn”,s); printf(“%sn”,ps); gets(s); printf(%sn,s); gets(p); printf(%sn,s); /*定義ps為指向字符串首

21、地址的指針變量*/*用字符型數(shù)組整體輸出字符串*/*用字符指針整體輸出字符串*/*用字符型數(shù)組整體輸入帶空格的字符串*/ /*用字符型指針整體輸入帶空格的字符串*/ Hello!Welcome to you!How do you do? How do you do?How are you?How are you?注意:字符指針變量和字符數(shù)組的區(qū)別(1) 存儲(chǔ)的內(nèi)容不同:字符數(shù)組存儲(chǔ)著字符串的內(nèi)容, 而字符指針變量存放的是字符串首元素的地址,不是它的內(nèi)容。(2) 分配的內(nèi)存單元不同:字符數(shù)組分配一段有確定地址的內(nèi)存。而指針變量只分配用來存放地址的內(nèi)存單元,該指針變量可以指向一個(gè)字符型數(shù)據(jù),但若未

22、賦初值,則它并未指向一個(gè)明確的地址。此時(shí)它指向的變量并不存在。(3) 賦值方法不同:對(duì)字符數(shù)組只能在定義時(shí)整體賦初值, 不能引用時(shí)進(jìn)行整體賦值。賦值語句只能對(duì)各個(gè)元素分開賦值。如: char s16; (錯(cuò)誤) s=I am a student.;char s16=I am a student.;(正確)對(duì)字符指針變量, 可以采用下面方法賦值: char *p; p=I am a student.;(4) 指針變量的值是可以改變的, 字符數(shù)組名是地址常量,其值是不能改變的。char *p=“Welcome to you ”;p=p+8; (正確)char a=“Welcome to you ”

23、;a=a+8; (錯(cuò)誤)2. 字符串處理函數(shù)的實(shí)現(xiàn)(1) 字符串復(fù)制函數(shù)strcpy主要功能實(shí)現(xiàn)方法一: 數(shù)組下標(biāo)法void strcpy(char s1, char s2) int i=0; while(s1i=s2i) i+;方法二: 指針法void strcpy(char *s1, char *s2) while(*s1+=*s2+) ;空語句(2) 字符串比較函數(shù)strcmp主要功能實(shí)現(xiàn)(指針法)int strcmp(char *s1,char *s2) while(*s1=*s2) if(*s1=0) return 0; s1+; s2+; return (*s1-*s2);main

24、() char a20,b20; gets(a); gets(b); printf(“a=%s, b=%sn cmp(a, b)=%d”,a,b,strcmp(a,b); printf(“n strcmp(b,a)=%d”,strcmp(b,a); printf(“n strcmp(b,b)=%d”,strcmp(b,b);abcdefgabc xyza=abcdefg,b=abc xyzcmp(a,b)=68strcmp(b,a)=-68strcmp(b,b)=0gets(a);gets(b);printf(“a=%s, b=%sn cmp(a, b)=%d”,a,b,strcmp(a,b)

25、;printf(“n strcmp(b,a)=%d”,strcmp(b,a); printf(“n strcmp(b,b)=%d”,strcmp(b,b);運(yùn)行結(jié)果:地址越界問題使用指針時(shí),系統(tǒng)不做越界檢查,注意以下幾點(diǎn):(1) 用指針變量訪問數(shù)組元素,隨時(shí)檢查指針變化范圍,始終不能越界。(2) 引用指針前,一定要對(duì)它正確賦值。不能引用沒有賦值的指針變量。(3) 指針運(yùn)算中注意各運(yùn)算符的優(yōu)先級(jí)和結(jié)合性,多使用括號(hào),使程序易于理解。(4) 字符串整體輸入時(shí),一定要限制輸入的字符串長度。例 地址越界實(shí)例。main() char ps =“Hello !”; char pt =“He is a wo

26、rker.”; char *p=ps; printf(“%sn”,ps); for(p=ps;p90123指針數(shù)組如果每個(gè)數(shù)組元素均為指針類型的變量,即數(shù)組元素的類型是指針類型,則稱這樣的數(shù)組為指針數(shù)組。 一維指針數(shù)組的定義形式為:基類型名 *數(shù)組名數(shù)組長度=地址初值列表;例如:int i,j,k,m,n;int *q5=&i,&j,&k,&m,&n; 比*優(yōu)先級(jí)高,因此數(shù)組名先與結(jié)合,表明是數(shù)組,然后再與前面的*結(jié)合,表明數(shù)組的元素是指針,再與基類型結(jié)合,表明元素類型是指向基類型的指針變量。1. 指針數(shù)組的概念 為什么要用到指針數(shù)組呢?它比較適合于用來指向若干個(gè)字符串,使字符串處理更加方便靈

27、活。 例如,圖書館有若干本書,想把書名放在一個(gè)數(shù)組中(圖a),然后要對(duì)這些書目進(jìn)行排序和查詢。按一般方法,字符串本身就是一個(gè)字符數(shù)組。因此要設(shè)計(jì)一個(gè)二維的字符數(shù)組才能存放多個(gè)字符串。但在定義二維數(shù)組時(shí),需要指定列數(shù),也就是說二維數(shù)組中每一行中包含的元素個(gè)數(shù)(即列數(shù))相等。而實(shí)際上各字符串(書名)長度一般是不相等的。如按最長的字符串來定義列數(shù),則會(huì)浪費(fèi)許多內(nèi)存單元(見圖b)。 可以分別定義一些字符串,然后用指針數(shù)組中的元素分別指向各字符串(見圖c)。如果想對(duì)字符串排序,不必改動(dòng)字符串的位置,只需改動(dòng)指針數(shù)組中各元素的指向(即改變各元素的值,這些值是各字符串的首地址)。這樣,各字符串的長度可以不同

28、,而且移動(dòng)指針變量的值(地址)要比移動(dòng)字符串所花的時(shí)間少得多。例 將若干字符串按字母順序(由小到大)輸出。main() void Sort(char *name ,int n); void print(char *name ,int n);char *name =Follow me,BASIC,Great Wall,F(xiàn)ORTRAN,Computer Design;int n=5;Sort(name,n);print(name,n);void Sort(char *name ,int n) chartemp; int i,j,k; for(i=0;in-1;i+) k=i; for(j=i+1;

29、j0)k=j;if(k!=i) temp=namei; namei=namek; namek=temp; void print(char *name ,int n) int i; for(i=0;in;i+) printf(%sn,namei);運(yùn)行結(jié)果為: BASIC Computer Design FORTRAN Follow me Great Wall 在main函數(shù)中定義指針數(shù)組name。它有5個(gè)元素,其初值分別是“Follow me”、“BASIC”、“Great all”、“FORTRAN”,“Computer Design”的首地址(見圖c)。這些字符串是不等長的(并不是按同一長

30、度定義的)。Sort函數(shù)的作用是對(duì)字符串排序。Sort函數(shù)的形參name也是指針數(shù)組名,接受實(shí)參傳過來的name數(shù)組的首地址,因此形參name數(shù)組和實(shí)參name數(shù)組指的是同一數(shù)組。用選擇法對(duì)字符串排序。strcmp是字符串比較函數(shù),namek和namej是第k個(gè)和第j個(gè)字符串的起始地址。strcmp(namek,namej)的值為:如果namek所指的字符串大于namej所指的字符串,則此函數(shù)值為正值;若相等,則函數(shù)值為0;若小于,則函數(shù)值為負(fù)值。if語句的作用是將兩個(gè)串中“小”的那個(gè)串的序號(hào)(i或j之一)保留在變量k中。當(dāng)執(zhí)行完內(nèi)循環(huán)for語句后,從第i個(gè)串到第n個(gè)串這么多字符串中,第k個(gè)串

31、最“小”。若ki就表示最小的串不是第i串。故將namei和namek對(duì)換,也就是將指向第i個(gè)串的數(shù)組元素(是指針型元素)與指向第k個(gè)串的數(shù)組元素對(duì)換。執(zhí)行完Sort函數(shù)后指針數(shù)組的情況:(1)指向指針的指針(二級(jí)指針變量) 在掌握了指針數(shù)組的概念的基礎(chǔ)上,下面介紹指向指針數(shù)據(jù)的指針變量,簡(jiǎn)稱為指向指針的指針。前面的例子中,name是一個(gè)指針數(shù)組,它的每一個(gè)元素是一個(gè)指針型數(shù)據(jù),其值為地址。name是一個(gè)數(shù)組,它的每一元素都有相應(yīng)的地址。數(shù)組名name代表該指針數(shù)組的首地址。name+i是namei的地址。name+i就是指向指針型數(shù)據(jù)的指針(地址)。于是,可以設(shè)置一個(gè)指針變量p,讓它指向指針數(shù)

32、組的元素,那么,p就是指向指針型數(shù)據(jù)的指針變量,也就是二級(jí)指針變量。 怎樣定義一個(gè)指向指針數(shù)據(jù)的指針變量呢?如下: char *p;2.用二級(jí)指針變量訪問指針數(shù)組 (2)用二級(jí)指針變量訪問指針數(shù)組 例如: int a=3,*q=&a;int *p; /*二級(jí)指針*/p=&q;printf(“%d”, *p); 若要通過該二級(jí)指針變量來訪問指針數(shù)組元素所指向的變量的內(nèi)容,則需要進(jìn)行兩次間接訪問。 用所定義的二級(jí)指針變量來指向指針數(shù)組的各元素,進(jìn)行間接訪問。&a8&qaqp480026001700例 指針數(shù)組的各元素指向整型數(shù)據(jù)的簡(jiǎn)單實(shí)例 main() static int s5=10,20,30

33、,40,50; int *q5=&s0,&s1,&s2,&s3,&s4; int *p; for(p=q; pq+5; p+) printf(%dt,*p); 運(yùn)行結(jié)果:10 20 30 40 50 數(shù)組名q是指向數(shù)組首元素的地址,而數(shù)組首元素是一個(gè)指針變量,所以q是指向一個(gè)指針變量的指針,是一個(gè)二級(jí)指針常量。數(shù)組名是指向該數(shù)組首元素的指針常量數(shù)組名等于數(shù)組首元素的地址指針數(shù)組是每個(gè)數(shù)組元素都是指針的數(shù)組二級(jí)指針變量是指向指針的指針變量指針數(shù)組名是指向數(shù)組首元素的指針常量,因?yàn)槠鋽?shù)組元素本身又是指針類型,所以指針數(shù)組名是指向指針的指針常量,稱之為二級(jí)指針常量??梢詫⒍?jí)指針常量賦值給同類型的二

34、級(jí)指針變量,所以可以將指針數(shù)組名賦值給同類型的二級(jí)指針變量。int *q5;int *p;多維數(shù)組和指向分?jǐn)?shù)組的指針1. 多維數(shù)組的地址以二維數(shù)組為例,設(shè)二維數(shù)組a有3行4列。 int a34=1,3,5,7,9,11,13,15,17,19,21,23a是數(shù)組名, a數(shù)組有3行, 即3個(gè)分?jǐn)?shù)組:a0,a1,a2。每個(gè)分?jǐn)?shù)組又是含4個(gè)列元素的一維數(shù)組。 用指針變量可以指向一維數(shù)組,也可以指向多維數(shù)組。但在概念上和使用上,多維數(shù)組的指針比一維數(shù)組的指針要復(fù)雜一些。 從宏觀角度去看二維數(shù)組,可以把二維數(shù)組的每一行看成是它的一個(gè)元素,每個(gè)元素都是一個(gè)一維數(shù)組,或者說每個(gè)元素都是一個(gè)分?jǐn)?shù)組。 基于如此

35、宏觀的理解,數(shù)組名a是指向數(shù)組首元素的指針,而二維數(shù)組的第0個(gè)元素就是第0行,也就是第0個(gè)分?jǐn)?shù)組。所以a是指向第0個(gè)分?jǐn)?shù)組的指針。a+1則指向第1個(gè)元素也就是第1行,或者說指向第一個(gè)分?jǐn)?shù)組。如果二維數(shù)組的首地址為2000,則a+1為2008,因?yàn)榈?行有4個(gè)整型數(shù)據(jù),因此a+1的含義是a1的地址,即a+42=2008。a+2代表第2行的首地址,它的值是2016,見圖。 a0、a1、a2既然是一維數(shù)組名,而C語言又規(guī)定了數(shù)組名代表數(shù)組的首地址,因此a0代表第0行一維數(shù)組中第0列元素的地址,即&a00。a1的值是&a10,a2的值是&a20。a1357911131517192123a+1a+2a0

36、a0+2a1a1+2a2a2+2a0+3a0+1a等價(jià)&a0*a等價(jià)a0 a1等價(jià)&a10, *a1等價(jià)a10a1+2等價(jià)&a12,*(a1+2)等價(jià)a12*(*(a+1)+2)等價(jià) *(a1+2) 等價(jià) a12a+1等價(jià)&a1*(a+1)等價(jià)a1 請(qǐng)考慮第0行第1列元素的地址怎么表示?可以用a0+1來表示,見圖。此時(shí)“a0+1”中的1代表1個(gè)列元素的字節(jié)數(shù),即2個(gè)字節(jié)。今a0的值是2000,a0+1的值是2002(而不是2008)。這是因?yàn)楝F(xiàn)在是在一維數(shù)組范圍內(nèi)討論問題的,正如有一個(gè)一維數(shù)組s,s+1是其第1個(gè)元素地址一樣。a0+0、a0+1、a0+2、a0+3分別是a00、a01、a02、

37、a03的地址(即&a00、&a01、&a02、&a03)。前面講到,a0和*(a+0)等價(jià),a1和*(a+1)等價(jià),ai和*(a+i)等價(jià)。因此,a0+1和*(a+0)+1的值都是&a01 (即圖中的2002)。a1+2和*(a+1)+2的值都是&a12(即圖中的2012)。請(qǐng)注意不要將*(a+1)+2錯(cuò)寫成*(a+1+2),后者變成*(a+3)了,相當(dāng)于a3。 進(jìn)一步分析,欲得到a01的值,用地址法怎么表示呢?既然a0+1和*(a+0)+1,是a01的地址,那么,*(a0+1)就是a01的值。同理,*(*(a+0)+1)或*(*a+1)也是a01的值。*(ai+j)或*(*(a+i)+j)是

38、aij的值。請(qǐng)記住*(a+i)和ai是等價(jià)的。 有必要對(duì)ai的性質(zhì)作進(jìn)一步說明。ai從形式上看是a數(shù)組中第i個(gè)元素。如果a是一維數(shù)組名,則ai代表a數(shù)組第i個(gè)元素所占的內(nèi)存單元。ai是有物理地址的,是占內(nèi)存單元的。但如果a是二維數(shù)組,則ai是代表一維數(shù)組名。ai本身并不占內(nèi)存單元,它也不存放a數(shù)組中各個(gè)元素的值。它只是一個(gè)地址(如同一個(gè)一維數(shù)組名s并不占內(nèi)存單元而只代表地址一樣)。a、a+i、ai、*(a+i)、*(a+i)+j、ai+j都是地址。*(ai+j)、*(*(a+i)+j)是二維數(shù)組元素aij的值。有些同學(xué)可能不理解為什么a+1和*(a+1)都是2008呢?他們想“a+1的值和a+

39、1的地址怎么都是一樣的呢”?的確,二維數(shù)組中有些概念比較復(fù)雜難懂,要反復(fù)思考。首先說明,a+1是地址(指向第1行首地址),而*(a+1)并不是“a+1單元的內(nèi)容(值)”,因?yàn)閍+1并不是一個(gè)實(shí)際變量,也就談不上它的內(nèi)容。*(a+1)就是a1,而a1是一維數(shù)組名,所以也是地址。以上各種形式都是地址計(jì)算的不同表示。 為了說明這個(gè)容易搞混的問題,舉一個(gè)日常生活中的例子來說明。有一個(gè)排,下設(shè)3個(gè)班,每班有10名戰(zhàn)士。規(guī)定排長只管理到班,班長管理戰(zhàn)士。在排長眼里只有第0、1、2班(為與C語言中數(shù)組下標(biāo)一致,假定班號(hào)也從0開始)。排長從第0班的起始位置走到第1班的起始位置,看來只走了一步,但實(shí)際上它跳過了

40、10個(gè)戰(zhàn)士。這相當(dāng)于a+1(見圖)。為了找到某一班內(nèi)某一個(gè)戰(zhàn)士,必須給兩個(gè)參數(shù),即第i班第j個(gè)戰(zhàn)士,先找到第i班,然后由該班班長在本班范圍內(nèi)找第j個(gè)戰(zhàn)士。這個(gè)戰(zhàn)士的位置就是ai+j(這是一個(gè)地址)。開始時(shí)班長面對(duì)第0個(gè)戰(zhàn)士。注意,排長和班長的初始位置是相同的(如前面圖中的a和a0都是2000)。但它們的“指向”是不同的。排長“指向”班,他走一步就跳過1個(gè)班,而班長“指向”戰(zhàn)士,走一步只是指向下一個(gè)戰(zhàn)士??梢钥吹脚砰L是“宏觀管理”,只管班,在上圖中是控制縱向,班長則是“微觀管理”,管理到戰(zhàn)士,在圖上是控制橫向。如果要找第1班第2個(gè)戰(zhàn)士,則先由排長找到第1班的班長,然后,由班長在本班范圍內(nèi)找到第2

41、個(gè)戰(zhàn)士。二維數(shù)組a相當(dāng)于排長,每一行(即一維數(shù)組a0、a1、a2)相當(dāng)于班長,每一行中的元素(如a12)相當(dāng)于戰(zhàn)士。a+1與a0+1是不同的,a+1是第1行的首地址,a+1指向第1行(相當(dāng)于排長走到第1班的開頭),而*(a+1)或a1或a1+0都指向第1行第0列元素(相當(dāng)于第1班第0個(gè)戰(zhàn)士),二者地址雖相同,但含義不同了。前者是“縱向控制”,后者是“橫向控制”。 a,a0的值雖然相同(等于2000),但是由于指針的類型不同(a是指向一維數(shù)組,a0指向a00元素)因此,對(duì)這些指針進(jìn)行加1的運(yùn)算,得到的結(jié)果是不同的。請(qǐng)記住,二維數(shù)組名(如a)是指向行的。因此a+1中的“1”代表一行中全部元素所占的

42、字節(jié)數(shù)(前面圖中表示為8個(gè)字節(jié))。一維數(shù)組名(如a0,a1)是指向列元素的。a0+1中的“1” 代表一個(gè)元素所占的字節(jié)數(shù)(前面圖中表示為2個(gè)字節(jié))。在行指針前面加一個(gè)*,就轉(zhuǎn)換為列指針。例如,a和a+1是行指針,在它們前面加一個(gè)*就是*a和*(a+1),它們就成為列指針,分別指向a數(shù)組0行0列的元素和1行0列的元素。反之,在列指針前面加&,就成為行指針。例如a0是指向0行0列元素的列指針,在它前面加一個(gè)&,得&a0,由于a0與*(a+0)等價(jià),因此&a0與&*a等價(jià),也就是與a等價(jià),它指向二維數(shù)組的0行。 不要把 &ai簡(jiǎn)單地理解為 ai單元的物理地址,因?yàn)椴⒉淮嬖?ai這樣一個(gè)變量。它只是一

43、種地址的計(jì)算方法,能得到第i行的首地址, &ai和ai的值是一樣的, 但它們的含義是不同的。 &ai或a+i指向行,而ai或*(a+i)指向列。當(dāng)列下標(biāo)j為0時(shí),&ai和ai(即ai+j)值相等,即它們具有同一地址值。(a+i)只是ai的另一種表示形式,不要簡(jiǎn)單地認(rèn)為是“a+i所指單元中的內(nèi)容”。在一維數(shù)組中a+i所指向的是一個(gè)數(shù)組元素的存儲(chǔ)單元,它有具體值,上述說法是正確的。而對(duì)二維數(shù)組,a+i不是指向具體存儲(chǔ)單元而指向行。在二維數(shù)組中,a+i=ai=*(a+i)=&ai=&ai0,即它們的地址值是相等的。請(qǐng)讀者仔細(xì)琢磨其概念。注意:a+1與a0+1不同a+1是a第1行分?jǐn)?shù)組地址*(a+1)

44、是第1行第0列地址*(a+1)是元素a10 a0是第0行分?jǐn)?shù)組名a0+1是元素a01 地址*(a0+1)是元素a01 形式 含義 內(nèi)容a ,&a0 二維數(shù)組名,0行分?jǐn)?shù)組地址 2000a0,*(a+0),*a ,&a00 0行一維數(shù)組名,0行0列元素地址 2000a0+1,*a+1,&a01 0行1列元素地址 2002a+1,&a1 1行一維數(shù)組首地址 2008a1,*(a+1) ,&a10 1行一維數(shù)組名,1行0列元素地址 2008a1+3,*(a+1)+3,&a13 1行3列元素地址 2014*(a2+3),*(*(a+2)+3),a23 2行3列元素 12注意: a和a0的地址均為200

45、0,但不等價(jià),a+1和a0+1不等。2. 指向數(shù)組元素和指向分?jǐn)?shù)組的指針變量(1) 指向二維數(shù)組元素的指針變量例:用指針變量輸出數(shù)組元素的值。main( ) int a34=1,2,3,4,5,6,7,8,9,10,11,12; int *p; /*定義p為指向整型的變量*/ for (p=a0;pa0+12;p+) if(p-a0)%4=0) printf(n); printf(%4d,*p); 1 2 3 4 5 6 7 8 9 10 11 12&a00 與a0等價(jià)a0=&a00;p=&a00;910111256781234pp+1p+2p+3p+4p+5p+6p+7p+8p+9p+10p

46、+11a0指向二維數(shù)組的分?jǐn)?shù)組的指針變量,應(yīng)該指向整個(gè)一維數(shù)組。指向整個(gè)一維數(shù)組的指針變量的定義如下:基類型名 (*指針變量名)長度; 指針變量名先與*結(jié)合,再與結(jié)合。先與*結(jié)合,表明是一個(gè)指針變量;再與結(jié)合,表明指針變量指向一個(gè)數(shù)組。最后與基類型結(jié)合,表明數(shù)組元素的類型是基類型。 (2) 指向分?jǐn)?shù)組的指針變量注意 指針數(shù)組和指向數(shù)組的指針的區(qū)別int (*p)5; /*定義p為指向一維數(shù)組(元素為整型,個(gè)數(shù)為5)的指針變量*/int *a5; /*定義a為數(shù)組,數(shù)組元素(5個(gè))均為指向整型的指針變量*/例如: static int a=10,b=20,c=30,d=40;static s34

47、=1,2,3,4,5,6,7,8,9,10,11,12;int *q4=&a, &b, &c, &d; /*指針數(shù)組*/int (*p)4; /*指向數(shù)組的指針*/int *r; /*指向整型的指針*/r=s0; /* r=&s00 */p=s; /* p=&s0 */152637489101112pp+1p+2srr+1r+210203040abcd&a&b&c&dq0q1q2q3qs0例 用指向二維數(shù)組的分?jǐn)?shù)組的指針變量, 按行輸出二維數(shù)組中各元素的值。main( ) int a34=1,2,3,4,5,6,7,8,9,10,11,12; int *q; /*定義指向元素的指針變量q*/

48、int (*p)4; /*定義指向數(shù)組的指針變量p*/ for(p=a;pa+3;p+) for(q=*p;q*p+4;q+) printf(%5d,*q); printf(n); 1 2 3 4 5 6 7 8 9 10 11 12q q+2pp+2例 用指向分?jǐn)?shù)組的指針變量, 輸入多個(gè)字符串,將它們按行存儲(chǔ)在二維字符數(shù)組中,然后輸出全部字符串。main( ) char a420; char (*p)20; printf(“Input strings: n”); for(p=a; pa+4; p+) gets(*p); printf(“Output strings: n”); for(p=a

49、; pa+4; p+) printf(“%s ”,*p);Input strings: Zhang San,Li Si,Wang Wu,Welcome! Output strings: Zhang San, Li Si, Wang Wu, Welcome!只有字符數(shù)組可以整體輸入輸出p=a=&a0 *p=a0,a0是一維字符數(shù)組名(字符串名), *p是一維字符數(shù)組apppp3.用多維數(shù)組名和指針變量作函數(shù)參數(shù)(1)用多維數(shù)組名作實(shí)參或形參。如: f(int a 4, int n);(2)用指向元素的指針變量作實(shí)參或形參。如: f1(int *p);(3)用指向分?jǐn)?shù)組的指針變量作函數(shù)參數(shù)。如:f

50、2(int (*q)4, int m);例 用兩個(gè)二維數(shù)組存儲(chǔ)矩陣,調(diào)用函數(shù)求兩個(gè)矩陣之差,差矩陣存放在第一個(gè)實(shí)參數(shù)組中,用指向分?jǐn)?shù)組的指針變量作形參。矩陣輸出也用函數(shù)實(shí)現(xiàn)。 #define N 4sub( int (*p1)N, int (*p2)N, int m ) int *q1,*q2, (*u)N; u=p1+m; for( ; p1u; p1+,p2+) for(q1=*p1,q2=*p2;q1*p1+N;q1+,q2+) *q1-=*q2;print(int (*p)N,int m) int *q,(*u)N; u=p+m; for( ; pu; p+) for(q=*p; q*

51、p+N;q+) printf(%4d,*q); printf(n); printf(n);main() int i, j, a N=1,2,3,4,5,6,7,8 ; int b N=10,20,30,40,50,60,70,80; print(a,2); print(b,2); sub(b,a,2); print(b,2); 1 2 3 4 5 6 7 810 20 30 40 50 60 70 80 9 18 27 36 45 54 63 72sub( int (*p1)N, int (*p2)N, int m ) int *q1,*q2, (*u)N; u=p1+m; for( ; p1

52、u; p1+,p2+) for(q1=*p1,q2=*p2;q1*p1+N;q1+,q2+) *q1-=*q2;1050206030704080b15263748ap1p2sub(b,a,2)p1=b;p2=a;m=2;uq1q2q1q2q1q2q1q2p2p19182736q2q1q2q1q2q1q2q145546372q2q1p2p1print(int (*p)N,int m) int *q,(*u)N; u=p+m; for( ; pu; p+) for(q=*p; q*p+N;q+) printf(%4d,*q); printf(n); printf(n);print(a,2);p=a

53、;m=2;15263748auppqqqqqqqqqpprint(int *p, int m) int *q,*u; u=p+m*N; for(; pu; p+=N) for(q=p;qnum 等價(jià)-指向結(jié)構(gòu)體成員運(yùn)算符最高優(yōu)先級(jí),自左向右結(jié)合性struct student long num; char name20; char sex; float score;main( ) struct student stu_1 ,*p; p=&stu_1; stu_1.num=8901; strcpy(stu_1.name,”Li Lin”); stu_1.sex=M; stu_1.score=89.

54、5; printf(“No:%ldnname:%snsex:%cnscore:%.1fn”, stu_1.num,stu_1.name,stu_1.sex,stu_1.score); printf(“No:%ldnname:%snsex:%cnscore:%.1fn”, (*p).num, (*p).name, p-sex, p-score);運(yùn)行結(jié)果:No:8901name:LiLinsex:MNo:8901name:LiLinsex:Mpp-n+ 引用p指向的結(jié)構(gòu)體變量中成員n, 然后使n增1。(p+)-n 引用p指向的結(jié)構(gòu)體變量中成員n, 然后使p增1。+p-n 使p指向的結(jié)構(gòu)體變量中成

55、員n先增1(不是p增1), 再取n的值。(+p)-n 使p的值增1, 再引用p指向的結(jié)構(gòu)體變量中成員n的 值。以下三種形式等價(jià):s0.成員名 (*p).成員名 p-成員名 指向成員運(yùn)算符(-)具有最高優(yōu)先級(jí),左結(jié)合性2.用指向結(jié)構(gòu)體的指針作函數(shù)參數(shù) (2)采取“引用傳遞”的方式, 它用指向結(jié)構(gòu)體的指針變量作形參和實(shí)參。調(diào)用函數(shù)時(shí),只需將結(jié)構(gòu)體變量(或數(shù)組)的地址傳給形參。形參只占用一個(gè)存地址的內(nèi)存單元,時(shí)間和空間的開銷都比較小。如果在被調(diào)用函數(shù)中改變了形參指向的結(jié)構(gòu)體的值,該值可以帶回主調(diào)函數(shù)。該方法使用較多。(1)采取“值傳遞”的方式,用結(jié)構(gòu)體變量整體作為函數(shù)的參數(shù)。形參是結(jié)構(gòu)體類型的局部變

56、量,函數(shù)調(diào)用時(shí),需要分配結(jié)構(gòu)體類型對(duì)應(yīng)的內(nèi)存單元,費(fèi)時(shí)又占空間,同時(shí)無法將形參的修改結(jié)果帶回主調(diào)函數(shù),因此,此方法很少采用。 例 采用“引用傳遞”的方式,用指向結(jié)構(gòu)體的指針變量作參數(shù),在input函數(shù)中輸入并計(jì)算平均成績(jī),在main函數(shù)輸出。 #define N 4#include#define FMT %5d %-11s%5d%8d%8d%10.1fnstruct st int num; char name11; int s3; float aver;void input(struct st *p) scanf(%d%s%d%d%d,&p-num,p-name,&p-s0,&p-s1,&p-

57、s2); p-aver=(p-s0+p-s1+p-s2)/3.0;main() struct st aN,*p=a; printf(Input student:number name score1 score2 score3n); while(pa+N) input(p+); printf(number name score1 score2 score3 averagen); for(p=a;pnum,p-name,p-s0,p-s1,p-s2,p-aver); 9.5 返回值為指針類型的函數(shù) 返回值為指針類型的函數(shù),稱為指針類型的函數(shù),簡(jiǎn)稱為指針函數(shù)。 指針函數(shù)的定義格式如下: 類型名 *函

58、數(shù)名(參數(shù)表)例如:int *f(int x) ()優(yōu)先級(jí)高于*,所以f先與()結(jié)合,表明它是一個(gè)函數(shù),則f是函數(shù)名,()中的x是形參。f前面有個(gè)*,表明此函數(shù)返回一個(gè)指針類型,再考慮*前面是int,表明函數(shù)返回一個(gè)指向整型的指針。例 實(shí)現(xiàn)系統(tǒng)提供的字符串復(fù)制函數(shù)strcpy()的全部功能。 char *strcpy(char *s1,char *s2) char *p=s1; while(*s1+=*s2+) ; return(p); main() char s20; printf(%sn, strcpy(s,Welcome to you!); while(*s1=*s2) s1+; s2+;運(yùn)行結(jié)果:Welcome to you !;是空語句例 實(shí)現(xiàn)系統(tǒng)提供的字符串連接函數(shù)strcat(s1,s2)的全部功能。 char *strcat(char *s1, char *s2) char *p=s1; while(*s1) s1+; while(*s1+=*s2+); return(p); main() char s40=Hello, ; printf(%sn,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(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ǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論