转自:https://blog.csdn.net/david_xtd/article/details/7311204

名称

malloc,free,calloc,realloc--分配和释放动态内存

概要

#include <stdlib.h>

void *malloc(size_tsize);

void free(void *ptr);

void *realloc(void*ptr, size_t size);

void *calloc(size_tnmemb, size_tsize);

描述

malloc()函数分配size个字节的内存并返回指向已分配内存的指针。该内存未初始化。如果size为0,malloc()或者返回空指针NULL,或者返回能成功传给free()函数的唯一的指针值。

free()函数释放指针ptr指向的内存空间,ptr必须是调用malloc()、calloc()或realloc()时返回的指针值,否则,或者如果free(ptr)已经被调用过了,会发生不确定的行为。如果ptr是空指针NULL,则不会执行任何操作。

calloc()函数为一个nmemb个元素大小为size个字节的数组分配内存并返回指向已分配内存的指针。已分配内存的内容被清零。如果nmembsize为0,calloc()或者返回空指针NULL,或者返回能成功传给free()函数的唯一的指针值。

realloc()函数改变ptr指向的内存块的大小为size个字节。从内存块的起始地址到新旧大小最小值之间区域的内容不变。如果新的内存块大于原来的内存块,新增加的内存被初始化。如果ptr是空指针NULL,对于所有size来说,该调用就等效于malloc(size);如果size为0,并且ptr是非空指针NULL,则该调用等效于free(ptr)。只要ptr是非空指针NULL,则必须是之前调用malloc()、calloc()或realloc()时返回的指针值。如果指向的区域移动了,会进行free(ptr)操作。

返回值

malloc()函数和calloc()函数返回指向已分配区域的指针。该内存对于任何类型的变量都已经合理地对齐。出错时,返回空指针NULL。空指针也可能在成功调用当size为0的malloc()函数时返回,或成功调用nememb为0或size为0的calloc()函数时返回。

free()函数没有返回值。

realloc()函数返回指向新分配内存区的指针,该内存区已对于任何类型的变量已合理对齐,该指针可能与ptr不同,或者当请求失败时返回空指针NULL。如果size为0,或者返回空指针NULL,或者返回要传给free()函数的合适的指针。如果realloc()函数失败,原来的内存块不受影响,既未移动,也未释放。

注释

通常,malloc()函数自堆中分配内存,并使用sbrk根据需求调整堆的大小。当正在分配的内存块大于MMAP_THRESHOLD字节数时,glibc的malloc()实现使用mmap将内存的分配当作私有的匿名映射。MMAP_THRESHOLD缺省是128KB,但可以使用mallopt调整大小。使用mmap进行的内存分配不受RLIMIT_DATA资源限制的影响。

UNIX 98标准要求malloc()、calloc()和realloc()在出错时设定errnoENOMEM。Glibc假定这些要求都已经实现。如果用户使用了没有设定errno的私有的malloc实现,某些特定的库函数在errno上可能会毫无理由地失败。

英文网址:http://www.kernel.org/doc/man-pages/online/pages/man3/free.3.html

使用注意事项

1. 函数使用中需要注意:

A、申请了内存空间后,必须检查是否分配成功。

B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止后面程序不小心使用了它。

C、这两个函数应该是配对的。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。只能释放一次,如果释放两次及两次以上会

出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。

D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一

些编译器的检查。

2. malloc()从堆得到内存空间。

堆是大家共有的空间(分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间)。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。

与之对应的是栈。栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。

通过上述内容,malloc()和free()只会涉及到堆的使用,可由用户控制;(为防止内存泄露,malloc()使用结束一定要记得释放!!)

而栈的使用是由系统自动控制的,无需用户介入。

3. malloc()和free()的机制

free()函数非常简单,只有一个参数,只要把指向申请空间的指针传递给free()中的参数就可以完成释放工作。

这里要追踪到malloc()的申请问题了。申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。

malloc()申请的空间实际我觉得就是分了两个不同性质的空间。一个就是用来记录管理信息的空间,另外一个就是可用空间了。而用来记录管理信息的实际上是一个结构体。

在C语言中,用结构体来记录同一个对象的不同信息是天经地义的事!下面看看这个结构体的原型:

程序代码:
   struct mem_control_block {
    int is_available;    //这是一个标记?
    int size;            //这是实际空间的大小
    };

对于size,这个是实际分配空间大小。

   下面看看free()的源代码。

程序代码:

  1. // code...
  2. void free(void *ptr) {
  3. struct mem_control_block *free;
  4. free = ptr - sizeof(struct mem_control_block);
  5. free->is_available = 1;
  6. return;
  7. }

看一下函数第二句,这句非常重要和关键。其实这句就是把指向可用空间的指针倒回去,让它指向管理信息的那块空间,因为这里是在值上减去了一个结构体的大小!

图示如下:

该文作者原先有错误的认识,就是认为指向那块内存的指针不管移到那块内存中的哪个位置都可以释放那块内存!

但是,这是大错特错!释放是不可以释放一部分的!首先这点应该要明白。而且,从free()的源代码看,ptr只能指向可用空间的首地址,不然,减去结构体大小之后一定不是指向管理信息空间的首地址。所以,要确保指针指向可用空间的首地址!

该错误认识通过上图更能清晰地看出来,只有当ptr指向可用空间的首地址时,在ptr减去struct mem_control_block的大小后才能使得后面的语句free->is_available得到有效数值。否则,传给系统的数值就肯定不是正确的,由此造成的后果也不可预测了。

4. 错误使用举例。

  1. int main(int argc, char *argv[])
  2. {
  3.  
  4. char *buffer = NULL, *str = NULL;
  5. char *a = "abcdefghij";
  6.  
  7. int length = 10, i = 0;
  8.  
  9.  
  10. buffer = (char *)malloc(length * sizeof(char));
  11. if(!buffer) {
  12.  
  13. printf("1:malloc error!\n");
  14. return 0;
  15.  
  16. }
  17. memset(buffer, 0, length);
  18. for(i = 0; i < length - 1; i++) {
  19.  
  20. *buffer++ = a[i];
  21.  
  22. }
  23. fprintf(stderr, "buffer: %s\n", buffer);
  24.  
  25. free(buffer);
  26.  
  27.  
  28. str=(char *)malloc(length * sizeof(char));
  29. if(!str) {
  30.  
  31. printf("2:malloc error!\n");
  32. return 0;
  33.  
  34. }
  35. memset(str, 0, length);
  36. for(i = 0; i < length - 1; i++) {
  37.  
  38. str[i] = a[i];
  39.  
  40. }
  41. fprintf(stderr, "str: %s\n", str);
  42. free(str);
  43.  
  44. }

上面程序中同样使用malloc()函数为buffer和str分配了10个字节的内存,最后都通过free()的方式释放内存。其中,malloc(str)和free(str)都是正确的,而malloc(buffer)和free(buffer)就错了。因为指针buffer的值发生改变,已经不再是通过malloc(buffer)返回的指针值了。

总之,一句话,为防止内存泄露,malloc()使用结束一定要记得用free(ptr)释放!!

并且,ptr一定要是malloc()分配时得到的指针地址

malloc()和free()机制等部分转载了bccn作者ID:lj_860603(键键)的文章,如下:

http://www.bccn.net/Article/kfyy/cyy/jszl/200608/4238_2.html

