大学C语言程序设计基础第9章参考_第1页
大学C语言程序设计基础第9章参考_第2页
大学C语言程序设计基础第9章参考_第3页
大学C语言程序设计基础第9章参考_第4页
大学C语言程序设计基础第9章参考_第5页
已阅读5页,还剩52页未读 继续免费阅读

付费下载

下载本文档

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

文档简介

1、 第九章 指针 第第9 9章章 指指 针针 指针是语言中广泛使用的一种指针是语言中广泛使用的一种数据类型数据类型。能很方便地。能很方便地使用数使用数组和字符串组和字符串;并能像汇编语言一样;并能像汇编语言一样处理内存地址处理内存地址,正确理解和使用指针是,正确理解和使用指针是掌握语言的一个重要标志。诚然,指针也是语言中最为困难的一部掌握语言的一个重要标志。诚然,指针也是语言中最为困难的一部分内容。分内容。一个变量有如下几个属性:一个变量有如下几个属性: 变量名变量名 变量值变量值 变量类型变量类型( (存储宽度存储宽度) ) 变量存储地址变量存储地址-指针指针 变量作用域变量作用域 变量生存期

2、变量生存期 指针其实就是变量的地址指针其实就是变量的地址。 指针也是一种指针也是一种数据类型数据类型,它用专门的变量,它用专门的变量“指针变量指针变量”来存放。来存放。注意:注意: 9.1 9.1 地址和指针的基本概念地址和指针的基本概念 一、一、 数据的存取:数据的存取: 图图 9.1 用户数据区用户数据区地址:地址: 变量:变量:2000H 00000000 变量变量I=3 000001012002H 00000000 变量变量j=6 000001102004H 00000000 变量变量k=9 00001001 . 指针变量指针变量 3010H 00000000 P=2000H3011H

3、 00100000 一般把存储器中的一般把存储器中的一个字节称为一个字节称为一个内存单元,一个内存单元,如整型量占如整型量占2个单元,个单元,字符量占字符量占1个单元等。每个内存单元的个单元等。每个内存单元的编号称为编号称为“内存地址内存地址”。 程序中的每个变量都对应着内存程序中的每个变量都对应着内存中的一个地址,从该地址开始的一个中的一个地址,从该地址开始的一个或多个字节用来存放该数据。或多个字节用来存放该数据。 根据内存单元的地址就可以找到根据内存单元的地址就可以找到内存单元中的数据,这个内存单元中的数据,这个地址地址称为内称为内存单元的存单元的指针指针。内存单元的指针和内。内存单元的指

4、针和内存单元的数据是两个不同的概念,例存单元的数据是两个不同的概念,例如,若有三个整形变量及值分别为:如,若有三个整形变量及值分别为: int i=3,j=6,k=9 则它们在内存中的存则它们在内存中的存储情况如图储情况如图 9.1 对于一个内存单元来说,对于一个内存单元来说,地址是它的位置,数据是它地址是它的位置,数据是它的内容。的内容。 在语言中,允许用一个变量来存放指针,在语言中,允许用一个变量来存放指针,这种变量称为这种变量称为指针变量。指针变量。定义指针的目的是为了通过指针去访问内存单元。定义指针的目的是为了通过指针去访问内存单元。程序编译后已经没有程序编译后已经没有 i、j、k 这

5、些变量名了,而是将变量这些变量名了,而是将变量名转换成了变量的地址如:名转换成了变量的地址如:2000、2002、2004。系统通。系统通过内存地址对变量进行存取。过内存地址对变量进行存取。不仅可以存放不仅可以存放变量的地址变量的地址,也可以是其他数据,也可以是其他数据 结构结构(如如: 数组、字符串、函数数组、字符串、函数)的地址。的地址。 因为数组、字符串、函数都是连续存放的,所以因为数组、字符串、函数都是连续存放的,所以指针指针变量中存放的是他们的首地址。变量中存放的是他们的首地址。二、内存单元的直接访问和间接访问方式二、内存单元的直接访问和间接访问方式按变量地址存取变量值的方式称为直接

6、访问方式按变量地址存取变量值的方式称为直接访问方式。 如语句:如语句:printf(“%d”,i); 程序编译时将变量程序编译时将变量 i 转换为转换为2000, 执行时,找到地址执行时,找到地址2000,从,从 2000,2001两个字节中取出数据两个字节中取出数据 3,把它输出。,把它输出。 又例如语句:又例如语句:scanf(“%f”,&i); 系统将键盘输入的值送到地址为系统将键盘输入的值送到地址为2000开始的变量开始的变量i的存储单元中。的存储单元中。通过指针变量找到变量的地址,再按变量地址定位到通过指针变量找到变量的地址,再按变量地址定位到内存单元内存单元,再存取变量的值。再存取

