收藏 分享(赏)

《C语言程序设计与数据结构》第8章 指针.ppt

上传人:ysd1539 文档编号:7070051 上传时间:2019-05-05 格式:PPT 页数:97 大小:2.12MB
下载 相关 举报
《C语言程序设计与数据结构》第8章 指针.ppt_第1页
第1页 / 共97页
《C语言程序设计与数据结构》第8章 指针.ppt_第2页
第2页 / 共97页
《C语言程序设计与数据结构》第8章 指针.ppt_第3页
第3页 / 共97页
《C语言程序设计与数据结构》第8章 指针.ppt_第4页
第4页 / 共97页
《C语言程序设计与数据结构》第8章 指针.ppt_第5页
第5页 / 共97页
点击查看更多>>
资源描述

1、C语言程序设计与数据结构,第8章 指 针,C语言程序设计与数据结构,教学提示: 指针是C语言的精华部分,通过利用指针可以描述复杂的数据结构,很方便地使用数组和字符串,并象汇编语言一样处理内存地址,使程序精练、高效。另一方面,不正确的指针使用是危险的,轻则影响到结果的正确性,重则会导致系统瘫痪。对初学者来说除了要正确理解有关概念外,还必须要多编程多上机调试。 教学要求:本章要求掌握指针变量的定义,理解地址就是指针的的概念,一维数组的指针与指向一维数组的指针的区别,指针与字符串、函数的关系,指针变量作函数参数时参数的传递方式,返回指针值的函数定义形式以及指向函数的指针变量定义。,C语言程序设计与数

2、据结构,8.1 地址与指针概述,如果我们在前面的编程中定义或说明了变量,编译系统就为已定义的变量分配相应的内存单元(一般把存储器中的一个字节称为一个内存单元),为了能正确地访问这些内存单元,可以为每个内存单元编上号,根据一个内存单元的编号就可准确地找到该内存单元。内存单元的编号也叫做地址,通常也把这个地址称为指针。也就是说,每个变量在内存中会有固定的位置,即具体的地址。变量的数据类型不同,它所占的内存单元的数目也不相同。,C语言程序设计与数据结构,若我们在程序中已有如下定义:int a=1, b=2; float x=3.4, y = 4.5 ;double m=3.124;char ch1=

3、a, ch2=b; 那么编译系统可以按下面方法为变量分配内存。变量a ,b是整型变量,在内存中各占2个字节;x , y是实型,各占4个字节;m是双精度实型,占8个字节;ch1 , ch2是字符型,各占1个字节。由于计算机内存是按字节编址的,设变量的存放从内存2000单元开始存放,则编译系统对上述变量在内存中的一种可能存放情况如图8.1所示。变量a 在内存的地址是2000,占据两个字节2000和2001后,变量b的内存地址就为2002。以此类推,变量m的内存地址为2012等。另外内存地址都是整形数,不会出现小数。,C语言程序设计与数据结构,图8.1 不同数据类型变量在内存中占用的空间,C语言程序

4、设计与数据结构,指针变量,存放变量地址的变量称为指针变量。如果将变量a的地址保存在内存的特定区域,用变量pa来存放这些地址,这样的变量pa就是指针变量。因此,一个指针变量(如pa)的值就是某个变量(如a)的地址(也称为某变量的指针),也称为pa指向变量a,或者说pa是指向变量a的指针变量。既然pa是变量,那么指针变量pa不但可以存放变量a的地址,也可以存放变量b的地址。有些书上把指针变量简称为指针。为了避免混淆,我们约定:“指针”是指地址,是常量,“指针变量”是指取值为地址的变量。定义指针的目的是为了通过指针去访问内存单元。,C语言程序设计与数据结构,定义指针变量,对指针变量的类型说明包括三个

