第09章指针课件_第1页
第09章指针课件_第2页
第09章指针课件_第3页
第09章指针课件_第4页
第09章指针课件_第5页
已阅读5页,还剩100页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第9章指针

本章要点:

0指针的概念

0指向数组的指针

0指针的各种应用

9.1指针与指针变量

■指针是C语言中的一个重要概念,也是C语言的重要

■指针类型是C语言的一种特殊的数据类型。正确而

灵活地应用指针,可以有效地表示复杂的数据结构、

动态地分配内存、方便地使用字符串、有效而方便

地使用数组、直接处理内存地址等。使用指针编写

的程序在代码质量上比用其他方法效率更高,因此

指针在C程序中用得非常多。指针是C语言的精华所

在,同时也是c语言的难点之一。学习指针应该充

分地理解指针的概念,在上机实践中进一步掌握它。

2

9.L1指针的概念

指针是一种数据类型,是一个变量在内存中所对应单元的

地址。

这个地址可以是变量的地址,也可以是数组、函数的起始

地址,还可以是一个指针变量的地址。

3

变量一经定义,系统为其分配存储单元。

如:inta=10,b=8;

内存中的每个字节有编号,称之为地址。

访问变量有直接和间接两种方式

■直接访问方式:按变量的

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

■如:a=10;

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

将键盘输入的数,送到

地址为2002开始的存储单元。

内存

4

■间接访问方式:将变量a的地址存放在另一个变量

p中。

■取a中数的过程:先通过p的内容,得到a的地址

2000,再到地址为2000的存储单元中取出数10。

■变量的地址称为指针。

■存放地址的变量p称为

指针变量。

5

9.1.2指针变量的定义

■定义格式:类型名*指针变量名

■例如:/*定义指向整型变量的指针*/

■float*p2;/*定义指向实型变量的指针*/

o

■使指针pl指向整型变量i:pl1

■pl=&i;

■使指针p2指向实型变量f:p2

■p2=&f;&f

■注意:指针变量只能放地址。

6

9.1.3指针变量的两种运算符

C语言提供了两种指针运算符:

&:取地址运算符。

*:指针内容运算符(也称为:间接访问运算符)

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

p=&x;/*将变量x的地址赋给指针变量p*/

*p是P所指向的变量。

y=*p;/*等价于y=x*/

7

■&和*两个运算符优先级相同

□结合性:从右到左。

若有int*p;p=&a;

(1)则&*p的含义:即相当于&(*p)

先执行*P操作,即访问a,

再进行&操作:即所以&*p等价于

(2)而*&a的含义:即相当于*(&a),

先执行&a,得到a的地址,

再对该地址取*操作:*(&a),得到a的值。

所以*&a等价于*p,等价于a。

8

■*与++优先级相同。

(1)*p++即相当于*(p++)

执行p++,先用p的原值,执行*p得a;然后执行p++,

p将示指向aTo

(2)(*p)++等价于:a++

■因为*p就是a,(*p)++就是(a)++,即a++

9

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

且有:px=&x;

则变量X与指向变量X的指针px之间有以下等价关系:

y=*px;等价于y=x;

(*px)++;等价于x++;/*对指针变量px的内容加1

*/

y=(*px)+5;等价于y=x+5;

y=*(&x);等价于y=x;/*y二变量x地址的内容

*/

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

指针P为空,没有指向任何对象。

10

注意:

L&运算符只能作用于变量,包括基本类型变量和数

组的元素、结构体类型变量或结构体的成员,不能

作用于数组名、常量或寄存器变量。

2.单目运算符*是&的逆运算,它的操作数是对象的

地址,*运算的结果是对象本身。单目*称为间接访

问运算符,是通过变量的地址存取(或引用)变量。

例如:doubler,a[20];

inti;则表达式&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指针变量的初始化

在使用指针变量前,要首先对指针变量进行初始化,

让指针变量指向一个具体的变量。进行指针变量初

始化的方式有两种:

方法一:使用赋值语句进行指针初始化,如:

inta,*pa;

pa=&a;赋值后将变量a的地址赋给指针pa。

方法二:在定义指针变量的同时进行初始化如:

inta,*pa=&a;将变量a的地址赋给指针。

