计算机C语言程序设计ch07指针上.ppt
《计算机C语言程序设计ch07指针上.ppt》由会员分享,可在线阅读,更多相关《计算机C语言程序设计ch07指针上.ppt(89页珍藏版)》请在三一办公上搜索。
1、第七章 指针,指针与变量指针运算指针与数组指针与字符串指向指针的指针命令行参数本章小结,作业:7.6 7.8 7.9 7.10 7.13 7.16 7.23 7.27练习:7.1-7.5 7.7 7.11 7.12 7.14 7.15,指针是高级程序设计语言中一个重要的概念正确灵活运用指针可有效地表示和使用复杂的数据结构可动态分配内存空间,节省程序运行空间,提高运行效率不正确理解和使用指针,指针将是程序中最危险的成分,由此带来的后果可能是无法估量的。,指针,必须清楚:数据在内存中的存储和访问方式已知:每个变量在计算机内存占用一块存储区该存储区的地址就是相应变量的地址变量可能有值该存储区保存的内
2、容就是相应变量的值,变量地址,变量名,变量值,变量的存储区,7.1 指针与变量,例如有变量声明 char c=S;int v=27,u=32;int*p=则编译程序分别给变量 c、v、u、p 分配存储空间如图所示其中:B900是变量v的地址 也是变量v的指针,指针即是地址 变量的指针就是变量的地址 存放指针(变量地址)的变量是指针变量 指针变量简称指针必须理解清楚:给变量分配的内存区域该内存区域的地址该内存区域保存的内容以及它们之间的关系,指针类型与指针变量,指针类型:格式指向T类型变量的指针类型用:T*其中:T称为该指针类型的基类型在C中,任何一个类型都伴随着一个指向本类型变量的指针类型基类
3、型(指针所指向的类型)可以是基本数据类型构造型数据类型指针类型函数,指针变量:,声明指针变量T*p1,*p2,*pn;其中,T*指针类型,T称为该指针类型的基类型 pi是标识符,是指针类型的变量,指向T类型变量的指针变量意义指针变量简称指针是一种特殊的变量它里面存储的“值”被解释成为一个变量的地址,确切的说是计算机内存的一个地址,T*v;称“指向T类型变量的指针变量v”“v指向T类型”“T类型的指针v”例如int x,y;char ch=a;int*ip1=/*pa是指向float类型变量的指针变 量*/,cp=,指针变量的值是内存地址(即变量的地址)取地址的方法:基本类型变量、数组成员、结构
4、体变量、公用体变量等,用求地址运算符“函数的地址为函数的入口地址,用函数名字表示,设有声明:int*ip1,*ip2;char*cp;int x,y;char ch=a;在此基础上,有操作:,ip1=,cp=,x=5;或*ip1=5;,ip2=,y=8;,内存单元,地址,变量,E990,指针ip1,E994,指针ip2,E998,指针cp,E99C,int型变量 x,E99E,int型变量 y,E9A0,char型变量 ch,E99C,E99E,E9A0,a,5,8,如果再执行 ip1=ip2;,E99E,指针变量ip1指针所指变量x,访问变量(指针所指变量)的方法直接访问:直接使用变量的名字
5、int v=10;v=v*10;间接访问:用指向该变量的指针*p 比如访问变量 v 可以用下面方式来实现:int*p=它通过指向 v 的指针变量 p,采用间接访问的方 式实现对变量 v的访问,取出变量 v 的值参与运算区分指针变量和指针所指的变量区分开指针值和指针所指变量的值,程序片段 int*ip;int i=3,j;ip=,j=*ip;,3,注意:指针变量在使用前一定有值,void main()/*2*/int i,j;/*3*/char ch;/*4*/int*pi,*pj;/*5*/char*pch;/*6*/printf(Input an integer:);/*7*/scanf(%
6、d,/*17*/*18*/,例7-1 指针变量与指针所指变量,该程序运行过程为:程序第7行输出提示信息在键盘输入23程序第9行输出提示信息在键盘输入45程序第11行输出提示信息在键盘输入r程序第16行输出程序第17行输出,Input an integer:23Input another integer:45Input a char:ri=23 j=45 ch=r*pi=23*pj=45*pch=r,变量i,j,ch在内存中存储的内容,分别通过对指针pi,pj,pch的间接引用获得。,void main()/*2*/int i,j;/*3*/int*pmax,*pmin,*p;/*4*/prin
7、tf(Input an integer:);/*5*/scanf(%d,/*16*/*17*/,例7-2 用指针变量实现:输入两个 整数,按从大到小顺序输出,假设输入25、38,该程序运行到第10行结束时,&i,&i,&j,&j,&i,当程序执行完第12行 p=pmax;,当程序执行完第13行pmax=pmin;,当程序执行完第14行pmin=p;,“*”的用法:“*”放在指针定义中时,表示指针类型 int*p指针定义符,用来说明指针变量“*”放在表达式中的指针变量之前 j=*ip 间接访问操作符,“对指针所指变量的访问”“*”运算符 3*5例7-1第5行的“int*pi,*pj;”,说明指向
8、int类型的指针变量pi、pj;第6行的“char*pch;”,说明指向char类型的指针变量pch 例7-1第17行打印语句中的“*pi”,“*pj”,“*pch”,空指针与无效指针,T*p=NULL;NULL是C指针类型的一个特殊值,称为“空”表示指针变量的值为空,不指向任何变量或函数。NULL值属于所有指针类型。判断指针变量iptr的值是否为空可以使用 iptr!=NULL 或 iptr=NULL保证指针在没有指向有效对象时取值为NULL是一种良好的编程风格。,有时可能不小心生成无效指针 invalid pointer无效指针是指一个指针变量无值,它既没有指向确定的变量或函数,也不是NU
9、LL产生无效指针的原因很多,例如说明指针变量后还没有给它赋值;把整型变量转换成指针;回收为指针所指对象分配存储空间;指针运算超出数组范围。访问空指针(指针变量的值为NULL)或无效指针(指针变量无值)所指向的内容是错误的程序中存在无效指针,不是好的程序设计风格,例7-3 分析下述程序片段的执行结果,int*p,*q,u,v;q=,&u,3,&v,3,5,&u,7,NULL,*p=3发生错误,因为 p 不指向任何变量,7.2 指针运算,求地址,赋值=把一个指针值赋值给某个指针变量例子:int*px,*py,x;px=/*将地址4800赋给px,而不是整数类型4800*/,加+(+)和减-(-)操
10、作常用于数组加+(+)当指针指向数组的一个元素(成分),指针值加上一个整数表达式,结果值仍然是个指针值 如:int*p,a10=1,2,3,4,5 p=,例如:int*p,*q,*r,a100;p=则 p+3 是 a13的地址 计算过程如下:&(a10)+3*sizeof(int)即a13的地址,若有q=p+3;则 q指向a13“p+”表示“p=p+1”,减-(-)指针的减法运算包括:指针值减去一个整数表达式,和两个相容的指针值相减 指针值减去一个整数表达式 当指针指向数组的一个成分,指针值减去一个整数表达式,得到的结果值仍然是一个指针值如:int*p,a10=1,2,3,4,5 p=,例如:
11、int*p,*q,*r,a100;p=则 p-3 是a7的地址计算过程是&(a10)-3*sizeof(int)即a7的地址若有 q=p-3;则 q指向a7“p-”表示“p=p-1”,两个相容的指针值相减(同一个数组)指针值相容,即所指的对象是同一个类型 两个相容的指针相减,结果是整型值,即两指针值间的距离 例如int*p,*q,*r,a100;p=则p-q得-5 而 q-p得5,指针加减运算限制:若指针p指向的不是数组成分,或p+k、p-k后超出数组定义范围,则其行为是未定义的,将产生不可预料的结果不能对函数指针、void*类型指针进行加减运算不允许两个指针间进行加法运算,判等运算和关系运算
12、兼容类型的指针进行判等运算和关系运算,得到的结果是bool类型关系运算包括:判断两个指针值是否相等或不相等=、!=;比较两个指针值的大小关系、=、=例子pxpy 判断px所指向的存储单元地址是否小 于py所指向的存储单元地址。px=py 判断px与py是否指向同一个存储单元px=0、px!=0、px=NULL、px!=NULL 都是判断px是否为空指针,一定要注意,参与关系运算的指针值必须是类型兼容的,如果p指向一个int类型变量,而q指向一个 float 类型变量,进行p与q的比较是错误的,例7-4 指针运算实例,#include void main()char str255,*p;int
13、v;scanf(%s,str);p=str;while(*p!=0)p+;printf(The string length is%d n;p-str);,程序运行若输入:abcdef则输出结果为 The string length is 6,7.3 指针与数组,密切的关系数组名是数组的首地址,即a0的地址指针值也是一个地址,如一个指针p指向数组a的首地址即指向a0,则p与a表示的是同一个对象事实上,在C中把指针和数组当作同一个概念看待,数组名是指针,指针也是数组数组名是常量指针,7.3.1 用指针标识数组,例如 int a5;int*iptr iptr=a;/也可以使用 iptr=&(a0)如
14、下操作等价 ai*(a+i)iptri*(iptr+i),例7-5 展示指针与数组间关系,void main()int a5;int i,*p;for(i=0;i5;i+)printf(a%d=,i);scanf(%d,假设分别输入1、2、3、4、5 在输出阶段:执行第一个for语句输出结果:执行第二个for语句输出结果:执行第三个for语句输出结果:,a0=1a1=2a2=3a3=4a4=51 2 3 4 5 1 2 3 4 5 1 2 3 4 5,注意1:数组名是指针常量,数组名是指针常量,不能改变其值如:对数组变量a的增1运算“a+”是非法的 for(a=p;ap+5;a+)printf
15、(%2d,*a);指针变量可以参与运算,比如例7-5中有语句:for(p=a;pa+5;p+)printf(%2d,*p);该语句中,对指针变量p不断进行增1运算,注意2:指针变量的当前值,指针变量指向数组的首地址。如有int a10,*iptr;iptr=a;若访问a数组的第i个元素,可用下标法和指针法ai/下标法*(a+i)/指针法iptri/下标法*(iptr+i)/指针法注意:当指针不是指向数组的首地址,这四种写法不等价,如若有语句iptr=被执行后,则:iptri、*(iptr+i)、ai+2、*(a+i+2)等价 写程序时要特别注意指针变量的当前值,有时由于忽略指针变量的当前值,会
16、使程序产生严重错误,而且这种错误还十分难于查找。例7-6说明该问题。该程序原想输入10个整数,再把它们打印出来,但是程序运行结果却不然,例7-6 输入10个整数,再把它们打印出来。(指针变量错误使用实例),#include“stdio.h”void main()int i,*p,a10;p=a;for(i=0;i10;i+)scanf(“%d”,p+);for(i=0;i10;i+)printf(“%dn”,*p);p+;,错误在:当执行完输入语句后,p已经指向数组的最后一个元素,执行输出时从a9开始的单元输出十个元素,使用指针形式访问数组元素,是从指针变量当前所指的位置开始“向前”或“向后”
17、计算。而不是当初给指针变量赋的初值,写程序时要特别注意指针变量的当前值,有时由于忽略指针变量的当前值,会使程序产生严重错误,而且这种错误还十分难于查找,注意3:数组超界,数组超界是指访问不存在的数组元素。如有如下声明:int a10,*aptr;aptr=a+5;*(aptr+v)指针法访问元素 当v的值大于4时,就会出错。这种错误是最隐蔽、最难于查找的 C系统根本不检查数组超界,注意4:指针变量的运算,自增“+”和自减“-”运算,设有如下声明和运算:int a10,*ptr,v,*q,u;v=5;ptr=,讨论如下运算的意义 ptr+*(ptr+)*ptr+(*ptr)+ptr*(+ptr)
18、*+ptr,运算“ptr+”的意义是把 ptr 的值加 1,运算结束后 ptr指向a6。表达式的值是ptr加1之前时ptr的值,即a5的地址。若有q=ptr+;则结果:q 指向a5;ptr 指向a6,按刚才解释,ptr+的值是a5地址,*(ptr+)是求 a5 的值,为 50该运算相当于“av+”。若有u=*(ptr+);则结果u的值为50。,*ptr是求ptr所指变量的值,即a5的值,为50;“(*ptr)+”是a5+,最后a5的值为51,而该表达式的值为加 1 之前的值,仍然是50。若有u=(*ptr)+;则结果:u的值为50;a5的值为51。,由于运算符“*”和“+”优先级相同,结合方向
19、是从右向左,因此该表达式相当于前述*(ptr+)它的运算与该表达式完全相同。,与ptr+类似,运算“+ptr”意义是把ptr的值加1,运算结束后ptr指向a6表达式的值是ptr加1之后ptr的值,即a6的地址。若有 q=+ptr;则结果:q 指向 a6;ptr指向 a6。,按刚才的叙述,“+ptr”的值是 a6 的地址,则“*(+ptr)”是求 a6的值,得 60。该运算相当于“a+v”。若有u=*(+ptr);则结果 u 的值为60。,由于运算符“*”和“+”优先级相同,结合方向是从右向左,因此该表达式相当于*(+ptr)有关它的运算与完全一致,最后 u 的值为 60。,7.3.2 多维数组
20、与指针,1.二维数组元素的地址二维数组 amn 可以看作是由 m 个一维数组 a0、a1、am-2、am-1构成。每个一维数组有 n 个元素,即每个ai都是由 n 个变量ai0、ai1、ain-1组成的数组,如图所示,按数组与指针的关系:从一维角度看,a表示一维数组的首地址,该一维数组的数组元素仍然是数组,则:a=&a0,a+i=&ai每个ai也都表示一维数组的首地址,该一维数组是a数组的第i行,它的各个元素是int类型,则:a0=&a00,ai=&ai0*(a)=a0,*(a0)=a00,则*(*(a)=a00,实际上,a、a0、a1、am-1 是数组的名字,a、a0、a1、a2、am-1都
21、是指针常量,C 系统不给它们分配内存,只分配 m*n 个变量的内存空间。下图是一个示意图,给出的a、a0、a1、am-1只是一个示意,读者不要误会。,进一步,ai是a数组第i个元素。如果a是一维数组,则ai是一个变量并且可以有值,C系统会给它分配相应的存储空间,它实实在在占用计算机内存如果a是二维数组,则ai代表一维数组,它是一个指针常量,C系统不给它分配存储区,它不占用内存空间,仅仅是一个地址。,指针常量,指针常量,注意:在该表的各种表示形式中:&(aij)、ai+j、*(a+i)+j 是实际计算机内存的物理地址,不占用计算机内存aij、*(ai+j)、*(*(a+i)+j)是它们各自成分的
22、值,占用计算机内存 其它形式都是表示地址的指针常量,没有被分配具体内存空间。例如,并不存在 ai 这样一个实际的变量,它只是一个指针常量,运算“&(ai)”只是一种地址计算方式而已,并不是求内存实际存在的变量ai的内存地址。,2.指向二维数组元素的指针变量,二维数组的存储方式用指针变量表示二维数组的元素,C数组的存储分配方式,在C中,按“行优先”原则分配数组元素的存储空间。即对数组amn来说,它的各个成分被分配的内存空间的顺序是:首先分配第0行元素;然后分配第1行元素;最后再分配第n-1行元素,如此等等。每行元素按下标值从小到大进行。,int a34;假设从首地址A000开始分配内存空间每个元
23、素占2个字节数组a的存储分配图,使用成分类型指针访问两维数组元素,设有声明:int*aptr,amn,x;则可以直接用aptr访问a的成分。使用方法是:首先使aptr指向a的某个成分aij,aptr=最常用的地址基点是a数组的第一个成分a00 aptr=&(a00)或 aptr=a0 然后以该成分的地址为基点,计算所要访问的数组成分的相对地址,并进行访问,在上述赋值运算的前提下,a的成分auv的地址为 aptr+u*n+v若把auv的值送入变量x中,可以使用赋值运算:x=*(aptr+u*n+v)等价于 x=auv若把某表达式e的值送入数组a的成分auv中,可以使用赋值运算:*(aptr+u*
24、n+v)=e 等价于auv=e,地址计算公式“aptr+u*n+v”基点+行数*每行元素个数+剩余行的零头元素个数例如,a21的地址是:aptr+2*4+1,若再考虑每个元素占用的内存尺寸,2*4+1 还要乘以 int 类型一个变量占用内存空间数 2,最后 a21 对应的具体内存地址是:A000+(2*4+1)*2为A012。,注意:程序中只要写地址计算公式“aptr+u*n+v”即可没有必要也不允许考虑每个元素占用的存储空间尺寸没有必要,也不允许,更不可能写出具体的地址计算计算算式“A000+(2*4+1)*2”。,例7-7 编函数,求m*n个元素的给定float型数组各 个元素之乘积。,f
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机 语言程序设计 ch07 指针
链接地址:https://www.31ppt.com/p-6606107.html