关关雎鸠 南邮 C语言课件 第5章_第1页
关关雎鸠 南邮 C语言课件 第5章_第2页
关关雎鸠 南邮 C语言课件 第5章_第3页
关关雎鸠 南邮 C语言课件 第5章_第4页
关关雎鸠 南邮 C语言课件 第5章_第5页
已阅读5页,还剩33页未读 继续免费阅读

付费下载

下载本文档

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

文档简介

1、高级语言程序设计 2022/8/151第五章 一级指针与一维数组主讲: 计算机学院 朱立华内容提要直接引用与间接引用的不同方式及实质指针是地址的类型,是对地址进行的一种类型抽象,用来实现间接访问,掌握以下指针的知识指针类型与指针的基类型指针的基本操作:间接引用、加减整数、逻辑及关系运算指针与一维数组的关系,如何用指针操作一维数组一维数组专用于一批类型相同的变量的处理一维数组的定义及初始化,一维数组的基类型(数组的元素类型)与指针基类型的一致性,一维数组名就是指针常量访问一维数组元素的方式间接引用方式,可随机访问一维数组元素在内存中的存储方式,可随机访问元素的实质一维数组中的常见操作及算法:输入

2、、输出、逆置、查找、插入、删除、排序2022/8/153间接引用的必要性内容回顾:int m; 表示定义一个变量,m是变量名,即变量空间名,直接用m访问的是变量空间中的内容,称为直接引用一个算法问题:输入10000个整数并求平均值,并且保留这些原始数据到最后统一输出解决方案:将这10000个整数看作逻辑上前后相邻的并且可以存储在内存中一片连续的区域,只要知道这些数在内存中的起始地址,就能找到对应的空间,进而访问空间中的内容,这就是间接引用方式,因此:要有变量可以存放地址-指针;要有类型可以定义一个标识符代表一组连续空间的起始地址-一维数组用第4章的循环可以求解,定义1个变量,在循环体中读入值并

3、求和用1个变量不能达到这一要求,根据前面的知识,似乎应该定义10000个变量,可是这样又无法用循环控制间接引用方式下,传递某一个数据地址(一般是第1个数据的地址)相当于传递了全部数据 2022/8/154一级指针类型(引言) C语言优越于其他高级语言的一个特性就是:可对硬件编程;通过第一章机器语言程序设计的学习,在计算机内部访问操作数首先是读取其在内存中的存储地址值,然后通过该地址值去访问该地址所在空间中的内容C语言为了实现对硬件编程,必定要将内存地址抽象为一种类型,这就是(一级)指针类型,即指针类型是地址的类型,该类型的常量和变量值都是内存地址值。地址值是无符号整数,无论该地址的内存中数据是

4、什么类型,地址值都占4个字节显然,知道地址值是为了操作这个地址中所存储的内容。通过地址来访问数据空间的方式称为间接引用通过该地址去间接引用的数据类型称为地址的基类型前面学习的通过存储空间的名称引用数据的方式称为直接引用这两种类型有区别也有联系2022/8/155一级指针类型(概述)直接引用与间接引用:在C语言源程序中的直接引用方式经编译后在计算机内部实质上是间接引用,例如源程序中有下列代码: int n,m;/定义2个整型变量,n和m是变量名double x;/定义1个双浮点型变量,x是变量名表n=5;/直接引用,给n赋值5m=n;/直接引用,将n中的值赋给mx=3.1415;/直接引用,给x

5、赋值3.1415 经编译后,变量名消失,留下其地址及类型信息,如下表:变量名变量值地址类型x3.14150 x12ff70doublem50 x12ff78intn50 x12ff7cint源程序中目标程序中地址的基类型到哪里访问数据指示编译器怎样操作特定地址上的内存区域:该区域包含多少连续的字节,数据存储的格式,以及可以实施哪些基本操作 2022/8/156一级指针类型(概述)C语言中,用一级指针类型作为地址的类型。地址关联着两个存储空间,存放着两种不同的值,彼此又有紧密的联系,以上页表中地址0 x12ff78为例如下: (int*) 0 x12ff78m0 x12ff78 5整型变量m的空

