版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、C语言程序设计指针,林大 经管学院 瞿华,指针,指针是啥? 指针基本运算 函数中的指针 指针与数组 指针与动态数组 指针与结构 函数指针 指针数组与多重指针 实验,一、指针是啥,什么是指针? 假设Z同学是我们班作业做得最好的同学,大家都喜欢参考他的作业。 Z=作业的标准答案 可以把Z看作是一个作业类型的普通变量 某天A同学找Z:“把作业借我参考一下?”周X回答:“标准答案在Y同学那里,你找他吧” Z=“标准答案在Y那里” 这时候Z相当于一个指向别人(Y)的链接, 他就变成了一个指针!,一、指针是啥,指针(Point)实际上就是一个链接! 指针变量中保存的内容是一个内存地址。 例: int y=
2、10; int *z= 指针z的内容就是y所在的内存地址。 “z,标准答案是多少?” z说:你去问y吧! y说:标准答案是10!,一、指针是啥,int y=10; int *z=,10,y,内存地址1008,1008,z,内存地址1004,z指向y,二、指针基本运算,要学好指针,必须熟练掌握指针相关的运算。(接下来会提问!)如: 指针的定义方法:在变量标识符前加* int *p,a,b; /定义了一个整型指针p和一个普通变量a /将30赋给p指向的内存中 对于指针p,*p相当于一个普通变量! 见01points.c(使用调试单步执行查看结果),2.1 ,?,a,内存地址1008,?,b,内存地
3、址1004,?,p,内存地址1000,2.1 a=10;,?,a,内存地址1008,?,b,内存地址1004,?,p,内存地址1000,2.1 a=10;,10,a,内存地址1008,?,b,内存地址1004,?,p,内存地址1000,2.1 a=10; p=,10,a,内存地址1008,?,b,内存地址1004,?,p,内存地址1000,2.1 a=10; p=,10,a,内存地址1008,?,b,内存地址1004,1000,p,内存地址1000,2.1 a=10; p=,10,a,内存地址1008,?,b,内存地址1004,1000,p,内存地址1000,2.1 a=10; p=,10,a
4、,内存地址1008,10,b,内存地址1004,1000,p,内存地址1000,2.1 a=10; p=,10,a,内存地址1008,10,b,内存地址1004,1000,p,内存地址1000,2.1 a=10; p=,20,a,内存地址1008,10,b,内存地址1004,1000,p,内存地址1000,2.1 a=10; p=,20,a,内存地址1008,10,b,内存地址1004,1000,p,内存地址1000,2.1 a=10; p=,21,a,内存地址1008,10,b,内存地址1004,1000,p,内存地址1000,2.1 double *p2; sizeof(p1)和sizeo
5、f(p2)哪个大?为什么? 因为我们使用的是32位的gcc编译器(dev-cpp自带),所以每个指针的大小都是32位,即4个字节。 见04size.c,三、函数中的指针,折腾指针有啥用呢? 回忆一下函数的知识: 在函数中改变形式参数的值,会影响实际参数吗?为什么? 见05swap_1.c 由于: 函数的形式参数实质上是一个局部变量 函数执行时先将实际参数的值赋给形式参数 所以在函数中改变形式参数,不会影响实际参数,三、函数中的指针,swap(i,t)就相当于: int a=i; int b=t; int temp=a; a=b; b=temp; 很显然,i和t的值实际并未改变。,3.1 指针类
6、型参数,可是我确实需要在函数中改变实参的值,怎么办? 使用指针类型参数,就可以解决这个问题。 见05swap_2.c 为什么? 在函数swap(int *p1,int *p2)中,p1和p2是两个指针类型的形式参数。 注意,在函数中,p1和p2各自指向哪里有变化吗? 变化的是*p1和*p2,即p1和p2指向的内存地址中保存的数据!,3.1 指针类型参数,swap( 很显然,这样是能交换i和t的内容的。,3.1 指针类型参数,使用指针参数的另外一个好处是节约栈空间。 见06stacksize.c。程序为什么会异常关闭? 由于函数调用时会为struct参数分配很大一块内存(1M字节),超过了栈的现
7、有空间大小,导致堆栈溢出。 见06stacksize_2.c,改用struct指针作为参数。 函数调用时只需要为指针参数分配一块内存(还记得一个指针占用多大空间吗?),所以就不存在堆栈溢出问题了!,3.2 指针类型返回值,函数也可以返回指针类型的数据。 例:07pointreturn.c 思考:可以返回一个指向函数局部变量的指针吗?为什么? 见08localpoint.c 因为函数执行完毕后,其局部变量的生命就结束了!对应的内存空间可能会被别的变量使用! Never ever返回指向函数局部变量的指针!,四、指针与数组,指针变量中保存的是地址。 也可以理解为,指针就是地址类型的变量。 数组实质
8、上是地址类型的常量。 因此: 可以将数组地址赋给指针 也可以直接使用下标来访问指针指向的数组地址。 同样,可以使用*运算符来访问数组的第一个元素 见09arraypoint.c,4.2数组元素访问与指针,如果希望指针p指向a的第4个元素的地址,怎么办? 方法1:使用 方法2:使用+运算符 p=a+3; 方法2写起来更简单,因此更常见。 思考:想得到字符串str从第3个字符开始的字串,怎么办? 假设str为”12345678”,想得到”45678”。 见10substring.c,4.3 指针地址运算,指针(数组)可以与整数做加减运算,得到的是一个新的地址 假设p指向一个数组,那么: p+1指向
9、数组中的下一个元素。 p-1指向数组中的上一个元素。 p+4指向数组中的后面第4个元素 p-4指向数组中的前面第4个元素 p+令p指向数组中的下一个元素 p令p指向数组中的上一个元素 见11pointmath.c,4.3 指针地址运算,C语言中经常利用地址运算来处理字符串 例:模拟实现strcpy函数 见例12strcpy.c 注意,该程序使用了多个技巧,请认真思考体会: 字符串以0结尾 C语言中将0作为逻辑假,非0作为逻辑真 指针算数+; 函数形参改变不影响实参,4.3 指针地址运算,在C语言中,两个同类型的指针可以做减法。 要让两个指针的减法p2-p1产生有意义的结果,需要满足下面两个条件
10、: p2和p1指向同一个数组的不同元素 p2指向的元素与p1相同,或者在p1指向的元素之后 则p2-p1表示p2和p1之间差多少个元素,即p2指向的元素与p1指向的元素的下标之差 见13strlen.c,计算字符串长度,4.4 数组参数与指针,在函数定义中,将参数类型定义为指针或者定义为数组,效果都是一样的 实际都是定义了一个指针类型的参数。 这是C语言的一个语法糖 /syntax sugar 同样,也可以将数组作为实参传递给指针类型的形参 见例14arrayparam.c,4.5 字符串与指针,使用字符数组与字符指针,最大的区别在于C对它们的初始化的处理上。 例如: char str=“He
11、llo world!”; char s*=“Hello world!”; C会为str在栈上分配一块13字节大小的内存,并将“Hello world!”这13个字符拷贝到这块内存中。 相当于:char str13;strcpy(str,”Hello world!”); 而s只是在栈上分配了4字节大小的内存,然后把“Hello world!”在程序的常量数据区中的地址保存在s中。,4.5 字符串与指针,由于程序的常量区是不可写的,所以在程序中可以修改str的内容,而修改s的内容就会出错! 见:15strchange.c,4.6 练习,已知: int a=0,1,2,3,4,5,6,7,8,9,1
12、0; int *p1=a,*p2=a+10,*p3; 求下列运算的结果:,(7)*(p1+3)+*(a+5) 8 (8)p14+a610 (9)p3=p1;p3+;*p31 (10)p3=a+6;p3-p1;6 (11)p1=a 0 (12)p2=p1 1,(1)p2-p1 10 (2)*(p1) 0 (3)p100 (4)*a0 (5)*(a+5)5 (6)*(p2-3)7,五、指针与动态数组,除了用作函数参数外,指针的另一个重要作用是用来实现动态内存管理。 所谓动态内存,就是指大小、生存期都由你的代码自己来控制一块内存。 主要涉及两个函数,即malloc/表示内存分配和free。/表示内存
13、释放 malloc:在堆(heap)中分配一块指定大小的内存 free:释放之前由malloc分配的内存。 堆的大小只受到操作系统寻址能力的限制(32位指针最大只能表示4G内存) 动态内存最常见的用途之一是实现动态数组。,五、指针与动态数组,普通数组主要有两个缺陷: 数组的大小是程序编写时决定的。为了保证数组的大小够用,通常需要将数组定得很大,导致内存的浪费。 数组的大小受到栈空间大小的限制。 使用动态数组就可以解决这些问题。 见17dynamicarray.c 注意:使用动态内存分配时,一定要注意及时free不需要的内存。否则就会造成内存泄漏。,六、指针与结构,指针除了可以用于指向基本数据类
14、型的地址外,也可以指向结构等自定义类型数据的地址。 结构指针在使用上和普通类型指针没有区别。 可以先用*取指针对应结构的内容,然后用.来访问其成员,如(*p).name 但也可以直接使用-访问结构指针成员,这种用法更常见,如:p-name 例:见18structpoints.c,6.1 结构指针与参数,使用结构指针来作为函数的形参是一种常见的函数定义方式。 好处: 利用结构的成员,一次可以传入多项数据,从而简化了函数的定义和调用 使用结构指针做形参,可以在函数中修改结构的成员 使用结构指针做形参,可以减少函数调用时参数内容复制的开销。 后面我们会大量使用结构指针来做形参!,6.2 链表,利用结
15、构指针,可以实现一种重要的数据结构链表。 使用动态数组,我们可以解决程序编写时,不知道实际元素的数量导致的栈空间浪费问题。 但动态数组依然需要在为数组分配空间之前知道元素的数量! 如果在实际使用中,实际元素的数量是经常动态变化的,那么动态数组依然会有内存浪费的问题。,6.2 链表,数组还存在另一个缺点,就是删除和插入元素的效率问题。 如果要将一个新元素插入到数组的第3个位置上,那么从3到最后的全部元素都必须向后移动一位 同样,删除元素需要将后面的全部元素向前移动一位 链表解决了数组的这些缺点。它也是一种常用的数据结构。它的特点是: 能够动态增加或减少元素 插入或删除某个元素,只会影响和它相邻的
16、两个元素。 搞明白链表及其操作,指针就彻底学会了!,6.2 链表,链表(Chained List/Linked List)在形式上类似于现实中的链条: 由多个结点(node)组成 每个结点中除数据外,还包含一个指针,指向链表中的下一个结点。 通过指针,各结点依次连接成一个链表 我们利用图形的形式来看一下链表,6.2 链表,哨兵,结点1,结点2,结点3,结点4,结点5,NULL,链表头指针head,单向链表的基本形式,struct node int data; struct node* next; ;,6.2 链表,哨兵,结点1,结点2,结点3,结点4,结点5,NULL,链表头指针head,指针
17、变量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /访问数据p-data p=p-next; ,遍历链表,6.2 链表,结点1,结点2,结点3,结点4,结点5,NULL,链表头指针head,指针变量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /访问数据p-data p=p-next; ,遍历链表,哨兵,6.2 链表,结点1,结点2,结点3,结点4,结点5,NULL,链表头指针
18、head,指针变量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /访问数据p-data p=p-next; ,遍历链表,哨兵,6.2 链表,结点1,结点2,结点3,结点4,结点5,NULL,链表头指针head,指针变量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /访问数据p-data p=p-next; ,遍历链表,哨兵,6.2 链表,结点1,结点2,结点3,结点4,结点5,
19、NULL,链表头指针head,指针变量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /访问数据p-data p=p-next; ,遍历链表,哨兵,6.2 链表,结点1,结点2,结点3,结点4,结点5,NULL,链表头指针head,遍历链表,指针变量p,struct node int data; struct node* next; ;,p=head-next; while(p-next!=NULL) /访问数据p-data p=p-next; ,NULL,哨兵,6.2 链表,哨兵,结点
20、1,结点2,结点3,结点4,结点5,链表头指针head,新节点,struct node int data; struct node* next; ;,先使用遍历操作找到接点2; p2-next=p1-next;,插入新结点到结点2、3之间,指针变量p1,指针变量p2,NULL,NULL,6.2 链表,结点1,结点2,结点3,结点4,结点5,链表头指针head,新节点,struct node int data; struct node* next; ;,先使用遍历操作找到接点2; p2-next=p1-next; p1-next-p2;,插入新结点到结点2、3之间,指针变量p1,指针变量p2,N
21、ULL,哨兵,6.2 链表,结点1,结点2,结点3,结点4,结点5,链表头指针head,新节点,struct node int data; struct node* next; ;,先使用遍历操作找到接点2; p2-next=p1-next; p1-next-p2; 整理一下图形,插入新结点到结点2、3之间,指针变量p1,指针变量p2,NULL,哨兵,6.2 链表,结点1,结点2,结点3,结点4,结点5,链表头指针head,新节点,struct node int data; struct node* next; ;,先使用遍历操作找到接点2; p2-next=p1-next; p1-next-
22、p2; 整理一下图形,插入新结点到结点2、3之间,NULL,哨兵,6.2 链表,哨兵,结点1,结点2,结点3,结点4,结点5,NULL,链表头指针head,指针变量p1,struct node int data; struct node* next; ;,令p1指向结点1,p2指向结点2 p1-next=p2-next;,删除结点2,指针变量p2,6.2 链表,结点1,结点2,结点3,结点4,结点5,NULL,链表头指针head,指针变量p1,struct node int data; struct node* next; ;,令p1指向结点1,p2指向结点2 p1-next=p2-next;
23、 整理图形,删除结点2,指针变量p2,哨兵,6.2 链表,结点1,结点3,结点4,结点5,NULL,链表头指针head,struct node int data; struct node* next; ;,令p1指向结点1,p2指向结点2 p1-next=p2-next;,删除结点2,哨兵,6.2 链表,在单向链表的基础上,还可以进一步实现双向链表、循环链表等更复杂的数据结构。 例:输入学生信息,学号为0时结束输入。保存并输出按照学号排序的信息。然后用户每输入一个名字,从存储中删除对应的信息,直到用户输入回车或存储为空为止。 分析: 使用链表保存学生信息 每输入一个学生信息,动态建立一个结点,并插入到合适的位置 最后使用遍历操作来输出学生信息 例:19studentlink.c,七、函数指针,指针实质上是一个内存地址。这个地址不但可以是数据的存放地址,也可以是一段代码的地址。 函数指针就是一个指向函数地址的指针,即指向代码的指针。 函数指针的定义及使用见20funcpoints.c 利用函数指针,可以实现很多非常强大的功能。,7.1 函数指针做参数,使用函数指针做函数的参数,可以用一个函数实现多个功能 例:学生信
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026湖北黄冈市蕲春县李时珍中医药职业技术学校招聘教师19人笔试备考题库及答案详解
- 2026福建三明市湄洲湾职业技术学院招聘编外人员(校聘)43人笔试模拟试题及答案详解
- 职业教育学与职业教育试题及答案
- 职业技能鉴定《药物制剂工》考试试题及答案
- 2026北京大学物理学院量子材料科学中心教学科研岗位招聘(更新)笔试参考题库及答案详解
- 2026鄂州职业大学博士人才引进15人笔试参考题库及答案详解
- 2026广西来宾市忻城县市场监督管理局城镇公益性岗位工作人员招聘1人笔试备考试题及答案详解
- 浙江省温州市住房和城乡建设领域现场专业人员培训考试(监理员)题库及答案(2026年)
- 2026年四川乐山市卫生健康委员会市本级医疗卫生辅助岗位招募27人笔试参考题库及答案详解
- 2025年广东省珠海市社区工作者招聘考试试题及答案详解
- 2025届上海市高考英语考纲词汇表
- DB31-T 1310-2021 火花探测和熄灭系统应用指南
- 2023年6月上海高考英语卷试题真题答案解析(含作文范文+听力原文)
- 透析高钾护理个案
- 牙齿疼痛的物理治疗与药物管理
- 阳春市保力新储能项目环境影响报告表
- 泌尿外科病例讨论02
- 2023新能源集控中心网络与信息安全管理标准
- 头位难产(精)课件
- 工程施工灌浆平洞灌浆施组
- JJF 1637-2017廉金属热电偶校准规范
评论
0/150
提交评论