malloc()函数(Linux程序员手册)及函数的正确使用【转】的更多相关文章

  1. DOS程序员手册(一)

    当今MS-Windows横扫大江南北,让我们这就来研究一下它的祖宗——MS-DOS! 这本书很难得,希望读者好好学习! DOS程序员手册(一) DOS教程 (以下内容全部为原作者的阐述,照样保留) 这 ...

  2. PowerShell:Linux程序员喜欢的cmd增强版

    Linux程序员有时偶尔使用Windows下的cmd工具,会被逼疯的,有些命令ls, cat, ps等已经条件反射一样使用. 但在cmd下,根本不知道该用什么命令,好在盖兹大叔照顾了此部分需求.从Vi ...

  3. 函数sql黑马程序员——SQL常用函数

    最近使用开辟的过程中出现了一个小问题,顺便记录一下原因和方法--函数sql ---------------------- ASP.Net+Android+IO开辟S..Net培训.等待与您交流! -- ...

  4. 做10年Windows程序员与做10年Linux程序员的区别

    如果一个程序员从来没有在linux,unix下开发过程序,一直在windows下面开发程序, 同样是工作10年, 大部分情况下与在linux,unix下面开发10年的程序员水平会差别很大.我写这篇文章 ...

  5. 做10年Windows程序员与做10年Linux程序员的区别(附无数评论)(开源软件相当于熟读唐诗三百首,不会作诗也会吟)

    如果一个程序员从来没有在linux,unix下开发过程序,一直在windows下面开发程序, 同样是工作10年, 大部分情况下与在linux,unix下面开发10年的程序员水平会差别很大.我写这篇文章 ...

  6. DOS程序员手册(九)

    第14章参考手册概述     本书余下的章节将向读者们介绍BIOS.DOS各种各样API函数和服务,作为一名程 序员,了解和掌握这些知识是很有好处的.在所介绍的参考手册中,每部手册都汇集了大 量的资源 ...

  7. DOS程序员手册(八)

    备,就可以从程序中访问驱动程序.可以用句柄功能调用来     打开设备(见列表12.9)         列表12.9           /*example.C               List ...

  8. DOS程序员手册(七)

    第11章      中断处理程序 本章将深入到DOS系统内部探讨中断处理程序的内容.与其他计算机编程不一样, 中断处理程序这个名词听起来就很难懂.用最简单的话来说,中断处理程序就是对应于中 断激活的程 ...

  9. DOS程序员手册(六)

    217页 程序的主要部分后面是主程序所使用的许多小的扩充内存功能.将这些功能组合起 来这些功能便覆盖了扩充内存的操作,尽管还可能想向它们添加错误检查. 程序所包含的函数有: emmtest   检验内 ...

随机推荐

  1. luogu2279 消防局的设立 (贪心)

    按点的深度从大到小排序,每次取出深度最大的那个点,如果它还没被覆盖,就在它爷爷上放一个消防局,这样一定是最优的 为了判定是否被覆盖,可以记录从某点的子树中到这个点的最近消防局的距离dis[](如果没有 ...

  2. vue-loader 作用

    vue-loader:解析和转换 .vue 文件,提取出其中的逻辑代码 script.样式代码 style.以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理. cs ...

  3. apigateway-kong(七)配置说明

    这一部分应该在最开始介绍,但是我觉得在对kong有一定了解后再回头看下配置,会理解的更深刻.接下来对这个配置文件里的参数做个详细的解释便于更好的使用或优化kong网关. 目录 一.配置加载 二.验证配 ...

  4. 常量引用 const T&

    1.引用本身不是对象,只是引用对象的别名,没有内存空间产生 2.引用必须严格类型匹配 3.而常量引用 const T& 可以引用字面值常量及表达式 其实也就是右值,且常量引用的不同与T类型对象 ...

  5. (原)2018牛课多校第4场--G

    传送门 /* 按值从大到小排序,记录下相应出现的次数并去重 枚举:从大到小枚举,如果能够通过删除其他数让当前这个数成为众数,则循环结束,输出此数,如果循环结束也没答案,输出-1 优先级:值优先 举例: ...

  6. Spark进阶之路-Standalone模式搭建

    Spark进阶之路-Standalone模式搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Spark的集群的准备环境 1>.master节点信息(s101) 2&g ...

  7. Python新手入门英文词汇笔记(转)

    一.交互式环境与print输出 1.print:打印/输出2.coding:编码3.syntax:语法4.error:错误5.invalid:无效6.identifier:名称/标识符7.charac ...

  8. secure CRT the remote system refused the connection 解决办法

    1.安装ssh服务器和客户端 apt-get install openssh-server apt-get install openssh-client 2.重启ssh /etc/init.d/ssh ...

  9. 为什么推荐InnoDB引擎使用自增主键?

    索引使用时遇到的问题(顺丰)--InnoDB引擎不使用自增主键导致性能问题,也可答最左前缀 InnoDB自增主键 InnoDB主索引(同时也是数据文件)的示意图: 上文讨论过InnoDB的索引实现,I ...

  10. 【JUC】CopyOnWriteArrayList

    写入时复制(CopyOnWrite) 什么是CopyOnWrite容器 CopyOnWrite容器即写时复制的容器.通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进 ...