6、间,此为变量空间编译后指向m的地址值,是指针常量值因此,一级指针类型是复合类型,由指针的基类型名称加”*” 共同组成,例:int * -整型指针类型,即指针所指向的空间存int值double * -双浮点型指针类型指针字面值常量,即指针常量空间的名称2022/8/157一级指针类型(用*间接引用)利用指针去访问它指向的基类型的空间分两步:(1)通过指针字面值常量取出基类型空间的地址,这是直接引用 (2)加间接引用运算符“*”,得到与基类型空间名称等价的表达式,称为间接引用表达式,这是间接引用(int*) 0 x12ff78m0 x12ff78 5因此,*(int*)0 x12ff78与m完全等

7、价,m=5;也可以写成: *(int*)0 x12ff78=5;上机在VC+下演示程序5.1总结:间接引用运算符*使得指针可以访问其基类型空间动态演示过程2022/8/158一级指针类型(基本操作)指针的基本操作加减一个整数(1) 指针加一个整数i,是将当前地址值加上i*sizeof(基类型)(2) 指针减一个整数i,是将当前地址值减去i*sizeof(基类型)总结:理论上,指针可以加减任何整数,但必须保证结果指针指向应用程序的数据空间,否则不能间接访问指针字面值常量地址值基类型值(int*)0 x12ff000 x12ff00 5(int*)0 x12ff040 x12ff04 6(int*

8、)0 x12ff080 x12ff08 7(int*)0 x12ff0c0 x12ff0c 8(int*)0 x12ff100 x12ff10 9(int*)0 x12ff00+2=(int*)0 x12ff08 (int*)0 x12ff10-3=(int*)0 x12ff04 sizeof(int)=4(int*)0 x12ff10+2=(int*)0 x12ff18, 地址0 x12ff18所指向的空间不是本程序的数据空间,无意义!动态演示过程2022/8/159一级指针类型(基本操作)指针的其它基本操作:(1) 指针可以进行逻辑运算,例:!(int*)0 x12ff00的结果为0(2)

9、 指针可以进行关系运算,例:(int*)0 x12ff00(int*)0 x12ff08 的结果为1(真)(3)两个类型相同的指针(即基类型相同的指针)可以相减,地址大的减地址小的,结果为两个地址间区域所含基类型数据个数。 指针字面值常量地址值基类型值(int*)0 x12ff000 x12ff00 5(int*)0 x12ff040 x12ff04 6(int*)0 x12ff080 x12ff08 7(int*)0 x12ff0c0 x12ff0c 8(int*)0 x12ff100 x12ff10 9(int*)0 x12ff0c- (int*)0 x12ff04=2 2022/8/15

10、10将物理上前后相邻、类型相同的一组变量作为一个整体引入C语言,这个整体称为(一维)数组类型的变量,简称(一维)数组,其中每一个变量称为数组元素,变量的个数称为数组长度或数组容量。 引入数组的目的:利用间接引用方式,访问一组数据。具体地说,从第一个数组元素的地址,计算出其他所有数组元素的地址,然后通过数组元素的地址,间接访问数组元素。定义一个数组:需要:(1)指定数组名,这个名称代表着第一个数组元素的指针,是一个指针常量,等价于一个指针字面值常量,称为数组指针(2)指定数组元素的类型,它是数组指针的基类型,是间接引用方式的基础(3)指定数组长度,即数组包含的元素个数,它决定了数组指针在进行加减

11、整数的算术运算时的有效范围一维数组类型(概述)2022/8/1511一维数组类型(数组定义)数组的定义格式为: 类型标识符 一维数组名整型常量表达式; 例:int a5;类型标识符是数组元素的类型(也称为数组的基类型)的标识 是1个合法的用户自定义标识符,代表整个数组空间的起始地址(第1个元素的地址),是1个指针常量 表示数组的长度,即数组元素的个数,必须用一个常量表达式而不能用变量 元素地址元素值元素名1元素名2a?*aa0a+1?*(a+1)a1a+2?*(a+2)a2a+3?*(a+3)a3a+4?*(a+4)a4间接引用表达式下标(索引)表达式注意:数组元素的下标从0开始,可以是整型常

