第09章指針課件_第1頁
第09章指針課件_第2頁
第09章指針課件_第3頁
第09章指針課件_第4頁
第09章指針課件_第5頁
已閱讀5頁,還剩100頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

第9章指針

本章要點(diǎn):

0指針的概念

0指向數(shù)組的指針

0指針的各種應(yīng)用

9.1指針與指針變量

■指針是C語言中的一個(gè)重要概念,也是C語言的重要

■指針類型是C語言的一種特殊的數(shù)據(jù)類型。正確而

靈活地應(yīng)用指針,可以有效地表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu)、

動(dòng)態(tài)地分配內(nèi)存、方便地使用字符串、有效而方便

地使用數(shù)組、直接處理內(nèi)存地址等。使用指針編寫

的程序在代碼質(zhì)量上比用其他方法效率更高,因此

指針在C程序中用得非常多。指針是C語言的精華所

在,同時(shí)也是c語言的難點(diǎn)之一。學(xué)習(xí)指針應(yīng)該充

分地理解指針的概念,在上機(jī)實(shí)踐中進(jìn)一步掌握它。

2

9.L1指針的概念

指針是一種數(shù)據(jù)類型,是一個(gè)變量在內(nèi)存中所對(duì)應(yīng)單元的

地址。

這個(gè)地址可以是變量的地址,也可以是數(shù)組、函數(shù)的起始

地址,還可以是一個(gè)指針變量的地址。

3

變量一經(jīng)定義,系統(tǒng)為其分配存儲(chǔ)單元。

如:inta=10,b=8;

內(nèi)存中的每個(gè)字節(jié)有編號(hào),稱之為地址。

訪問變量有直接和間接兩種方式

■直接訪問方式:按變量的

□地址,直接存取變量侑。

■如:a=10;

■或:scanff6%d?\&b);

將鍵盤輸入的數(shù),送到

地址為2002開始的存儲(chǔ)單元。

內(nèi)存

4

■間接訪問方式:將變量a的地址存放在另一個(gè)變量

p中。

■取a中數(shù)的過程:先通過p的內(nèi)容,得到a的地址

2000,再到地址為2000的存儲(chǔ)單元中取出數(shù)10。

■變量的地址稱為指針。

■存放地址的變量p稱為

指針變量。

5

9.1.2指針變量的定義

■定義格式:類型名*指針變量名

■例如:/*定義指向整型變量的指針*/

■float*p2;/*定義指向?qū)嵭妥兞康闹羔?/

o

■使指針pl指向整型變量i:pl1

■pl=&i;

■使指針p2指向?qū)嵭妥兞縡:p2

■p2=&f;&f

■注意:指針變量只能放地址。

6

9.1.3指針變量的兩種運(yùn)算符

C語言提供了兩種指針運(yùn)算符:

&:取地址運(yùn)算符。

*:指針內(nèi)容運(yùn)算符(也稱為:間接訪問運(yùn)算符)

例如:intx=10,*p,y;

p=&x;/*將變量x的地址賦給指針變量p*/

*p是P所指向的變量。

y=*p;/*等價(jià)于y=x*/

7

■&和*兩個(gè)運(yùn)算符優(yōu)先級(jí)相同

□結(jié)合性:從右到左。

若有int*p;p=&a;

(1)則&*p的含義:即相當(dāng)于&(*p)

先執(zhí)行*P操作,即訪問a,

再進(jìn)行&操作:即所以&*p等價(jià)于

(2)而*&a的含義:即相當(dāng)于*(&a),

先執(zhí)行&a,得到a的地址,

再對(duì)該地址取*操作:*(&a),得到a的值。

所以*&a等價(jià)于*p,等價(jià)于a。

8

■*與++優(yōu)先級(jí)相同。

(1)*p++即相當(dāng)于*(p++)

執(zhí)行p++,先用p的原值,執(zhí)行*p得a;然后執(zhí)行p++,

p將示指向aTo

(2)(*p)++等價(jià)于:a++

■因?yàn)?p就是a,(*p)++就是(a)++,即a++

9

如果:intx=10,y,*px;

且有:px=&x;

則變量X與指向變量X的指針px之間有以下等價(jià)關(guān)系:

y=*px;等價(jià)于y=x;

(*px)++;等價(jià)于x++;/*對(duì)指針變量px的內(nèi)容加1

*/

y=(*px)+5;等價(jià)于y=x+5;

y=*(&x);等價(jià)于y=x;/*y二變量x地址的內(nèi)容

*/

C語言中用NULL表示空指針。若有語句:p=NULL;表示

指針P為空,沒有指向任何對(duì)象。

10

注意:

L&運(yùn)算符只能作用于變量,包括基本類型變量和數(shù)

組的元素、結(jié)構(gòu)體類型變量或結(jié)構(gòu)體的成員,不能

作用于數(shù)組名、常量或寄存器變量。

2.單目運(yùn)算符*是&的逆運(yùn)算,它的操作數(shù)是對(duì)象的

地址,*運(yùn)算的結(jié)果是對(duì)象本身。單目*稱為間接訪

問運(yùn)算符,是通過變量的地址存取(或引用)變量。

例如:doubler,a[20];

inti;則表達(dá)式&r、&a[0],&a[i]是正確的,

而&(2*r)、&a、&k是非法表示。

charc,*pc=&c;賦值語?:*(&c)='a';*pc='a,;c-a*;

registerintk;效果相同,都是將字符W存入變量c。

11

9.1.4指針變量的初始化

在使用指針變量前,要首先對(duì)指針變量進(jìn)行初始化,

讓指針變量指向一個(gè)具體的變量。進(jìn)行指針變量初

始化的方式有兩種:

方法一:使用賦值語句進(jìn)行指針初始化,如:

