第九章 指针

84
第第第 第第 第第第第第第1 第第第第第第第第 第第第第第第第 、,; 2 第第第第第第第 第第第 、、、 第第3 第第第第第第第第第 、。 4 第第第第第第第第第第第 第第第第第第 第第第第第 、()。 5 第第第第第第第第第第第第第第 、。

Upload: reese-roberson

Post on 30-Dec-2015

41 views

Category:

Documents


5 download

DESCRIPTION

第九章 指针. 本章主要任务: 1 、指针的基本概念,变量访问方式; 2 、指针变量定义、赋值、引用。 3 、指针作为函数参数。 4 、数组的指针及指向数组(或数组元素)指针变量。 5 、指向数组的指针作为函数参数。. 内存. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第九章 指针

第九章 指针本章主要任务:

1 、指针的基本概念,变量访问方式; 2 、指针变量定义、赋值、引用。3 、指针作为函数参数。 4 、数组的指针及指向数组(或数组元素)指针变量。5 、指向数组的指针作为函数参数。

Page 2: 第九章 指针

内存内存(内部存储器):是由大规模集成电路芯片组成存储器,包括 RAM 、 ROM 。运行中的程序和数据都是存放在内存中的。与内存相对的是外存,外存是辅助存储器(包括软盘、硬盘、光盘),一般用于保存永久的数据。一定要记住:程序、数据是在内存中由 CPU 来执行和处理的。外存上尽管可以保存程序和数据,但是当这些数据在没有调入内存之前,是不能由 CPU 来执行和处理的。

Page 3: 第九章 指针

内存地址内存地址:内存是由内存单元(一般称为字

节)构成的一片连续的存储空间,每个内存单元都有一个编号。内存单元的编号就是内存地址,简称地址。

CPU是通过内存地址来访问内存,进行数据存取(读 /写)。

Page 4: 第九章 指针

示意图

Page 5: 第九章 指针

变量、变量名、变量的地址、变量值

变量:命名的内存空间。变量在内存中占有一定空间,用于存放各种类型的数据。

变量名:变量名是给内存空间取的一个容易记忆的名字。

变量的地址:变量所使用的内存空间的地址。

变量值:在变量的地址所对应的内存空间中存放的数值

即为变量的值或变量的内容。

Page 6: 第九章 指针

示意图

Page 7: 第九章 指针

指针、变量的指针

指针:就是 “内存单元的地址”。指针指向一个内存单元。

变量的指针:就是“变量的地址”。变量的指针指向一个变量对应的内存单元。

Page 8: 第九章 指针

指针变量指针变量:

就是地址变量。地址(指针)也是数据,可以保存在一个变量中。保存地址(指针)数据的变量称为指针变量。 指针变量 p 中的值是一个地址值,可以说指针变量p 指向这个地址。如果这个地址是一个变量 i 的地址,则称指针变量 p 指向变量 i 。指针变量 p 指向的地址也可能仅仅是一个内存地址。

Page 9: 第九章 指针

示意图

Page 10: 第九章 指针

说明

1 、牢记:指针 - 地址。指针变量 - 地址变量。

2 、指针变量是变量,它也有地址,指针变量的地址 - 指针变量的指针(指针的指针)。

Page 11: 第九章 指针

系统访问变量的两种方式(变量的存取方式)

1 、直接访问:按地址存取内存的方式称为“直接访问” 。

2 、间接访问(使用指针变量访问变量) 。

Page 12: 第九章 指针

直接访问1) 按变量名直接访问 , 按变量地址直接访问。 如: a

=3; *(&a)=3; 从系统的角度看不管是按变量名访问变量,还是按变量地址访问变量 , 本质上都是对地址的直接访问。用变量名对变量的访问属于直接访问,因为编译后,变量名 - 变量地址之间有对应关系,对变量名的访问系统自动转化为利用变量地址对变量的访问。

Page 13: 第九章 指针