5、内容: 指针类型说明,即定义变量为一个指针变量; 指针变量名; 变量值(指针)所指向的变量的数据类型。其一般定义形式为: 类型说明符 *变量名;其中,*表示其后面的变量是一个指针变量,变量名即为定义的指针变量名,类型说明符表示指针变量所指向的变量的数据类型。,C语言程序设计与数据结构,定义指针变量,例如:int *p1; 其中的*表示p1是一个指针变量,变量名为p1,它的值只能是某个整型变量的地址,或者说p1指向一个整型变量。至于p1究竟指向哪一个整型变量,应由向p1赋予的地址来决定。但一个指针变量只能指向同一种类型的变量,如下面的p3 只能指向浮点型变量(如前面的x或y)而不能指向字符型变量

6、。再如:double *p2; /*p2是指向double型变量的指针变量*/float *p3; /*p3是指向浮点型变量的指针变量*/char *p4; /*p4是指向字符型变量的指针变量*/,C语言程序设计与数据结构,指针变量的赋值与引用,指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址,决不能赋予任何其它数据,否则将引起错误。设已定义下面两个变量:int a;int *p,*q; /* 定义指向整型变量的指针变量p和q */如果想把整型变量a的地址赋予指针变量p,首先要知道a 的地

7、址。C语言提供了一些运算符来实现此功能。 1、取地址运算符&2、指针运算符*(或称“间接访问”运算符、取内容运算符),C语言程序设计与数据结构,取地址运算符&,在语言中,变量的地址是由编译系统分配的,用户无需知道变量的具体地址。语言中提供了专门的取地址运算符&来表示变量的地址。取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量的地址。其一般形式为:&变量名;如&a表示变量a的地址。在前面章节的scanf函数中,我们已经使用了&运算符。取地址运算符&只能作用于对变量和数组元素,而不能作用于表达式、常量。,C语言程序设计与数据结构,要把整型变量a的地址赋予指针变量p, 可以有以下两种方

8、式: (1) 指针变量初始化的方法int a;int *p=,C语言程序设计与数据结构,C语言程序设计与数据结构,【例8.1】取地址运算符 运行结果如下: 0012FF7C,0012FF7C, 12ff7c, 12ff7c, 1245052 注意:具体的地址值可能与上述结果12FF7C不同,这跟机 器结构、操作系统、变量的类型及存储器的用法等有关。,C语言程序设计与数据结构,我们知道,一般情况下整型变量在内存中占2个字节;实型变量占4个字节;双精度实型变量占8个字节;字符型变量占8个字节。既然指针变量是一种专门用来存放他人地址的变量,那指针变量这种特殊的变量又在内存中占几个字节呢?【例8.2】