7、变量的值。 例如例如: int *p,I; 通过执行语句通过执行语句 p=&i; 将整型变量将整型变量i 的地址存放到变量的地址存放到变量 p中,即中,即 p 的的值为变量值为变量 i 所对应的内存单元的起始地址所对应的内存单元的起始地址2000。 找到存放找到存放i的地址的内存单元地址的地址的内存单元地址(3010和和3011),从中取出变量,从中取出变量i的的 地址值地址值2000, 对对2000和和2001单元进行存取单元进行存取这就称为这就称为 指针变量指针变量p p 的值为的值为20002000,即变量,即变量 i i 的地址,这样就在的地址,这样就在p p和和 i i 之间建立之间

8、建立了一种联系:了一种联系: 通过指针变量通过指针变量p p知道变量知道变量 i i 的地址,从而可找到变量的地址,从而可找到变量 i i 的内存单元,的内存单元,因此说因此说 ,如下图所示:如下图所示: 为了将整数为了将整数1010送到变量送到变量 i i 中,可以有以下两种表示方法:中,可以有以下两种表示方法: 将将1010直接送到变量直接送到变量i i所标志的单元中所标志的单元中, , 如左下图所示。如左下图所示。(2) (2) 将将1010送到送到指针变量指针变量 p p 所指向所指向的单元中的单元中, , 如右下图所示。如右下图所示。 20003000p2000i102000i200

9、03000p102000i4 4、指针与指针变量的概念、指针与指针变量的概念 如果一个变量专门用来存放另一个变量的地址,则称这个变量为如果一个变量专门用来存放另一个变量的地址,则称这个变量为“指指针变量针变量”。指针变量的值(即指针变量中存放的数据)是指针(地址)。指针变量的值(即指针变量中存放的数据)是指针(地址)。注意区分注意区分“指针指针”和和“指针变量指针变量”这两个概念。这两个概念。 几点说明几点说明数据所需内存单元的个数是由数据类型决定的。数据所需内存单元的个数是由数据类型决定的。变量的地址是指变量所占内存单元中第变量的地址是指变量所占内存单元中第1 1个字节的地址。个字节的地址。

10、地址的值与整数是有区别的地址的值与整数是有区别的。一、指针变量的定义一、指针变量的定义1、 指针变量的定义形式:指针变量的定义形式: 基类型基类型 *变量名;变量名; 定义包括三个内容:定义包括三个内容: (1) 指针类型说明,即定义变量为一个指针变量;指针类型说明,即定义变量为一个指针变量; (2) 指针变量名;指针变量名; (3) 指针所指向的变量的数据类型。指针所指向的变量的数据类型。2、 定义示例定义示例 例如:例如: int i, *p1=&i; 表示表示p1是一个指针变量,它的值是整型变量是一个指针变量,它的值是整型变量i的地址。或者说,的地址。或者说,p1指向整型变量指向整型变量

11、i。 又例如:又例如:int *p2; /* p2是指向整型变量的指针变量是指向整型变量的指针变量 */float *p3, x; /* p3是指向实型变量的指针变量是指向实型变量的指针变量 */char *p4; /* p4是指向字符变量的指针变量是指向字符变量的指针变量 */ 应该注意的是,应该注意的是,如,如: P3 只能指只能指向实型变量。向实型变量。9.2 指针变量的定义与引用指针变量的定义与引用3、说明、说明(1)“*”只是表示定义的变量为指针变量,指针变量名中并不包含只是表示定义的变量为指针变量,指针变量名中并不包含“*”; “*”是指针变量的标志,不可丢掉。是指针变量的标志,不

12、可丢掉。(2) 一个指针变量被定义之后,它所一个指针变量被定义之后,它所指向对象的类型指向对象的类型就确定了。就确定了。 例如:例如:int x,y,*p; double a; p&x; 不能把不能把a的地址赋给的地址赋给p,即不能有,即不能有 p&a。(3)所有指针变量占用相同字节的内存单元。所有指针变量占用相同字节的内存单元。(4)指针变量可以指向任何类型的对象,包括指向数组、指向别的指针变指针变量可以指向任何类型的对象,包括指向数组、指向别的指针变 量、指向函数等。量、指向函数等。例如,可以有下列变量说明:例如,可以有下列变量说明:char (*p) 5;p指向含指向含5个元素的一维字符