直接访问2 )按地址直接访问(访问内存存储空间) -

一般不要这么使用,这里仅为了说明概念。如: *((int *)(2008))=5; 在地址 2008 保存一个

整数。farptr=(char far *)0xA0000000; *(farptr+offs+i1*MAXB)=*farbit; 操作显示内存。

Page 14: 第九章 指针

间接访问(使用指针变量访问变量)

将变量 a 的地址(指针)存放在指针变量 p 中,p 中的内容就是变量 a 的地址,也就是 p 指向 a ,然后利用指针变量 p 进行变量 a 的访问。

p=&a, *p=3 。 从变量名获得变量地址用“ &” 运算符,从地址获得地址指向的数据用“ *” 运算符。

Page 15: 第九章 指针

示意图

Page 16: 第九章 指针

指针变量的定义

定义格式 :基类型 * 变量名;

Page 17: 第九章 指针

说明 1 、 C 语言变量先定义后使用,指针变量也不例外,

为了表示指针变量是存放地址的特殊变量,定义变量时在变量名前加“ *” 号。

2 、指针变量存放地址值, PC 机用 2 个字节表示一个地址,所以指针变量无论什么类型,其本身在内存中占用的空间是 2 个字节。 sizeof(pt1)=sizeof(f)=sizeof(pc)=2 。

Page 18: 第九章 指针

说明

3 、指针变量的基类型(简称:指针变量类型):指针变量所指向数据的类型。我们知道,整型数据占用 2 个字节,浮点数据占用4 个字节,字符数据占用 1 个字节。指针变量类型使得指针变量的某些操作具有特殊的含义。比如, pt1++; 不是将地址值增 1 ,而是表示将地址值 +2 (指向后面一个整数)。

Page 19: 第九章 指针

指针变量的赋值方法

1 、方法一:将地址直接赋值给指针变量(指针变量指向该地址代表的内存空间) 。

2 、方法二:将变量的地址赋值给指针变量(指针变量指向该变量) 。

Page 20: 第九章 指针

方法一将地址直接赋值给指针变量(指针变量指向该地址代表的内存空间) 。

例如:char far *farptr=(char far *)0xA0000000; 将显存首

地址赋值给指针。float *f=(float *)malloc(4); malloc 动态分配了 4 个字节的连续空间,返回空间首地址,然后将首地址赋值给浮点型指针 f 。这样浮点型指针 f 指向这个连续空间的第一个字节。

Page 21: 第九章 指针

方法二

将变量的地址赋值给指针变量(指针变量指向该变量) 。

例如:int i,*p; p=&i;

Page 22: 第九章 指针

指针变量的引用

& 运算符(取地址运算符):表示取变量的地址。

* 运算符(指针运算符、间接访问运算符):访问指针变量指向的变量的值。

Page 23: 第九章 指针

应用举例

Page 24: 第九章 指针

指针变量作为函数的参数

指针变量作为函数参数时,同样是从实参单向传递指针变量的内容给形参,只是传递的内容是一个地址值。可以通过这个地址值间接改变实参、形参所共同指向的变量。所以尽管不能改变实际参数地址本身,但是可以间接改变地址所指向的变量。

Page 25: 第九章 指针

应用举例

例 10-2 :输入 a,b ;交换 a,b 数据后输出。

Page 26: 第九章 指针

正确解法

Page 27: 第九章 指针

变量传递示意图

Page 28: 第九章 指针

说明

1 、将主调函数变量的地址传递给被调用函数,就是说函数应当传递的是变量的地址。这样被调用函数的形参应当使用指针变量接受主调函数的地址值。

Page 29: 第九章 指针

说明

2 、在被调用函数中通过形参指针变量间接访问,修改实参、形参地址所共同指向的变量。本例的操作是交换两个指针变量所指向的变量。

Page 30: 第九章 指针

数组的指针

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

组的起始地址(首地址),也就是第一个数组元素的地址。

