malloc、free的使用
一、malloc()和free()的基本概念以及基本用法:
1、函数原型及说明:
void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针。如果分配失败,则返回一个空指针(NULL)。
关于分配失败的原因,应该有多种,比如说空间不足就是一种。
void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。
2、函数的用法:
其实这两个函数用起来倒不是很难,也就是malloc()之后觉得用够了就甩了它把它给free()了,举个简单例子:
程序代码:
// Code...
char *Ptr = NULL;
Ptr = (char *)malloc(100 * sizeof(char));
if (NULL == Ptr)
{
exit (1);
}
gets(Ptr);
// code...
free(Ptr);
Ptr = NULL;
// code...
就是这样!当然,具体情况要具体分析以及具体解决。比如说,你定义了一个指针,在一个函数里申请了一块内存然后通过函数返回传递给这个指针,那么也许释放这块内存这项工作就应该留给其他函数了。
3、关于函数使用需要注意的一些地方:
A、申请了内存空间后,必须检查是否分配成功。
B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。
C、这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会
出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。
D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一
些编译器的检查。
好了!最基础的东西大概这么说!现在进入第二部分:
二、malloc()到底从哪里得来了内存空间:
1、malloc()到底从哪里得到了内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。就是这样!
说到这里,不得不另外插入一个小话题,相信大家也知道是什么话题了。什么是堆?说到堆,又忍不住说到了栈!什么是栈?下面就另外开个小部分专门而又简单地说一下这个题外话:
2、什么是堆:堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。
什么是栈:栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。
以上的概念描述是标准的描述,不过有个别语句被我删除,不知道因为这样而变得不标准了^_^.
通过上面对概念的描述,可以知道:
栈是由编译器自动分配释放,存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。
堆一般由程序员分配释放,若不释放,程序结束时可能由OS回收。注意这里说是可能,并非一定。所以我想再强调一次,记得要释放!
----------------------------------------------------------------------------
(转)
malloc函数和free函数
假设您的程序在执行过程中需要分配一定量的内存。您可以随时调用malloc函数从堆中申请一块内存。在操作系统为您的程序预留出这块内存,之后您就可以随意使用它了。用完之后,要使用free函数将这块内存返回给操作系统进行回收。以后其他程序还可以按自己的需要预留这块内存。
作为例子,下面的代码演示了最简单的使用堆的方法:
int main()
{int *p;p = (int *)malloc(sizeof(int));if (p==0)
{printf("错误:内存不足n");return 1;
}*p=5;printf("&dn", *p);free(p);return 0;}
程序的开始调用了malloc函数,这个函数做了三件事:
- malloc语句首先检查堆上的空闲内存总数,然后判断:“有没有足够的空闲内存可以分配一个所申请的大小的内存块呢?”申请的内存块大小是由传入malloc的参数确定的——本例中的sizeof(int)是4个字节。若内存不足,malloc函数会返回零地址告知发生的错误(零地址的另一种表示是NULL,它在C代码中很常用)。否则malloc函数继续执行。
- 若堆上有足够的内存,系统就从堆上“分配”或“预留”出指定大小的内存块。预留的目的是为了防止多个malloc语句恰巧使用同一个内存块。
- 接下来系统将预留出的内存块的地址保存到指针变量中(本例中就是p)。指针变量本身保存了一个地址。被分配的内存块能够存储一个指定类型的数值,而指针正是指向此数值。
下图显示了调用malloc之后的内存状态:
右边的方框表示malloc分配的内存块。
接着程序用if (p==0)检查指针p以确定分配申请成功(此行也可写成if (p==NULL)甚至if (!p))。如果分配失败(p等于零),则程序终止,否则程序将分配的内存块初始化为5,然后打印内存块的值,接着调用free函数将内存块返还给堆,最后退出。
前面的章节有一段代码是将p赋值为一个现成整数i的地址,而本例中的代码和那段代码实际上并无不同。区别只是在于:对于变量i的内存,它是程序预分配内存空间的一部分,有两个名字i和*p;而对于从堆上分配的内存,它只有一个名字*p,且是在程序运行中分配的。两个常见的问题是:
- 每次分配内存后都要检查指针的值是否为零,这真的很重要吗?是的。因为堆的大小取决于当前正在运行哪些程序、它们分配了多少内存等诸多因素,所以一直都在变化,不能保证调用malloc总是成功的。每次调用malloc以后,您都应该检查一下指针以确保其有效性。
- 如果程序结束前我忘记了释放分配的内存块会怎样呢?程序结束以后,操作系统会做“善后处理”:释放可执行代码、栈、全局变量和所有从堆上分配的内存空间以供回收利用。因此,对分配的内存置之不理,在程序结束以后是不会对系统造成持续影响的。但是这种做法会被认为是“不良的风格”,且程序运行中的“内存泄漏”是有害的。这一点下文还会讲到。
下面两段程序显示了两种不同的使用指针的正确方法,旨在区分指针和指针的值在使用上的区别:
void main()
{int*p, *q;p=(int *)malloc(sizeof(int));q=p;*p=10;printf("%dn", *q);*q=20;
printf("%dn", *q);}
此程序的最后输出结果是代码第4行打印的10和代码第6行打印的20。下面是一个内存状态示意图:
下面这个程序稍有不同:
void main()
{int *p, *q;p=(int *)malloc(sizeof(int));q=(int *)malloc(sizeof(int));
*p=10;*q=20;*p=*q;printf("%dn", *p);}
此程序的最后输出结果是代码第6行打印的20。下面是它的内存状态示意图:
注意,编译器会接受*p=*q,因为*p和*q都是整数。这条语句的意思是说:“将q指向的整数传送到p指向的整数中去。”被传送的是数值。编译器也会接受p=q,因为p和q都是指针且指向相同的类型(若s为指向字符的指针则p=s是不允许的,因为它们指向不同类型)。p=q这条语句的意思是说:“将p指向和q相同的内存位置。”换句话说,q指向的地址被传送到了p,因此两个指针指向相同的地址。被传送的是地址。
从这些例子可以知道,初始化指针的方式有四种。在程序中声明一个指针时(如int *p),它开始处于未初始化状态。它可能指向任何位置,因此对它的解引用(取出指针指向的地址中的内容)是错误的。初始化指针就是将其指向一个已知的内存地址。
- 第一种方式是例子中使用的malloc语句。此语句从堆上分配一块内存并将指针指向它。这样指针便完成了初始化,因为它现在保存了一个有效地址,即新分配的内存块的地址。
- 第二种方式,也是刚才用到的,是用p=q这样的语句使p指向和q相同的位置。若q已经指向有效地址,则p完成初始化。指针p将保存q已经保存的有效地址。但若q未初始化或无效,则这个无价值的地址也会传给 p。
- 第三种方式是将指针指向已知地址,如一个全局变量的地址。例如,若i是一个整数且p是一个整型指针,则语句p=&i初始化p为指向i。
- 第四种方式是将指针初始化为零。在使用指针时零是一个特殊值,如下所示:
p=0;
或:
p=NULL;
此语句完成的操作是将零赋给p。指针p指向的地址为零。一般用下面的示意图表示这种情况:
任何指针都可设为指向零地址。虽然p指向零地址,但是它却不指向任何真正的内存块。此指针保存的零值只是一个标志。可以像下面语句这样使用它:
if (p==0)
{...}
或:
while (p!=0){...}
系统会识别零值,如果您无意中解引用一个零指针,系统会报错。例如下列代码:
p=0;*p=5;
程序一般会崩溃。指针p不指向内存块而是零地址,所以不能为*p赋值。后面我们讲到链表时,零指针将被作为一个标志使用。
malloc命令用于分配一个内存块。当此内存块不再需要时还可以将其释放。释放的内存块可以被后来的malloc语句重新分配,这样系统就可以回收内存。释放内存的命令叫做free,它接受一个指针作为参数。free命令完成两件事情:
- 不再预留指针指向的内存块,而是将其返还到堆上的空闲内存区。此内存块可以被随后的语句重新使用。
- 指针被置为未初始化的状态,再次使用前必须重新初始化。
free语句只是将指针还原为未初始化状态并使内存块在堆上重新变成可用状态。
下例显示了如何使用堆。它分配了一块整数内存,写入数据然后输出,最后废除此内存块:
#include int main()
{int *p;p=(int *)malloc (sizeof(int));*p=10;printf("%dn",*p);free(p);return 0;}
此代码其实只适用于在C中演示分配、使用和释放内存块的过程。malloc用于分配一块指定大小的内存,本例中是sizeof(int)字节(4字节)。C语言的sizeof命令以字节为单位返回任何类型的大小。代码中完全可以写成malloc(4),因为在大部分机器上sizeof(int)等于4个字节。但是使用sizeof可以大大增强代码的可移植性和可读性。
malloc函数返回一个指向被分配内存块的指针。这是一个通用指针,若不经类型转换即使用一般会导致编译器发出类型警告。类型转换(int *)将malloc返回的通用指针转换为一个“指向整数的指针”,即与p一致。C中的free语句将内存块返还给堆以供重新使用。
第二个例子说明的函数和前一例相同,但是用结构体代替了整数。C代码如下:
#include struct rec
{int i;float f;char c;}; int main()
{struct rec *p;p=(struct rec *) malloc (sizeof(struct rec));(*p).i=10;
(*p).f=3.14;
(*p).c='a';
printf("%d %f %cn",(*p).i,(*p).f,(*p).c);
free(p);
return 0;}
请注意这行:
(*p).i=10;
很多人不明白为什么不能写成:
*p.i=10;
答案是这和C语言的操作符优先级有关。5+3*4的结果是17,不是32,因为在大多数计算机语言中*比+有更高的优先级。C语言中,操作符.比*有更高的优先级,所以要使用括号保持正确的操作顺序。
但是大部分人觉得总是输入(*p).i太麻烦了,因此C提供了一种简洁记法。下面的两条语句完全等效,而第二条的输入更加简便:
(*p).i=10;
p->i=10;
阅读别人代码的时候,您会发现第二种记法比第一种更常用。
malloc、free的使用的更多相关文章
- malloc 与 free函数详解<转载>
malloc和free函数详解 本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...
- C 语言中 malloc、calloc、realloc 和free 函数的使用方法
C标准函数库中,常见的堆上内存管理函数有malloc(), calloc(), recalloc(), free(). 之所以使用堆,是因为栈只能用来保存临时变量.局部变量和函数参数.在函数返回时,自 ...
- 以冒泡排序为例--malloc/free 重定向stdin stdout
esort.c 代码如下,可关注下mallloc/free,freopen重定向的用法,排序为每轮将最小的数放在最前面: #include<stdio.h> #include<mal ...
- 内存动态分配之realloc(),malloc(),calloc()与new运算符
1,malloc与free是C/C++的标准库函数,new/delete是C++的运算符,是C++面向对象的特征,它们都可用于申请动态内存和释放内存.2,对于非内部数据类型的对象而言,光用maloc/ ...
- 在dll里malloc/new/cvCreate分配内存,在exe里free/Releases释放内存时会出错。
写了个程序,在DLL中用malloc分配了一块内存,但是在exe程序中释放,结果程序crash,原因就是:其原因可能是堆被损坏,这也说明 TestMySticker.exe 中或它所加载的任何 DLL ...
- Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解
C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般 ...
- malloc与new的区别
1.new是运算符,而malloc是库函数 2.new可以重载,可以自定义内存分配策略,甚至不做内存分配,甚至分配到非内存设备上.而malloc不能. 3.new在用于定义一个新的非内部对象的时候,默 ...
- new 等于 malloc加构造函数
1.new 是c++中的操作符,malloc是c 中的一个函数 2.new 不止是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数,而malloc则只分配内存,不会进行初始化类成员 ...
- 关于malloc函数的动态分配问题
malloc函数动态分配了一个整型的内存空间,让abc都指向刚申请的空间,所以只有最后一个赋值语句的值保留在了空间里 #include<stdio.h> main() { int *a,* ...
- 转:如何实现一个malloc
如何实现一个malloc 转载后排版效果很差,看原文! 任何一个用过或学过C的人对malloc都不会陌生.大家都知道malloc可以分配一段连续的内存空间,并且在不再使用时可以通过free释放掉. ...
随机推荐
- linux服务器重启服务命令说明文档
(前提是电脑上面已经安装好了ssh软件~!)输入ip,用户名,端口(默认22) 输入密码,登陆成功之后, 转入到/usr/local/tomcat/bin 目录,输入命令行: [root@yangch ...
- time wait duo
linux 下Time_wait过多问题解决 分类: linux FAQ2011-07-14 11:20 3485人阅读 评论(0) 收藏 举报 linux服务器tcp通讯活动ssh 问题起因: 自己 ...
- ZOJ3765 Lights Splay树
非常裸的一棵Splay树,需要询问的是区间gcd,但是区间上每个数分成了两种状态,做的时候分别存在val[2]的数组里就好.区间gcd的时候基本上不支持区间的操作了吧..不然你一个区间里加一个数gcd ...
- java001-Helloworld
public class test05 { public static void main(String[] args) { System.out.println("Hello World! ...
- C# 委托的”四步走“
看了一本<深入了解C#>感觉很不错,对于委托的讲解,给大家摘录了下来! 1.什么是委托 我的拙见:委托就是将方法作为参数,进行传递的 书中的记载:将某种行为“包含”在一个对象中,这个对象可 ...
- Code::Blocks生成的EXE文件执行错误解决:The program can't start because libgcc_s_dw2-1.dll is missing
想用C++弄个简单东东,看有没有可行性, 开发软件,微软的太大太肿,就选用了Code::Blocks. 测试HELLO时,在工程环境中没问题的,但生成的EXE执行有问题, 报什么 libgcc_s_d ...
- 读写txt文件
public void SetUpdateTime(string strNewDate) { try { var path =Application.StartupPath + Configurati ...
- 手把手VirtualBox虚拟机下安装rhel6.4 linux 64位系统详细文档
下面演示安装的是在VirtualBox里安装rhel 6.4 linux 64位系统. 一.VirtualBOX 版本. 二.虚拟机的配置. 1.现在开始演示安装,一起从零开始.点击“新建”,创建新的 ...
- ubuntu 13.10 64bit装BeyondCompare
1. Beyond Compare官网下载amd-64位的,安装失败,依赖于ia32-libs,但是这个文件已经不在源里了: 2. 官网下载tar.gz源码包,解压安装失败: 3. 直接装32位的,可 ...
- 使用预处理PreparedStatement执行Sql语句
/** * 使用预处理的方式执行Sql * @param sql Sql语句 * @param obj 变量值数组 * @return 查询结果 * @throws SQLException */ p ...