动态内存管理
前言
在之前的学习中我们已经学习掌握了了代码区常量区、全局变量以及栈区,接下来我们学习动态内存管理,其主要是与堆区相关
一、为什么存在动态内存分配
如果我们想要定义一个很大的数组时,这时栈内无法满足我们的要求,栈内空间太小了。而 空间开辟大小是固定的。数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。但是对于空间的需求,不仅仅是该的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。 这时候就只能试试动态存开辟了。
所以进行动态内存管理
①可以申请大块内存,进行较为大类型的应用
②可以在程序运行期间进行申请,可以更灵活的使用内存空间
二、动态内存函数的介绍
1.malloc和free
malloc是一个动态内存开辟空间的函数,申请堆空间,但是不做任何初始化
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针
void* malloc (size_t size) ;
1.其中size_t size表示无符号整数申请几个字节。申请成功,malloc返回值void为一段连续空间的起始地址(最小字节对应的地址);申请失败,返回值为空。
2.返回值的类型是 void ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
3,如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
另外一个函数free,专门是用来做动态内存的释放和回收的,函数原型如下:
void free (void* ptr);
1.free函数用来释放动态开辟的内存。
2.如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
3.如果参数 ptr 是NULL指针,则函数什么事都不做
malloc和free都声明在 stdlib.h 头文件中。 举个例子:
malloc、free是函数,必须时程序运行起来才能调用。编译的过程早就已经过了(在程序运行期间进行申请)
常见细节:
1.整体申请,整体释放
2.只申请内存不归还,会造成内存泄露。一种严重的问题,可用内存越老越少。进程退出了,内存泄露问题就不在了。
3.申请有大小,free没有告诉我们应该释放多少字节,那么free如何知道要释放多少字节?
目前free参数只能知道从哪开始释放。申请的时候,实际申请的空间会比你要的空间大一些,大出来的部分,用来保存本次申请的“元信息”(元信息:属性信息,对应堆空间的大小(也称为:内存cookie信息))
4.堆空间比较适合大块内存申请?还是小块内存申请?
大块内存申请
5.free究竟做了什么?
首先free前和后地址相同,但是free之后指针不可用
free用来取消内部的地址和堆空间的关系,所以没有关系无法使用
2.calloc
calloc 函数也用来动态内存分配。原型如下:
void * calloc (size_t num, size_of size);
size_t num元素个数 size_of size元素个数大小
函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。并且也需要free函数释放空间
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = calloc(10, sizeof(int));
if(NULL != p)
{
//使用空间
}
free(p);
p = NULL;
return 0;
}
3.realloc
对已经分配的堆空间再次或多次进行调整,让动态内存管理更加灵活
有时候我们发现过去申请的空间太小了或申请的空间过大了,那么为了合理的时候内存,我们一定会对内存的大小做灵活的调整。因此 realloc 函数就可以做到对动态开辟内存大小的调整。
void* realloc (void* ptr, size_t size);
其中:
1.ptr 是要调整的内存地址(要调整的堆空间起始地址)
2.size 调整之后新的大小
3.返回值为调整之后的新的内存起始位置。
4.这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
realloc在调整内存空间存在两种情况:
①:原有空间之后有足够大的空间况
②:原有空间之后没有足够大的空间(可以扩展但是不够/不可以扩展)
对空间必须是连续的内存空间,因为存在对其进行遍历
对于①向后扩展空间,堆空间起始地址不变
对于②先跳过占用的空间找到开辟合适的空间大小,将原有内容拷贝过来再填写后面内容,最后将原先开辟的堆空间释放,对空间起始地址改变
如果调整空间依然不够,那么调整失败,此时返回值为NULL
以上3种堆空间申请方式都用free函数来释放