自上次发现自己对这几个C函数不熟悉,就打算抽空整理一下,也就现在吧。这几个函数都是跟堆内存打交道的,还有一个好玩的函数--alloca,它是跟栈内存打交道的,我想留在以后研究出好玩点的来,再专门为其写一篇铭文。

1.malloc:

头文件:<stdlib.h>

原型:extern void *malloc(unsigned int num_bytes);

功能:分配长度为num_bytes字节的内存块。如果分配成功则返回指向被分配内存的指针,否则返回NULL。

机理:malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。如果无法获得符合要求的内存块,malloc函数会返回NULL指针,因此在调用malloc动态申请内存块时,一定要进行返回值的判断。

2.realloc:

头文件:<stdlib.h>

原型:extern void *realloc(void *mem_address, unsigned int newsize);

功能:改变指针mem_address所指向区域的大小为newsize。如果成功则返回指针mem_address,否则返回NULL。

机理:先判断当前的指针mem_address是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

3.calloc:

头文件:<stdlib.h>

原型:void* calloc(size_t n, size_t size);

功能: 在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。

机理:在malloc的基础上加上内存空间清0操作。

4.free:

头文件:<stdlib.h>

原型:void free (void* ptr);

功能:释放指针ptr指向的堆内存。

5.Example

#include <stdlib.h>     /* malloc, calloc, realloc, free */

int main ()
{
int * buffer1, * buffer2, * buffer3;
buffer1 = (int*) malloc (*sizeof(int));
buffer2 = (int*) calloc (,sizeof(int));
buffer3 = (int*) realloc (buffer2,*sizeof(int));
free (buffer1);
free (buffer3);
return ;
}

下面是好玩的地方:

1.malloc与calloc的区别:函数malloc不能初始化所分配的内存空间,而函数calloc能。函数calloc() 会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为0;如果你是为指针类型的元素分配内存,那么这些元素通常会被初始化为空指针;如果你为实型数据分配内存,则这些元素会被初始化为浮点型的零.

2.realloc需要注意的安全问题:

(1)从realloc的机理得知,其返回的地址不一定是原地址,这点尤为重要. realloc可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或是缩小,原有内存的中内容将保持不变.当然,对于缩小,则被缩小的那一部分的内容会丢失.realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址.相反,realloc返回的指针很可能指向一个新的地址.

(2)下面说下realloc的扩展:

1】. 与名字相符,真正的realloc,参数ptr和size均不为NULL,重新调整内存大小,并将新的内存指针返回,并保证最小的size的内容不变;
2】. 参数ptr为NULL,但size不为0,那么行为就等于malloc(size);
3】. 参数size为0,则realloc的行为为free(ptr);这时原有的指针已经被free掉,不能继续使用。而此时realloc的返回值为NULL。这意味着不检查realloc的返回值,直接使用,会导致crash。
下面说两种bug:
<1>

void *ptr = realloc(ptr, new_size);
if (!ptr) {
错误处理
}

这里就引出了一个内存泄露的问题,当realloc分配失败的时候,会返回NULL。但是参数中的ptr的内存是没有被释放的。如果直接将realloc的返回值赋给ptr。那么当申请内存失败时,就会造成ptr原来指向的内存丢失,造成泄露。

正确的处理应该是这样:

void *new_ptr = realloc(ptr, new_size);
if (!new_ptr) {
错误处理。
}
ptr = new_ptr

<2>

void *new_ptr = realloc(old_ptr, new_size);
//其它代码
...... ......

这种bug由一种不好的编程习惯引发的。即认为申请内存始终可以成功,因此并不检查malloc的返回值。这在一般情况下,不会引发问题。但是对于realloc来说,当new_size为0时,realloc返回NULL。而在后面的代码上,继续使用new_ptr,比如会导致程序crash。