注真:不要将其与一般的赋值语句混淆,也不要表示

成:inta,*pa;

*pa=&a;这是错误的。

12

【例9.1】通过指针变量访问整型变量。

程序代码如下:

/*c09_0Lc*/

#include''stdio.h"

main()程序的运行结果为:

{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】分析程序的执行过程比较变量引用方式。

直接引用方式:

#include<stdio.h>

main()

{inta,b;

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

/*在scanf函数中直接使用变量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);

/*通过*运算符实现间接访问*/

}

运行程序:程序的运行结果为:

217J

a=21,b=7

15

【例9.3】输入a和b两个数,按大小顺序输出a和b。

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

#include"stdio.h"程序的运行结果为:

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指针与函数

■前面章节我们在函数之间传递过一般的变量

的值,同样在函数之间可以传递指针。

■函数利用指针传递参数有三种方式:

□1.指针作为函数的参数;

□2.指针作为函数的返回值;

□3.利用指向函数的指针传递。

17

9.2.1指针作函数的参数

利用指针传递函数的参数是一种间接传值方式。

知道变量的地址就可以通过地址间接访问变量的数值,

通过地址间接访问变量的数值就是通过指针间接访

问指针所指的内容。指针作函数的参数就是在函数

间传递变量的地址。

此时,在调用函数时变量的地址作为实参,被调用函

数使用指针变量作为形参接收传递的地址。

18

【例9.4]使用函数phis求两个数的和。

#include<stdio.h>

程序的运行结果为:

main()EnterAandB:820J

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

printf(nEnterAandB:

n!

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

c=phis(&a,&b);/*调用phis函数,实参为变量a和b的地

址*/

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

)

intplus(int*px,int*py)/*形参为指向整型变量的指针刃

{return(*px+*py);/*返回两个整数的和*1

■我们学习函数时知道,函数调用结束时返回一个结

果,是函数的返回值,这个返回值只有一个。

■如果试图用一个函数交换主函数main中两个变量值,

并将交换的结果返回主函数,使用普通变量做函数

参数是无法实现。

■可以采用两个指针变量传递地址的方式完成,即设

置两个指针变量做函数的参数。

20

【例9.5】用函数交换main函数中两个变量的值。

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

■{intt;

■t=*px;

px=*py;

■*py=t;

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

■}________________

■voidmain()I程序的运行结果为:

■{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);

■运行:输入:5,8J

■输出:a=5,b=8

22

练习题(1)

■voidfun(int*x)

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

□*x=10;

□)

■main()

□{inta=25;

□fun(&a);

printf(“%d”,a);

口}

■运行结果2610

23

练习(2)

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

■main

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

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

■结果显示71

24

9.2.2函数返回指针

指针能作为函数的返回值。过去我们将整型等简单类型作为

返回值,现在我们将函数的返回值设置为指针,

一般定义形式:

数据类型*函数名(参数列表)

〃数据类型〃后面的*表示:函数的返回值是一个指向该数据类

型的指针。注意,此时定义的是函数,而不是指针。

25

■[例9.6]使用函数求两个变量的最大值。

voidmain()

■{inta,b,*max;

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

■printf(uEnterab:n);运行结果如下:

■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指向函数的指针

在定义一个函数之后,编译系统为每个函数确定一个

入口地址,当调用该函数的时候,系统会从这个

“入口地址”开始执行该函数。

函数名代表函数的入口地址.

存放函数的入口地址的指针就是一个指向函数的指针,

简称函数的指针。

函数的指针的定义格式:

类型标识符(*指针变量名)()

27

类型标识符为函数返回值的类型。特别值得注意的是,由于c

语言中,()的优先级比*高,因此,〃*指针变量名〃外部

必须用括号,否则指针变量名首先与后面的()结合,就是

前面介绍的〃返回指针的函数〃。试比较下面两个定义语句:

int(*pf)();/*定义一个指向函数的指针,该函数的返

回值为整型数据*/

int*f();/*定义一个返回值为指针的函数,该指针

指向一个整型数据*/

和变量的指针一样,函数的指针也必须赋初值,才能指向具

体的函数。由于函数名代表了该函数的入口地址,因此,

一个简单的方法是:直接用函数名为函数指针赋值,即:

函数指针名二函数玄

函数型指针经定义和初始化之后,在程序中可以引用该指针,

目的是调用被指针所指的函数。由此可见,使用函数型指

针,增加了函数调用的方式。

28

用指向函数的指针变量调用函数

■函数的指针:指函数的入口地址。

■函数名:代表函数的入口地址。

■指向函数的指针变量的定义:类型名(*变量名)()

■例:int(*p)();定义p为指向整型函数的指针变量。

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

■intmax(intx,inty)/*定义函数*/

■{intz;

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

■returnz;}

29

方法1:直接调用函数:方法2:用指针变量调用函

数:

main()

main()

{intabc;

{inta,b,c;99

int(*p)();

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

p=max;/*p指向函数*/

c=max(a9b);/*调用函数*/

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

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

c=(*p)(a,b);/*调用函数*/

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

30

【例9.7]用指针调用函数,输出三个数中最大值。

funmax(intx,inty)

{return(x>y)?x:y;运行结果如下:

)2,34,8J

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

max=34

{intrpf)O;

inta,b,c,d,e;

pf=funmax;/*指针变量指向funmax函数*/

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

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

e=(*pf)(c,d);/*等价于e=funmaxCd)*/

nn

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

31

当一个指针指向一个函数时,通过指针,就可以访问

它指向的函数。

需要注意的是,一个函数指针可以先后指向不同的函

数,将哪个函数的地址赋给它,它就指向哪个函数,

使用该指针,就可以调用函数.

另外,如果有函数指针(*pf)(),则pf+n、pf++、

pf一等运算是无意义的。

32

9.3指针与数组

我们可以定义指针来访问数组元素。一个变量在内

存中有相应的地址,而数组包含多个元素,每个

数组元素在内存中都占有一个内存地址,因此我

们也可以定义一个指针指向这个地址。

元素的指针:是指数组每个元素的地址

数组的指针:是指数组的首地址。

数组名:代表数组首地址。

可以利用指针引用数组元素。

33

9.3.1通过指针引用一维数组元素

■在数组中我们已经知道,可以通过数组的下标唯一确定某

个数组元素在数组中的顺序和存储地址。

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

■通过下标可直接访问数组a中的元素:

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

■由于每个数组元素相当于一个变量,因此指针变量可以指

向数组中的元素,也就是可以用“指针方式”访问数组中

的元素。

■指向数组元素的指针,与指向变量的指针相同。

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

■p=&a[0];/*等价于p=a;数组的首地址赋给p*/

■或初始化指针变量:int*p=&a[0];等价于:int*p=a;

34

地址o

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

P,a—

■则等价于

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

(等于指向下一个元素

■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

■因为:a+l,p+l是a[l]的地址

■则*(p+l)或*(a+l)等价于a[l]

■因为:a+i,p+i是a[i]的地址,

■贝lj*(p+i)或*(a+i)等价于a[i]

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

等价于:a[9]=10;

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

■总之,数组元素引用方法如下:

■(1)下标法:a[i]

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

36

【例9.8】数组元素的三种引用方法。

(1)下标法。

程序代码如下:

/*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)通过数组名计算数组元素地址,求元素的值。

程序代码如下:/*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;三个程序运行结果相同如下:

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为数组的首地址刃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));运行结果:

12

33

5440

注意,

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

*p的值。

而尸是先取指针P值作“”运算,再使指针P自

减1。

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

41

练习

■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

■输出结果1,9

•可见对一维数组而言,a指向a[0]、a+i指向a[i]

42

9.3.2指针基本运算

对于指针的运算有:指针的加减运算和两个指针的关

系运算。

1.指针的加、减运算

当指针P指向数组中的元素时,n为一个正整数,表达

式:p±n表示:指针p所指向当前元素之后或之

前的第n个元素。

最常见的指针加减运算p++、P--的含义是:

指针加1,指向数组中的后一个元素;

指针减1,指向数组中的前一个元素。指针与整数进

行加减运算后,它们的相对关系如图9.7所示。

43

数组指针

P-R

p-2

p-1

p指针当前位置

p+1

p+2

p+n

图9.7指针的加减运算

44

■注意:p++操作,改变了指针变量的值。使用时要注意指针

变量所指的当前位置。

■而a++是不允许的。因为a是数组名,固定代表数组首地址。

■例:注意下题中出现的问题

□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

■上例中,由于第一个循环中p++使P指向下一个元素,

循环结束时,p指向*(a+10),所以第二个循环,用

P输出的是a数组以外的内存中的数据。

■因此在第二个循环之前,应重新设置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所指的具体对象不同,所以对指针与整

数进行加减运算时,C语言会根据所指的不同数据

类型计算出不同的存储单元的大小,以保证正确操

作实际的运算对象。

■数据类型的存储单元的大小等于一个该数据类型的

变量所占用的内存单元字节数。

■对于char型,存储单元的大小为1字节;

■对于int型,存储单元的大小为2字节;

■对于long型,存储单元的大小为4字节;

■对于double型,存储单元的大小为8字节。

■p+1运算,其中的1意味着是该类型变量的一个存

储单元。

47

【例9.10】编程将串strl复制到串str2中。

main()

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

printf("Enterstring1:");

gets(strl);

pl=strl;

p2=str2;

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

p2所指的元素中*/

{pl++;p2++;}/*指针pl和p2分别后移1个元素*/

printf("String2:〃j

运行结果如下:

puts(str2);I

Enterstring1:china

String2:china

48

程序中的关键是while语句,“(*p2=*pl)!二‘\0’”

的含义是:

先将指针P1所指元素的内容送到指针P2所指元素的元

素中,然后再判断所赋值的字符是否是串结束标记

'\0',如果不是串结束标记,则执行循环继续进行字

符复制;如果是串结束标记,则退出循环,完成串复

制。

对于上面程序中的while循环,可以进行如下改进:

方法一:

while(*p2=*pl)

{pl++;p2++;}

方法二:

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

/*循环体为空语句*/

49

【例9.n】编写程序求字符串的长度。

分析:字符串的存储结束标志为、0、可以设置一个指针

变量P指向字符串首字符,判断p当前所指的字符如果

为非,网,则p++,指向下一个字符,再判断,直到p指

向字符串尾,程序结束。字符串的长度应为p的当前位

置与字符串首地址的差。

main()

运行结果如下:

{charstr[50],wp=str;

Enterstring:china」

nn;

printf(Enterstring:)Stringlength=5

gets(str);

while(*p)

p++;

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

}

50

2.两个指针的关系运算

只有当两个指针指向同类型的数据元素时,才能进行关系运

算。即:

■P<q当P所指的元素在q所指的元素之前时,表达式的值为

1;反之为0。

■p>q当P所指的元素在q所指的元素之后时,表达式的值为

1;反之为0。

■p==q当P和q指向同一元素时,表达式的值为1;反之为0。

■p!二q当P和q不指向同一元素时,表达式的值为1;反之为

0o

51

■任何指针p与NULL进行“p二二NULL”或“p!二NULL”

运算均有意义,

■“p二二NULL”的含义是当指针p为空时关系表达式

为真

■〃p!二NULL〃的含义是当p不为空时表达式为真。

■指向两个不同数组的指针进行比较,没有任何实际

的意义。

52

【例9.12】编写程序将一个字符串逆置。

#include<stdio.h>

main()运行结果如下:

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

printf(nEnterstring:");anihc

gets(str);

p=s=str;/*指针p和s指向str数组*/

while(*p)

p++;/*找到串结束标记)(T号

p--;/*指针回退一个字符,使p指向最后一个字符刃

while(s<p)/*当串前面的指针串后面的指针p时,进行循环*/

{C=*s;/*交换两个指针所指向的字符*/

*s++=*p;/*串前面的指针S向后(+1)移动刃

*p-=C;/*串后面的指针P向前(-1)移动*/

}

puts(str);

53

9.3.3通过指针引用二维数组元素

■二维数组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]

■二维数组a[3][4]可以理解为:

■a数组中,包含3个元素:a[O]a[l]a[2],每

个元素都是一个一维数组的名字,代表该

行元素的首地址。

54

■1.多维数组的地址

■若定义以下数组:

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

■可理解为:a数组包含3个元素:a[0]>a[l]>a[2]

■这三个元素本身各代表一个一维数组。

■a:代表数组首地址,指向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.指向下一个元素.

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

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

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

*(a[O]+l):是时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)

■因为用列指针引用元素的形式:*(a[i]+j)

■所以表示元素。

■总之:

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

■列指针a[0],加1,指向下1个元素。

■要找到某行中的某个元素,要用列指针a[i]运算

■要找到某行的首地址,要用行指针a运算

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

57

2.指向二维数组的指针变量p=a[OL1

p++―A2

■(1)存放列地址的指针变量3

■这种指针变量,可以寻找到每个元素。4

■定义形式和指向普通变量的指针变量一样。一

■【例9.13】多维数组的输出。工

■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);}程序的运行结果为:

1234

5678

9101112

58

■(2)指向m个元素组成的一维数组的指针变量

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

■则p+1移过m个元素。

■可见:这里p应接受行地址。

59

【例9.14】给定某年某月某日,将其转换成这一年的第

几天并输出。

#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));/*实参

为二维数组名*/一

60

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

■/*形参为指向13个元素的一维数组的指针变量*/

■{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);

■}