13、数组个元素的一维字符数组,或理解为字符型二,或理解为字符型二 维数组的行指针,每行为含维数组的行指针,每行为含5个元素,个元素,p+i 指向第指向第 i 行。行。 int *p5; P为指针型数组,为指针型数组,其其5个元素都是指针,都指向整型数组。个元素都是指针,都指向整型数组。 int * *ip; 指向指向整形指针的指针整形指针的指针 int *fip( ); 函数值为指针的函数函数值为指针的函数-指针型函数指针型函数,指向整形函数。,指向整形函数。 int (*pti)( ) 指向整形函数的指针指向整形函数的指针 , 二、指针运算符二、指针运算符 “*”(间接访问变量的值)(间接访问变

14、量的值) “*” 可以得到指针变量所指向的变量的值。可以得到指针变量所指向的变量的值。 例如:若例如:若ip为指针变量,它指向变量为指针变量,它指向变量 i, 则则 *ip 与与I 等价。等价。 int i, *ip; ip=&i; /*指针变量指针变量ip中存放整形变量中存放整形变量i的地址的地址*/则下面两个赋值语句作用相同:则下面两个赋值语句作用相同: i=5; *ip=5; 第第2个语句的含义是将个语句的含义是将5赋给指针变量赋给指针变量ip所指向的变量。所指向的变量。结论:结论: 因为因为 所以所以 x=i+3; 与与 x=*ip+3; 也等价。也等价。三、取地址运算符三、取地址运算

15、符“&” 运算符运算符“&”与一个变量连用,可以得到该变量的内存与一个变量连用,可以得到该变量的内存 地址。地址。如:如:&a 、&x1说明说明(1) 取地址运算符只能作用于变量取地址运算符只能作用于变量, 如:如:&x, &a5;不能作用不能作用 于常量、表达式或寄存器变量于常量、表达式或寄存器变量, 如如“&25, &(i+1);”是错的。是错的。(2) 不能把整数赋值给一个指针变量。不能把整数赋值给一个指针变量。 如如: int *ip; ip=3000; 是错的是错的。为什么?。为什么?(3) 不能把一个指针变量的值赋值给一个整型变量不能把一个指针变量的值赋值给一个整型变量. 如如:

16、int *ip, x; x=ip; 是错的。是错的。为什么?为什么?例例J9.1: “*”运算符和运算符和“&”运算符用法的例子。运算符用法的例子。 #include (演示)(演示)void main()float x; /* x是一个实型变量是一个实型变量 */ float *p = &x; /*定义指针变量定义指针变量p,将实型变量,将实型变量x的地址传给的地址传给p*/ /* 也可以写成:也可以写成:float *p; p=&x; */ x = 7.10;printf( The address of x is %x The value of p is %x n,&x,p); /* 以十

17、六进制形式显示以十六进制形式显示x的地址和的地址和p的值的值 */printf( The value of x is %f The value of *p is %fn,x,*p); /* 输出输出x的值和指针的值和指针xptr所指向的变量所指向的变量x的值的值 */运行结果为:运行结果为:The address of x is ffd6 The value of p is ffd6 The value of x is 7.100000 The value of *p is 7.100000四、指针变量的赋值和引用四、指针变量的赋值和引用1、指针变量的赋值、指针变量的赋值 指针变量在使用之前不

18、仅要定义而且必须赋值。未经赋值的指针变量指针变量在使用之前不仅要定义而且必须赋值。未经赋值的指针变量 (称为称为:)不能使用,否则将造成系统混乱,甚至死机。不能使用,否则将造成系统混乱,甚至死机。 指针变量只能赋予变量的地址值。指针变量只能赋予变量的地址值。例如,可以用以下两种方式给指针赋值:例如,可以用以下两种方式给指针赋值: (1) 用用指针变量初始化指针变量初始化的方法,即的方法,即: int a; int *p=&a; (2) 用用赋值语句赋值语句的方法的方法: int a; int *p; p=&a;同类型同类型的指针变量可以相互赋值的指针变量可以相互赋值: 例如例如: int *p

19、1,*p2,i; p1=&i; p2=p1说明说明:(1) 指针变量定义后,若不赋值,其值是不确定的指针变量定义后,若不赋值,其值是不确定的(浮动浮动)。(2) 可以给指针变量赋空值可以给指针变量赋空值(NULL),使指针变量不指向任何变量,例如,使指针变量不指向任何变量,例如: #define NULL 0 int *p ip=NULL;(3) 与与 意义是不同的。意义是不同的。(4) 指针变量的值是它所指对象在内存中的地址,利用运算符指针变量的值是它所指对象在内存中的地址,利用运算符“&”可得到可得到 该对象的地址。该对象的地址。(5) 利用指针可以间接访问对象,这是通过运算符利用指针可以

20、间接访问对象,这是通过运算符“*”实现的。实现的。(6) 不能将一个整型量不能将一个整型量(或任何其他非地址类型的数据或任何其他非地址类型的数据)赋给一个指针变量。赋给一个指针变量。 例如例如: int *p; p=1000; 是错误的。是错误的。(7) 被赋值的指针变量前不能再加被赋值的指针变量前不能再加“*”说明符,如写为说明符,如写为 *p=&a 也是错误的也是错误的。 因为因为 *p 表示变量的值。表示变量的值。2. 指针变量的引用指针变量的引用说明说明 “&” 既能作用于一般变量,也能作用于既能作用于一般变量,也能作用于 指针变量;指针变量;但但“*“只能作用只能作用于指于指 针变量

