八 指针PPT课件_第1页
八 指针PPT课件_第2页
八 指针PPT课件_第3页
八 指针PPT课件_第4页
八 指针PPT课件_第5页
已阅读5页,还剩69页未读 继续免费阅读

下载本文档

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

文档简介

第8章指针,指针是C语言中的一个重要概念,是C语言的精华、灵魂。,1.内存单元地址程序中定义了变量后,在编译时系统就给这个变量分配内存单元。内存中每一个内存单元都有一个编号,这就是“地址”。内存单元地址就是编译后系统分配给变量的内存空间位置。例如:inti,j,k;,8.1地址和指针的概念,数据在内存中的存取方式:直接访问方式和间接访问方式。直接访问方式:按变量地址存取变量值。间接访问方式:把一个变量的地址放在另一个变量中。,内存单元的内容内存单元中存放的数值。例如:i=3;j=6;在2000单元中存放数值3,3即为内容。在2002单元中存放数值6,6即为内容。,例:printf(%d,i);其执行是这样的:根据变量名与地址的对应关系,找到变量i的地址2000,然后从由2000开始的两个字节中取出数据(即变量的值3),把它输出。这种按变量地址存取变量值的方式称为“直接访问”方式。,例如,我们定义一个变量i_pointer,用来存放整型变量i的地址:i_pointer=/*把变量i的地址赋给变量i_pointer*/这时i_pointer的值就是变量i所占用的内存单元的起始地址(2000)。如何存取变量i的值?,间接访问方式:通过存储在某一个内存单元中的地址去存取该地址所指向的内存单元中的变量值。,要存取变量i的值,先要找到存放i的地址的变量(i_pointer),从中取出i的地址(2000),然后到2000、2001字节中取出i的值(3)。,表示将数值3送到变量中,有两种方法:将3送到变量i所标志的单元中。将3送到变量i_pointer所“指向”的单元中。所谓“指向”就是通过地址来体现的。(如右图所示),由于通过地址可以找到所需的变量单元,因此可以说,地址“指向”该内存单元。在C语言中,将地址形象化地称为“指针”。一个变量的地址称为该变量的“指针”。例如地址2000是变量i的指针。如果有一个变量,专门用来存放另一个变量的地址(即指针),则它称为“指针变量”。如前面所说的i_pointer变量称为指针变量。指针变量的值是指针(地址)。注意:(1)“指针”和“指针变量”这两个不同的概念。(2)通过指针变量如何访问变量i的值?(间接访问),变量的指针就是变量的地址。存放变量地址的变量是指针变量,用来指向另一个变量。指针变量和它所指向的变量之间,用“*”表示“指向”。例如i_pointer代表指针变量,*i_pointer是i_pointer所指向的变量。,8.2变量的指针和指向变量的指针变量,可以看到,*i_pointer也代表一个变量,它和变量i是同一回事。下面两个语句作用相同:i=3;*i_pointer=3;第个语句的含义是将3赋给指针变量i_pointer所指向的变量。,8.2.1定义一个指针变量,指针变量是专门用来存放地址的,因此必须定义为“指针类型”。指针变量定义的一般形式:基类型*指针变量名指针变量的基类型用来指定该指针变量可以指向的变量的类型。例如:int*pointer_1,*pointer_2;(指向整型变量的指针变量)float*pointer_3;(指向实型变量的指针变量)char*pointer_4;(指向字符型变量的指针变量),注意:1.指针变量前面的“*”表示该变量是指针变量。指针变量名是pointer_1、pointer_2,而不是*pointer_1、*pointer_2.2.在定义指针变量时必须指定基类型。不同类型的数据在内存中所占的字节数是不同的。指针变量的类型说明是为了告诉系统按变量中的地址从内存选取几个字节的数据进行操作,便于指针的移动和指针的运算操作。3.一个指针变量只能指向同一类型的变量,即存放同一类型变量的地址。,怎样使一个指针变量指向另一个变量呢?可以使用赋值语句。例如:floatx;charch;float*pointer_3;char*pointer_4;pointer_3=,例:intk,i=5;int*pointer;pointer=,输出变量i的值5,k的值为5,8.2.2指针变量的引用,指针变量中只能存放地址(指针),不能将一个整型量或任何其它非地址类型的数据赋给一个指针变量。例如赋值语句:pointer_1=2000;(不合法),有关地址的运算符:1.int*pointer_1,*pointer_2;/*定义指针变量,指向整型变量*/a=100;b=10;pointer_1=,例8.1通过指针变量访问整型变量。,运行结果:100,10100,10,pointer_1指向a,*pointer_1就是变量a。pointer_2指向b,*pointer_2就是变量b。,scanf(%d,%d,例8.2输入整数a和b,按先大后小的顺序输出a和b。,运行结果:a=5,b=9max=9,min=5,实际上并没有交换a和b。算法不交换整型变量的值(变量a和b中的值没有改变),而是交换两个指针变量的值(即变量a和b的地址),使p1指向大的数,p2指向小的数。,8.2.3指针变量作为函数参数,例:对输入的两个整数按大小顺序输出。,#includevoidmain()voidswap(int*,int*);int,;int*pointer_,*pointer_;scanf(,);pointer_;pointer_2;if()swap(pointer_,pointer_2);printf(,);,voidswap(int*,int*)inttemp;temp*1;*;*temp;,例:对输入的三个整数按大小顺序输出。,#includevoidmain()inta,b,c,*p1,*p2,*p3;scanf(%d,%d,%d,voidexchange(int*q1,int*q2,int*q3)if(*q1*q2)swap(q1,q2);if(*q1*q3)swap(q1,q3);if(*q2*q3)swap(q2,q3);,voidswap(int*pt1,int*pt2)inttemp;temp=*pt1;*pt1=*pt2;*pt2=temp;,一个变量有地址,一个数组包含若干元素,每个元素在内存中占用存储单元,它们也应该有相应的地址。一个变量既然可以指向变量,当然也可以指向数组和数组元素。所谓数组的指针是指数组的起始地址。数组元素的指针是数组元素的地址。例如:inta10,i,*p,*p1;p=a;或p=,8.3数组的指针和指向数组的指针变量,引用数组元素可以用下标法(如a3),也可以用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高(占用内存少,运行速度快)。,8.3.1指向数组元素的指针,例如:inta10;int*p;.p=,指向数组元素的指针变量,其定义与普通指针变量的定义相同。,把元素a0的地址赋给p,即p指向数组a的第0个元素。因为数组名表示数组的首地址,所以它等价于p=a;应注意数组a并不代表整个数组,而是把数组a的首地址赋给指针变量p,不是把数组a的各个元素赋给p。,假设已经定义了数组和一个指针变量inta10;int*p=a;.*p=1;,数组元素的引用可以用1.下标法:ai2.指针法:*(a+i)或*(p+i)其中p为指向数组a的指针变量,初值p=a;下标法比较直观,程序容易阅读,指针表示,8.3.2通过指针引用数组元素,对p当前所指的元素赋整数值1,注意:C规定:p+1(或p+)指向同一数组的下一个元素(不是地址值简单加1)。p+1代表的实际地址是p+1d(d是一个数组元素所占的字节数)。当p的初值为a的首地址时,p+i或a+i就是ai的地址,因为a代表了数组的首地址。*(p+i)或*(a+i)所指的数组元素就是ai的内容。实际上,是变址运算符,对ai的处理,是将ai按a+i计算地址,然后找出此地址单元中的值。指向数组的指针变量也可以带下标,如:pi等价于*(p+i),即ai。,例8.5输出数组中全部元素:四种方法。,main()inta10=1,2,3,4,5,6,7,8,9,10;int*p,i;printf(n下标法:n);for(i=0;i10;i+)printf(%d,ai);printf(n指针法(数组名):n);for(i=0;i10;i+)printf(%d,*(a+i);printf(n指针法(指针变量):n);p=a;for(i=0;i10;i+)printf(%d,*(p+i);printf(n指针法(指针变量):n);for(p=a;pa+10;p+)printf(%d,*p);printf(n);,否!a+的操作是非法的,因a是常量。,能否改成如下形式?for(p=a;ap+10;a+)printf(%d,*a),几种方法的比较:下标法和指针法(数组名)执行效果是相同的。编译系统先将ai转换为*(a+i),即先计算元素地址,因此这两种方法找数组元素比较费时。指针变量法是直接指向数组元素,p+的自加操作比较快。用下标法比较直观。,例8.6通过指针变量输入输出数组a的10个元素main()int*p,i,a10;p=a;for(i=0;i10;i+)scanf(%d,如果输出时没有语句p=a;程序将?,P是地址,不要加则:,一、多维数组的地址例.二维数组inta34=1,3,5,7,9,11,13,15,17,19,21,23;分析二维数组的性质:a是一个数组名,包含3个元素:a0,a1,a2。每个元素又是一个一维数组,包含4个元素。,8.3.4指向多维数组的指针和指针变量,从二维数组的角度看,a代表整个二维数组的首地址,也就是第0行的首地址。若a的首地址为2000,因为每一行4个元素,占用8个字节,所以则a+1的首地址为2008,a+2的首地址为2016。故a+1代表第1行的首地址,即a1的地址;a+2代表第2行的首地址,即a2的地址。,由于a0与*(a+0)等价,a1与*(a+1)等价,ai与*(a+i)等价,因此ai+j与*(a+i)+j等价,它们都是元素aij的地址。故:元素aij的地址表示是:ai+j或*(a+i)+j而*(*(a+i)+j)或*(ai+j)是元素aij的值。,a0、a1、a2既然是一维数组名,则它们应代表一维数组的首地址。a0代表第0行一维数组中第0列元素的地址,即printf(FORMAT,a,*a);1printf(FORMAT,a0,*(a+0);2printf(FORMAT,8,(假设系统给数组a分配的首地址为2000)则运行结果是:,注意:a是二维数组名,代表数组首地址,不能企图用*a来得到a00的值。*a相当于*(a+0),即a0,它是第0行地址。a是行指针,*a是列指针,指向0行0列元素。*a是0行0列元素的值。a+1指向第一行首地址,不能企图用*(a+1)得到a10的值,而应该用*(a+1)求a10元素的值。,2000,20002000,20002000,20002008,20082008,20082016,20162016,20169,9,例8.12用指针变量输出数组元素的值。main()inta34=1,3,5,7,9,11,13,15,17,19,21,23;int*p;for(p=a0;pa0+12;p+)printf(%4d,*p);,运行结果:1357911131517192123,p-a0:为相距的单元个数,不是字节数若:a02000p2008则:p-a0=4,1.指向数组元素的指针变量,二、指向多维数组的指针变量,if(p-a0)%4=0)printf(n);,数组元素在数组中的位置:计算某个指定的数组元素在数组中的位置(即相对于数组起始位置的相对位移量):设a是大小为nm的二维数组,则元素aij在数组中的相对位置的计算公式为:i*m+j若p是一个指针变量,指向二维数组a的首地址:p=,若定义:inta34;p=/*p指向a0*/则p+1不是指向a01,而是a1,p的增值以一维数组的长度为单位。故aij可表示为:*(*(p+i)+j)。,例8.13输出二维数组任一行任一列元素的值。,main()inta34=1,3,5,7,9,11,13,15,17,19,21,23;int(*p)4,i,j;p=a;scanf(%d,%d,运行结果:输入:1,2输出:a12=13,说明:aij的地址可以表示为:*(p+i)+j。注意*(p+i)+j不能写成p+i+j。对于数组指针p,p=a;则p指向二维数组a的第一行首地址。对于指针变量p,p=a0;则p指向二维数组a的第一行第一列元素首地址,而p=a;是不合法的。,voidaverage(float*p,intn)float*p_end;floatsum=0,aver;p_end=p+n-1;for(;p=p_end;p+)sum=sum+(*p);aver=sum/n;printf(average=%6.2n,aver);voidsearch(float(*p)4,intn)intj;printf(thescoreofNo.%dare:n,n);for(j=0;j4;j+)printf(%5.2f,*(*(p+n)+j);,由于p指向一维数组,因此,*(p+n)是第n行的首地址,*(p+n)+j是第n行第j列元素的地址。,运行结果:average=82.25thescoreofNo.2are:90.0099.00100.0098.00,最后一个元素的地址,从指向第一个元素起,依次指向下一个元素,例8.15在上例中,找出有一门以上不及袼的学生,输出其全部成绩。,voidsearch(float(*p)4,intn)inti,j,flag;for(j=0;jn;j+)flag=0;for(i=0;i4;i+)if(*(*(p+j)+i)60)flag=1;if(flag=1)printf(No.%dfails,hisscoresare:n,j+1);for(i=0;iy?x:y);,调用p所指向的函数,8.7.1指针数组指针数组数组元素均为指针类型数据,即每个元素都是指针变量。指针数组的定义形式:类型标识*数组名数组长度例如:int*p4,例如:若干个字符串的排序和查找。由于字符串本身就是一个字符数组,而各个字符串的长度又不同,因此用二维数组处理不太方便。如果用指针数组,使各元素分别指向各个字符串,那么只要改变指针数组中各元素的指向,就可对所指的字符串进行排序。,注意与int(*p)4的区别!,8.7指针数组和指向指针的指针,由于的优先级高于*,p先与结合表示数组,然后p再与*结合,表示数组是指针类型,int表示每个数组元素指向一个整型变量.,例如:有若干字符串,长短不一,可以分别定义一些字符串,然后用指针数组中的元素分别指向各字符串。如果想对字符串排序,不必改动字符串的位置,只需改动指针数组中各元素的指向。这样,各字符串的长度可以不同,且移动指针要比移动字符串所花的时间少得多。,voidprint(char*name,intn)inti;for(i=0;in;i+)printf(%sn,namei);,#includemain()voidsort(char*name,intn);voidprint(char*name,intn);char*name=Followme,BASIC,GreatWall,FORTRAN,Computerdesign;intn=5;/*字符串个数*/sort(name,n);print(name,n);,voidsort(char*name,intn)char*temp;inti,j,k;for(i=0;i0)k=j;if(k!=i)temp=namei;namei=namek;namek=temp;,例8.27将n个字符串按字母顺序(由小到大)排序输出(设n=5),运行结果:BASICComputerdesignFORTRANFollowmeGreatWall,定义形式:类型标识*变量名例如:char*p,由于*是从右到左结合,因此*p相当于*(*p),8.7.2指向指针的指针,例如:char*name5;char*p;p=name+2;printf(%on,*p);printf(%sn,*p);,例8.28使用指向指针的指针,main()char*name=Followme,BASIC,GreatWall,FORTRAN,Computerdesign;char*p;intj;p=name;for(j=0;j5;j+)printf(%sn,*(p+j);,以%o输出name2的值(地址),以%s输出name2的字符串GreatWall,运行结果:FollowmeBASICFORTRANGreatWallComputerdesign,main()inta5=1,3,5,7,9;int*num5=,例8.29,运行结果:13579,8.8.1指针类型的小结,8.8指针类型和指针运算的小结,指针运算有如下几种:1.指针变量可以和整数进行加(减),例如:p+,p-,p+i,p-i,p+=i,p-=i;注意:p+1指的是加1个单位,即p所指向的变量占用的内存字节数,如p是指向整型变量的指针,则加2个字节。2.指针变量可以赋值(赋地址),例如:p=(NULL表示整数0),在stdio.h中有定义:#defineNULL0任何指针变量或地址都可以与NULL作相等或不相等的比较,如if(p=NULL)4.两个指针变量可以相减,即p2-p1,表示两个指针之间的元素个数。但p1+p2无意义。5.若两个指针指向同一个数组的元素,则可以进行比较,例如:p1p2,p1=p2.,8.8.2指针运算小结,它可以用来表示指向一个抽象的数据类型。例如:char*p1;void*p2;p1=(char*)p2;把p2强制转换为指向字符变量的指针。也可以将一个函数定义为(void*)类型,例如:void*fun(charch1,charch2),指针是C语言中重要的概念。使用指针的优点是:(1)提高效率;(2)被调函数可以改变主调函数的值,即可以返回多个值;(3)可以实现动态存储分配。,8.8.3void指针类型,指针变量如何定义,指针和地址的关系,如何对指针进行运算?如何定义和使用以下对象:指针数组、数组指针、指针的指针、函数指针、返回值为指针的函数。如何使用字符指针?如何通过指针来改变函数实在参数的值?什么是命令行参数?如何正确使用?,本章要点,习题八(一),(一)填空(1)写出建立图一所示的存储结构所需的定义语句:char_.(2)写出图一所示的存储结构所需的赋值语句:_=B;p=_.(3)写出用指针变量p输出字符变量的语句:printf(%cn,);(二)填空(1)写出建立图二所示的存储结构所需的定义语句:int_,_;(2)写出图二所示的存储结构所需的赋值语句:p=_;(3)写出用指针变量p输出数组s每一个元素值的语句:for(j=0;j0)temp=*(a+0);*(a+0)=*(a+m);*(a+m)=temp;if(n9)temp=*(a+9);*(a+9)=*(a+n);*(a+n)=temp;,voidprint()intj;for(j=0;j10;j+)printf(%4d,*(a+j);main()input();change();print();,指针习题解答,6、#includemain()intlen(char*ptr);chars80,*p;intm;gets(s);p=s;m

温馨提示

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

评论

0/150

提交评论