9、各种变量占用内存数比较。main( ) int a, *p;float x=3.0 ;double m=3.124;char ch1=a, ch2=b; printf(“%d,%d,%d,%d,%d,%dn“,sizeof(int),sizeof(int *),sizeof(float),sizeof(double),sizeof(char),sizeof(p);printf(“%p,%p,%p,%p,%p,%p n“,C语言程序设计与数据结构,运行结果如下:4,4,4,8,1,40012FF7C, 0012FF78, 0012FF74, 0012FF6C, 0012FF68, 0012FF6

10、4再看看图8.1,是不是这样呢?,图8.1 不同数据类型变量在内存中占用的空间,C语言程序设计与数据结构,指针运算符*,指针运算符*(或称“间接访问”运算符、取内容运算符),是单目运算符,其结合性为自右至左,用来表示指针变量所指向的变量。在*运算符之后跟的变量必须是指针变量。,C语言程序设计与数据结构,【例8.3】取地址运算符 运行结果如下:0012FF7C,0012FF7Ca=200,x=100,*p=200,*&a=200a=200,x=200,*p=200,*&a=200a=300,x=200,*p=300,*&a=300,C语言程序设计与数据结构,需要注意的是指针运算符*和指针变量说明

11、中的指针说明符*不是一回事。在代码第3行中,int *p中的*是类型说明符,表示其后的变量p是指针类型。而代码第7行x=*p中的“*”则是一个运算符用以表示指针变量p所指的变量a。假设变量a的地址为FF7C, 例8.3代码第7行的赋值可形象理解为图8.3所示的联系。,C语言程序设计与数据结构,【例8.4】 从键盘输入两个整数,按由大到小的顺序输出。 main( ) int *p1,*p2,a,b,t; /*定义指针变量与整型变量*/ printf(“Input a,b:“);scanf(“%d,%d“, 在程序中,当执行赋值操作p1=&a和p2=&b后,指针分别指向了变量a与b,这时引用指针*

12、p1与*p2,就代表了变量a与b。运行情况如下: Input a,b:3 , 4 a=4, b=3max=4,min=3,C语言程序设计与数据结构,在程序运行过程中,指针与所指的变量之间的关系如图8.4所示,当指针被赋值后,其在内存的存放如(a),当数据比较后进行交换,这时,指针变量与所指向的变量的关系如(b)所示,在程序的运行过程中,指针变量与所指向的变量其指向始终没有变化。,C语言程序设计与数据结构,另外,既然指针变量和一般变量一样都是变量,就具有变量的性质存放在它们之中的值是可以改变的,也就是说可以改变它们的指向。下面对【例8.4】做一下修改。 【例8.5】 从键盘输入两个整数,按由大到

13、小的顺序输出a和b。 main ( ) int *p1,*p2,a,b,*t;printf(“Input a,b: “);scanf(“%d,%d“ , ,C语言程序设计与数据结构,运行情况如下: Input a,b: 3 , 4 a=3, b=4 max=4,min=3 程序在运行过程中,实际存放在内存中的数据没有移动,而是将指向该变量的指针交换了指向,如图8.5所示。当指针交换指向后,p1和p2由原来指向的变量a和b改变为指向变量b和a,这样一来,*p1就表示变量b,而*p2就表示变量a。,C语言程序设计与数据结构,指针变量可出现在表达式中,设有: int x=3, y, *p= 表示把*

14、p即变量x的内容加3后赋给x自己,赋值后x值为6,C语言程序设计与数据结构,【例8.6】通过变量的指针实现求两个数的和与积。 #include main() int a=10,b=20,s,t,*pa,*pb; /* 说明pa,pb为整型指针变量*/pa= 运行情况如下: a=10, b=20, a+b=30, a*b=200 s=30, t=200,C语言程序设计与数据结构,8.2.3 指针变量作为函数参数,函数的参数不仅可以是整型、实型、字符型等数据,还可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中。,C语言程序设计与数据结构,【例8.7】将输入的两个整数按大小顺序输出。要求

15、用函数处理,而且用指针类型的数据作函数参数。 #include swap(int *p1,int *p2) int temp;temp=*p1;*p1=*p2;*p2=temp; ,main() int a,b; int *pointer_1,*pointer_2; printf(“Input a, b: ”);scanf(“%d,%d“,运行情况如下: Input a,b: 3 , 4 a=4, b=3,C语言程序设计与数据结构,程序分析,swap是用户定义的函数,它的作用是交换两个变量(a和b)的值。swap函数的形参p1、p2是指针变量。程序运行时,先执行main函数,输入a和b的值。然

16、后将a和b的地址分别赋给指针变量pointer_1和pointer_2,使pointer_1指向a,pointer_2指向b。接着执行if语句,由于ab,因此执行swap函数。注意实参pointer_1和pointer_2是指针变量,在函数调用时,将实参变量的值传递给形参变量。采取的依然是“值传递”方式。因此虚实结合后形参p1的值为&a,p2的值为&b。这时p1和pointer_1指向变量a,p2和pointer_2指向变量b。接着执行swap函数的函数体使*p1和*p2的值互换,也就是使a和b的值互换。函数调用结束后,p1和p2不复存在(已释放)。最后在main函数中输出的a和b的值是已经过

17、交换的值。,C语言程序设计与数据结构,思 考,为什么不能用下面的函数swap2呢? swap2 (int *p1,int *p2) int *temp;*temp=*p1; /* 此语句有问题,temp指针没有指向明确的地址 */*p1=*p2;*p2=*temp; ,C语言程序设计与数据结构,8.3 一维数组与指针,每个数组包含一组具有同一类型的变量(即数组元素),这些变量在内存中占有连续的存储单元,它们都有自己相应的地址。数组元素的指针就是数组元素的地址。而所谓数组的指针则是指数组的起始地址。指针变量用来存放变量的地址,它可以指向变量,当然也可存放数组的首地址或数组元素的地址。也就是说,指

18、针变量可以指向数组或数组元素。,C语言程序设计与数据结构,指向数组元素的指针,一个数组是由连续的一块内存单元组成的。C语言规定,数组名就是这块连续内存单元的首地址。而每个数组元素按其类型不同占有几个连续的内存单元,每个数组元素的首地址就是该元素所占有的几个内存单元的起始地址。设有: int a10; /*定义a为包含10个整型数据的数组*/int *p; /*定义p为指向整型变量的指针*/既然a的每个元素为int型,指针变量p又为指向int型的指针变量。则可以对指针变量p做如下赋值:p=后,p,a,&a0均指向同一单元,它们都是数组a的首地址,也就是0号元素a0的首地址。,C语言程序设计与数据

19、结构,C语言规定:如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。这是因为p是指针变量,它可以指向a0,也可以改变指向,比如再指向a3,如果有p=&a3,则p=p+1操作后,p改为指向a4。要注意的是数组a的地址和&a0都是常量,不能改变。对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指针变量,则pa+n,pa-n,pa+,+pa,pa-,-pa 运算都是合法的。指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。应该注意,数组指针变量向前或向后移动一个位置和地址加1或减1 在概念上是不同的。因为数组可

20、以有不同的类型,各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。,C语言程序设计与数据结构,例如: int a5, *pa; pa=a; /*pa指向数组a,也是指向a0*/ pa=pa+2; /*pa指向a2,即pa的值为&pa2*/,C语言程序设计与数据结构,8.3.2 通过指针引用数组元素,引用单个数组元素 引用连续的数组元素,C语言程序设计与数据结构,引用单个数组元素,数组的每个元素与单个同类型变量的用法一样。 【例8.8】 从键盘输入两个整数,按由大到小的顺序输出。 #include ma

21、in( ) int *p1,*p2, a2, t; /*定义指针变量与整型数组*/ printf(“Input a0 ,a1: ”);scanf(“%d,%d“, 运行情况如下: Input a0,a1: 3 , 4 a0=4, a1=3max=4, min=3,C语言程序设计与数据结构,【例8.9】将输入的两个整数按大小顺序输出。要求用函数处理,而且用指针类型的数据作函数参数。 #include swap(int *p1,int *p2) int temp;temp=*p1;*p1=*p2;*p2=temp; main() int a2, *p1,*p2;printf(“Input a0 ,

22、a1: ”);scanf(“%d,%d“,运行情况如下: Input a0,a1: 3 , 4 a0=4, a1=3,C语言程序设计与数据结构,引用连续的数组元素,假设a数组有10个元素,如果已做赋值操作p= 则有: (1) p+n与a+n都表示数组元素an的地址,即&an。对整个a数组来说,共有10个元素,n 的取值为09,则各数组元素的地址可以表示为ptr+0ptr+9或a+0a+9,与&a0&a 9完全一致。 (2)*(p+n)或*(a+n)就是p+n或a+n所指向的数组元素,即an。例如*(p+5)或*(a+5)就是a5。 (3)指向数组的指针变量也可以带下标,如pi与*(p+n)或a

23、n等价。 但要注意,如果做赋值操作p=&a2,则有:(1) p+n与a+n+2都表示数组元素an+2的地址,即&an+2。n 的取值为07,则数组元素a2a9的地址可以表示为ptr+0ptr+7或a+2a+9,与&a2&a9完全一致。 (2)*(p+n)或*(a+n+2)就是p+n或a+n+2所指向的数组元素,即an+2。例如*(p+5)或*(a+5+2)就是a7。,C语言程序设计与数据结构,【例8.10】输出数组中的全部元素。(利用数组下标) main() int a5,i;for(i=0;i5;i+)ai=i; /*此处可以改为scanf(“%d”, ,C语言程序设计与数据结构,【例8.1

24、1】输出数组中的全部元素。(通过数组名计算各元素的地址,找出元素的值) main() int a5,i;for(i=0;i5;i+)*(a+i)=i; /*此处可以改为scanf(“%d”, a+i); 来随机输入5个整数*/for(i=0;i5;i+)printf(“a%d=%dn“,i,*(a+i); ,C语言程序设计与数据结构,【例8.12】输出数组中的全部元素。(用指针变量,注意p一直指向a的首地址) main() int a5,i,*p;p=a;for(i=0;i5;i+)*(p+i)=i; /*此处可以改为scanf(“%d”, p+i); 来随机输入5 个整数*/for(i=0;

25、i5;i+)printf(“a%d=%dn“,i,*(p+i); ,C语言程序设计与数据结构,【例8.13】输出数组中的全部元素。(用指针变量,注意p不断改变指向的数组元素) main() int a5,i,*p=a;for(i=0;i5; i+)*p=i; /*此处可以改为scanf(“%d”, p); 来随机输入5个整数*/ p+; /* 指针变量p可以实现本身的值的改变,此处p+是合法的; 而a+是错误的,因为a是数组名,它是数组的首地址,是常量 */p=a; /*指针变量p通过上面的多次p+,已不再指向a数组的首地址。需要重新赋值,使p再次指向a数组的首地址*/for(i=0;i5;

26、i+)printf(“a%d=%dn“,i,*p);p+; ,C语言程序设计与数据结构,【例8.14】本例能否达到和例8.11同样的效果?为什么?如不能则找出其中的错误。 main() int *p,i,a5;p=a;p=a;for(i=0;i5;i+)*p+=i;for(i=0;i5;i+)printf(“a%d=%dn“,i,*p+); 从本例可以看出,虽然定义数组时指定它包含10个元素,但指针变量p在第二个for循环语句时已经指到数组以后的内存单元,虽然系统编译并不认为非法,但逻辑上已错。应在第一个for循环结束后加上一句p=a; 。,C语言程序设计与数据结构,其他说明,(1)*p+,由

27、于+和*同优先级,结合方向自右而左,等价于*(p+)。 y=+*px; 含义是把px的内容加上1之后赋给y,+*px相当于+(*px)。 y=*px+; 相当于y=*px; 和 px+;两个语句。 (2)*(p+)与*(+p)作用不同。若p的初值为a,则*(p+)等价a0,*(+p)等价a1。 (3)(*p)+表示p所指向的元素值加1。 (4)如果p当前指向a数组中的第i个元素,则: *(p-)相当于ai-; *(+p)相当于a+i; *(-p)相当于a-i。,C语言程序设计与数据结构,(5)两个指针变量进行关系运算 指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系。例如:

28、 pf1= =pf2表示pf1和pf2指向同一数组元素 pf1pf2表示pf1处于高地址位置 pf1pf2表示pf2处于低地址位置 (6)指针变量还可以与0比较。设p为指针变量,则p=0表明p是空指针,它不指向任何变量;p!=0表示p不是空指针。空指针是由对指针变量赋予0值而得到的。如:int *p=NULL;NULL是个宏,一般在系统头文件stdio.h中会有这样的宏定义如下: #define NULL 0对指针变量赋0值和不赋值是不同的。指针变量未赋值时,可以是任意值,是不能使用的。否则将造成意外错误。而指针变量赋0值后,则可以使用,只是它不指向具体的变量而已。,C语言程序设计与数据结构,

29、8.3.3 一维数组名作函数参数,数组名可以作函数的实参和形参。数组名就是数组的首地址,实参向形参传送数组名实际上就是传送数组的地址,形参得到该地址后也指向同一数组。同样,指针变量的值也是地址,数组指针变量的值即为数组的首地址,当然也可作为函数的参数使用。 如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有以下种,例题8.15例题8.18分别对其进行了演示: (1) 形参和实参都是数组名 (2) 实参用数组,形参用指针变量。 (3) 实参、型参都用指针变量。(4)实参为指针变量,型参为数组名。,C语言程序设计与数据结构,【例8.15】将数组a中的n个整数按相反顺序存放。

30、(形参和实参都是数组名) 算法为:将a0与an-1对换,再a1与an-2 对换,直到将a(n-1/2)与an-int(n-1)/2)对换。今用循环处理此问题,设两个“位置指示变量”i和j,i的初值为0,j的初值为n-1。将ai与aj交换,然后使i的值加1,j的值减1,再将ai与aj交换,直到i=(n-1)/2为止。 程序如下: void inv(int x,int n) /*形参x是数组名*/ 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

31、,11,0,6,7,5,4,2;printf(“The original array:n“);for(i=0;i10;i+)printf(“%d,“,ai);printf(“n“);inv(a,10); /*实参a是数组名*/printf(“The array has benn inverted:n“);for(i=0;i10;i+)printf(“%d,“,ai);printf(“n“); ,C语言程序设计与数据结构,【例8.16】对例8.15作一些改动。实参用数组,形参用指针变量。 程序如下: void inv(int *x,int n) /* 形参x为指针变量 */ int *p,tem

32、p,*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,a10=3,7,9,11,0,6,7,5,4,2;printf(“The original array:n“);for(i=0;i10;i+)printf(“%d,“,ai);printf(“n“);inv(a,10); /*实参a是数组名*/printf(“The array has benn inverted:n“);for(i=0;i10;i+)printf(“%d,“,ai);printf(“n“);

33、 ,C语言程序设计与数据结构,【例8.17】 输入5个分数,求出平均分。要求实参、型参都用指针变量。 float aver(float *pa); main() float sco5,av,*sp;int i;sp=sco;printf(“ninput 5 scores:n“);for(i=0;i5;i+) scanf(“%f“, ,C语言程序设计与数据结构,【例8.18】 输入5个分数,求出平均分。要求实参用指针变量,型参是数组。 float aver(float pa); main() float sco5,av,*sp;int i;sp=sco;printf(“ninput 5 scor

34、es:n“);for(i=0;i5;i+) scanf(“%f“, ,C语言程序设计与数据结构,8.4 二维数组与指针,8.4.1 引用单个数组元素 8.4.2 指向二维数组的指针变量 8.4.3 指向多维数组的指针变量,C语言程序设计与数据结构,8.4.1 引用单个数组元素int a23; /*定义a为两行三列的二维数组*/ int *p; /*定义p为指向整型变量的指针*/既然a的每个元素为int型,指针变量p又为指向int型的指针变量。则可以对指针变量p做赋值:p= 就是把a02元素的地址赋给指针变量p。,C语言程序设计与数据结构,【例8.19】 把二维数组a23第一行和第二行的值互换。

35、 main( ) int *p1,*p2, t, j, k, a23=1,2,3,4,5,6; for( j=0; j3; j+)p1 = 运行结果: 4 5 61 2 3,C语言程序设计与数据结构,指向二维数组的指针变量,定义一个二维数组:int a34; 表示二维数组有三行四列共12个元素,在内存中按行存放,存放形式为图8.6。其中a是二维数组的首地址,可把a看作由三个元素a0、a1、a2组成的一维数组。所以:a+0或a 等价于 &a0a+1 等价于 &a1a+2 等价于 &a2*a或*(a+0) 等价于 a0*(a+1) 等价于 a1*(a+2) 等价于 a2也就是 *(a+i) 等价于

36、ai, a+i等价于&ai。而每个元素ai (0=i=2)相当于由四个元素ai0、ai1、ai2、ai3组成的一维数组。ai+j 等价于 &aij (0=j=3)*(ai+j) 等价于 aij所以 *(a+i)+j等价于&aij,*(*(a+i)+j) 等价于aij。,C语言程序设计与数据结构,图8.6 二维数组在内存中的存放形式,C语言程序设计与数据结构,分析,我们定义的二维数组a其元素类型为整型,每个元素在内存占两个字节,若假定二维数组a从1000单元开始存放,则按照按行存放的原则,数组元素在内存的存放地址为10001022。若用地址法来表示数组各元素的地址,对元素a12来说,&a12是其

37、地址,a1+2也是其地址。分析a1+1与a1+2的地址关系,它们地址的差并非整数1,而是一个数组元素所占的字节数2,原因是每个数组元素占两个字节。对0行首地址与1行首地址a与a+1来说,地址的差同样也并非整数1,而是一行共四个元素所占的字节数8。前面介绍过,语言允许把一个二维数组分解为多个一维数组来处理。因此数组a34可分解为三个一维数组,即a0,a1,a2。每一个一维数组又含有四个元素。例如a0数组,含有a00,a01,a02,a03四个元素。,C语言程序设计与数据结构,从二维数组的角度来看,a是二维数组名,a代表整个二维数组的首地址,也是二维数组0行的首地址,等于1000。a+1代表第一行

38、的首地址,等于1008。a0是第一个一维数组的数组名和首地址,因此也为1000。*(a+0)或*a是与a0等效的, 它表示一维数组a00 号元素的首地址,也为1000。&a00是二维数组a的0行0列元素的首地址,同样是1000。因此,a,a0,*(a+0),*a,&a00是相等的。同理,a+1是二维数组1行的首地址,等于1008。a1是第二个一维数组的数组名和首地址,因此也为1008。&a10是二维数组a的1行0列元素地址,也是1008。因此a+1,a1,*(a+1),&a10是等同的。由此可得出:a+i,ai,*(a+i),&ai0是等同的。此外,&ai和ai也是等同的。因为在二维数组中不能

39、把&ai理解为元素ai的地址,不存在元素ai。语言规定,它只是一种地址计算方法,表示数组a第i行首地址。由此,我们得出:ai,&ai,*(a+i)和a+i也都是等同的。,C语言程序设计与数据结构,另外,a0也可以看成是a0+0,是一维数组a0的0号元素的首地址,而a0+1则是a0的1号元素首地址,由此可得出ai+j则是一维数组ai的j号元素首地址,它等于&aij。由ai=*(a+i)得ai+j=*(a+i)+j。由于*(a+i)+j是二维数组a的i行j列元素的首地址,所以,该元素的值等于*(*(a+i)+j)。 由于数组元素在内存的连续存放,如给指向整型变量的指针赋以数组的首地址,则该指针指向

40、二维数组。 如: int *ptr, a34;若赋值:ptr=a0;则用ptr+ 就能访问数组的各元素。,C语言程序设计与数据结构,【例8.20 】用地址法输入输出二维数组各元素。 #include main( ) int a34, i, j; printf(“Input 12 ge integer:n“); for(i=0;i3;i+) for(j=0;j4;j+) scanf(“%d“ ,ai+j) ; /*地址法*/ for(i=0;i3;i+) for(j=0;j4;j+)printf(“%4d“,*(ai+j); /* 此处*(ai+j)是地址法所表示的数组元素 */ printf(

41、“n“); 运行结果为: 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12,C语言程序设计与数据结构,【例8.21】用指针法输入输出二维数组各元素。 # include main( ) int a34, i ,j,*ptr; ptr=a0; printf(“Input 12 ge integer:n“); for(i=0;i3;i+) for(j=0;j4;j+) scanf(“%d“,ptr+); /* 指针的表示方法 */ ptr=a0; for(i=0;i3;i+) for(j=0;j4;j+)printf(“%4d“,*ptr+

42、); printf(“n“); ,C语言程序设计与数据结构,运行结果为: 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12 对指针法而言,上述程序中的for循环阴影部分也可以把二维数组看作是展开的一维数组: for(i=0; i12; i+) printf(“%4d“ ,*ptr+); printf(“n“);运行结果为: 1 2 3 4 5 6 7 8 9 10 11 121 2 3 4 5 6 7 8 9 10 11 12,C语言程序设计与数据结构,8.4.3 指向多维数组的指针变量,把二维数组a分解为一维数组a0,a1,a2之后,

43、设p为指向二维数组的指针变量。可定义为: int (*p)4; 它表示p是一个指针变量,它指向包含4个元素的一维数组。若指向第一个一维数组a0,其值等于a,a0,或&a00等。而p+i则指向一维数组ai。从前面的分析可得出*(p+i)+j是二维数组i行j 列的元素的地址,而*(*(p+i)+j)则是i行j列元素的值。二维数组指针变量说明的一般形式为:类型说明符 (*指针变量名)长度其中“类型说明符”为所指数组的数据类型。“*”表示其后的变量是指针类型。“长度”表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。应注意“(*指针变量名)”两边的括号不可少,如缺少括号则表示是指

44、针数组(本章后面介绍),意义就完全不同了。,C语言程序设计与数据结构,【例8.22】 main() int a34=0,1,2,3,4,5,6,7,8,9,10,11;int (*p)4;int i,j;p=a;for(i=0;i3;i+)for(j=0;j4;j+) printf(“%2d “,*(*(p+i)+j);printf(“n“); ,C语言程序设计与数据结构,8.5 指向字符串的指针变量在C语言中,可以用两种方法访问一个字符串。 8.5.1 用字符数组存放一个字符串 8.5.2 用字符指针变量指向一个字符串,C语言程序设计与数据结构,用字符数组存放一个字符串,【例8.23】 ma

45、in() char str1=s,t,r,i,n,g; /*字符数组str1, 数组长度为6,存放了6个字符*/char str2=s,t,r,i,n,g,0; /*字符数组str2, 数组长度为7,存放了一个字符串*/ char str3=”string”; /*字符数组str3, 数组长度为7,存放了一个字符串*/ char str4=”string”; /*字符数组str4, 数组长度为7,存放了一个字符串*/ char str510=”string”; /*字符数组str5, 数组长度为10,存放了一个字符串*/printf(“%sn“,str2); 说明:和前面介绍的数组属性一样,s

46、tr1str5都是数组名,它代表字符数组的首地址。,C语言程序设计与数据结构,8.5.2 用字符指针变量指向一个字符串,要想用字符指针变量指向一个字符串,首先应定义一个指向字符变量的指针变量。至于该指针变量是指向字符串还是字符变量,要根据对指针变量的赋值不同来区别。对指向字符变量的指针变量应赋予该字符变量的地址。 如:char ch,*p= 则表示p是一个指向字符串的指针变量,把字符串的首地址赋予p。,C语言程序设计与数据结构,【例8.24】 main() char str=”Hello!”;char *pstr=”I love you!”;printf(“%sn“,pstr); ,例8.24

47、中,如图8.7所示,首先定义pstr是一个字符指针变量,然后把字符串的首地址赋予pstr (写出整个无名字符串,以便编译系统把该无名字符串装入连续的一块内存单元),并把首地址送入pstr。 程序中的:char *pstr=“ I love you!“; 等效于下面两行:char *pstr; pstr=“ I love you!“; 但对数组方式: char str=“Hello!“; 不能写为: char str20;str=“ Hello!“; 因为数组的首地址不能变,此处是想把str指向一个无名字符串(该无名字符串存放在地址连续的一块内存单元内,可以看做是一个无名的字符数组),所以不行。,C语言程序设计与数据结构,【例8.25】输出字符串中n个字符后的所有字符。 main() char *ps=“this is a book“;int n=10;ps=ps+n;printf(“%sn“,ps); 运行结果为:book在程序中对ps初始化时,即把字符串首地址赋予ps,当ps= ps+10之后,ps指向字符“b”,因此输出为“book“。,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 网络科技 > C/C++资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报