21、。针变量。 表达式中的表达式中的 *p 与变量定义中的与变量定义中的 *p 含义不同,如有以下语句:含义不同,如有以下语句: int i, *p=&i; /*定义一个指针定义一个指针p,其值为变量,其值为变量 i 的地址的地址*/ *p=5; /*给变量给变量 i 赋值赋值 */ 又假设又假设: int i=200, x; int *ip; ip=&i; 假设变量假设变量i的地址为的地址为1800,以后便可以通过指针变量,以后便可以通过指针变量ip间接访问变量间接访问变量 i, 例如例如: x=*ip; 运算符运算符“*”可以访问以可以访问以ip为地址的存储区域为地址的存储区域, 而而ip中存

22、放的是变量中存放的是变量i的地的地址。因此,址。因此,*ip访问的是地址为访问的是地址为1800的存储区域的存储区域( 因为是整数因为是整数,实际上是从实际上是从1800开始的两个字节开始的两个字节), 它就是它就是 i 所占用的存储区域。所以,上面的赋值表所占用的存储区域。所以,上面的赋值表达式等价于达式等价于: x=i;(3)指针变量中的值是可以改变的。改变他的值就是改变它的指向。如:)指针变量中的值是可以改变的。改变他的值就是改变它的指向。如:int i,j,*p1,*p2;i=a;j=b;p1=&i;p2=&j;如图如图10.7若执行若执行 p2=p1;则则p2与与p1指向同一变量指向

23、同一变量i,,如图,如图9.8若执行若执行 *p2=*p1; 相当于相当于: j=i; 。如图。如图9.9所示。所示。图 9.8图 9.7图 9.94)指针变量可出现在表达式中。)指针变量可出现在表达式中。若有定义若有定义: int x,y,*px=&x;则则*px可以出现在表达式中:可以出现在表达式中:y=*px+5; /* 表示把表示把*px中的内容加中的内容加5并赋给并赋给y */y=+*px; /*右结合右结合,px的内容加上的内容加上1之后赋给之后赋给y,+*px相当于相当于+(*px) */y=*px+; /* 运算符运算符右结合右结合,等价于,等价于 *(px+), 括号中后置运

24、算括号中后置运算, 故先故先*/ /*做做 y=*px; 再做再做 px+; 于是于是px指向下一个整型变量了指向下一个整型变量了 */ 例例J9-2指针与指针与+、- 的结合的结合 (演示)(演示)#include void main()int i,j,k,m,*p=&i; i=5,j=8; printf(The value of +*p is %dn,+*p); printf(The value of p is %xn,p); k=*p+; /* 执行后执行后P指向下一个变量了指向下一个变量了*/ m=*p; printf(The value of p+ is %xn,p); printf

25、(%d,%dn,k,m); getch(); 运行结果:运行结果:The value of +*p is 6 The value of p is ffc8 The value of p+ is ffca 6,8 指针变量的引用举例指针变量的引用举例阅读阅读P179例例L9.1 a),注意到变量注意到变量a,b的值的值并没有改变并没有改变.阅读阅读P179例例L9.1 b),注意到变量注意到变量a,b的值的值已经改变了已经改变了。指针变量的引用方法:指针变量的引用方法:(1) 将变量的地址赋给指针变量将变量的地址赋给指针变量(p1=&a1)。(2) 将一个指针变量赋给另一个指针变量将一个指针变量

26、赋给另一个指针变量(p2=p1;)。(3) 通过指针变量间接访问它所指向的变量通过指针变量间接访问它所指向的变量(*p1)。五、指针变量作为函数的参数五、指针变量作为函数的参数有两种不同的方式把实参值传递给被调函数的形参:有两种不同的方式把实参值传递给被调函数的形参:一种是前面所讲的传递实参的值;一种是前面所讲的传递实参的值;另一种方式就是传递实参的地址。另一种方式就是传递实参的地址。 由于被调函数接收到的值是实参的地址,所以在被调函数执行过程中由于被调函数接收到的值是实参的地址,所以在被调函数执行过程中就可以引用这个地址而修改主调函数中相应实参变量的值。就可以引用这个地址而修改主调函数中相应