■运行结果如下:

■200023/*输入数据年月日*/

■34

61

9.4字符串与指针

■9.4.1字符数组与字符指针

■字符串的访问方法:用字符串的首地址。

■字符数组名,代表字符串的首地址。

■L字符数组存放字符串

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

■此时,string是字符数组,存放了一个字符串。

■例main()

■{charstring[]="IamChinese.59;

■printff6%s55,string);

运行时,输出:

IamChinese.

62

2用字符指针变量指向一个字符串。

■字符指针也可以指向一个字符串。我们可以用字符串常量

对字符指针进行初始化。例如,有语回

■char*str="China.";对字符指针进行初始化。

■此时,字符指针变量存放的是字符串的首地址,即指向字

符串的首地址。

■例main()

str-

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

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

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

SL

■}

■运行结果显示:\o

■China,ina.

■这里char*str="China.";等价于以下两行:

char*str;

str=6'China.”;

63

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

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

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

向新的字符串*/

str=strl;/*改变指针str的指向*/

strcpy(string,“ThisisaNEWstring.")/*

改变字符数组的的内容*/

strcat(string,str)/*进行串连接操作*/

strcpy(str,string)/*指针变量没有初始化时,

不要向str进行串复制,可能会破坏其它数据*/

64

9.4.2常见的字符串操作

■由于使用指针编写的字符串处理程序比使用数组方式处理

字符串的程序更简洁、更方便,所以在c语言中中,大量使

用指针对字符串进行各种处理。

■在处理字符串的函数中,一般都使用字符指针作为形参。

■由于数组名代表着数组的首地址,因此在函数之间可以采

用指针传递整个数组,这样在被调用函数的内部,就可以

用指针方式访问数组中的元素。

■下面我们来看几个使用指针处理字符串的程序。

65

【例9.15]用字符指针指向一个字符串。

