已阅读5页,还剩84页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第七章指针,指针与变量指针运算指针与数组指针与字符串指向指针的指针命令行参数本章小结,作业:7.67.87.97.107.137.167.237.27练习:7.1-7.57.77.117.127.147.157.17-7.19,指针是高级程序设计语言中一个重要的概念正确灵活运用指针可有效地表示和使用复杂的数据结构可动态分配内存空间,节省程序运行空间,提高运行效率不正确理解和使用指针,指针将是程序中最危险的成分,由此带来的后果可能是无法估量的。,指针,必须清楚:数据在内存中的存储和访问方式已知:每个变量在计算机内存占用一块存储区该存储区的地址就是相应变量的地址变量可能有值该存储区保存的内容就是相应变量的值,变量地址,变量名,变量值,变量的存储区,7.1指针与变量,例如有变量声明charc=S;intv=27,u=32;int*p=则编译程序分别给变量c、v、u、p分配存储空间如图所示其中:B900是变量v的地址也是变量v的指针,指针即是地址变量的指针就是变量的地址存放指针(变量地址)的变量是指针变量指针变量简称指针必须理解清楚:给变量分配的内存区域该内存区域的地址该内存区域保存的内容以及它们之间的关系,指针类型与指针变量,指针类型:格式指向T类型变量的指针类型用:T*其中:T称为该指针类型的基类型在C中,任何一个类型都伴随着一个指向本类型变量的指针类型基类型(指针所指向的类型)可以是基本数据类型构造型数据类型指针类型函数,指针变量:,声明指针变量T*p1,*p2,*pn;其中,T*指针类型,T称为该指针类型的基类型pi是标识符,是指针类型的变量,指向T类型变量的指针变量意义指针变量简称指针是一种特殊的变量它里面存储的“值”被解释成为一个变量的地址,确切的说是计算机内存的一个地址,T*v;称“指向T类型变量的指针变量v”“v指向T类型”“T类型的指针v”例如intx,y;charch=a;int*ip1=/*pa是指向float类型变量的指针变量*/,cp=,指针变量的值是内存地址(即变量的地址)取地址的方法:基本类型变量、数组成员、结构体变量、公用体变量等,用求地址运算符“函数的地址为函数的入口地址,用函数名字表示,设有声明:int*ip1,*ip2;char*cp;intx,y;charch=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,访问变量(指针所指变量)的方法直接访问:直接使用变量的名字intv=10;v=v*10;间接访问:用指向该变量的指针*p比如访问变量v可以用下面方式来实现:int*p=它通过指向v的指针变量p,采用间接访问的方式实现对变量v的访问,取出变量v的值参与运算区分指针变量和指针所指的变量区分开指针值和指针所指变量的值,程序片段int*ip;inti=3,j;ip=,j=*ip;,3,注意:指针变量在使用前一定有值,voidmain()/*2*/inti,j;/*3*/charch;/*4*/int*pi,*pj;/*5*/char*pch;/*6*/printf(Inputaninteger:);/*7*/scanf(%d,/*17*/*18*/,例7-1指针变量与指针所指变量,该程序运行过程为:程序第7行输出提示信息在键盘输入23程序第9行输出提示信息在键盘输入45程序第11行输出提示信息在键盘输入r程序第16行输出程序第17行输出,Inputaninteger:23Inputanotherinteger:45Inputachar:ri=23j=45ch=r*pi=23*pj=45*pch=r,变量i,j,ch在内存中存储的内容,分别通过对指针pi,pj,pch的间接引用获得。,voidmain()/*2*/inti,j;/*3*/int*pmax,*pmin,*p;/*4*/printf(Inputaninteger:);/*5*/scanf(%d,/*16*/*17*/,例7-2用指针变量实现:输入两个整数,按从大到小顺序输出,假设输入25、38,该程序运行到第10行结束时,当程序执行完第13行pmax=pmin;,当程序执行完第14行pmin=p;,“*”的用法:“*”放在指针定义中时,表示指针类型int*p指针定义符,用来说明指针变量“*”放在表达式中的指针变量之前j=*ip间接访问操作符,“对指针所指变量的访问”“*”运算符3*5例7-1第5行的“int*pi,*pj;”,说明指向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是一种良好的编程风格。,有时可能不小心生成无效指针invalidpointer无效指针是指一个指针变量无值,它既没有指向确定的变量或函数,也不是NULL产生无效指针的原因很多,例如说明指针变量后还没有给它赋值;把整型变量转换成指针;回收为指针所指对象分配存储空间;指针运算超出数组范围。访问空指针(指针变量的值为NULL)或无效指针(指针变量无值)所指向的内容是错误的程序中存在无效指针,不是好的程序设计风格,例7-3分析下述程序片段的执行结果,int*p,*q,u,v;q=,px=/*将地址4800赋给px,而不是整数类型4800*/,加+(+)和减-(-)操作常用于数组加+(+)当指针指向数组的一个元素(成分),指针值加上一个整数表达式,结果值仍然是个指针值如:int*p,a10=1,2,3,4,5p=,例如:int*p,*q,*r,a100;p=则p+3是a13的地址计算过程如下:p=则p-3是a7的地址计算过程是p=则p-q得-5而q-p得5,指针加减运算限制:若指针p指向的不是数组成分,或p+k、p-k后超出数组定义范围,则其行为是未定义的,将产生不可预料的结果不能对函数指针、void*类型指针进行加减运算不允许两个指针间进行加法运算,判等运算和关系运算兼容类型的指针进行判等运算和关系运算,得到的结果是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指针运算实例,#includevoidmain()charstr255,*p;intv;scanf(%s,str);p=str;while(*p!=0)p+;printf(Thestringlengthis%dn;p-str);,程序运行若输入:abcdef则输出结果为Thestringlengthis6,7.3指针与数组,密切的关系数组名是数组的首地址,即a0的地址指针值也是一个地址,如一个指针p指向数组a的首地址即指向a0,则p与a表示的是同一个对象事实上,在C中把指针和数组当作同一个概念看待,数组名是指针,指针也是数组数组名是常量指针,7.3.1用指针标识数组,例如inta5;int*iptriptr=a;/也可以使用iptr=inti,*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=5123451234512345,注意1:数组名是指针常量,数组名是指针常量,不能改变其值如:对数组变量a的增1运算“a+”是非法的for(a=p;ap+5;a+)printf(%2d,*a);指针变量可以参与运算,比如例7-5中有语句:for(p=a;pa+5;p+)printf(%2d,*p);该语句中,对指针变量p不断进行增1运算,注意2:指针变量的当前值,指针变量指向数组的首地址。如有inta10,*iptr;iptr=a;若访问a数组的第i个元素,可用下标法和指针法ai/下标法*(a+i)/指针法iptri/下标法*(iptr+i)/指针法注意:当指针不是指向数组的首地址,这四种写法不等价,如若有语句iptr=被执行后,则:iptri、*(iptr+i)、ai+2、*(a+i+2)等价写程序时要特别注意指针变量的当前值,有时由于忽略指针变量的当前值,会使程序产生严重错误,而且这种错误还十分难于查找。例7-6说明该问题。该程序原想输入10个整数,再把它们打印出来,但是程序运行结果却不然,例7-6输入10个整数,再把它们打印出来。(指针变量错误使用实例),#include“stdio.h”voidmain()inti,*p,a10;p=a;for(i=0;i10;i+)scanf(“%d”,p+);for(i=0;i10;i+)printf(“%dn”,*p);p+;,错误在:当执行完输入语句后,p已经指向数组的最后一个元素,执行输出时从a9开始的单元输出十个元素,使用指针形式访问数组元素,是从指针变量当前所指的位置开始“向前”或“向后”计算。而不是当初给指针变量赋的初值,写程序时要特别注意指针变量的当前值,有时由于忽略指针变量的当前值,会使程序产生严重错误,而且这种错误还十分难于查找,注意3:数组超界,数组超界是指访问不存在的数组元素。如有如下声明:inta10,*aptr;aptr=a+5;*(aptr+v)指针法访问元素当v的值大于4时,就会出错。这种错误是最隐蔽、最难于查找的C系统根本不检查数组超界,注意4:指针变量的运算,自增“+”和自减“-”运算,设有如下声明和运算:inta10,*ptr,v,*q,u;v=5;ptr=,讨论如下运算的意义ptr+*(ptr+)*ptr+(*ptr)+ptr*(+ptr)*+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。,由于运算符“*”和“+”优先级相同,结合方向是从右向左,因此该表达式相当于前述*(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多维数组与指针,1.二维数组元素的地址二维数组amn可以看作是由m个一维数组a0、a1、am-2、am-1构成。每个一维数组有n个元素,即每个ai都是由n个变量ai0、ai1、ain-1组成的数组,如图所示,按数组与指针的关系:从一维角度看,a表示一维数组的首地址,该一维数组的数组元素仍然是数组,则:a=假设从首地址A000开始分配内存空间每个元素占2个字节数组a的存储分配图,使用成分类型指针访问两维数组元素,设有声明:int*aptr,amn,x;则可以直接用aptr访问a的成分。使用方法是:首先使aptr指向a的某个成分aij,aptr=最常用的地址基点是a数组的第一个成分a00aptr=floatmul;mul=1;for(u=0;um;u+)for(v=0;vn;v+)mul=mul*(*(arr+u*n+v);returnmul;,设有声明floata1015;则可以用如下任何一种形式调用该函数:arrmul(10,15,则有:p=int*n5,i;int*p=n;for(i=0;i5;i+)ni=i+,p+)printf(“%4d”,*p);程序运行结果将输出:2324252627,“指向指针的指针变量p”“指针数组n”与“数组a”关系图,注:int*p=对否,注:int*p=n;或int*p=对否,【例7-9】二维数组、指针数组和指针间的关系inta44=1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34;int*pa4=a0,a1,a2,a3;int*p=a0,i;voidmain()for(i=0;i3;i+)printf(“%d%d%dn”,ai2+i,*(ai),*(*(a+i)+i);for(i=0;i4;i+)printf(“%d%dn”,*(pai),pi);,程序运行结果将输出:31114111231212311112213314,a、pa、p之间关系图,注:int*p=对否,例7-10把若干给定的字符串按字母顺序排序并输出,voidsort_string(char*arr_str,intn);voidout_string(char*arr_str,intn);intstr_cmp(char*str1,char*str2);char*name=basic,programming“,greatwall,language,computer;voidmain()sort_string(name,5);out_string(name,5);,该程序首先调用sort_string函数对name数组排序;然后调用ou
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年广东省房屋安全检测鉴定技术培训考核核心考点速记速练300题(附答案)
- 2025年辽阳灯塔市中小学教师招聘笔试参考试题及答案解析
- (必刷)河北对口单招医学类职业技能《生理学基础》考点精粹必做500题-含答案
- 2025年虚拟数字人形象授权补充协议
- 2025年蓬溪县教师招聘参考题库及答案解析
- 2025年七台河市中小学教师招聘笔试参考题库及答案解析
- 云南省江川一中2026届高一上生物期末教学质量检测模拟试题含解析
- 2025年榆林市榆阳区中小学教师招聘笔试参考题库及答案解析
- 深圳技术大学《多声部音乐基础》2024-2025学年第一学期期末试卷
- 2025年虚拟数字人电商直播合作协议
- 期末综合素养测评(试题)- 三年级上册数学北师大版
- 读书分享读书交流会《青铜葵花》
- 大学生面试礼仪和技巧课件
- EPC项目-装饰装修EPC总承包工程-技术标(实施方案、实施技术方案、实施管理组织方案)
- 业务连续性管理实务
- GB/T 5680-2023奥氏体锰钢铸件
- 数控车床基本操作按钮
- EIM Starter Unit 8 Dont do that单元知识要点
- 美丽乡村建设项目重点难点施工区技术措施
- 05.辩论的基础知识
- 第六单元 中华民族的抗日战争 复习课件 部编版八年级历史上册
评论
0/150
提交评论