27、实参变量的值。P182页例页例L9.2 用传值方式和传址方式编写一个程序,输入两个整数用传值方式和传址方式编写一个程序,输入两个整数 a、b,按大小顺序输出。,按大小顺序输出。(1)按)按“传值传值”调用方式编写程序并不能达到目的。调用方式编写程序并不能达到目的。 因为因为 阅读阅读P182页程序。页程序。(2)按)按“传址传址”调用方式编写程序能得到正确的结果。调用方式编写程序能得到正确的结果。 阅读阅读P183页程序页程序分析下面的程序是否能交换变量的值?分析下面的程序是否能交换变量的值? 例例J9-3J9-3#include void swap(int *px, int *py) int

28、 *temp; *temp=*px; /*危险危险*/ *px=*py; *py=*temp;void main( ) int a, b, *p1, *p2; printf(nInput a, b: ); scanf(%d,%d, &a, &b); p1=&a; p2=&b; if (ab) swap(p1, p2); printf(max=%d, min=%dn, a, b); (演示)(演示)答案是否定的!答案是否定的!因为因为*temp是指针变量是指针变量temp所指向所指向的变量,但的变量,但temp中并无确定的地址中并无确定的地址值,值, 因此,因此,对一个不确定的地址单元赋对一个不

29、确定的地址单元赋值会破坏系统的稳定性。值会破坏系统的稳定性。正确的做正确的做法应象法应象P183页的程序那样。将页的程序那样。将*px的值赋给一个整型变量,用整型变的值赋给一个整型变量,用整型变量作为临时存储空间实现量作为临时存储空间实现*px和和*py的交换。的交换。再分析下面的程序是否能交换变量的值?分析下面的程序是否能交换变量的值? 例例J10-4J10-4#include void swap(int *px, int *py) int *p; p=px; px=py; py=p; void main( ) int a, b, *p1, *p2; printf(nInput a, b:

30、); scanf(%d,%d, &a, &b); p1=&a; p2=&b; if (apf2表示表示pf1处于高地址位置(后面);处于高地址位置(后面); pf1pf2表示表示pf2处于低地址位置(前面)。处于低地址位置(前面)。 p=0 表明表明p是空指针,它不指向任何变量。是空指针,它不指向任何变量。空指针空指针是由对指针变量赋予是由对指针变量赋予0值而得到的。例如:值而得到的。例如: #define NULL 0 int *p=NULL; 对指针变量赋对指针变量赋0值和不赋值是不同的。指针变量未赋值值和不赋值是不同的。指针变量未赋值时,是不能使用的。而指针变量赋时,是不能使用的。而指针

31、变量赋0值后,则可以使用,值后,则可以使用,只是它不指向具体的变量而已。只是它不指向具体的变量而已。 9.3 数组指针和指向数组的指针变量数组指针和指向数组的指针变量一、指向数组元素的指针一、指向数组元素的指针 1、巩固几个基本概念:、巩固几个基本概念:(1) 一个变量的地址称为该变量的指针。当用一个变量来存一个变量的地址称为该变量的指针。当用一个变量来存放该地址放该地址(指针指针)时,称为时,称为指针变量指针变量。(2) 每个数组都有一个起始地址,每个数组都有一个起始地址,数组的起始地址称为数组的数组的起始地址称为数组的指针。指针。(3) 一个数组包含若干元素,每个数组元素都在内存中占用一一

32、个数组包含若干元素,每个数组元素都在内存中占用一定的存储单元,即都有相应的地址,定的存储单元,即都有相应的地址,数组元素的地址称数组元素的地址称为数组元素的指针。为数组元素的指针。(4) 指针变量可以指向变量,当然也可以指向数组和数组元素。指针变量可以指向变量,当然也可以指向数组和数组元素。2 2、数组指针的定义、数组指针的定义 数组指针的定义方法与简单变量指针定义相同,但引用略有不同数组指针的定义方法与简单变量指针定义相同,但引用略有不同,其其一般形式为一般形式为: 类型说明符类型说明符 *指针变量名指针变量名; 例如:例如: int a10; /* 定义定义a为包含为包含10个整型数据的数

33、组个整型数据的数组 */ int *p; /* 定义定义p为指向整型变量的指针为指向整型变量的指针 */或:或: int a10,*p;指向数组的指针变量和指向普通变量的指针变量的定义是相同的指向数组的指针变量和指向普通变量的指针变量的定义是相同的,3 3、数组指针变量的赋值、数组指针变量的赋值 注意指针类型与数组类型一致注意指针类型与数组类型一致 i int a10,*p; p=&a0;或:或: p=a 表示把数组表示把数组a0元素的地址赋给指针变量元素的地址赋给指针变量p。也就是也就是p指向指向a数组的第数组的第0号元素。号元素。4、说明:、说明:(1)C语言规定语言规定, a的首地址可用

34、的首地址可用&a0表示,表示, 也可用也可用a表示。所以表示。所以 p=&a0 和和 p=a 等价等价.(2) 可以在定义指针变量时赋初值可以在定义指针变量时赋初值. int p=&a0; 或或: int p=a; 等价于等价于: int *p; p=a;而语句:而语句:*p=&a0;是不成立的。;是不成立的。 从图中可以看出:从图中可以看出:p,a,&a0均指向同一单均指向同一单元,它们是数组元,它们是数组a的首地址,也是第的首地址,也是第0号元号元素素a0的首地址。的首地址。二、通过指针访问一维数组二、通过指针访问一维数组 1、通过指针引用数组元素。、通过指针引用数组元素。 若:若:int

35、 a5=1,3,5,7,9, *p; 则:则:p=a; 于是于是 *p=1; 等效于等效于 a0=1; p=&a3; 于是于是 *p=7; 等效于等效于 a3=7; 语言规定语言规定,无论数组的数据类型如何,若指针变量无论数组的数据类型如何,若指针变量p已指向数组已指向数组 中的某一元素,则中的某一元素,则p+1指向同一数组中的下一个元素。指向同一数组中的下一个元素。对于指向整型数组的指针变量对于指向整型数组的指针变量p,p+1意味着使意味着使p在原值的基础上加在原值的基础上加2 个字节,个字节, 对于指向对于指向float型数组的指针变量型数组的指针变量p,p+1意味着使意味着使p在原值的基

36、础上在原值的基础上 加加4个字节,个字节,总之:总之: 若设若设d是一个数组元素所占的字节数,则是一个数组元素所占的字节数,则p+i表示指针移动了表示指针移动了 i 个元个元素,而它实际的地址变化为素,而它实际的地址变化为 p+i*d。(1) 给指针赋初值的方法是:给指针赋初值的方法是: p=a; 或或 p=&a0;(2) p+1或或a+1实际上是表示数组元素实际上是表示数组元素a1 的地址,而的地址,而p+i或或a+i表示数组的第表示数组的第i个个 元素的地址。元素的地址。(3) *(p+i) 或或*(a+i)表示表示ai。(4) 指向数组的指针变量也可以带下标。指向数组的指针变量也可以带下

37、标。 如:如:即即ai等价。等价。 参见右边例参见右边例L19-2-1(5) 若若p已经指向某个数组元素已经指向某个数组元素ai,则,则p+j 表示指向数组元素表示指向数组元素ai+j。(6)可以用两种方法来引用一个数组元素可以用两种方法来引用一个数组元素下标法:用下标法:用ai 来引用数组来引用数组a中的第中的第i号号 元素。元素。指针法:用指针法:用*(p+i)或或*(a+i)来引用数组来引用数组 中的第中的第i号元素。号元素。2 2、通过、通过指针变量引用数组元素指针变量引用数组元素时应注意的问题:时应注意的问题:3、 如何使用数组指针如何使用数组指针 ()(1) 可以使用可以使用p+使

38、指针变量使指针变量p的值不断改变,例如:的值不断改变,例如:for (p=a; p(a+10); p+) printf(%4d, *p);(2) 注意指针变量的运算:注意指针变量的运算: 若若p指向数组的开始,即:指向数组的开始,即:p=a; 则:则: p+; 使使p指向下一元素,即:指向下一元素,即:a1; *p+; *p+相当于相当于*(p+), 若若p=&a0, 则先取则先取*p的值、即的值、即 a0的值,再的值,再使使 p+1, p指向指向a1, 而:而:*(+p)为先使为先使p=p+1, p指向指向a1,*(+p)取出取出a1的值的值。设指针变量指向数组的第设指针变量指向数组的第i号

39、元素,则:号元素,则: *(p- -)相当于相当于ai - -;先取;先取ai,再指向再指向ai-1 *(+p)相当于相当于a+i; *(-p)相当于相当于a- - i。 (*p)+表示表示p所指向的元素值加所指向的元素值加1, (*p)-表示表示p所指向的元素值减所指向的元素值减1。 但:但: 等价。等价。 等价。等价。例例J9-5 (演示)演示) #includevoid main()int i,j,k,*p1,*p2,*p3; int a5=1,5,10,15,20; p1=a;p2=p1;p3=p1; i= *(p1)+; printf(a0=%dn,a0); j= (*p2)+; p

40、rintf(a0=%dn,a0); k= *p3+; printf(%d,%d,%d,%dn,a0,i,j,k); 运行结果:运行结果:a0=1 a0=2 2, 1,1, 2 三、通过指针在函数间传递一维数组三、通过指针在函数间传递一维数组 1. 数组元素作为函数参数数组元素作为函数参数: void swap(int x, int y); swap(a1, a2); 2. 数组名作为函数参数数组名作为函数参数: 当实参、形参均为数组名时,调用时会将实参数组首地址传递当实参、形参均为数组名时,调用时会将实参数组首地址传递(单向单向)给给形参数组,形参和实参指向同一数组。形参数组,形参和实参指向同

