malloc()函数(Linux程序员手册)及函数的正确使用【转】
转自: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个字节的数组分配内存并返回指向已分配内存的指针。已分配内存的内容被清零。如果nmemb或size为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()在出错时设定errno为ENOMEM。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()的源代码。
程序代码:
- // code...
- void free(void *ptr) {
- struct mem_control_block *free;
- free = ptr - sizeof(struct mem_control_block);
- free->is_available = 1;
- return;
- }
看一下函数第二句,这句非常重要和关键。其实这句就是把指向可用空间的指针倒回去,让它指向管理信息的那块空间,因为这里是在值上减去了一个结构体的大小!
图示如下:

该文作者原先有错误的认识,就是认为指向那块内存的指针不管移到那块内存中的哪个位置都可以释放那块内存!
但是,这是大错特错!释放是不可以释放一部分的!首先这点应该要明白。而且,从free()的源代码看,ptr只能指向可用空间的首地址,不然,减去结构体大小之后一定不是指向管理信息空间的首地址。所以,要确保指针指向可用空间的首地址!
该错误认识通过上图更能清晰地看出来,只有当ptr指向可用空间的首地址时,在ptr减去struct mem_control_block的大小后才能使得后面的语句free->is_available得到有效数值。否则,传给系统的数值就肯定不是正确的,由此造成的后果也不可预测了。
4. 错误使用举例。
int main(int argc, char *argv[]) { char *buffer = NULL, *str = NULL; char *a = "abcdefghij"; int length = 10, i = 0; buffer = (char *)malloc(length * sizeof(char)); if(!buffer) { printf("1:malloc error!\n"); return 0; } memset(buffer, 0, length); for(i = 0; i < length - 1; i++) { *buffer++ = a[i]; } fprintf(stderr, "buffer: %s\n", buffer); free(buffer); str=(char *)malloc(length * sizeof(char)); if(!str) { printf("2:malloc error!\n"); return 0; } memset(str, 0, length); for(i = 0; i < length - 1; i++) { str[i] = a[i]; } fprintf(stderr, "str: %s\n", str); free(str); }上面程序中同样使用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程序员手册)及函数的正确使用【转】的更多相关文章
- DOS程序员手册(一)
当今MS-Windows横扫大江南北,让我们这就来研究一下它的祖宗——MS-DOS! 这本书很难得,希望读者好好学习! DOS程序员手册(一) DOS教程 (以下内容全部为原作者的阐述,照样保留) 这 ...
- PowerShell:Linux程序员喜欢的cmd增强版
Linux程序员有时偶尔使用Windows下的cmd工具,会被逼疯的,有些命令ls, cat, ps等已经条件反射一样使用. 但在cmd下,根本不知道该用什么命令,好在盖兹大叔照顾了此部分需求.从Vi ...
- 函数sql黑马程序员——SQL常用函数
最近使用开辟的过程中出现了一个小问题,顺便记录一下原因和方法--函数sql ---------------------- ASP.Net+Android+IO开辟S..Net培训.等待与您交流! -- ...
- 做10年Windows程序员与做10年Linux程序员的区别
如果一个程序员从来没有在linux,unix下开发过程序,一直在windows下面开发程序, 同样是工作10年, 大部分情况下与在linux,unix下面开发10年的程序员水平会差别很大.我写这篇文章 ...
- 做10年Windows程序员与做10年Linux程序员的区别(附无数评论)(开源软件相当于熟读唐诗三百首,不会作诗也会吟)
如果一个程序员从来没有在linux,unix下开发过程序,一直在windows下面开发程序, 同样是工作10年, 大部分情况下与在linux,unix下面开发10年的程序员水平会差别很大.我写这篇文章 ...
- DOS程序员手册(九)
第14章参考手册概述 本书余下的章节将向读者们介绍BIOS.DOS各种各样API函数和服务,作为一名程 序员,了解和掌握这些知识是很有好处的.在所介绍的参考手册中,每部手册都汇集了大 量的资源 ...
- DOS程序员手册(八)
备,就可以从程序中访问驱动程序.可以用句柄功能调用来 打开设备(见列表12.9) 列表12.9 /*example.C List ...
- DOS程序员手册(七)
第11章 中断处理程序 本章将深入到DOS系统内部探讨中断处理程序的内容.与其他计算机编程不一样, 中断处理程序这个名词听起来就很难懂.用最简单的话来说,中断处理程序就是对应于中 断激活的程 ...
- DOS程序员手册(六)
217页 程序的主要部分后面是主程序所使用的许多小的扩充内存功能.将这些功能组合起 来这些功能便覆盖了扩充内存的操作,尽管还可能想向它们添加错误检查. 程序所包含的函数有: emmtest 检验内 ...
随机推荐
- 17 利用Zabbix完成VMare监控
点击返回:自学Zabbix之路 17 利用Zabbix完成VMare监控 最近在研究通过Zabbix监控VMware vSphere,Zabbix Documentation 3.0 从文档中我们看到 ...
- 【bzoj3438】 小M的作物
http://www.lydsy.com/JudgeOnline/problem.php?id=3438 (题目链接) 题意 $n$种作物,每种可以种在A田也可以种在B田,两种种植方法有不同的收益.$ ...
- Java8的Stream流(一) --- 基础用法
Java8中的Stream Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象. Stream的特性及优点: 无存储. Stream不是一种数据 ...
- SQL: 从一个表随机读取一行或几行记录的问题
比如ms sql 2000,随机读取了一行记录: SELECT TOP 1 * FROM [tablename] ORDER BY NEWID() 遇到的问题是,如果这个表记录不多,比如几十或几百.几 ...
- MyEclipse2017配置多个tomcat
一:添加多个tomcat的运行环境 首先,在Window——Preferences 搜索 servers, 在Servers中点Runtime Environments, 点右边的Add,选择我们要添 ...
- UML简单熟悉
+ :代表public - :代表private # :代表protected 实现,继承关系:implements,extends 关联关系:使一个类知道另一个类的属性和方法 每一个Driver类 ...
- 在Win10中,在安装msi安装包的时候常常会出现代码为2502、2503的错误。
前言:在Win10中,在安装msi安装包的时候常常会出现代码为2502.2503的错误.其实这种错误是由于安装权限不足造成的,可以这种msi的安装包不像其他exe的安装程序,在安装包上点击“右键”之后 ...
- 函数和常用模块【day05】:装饰器前戏(二)
本节内容 嵌套函数 局部作用域和全局作用域的访问顺序 一.嵌套函数 1.定义 在一个函数的函数体内,用def 去声明一个函数,而不是去调用其他函数,称为嵌套函数. 1 2 3 4 5 6 7 8 9 ...
- .Net MVC发布出错 Server Error in '/' Application.
发布的时候遇到这个错误:Server Error in '/' Application. Could not load file or assembly 'SettingsProviderNet' ...
- 多目标遗传算法 ------ NSGA-II (部分源码解析) 实数、二进制编码的变异操作 mutation.c
遗传算法的变异操作 /* Mutation routines */ # include <stdio.h> # include <stdlib.h> # include < ...