12、量或变量,需要保证范围在0整型常量表达式-1,否则越界2022/8/1512一维数组类型(数组定义)表5.2 数组元素及元素地址的表示(数组定义:int a5;)表示 意义 等价表示 a 数组第一个元素的地址,是指针常量&a0a+i(0i4) 第i+1个元素的地址,是指针常量表达式,不可被修改 &ai &ai(0i4)a+i *(a+i)(0i4)第i+1个元素的间接引用表达,是基类型的变量 ai ai(0i4)第i+1个元素的下标(索引)表达,是基类型的变量 *(a+i) 总结:一维数组元素的地址有两种等价表示:a+i= =&ai;一维数组元素有两种等价表示:*(a+i)= ai2022/8

13、/1513一维数组的初始化:在定义数组时为其全部或部分元素指定初值。一维数组的初始化的形式: 类型标识符 一维数组名整型常量表达式=常量1 ,常量2,常量n; 正确的初始化示例:int a5=1,2,3,4,5; int a =1,2,3,4,5; int a5=1,2*4; 错误的初始化示例: int a5=,2,3 ; int a5=1,2,3,4,5,6,7; 一维数组类型(初始化)所有元素都有初值,a0至a4的值依次为1,2,3,4,5相当于a5=1,2,3,4,5;当所有元素都有初值时,数组元素个数可缺省,自动等于初值个数相当于a5=1,8,0,0,0;可以只对数组的前几个元素赋初值

14、,其余元素的初值自动为0。注意!当不做初始化时所有数组元素的值均为随机数而不是0对数组元素初始化时只能从左到右依次,只能缺省最右边的元素值初值个数不能超过数组元素的个数2022/8/1514一维数组定义(包括初始化)结束之后,只能对其元素进行访问,而不能对数组整体访问错误的数组赋值示例: (1) int a5; a5=1,2,3,4,5; (2) int a5; a=1,2,3,4,5; (3) int a5=1,2,3,4,5; int b5=a; b=a; 正确做法可以是: b0=a0; b1=a1;b2=a2;b3=a3;b4=a4;最简洁通用的方法是:(设已有变量定义:int i;)

15、for (i=0;i5;i+) bi=ai;一维数组类型(赋值)错误原因:a5是对某个数组元素的引用,而长度为5的数组没有a5这个元素,不能用一组值给一个元素赋值错误原因:数组名a在赋值语句中是指向第1个数组元素的指针常量&a0,常量不是左值,不能被赋值。 错误原因:一个数组不能给另一个数组初始化 错误原因:一个数组不能给另一个数组整体赋值 2022/8/1515程序5.2 编程定义并初始化一维数组,显示一维整型数组所有元素的值及对应地址,并对数组的所有元素求和 思路:(1)首先需要定义并初始化数组(假设数组名为a),根据题意,还需要定义循环控制变量和累加器变量(2)然后分别用一层循环输出所有

16、的元素值、地址值(3)再用一层循环求所有元素之和,最后输出和值程序5.3从键盘上输入n(1n10)个整数,输出这些元素,再分别统计其中正数和负数的个数,并求出最大值与最小值 思路:一维数组类型(举例)元素值有两种等价表示:ai和*(a+i)元素地址有两种等价表示:&ai和a+i(1)首先需要定义数组以存储n个整数,再用一层循环输出元素值(2)然后分别用一层循环作统计、找最大最小值(3)最后输出结果动态演示过程2022/8/1516程序5.3:源程序代码 #include int main() int a10,i,n; int max,min; int positive=0,negative=0

17、; do printf(Please input n(1=n=10):n); scanf(%d,&n); while (n10); printf(Please input %d elements:n,n); for (i=0;in;i+) scanf(%d,&ai); printf(The elements are:n); for (i=0;in;i+) printf(%5d,ai); printf(n);保证读入的n在1至10之间读入数组的前n个元素输出数组的元素2022/8/1517程序5.3:源程序代码 for (i=0;i0) positive+; else if (ai0) nega

