C语言malloc用法:大容量和不定量内存就靠它
一、malloc()和free()的基本概念以及基本用法使用malloc的情况一开始要讲清楚通过malloc动态申请得来的那个内存空间属于堆式的内存空间而静态的那种内存空间是栈式的关于堆栈的这些知识可以去参考别的相关资料。1. 大容量内存需求a) 传言讲当咱们所需的内存空间超出0.5兆之时最好采用动态内存也就是借助malloc去申请内存空间。能够如此觉得若内存过大就会难以管理而malloc堪称是一位专业的内存管理者然而静态的却能够被当作是一个业余的。毕竟术业有专攻。2. 不确定内存需求a) 啥时候我们所需内存空间大小连自己都不清楚为避免内存空间被浪费就得用到malloc函数。要是把静态内存空间说成是铁盒子那动态内存空间就能看成是可伸缩的袋子这袋子容量能依据所装物体体积不同来定制。当然我们也能利用静态内存而这种情况下会有结果呈现其一是你申请的空间不够用程序就会异常其二是申请的内存过大造成浪费。1、函数原型及说明空指针类型的函数指针malloc其参数为长整形NumBytes函数可按照NumBytes所示字节数进行内存分配之后返回指向所分配内存区域的指针若是分配操作无法达成预期便会返回空指针类型值空指针NULL关于分配失败的原因应该有多种比如说空间不足就是一种。空类型的释放函数其参数为指向首个字节的无类型指针此函数的作用是把先前通过动态内存分配函数所分配的空间归还给程序或者操作系统这种行为也就是对那块内存进行释放操作从而让它再次获得自由状态。2、函数的用法那实际上呢这两个函数在运用的时候倒也算不上是特别困难也就是在执行malloc()操作之后一旦感觉已经使用得足够了就将其舍弃掉把它进行free()处理举个简单的例子来说// Code...char *Ptr NULL;Ptr被指针强制转换为字符指针类型通过使用malloc函数分配内存该内存大小为100个字符类型大小以字节为单位。if (NULL Ptr)exit (1);gets(Ptr);// code...free(Ptr);Ptr NULL;// code...是这样的当然啦针对具体的情形得进行具体的剖析还要具体地去处理。就好比你定义了一个指针在某个函数内申请了一块内存之后经由函数返回将其传递给这个指针那么说不定释放这块内存的这项任务就应当交给其他函数去完成了。3、关于函数使用需要注意的一些地方A、申请了内存空间后必须检查是否分配成功。B、一旦处于不需要再度运用所申请的内存的情形时要记着去实施释放的操作在完成释放之后应当将指向这一块内存的指针设定为指向NULL以此来避免程序在后续运行进程中不经意间运用了它。C、这两个函数理应是配对的要是申请之后不进行释放那便是内存泄露要是毫无缘由的释放那就是什么事情都没做释放仅能有一次要是释放两次以及两次以上就会。发生了错误存在释放空指针之处出现例外情况释放空指针实际上等同于什么都没做因而无论释放空指针多少次都不会存在问题呀。D、尽管malloc()函数的类型为(void *), 任何类型的指针均可转换成(void *), 然而最好还是于前面实施强制类型转换, 因为如此能够避开一。些编译器的检查。二、malloc()到底从哪里得来了内存空间1、它申请内存空间的源头究竟是哪儿呢答案是从堆当中获取空间。这意思是函数返回的指针所指向的是堆那儿的一块内存。操作系统那儿存在着一个记录空闲内存地址的链表。当操作系统获取到程序的申请之时就会对该链表展开遍历而后寻觅首个空间比所申请空间大的堆结点随后把该结点从空闲结点链表里移除并且将该结点的空间分配给程序。就是如此这般提至此不得不额外嵌入一个小话题想必大家也晓得是啥话题了。啥是堆提及堆就不由自主地讲到了栈啥是栈接下来就另起一小部分专门且简要地讲讲这个题外话2、说起来堆是什么堆呀是大家共同拥有的那种空间它又分为全局堆以及局部堆这两种全局堆指的是所有那些尚未被分配出去的空间至于局部堆那便是用户自行分配出来的空间。堆是怎样进行分配的它在操作系统针对进程展开初始化的时候会被分配而且在运行的过程当中也是能够向系统去索要额外的堆的不过要记住用完之后一定要归还给操作系统才行要是不这样做的话那可就是出现内存泄漏的情况了。栈是什么呢栈是线程独有的它用于保存线程的运行状态它还用于保存线程的局部自动变量。栈是在线程开始的时候进行初始化的每个线程的栈是互相独立的。对于每个具体的函数而言其都有属于自己的栈栈被用于在函数之间传递参数。操作系统在切换线程的时候会自动去切换栈而所谓切换栈其实就是切换SS/ESP寄存器。栈空间在高级语言里面是没有必要进行显式的分配和释放操作的。所提及的概念其描述属于标准的那种描述然而存在个别语句被我给删除了不清楚是不是因为如此就变得不再标准了^_^。通过上面对概念的描述可以知道栈是经由编译器自动进行分配以及释放之举的它用于存放函数的参数值还用于存放局部变量的值等。其操作方式和数据结构里的栈相类似。程序员通常会对堆进行分配以及释放操作要是没有进行释放的话当程序结束的时候存在一种可能性那就是会由操作系统进行回收需要注意的是这里所讲的是存在可能性并不是绝对会这样所以我想要再次着重强调一下一定要记得去释放关注它跟数据结构里的堆是完全不同的两码事其分配方式反倒跟链表有相似之处关于这点我在上面略微谈及过。故而比如说要是你于函数之上针对一个指针变量予以定义接着于该函数之中申请了一块内存致使指针指向它。事实上此指针的地址是处于栈上然而它所指向的内容却是在堆之上哟这一要点可得留意呀故而再三斟酌下于一个函数里申请了空间之后好比下面这个函数// code...void Function(void)字符指针p被赋值为通过动态内存分配函数malloc分配100个字符大小内存空间后转换为字符指针类型的值。这个例子千万别觉得函数返回时函数所在的栈被销毁指针也跟着被销毁申请的内存就同样跟着被销毁了这完全错得离谱而原因是申请的内存在堆上函数所在的栈被销毁和堆根本一点关系都没有。所以还是那句话要记得释放3、free()到底释放了什么这一问题相对较为简单实际上我不过是想要与第二大部分的题目形成呼应罢了哈哈free()所释放的乃是指针所指向的内存留意释放的是内存并非指针这一点极其重要指针是一个变量唯有在程序结束之际才会被销毁。在释放了内存空间后原本指向该空间的指针依旧存在只不过此刻指针所指向的内容是垃圾是未定义的故而称之为垃圾。所以先前我已然讲过在释放内存之后要将指针指向NULL以此防止指针在后续不小心再度被解引用了。非常重要啊这一点行了终于把这个所谓的“题外话”给讲完了。仅仅就这么简简单单地说上一回大致了解个梗概就成了接下来便要进入到第三个主要部分三、malloc()以及free()的机制对于这个部分直至今日我才产生了全新的认知并且此认知属于转折性质的因而极有可能这份认知里包涵着更多的错误之处倘若存在错误之处请各位给予指出事实上认真瞧一瞧free()的函数原型说不定也会发觉好像挺奇妙free()函数十分简易仅有一个参数只要将指向申请空间的指针予以传递。向free()里头的参数给予便能达成释放工作于此要追寻至malloc()的申请问题之上了。申请之际实际上所占用的内存相较于申请的而言更大。缘由在于超出的空间乃是用以记载针对这块内存的管理信息。先瞧一瞧于《UNIX环境高级编程》里第七章的一段话绝大多数实现所给予的存储空间相较所需求的会稍微大那么一点儿额外的空间用于记载管理信息涵盖分配块的长度指向往后一个分配块的指针等等。这便表明要是写越过一个已分配区域的末尾那就会改写后面一块的管理信息。此种类型的错误具有灾难性然而鉴于这种错误不会迅速暴露出来故而也就极难被发觉。把指向分配块的指针朝后挪动同样可能会改写本块的管理信息。以上这段话已经给了我们一些信息了。malloc()申请的空间实际我觉得就是分了两个空间这两个空间性质不同。一个空间是用来记录管理信息的另一个空间就是可用空间了。而用来记录管理信息的实际上是一个结构体。在C语言中用结构体来记录同一个对象的不同信息是。天经地义的事下面看看这个结构体的原型struct mem_control_block {这是一个标记存在一个声明为整型的名为is_available的变量整型的大小这是实际存在的空间所具有的大小。};就size而言这是实际存在的空间大小这儿实际上我心存一个疑问is_available是不是一个标记呢源于我查看了free()的源代码随后对这个变量感到有些疑惑源代码于下面进行分析这儿烦请大家予以指出所以free()乃是借由该结构体的相关信息去释放经由malloc()所申请的空间而结构体那两个成员的大小我认为应是操作系统所负责的事情。然而在这里存在着一个状况malloc()申请空间之后返回的一个指针理应是指向那第二种空间的也就是可用空间不然要是指向管理信息空间所写入的内容与结构体的类型就有或许不一致抑或是会将管理信息给屏蔽掉如此一来就没办法去释放内存空间了所以就会出现错误感觉自己在这儿讲的都是些多余的话呢好啦然后来瞧瞧free() 的源代码我自行进行了一番分析发觉相比于malloc() 的源代码而言反倒容易简单了许多。仅仅存在一个疑问在此予以指出// code...void free(void *ptr)结构体类型的内存控制块指针名为free ,且指向的是空闲的内存控制块。取出指针所指位置与结构体成员大小字节数相减后的值将其赋值给名为free的变量该结构体为内存控制块结构体。free-is_available 1;return;瞧一瞧函数的第二句话此句极为重要且关键实际上这句话就是将指向可用空间的指针往回倒使其指向管控信息的那块空间体原因是在此处从值上减掉了一个结构体的大小尺寸后面紧接着的那句free-is_available 1;让我感到有些疑惑不解我的思考观点是此地is_available应当仅仅只是一个标记罢了因为从这个变量的名称层面观察is_available翻译过来便是“是可以用”可别讲我土里土气哦我感觉变量的名字能够体现出一个变量所具备的作用尤其是那些严密的代码。这属于源代码因而我认定绝对是严密的此变量的值为1这意味着是能够使用的空间只是在这儿我思索了一番要是把它改成0或者是别的值不清楚会出现什么状况然而有一点我能够确定那就是释放绝对不会那般顺遂地开展由于这是一个标记当然这里说不定依旧会有人存有疑问为啥如此这般就能释放我刚刚也有过这个疑问。随后我想到释放乃是操作系统的事儿那么就free()这个源代码而言啥都没释放对不然而它的确是明确了管理信息的那块内存的内容。所以free()仅仅是记录了一些信息接着告知操作系统那块内存能够去释放具体是怎样告知操作系统的我不清楚可我觉着这已然超出了我这篇文章的探讨范畴了。那么我之前存在过一种错误见解是以为什么样的指针指向那块内存不管它移至那块内存里的哪一处位置后皆能够成功释出那块内存然而这绝对是大错特错了释放并不是能够去释放其中那一部分的首先这一点理应得明白。并且从free()的源代码方面来看ptr仅仅能够指向可用空间的起始地址不然的话在减去结构体大小而后必定不会是指向管理信息空间的起始地址。所以务必要保证指针指向可用空间的起始地址难道不信吗自行去写一个程序接着移动指向可用空间的指针瞧瞧程序究竟会不会崩溃也许最终会想要去瞧一瞧malloc()的源代码以此弄明白malloc()究竟是怎样进行空间分配的而在此过程当中是关联到诸多其他层面的知识的