C 语言还规定数组名代表数组的首地址。

Page 31: 第九章 指针

举例

对于整型数组 int a[10]; 数组的指针就是数组的起始地址 &a[0] ,也可以用数组名 a 表示。

Page 32: 第九章 指针

指向数组的指针变量 ( 指向数组元素的指针变量 )

指向数组的指针变量:存放数组元素地址(初始时一般为数组首地址)的变量,称为指向数组的指针变量(简称:数组的指针变量)。

Page 33: 第九章 指针

数组指针变量的定义和初始化

Page 34: 第九章 指针

说明

1 、数组的指针变量的定义与数组元素的指针变量的定义相同。实质就是基类型指针变量的定义。

例如:int a[10],*p; 定义了一个整型数组 a ,如果需要定义指向该数组的指针变量就要定义一个整型指针变量 p 。

Page 35: 第九章 指针

说明2 、数组的指针变量的初始化可以用两种方法:( 1 )定义时初始化,可以使用已经定义的数

组的数组名来初始化数组的指针变量。 ( 2 )通过赋值初始化,将数组的首地址赋值

给数组的指针变量(数组的指针变量的赋值也与一般的指针变量的赋值相同)。

Page 36: 第九章 指针

举例int a[10],*p; 定义了一个整型数组 a ,一个整

型指针变量 p 。p=a; 或者 p=&a[0]; 将数组 a 的首地址赋值给

整型变量 p,此时 p 就是指向数组的指针变量。也可以:

int a[10],*p=a; 在定义数组的指针变量 p 的同时初始化指向已经定义的数组 a 。

Page 37: 第九章 指针

通过指针引用数组元素

1 、指针 p+i 的含义(复习):不是地址值 p增加 i 个字节后的地址值,而是指 p 向后移动 i 个基类型元素后的地址值。 p-i,p++ ,p-- 都有类似的含义。

2 、指针与数组的关系 。

Page 38: 第九章 指针

示意图

Page 39: 第九章 指针

通过指针引用数组元素

两种方法:通过下标(索引)来访问数组元素的,数组元素的访问还可以通过指针完成。

Page 40: 第九章 指针

数组元素的地址表示

假如:p 定义为指向数组 a 的指针。数组元素 a[i] 的地址可以表示为: &a[i],p+i,a+i 。

Page 41: 第九章 指针

数组元素的访问

例如:数组元素 a[i] 的访问可以是: a[i],*(p+i),*(a+i) 。

Page 42: 第九章 指针

数组指针变量,数组名在许多场合甚至可以交换使用

假如:p=a,那么 a[i]甚至可以表示为 p[i] (指针变量带下标)

Page 43: 第九章 指针

注意1 、数组名,数组指针变量使用时的区别:数组名是常量指针,它指向数组首地址,数组指针变量是变量,它的值可以改变。在不至于混淆的场合,数组名,数组指针变量可以统称数组指针。

例如:假设 a 、 b 是数组名, p 是同类型的数组指针变量。

a++; *(a++); a=a+i; a=b; 错误而 p++; *(p++); p=p+i; p=a; 都是可以的。

Page 44: 第九章 指针

数组指针作为函数参数可以分为 4种情况

1 、形参、实参都是数组名。2 、实参是数组名,形参是指针变量 。3 、形参、实参都是指针变量 。4 、实参是指针变量,形参是数组名 。

Page 45: 第九章 指针

指向多维数组的指针和指针变量

多维数组的指针:维数组的地址(首地址)。多维数组的指针变量:

存放多维数组地址的变量。

Page 46: 第九章 指针

二维数组的地址

假设一个二维数组 int S[3][4]。S 数组是一个 3x4 ( 3 行 4列)的二维数组。可以将它想象为一个矩阵(图 1 )。各个数组元素按行存储 , 即先存储 s[0] 行各个元素( s[0][0],...s[0][3] ),再存储 s[1] 行各个元素 (s[1][0],...s[1][3]) ,最后存储 s[2] 行各个元素 (s[2][0],...s[2][3]) 。