41、一数组。 void f(int x , int n); f(a, 10); 语言编译系统将语言编译系统将 数组名数组名作作为为指针变量指针变量来处理的来处理的,例如例如: int a10; x=a; xi 等效于等效于 *(x+i) 若在函数调用期间改变了数组某一存储单元的内容,则在函数调用若在函数调用期间改变了数组某一存储单元的内容,则在函数调用 完毕后,已改变的值将被保留下来。完毕后,已改变的值将被保留下来。阅读阅读P191页页例例9-73、用指针变量替代数组名作为函数的参数、用指针变量替代数组名作为函数的参数 (1) 形参和实参都用数组名形参和实参都用数组名,例如:,例如: 定义:定义:

42、f(int x , int n); 调用:调用:f(a, 10); (2) 实参用数组名,形参用指针变量实参用数组名,形参用指针变量,例如:,例如: 定义:定义:f(int *x, int n); 调用:调用:f(a, 10);(3) 形参和实参都用指针变量形参和实参都用指针变量,例如:,例如: 定义:定义:f(int *x, int n); 调用:调用:f(p, 10); p=a;(4) 实参为指针变量,形参为数组名,实参为指针变量,形参为数组名,例如:例如: 定义:定义:f(int x , int n); 调用:调用:f(p, 10);阅读阅读P194页,页,例例9-8至例至例9-10四、

43、指向二维数组的指针和指针变量四、指向二维数组的指针和指针变量考察二维数组考察二维数组a34:0 1 2 34 5 6 78 9 10 11其定义为:其定义为: int a34=0,1,2,3,4,5,6,7,8,9,10,11 巩固概念:巩固概念:二维数组二维数组a由由3个名为:个名为: a0、a1、a2的一维数组组成。的一维数组组成。 a0a1a2都是地址,不是元素,二维数组元素应带都是地址,不是元素,二维数组元素应带2个下标。个下标。1、二维数组的地址、二维数组的地址上述上述: 二维数组名二维数组名 a 中存放着二维数组的首地址。中存放着二维数组的首地址。 3 个个一维数组名一维数组名 a

44、0、a1、a2 分别存放着分别存放着3个行的首地址。个行的首地址。 a 是第是第 0 行的首地址行的首地址 a0; a0+0是数组元素是数组元素a00的地址的地址 a0+1是数组元素是数组元素a01的地址的地址 a0+2是数组元素是数组元素a02的地址的地址 a0+3是数组元素是数组元素a03的地址的地址 a+1是第是第1行的首地址行的首地址a1; a+2是第是第2行的首地址行的首地址a2;地址:地址: a, a0,*(a+0),*a,&a00 是等价的是等价的。 a+1, a1, *(a+1), &a10 是等价的。是等价的。 推广:推广:a+i, ai, *(a+i), &ai0 是等价的

45、。是等价的。 特别特别别扭之处别扭之处:a+i 、*(a+i) 怎么是一个地址呢?怎么是一个地址呢?*(a+i)不是表示不是表示变量变量 a 的值吗?的值吗? 注意:此处注意:此处a是二维数组名是二维数组名,在二维数组中就有此规定。,在二维数组中就有此规定。 还有如下还有如下别扭之处别扭之处: &ai 和和 ai 也是等同的。因为在二维数组中不能把也是等同的。因为在二维数组中不能把&ai理解为理解为元素元素ai的地址,的地址,不存在元素不存在元素ai。表示二维数组。表示二维数组 a 第第 i 行首地址。行首地址。 由此可见:由此可见:ai,&ai,*(a+i),a+i 也都是等价的也都是等价的

46、。由于由于 *(a+1) 都是第都是第1行元素的首地址,故行元素的首地址,故 *(a+1)+1 是元素是元素a11的地址。的地址。于是:于是: *(*(a+1)+1) 才是元素才是元素 a11的值的值。 此处此处a 是二维数组!是二维数组! 阅读阅读P199页例页例9-12二、指向二维数组的指针变量二、指向二维数组的指针变量设有二维数组:设有二维数组: int a34 可以做如下定义:可以做如下定义: int a34=0,1,2,3,4,5,6,7,8,9,10,11; int(*p)4; /*定义二维数组指针定义二维数组指针p */ p=a; /*p指向二维数组指向二维数组a */ 二维数组

47、指针说明的一般形式为:二维数组指针说明的一般形式为: 类型说明符类型说明符 (*指针变量名指针变量名)长度长度“类型说明符类型说明符” : 所指数组的数据类型。所指数组的数据类型。“长度长度” : 也就是二维数组的列数。也就是二维数组的列数。“*指针变量名指针变量名”两边的圆括号不可少,如缺少圆括号则表示两边的圆括号不可少,如缺少圆括号则表示是指针数组。是指针数组。对于:对于:int(*p)4;说明:说明:(1) *p有有4个元素,每个元素为整型个元素,每个元素为整型, p所指的对所指的对 象是有象是有4个整型元素的数组,个整型元素的数组, p为行指针。为行指针。(2) p只能指向一个包含只能