程序代码如下:

/*c09_15.c*/

#includenstdio.hn

main(){

char*str=nhelloworldn;

printf(n%s\nn,str);

}

运行结果如下:

helloworld

66

程序分析与注意事项:

这里的str是指向字符串“helloworld”的指针,即

字符串的首地址赋给了字符指针,使一个字符指

针指向了一个字符串。

C语言对字符串常量是按字符数组处理的,在内存

开辟了一个字符数组用来存放字符串常量。

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

str被定义为一个指向字符型数据的指针变量,在

指向字符串时,并不是把字符串的所有的字符存

放到str中,也不是把字符串赋给*str,只是把

字符串的首地址赋给字符指针。

67

下面的情况是不允许的:

char*str;

scanf("%s",str);

因为指针没有明确的指向,其值是任意的,也许所

指向的区域不是用户可以访问的内存区域,或者

是根本不存在的地方。

输出一个字符串时,系统先输出字符指针所指向的

一个字符数据,然后自动使str加1,指向下一个

字符,直到遇到字符串结束标志’\0’为止。

68

虽然字符数组和字符指针都可以用来表达字符串,但是它们

还是有不同之处,例如:

charstring口二“helloworld”;

char*str="helloworld”;

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

string是一个字符数组,名字本身是一个地址常量;而str