Page 47: 第九章 指针

指向多维数组的指针变量

Page 48: 第九章 指针

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

定义格式:基类型 (*p)[m];说明:指定 p 是一个指针变量,它指向包含m

个元素的一维数组。 () 不能省略,否则表示指针数组。

例如:int s[3][4]; int (*p)[4]; p=s;

Page 49: 第九章 指针

字符串的表示形式

1 、字符数组。

2 、字符指。

Page 50: 第九章 指针

字符数组

将字符串的各个字符(包括结尾标志‘ \0’)依次存放到字符数组中,利用数组名或下标变量对数组进行操作。

Page 51: 第九章 指针

字符数组应用

Page 52: 第九章 指针

字符指针

可以不定义字符数组,直接定义指向字符串的指针变量,利用指针变量对字符串进行操作。

Page 53: 第九章 指针

字符指针的应用

Page 54: 第九章 指针

应用举例

例 10-11 :输入两个字符串,比较是否相等。相等输出yes, 不等输出 no.(P.152)

( 要求使用字符指针处理字符串 ) 。

Page 55: 第九章 指针
Page 56: 第九章 指针

字符串指针作为函数参数

使用字符串(字符数组)指针变量 (实际就是字符指针变量 ) 可以作为函数形参接受来自实参字符串(字符数组)的地址。在函数中改变字符指向的字符串的内容,在主调函数中得到改变了的字符串。

Page 57: 第九章 指针

应用举例

例 10-12 :将输入字符串中的大写字母改为小写字母,然后输出字符串。

Page 58: 第九章 指针
Page 59: 第九章 指针

字符数组和字符指针的区别

存储方式的区别:字符数组由若干元素组成,每个元素存放一个字符。字符指针存放的是地址(字符数组的首地址),不是将整个字符串放到字符指针变量中。

Page 60: 第九章 指针

字符数组和字符指针的区别赋值方式的区别:

对字符数组只能对各个元素赋值,不能将一个常量字符串赋值给字符数组(字符数组定义例外)。可以将一个常量字符串赋值给字符指针,但含义仅仅是将常量串首地址赋值给字符指针。

例如:不允许: char str[100]; str=”I am a student.”;允许: char *pstr; pstr=”I am a student.”;

Page 61: 第九章 指针

字符数组和字符指针的区别定义方式的区别 :

定义数组后,编译系统分配具体的内存单元(一片连续内存空间),各个单元有确切的地址。定义一个指针变量,编译系统只分配一个 2 字节存储单元,以存放地址值。也就是说字符指针变量可以指向一个字符型数据(字符变量或字符数组),但是在对它赋以具体地址前,它的值是随机的(不知道它指向的是什么)。所以字符指针必须初始化才能使用。

Page 62: 第九章 指针

字符数组和字符指针的区别

运算方面的区别 :指针变量的值允许改变( ++ , -- ,赋值等),而字符数组的数组名是常量地址,不允许改变。

Page 63: 第九章 指针

指向函数的指针变量 函数的指针:

函数的入口地址(函数的首地址)。 C 语言规定函数的首地址就是函数名,所以函数名就是函数的指针。

指向函数的指针变量:存放函数入口地址(函数指针)的变量,称为指向函数的指针变量。简称函数的指针变量。函数可以通过函数名调用,也可以通过函数指针调用。

Page 64: 第九章 指针

通过函数指针实现函数调用的步骤

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

2 、指向函数的指针变量的赋值,指向某个函数: 函数指针变量名 = 函数名;

3 、利用指向函数的指针变量调用函数:( * 函数指针变量名)(实参表)。

Page 65: 第九章 指针

应用举例

例 10-14 :输入 10 个数,求其中的最大值。

Page 66: 第九章 指针

一般做法

