第九章 指针
DESCRIPTION
第九章 指针. 本章主要任务: 1 、指针的基本概念,变量访问方式; 2 、指针变量定义、赋值、引用。 3 、指针作为函数参数。 4 、数组的指针及指向数组(或数组元素)指针变量。 5 、指向数组的指针作为函数参数。. 内存. - PowerPoint PPT PresentationTRANSCRIPT
第九章 指针本章主要任务:
1 、指针的基本概念,变量访问方式; 2 、指针变量定义、赋值、引用。3 、指针作为函数参数。 4 、数组的指针及指向数组(或数组元素)指针变量。5 、指向数组的指针作为函数参数。
内存内存(内部存储器):是由大规模集成电路芯片组成存储器,包括 RAM 、 ROM 。运行中的程序和数据都是存放在内存中的。与内存相对的是外存,外存是辅助存储器(包括软盘、硬盘、光盘),一般用于保存永久的数据。一定要记住:程序、数据是在内存中由 CPU 来执行和处理的。外存上尽管可以保存程序和数据,但是当这些数据在没有调入内存之前,是不能由 CPU 来执行和处理的。
内存地址内存地址:内存是由内存单元(一般称为字
节)构成的一片连续的存储空间,每个内存单元都有一个编号。内存单元的编号就是内存地址,简称地址。
CPU是通过内存地址来访问内存,进行数据存取(读 /写)。
示意图
变量、变量名、变量的地址、变量值
变量:命名的内存空间。变量在内存中占有一定空间,用于存放各种类型的数据。
变量名:变量名是给内存空间取的一个容易记忆的名字。
变量的地址:变量所使用的内存空间的地址。
变量值:在变量的地址所对应的内存空间中存放的数值
即为变量的值或变量的内容。
示意图
指针、变量的指针
指针:就是 “内存单元的地址”。指针指向一个内存单元。
变量的指针:就是“变量的地址”。变量的指针指向一个变量对应的内存单元。
指针变量指针变量:
就是地址变量。地址(指针)也是数据,可以保存在一个变量中。保存地址(指针)数据的变量称为指针变量。 指针变量 p 中的值是一个地址值,可以说指针变量p 指向这个地址。如果这个地址是一个变量 i 的地址,则称指针变量 p 指向变量 i 。指针变量 p 指向的地址也可能仅仅是一个内存地址。
示意图
说明
1 、牢记:指针 - 地址。指针变量 - 地址变量。
2 、指针变量是变量,它也有地址,指针变量的地址 - 指针变量的指针(指针的指针)。
系统访问变量的两种方式(变量的存取方式)
1 、直接访问:按地址存取内存的方式称为“直接访问” 。
2 、间接访问(使用指针变量访问变量) 。
直接访问1) 按变量名直接访问 , 按变量地址直接访问。 如: a
=3; *(&a)=3; 从系统的角度看不管是按变量名访问变量,还是按变量地址访问变量 , 本质上都是对地址的直接访问。用变量名对变量的访问属于直接访问,因为编译后,变量名 - 变量地址之间有对应关系,对变量名的访问系统自动转化为利用变量地址对变量的访问。
直接访问2 )按地址直接访问(访问内存存储空间) -
一般不要这么使用,这里仅为了说明概念。如: *((int *)(2008))=5; 在地址 2008 保存一个
整数。farptr=(char far *)0xA0000000; *(farptr+offs+i1*MAXB)=*farbit; 操作显示内存。
间接访问(使用指针变量访问变量)
将变量 a 的地址(指针)存放在指针变量 p 中,p 中的内容就是变量 a 的地址,也就是 p 指向 a ,然后利用指针变量 p 进行变量 a 的访问。
p=&a, *p=3 。 从变量名获得变量地址用“ &” 运算符,从地址获得地址指向的数据用“ *” 运算符。
示意图
指针变量的定义
定义格式 :基类型 * 变量名;
说明 1 、 C 语言变量先定义后使用,指针变量也不例外,
为了表示指针变量是存放地址的特殊变量,定义变量时在变量名前加“ *” 号。
2 、指针变量存放地址值, PC 机用 2 个字节表示一个地址,所以指针变量无论什么类型,其本身在内存中占用的空间是 2 个字节。 sizeof(pt1)=sizeof(f)=sizeof(pc)=2 。
说明
3 、指针变量的基类型(简称:指针变量类型):指针变量所指向数据的类型。我们知道,整型数据占用 2 个字节,浮点数据占用4 个字节,字符数据占用 1 个字节。指针变量类型使得指针变量的某些操作具有特殊的含义。比如, pt1++; 不是将地址值增 1 ,而是表示将地址值 +2 (指向后面一个整数)。
指针变量的赋值方法
1 、方法一:将地址直接赋值给指针变量(指针变量指向该地址代表的内存空间) 。
2 、方法二:将变量的地址赋值给指针变量(指针变量指向该变量) 。
方法一将地址直接赋值给指针变量(指针变量指向该地址代表的内存空间) 。
例如:char far *farptr=(char far *)0xA0000000; 将显存首
地址赋值给指针。float *f=(float *)malloc(4); malloc 动态分配了 4 个字节的连续空间,返回空间首地址,然后将首地址赋值给浮点型指针 f 。这样浮点型指针 f 指向这个连续空间的第一个字节。
方法二
将变量的地址赋值给指针变量(指针变量指向该变量) 。
例如:int i,*p; p=&i;
指针变量的引用
& 运算符(取地址运算符):表示取变量的地址。
* 运算符(指针运算符、间接访问运算符):访问指针变量指向的变量的值。
应用举例
指针变量作为函数的参数
指针变量作为函数参数时,同样是从实参单向传递指针变量的内容给形参,只是传递的内容是一个地址值。可以通过这个地址值间接改变实参、形参所共同指向的变量。所以尽管不能改变实际参数地址本身,但是可以间接改变地址所指向的变量。
应用举例
例 10-2 :输入 a,b ;交换 a,b 数据后输出。
正确解法
变量传递示意图
说明
1 、将主调函数变量的地址传递给被调用函数,就是说函数应当传递的是变量的地址。这样被调用函数的形参应当使用指针变量接受主调函数的地址值。
说明
2 、在被调用函数中通过形参指针变量间接访问,修改实参、形参地址所共同指向的变量。本例的操作是交换两个指针变量所指向的变量。
数组的指针
数组的指针:就是数组的地址。数组的地址指的是数
组的起始地址(首地址),也就是第一个数组元素的地址。
C 语言还规定数组名代表数组的首地址。
举例
对于整型数组 int a[10]; 数组的指针就是数组的起始地址 &a[0] ,也可以用数组名 a 表示。
指向数组的指针变量 ( 指向数组元素的指针变量 )
指向数组的指针变量:存放数组元素地址(初始时一般为数组首地址)的变量,称为指向数组的指针变量(简称:数组的指针变量)。
数组指针变量的定义和初始化
说明
1 、数组的指针变量的定义与数组元素的指针变量的定义相同。实质就是基类型指针变量的定义。
例如:int a[10],*p; 定义了一个整型数组 a ,如果需要定义指向该数组的指针变量就要定义一个整型指针变量 p 。
说明2 、数组的指针变量的初始化可以用两种方法:( 1 )定义时初始化,可以使用已经定义的数
组的数组名来初始化数组的指针变量。 ( 2 )通过赋值初始化,将数组的首地址赋值
给数组的指针变量(数组的指针变量的赋值也与一般的指针变量的赋值相同)。
举例int a[10],*p; 定义了一个整型数组 a ,一个整
型指针变量 p 。p=a; 或者 p=&a[0]; 将数组 a 的首地址赋值给
整型变量 p,此时 p 就是指向数组的指针变量。也可以:
int a[10],*p=a; 在定义数组的指针变量 p 的同时初始化指向已经定义的数组 a 。
通过指针引用数组元素
1 、指针 p+i 的含义(复习):不是地址值 p增加 i 个字节后的地址值,而是指 p 向后移动 i 个基类型元素后的地址值。 p-i,p++ ,p-- 都有类似的含义。
2 、指针与数组的关系 。
示意图
通过指针引用数组元素
两种方法:通过下标(索引)来访问数组元素的,数组元素的访问还可以通过指针完成。
数组元素的地址表示
假如:p 定义为指向数组 a 的指针。数组元素 a[i] 的地址可以表示为: &a[i],p+i,a+i 。
数组元素的访问
例如:数组元素 a[i] 的访问可以是: a[i],*(p+i),*(a+i) 。
数组指针变量,数组名在许多场合甚至可以交换使用
假如:p=a,那么 a[i]甚至可以表示为 p[i] (指针变量带下标)
注意1 、数组名,数组指针变量使用时的区别:数组名是常量指针,它指向数组首地址,数组指针变量是变量,它的值可以改变。在不至于混淆的场合,数组名,数组指针变量可以统称数组指针。
例如:假设 a 、 b 是数组名, p 是同类型的数组指针变量。
a++; *(a++); a=a+i; a=b; 错误而 p++; *(p++); p=p+i; p=a; 都是可以的。
数组指针作为函数参数可以分为 4种情况
1 、形参、实参都是数组名。2 、实参是数组名,形参是指针变量 。3 、形参、实参都是指针变量 。4 、实参是指针变量,形参是数组名 。
指向多维数组的指针和指针变量
多维数组的指针:维数组的地址(首地址)。多维数组的指针变量:
存放多维数组地址的变量。
二维数组的地址
假设一个二维数组 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]) 。
指向多维数组的指针变量
指向由 m 个元素组成的一维数组的指针变量
定义格式:基类型 (*p)[m];说明:指定 p 是一个指针变量,它指向包含m
个元素的一维数组。 () 不能省略,否则表示指针数组。
例如:int s[3][4]; int (*p)[4]; p=s;
字符串的表示形式
1 、字符数组。
2 、字符指。
字符数组
将字符串的各个字符(包括结尾标志‘ \0’)依次存放到字符数组中,利用数组名或下标变量对数组进行操作。
字符数组应用
字符指针
可以不定义字符数组,直接定义指向字符串的指针变量,利用指针变量对字符串进行操作。
字符指针的应用
应用举例
例 10-11 :输入两个字符串,比较是否相等。相等输出yes, 不等输出 no.(P.152)
( 要求使用字符指针处理字符串 ) 。
字符串指针作为函数参数
使用字符串(字符数组)指针变量 (实际就是字符指针变量 ) 可以作为函数形参接受来自实参字符串(字符数组)的地址。在函数中改变字符指向的字符串的内容,在主调函数中得到改变了的字符串。
应用举例
例 10-12 :将输入字符串中的大写字母改为小写字母,然后输出字符串。
字符数组和字符指针的区别
存储方式的区别:字符数组由若干元素组成,每个元素存放一个字符。字符指针存放的是地址(字符数组的首地址),不是将整个字符串放到字符指针变量中。
字符数组和字符指针的区别赋值方式的区别:
对字符数组只能对各个元素赋值,不能将一个常量字符串赋值给字符数组(字符数组定义例外)。可以将一个常量字符串赋值给字符指针,但含义仅仅是将常量串首地址赋值给字符指针。
例如:不允许: char str[100]; str=”I am a student.”;允许: char *pstr; pstr=”I am a student.”;
字符数组和字符指针的区别定义方式的区别 :
定义数组后,编译系统分配具体的内存单元(一片连续内存空间),各个单元有确切的地址。定义一个指针变量,编译系统只分配一个 2 字节存储单元,以存放地址值。也就是说字符指针变量可以指向一个字符型数据(字符变量或字符数组),但是在对它赋以具体地址前,它的值是随机的(不知道它指向的是什么)。所以字符指针必须初始化才能使用。
字符数组和字符指针的区别
运算方面的区别 :指针变量的值允许改变( ++ , -- ,赋值等),而字符数组的数组名是常量地址,不允许改变。
指向函数的指针变量 函数的指针:
函数的入口地址(函数的首地址)。 C 语言规定函数的首地址就是函数名,所以函数名就是函数的指针。
指向函数的指针变量:存放函数入口地址(函数指针)的变量,称为指向函数的指针变量。简称函数的指针变量。函数可以通过函数名调用,也可以通过函数指针调用。
通过函数指针实现函数调用的步骤
1 、指向函数的指针变量的定义: 类型 ( * 函数指针变量名) () ;
2 、指向函数的指针变量的赋值,指向某个函数: 函数指针变量名 = 函数名;
3 、利用指向函数的指针变量调用函数:( * 函数指针变量名)(实参表)。
应用举例
例 10-14 :输入 10 个数,求其中的最大值。
一般做法
使用函数指针变量调用函数
说明
1 、定义函数指针变量时,两组括号()都不能少。如果少了前面的一组括号 =>返回值类型 * 函数名 () ; -返回值为地址值(指针)的函数。
2 、函数指针变量的类型是被指向的函数的类型,即返回值类型。
说明3 、函数指针的赋值,只要给出函数名,不必
给出参数。(不要给出实参或形参)。 4 、用指针变量调用函数时, (* 函数指针 )代替函数名。参数表与使用函数名调用函数一样。
5 、可以看出,定义的函数指针变量可以用于一类函数,只要这些函数返回值类型(函数类型)相同。
用指向函数的指针作为函数的参数(常用于编制“通用”的函数)
函数的参数除了可以是变量、指向变量的指针,数组(实际是指向数组的指针)、指向数组的指针以外,还可以是函数的指针。
函数的指针可以作为函数参数,在函数调用时可以将某个函数的首地址传递给被调用的函数,使这个被传递的函数在被调用的函数中调用(看上去好象是将函数传递给一个函数)。函数指针的使用在有些情况下可以增加函数的通用性,特别是在可能调用的函数可变的情况下。
应用举例
例 10-15 :编制一个对两个整数 a,b 的通用处理函数 process ,要求根据调用 process 时指出的处理方法计算 a , b 两数中的大数、小数、和。
结果
返回指针值的函数 函数可以返回整型、实型、字符型等类型的数据,还
可以返回地址值 - 即返回指针值。返回指针值的函数定义:类型名 * 函数名(参数表)例如: int *fun(int x,int y)
表示 func 是返回整型指针的函数,返回的指针值指向一个整型数据。该函数还包含两个整型参数 x,y 。
应用举例
例 10-16 :返回两个数中大数地址的函数。
指针数组
指针数组:一个数组,如果其数组元素均为指针,那么此数组为指针数组。
一维指针数组的定义:类型名 * 数组名 [数组长度 ]
数组的指针
数组的指针:指向数组元素的指针。数组元素可以是一般数据类型,也可以是数组、结构体等数据类型。数组指针的定义与数组元素指针的定义相同。
举例例如: int *p[4];定义一个 4 个元素的数组 p ,其中每个元素是一个整
型指针,也即数组 p 是一个 4 元素整型指针数组。又如: char *p[4];
定义一个 4 个元素的字符指针数组 p ,其中每个数组元素是一个字符指针,可以指向一个字符串。也就是说利用此字符指针数组可以指向 4 个字符串。
指针的指针
指针的指针:指向指针变量的指针变量。指针的指针存放的是指针变量地址。
举例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 。
指向指针的指针变量的应用
指针运算举例
例 10-20 :编写函数 length(char *s) ,函数返回指针 s所指字符串的长度。 P164.