inta,*pa;

pa=&a;賦值后將變量a的地址賦給指針pa。

方法二:在定義指針變量的同時(shí)進(jìn)行初始化如:

inta,*pa=&a;將變量a的地址賦給指針。

注真:不要將其與一般的賦值語句混淆,也不要表示

成:inta,*pa;

*pa=&a;這是錯(cuò)誤的。

12

【例9.1】通過指針變量訪問整型變量。

程序代碼如下:

/*c09_0Lc*/

#include''stdio.h"

main()程序的運(yùn)行結(jié)果為:

{inta,b;10,20

int*pl/p2;10,20

a=10;b=20;

pl=&a;p2=&b;

printf(n%d,%d\n'「a,b);

printf(n%d,%d\nn/pl/p2);

J3

9.L5引用指針變量

引用變量的方式有兩種:用變量名直接引用,也可以通過指

向變量的指針間接引用。

【例9.2】分析程序的執(zhí)行過程比較變量引用方式。

直接引用方式:

#include<stdio.h>

main()

{inta,b;

scanf(n%d%dn,&a,&b);

/*在scanf函數(shù)中直接使用變量a和b的地址*/

printf(na=%d,b=%d\nn,a,b);

/*直接輸出變量a和b的值刃

}

14

間接引用方式:通過變量的地址輸出變量的值

#include<stdio.h>

main(){inta,b,*pa,*pb;

pa=&a,pb=&b;/*指針pa和pb分別指向變量a和b*/

scanf(n%d%dM,pa,pb);

printf(na=%d,b=%d\n!\*pa,*pb);

/*通過*運(yùn)算符實(shí)現(xiàn)間接訪問*/

}

運(yùn)行程序:程序的運(yùn)行結(jié)果為:

217J

a=21,b=7

15

【例9.3】輸入a和b兩個(gè)數(shù),按大小順序輸出a和b。

程序代碼如下:/*c0902-2.C/

#include"stdio.h"程序的運(yùn)行結(jié)果為:

main()Inputa=?,b=?:59J

{inta,b;a=5,b=9

int*pl,*p2,*p;max=9,min=5

printf(rrInputa=?,b=?\n");

scanf(〃%d%d〃,&a,&b);

pl=&a;p2=&b;

if(a<b){p=pl;pl=p2;p2=p;}

printf("\na=%d,b=%d\n”,a,b);

printf("max=%d,min=%d\n",*p2);

}

16

9.2指針與函數(shù)

■前面章節(jié)我們?cè)诤瘮?shù)之間傳遞過一般的變量

的值,同樣在函數(shù)之間可以傳遞指針。

■函數(shù)利用指針傳遞參數(shù)有三種方式:

□1.指針作為函數(shù)的參數(shù);

□2.指針作為函數(shù)的返回值;

□3.利用指向函數(shù)的指針傳遞。

17

9.2.1指針作函數(shù)的參數(shù)

利用指針傳遞函數(shù)的參數(shù)是一種間接傳值方式。

知道變量的地址就可以通過地址間接訪問變量的數(shù)值,

通過地址間接訪問變量的數(shù)值就是通過指針間接訪

問指針?biāo)傅膬?nèi)容。指針作函數(shù)的參數(shù)就是在函數(shù)

間傳遞變量的地址。

此時(shí),在調(diào)用函數(shù)時(shí)變量的地址作為實(shí)參,被調(diào)用函

數(shù)使用指針變量作為形參接收傳遞的地址。

18

【例9.4]使用函數(shù)phis求兩個(gè)數(shù)的和。

#include<stdio.h>

程序的運(yùn)行結(jié)果為:

main()EnterAandB:820J

{inta,b,c;A+B=28

printf(nEnterAandB:

n!

scanf(%d%d\&a9&b);

c=phis(&a,&b);/*調(diào)用phis函數(shù),實(shí)參為變量a和b的地

址*/

printf(°A+B=%d!\c);

)

intplus(int*px,int*py)/*形參為指向整型變量的指針刃

{return(*px+*py);/*返回兩個(gè)整數(shù)的和*1

■我們學(xué)習(xí)函數(shù)時(shí)知道,函數(shù)調(diào)用結(jié)束時(shí)返回一個(gè)結(jié)

果,是函數(shù)的返回值,這個(gè)返回值只有一個(gè)。

■如果試圖用一個(gè)函數(shù)交換主函數(shù)main中兩個(gè)變量值,

并將交換的結(jié)果返回主函數(shù),使用普通變量做函數(shù)

參數(shù)是無法實(shí)現(xiàn)。

■可以采用兩個(gè)指針變量傳遞地址的方式完成,即設(shè)

置兩個(gè)指針變量做函數(shù)的參數(shù)。

20

【例9.5】用函數(shù)交換main函數(shù)中兩個(gè)變量的值。

■voidswap(int*px,int*py)PXa

■{intt;

■t=*px;

px=*py;

■*py=t;

■printf(ninswap:*px=%d,*py=%d\n'\*px,*py);

■}________________

■voidmain()I程序的運(yùn)行結(jié)果為:

■{inta,b;Ibeforeswap:a=5,b=10

■a=5;b=10;Iinswap:*px=10,*py=5

■printf(nbeforeswap:a=%d|afterswap:a=10,b=5

■swap(&a,&b);

■printf(nafterswap:a=%d,b=%d\nn,a,b);

以下程序能否改變即b的值?

■voidswap(intx,inty)Xa

□{intt;

口t=x;x=y;y=t;}

■main()

■{inta,b;

■scanf(“%d,%d”,&a,&b);

■if(a<b)swap(a,b);

■printf("a=%d,b=%d\n”,a,b);

■運(yùn)行:輸入:5,8J

■輸出:a=5,b=8

22

練習(xí)題(1)

■voidfun(int*x)

□{printf(66%d”,++*x)

□*x=10;

□)

■main()

□{inta=25;

□fun(&a);

printf(“%d”,a);

口}

■運(yùn)行結(jié)果2610

23

練習(xí)(2)

■intast(intx^inty,int*qp,int*Qp)

■main

■ast(a,b\&c\&d);

■printf(^%d%d\n",.d);

■結(jié)果顯示71

24

9.2.2函數(shù)返回指針

指針能作為函數(shù)的返回值。過去我們將整型等簡(jiǎn)單類型作為

返回值,現(xiàn)在我們將函數(shù)的返回值設(shè)置為指針,

一般定義形式:

數(shù)據(jù)類型*函數(shù)名(參數(shù)列表)

〃數(shù)據(jù)類型〃后面的*表示:函數(shù)的返回值是一個(gè)指向該數(shù)據(jù)類

型的指針。注意,此時(shí)定義的是函數(shù),而不是指針。

25

■[例9.6]使用函數(shù)求兩個(gè)變量的最大值。

voidmain()

■{inta,b,*max;

■int*maxi(int*x,int*y);

■printf(uEnterab:n);運(yùn)行結(jié)果如下:

■scanf(n%d&b);Enterab:128J

■max=maxl(&a,&b);max=12

■printf(''max=%d\n'',*max);

■}

■int*maxi(int*x,int*y)

■{int*p;

■p=*x>*y?x:y;

■return(p);

}

26

9.2.3指向函數(shù)的指針

在定義一個(gè)函數(shù)之后,編譯系統(tǒng)為每個(gè)函數(shù)確定一個(gè)

入口地址,當(dāng)調(diào)用該函數(shù)的時(shí)候,系統(tǒng)會(huì)從這個(gè)

“入口地址”開始執(zhí)行該函數(shù)。

函數(shù)名代表函數(shù)的入口地址.

存放函數(shù)的入口地址的指針就是一個(gè)指向函數(shù)的指針,

簡(jiǎn)稱函數(shù)的指針。

函數(shù)的指針的定義格式:

類型標(biāo)識(shí)符(*指針變量名)()

27

類型標(biāo)識(shí)符為函數(shù)返回值的類型。特別值得注意的是,由于c

語言中,()的優(yōu)先級(jí)比*高,因此,〃*指針變量名〃外部

必須用括號(hào),否則指針變量名首先與后面的()結(jié)合,就是

前面介紹的〃返回指針的函數(shù)〃。試比較下面兩個(gè)定義語句:

int(*pf)();/*定義一個(gè)指向函數(shù)的指針,該函數(shù)的返

回值為整型數(shù)據(jù)*/

int*f();/*定義一個(gè)返回值為指針的函數(shù),該指針

指向一個(gè)整型數(shù)據(jù)*/

和變量的指針一樣,函數(shù)的指針也必須賦初值,才能指向具

體的函數(shù)。由于函數(shù)名代表了該函數(shù)的入口地址,因此,

一個(gè)簡(jiǎn)單的方法是:直接用函數(shù)名為函數(shù)指針賦值,即:

函數(shù)指針名二函數(shù)玄

函數(shù)型指針經(jīng)定義和初始化之后,在程序中可以引用該指針,

目的是調(diào)用被指針?biāo)傅暮瘮?shù)。由此可見,使用函數(shù)型指