18、tive+ ; max=min=a0 ; for (i=1;imax) max=*(a+i); else if (*(a+i)m是一个整型变量的变量名,代表整型变量空间,m的类型标识为int同理:int a5; -a是一个数组变量的变量名,代表整个数组空间,a的类型标识为int5因此,数组名a有双重含义:(1)是一个数组变量的变量名,代表整个数组空间,在&a,sizeof(a)中体现该含义,但是数组变量不能通过其名称直接引用数组元素,因此数组名称“退化”了 (2)是指向第一个数组元素的指针常量,所有元素的地址可根据该常量的地址值计算求得,从而方便实现间接访问数组的元素程序5.4 设计程序验证d

19、与&d的区别,重点关注d+1与&d+1的不同 (选讲)一维数组名的双重含义动态演示过程2022/8/1519(选讲)一维数组名的双重含义名称意义类型基类型运算或关系数组元素d0d4 类型相同的变量 double无实型变量运算、取址运算& 数组指针d 指向第一个数组元素的指针常量 double*doubled=&d0, d+i=&di, *(d+i)=di (i=04) 数组空间名称d 数组变量(空间)的标识符 double5无sizeof(d)=5*8=40, &d 数组空间取址&d 整个数组空间的首地址 double*5double5+、-、间接引用* &d与数组指针d的值虽然相等,但是d的

20、类型是double*,基类型是数组元素类型double;而&d的类型是double(*)5,基类型是double5。执行d+1,地址增加8,执行&d+1,地址增减40。 数组名具体代表什么意思,要依赖上下文而定,如下表: 2022/8/1520引入数组的目的:传递数组首元素地址,相当于传递整个数组空间所有元素的值。数组首元素地址可以传给?基类型相同的指针变量指针变量的定义:回顾: 整数类型 int - 整型变量 int x;同理:基类型为整型的指针类型 int * - 指针变量 int * x;一维数组名是指针常量,当然可以将值 赋给基类型相同的指针变量,使指针变量 和数组指针在间接引用方式下

21、“共享” 同一段数组空间,这相当于把数组空间的 数据传给了指针变量,称为地址传递, 例:int a5; int *p=a; 一级指针变量与一维数组a0a1a2a3a413ff58app0p1p2p3p413ff582022/8/1521当p=a后,有下列等价关系存在:(1)数组元素的表示: 下标法:pi 等价于ai 间接引用法:*(p+i) 等价于*(a+i)(2)数组元素地址的表示: 指针表达式法:p+i等价于a+i 元素取地址法:&pi等价于&ai注意:(1)p是变量,因此它有存储空间可以取地址,即&p是指向p存储空间的指针常量,其基类型为int* (2)p是变量,一般获得数组首元素地址值

22、,也可以获得任意元素的地址值,例:p=&a2 此时:p0等价于a2, p2等价于a2程序5.5:用一级指针访问一维数组元素示例 一级指针变量与一维数组a0a1a2a3a413ff58app0p1p2p3p413ff5813ff60p0p1p2动态演示过程2022/8/1522一级指针变量定义时*的位置:情况1:只定义一个指针变量,此时*位置可以近基类型名、近变量名或居中三者均可例:int *p; int* p; int * p; 情况2:一条定义语句既定义基类型的变量,又定义指针变量,此时,*近指针变量例:int a,*p,b; 情况3:一条定义语句定义多个同类型的指针变量时,每个指针变量前都

23、跟一个*号例:int *p,*q;简单总结: (1)“*”贴近指针变量总是正确的(2)每个指针变量前面都必须有一个“*” 一级指针变量与一维数组近变量名近基类型名居中必须近变量名2022/8/1523关于数组指针的基类型与指针变量基类型的一致性问题目的1:如果传递数组指针的目的是传递数组的值,那么应该将数组指针传递给同类型的指针变量,类型不同时虽然可通过强制类型转换赋值,但无意义例:int a5=10,15,20,25,30; double* pd; pd=(double*)a; float* pf; pf=(float*)a; 目的2:如果传递数组指针的目的在于高效使用内存资源,那么可以通过

24、强制类型转换把该数组空间指针传递给其他类型的指针变量,把用过的数组空间用来存储其他类型的数据。 程序5.6 同一段空间,可用作不同类型的数组空间示例 一级指针变量与一维数组强制类型转换使赋值有效但无意义,因为pd+ia+i且pdi ai 强制类型转换使赋值有效但无意义,因为虽然pf+i=a+i但pfi ai 动态演示过程这样做虽然节省了空间,但是容易引起数据访问的歧义实际编程中这种方法不常用 2022/8/1524一级指针变量与一维数组一个基类型的变量等价于长度为1的数组定义int a4;int n=5;分析的对象a&n对象的性质长度为4的整型数组指针常量长度为1的整型数组指针常量访问第一个元

25、素a0=*(a+0)&n0= =*(&n+0)=*(&n)=n若有int *p;给p的赋值p=a;p=&n;用p间接访问元素p0=*(p+0)=*pp0=*(p+0)=*p,直接用*p结论:int n,*p;则n相当于长度为1的数组&n的唯一元素,赋值给p之后,存在两组等价关系:p=&n; *p=n;但&n为常量,p为变量2022/8/1525一级指针变量与一维数组取址运算&和间接引用运算*互为逆运算二者都是第2优先级的运算符,结合方向为从右向左。需要注意,运算的每一步都要保证有意义。 例:int n,m=5, *p=&m; 则有5组等价关系: (1)p= =&m; (2) *p=m ; (3

26、)&*p=p ; (4) *&p=p (5) *&m=m但是:&*m=m; 却是错误的,因为m不代表地址,所以*m无意义。回顾表5.1的内容:x=*(double*)0 x12ff70 两边同时进行取址运算“&”,再消掉互逆运算符得到: &x=&*(double*)0 x12ff70=(double*)0 x12ff70 最左和最右同时进行间接引用运算“*”,再消掉互逆运算符得到: *&x=*(double*)0 x12ff70=x2022/8/1526一级指针变量与一维数组野指针:是指向”垃圾”内存的指针,有以下几种情况(1)指针变量没有被赋值,它存储的地址是不确定的 例:int *p;*p

27、=100; (2)指针操作超越了变量的作用范围 例:int a3, *p=a; p=p+3; *p=100; (3)一个字面值指针常量,例如(int*)0 x12ff7c,如果其值0 x12ff7c不是系统已经分配给用户程序使用的空间地址。因此一般编程时很少直接使用字面值指针常量进行间接引用(4)利用指针申请的动态空间被释放后,仍用该指针进行间接访问(具体见第6章6.5.3)一个没有赋值的“野”指针用“野”指针间接引用很危险指针获得数组首元素地址指针增加3,出了数组范围间接引用的空间不是程序的有效数据空间2022/8/1527一级指针变量与一维数组void型指针:称为通用指针或泛指针。可以把任

28、何类型变量的地址赋给它,但是不能利用这样的指针做相应类型的访问或处理。例:void *p;int x=5;p=&x; /合法*p=6; /非法printf(%d,*p); /非法void指针主要用于单纯的内存数据的拷贝。在第11章的“流与文件”中,将遇到这样的指针。2022/8/1528一级指针变量与一维数组回顾:当一级指针变量的基类型与一维数组的基类型一致时,可以将一维数组名赋值给指针变量,这时对数组元素的访问既可以用一维数组也可以用指针变量。用一维数组访问数组的元素只能通过改变下标的方式用一级指针变量间接访问一维数组的元素可以通过移动下标(指针不动)或移动指针(指针改变)两种方式程序5.7 分别用移动下标的方法和移动指针的方法实现输出数组的所有元素。在方法1中,pai+实际上先访问pai,再执行i=i+1,当循环结束时,指针pa还是等于a即&a0,pai+也可写成ai+在方法2中,*pa+相当于*(pa+),这里是后+,因此相当于先访问*pa,再执行pa=pa+1,当循环结束时,pa等于a+5。由于a是常量,故*pa+不能写成*a+动态演示过程2022/8/1529一级指针变量与一维数组移动下标与移动指针访问数组的元素例示:程序5.8 调用随机函数产生10个1至100内的整数作为数组的元素,然后再逆置存放,输出初始序列和逆置以后的序列。 问题分析:本题中首先需

温馨提示

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

评论

0/150

提交评论