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 检验内 ...
随机推荐
- Leetcode 191.位1的个数 By Python
编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量). 示例 : 输入: 11 输出: 3 解释: 整数 11 的二进制表示为 00000000000 ...
- Shell基础知识(三)
Shell中变量的作用域: 在当前Shell会话中使用,全局变量. 在函数内部使用,局部变量. 可以在其他Shell会话中使用,环境变量. 局部变量: 默认情况下函数内的变量也是全局变量 #!/bin ...
- android关闭日志
我们在开发时,经常会输出各种日志来debug代码.但是等到应用发布的apk运行时不希望它输出日志. 关闭输出日志Log.v(),Log.i(),Log.w(),Log.v(),Log.e()等 原理: ...
- 前端基础之html(一)
https://www.cnblogs.com/haiyan123/p/7516060.html 一.初始html 1.web服务本质 import socket sock=socket.socket ...
- 基于Spring Cloud的微服务入门教程
(本教程的原地址发布在本人的简书上:http://www.jianshu.com/p/947d57d042e7,若各位看官有什么问题或不同看法请在这里或简书留言,谢谢!) 本人也是前段时间才开始接触S ...
- 20145215《网络对抗》Exp3 免杀原理与实践
20145215<网络对抗>Exp3 免杀原理与实践 基础问题回答 杀软是如何检测出恶意代码的? 基于特征来检测:恶意代码中一般会有一段有较明显特征的代码也就是特征码,如果杀毒软件检测到有 ...
- java代码示例(6-4)
创建ChangePassword.java /** * 需求分析:修改用户密码 * @author chenyanlong * 日期:2017/10/15 */ package com.hp.test ...
- JAVA-大白话探索JVM-类加载器(一)
JVM??? Java语言的一个非常重要的特点就是与平台的无关性.而使用Java虚拟机是实现这一特点的关键.JVM是Java Virtual Machine(Java虚拟机)的缩写,Java程序编译后 ...
- scala基本语法和单词统计
scala 基本语法 1.声明变量 (1)val i = 1 使用val声明的变量值是不可变的,相当于java里final修饰的变量,推荐使用. (2)var i = "hello" ...
- UESTC - 1167 一句话题意
---恢复内容开始--- 题目链接:https://vjudge.net/problem/UESTC-1167 请问从n*n的正方形左下角走到右上角且不越过对角线的情况总数模m的结果~ 分析: 还记得 ...