針,增加了函數(shù)調(diào)用的方式。

28

用指向函數(shù)的指針變量調(diào)用函數(shù)

■函數(shù)的指針:指函數(shù)的入口地址。

■函數(shù)名:代表函數(shù)的入口地址。

■指向函數(shù)的指針變量的定義:類型名(*變量名)()

■例:int(*p)();定義p為指向整型函數(shù)的指針變量。

■例:求a、b中的較大者。

■intmax(intx,inty)/*定義函數(shù)*/

■{intz;

■z=(x>y)?x:y;

■returnz;}

29

方法1:直接調(diào)用函數(shù):方法2:用指針變量調(diào)用函

數(shù):

main()

main()

{intabc;

{inta,b,c;99

int(*p)();

scanf("%d,%d”,&a,&b);

p=max;/*p指向函數(shù)*/

c=max(a9b);/*調(diào)用函數(shù)*/

scanf(n%d%d!\&a&b);

printf(“max=%d\n",c);95

c=(*p)(a,b);/*調(diào)用函數(shù)*/

printf(umax=%d\n!\c);

30

【例9.7]用指針調(diào)用函數(shù),輸出三個(gè)數(shù)中最大值。

funmax(intx,inty)

{return(x>y)?x:y;運(yùn)行結(jié)果如下:

)2,34,8J

main()a=2,b=34,c=8,

max=34

{intrpf)O;

inta,b,c,d,e;

pf=funmax;/*指針變量指向funmax函數(shù)*/

scanfC6%d,%d%d%&a,&b,&d);

c=(*pf)(a,b);9/*等彳介于?=£11111114乂(4力)*/

e=(*pf)(c,d);/*等價(jià)于e=funmaxCd)*/

nn

prmtf(a=%d,b=%d5d=%d9max=%d,a9b,d,e);

31

當(dāng)一個(gè)指針指向一個(gè)函數(shù)時(shí),通過指針,就可以訪問

它指向的函數(shù)。

需要注意的是,一個(gè)函數(shù)指針可以先后指向不同的函

數(shù),將哪個(gè)函數(shù)的地址賦給它,它就指向哪個(gè)函數(shù),

使用該指針,就可以調(diào)用函數(shù).

另外,如果有函數(shù)指針(*pf)(),則pf+n、pf++、

pf一等運(yùn)算是無意義的。

32

9.3指針與數(shù)組

我們可以定義指針來訪問數(shù)組元素。一個(gè)變量在內(nèi)

存中有相應(yīng)的地址,而數(shù)組包含多個(gè)元素,每個(gè)

數(shù)組元素在內(nèi)存中都占有一個(gè)內(nèi)存地址,因此我

們也可以定義一個(gè)指針指向這個(gè)地址。

元素的指針:是指數(shù)組每個(gè)元素的地址

數(shù)組的指針:是指數(shù)組的首地址。

數(shù)組名:代表數(shù)組首地址。

可以利用指針引用數(shù)組元素。

33

9.3.1通過指針引用一維數(shù)組元素

■在數(shù)組中我們已經(jīng)知道,可以通過數(shù)組的下標(biāo)唯一確定某

個(gè)數(shù)組元素在數(shù)組中的順序和存儲(chǔ)地址。

■例如:inta[5]={1,2,3,4,5},x,y,*p;

■通過下標(biāo)可直接訪問數(shù)組a中的元素:

■x=a[2];y=a[4];

■由于每個(gè)數(shù)組元素相當(dāng)于一個(gè)變量,因此指針變量可以指

向數(shù)組中的元素,也就是可以用“指針方式”訪問數(shù)組中

的元素。

■指向數(shù)組元素的指針,與指向變量的指針相同。

■例:inta[10];int*p;

■p=&a[0];/*等價(jià)于p=a;數(shù)組的首地址賦給p*/

■或初始化指針變量:int*p=&a[0];等價(jià)于:int*p=a;

34

地址o

■若int*p=a;(BPp=&a[OJ).a

P,a—

■則等價(jià)于

*p=l;a[O]=l;p+1,a+1

(等于指向下一個(gè)元素

■p+1a[l]p+2,a+2

■p+i(等于&a[i])指向元素a[i]

rO

p+i,a+履LA^

nG

p+9,a+9_>aV

=

35

■因?yàn)?a+l,p+l是a[l]的地址

■則*(p+l)或*(a+l)等價(jià)于a[l]

■因?yàn)椋篴+i,p+i是a[i]的地址,

■貝lj*(p+i)或*(a+i)等價(jià)于a[i]

■例:*(a+9)=10;或*(p+9尸10;

等價(jià)于:a[9]=10;

■*(p+i)也可以表示為p[i]0

■總之,數(shù)組元素引用方法如下:

■(1)下標(biāo)法:a[i]

■(2)指針法:*(a+i)、*(p+i)或p[i]

36

【例9.8】數(shù)組元素的三種引用方法。

(1)下標(biāo)法。

程序代碼如下:

/*c09_08_l.c*/

#includenstdio.h"

main()

{intaflOJ;

inti;

for(i=0;i<10;i++)

nn

scanf(%d9&a[i]);

printf(n\n");

for(i=0;i<10;i++);

printf(n%d「a[i]);

printf(n\nn);

}

37

(2)通過數(shù)組名計(jì)算數(shù)組元素地址,求元素的值。

程序代碼如下:/*c09_08_2.c*/

#include"stdio.h"

main()

{inta[10J;

inti;

for(i=0;i<10;i++)

scanfC%dH,或scanf("%d[a+i);

printf(n\nn);

for(i=0;i<10;i++)printf(n%dn,*(a+i));

printf(n\nn);

(3)通過指針變量得到元素的值。

程序代碼如下:/*c09_08_3,c*/

#include<stdio.h>

main()

{inta[10J;三個(gè)程序運(yùn)行結(jié)果相同如下:

intij;1234567890

int*p=a;1234567890

for(i=0;i<10;i++)

scanf(〃%d〃,&a[i]);

printf("\n");

for(i=0;i<10;i++)

{printf(〃%(T,*p);p++;}

printf("\n");

39

地址

【例9.9】分析程序。a[]

p=a―>

main()1a[0]

押二

{inta[]={1,2,3,4,5,6};2a[l]

int*p;3a[2]

p=a;/*指針p為數(shù)組的首地址刃a+34

5

printf(n%dfl,*p);p+二3

6a[5]

printf(n%d\n”,*(++p));

printf(n%dn,*++p);

printf(n%d\nn,*(p--));

p+=3;

printf(n%d%d\nf\*p,*(a+3));運(yùn)行結(jié)果:

12

33

5440

注意,

例中*(++p)等價(jià)于*++p,表示:先使p=p+l,再取

*p的值。

而尸是先取指針P值作“”運(yùn)算,再使指針P自

減1。

*p++表示:先取*P的值,再使p=p+l

41

練習(xí)

■main()

■{inta[10]={l,2,3,4,5,6,7,8,9,0};

■int*p=a;

■printf("%d,%d\iTJ(p+2),p[5]);

■printf(^%dJ:*a);

■printfC%d\n”,*(a+8));

■}3,6

■輸出結(jié)果1,9

?可見對(duì)一維數(shù)組而言,a指向a[0]、a+i指向a[i]

42

9.3.2指針基本運(yùn)算

對(duì)于指針的運(yùn)算有:指針的加減運(yùn)算和兩個(gè)指針的關(guān)

系運(yùn)算。

1.指針的加、減運(yùn)算

當(dāng)指針P指向數(shù)組中的元素時(shí),n為一個(gè)正整數(shù),表達(dá)

式:p±n表示:指針p所指向當(dāng)前元素之后或之

前的第n個(gè)元素。

最常見的指針加減運(yùn)算p++、P--的含義是:

指針加1,指向數(shù)組中的后一個(gè)元素;

指針減1,指向數(shù)組中的前一個(gè)元素。指針與整數(shù)進(jìn)

行加減運(yùn)算后,它們的相對(duì)關(guān)系如圖9.7所示。

43

數(shù)組指針

P-R

p-2

p-1

p指針當(dāng)前位置

p+1

p+2

p+n

圖9.7指針的加減運(yùn)算

44

■注意:p++操作,改變了指針變量的值。使用時(shí)要注意指針

變量所指的當(dāng)前位置。

■而a++是不允許的。因?yàn)閍是數(shù)組名,固定代表數(shù)組首地址。

■例:注意下題中出現(xiàn)的問題

□main()

□{inta[10],i,*p;

□p=a;

□for(i=0;i<10;i++)

□scanf(^%d工p++);

□printf(“\n”);

□for(i=0;i<10;i++,p++)

□printf(“%d”,*p);

□)

45

■上例中,由于第一個(gè)循環(huán)中p++使P指向下一個(gè)元素,

循環(huán)結(jié)束時(shí),p指向*(a+10),所以第二個(gè)循環(huán),用

P輸出的是a數(shù)組以外的內(nèi)存中的數(shù)據(jù)。

■因此在第二個(gè)循環(huán)之前,應(yīng)重新設(shè)置P指針的初值:

■for(p=a4=0;i<10;i++,p++)

printf(6<;p<a+10;

■也可以改為:

□for(p=aJ=0;i<10;i++)

□printf(u%d”,*p++);

46

■由于指針P所指的具體對(duì)象不同,所以對(duì)指針與整

數(shù)進(jìn)行加減運(yùn)算時(shí),C語言會(huì)根據(jù)所指的不同數(shù)據(jù)

類型計(jì)算出不同的存儲(chǔ)單元的大小,以保證正確操

作實(shí)際的運(yùn)算對(duì)象。

■數(shù)據(jù)類型的存儲(chǔ)單元的大小等于一個(gè)該數(shù)據(jù)類型的

變量所占用的內(nèi)存單元字節(jié)數(shù)。

■對(duì)于char型,存儲(chǔ)單元的大小為1字節(jié);

■對(duì)于int型,存儲(chǔ)單元的大小為2字節(jié);

■對(duì)于long型,存儲(chǔ)單元的大小為4字節(jié);

■對(duì)于double型,存儲(chǔ)單元的大小為8字節(jié)。

■p+1運(yùn)算,其中的1意味著是該類型變量的一個(gè)存

儲(chǔ)單元。

47

【例9.10】編程將串strl復(fù)制到串str2中。

main()

{charstr1[80],str2[80],*pl,*p2

printf("Enterstring1:");

gets(strl);

pl=strl;

p2=str2;

while((*p2=*pl)!='\0')/*pl所指的元素內(nèi)容送到

p2所指的元素中*/

{pl++;p2++;}/*指針pl和p2分別后移1個(gè)元素*/

printf("String2:〃j

運(yùn)行結(jié)果如下:

puts(str2);I

Enterstring1:china

String2:china

48

程序中的關(guān)鍵是while語句,“(*p2=*pl)!二‘\0’”

的含義是:

先將指針P1所指元素的內(nèi)容送到指針P2所指元素的元

素中,然后再判斷所賦值的字符是否是串結(jié)束標(biāo)記

'\0',如果不是串結(jié)束標(biāo)記,則執(zhí)行循環(huán)繼續(xù)進(jìn)行字

符復(fù)制;如果是串結(jié)束標(biāo)記,則退出循環(huán),完成串復(fù)

制。

對(duì)于上面程序中的while循環(huán),可以進(jìn)行如下改進(jìn):

方法一:

while(*p2=*pl)

{pl++;p2++;}

方法二:

while(*p2++=*pl++);

/*循環(huán)體為空語句*/

49

【例9.n】編寫程序求字符串的長(zhǎng)度。

分析:字符串的存儲(chǔ)結(jié)束標(biāo)志為、0、可以設(shè)置一個(gè)指針

變量P指向字符串首字符,判斷p當(dāng)前所指的字符如果

為非,網(wǎng),則p++,指向下一個(gè)字符,再判斷,直到p指

向字符串尾,程序結(jié)束。字符串的長(zhǎng)度應(yīng)為p的當(dāng)前位

置與字符串首地址的差。

main()

運(yùn)行結(jié)果如下:

{charstr[50],wp=str;

Enterstring:china」

nn;

printf(Enterstring:)Stringlength=5

gets(str);

while(*p)

p++;

printf(nStringlength=%d\nn,p-str);

}

50

2.兩個(gè)指針的關(guān)系運(yùn)算

只有當(dāng)兩個(gè)指針指向同類型的數(shù)據(jù)元素時(shí),才能進(jìn)行關(guān)系運(yùn)

算。即:

■P<q當(dāng)P所指的元素在q所指的元素之前時(shí),表達(dá)式的值為

1;反之為0。

■p>q當(dāng)P所指的元素在q所指的元素之后時(shí),表達(dá)式的值為

1;反之為0。

■p==q當(dāng)P和q指向同一元素時(shí),表達(dá)式的值為1;反之為0。

■p!二q當(dāng)P和q不指向同一元素時(shí),表達(dá)式的值為1;反之為

0o

51

■任何指針p與NULL進(jìn)行“p二二NULL”或“p!二NULL”

運(yùn)算均有意義,

■“p二二NULL”的含義是當(dāng)指針p為空時(shí)關(guān)系表達(dá)式

為真

■〃p!二NULL〃的含義是當(dāng)p不為空時(shí)表達(dá)式為真。

■指向兩個(gè)不同數(shù)組的指針進(jìn)行比較,沒有任何實(shí)際

的意義。

52

【例9.12】編寫程序?qū)⒁粋€(gè)字符串逆置。

#include<stdio.h>

main()運(yùn)行結(jié)果如下:

{charstr[50],*p,*s,c;Enterstring:china

printf(nEnterstring:");anihc

gets(str);

p=s=str;/*指針p和s指向str數(shù)組*/

while(*p)

p++;/*找到串結(jié)束標(biāo)記)(T號(hào)

p--;/*指針回退一個(gè)字符,使p指向最后一個(gè)字符刃

while(s<p)/*當(dāng)串前面的指針串后面的指針p時(shí),進(jìn)行循環(huán)*/

{C=*s;/*交換兩個(gè)指針?biāo)赶虻淖址?/

*s++=*p;/*串前面的指針S向后(+1)移動(dòng)刃

*p-=C;/*串后面的指針P向前(-1)移動(dòng)*/

}

puts(str);

53

9.3.3通過指針引用二維數(shù)組元素

■二維數(shù)組a[3][4],有以下元素:

a[O]¥a[O][O]a[O][l]a[0][2]a[0][3]

a[l]-a[l][O]曬HLa[l][2]a[l][3]

a[2]E][0]a[2][l]a[2][2]a[2][3]

■二維數(shù)組a[3][4]可以理解為:

■a數(shù)組中,包含3個(gè)元素:a[O]a[l]a[2],每

個(gè)元素都是一個(gè)一維數(shù)組的名字,代表該

行元素的首地址。

54

■1.多維數(shù)組的地址

■若定義以下數(shù)組:

■inta[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};

■可理解為:a數(shù)組包含3個(gè)元素:a[0]>a[l]>a[2]

■這三個(gè)元素本身各代表一個(gè)一維數(shù)組。

■a:代表數(shù)組首地址,指向a[0],即第0行首地址

■a+1:指向即第1行首地址

■賽a為行指針」可見:行指針+1,將指向下一行元素。

a-={1357}

a+Ja[l]={9111315}

a+2一[聞={17192123}

55

列地址:a[0]a[O]+la[0]+2a[0]+3

a—4a[o]={i357)

a+1-a[l]={9111315}

a+2一={17192123)

a[O]:是第0行元素的首地址——&a[O][O]

a[O]+l:是&a[O][lba[0]+2是&a[0][2]

可見,列指針+1.指向下一個(gè)元素.

a[l]:是第1行元素的首地址——&a[l][O]

a[2]:是第2行元素的首地址——&a[2][0]

*a[O]:是a[O][O]元贅

*(a[O]+l):是時(shí)0]口]三素

*(a[2]+l):是元素

所以元素用列指針表示為*(a[i]+j)

<AU56

元素用列指針表示為*(a[i]+j)

用行指針a表示元素:

■*a即*(a+0):表示a[0](即列指針)

■*(a+l):表示a[l]

■*(a+i):表示a[i]

■因而*(a[i]+j)可表示為*(*(a+i)+j)

■因?yàn)橛昧兄羔樢迷氐男问?*(a[i]+j)

■所以表示元素。

■總之:

■行指針a,加1,指向下1行;

■列指針a[0],加1,指向下1個(gè)元素。

■要找到某行中的某個(gè)元素,要用列指針a[i]運(yùn)算

■要找到某行的首地址,要用行指針a運(yùn)算

■*a=a[O](列指針)

57

2.指向二維數(shù)組的指針變量p=a[OL1

p++―A2

■(1)存放列地址的指針變量3

■這種指針變量,可以尋找到每個(gè)元素。4

■定義形式和指向普通變量的指針變量一樣。一

■【例9.13】多維數(shù)組的輸出。工

■main()

■{inta[3][4]={{l,2,3,4},{5,6,7,8},{9J8Jl」2}};1f

■int*P;a[O]+ll—JI

■for(p=a[0];p<a[0]+12;p++)/*p得到列地Ha[0]*/

if((p-a[0])%4==0)printff6\nw);

printf("%4d”/p);}程序的運(yùn)行結(jié)果為:

1234

5678

9101112

58

■(2)指向m個(gè)元素組成的一維數(shù)組的指針變量

■定義格式:int(*p)[m|;

■則p+1移過m個(gè)元素。

■可見:這里p應(yīng)接受行地址。

59

【例9.14】給定某年某月某日,將其轉(zhuǎn)換成這一年的第

幾天并輸出。

#include<stdio.h>

main()

{intday_tab[2][13]=

{{0,31,28,31,30,31,30,31,31,30,31,30,31},

{0,31,29,31,30,31,30,31,31,30,31,30,31}};

inty,m,d;

scanf(H%d%d%df\&y,&m,&d);

printf(n%d\nn,day_o^year(day_tab,y,m,d));/*實(shí)參

為二維數(shù)組名*/一

60

■day_o^year(int(*day_tab)[13],intyear,intmonth,intday)

■/*形參為指向13個(gè)元素的一維數(shù)組的指針變量*/

■{inti5j;

■i=(year%4==0&&year%100!=0)||year%400==0;/*為閏

年i=l,否則i=0*/

■for(j=l;j<month;j++)

■day+=*(*(day_tab+i)+j);

■return(day);

■}

■運(yùn)行結(jié)果如下:

■200023/*輸入數(shù)據(jù)年月日*/

■34

61

9.4字符串與指針

■9.4.1字符數(shù)組與字符指針

■字符串的訪問方法:用字符串的首地址。

■字符數(shù)組名,代表字符串的首地址。

■L字符數(shù)組存放字符串

■例如,有語句:charstring[]=66IamChinese.”;

■此時(shí),string是字符數(shù)組,存放了一個(gè)字符串。

■例main()

■{charstring[]="IamChinese.59;

■printff6%s55,string);

運(yùn)行時(shí),輸出:

IamChinese.

62

2用字符指針變量指向一個(gè)字符串。

■字符指針也可以指向一個(gè)字符串。我們可以用字符串常量

對(duì)字符指針進(jìn)行初始化。例如,有語回

■char*str="China.";對(duì)字符指針進(jìn)行初始化。

■此時(shí),字符指針變量存放的是字符串的首地址,即指向字

符串的首地址。

■例main()

str-

■{char*str="China.”;h

■printf(66%s5\str);str+2—>*

■printf("%s\ntr+2);n.

SL

■}

■運(yùn)行結(jié)果顯示:\o

■China,ina.

■這里char*str="China.";等價(jià)于以下兩行:

char*str;

str=6'China.”;

63

在程序中,可以使用如下語句:

str++;/*指針str加1*/

str="ThisisaNEWstring.";/*使指針指

向新的字符串*/

str=strl;/*改變指針str的指向*/

strcpy(string,“ThisisaNEWstring.")/*

改變字符數(shù)組的的內(nèi)容*/

strcat(string,str)/*進(jìn)行串連接操作*/

strcpy(str,string)/*指針變量沒有初始化時(shí),

不要向str進(jìn)行串復(fù)制,可能會(huì)破壞其它數(shù)據(jù)*/

64

9.4.2常見的字符串操作

■由于使用指針編寫的字符串處理程序比使用數(shù)組方式處理

字符串的程序更簡(jiǎn)潔、更方便,所以在c語言中中,大量使

用指針對(duì)字符串進(jìn)行各種處理。

■在處理字符串的函數(shù)中,一般都使用字符指針作為形參。

■由于數(shù)組名代表著數(shù)組的首地址,因此在函數(shù)之間可以采

用指針傳遞整個(gè)數(shù)組,這樣在被調(diào)用函數(shù)的內(nèi)部,就可以

用指針方式訪問數(shù)組中的元素。

■下面我們來看幾個(gè)使用指針處理字符串的程序。

65

【例9.15]用字符指針指向一個(gè)字符串。

程序代碼如下:

/*c09_15.c*/

#includenstdio.hn

main(){

char*str=nhelloworldn;

printf(n%s\nn,str);

}

運(yùn)行結(jié)果如下:

helloworld

66

程序分析與注意事項(xiàng):

這里的str是指向字符串“helloworld”的指針,即

字符串的首地址賦給了字符指針,使一個(gè)字符指

針指向了一個(gè)字符串。

C語言對(duì)字符串常量是按字符數(shù)組處理的,在內(nèi)存

開辟了一個(gè)字符數(shù)組用來存放字符串常量。

定義str的部分:char*str="helloworld7;

str被定義為一個(gè)指向字符型數(shù)據(jù)的指針變量,在

指向字符串時(shí),并不是把字符串的所有的字符存

放到str中,也不是把字符串賦給*str,只是把

字符串的首地址賦給字符指針。

67

下面的情況是不允許的:

char*str;

scanf("%s",str);

因?yàn)橹羔槢]有明確的指向,其值是任意的,也許所

指向的區(qū)域不是用戶可以訪問的內(nèi)存區(qū)域,或者

是根本不存在的地方。

輸出一個(gè)字符串時(shí),系統(tǒng)先輸出字符指針?biāo)赶虻?/p>

一個(gè)字符數(shù)據(jù),然后自動(dòng)使str加1,指向下一個(gè)

字符,直到遇到字符串結(jié)束標(biāo)志’\0’為止。

68

雖然字符數(shù)組和字符指針都可以用來表達(dá)字符串,但是它們

還是有不同之處,例如:

charstring口二“helloworld”;

char*str="helloworld”;

■string和str的值都是字符串"helloworld”的首地址,但是

string是一個(gè)字符數(shù)組,名字本身是一個(gè)地址常量;而str

是指向字符串首地址的指針變量。

■因而str可以被賦值,而string不能。例如str+=2可以,但

string+=2則不可以.

■若定義了一個(gè)指針變量,并使它指向一個(gè)字符串,就可以

用下標(biāo)形式引用指針變量所指向的字符串中的字符。

■如str[l]表示*(str+l),即串中第2個(gè)字符Q。

69

【例9.16】用指針作為函數(shù)的形式參數(shù),編寫字符串復(fù)制函

■#include<stdio.h>運(yùn)行結(jié)果如下:

■main()Enterstring:china

■{chara[30],b[30];a=china

b=china

■printf(nEnterstring:'');

■scanf(n%s!\a);

■strcopy(a,b);/*調(diào)用函數(shù)的實(shí)參為數(shù)組名,即數(shù)組的首址*/

■printf(na=%s\nb=%s\nu,a,b);

■)

■voidstrcopy(char*strl,char*str2)/*函數(shù)的形參為指

針變量*/

■{while(*str2++=*strl++);/*通過指針操作實(shí)參數(shù)組*/

}

70

【例9.17]編寫函數(shù),求字符串的長(zhǎng)度。

intstrlen(char*str)

{char*p=str;

while(*p)

p++;/*指針后移,直到串尾*/

return(p-str);_______

運(yùn)行結(jié)果如下:

main()Enterstring:English

{chara[50];Stringlength=7

printf(MEnterstring:11);

scanf(n%sn,a);

printf(nStringlength=%d\nn,strlen(a));

71

【例9.18]編寫函數(shù),實(shí)現(xiàn)兩個(gè)串的連接。

#include<stdio.h>

char*strcat(char*strl,char*str2)

{char*p=strl;

while(*p)p++;/*找至U串strl的尾刃

while(*p++=*str2++);

return(strl);}運(yùn)行結(jié)果如下:

main()Enterstringl:penJ

{chara[50],b[30];Enterstring2:childJ

printf(nEnterstringl:n);a+b=penchild

scanf(n%sn,a);

printf(nEnterstring2:'');

scanf(n%s!\b);

printf(na+b=%s\nn,strcat(a,b));}

72

【例9.19]用下標(biāo)的形式引用字符串中的元素。

程序代碼如下:/*c09_19.c*/

nn

#includestdio.h運(yùn)行結(jié)果如下:

main()Thefifthcharcteriso

{char*a="helloworld'';helloworld

inti;

printf(nThefifthcharcteris%c\n!\a[4]);

for(i=0;a[i]!=l\0,;i++)

printf(n%cl\a[i]);

printf(n\nn);

73

【例9.20]輸入兩個(gè)有序的字符串(小f大),編寫一

個(gè)合并兩個(gè)字符串的函數(shù),使合并后的字符串,

仍然是有序排列。程序代碼如下:

#include<stdio.h>stri[80]H2ac\o

■main()P

■{charstr1[80],str2[80],str[80];str2[80]]?bgh\0一

■char*p,*q,*r,*s;彳一

■inti,j,n;str[80]]

■printf(nEnterstringl:n);gets(strl);1

■printf(uEnterstring?:'');gets(str2);

■for(p=strl,q=str2,r=str;*p!=f\0f&&*q!=\(F;)

■if(*pv*q)*r++=*p++;/*若strl中的字符較小,則將它復(fù)

制至l]str中*/

■else*r++=*q++;/*若str2中的字符較小,則將它復(fù)制

至!Jstr中*/

74

■s=(*p)?p:q;/*判斷哪個(gè)字符串還沒有處理完畢*/

■while(*s)/*繼續(xù)處理(復(fù)制)未處理完畢的字符串*/

■*r++=*s++;

■*r=,\0,;/*向str中存入串結(jié)束標(biāo)記*/

■printf(^Result:11);

■puts(str);}運(yùn)行結(jié)果如下:

Enterstringl:112ac

Enterstring2:Obgh

Result:0112abcgh

75

9.5指針數(shù)組、數(shù)組指針及應(yīng)用

951指針數(shù)組與指向數(shù)組的指針變量

■1指針數(shù)組:

■數(shù)組中的每個(gè)元素,都是指針變量。

■一維指針數(shù)組的定義形式:inttpa[5]inta[5]

■類型名*數(shù)組名[常量表達(dá)式]pa[0]&a[(ga[0]

例如:int*pa[5];pa[l]&a[lja[l]

表示定義一個(gè)由5個(gè)指針變量構(gòu)成的pa[2]&a[2;a[2]

指針數(shù)組pa,數(shù)組中的每個(gè)數(shù)組元素pa[3]&a[31a[3]

都是指針,都可指向一個(gè)整數(shù).pa[4]&a[45a[4]

設(shè)有:inta[5],*pa[5];

for(i=0;i<5;i++)

pa[i]=&a[i];

76

2指向m個(gè)元素組成的一維數(shù)組的指針變量

定義的形式為:

類型(*數(shù)組名)[m];

例如:int(*pb)[5];

表示定義一個(gè)指向數(shù)組的指針變量pb,pb指向

的數(shù)組是5個(gè)元素組成的一維整型數(shù)組.

■則pb+1將移過5個(gè)元素。

■可見:這里pb可以接受二維數(shù)組的行地址。

例如:char*line[5];

表示line是一個(gè)數(shù)組,每個(gè)元素是一個(gè)指向字符型數(shù)據(jù)的一

個(gè)指針。若設(shè)指向的字符型數(shù)據(jù)(字符串)分別是“ONE”、

“TWO”、…、"FIVE”,則數(shù)組line的結(jié)構(gòu)如圖9.H所示.

指針數(shù)組常適用于指向若干字符串,這樣使字符串處理更加

靈活方便。

line[0]

line⑵

line[3]

line[4]

圖9.n指向字符串常量的指針

數(shù)組

78

【例9.21]輸入一個(gè)字符串,判斷該字符串是否是英文的星

期幾。使用指針數(shù)組實(shí)現(xiàn)。

程序代碼如下:/*c09_21.c*/

#include<stdio.h>

char*week_day[8]={''sun'',''mon'',ntuen,''wed'',

"thu'',Z'fri","sat”,NULL};

/*定義指針數(shù)組。數(shù)組中的每個(gè)元素指向一個(gè)字符串*/

main()

{intm;

charstring[20];

printf(uEnterastring:'');

scanf(n%sn,string);

m=lookup(string);

printf(nl=%d\nu,m);}

lookup(charch[])/*傳遞字符串(字符數(shù)組)*/

{inti,j;

char*pc;

for(i=0;week_day[i]!=NULL;i++)/*完成查找工作刃

{for(pc=week_day[i],j=0;*pc==ch[j];j++,pc++)

if(*pc==6\0f)return(i);/*若找到則返回對(duì)應(yīng)的序號(hào)*/

)

return(-l);/*若沒有找到,則返回-1*/

運(yùn)行結(jié)果如下:

Enterastring:wedJ

1=3

80

■程序中沒有使用二維的字符數(shù)組,而是采用指針數(shù)

組week_day??梢钥吹街羔様?shù)組比二維字符數(shù)組有

明顯的伍點(diǎn),一是指針數(shù)組中每個(gè)元素所指的字符

串不必限制在相同的字符長(zhǎng)度,二是訪問指針數(shù)組

中的一個(gè)元素是用指針間接進(jìn)行的,效率比下標(biāo)方

式要高。

81

【例9.22】輸入星期幾,輸出對(duì)應(yīng)星期的英文名稱。用指

針數(shù)組實(shí)現(xiàn)。

程序代碼如下:/*c09_22.c*/

#include<stdio.h>

char*week_day[8]={''sunday'',''monday'',ntuesdayn,

nWednesday0,nt

溫馨提示

  • 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)論