C语言动态分配内存

上传人:ning****hua 文档编号:243030490 上传时间:2024-09-14 格式:PPT 页数:62 大小:2.87MB
返回 下载 相关 举报
C语言动态分配内存_第1页
第1页 / 共62页
C语言动态分配内存_第2页
第2页 / 共62页
C语言动态分配内存_第3页
第3页 / 共62页
点击查看更多>>
资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,1,动态内存分配基础,2,动态内存分配实例,3,动态内存分配进阶,C,语言动态分配内存,动态分配,内存基础,动态分配内存概述,什么时候需要动态分配内存?,实例:顺序对一批文件进行解析,但是不知道文件的大小,如何建立缓冲区?,malloc,函数,malloc,函数原型:,void * malloc(size_t n);,n,是要分配的内存的大小,返回值是分配内存的块的首地址,malloc,函数,例,1,:使用,malloc,函数分配一个可以容纳,10,个整型元素的内存空间,并将其用作一个整型数组,malloc,函数,关键代码:,int * array;,array = (int *)malloc(10 * sizeof(int);,注意:内存大小不能写成数组元素的个数,malloc,函数,例,2,:定义一个结构,struct test,int a;,char b;,int c10;,;,使用,malloc,函数分配一个此种结构类型的对象,malloc,函数,关键代码:,struct test * p;,p = (struct test *)malloc(sizeof(struct test);,需要注意的问题,(1)malloc,函数是一个库函数,它并不是,C,语言中的关键字:,需要头文件,才可以使用该函数,并不是所有的平台都可以使用该函数,尤其是一些单片机系统,需要注意的问题,(2),指针类型转换是必须的,关系到接收分配好的内存块的地址可以向前看多少字节。,如果不做指针类型转换会怎么样?,void *,指针存在的意义。,需要注意的问题,(3),内存块大小的可移植性问题,分配一个整型变量数组应使用:,数组元素个数 *,sizeof(int),确定内存块的大小,问题:,sizeof,和,strlen,函数的区别,free,函数,free,函数原型:,void free(void * p);,p,是要释放的已分配内存的块的首地址,free,函数,释放一块动态分配的内存:,例如:,int *p;,p = (int *)malloc(sizeof(int);,free(p);,需要注意的问题,(1)free,函数同样是一个库函数,(2)free,函数的参数必须是一个由动态内存分配方法分配的内存块的首地址(使用,malloc,函数分配的内存),动态分配内存特点,内存空间大小可以是一个变量,其值在运行时确定,内存空间在运行时分配,在程序结束时收回;内存的分配由操作系统参与完成,动态分配的内存空间在未释放之前均可以被引用,保证其生命期,链表,链表的概述,struct node,int node; /*,数据域,存储结点的值 *,/,struct node * next;,;,链表示意图,value,1,value,2,value,3,value,4,NULL,处理链表使用的函数,动态申请内存:,void * malloc(size_t n);,释放动态内存:,void free(void *);,插入一个结点,struct node *p = ,a.next = p; /*,连接,a,结点和,b,结点 *,/,b.next = /*,连接,b,结点和,c,结点 *,/,删除一个结点,struct node *p = ,a.next = b.next; /*,连接,a,结点和,c,结点 *,/,free(p); /*,摘下的,b,结点一定要释放掉*,/,动态,内存分配实例,动态内存分配实例,设计一个学生链表,其每个结点是一个学生信息的集合。每个结点包含如下信息:学生姓名、学号、,C,语言成绩三项。初始时拥有,3,个学生,添加一个学生,(,使用一个函数实现此操作,),,再删除一个学生,(,使用另一个函数实现此操作,),,并打印该学生的信息。,实例关键点分析,结点结构:,struct info,char name10;,int id;,int score;,;,struct std,struct info;,struct std * next;,;,实例关键点分析,main,函数,:,int main(void),/*,初始化学生链表 *,/,/*,插入一个学生信息结点 *,/,/*,删除一个学生的信息,并且打印 *,/,return 0;,实例关键点分析,int insert(char * name, int id, int score),/*,分配一个,struct std,结构对象 *,/,/*,将参数赋值到结构对应的成员中 *,/,return 1; /*,正确完成操作,返回,1 */,实例关键点分析,int remove(int id,,,struct std * res),/*,根据,id,找到该学生的信息结点 *,/,/*,将该结点从链表上取下 *,/,/*,使用,res,保存该节点 *,/,/*,释放该结点所占用的内存 *,/,return 1; /*,成功操作返回,1 */,综合实例,(,1,)实现,print,函数对其遍历打印链表,(,2,)实现,destroy,函数释放每一个链表节点,(,3,)实现,search,函数查找链表中的元素,(,4,)实现一个升级版的,insert,将元素按顺序插入,(,5,)实现一个升级版的,search,函数按顺序查找,(,6,)实现,get_count,函数得到链表元素个数,综合实例,两个扩展函数:,(,1,)实现一个链表排序函数,使用冒泡排序的方法。,(,2,)遍历一个链表,找到链表的中点节点。,(,3,)寻找某一个节点之前的那个节点,类,malloc,函数,calloc,函数,void *calloc( size_t num, size_t size );,relloc,函数,void *realloc(void *mem_address, unsigned int newsize);,综合实例,实现一个可变的数组,从一个键盘输入若干个数字,以,-1,结尾。并将其逆序输出。,提示:作为数组的缓冲区的大小是固定的,当读取的数字的数目超过数组大小的时候需要使用,realloc,函数扩展缓冲区数组。,综合实例,实现一个,realloc,函数,动态,内存分配进阶,深入理解动态分配内存的内部机制,堆和栈,代码段,数据段,环境变量和命令行参数,栈,堆,进程地址空间,malloc,函数的机制,分配原则,最先适合分配方法,malloc,内部调用,sbrk(),系统调用,一个进程使用一个堆,所有内存由操作系统管理,问题:如果申请一个内存并没有释放,当进程结束运行的时候,会造成内存泄露么吗?,malloc,函数的实现,内存控制块结构定义:,struct,mem_control_block,int,is_available; /*,该块是否可用 *,/,int,size; /*,该块的大小 *,/;,malloc,函数的实现,两个重要的全局变量,堆底,分配块的第一块:,void,*managed_memory_start;,堆顶,分配块的最后一块,void,*last_valid_address;,malloc,代码分解,函数的参数:,void,*malloc(long,numbytes),numbytes,是要申请的字节数,但是并不包括内存控制块结构,也就是说我们实际需要的空间是,numbytes + sizeof(struct,mem_control_block),malloc,代码分解,几个重要的局部变量:,void,*current_location;,struct,mem_control_block,*current_location_mcb;,void,*memory_location;,malloc,代码分解,重要的语句:,numbytes,=,numbytes,+,sizeof(struct,mem_control_block); /*,得到完整的需要空间,用户需要的空间,+,内存控制块结构 *,/,current_location,=,managed_memory_start; /*,从内存块队列的头开始遍历整个内存队列 *,/,malloc,代码分解,while(current_location,!=,last_valid_address),current_location_mcb,= (struct,mem_control_block,*)current_location;,if(current_location_mcb-is_available) if(current_location_mcb-size,=,numbytes),current_location_mcb-is_available,=,0;,memory_location,=,current_location;,break;,current_location,=,current_location,+ current_location_mcb-size;,malloc,代码分解,如果现有的内存块不能满足需要:,if(!,memory_location) ,sbrk(numbytes);,memory_location,=,last_valid_address;,last_valid_address,=,last_valid_address,+,numbytes;,current_location_mcb,=,memory_location;,current_location_mcb-is_available,=,0;,current_location_mcb-size,=,numbytes;,malloc,代码分解,memory_location,=,memory_location,+,sizeof(struct,mem_control_block); /*,返回给用户可用内存的地址,跳过内存控制块结构 *,/,return,memory_location; /*,返回 *,/,sbrk,系统调用,malloc,代码大部分都由库来完成,为什么还要有这个系统调用?,这个系统调用做了什么?,为什么只有内存增加的时候需要系统干预?,现代操作系统的存储机制,free,函数的实现,void,free(void,*firstbyte),struct,mem_control_block,*mcb;,mcb,=,firstbyte,-,sizeof(struct,mem_control_block);,mcb-is_available,=,1; /*,这一步是最关键的 *,/,return;,free,机制总结,并不是真正的释放,只是将内存块标记为可用。,问题,1,:释放内存后,系统显示的可用内存数会发生改变吗?,问题,2,:释放的内存还可以引用吗?,非常规使用,(1),当申请,0,个字节时会出现什么情况,例如:,int *p;,p = (int *)malloc(0);,(2),释放一个非动态内存申请的空间,例如:,int array10, *p;,p = array;,free(p);,两种内存分配的比较,动态分配内存和非动态分配内存的比较,动态分配内存,非动态分配内存,大小在编译时确定,大小在运行时确定,由编译器分配,由操作系统参与分配,分配在数据段和栈内,在堆内,由操作系统自动释放,手动显式释放,memset,函数概念,如果需要将一块内存设置为同一个值的时候,需要使用,memset,函数。,例如:,分配一个缓冲区,将该缓冲区内的值清零,memset,函数原形,void memset(void *s, int n, size_t size);,s,:需要设置内存的首地址,n,:需要被设置的值,size,:需要设置的字节数,memset,函数实例,#include ,int main(),char s10;,memset(void *)s,a, 10);,s10 =,0,;,printf(,“,%sn,”, s);,return 0;,输出结构为:,aaaaaaaaa,综合实例,使用,memset,函数和,malloc,函数实现一个,calloc,函数,memset,函数实例,#include ,int main(),char s10;,memset(void *)s,a, 10);,s10 =,0,;,printf(,“,%sn,”, s);,return 0;,输出结构为:,aaaaaaaaa,memcpy,函数概念,当需要在两块内存之间进行数据拷贝的时候需要使用,memcpy,函数,其原形为:,void * memcpy(void *dest, const void * src, size_t n);,dest,:复制到目的地址,src,:复制的源地址,n,:需要复制的字节数,memcpy,函数实例,#include ,int main(),char s =,“,hello,”, d10;,memcpy(d, s, 5);,d5 =,0,;,printf(,“,%s,”, d);,return 0;,运行结果:,hello,替代函数,void bzero(void *s, size_t n);,void bcopy(void * dest, const void * src, size_t n);,其它内存块操作的函数,memccpy,(拷贝内存内容),定义函数,void * memccpy(void *dest, const void * src, int c,size_t n);,函数说明,memccpy(),用来拷贝,src,所指的内存内容前,n,个字节到,dest,所指的地址上。与,memcpy(),不同的是,,memccpy(),会在复制时检查参数,c,是否出现,若是则返回,dest,中值为,c,的下一个字节地址。返回值为,0,表示在,src,所指内存前,n,个字节中没有值为,c,的字节。,其它内存块操作的函数,memcmp,(比较内存内容) 相关函数,bcmp,,定义函数,int memcmp (const void *s1,const void *s2,size_t n);,函数说明,memcmp(),用来比较,s1,和,s2,所指的内存区间前,n,个字符。字符串大小的比较是以,ASCII,码表上的顺序来决定,次顺序亦为字符的值。,memcmp(),首先将,s1,第一个字符值减去,s2,第一个字符的值,若差为,0,则再继续比较下个字符,若差值不为,0,则将差值返回。例如,字符串,Ac,和,ba,比较则会返回字符,A(65),和,b(98),的差值,(,33),。返回值 若参数,s1,和,s2,所指的内存内容都完全相同则返回,0,值。,s1,若大于,s2,则返回大于,0,的值。,s1,若小于,s2,则返回小于,0,的值。,其它内存块操作的函数,memmove,(拷贝内存内容),定义函数,void * memmove(void *dest,const void *src,size_t n);,函数说明,memmove(),与,memcpy(),一样都是用来拷贝,src,所指的内存内容前,n,个字节到,dest,所指的地址上。不同的是,当,src,和,dest,所指的内存区域重叠时,,memmove(),仍然可以正确的处理,不过执行效率上会比使用,memcpy(),略慢些。,需要注意的问题,以上函数需要使用的头文件为,string.h,进行内存块复制的时候要注意目的地址和源地址交叉的问题,动态内存分配基础,:,1 malloc,函数,2 free,函数,3,动态内存分配的特点动态内存分配进阶,:,1,堆和栈的存储布局,2 malloc,函数的内部机制,3 malloc,函数的实现,4 sbrk(),系统调用,5 free,函数的内部机制,6 free,函数的实现,7,动态内存分配和静态内存分 配的比较,8,类,malloc,函数,本次课程知识点总结,Thank you,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!