Page 67: 第九章 指针

使用函数指针变量调用函数

Page 68: 第九章 指针

说明

1 、定义函数指针变量时,两组括号()都不能少。如果少了前面的一组括号 =>返回值类型 * 函数名 () ; -返回值为地址值(指针)的函数。

2 、函数指针变量的类型是被指向的函数的类型,即返回值类型。

Page 69: 第九章 指针

说明3 、函数指针的赋值,只要给出函数名,不必

给出参数。(不要给出实参或形参)。 4 、用指针变量调用函数时, (* 函数指针 )代替函数名。参数表与使用函数名调用函数一样。

5 、可以看出,定义的函数指针变量可以用于一类函数,只要这些函数返回值类型(函数类型)相同。

Page 70: 第九章 指针

用指向函数的指针作为函数的参数(常用于编制“通用”的函数)

函数的参数除了可以是变量、指向变量的指针,数组(实际是指向数组的指针)、指向数组的指针以外,还可以是函数的指针。

函数的指针可以作为函数参数,在函数调用时可以将某个函数的首地址传递给被调用的函数,使这个被传递的函数在被调用的函数中调用(看上去好象是将函数传递给一个函数)。函数指针的使用在有些情况下可以增加函数的通用性,特别是在可能调用的函数可变的情况下。

Page 71: 第九章 指针

应用举例

例 10-15 :编制一个对两个整数 a,b 的通用处理函数 process ,要求根据调用 process 时指出的处理方法计算 a , b 两数中的大数、小数、和。

Page 72: 第九章 指针
Page 73: 第九章 指针

结果

Page 74: 第九章 指针

返回指针值的函数 函数可以返回整型、实型、字符型等类型的数据,还

可以返回地址值 - 即返回指针值。返回指针值的函数定义:类型名 * 函数名(参数表)例如: int *fun(int x,int y)

表示 func 是返回整型指针的函数,返回的指针值指向一个整型数据。该函数还包含两个整型参数 x,y 。

Page 75: 第九章 指针

应用举例

例 10-16 :返回两个数中大数地址的函数。

Page 76: 第九章 指针
Page 77: 第九章 指针

指针数组

指针数组:一个数组,如果其数组元素均为指针,那么此数组为指针数组。

一维指针数组的定义:类型名 * 数组名 [数组长度 ]

Page 78: 第九章 指针

数组的指针

数组的指针:指向数组元素的指针。数组元素可以是一般数据类型,也可以是数组、结构体等数据类型。数组指针的定义与数组元素指针的定义相同。

Page 79: 第九章 指针

举例例如: int *p[4];定义一个 4 个元素的数组 p ,其中每个元素是一个整

型指针,也即数组 p 是一个 4 元素整型指针数组。又如: char *p[4];

定义一个 4 个元素的字符指针数组 p ,其中每个数组元素是一个字符指针,可以指向一个字符串。也就是说利用此字符指针数组可以指向 4 个字符串。

Page 80: 第九章 指针

指针的指针

指针的指针:指向指针变量的指针变量。指针的指针存放的是指针变量地址。

Page 81: 第九章 指针

举例int i=2; /* 定义整型变量 i */int *p1,**p2; /* 定义 p1 为整型指针,定义 p2 为整

型指针的指针 */p1=&i; /* i 的地址 =>p1 ,即,指针 p1 指向变量 i */p2=&p1; /* 指针 p1 的地址 =>p2 ,即,指针 p2 指向

指针 p1 */对变量 i 的访问可以是 i,*p1,又因为 *p2=p1 ,即,**p2=*p1 ,所以对变量 i 的访问可以是 i,*p1,**p2 。

Page 82: 第九章 指针

指向指针的指针变量的应用

Page 83: 第九章 指针

指针运算举例

例 10-20 :编写函数 length(char *s) ,函数返回指针 s所指字符串的长度。 P164.

Page 84: 第九章 指针