您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > C语言动态分配内存.
C语言动态分配内存什么时候需要动态分配内存?实例:顺序对一批文件进行解析,但是不知道文件的大小,如何建立缓冲区?malloc函数原型:void*malloc(size_tn);n是要分配的内存的大小,返回值是分配内存的块的首地址例1:使用malloc函数分配一个可以容纳10个整型元素的内存空间,并将其用作一个整型数组关键代码:int*array;array=(int*)malloc(10*sizeof(int));注意:内存大小不能写成数组元素的个数例2:定义一个结构structtest{inta;charb;intc[10];};使用malloc函数分配一个此种结构类型的对象关键代码:structtest*p;p=(structtest*)malloc(sizeof(structtest));(1)malloc函数是一个库函数,它并不是C语言中的关键字:需要头文件stdlib.h才可以使用该函数并不是所有的平台都可以使用该函数,尤其是一些单片机系统(2)指针类型转换是必须的,关系到接收分配好的内存块的地址可以向前看多少字节。如果不做指针类型转换会怎么样?void*指针存在的意义。(3)内存块大小的可移植性问题分配一个整型变量数组应使用:数组元素个数*sizeof(int)确定内存块的大小问题:sizeof和strlen函数的区别free函数原型:voidfree(void*p);p是要释放的已分配内存的块的首地址释放一块动态分配的内存:例如:int*p;p=(int*)malloc(sizeof(int));free(p);(1)free函数同样是一个库函数(2)free函数的参数必须是一个由动态内存分配方法分配的内存块的首地址(使用malloc函数分配的内存)内存空间大小可以是一个变量,其值在运行时确定内存空间在运行时分配,在程序结束时收回;内存的分配由操作系统参与完成动态分配的内存空间在未释放之前均可以被引用,保证其生命期structnode{intnode;/*数据域,存储结点的值*/structnode*next;};value1value2value3value4NULL动态申请内存:void*malloc(size_tn);释放动态内存:voidfree(void*);structnode*p=&b;a.next=p;/*连接a结点和b结点*/b.next=&c;/*连接b结点和c结点*/structnode*p=&b;a.next=b.next;/*连接a结点和c结点*/free(p);/*摘下的b结点一定要释放掉*/设计一个学生链表,其每个结点是一个学生信息的集合。每个结点包含如下信息:学生姓名、学号、C语言成绩三项。初始时拥有3个学生,添加一个学生(使用一个函数实现此操作),再删除一个学生(使用另一个函数实现此操作),并打印该学生的信息。结点结构:structinfo{charname[10];intid;intscore;};structstd{structinfo;structstd*next;};main函数:intmain(void){/*初始化学生链表*//*插入一个学生信息结点*//*删除一个学生的信息,并且打印*/return0;}intinsert(char*name,intid,intscore){/*分配一个structstd结构对象*//*将参数赋值到结构对应的成员中*/return1;/*正确完成操作,返回1*/}intremove(intid,structstd**res){/*根据id找到该学生的信息结点*//*将该结点从链表上取下*//*使用res保存该节点*//*释放该结点所占用的内存*/return1;/*成功操作返回1*/}(1)实现print函数对其遍历打印链表(2)实现destroy函数释放每一个链表节点(3)实现search函数查找链表中的元素(4)实现一个升级版的insert将元素按顺序插入(5)实现一个升级版的search函数按顺序查找(6)实现get_count函数得到链表元素个数两个扩展函数:(1)实现一个链表排序函数,使用冒泡排序的方法。(2)遍历一个链表,找到链表的中点节点。(3)寻找某一个节点之前的那个节点calloc函数void*calloc(size_tnum,size_tsize);relloc函数void*realloc(void*mem_address,unsignedintnewsize);实现一个可变的数组,从一个键盘输入若干个数字,以-1结尾。并将其逆序输出。提示:作为数组的缓冲区的大小是固定的,当读取的数字的数目超过数组大小的时候需要使用realloc函数扩展缓冲区数组。实现一个realloc函数深入理解动态分配内存的内部机制代码段数据段环境变量和命令行参数栈堆进程地址空间分配原则——最先适合分配方法malloc内部调用sbrk()系统调用一个进程使用一个堆,所有内存由操作系统管理问题:如果申请一个内存并没有释放,当进程结束运行的时候,会造成内存泄露么吗?内存控制块结构定义:structmem_control_block{intis_available;/*该块是否可用*/intsize;/*该块的大小*/};两个重要的全局变量堆底,分配块的第一块:void*managed_memory_start;堆顶,分配块的最后一块void*last_valid_address;函数的参数:void*malloc(longnumbytes){……}numbytes是要申请的字节数,但是并不包括内存控制块结构,也就是说我们实际需要的空间是numbytes+sizeof(structmem_control_block)几个重要的局部变量:void*current_location;structmem_control_block*current_location_mcb;void*memory_location;重要的语句:numbytes=numbytes+sizeof(structmem_control_block);/*得到完整的需要空间,用户需要的空间+内存控制块结构*/current_location=managed_memory_start;/*从内存块队列的头开始遍历整个内存队列*/while(current_location!=last_valid_address){current_location_mcb=(structmem_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;}如果现有的内存块不能满足需要: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;}memory_location=memory_location+sizeof(structmem_control_block);/*返回给用户可用内存的地址,跳过内存控制块结构*/returnmemory_location;/*返回*/malloc代码大部分都由库来完成,为什么还要有这个系统调用?这个系统调用做了什么?为什么只有内存增加的时候需要系统干预?现代操作系统的存储机制voidfree(void*firstbyte){structmem_control_block*mcb;mcb=firstbyte-sizeof(structmem_control_block);mcb-is_available=1;/*这一步是最关键的*/return;}并不是真正的释放,只是将内存块标记为可用。问题1:释放内存后,系统显示的可用内存数会发生改变吗?问题2:释放的内存还可以引用吗?(1)当申请0个字节时会出现什么情况例如:int*p;p=(int*)malloc(0);(2)释放一个非动态内存申请的空间例如:intarray[10],*p;p=array;free(p);动态分配内存和非动态分配内存的比较动态分配内存非动态分配内存大小在编译时确定大小在运行时确定由编译器分配由操作系统参与分配分配在数据段和栈内在堆内由操作系统自动释放手动显式释放如果需要将一块内存设置为同一个值的时候,需要使用memset函数。例如:分配一个缓冲区,将该缓冲区内的值清零voidmemset(void*s,intn,size_tsize);s:需要设置内存的首地址n:需要被设置的值size:需要设置的字节数#includestdio.hintmain(){chars[10];memset((void*)s,‘a’,10);s[10]=‘\0’;printf(“%s\n”,s);return0;}输出结构为:aaaaaaaaa使用memset函数和malloc函数实现一个calloc函数#includestdio.hintmain(){chars[10];memset((void*)s,‘a’,10);s[10]=‘\0’;printf(“%s\n”,s);return0;}输出结构为:aaaaaaaaa当需要在两块内存之间进行数据拷贝的时候需要使用memcpy函数其原形为:void*memcpy(void*dest,constvoid*src,size_tn);dest:复制到目的地址src:复制的源地址n:需要复制的字节数#includestdio.hintmain(){chars[]=“hello”,d[10];memcpy(d,s,5);d[5]=‘\0’;printf(“%s”,d);return0;}运行结果:hellovoidbzero(void*s,size_tn);voidbcopy(void*dest,constvoid*src,size_tn);memccpy(拷贝内存内容)定义函数void*memccpy(void*dest,constvoid*src,intc,size_tn);函数说明memccpy()用来拷贝src所指的内存内容前n个字节到dest所指的地址上。与memcpy()不同的是,memccpy()会在复制时检查参数c是否出现,若是则返回dest中值为c的下一个字节地址。返回值为0表示在src所指内存前n个字节中没有值为c的字节。memcmp(比较内存内容)相关函数bcmp,定义函数intmemcmp(constvoid*s1,constvoid*s2,size_tn);函数说明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(拷贝内存内
本文标题:C语言动态分配内存.
链接地址:https://www.777doc.com/doc-2908830 .html