48、指向一个包含4个元素的一维数组,个元素的一维数组,p 的值就是该一维数组的首地址。的值就是该一维数组的首地址。P 不能指向不能指向 一维数组中的元素一维数组中的元素.(3) p+i 表示二维数组中第表示二维数组中第 i 行的地址,行的地址, 于是:于是: *(p+i)+j表示第表示第i行第行第j列元素的地址;列元素的地址; *(*(p+i)+j)即数组元素即数组元素aij。例例10-18:二维数组指针变量的应用。二维数组指针变量的应用。通过指针输出二维数组的所有元素,程序如下:通过指针输出二维数组的所有元素,程序如下: void main()int a34=0,1,2,3,4,5,6,7,8,

49、9,10,11; int(*p)4; int i,j; p=a; for(i=0;i3;i+) for(j=0;jb)return a; else return b; #includevoid main() int(*pmax)(); /*定义函数指针定义函数指针*/ int x,y,z; pmax=max; /*给函数指针赋值给函数指针赋值*/ printf(input two numbers:n); scanf(%d,%d,&x,&y); z=(*pmax)(x,y); /*利用函数指针调用函数利用函数指针调用函数*/ printf(maxmum=%d,z);(2) 用函数指针变量调用函数

50、的步骤如下:用函数指针变量调用函数的步骤如下:先定义函数指针变量。先定义函数指针变量。把被调函数的入口地址把被调函数的入口地址(函数名函数名)赋予该函数指针变量。赋予该函数指针变量。用函数指针变量形式调用函数。用函数指针变量形式调用函数。注意:注意:(1) 函数指针变量不能进行算术运算。函数指针变量不能进行算术运算。(2) 函数调用中函数调用中 “(*指针变量名指针变量名)” 的两边的圆括号不可少,的两边的圆括号不可少,其其 中的中的 “*” 不应该理解为求值运算,在此处它只是一种表不应该理解为求值运算,在此处它只是一种表示示 符号。符号。6、指针型函数、指针型函数 函数的返回值可以是:字符型

51、、整型、实型,函数的返回值可以是:字符型、整型、实型, 事实上函数还可以事实上函数还可以返回一个指针值,返回一个指针值,指针型函数:返回值是指针的函数。指针型函数:返回值是指针的函数。 P212页页 例例9-22 就是一个指针函数的例子。就是一个指针函数的例子。指针型函数的定义:指针型函数的定义: 类型说明符类型说明符 *函数名函数名(形参表形参表) /* 函数体函数体 */ “*”: 表明这是一个指针型函数,表明这是一个指针型函数, “类型说明符类型说明符”: 表示返回的指针所指向的数据类型。表示返回的指针所指向的数据类型。阅读阅读P213页例页例9-237、指针数组和指向指针的指针、指针数

52、组和指向指针的指针一、指针数组的概念一、指针数组的概念 前面的学习中,数组元素可以是整型、实型、字符型,事实上,数前面的学习中,数组元素可以是整型、实型、字符型,事实上,数组元素还可以是指针。组元素还可以是指针。指针数组:指针数组:一组有序的指针的集合。一组有序的指针的集合。 指针数组的所有元素都必须是指向相同数据类型的指针变量。指针数组的所有元素都必须是指向相同数据类型的指针变量。指针数组的定义:指针数组的定义: 类型说明符类型说明符 *数组名数组名数组长度数组长度“类型说明符类型说明符”:指针指向的变量的类型。:指针指向的变量的类型。例如:例如: int *pa3; 表示表示pa是一个指针

53、数组,它有是一个指针数组,它有3个数组元素,每个元素值都是一个指个数组元素,每个元素值都是一个指针,它们都指向整型变量。针,它们都指向整型变量。指针数组和二维数组指针的区别指针数组和二维数组指针的区别 二维数组指针是单个的指针变量,如:二维数组指针是单个的指针变量,如:int (*p)3; 表示一个指向二维数组的指针变量表示一个指向二维数组的指针变量 P。该二维数组的列数为。该二维数组的列数为 3 ,P指向指向二维数组的第二维数组的第0行;行;P+1指向第指向第1行;行;P+i 指向第二维数组的第指向第二维数组的第 i 行。行。 而指针数组,如而指针数组,如 int *p3; 表示表示p是一个指针数组,有是一个指针数组,有3个下标变量个下标变量p0,p1,p2均为指针变量。均为指针变量

温馨提示

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

评论

0/150

提交评论