(计算机基础与C语言程序设计)第章指针课件.ppt
- 【下载声明】
1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
3. 本页资料《(计算机基础与C语言程序设计)第章指针课件.ppt》由用户(ziliao2023)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机 基础 语言程序设计 指针 课件
- 资源描述:
-
1、1 1第9章 指 针9.1 指针和地址指针和地址9.2 指针变量和指针变量的赋值指针变量和指针变量的赋值9.3 指针和函数参数指针和函数参数9.4 指针和数组指针和数组9.5 地址运算地址运算9.6 字符指针和有关函数字符指针和有关函数9.7 指针数组和指向数组的指针指针数组和指向数组的指针9.8 指针与函数指针与函数2 2指针是C语言中非常重要的一种数据类型,在C语言程序设计中被广泛使用。一方面,有时候某些计算必须用指针来表示;另一方面,同一个计算用指针来解决会使编写的程序更高效、更紧凑。指针是C语言学习过程中比较难掌握的内容,尤其对缺乏计算机硬件知识的读者更是如此;指针与数组紧密相关。本章
2、对指针的概念、指针作为函数的参数传递、指针和数组的关系、地址运算、指针和字符串的关系、指针数组和指向数组的指针、指向函数的指针等问题进行讲述。3 3一台计算机有一组连续的、编了号的、可以寻址的内存单元,可以独自对这些内存单元进行操作,或者以连续集合的方式对这些内存单元操作。一种普遍的情形是:char类型的数据占用一个字节单元,对这种类型的数据操作,就是对一个字节单元的操作;9.1 指指针针和和地地址址4 4short int类型的数据占用两个字节单元,对这种类型的数据操作,就是对两个字节单元的操作;而long 类型的数据占用四个相邻字节单元,对这种类型的数据操作,就是对四个字节单元的操作。一个
3、指针是指一组能够保存某种类型变量的地址的存储单元,指针通常占用两个字节或四个字节的内存单元(与系统有关)。5 5图9-1 内存的组织形式6 6假设c是一个char类型的变量,占用一个字节单元,p是一个指针,占用4个存储单元(指针占用多少个存储单元与系统有关,系统不同,会有差别)。根据指针的定义,我们可以用指针p保存字符型变量c的地址,假设变量c对应的内存单元地址是y4y3y2y1H,是4个字节,如果把变量c的地址保存到指针p,我们就说p指向变量c,或者说p是指向变量c的一个指针,如图9-1所示。7 7单目运算符“&”可以求出一个对象的地址,称为求地址运算符。例如:p=&c;该语句的作用是将变量
4、c的地址赋值给指针变量p,p现在就指向变量c。“&”运算符只能用于内存中的对象变量或数组元素,不能用于表达式或者寄存器变量。单目运算符“*”是一个间接访问运算符(也称为指针运算符)。当“*”用于指针上时,表示访问该指针指向的对象。例如:8 8int x=1,y=2;int*ip;/*ip是指向int型变量的指针。*/ip=&x;/*ip现在指向x。*/y=*ip;/*将指针ip指向的变量x的值赋给y,即y现在的值是1。*/*ip=0;/*将值0赋给指针ip指向的变量x,即x现在的值是0。*/注意:“*”运算符出现在指针的定义中和出现在表达式中的语法相似,但含义不同。9 9应当注意,指针是受限于
5、其指向某种对象类型的,即每个指针与指向的某种具体数据类型要一致。不过有一点要注意,void类型的指针比较特殊,void类型的指针赋值将在9.5节中介绍。如果ip是指向整数x的指针,那么*ip可以出现在x能出现的任何位置,也即x=x+10;可以用*ip=*ip+10;来代替。单目运算符“*”和“&”比算术运算符的优先级要高,这样对于下列赋值运算:y=*ip+1;就是将ip指向变量的值加1,再将结果赋给y。1010而语句“*ip+=1;”是将ip指向的变量值加1,然后再赋给那个变量;“+*ip;”语句也可完成同样的运算;“(*ip)+;”语句也可以完成,但注意“()”是必需的,否则,结果将是对ip
6、指针加1后的间接引用,这是因为单目运算符“*”和“+”优先级相同,结合时是自右向左结合的。指针是变量,它们也可以不通过间接引用来使用。例如:iq是另一个指向int型变量的指针,则执行语句“iq=ip;”后,将ip复制到iq,使iq指向ip指向的对象,此时iq和ip指向相同的对象。11119.2.1 指针变量指针变量指针变量用于保存某种类型变量的地址。指针变量的定义形式如下:类型名*指针变量名1,*指针变量名2,;例如:char*p1,*p2;9.2 指针变量和指针变量的赋值指针变量和指针变量的赋值1212该语句定义两个指针变量p1和p2,用星号(*)说明p1和p2是指针,用char来说明类型,
7、p1和p2可以指向char类型的变量,也就是说p1和p2用来保存char类型变量的地址。又如:int*p1,*p2;double*f1;此时,p1、p2是两个指向int类型变量的指针,f1是指向double类型变量的指针,也就是说,p1和p2中保存int类型变量的地址,f1保存double类型变量的地址。再比如:int*p1,*s1,k=20;s1=&k;p1=&s1;1313此时,指针变量p1指向int*类型的变量,而int*类型的变量也是一个指针,这个指针又指向int类型的变量,也就是说,p1是指向int类型指针的指针(p1是一个二级指针)。以上语句使s1指向k,然后使p1指向s1。其中,
8、“&”符号是求地址运算符,通过这个运算符可以获取一个变量的地址。定义指针变量要指出它的类型,用类型来指明它能够保存哪种类型变量的地址,这非常重要。我们在上一节讲到,不同数据类型占用的存储单元字节数不同,我们可以通过指针的加1、减1运算来移动指针,也就是通过修改指针中保存的地址指向下一个对象。1414不同数据类型的对象,要让指针指向下一个对象,所跨越的字节数是不同的,对指针加1、减1,是要求指针指向下一个不同的对象,所以用指针的类型来区分在对指针做运算时如何修改指针中保存的地址(比如,对指针加1、减1运算,char类型实际按照加、减1修改地址,short int类型按照加2、减2修改地址,lon
9、g类型按照加4、减4修改地址等)。类型不同的指针变量不能混合使用。注意:严格来讲,指针和指针变量是有区别的,指针是指已经保存了地址的指针变量,而指针变量是一种变量,它可以被重新赋值。本书中对指针和指针变量没有严格的区分。15159.2.2 指针变量的赋值指针变量的赋值指针变量可以通过不同的方式获得一个确定的地址值,让指针指向一个具体的对象。1.通过求地址运算符通过求地址运算符(&)获取变量的地址值获取变量的地址值&运算符是一个单目运算符,用于求出其操作数的地址,这个操作数可以是某种类型的变量。比如有如下两条语句:int*q,*p,k=1;q=&k;1616第二条语句是把k的地址取出赋给指针q,
10、也就是说q指向k,或者说q指针保存了变量k的地址。求地址运算符&的操作数只能是内存中的对象变量或者数组元素,不能用于register型的变量、常量以及表达式等,所以,q=&9,q=&(k+2)都是错误的。求地址运算符&的操作数的类型必须和指针的类型相同。标准输入函数scanf()函数要求输入项必须是地址值,所以当有语句q=&k;时,scanf(%d,&k)和scnaf(%d,q)是等价的,因为q中保存的是变量k的地址值。17172.通过指针变量获取地址值通过指针变量获取地址值可以通过把一个指针变量赋给另外一个相同类型的指针变量来实现指针赋值,赋值后这两个指针指向同一个对象。如:int*q,*p
11、,k=1;q=&k;p=q;上述语句就使指针变量p和q指向同一个变量k,即p和q中保存的都是k的地址。18183.通过标准函数获得地址值通过标准函数获得地址值C语言提供了两个标准函数,分别为malloc()和calloc(),这两个函数用于在内存中开辟动态存储空间,这两个函数返回地址值。有关如何使用malloc()和calloc()函数的内容,我们在后续章节中介绍。19194.给指针变量赋一个空给指针变量赋一个空(NULL)值值前面我们看到,指针变量可以间接地赋地址值,我们也可以给指针变量直接赋一个常量NULL值。除此之外,标准语言不允许给指针直接赋一个整数,例如:p=NULL;/*是合法的。
12、*/p=1234;/*是不合法的。编译时会出现警告错误。*/NULL是一个预定义的符号,它的定义在头文件“stdio.h”中。一个指针被赋值NULL,我们称该指针为空指针。空指针是无效指针,不能通过无效指针间接引用。2020在C语言中,一个调用函数(调用者)通过传值调用另一个被调用函数(被调用者),在被调用函数中对形参的修改,对调用函数的实参不起作用。例如:在排序子程序中可能要通过调用swap函数交换两个不符合顺序的参数(实参)a和b,调用语句为swap(a,b);swap()函数的定义如下:void swap(int x,int y)/*交换x和y的值*/9.3 指针和函数参数指针和函数参数
13、2121 int temp;temp=x;x=y;y=temp;假设在排序子程序中,通过传值调用去调用该swap函数,swap函数并没有影响排序子程序中a和b的值,swap函数中只是对a和b的一份拷贝(x和y)进行了操作。为了取得期望的效果,可以给调用函数传递地址。调用语句为swap(&a,&b);2222其中,&a表示a的地址,&b表示b的地址,那么swap的定义相应地改为void swap(int*px,int*py)/*px和py是指针参数,是形参*/int temp;temp=*px;*px=*py;*py=temp;2323这样就可以实现a和b的交换。调用函数和被调用函数参数之间的关
14、系如图9-2所示。指针作为函数的参数能使该函数(被调用者)访问并改变调用它的那个函数(调用者)中的对象。让我们举例来说明。2424图9-2 调用函数和被调用函数参数之间的关系2525【例【例9.1】使用第6章例6.4中的冒泡排序算法,逆序时调用swap函数实现两个数的交换。程序如下:#include void swap(int*px,int*py);main()int num9,i,j;printf(Input 9 integer numbers arbitrarily:);for(i=0;i9;i+)2626 scanf(%d,&numi);printf(nOriginal 9 intege
15、r numbers:);for(i=0;i9;i+)printf(%d,numi);for(i=0;i8;i+)/*n-1趟冒泡操作*/for(j=0;jnumj+1)/*比较numj和numj+1,即相邻两整数*/swap(&numj,&numj+1);/*逆序时交换numj和numj+1,传两个元素地址*/printf(nSorting result:);2727 for(i=0;i9;i+)printf(%d,numi);printf(n);void swap(int*px,int*py)/*px和py是指针参数,是形参*/int temp;temp=*px;2828 *px=*py;*
16、py=temp;程序运行后输出:Input 9 integer numbers arbitrarily:23 24 3 2 34 2356 6 7 777Original 9 integer numbers:23,24,3,2,34,2356,6,7,777Sorting result:2,3,6,7,23,24,34,777,23562929本例中,调用函数为main()函数,被调用函数为swap()函数。请用本节开头的swap()函数试一试,看看能否得到正确结果。3030【例【例9.2】编写函数addx(int*a,int*b),函数中把指针变量a和b所指的存储单元中的两个值相加,然后将结
17、果值作为函数值返回。在主函数中输入两个数赋给两个变量,把变量的地址作为实参,传送给对应形参。int addx(int *a,int*b)int sum;sum=*a+*b;return sum;3131main()int x,y,z;printf(Enter x,y:);scanf(%d%d,&x,&y);z=addx(&x,&y);printf(%d+%d=%dn,x,y,z);3232程序运行结果:Enter x,y:23 4523+45=683333在C语言中,指针和数组有着密切的关系,常将指针和数组进行同步讨论;能够通过数组下标完成的任何运算,也可以通过指针来完成,一般用指针完成得更快
18、,但指针的使用方法往往掌握起来有些困难。9.4 指指针针和和数数组组34349.4.1 一维数组和数组元素的地址一维数组和数组元素的地址定义一个一维数组:int a10;现在定义了一个有10个元素的一维数组,即有一组命名为a0、a1、a2、a9的对象。3535符号ai称为数组的第i个元素。如果pa是一个指向int的指针,定义为int*pa;那么赋值语句:pa=&a0;设置pa指向数组a的元素0,即pa保存了a0的地址。3636现在我们可以通过指针pa引用数组a的所有元素,pa+1指向pa的下一个元素,pa+i指向pa后的第i个元素,pa-i指向pa之前的第i个元素;*(pa+1)就是a1的内容
19、,*(pa+i)就是ai的内容。3737我们在前面讲过,数组名是一个常量指针,其指向数组的第一个元素,常量指针不能修改,但可以引用,如a=&x;a+;这些语句都是不合法的;pa=a;是合法的,等价于pa=&a0。38389.4.2 通过一维数组名和指针引用数组元素通过一维数组名和指针引用数组元素数组名是数组的首地址,指向数组的第一个元素。由以上例子可知,我们可以通过数组a的数组名a来引用其元素,a的值等于&a0的值,a+1的值等于&a1的值,a+9的值等于&a9的值。因此,我们可以通过间接访问运算符“*”访问指针指向的对象,对于数组元素a0的引用,可以用表达式*&a0来代替,也可以用*(a+0
20、)来代替,也可以写成*a;对数组元素a1的引用,可以用表达式*&a1来代替,也可以用*(a+1)来代替;3939依此类推,对数组元素a9的引用,可以用表达式*&a9来代替,也可以用*(a+9)来代替;因此我们可以用如下语句输出数组a中所有的元素:for(k=0;k10;k+)printf(%4d,*(a+k);或者:for(k=0;k10;k+)printf(%4d,ak);4040【例【例9.3】假设一个一维数组a,有10个整型元素,请用其数组名输出数组中的所有元素。方法1:用数组名引用一维数组中的元素。#include main()int i,a10=1,2,3,4,5,6,7,8,9,1
21、0;for(i=0;i10;i+)printf(%d,*(a+i);4141 printf(n);程序运行结果:1,2,3,4,5,6,7,8,9,10,方法2:通过每个数组元素的地址,用间接运算符来引用一维数组中的元素。#include main()4242 int i,a10=1,2,3,4,5,6,7,8,9,10;for(i=0;i10;i+)printf(%d,*&ai);printf(n);4343程序运行结果:1,2,3,4,5,6,7,8,9,10,也可以通过指针来引用一维数组中的元素,我们在前面讲过,数组名是一个常量指针,虽然我们不能给它重新赋一个新值,但我们可以引用,我们可
22、以把它拷贝到另一个指针变量,然后通过修改该指针变量来引用数组中的元素,下面举例说明。4444【例【例9.4】假设一个一维数组a有10个整型元素,请通过修改指针,引用数组中的元素并输出。#includemain()int i,a10=1,2,3,4,5,6,7,8,9,10;int*ip;ip=a;for(i=0;i10;i+)printf(%d,*ip);4545 ip+;/*现在可以修改ip指针的值,指针a不允许被修改*/printf(n);程序运行结果:1,2,3,4,5,6,7,8,9,10,46469.4.3 引用一维数组元素的方法总结引用一维数组元素的方法总结如果有以下定义和语句:i
23、nt*p,a10,i;p=a;我们可以用&ai、a+i和p+i三种表达式来表示数组元素ai的地址,同时可以用ai、*(a+i)和*(p+i)三种表达式来表示数组元素ai,还可以用pi表示数组元素ai。所以表示数组元素ai的表达式应当有:ai;*(a+i);*(p+i);pi。4747将指针、数组、地址运算整合在一起是体现C语言强大功能的一个方面。如果p是指向数组元素的一个指针,那么p+对p自加1运算后,p指向下一个元素,而p+=i对p加i后,p指向与p原来指向的那个元素相距i个元素的那个元素。如果p是一个指针变量,它可以保存地址,地址是一个无符号的整数值,我们可以对该指针做一些运算。由于地址本
24、身的特殊性,因此这些运算受到一定的限制。对指针只能进行如下运算:9.5 地地 址址 运运 算算4848(1)与整数相加、减运算。(2)赋值运算。(3)同一数组中各元素地址间的关系运算与相减运算。49499.5.1 指针与整数相加、减运算指针与整数相加、减运算指针与整数相加、减,表示指针在内存空间向下、向上移动,移动单位与其指向的数据类型有关。int型指针的移动单位可能是2个字节(与系统有关),即int型指针加1,向下移动2个字节,减1向上移动2个字节。char型指针的移动单位是1个字节。图9-3为指针与整数相加减时的指针移动示意图。假设pf指针是int型的指针,移动单位是2个字节。5050图9
25、-3 指针与整数相加、减时的指针移动示意图5151我们打个比方,仓库里有货架,货架上有货箱,货箱里有隔档,货架、货箱、隔档都有编号,用不同类型的指针保存这些编号。对指向货架的指针加1、减1,相当于指针变动1个货架位置;对指向货箱的指针加1、减1,相当于指针变动1个货箱位置;对指向隔档的指针加1、减1,相当于指针变动1个隔档位置;货架、货箱、隔档在仓库里占用的空间是不同的。5252【例【例9.5】指向不同类型的指针做加、减运算后,指针值的变化情况。#include main()short int*pf,dat2=1,2;float*fp,f2=3.5f,3.6f;char*cp,c2=A,B;p
展开阅读全文