是指向字符串首地址的指针变量。

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

string+=2则不可以.

■若定义了一个指针变量,并使它指向一个字符串,就可以

用下标形式引用指针变量所指向的字符串中的字符。

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

69

【例9.16】用指针作为函数的形式参数,编写字符串复制函

■#include<stdio.h>运行结果如下:

■main()Enterstring:china

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

b=china

■printf(nEnterstring:'');

■scanf(n%s!\a);

■strcopy(a,b);/*调用函数的实参为数组名,即数组的首址*/

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

■)

■voidstrcopy(char*strl,char*str2)/*函数的形参为指

针变量*/

■{while(*str2++=*strl++);/*通过指针操作实参数组*/

}

70

【例9.17]编写函数,求字符串的长度。

intstrlen(char*str)

{char*p=str;

while(*p)

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

return(p-str);_______

运行结果如下:

main()Enterstring:English

{chara[50];Stringlength=7

printf(MEnterstring:11);

scanf(n%sn,a);

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

71

【例9.18]编写函数,实现两个串的连接。

#include<stdio.h>

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

{char*p=strl;

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

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

return(strl);}运行结果如下:

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]用下标的形式引用字符串中的元素。

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

nn

#includestdio.h运行结果如下:

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]输入两个有序的字符串(小f大),编写一

个合并两个字符串的函数,使合并后的字符串,

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

#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中的字符较小,则将它复

制至l]str中*/

■else*r++=*q++;/*若str2中的字符较小,则将它复制

至!Jstr中*/

74

■s=(*p)?p:q;/*判断哪个字符串还没有处理完毕*/

■while(*s)/*继续处理(复制)未处理完毕的字符串*/

■*r++=*s++;

■*r=,\0,;/*向str中存入串结束标记*/

■printf(^Result:11);

■puts(str);}运行结果如下:

Enterstringl:112ac

Enterstring2:Obgh

Result:0112abcgh

75

9.5指针数组、数组指针及应用

951指针数组与指向数组的指针变量

■1指针数组:

■数组中的每个元素,都是指针变量。

■一维指针数组的定义形式:inttpa[5]inta[5]

■类型名*数组名[常量表达式]pa[0]&a[(ga[0]

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

表示定义一个由5个指针变量构成的pa[2]&a[2;a[2]

指针数组pa,数组中的每个数组元素pa[3]&a[31a[3]

都是指针,都可指向一个整数.pa[4]&a[45a[4]

设有:inta[5],*pa[5];

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

pa[i]=&a[i];

76

2指向m个元素组成的一维数组的指针变量

定义的形式为:

类型(*数组名)[m];

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

表示定义一个指向数组的指针变量pb,pb指向

的数组是5个元素组成的一维整型数组.

■则pb+1将移过5个元素。

■可见:这里pb可以接受二维数组的行地址。

例如:char*line[5];

表示line是一个数组,每个元素是一个指向字符型数据的一

个指针。若设指向的字符型数据(字符串)分别是“ONE”、

“TWO”、…、"FIVE”,则数组line的结构如图9.H所示.

指针数组常适用于指向若干字符串,这样使字符串处理更加

灵活方便。

line[0]

line⑵

line[3]

line[4]

图9.n指向字符串常量的指针

数组

78

【例9.21]输入一个字符串,判断该字符串是否是英文的星

期几。使用指针数组实现。

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

#include<stdio.h>

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

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

/*定义指针数组。数组中的每个元素指向一个字符串*/

main()

{intm;

charstring[20];

printf(uEnterastring:'');

scanf(n%sn,string);

m=lookup(string);

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

lookup(charch[])/*传递字符串(字符数组)*/

{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);/*若找到则返回对应的序号*/

)

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

运行结果如下:

Enterastring:wedJ

1=3

80

■程序中没有使用二维的字符数组,而是采用指针数

组week_day。可以看到指针数组比二维字符数组有

明显的伍点,一是指针数组中每个元素所指的字符

串不必限制在相同的字符长度,二是访问指针数组

中的一个元素是用指针间接进行的,效率比下标方

式要高。

81

【例9.22】输入星期几,输出对应星期的英文名称。用指

针数组实现。

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

#include<stdio.h>

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

nWednesday0,nt

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论