malloc realloc calloc free的更多相关文章

  1. c的三个内存分配函数(malloc,realloc,calloc)

    //内存分配_malloc int main(){ int *p; char *p1; p=(int *)malloc(sizeof(*p)*size);//size为需要存储的数量 p1=();// ...

  2. Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解

    C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般 ...

  3. malloc,calloc,realloc,alloc

    三个函数的申明分别是: void* realloc(void* ptr, unsigned newsize); void* malloc(unsigned size); void* calloc(si ...

  4. malloc,calloc,realloc函数用法,原理及不同解析

    https://blog.csdn.net/lixungogogo/article/details/50887028 一.malloc malloc在MSDN中原型为: void *malloc( s ...

  5. 【C/C++开发】malloc,calloc和realloc的区别和注意事项

    (1)C语言跟内存分配方式 <1>从静态存储区域分配.        内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量.static变量. <2&g ...

  6. malloc,calloc,realloc

    与堆操作相关的两个函数 malloc #include<stdio.h> #include<stdlib.h> #include<string.h> int mai ...

  7. malloc()与calloc差别

    Both the malloc() and the calloc() functions are used to allocate dynamic memory. Each operates slig ...

  8. malloc、calloc、relloc

    1.malloc void * malloc(size_t _Size); malloc函数在堆中分配参数_Size指定大小的内存,单位:字节,函数返回void *指针. 2.calloc void ...

  9. malloc()与calloc区别 (转)

    另外说明: 1.分配内存空间函数malloc 调用形式: (类型说明符*) malloc (size) 功能:在内存的动态存储区中分配一块长度为"size" 字节的连续区域.函数的 ...

随机推荐

  1. IO流-文件夹的拷贝

    文件夹的拷贝操作 要求: 完成文件夹的拷贝,包括子目录的拷贝和所有文件的拷贝 分析: 首先,得在目标目录下创建一个与源文件夹名称相同的文件夹 遍历源文件夹中的所有文件对象,判断子文件是目录还是文件 如 ...

  2. oracle之 11g RAC R2 体系结构---Grid

    -- 查看cluster 所维护的资源列表,不包括 OHAS 栈的 daemon [root@node1 bin]# ./crsctl status resource -t-------------- ...

  3. JavaFX 之自定义窗口标题栏(二)

    一.问题场景 PC客户端登录界面仿QQ,上边显示图片,下边显示输入框和登录按钮.而JavaFX默认的窗口,不满足需求. 二.解决思路 隐藏窗口默认的标题栏,使用创建label对象,使用css将按钮图片 ...

  4. jeecg选择按钮带入其他单据值

    前端的标签 <input class="inputxt" id="fshimian" name="fshimian" ignore=& ...

  5. Netty--JDK序列化编解码传输对象

    使用JDK序列化不需要额外的类库,只需要实现Serializable即可,但是序列化之后的码流只有Java才能反序列化,所以它不是跨语言的,另外由于Java序列化后码流比较大,效率也不高,所以在RPC ...

  6. linux 下查找文件或者内容常用命令

    转自:http://www.cnblogs.com/sunleecn/archive/2011/11/01/2232210.html whereis <程序名称>查找软件的安装路径-b 只 ...

  7. DjangoORM执行原生sql

    在Django中使用原生Sql主要有以下几种方式: 一:extra:结果集修改器,一种提供额外查询参数的机制 二:raw:执行原始sql并返回模型实例 三:直接执行自定义Sql   这种方式完全不依赖 ...

  8. http 和 https 区别?

    1. HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头2. HTTP 是不安全的,而 HTTPS 是安全的3. HTTP 标准端口是80 ,而 HTTPS ...

  9. Druid.io系列(八):部署

    介绍 前面几个章节对Druid的整体架构做了简单的说明,本文主要描述如何部署Druid的环境 Imply提供了一套完整的部署方式,包括依赖库,Druid,图形化的数据展示页面,SQL查询组件等.本文将 ...

  10. [转]搭建MySQL高可用负载均衡集群

    转自:http://www.cnblogs.com/phpstudy2015-6/p/6706465.html 阅读目录 1.简介 2.基本环境 3.配置MySQL主主复制 4.中间件简述 4.1.H ...