C—动态内存分配之malloc与realloc的区别
1、程序内存的分配
一个由C/C++编译的程序占用的内存分为以下几个部分:
1)栈区(stack) — 由编译器自动分配释放 , 存放为运行函数而分配的局部变量、 函数参数、 返回数据、 返回地址等。 其操作方式类似于数据结构中的栈。
2)堆区(heap) — 一般由程序员分配释放, 若程序员不释放, 程序结束时可能由OS回收,否则程序就会存在内存泄漏的问题 。 分配方式类似于链表。
3)全局区(静态区) (static) —存放全局变量、 静态数据、 常量。 程序结束后由系统释放。
4)文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放。
5) 程序代码区—存放函数体(类成员函数和全局函数) 的二进制代码
内存分配方式有三种:
1)从静态存储区域分配:内存在程序编译的时候就已经分配好, 这块内存在程序的整个运行期间都存在。 例如全局变量, static变量。
2)在栈上创建:在执行函数时, 函数内局部变量的存储单元都可以在栈上创建, 函数执行结束时这些存储单元自动被释放。 栈内存分配运算内置于处理器的指令集中, 效率很高, 但是分配的内存容量有限。
3)从堆上分配:亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定, 使用非常灵活, 但如果在堆上分配了空间, 就有责任回收它, 否则运行的程序会出现内存泄漏。频繁地分配和释放不同大小的堆空间将会产生堆内存碎块。
(new和malloc是C++中的内存分配关键字)
使用动态内存很明显的好处就是:不需要预先分配存储空间且分配的空间可以根据程序的需要扩大或缩小,这样可以有效的使用内存空间。
malloc和free
C函数库中的malloc和free分别用于执行动态内存分配和释放。这两个函数的原型如下所示,他们都在头文件stdlib.h中声明。
void *malloc ( size_t size );
void free ( void *pointer );
malloc的作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL,确保非空之后再使用非常重要。malloc所分配的内存是一块连续的空间。同时,malloc实际分配的内存空间可能会比你请求的多一点,但是这个行为只是由编译器定义的。malloc不知道用户所请求的内存需要存储的数据类型,所以malloc返回一个void *的指针,它可以转换为其它任何类型的指针。
由于内存区域总是有限的,不能不限制地分配下去,而且一个程序要尽量节省资源,所以当所分配的内存区域不用时,就要释放它,以便其它的变量或者程序使用。这时我们就要用到free函数。free的参数必须要么是NULL,要么是从malloc、relloc、calloc返回的值。作用是释放之前返回的指针指向的内存空间,向free传递一个NULL参数不会产生任何效果。
calloc和realloc与malloc的区别
calloc和realloc的原型如下:
void *calloc ( size_t num_elements, size_t element_size );
void *realloc (void *ptr, size_t new_size );
calloc和malloc 主要的区别在于前者在返回内存的指针之前将它初始化为0,另外它们请求数量的方式不同。calloc的参数包括所需元素的数量和每个元素的字节,根据这些值可以计算出总共需要分配的内存空间。
realloc函数用于修改一个原先已经分配的内存块的大小,可以使一块内存的扩大或缩小。当起始空间的地址为空,即*ptr = NULL,则同malloc。当*ptr非空:若nuw_size < size,即缩小*ptr所指向的内存空间,该内存块尾部的部分内存被拿掉,剩余部分内存的原先内容依然保留;若nuw_size > size,即扩大*ptr所指向的内存空间,如果原先的内存尾部有足够的扩大空间,则直接在原先的内存块尾部新增内存,如果原先的内存尾部空间不足,或原先的内存块无法改变大小,realloc将重新分配另一块new_size大小的内存,并把原先那块内存的内容复制到新的内存块上。因此,使用realloc后就应该改用realloc返回的新指针。
使用方法程序示例
int *ptr =NULL;
ptr = (int*)malloc(sizeof(int)*size);
if (*ptr == NULL)
{
strerror(error);
return;
}
上例中动态分配了size个整型存储区域。动态分配内存的步骤可细分为:分配size个整型的连续存储空间,并返回一个指向其起始地址的整型指针把此整型指针地址赋给ptr, 检测返回值是否为NULL。注意,类型转换(int*)将函数返回的地址转换成int类型的指针。这么做是因为malloc()是一般用途的函数,可为任何类型的数据分配内存。sizeof是一个运算符,它返回一个size_t类型的无符号整数,该整数是存储它的参数需要的字节数。它把关键字如int或float等作为参数,返回存储该类型的数据项所需的字节数。它的参数也可以是变量或数组名。把数组名作为参数时,sizeof返回存储整个数组所需的字节数。前一个例子请求分配足以存储size个int数据项的内存。以这种方式使用sizeof,可以根据不同的C编译器为int类型的值自动调整所需的内存空间。
int *p1,*p2;
p1 = (int*)malloc(size * sizeof(int));
p2=p1;
……
free(p1); /*或者free(p2)*/
给free函数传递其它的值很可能造成死机或其它灾难性的后果。注意:这里重要的是指针的值,而不是用来申请动态内存的指针本身。
malloc返回值赋给p1,又把p1的值赋给p2,所以此时p1,p2都可作为free函数的参数。malloc函数是对存储区域进行分配的。 free函数是释放已经不用的内存区域的。 所以由这两个函数就可以实现对内存区域进行动态分配并进行简单的管理了。
下面是使用动态分配的内存的基本规则:
●避免分配大量的小内存块。分配堆上的内存有一些系统开销,所以分配许多小的内存块比分配几个大内存块的系统开销大。
●仅在需要时分配内存。只要使用完堆上的内存块,就释放它。
●总是确保释放已分配的内存。在编写分配内存的代码时,就要确定在代码的什么地方释放内存。
●在释放内存之前,确保不会无意中覆盖堆上分配的内存的地址,否则程序就会出现内存泄漏。在循环中分配内存时,要特别小心。
C—动态内存分配之malloc与realloc的区别的更多相关文章
- 内存分配函数malloc、realloc、calloc、_alloca
1.内存分配函数_alloca.malloc.realloc.calloc: _alloca 函数原型void * __cdecl _alloca(size_t); 头文件:malloc.h _all ...
- 内存分配机制malloc&&alloca&&realloc
<1>从静态存储区域分配. 内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量.static变量.<2>在栈上创建 在执 ...
- c 链表和动态内存分配
兜兜转转又用到了c.c的一些基本却忘记的差不多了(笑哭)!! 动态内存分配 当malloc完将返回的指针类型强制转换成想要的类型后,指针中存有该指针的数据结构,而分配的内存恰好可用于该数据结构. 链表 ...
- c/c++动态内存分配的区别
c中动态内存分配使用malloc和free. malloc指定需要分配的内存大小,分配成功则返回指向该内存的指针,不成功则返回空指针.返回的指针类型为void *,表示不确定指针所指内存存放的数据类型 ...
- C语言中动态内存的分配(malloc,realloc)
动态内存分配:根据需要随时开辟,随时释放的内存分配方式.分配时机和释放时机完全由程序员决定,由于没有数据声明,这部分空间没有名字.无法像使用变量或数组那样通过变量名或数组名引用其中的数据,只能通过指针 ...
- 转: Linux C 动态内存分配 malloc及相关内容 .
一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...
- 数据结构基础——指针及动态内存分配(malloc)
一.指针 C语言中的指针是一种数据类型,比如说我们用int *a;就定义了一个指针a,它指向一个int类型的数.但是这个指针是未初始化的,所以,一般的,我们都在创建指针时初始化它,以免出错,在还不吃的 ...
- Linux C 动态内存分配--malloc,new,free及相关内容
一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...
- SQLite剖析之动态内存分配
SQLite通过动态内存分配来获取各种对象(例如数据库连接和SQL预处理语句)所需内存.建立数据库文件的内存Cache.保存查询结果. 1.特性 SQLite内核和它的内存分配子系统提供以下特性 ...
随机推荐
- db2_merge
DB2 MERGE INTO语句的使用 DB2中的Merge语句可以将一个表中的数据合并到另一个表中,在合并的同时可以根据条件进行插入.删除.更新等操作,功能非常强大. 语法如下:www.2c ...
- linux gdb基本概念
GDB是一个功能强大的调试器,它是一个自由软件,能够用在许多UNIX平台上.它同时也是Linux系统中的默认调试器.GDB已被移植到许多其他的计算机平台上,并且能够用于调试嵌入式实时系统.一般来说,G ...
- AngularJS2环境配置
所使用到的文件目录结构如下所示: 1. 创建配置文件: 1.1. 创建目录: mkdir angular-quickstart cd angular-quickstart 1.2. 载入 ...
- enote笔记语言(3)(ver0.2)
what&why(why not)&how&when&where&which:紫色,象征着神秘而又潜蕴着强大的力量,故取紫色. key&keyword: ...
- JSON - Qt 对 JSON的处理
1.关于JSON的介绍参考www.json.org Qt提供处理JSON数据的支持.QJSonObject类用于封装JSON object:QJsonDocument类提供读写JSON文档的方法:QJ ...
- C语言常见错误中英文对照表
C语言常见错误中英文对照表(网络搜索及经验积累不断更新中) 常见错误中英文对照表 fatal error C1003: error count exceeds number; stopping co ...
- Javascript学习一
//学习moocjs1 JavaScript-警告(alert 消息对话框) <script type="text/javascript"> var mynum = 3 ...
- 从HTML5规范弄清i、em、b、strong元素的区别
为了语义化,HTML5增加了不少新标签.其中i.em和b.strong这两组标签是最容易弄混的,不好好去探究一下,还真说不清.这个也是前端面试中经常会问的问题.今天从源头上,也就是从HTML5的文档( ...
- C++ 友元函数的函数指针
成员函数的指针 讲友元之前先讲普通的成员函数的函数指针 class Std_interface { public: virtual void suspend() = 0; }; // define t ...
- HTML文档及标签介绍
HTML标签 HTML 标记标签通常被称为 HTML 标签 (HTML tag). HTML标签是由尖括号包含的关键词,比如<html> HTML标签通常是成对出现的,比如<body ...