首先我们需要知道
一、在程序执行期间,变量存储空间有三种:
1、静态存储区。内存在程序编译的时候就已经分配好了,这块内存在程序执行期间都存在,
存储全局变量和静态变量。
2、栈存储区。内存是在程序执行期间才分配的,函数内局部变量及函数参数的存储单元,当
函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率
高但容量小。
3、堆存储区。在程序执行时由程序员用malloc或new申请的内存,程序员自己负责何时用
free或delete释放分配的内存。频繁的分配和释放不同大小的堆内存将会产生堆内碎片。
二、程序将操作系统分配给它运行的内存分成五个区域:
1、栈区,存放局部变量,函数参数,返回数据,返回地址等。
2、堆区,由程序员分配及释放。
3、静态存储区,存放全局变量、静态变量和常量。具体由三部分组成:
1>已初始化的全局变量和静态变量。
2>未初始化的全局变量和静态变量。
3>常量数据区。
4、文字常量区,程序中使用的常量字符串,程序结束后由系统释放。
5、程序代码区,存放函数体的二进制代码。
现在我们知道这次要研究的动态内存函数是存放在堆区的。
为什么需要动态内存分配呢?
我们之前知道,内存开辟可以在栈空间上开辟
int
val
=
20
;
//
在栈空间上开辟四个字节
|
char arr[10] = {0};//在栈空间上 |
但在栈中开辟空间会有限制条件
常见的内存函数有
malloc
|
free |
calloc |
realloc |
我们现在开始进行认识
一.malloc和free
我们常常将这两个放在一起研究是因为
1.malloc和free一般成对出现。申请了内存不使用时候需要释放掉。
2.free空指针不会有任何操作。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *test=NULL;
free(test);
return 0;
}
结果不会报告警告,也不会执行出错。
(1)malloc
由malloc的定义我们可以知道
1.malloc分配的内存大小至少为size参数所指定的字节数 |
2.malloc的返回值是一个指针,指向一段可用内存的起始地址 |
3.多次调用malloc所分配的地址不能有重叠部分,除非某次malloc所分配的地址被释放掉 |
4.malloc应该尽快完成内存分配并返回(不能使用NP-hard的内存分配算法) |
5.实现malloc时应同时实现内存大小调整和内存释放函数(即realloc和free) |
而malloc的具体实现则是
int *p=(int*)malloc(size_t)
malloc可申请的字节数为:2G=210241024*1024个字节
malloc一维数组
int (*p)[5]=(int (*)[5])malloc(4*5);
//(*)[5]必须要这么写,这样是数组指针,如果写成*[5],只是指针数组
int a[5];
int (*p)[5]=&a;
free(p);
(2)free
free常用来释放某个地址空间的,被释放的地址的值不是0,而是某个初始值,如下
int *p = (int*)malloc(4);
*p=12;
free(p);
注意:内存地址是不能重复释放的,会出现崩溃情况
不能释放栈区空间,会出现崩溃情况
二.其他动态内存函数
(1)calloc
calloc函数用于分配所需的内存空间,并返回一个指向它的指针。malloc 和 calloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。
由此可见calloc与malloc很相似,但是还是有所不同
calloc函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。 |
与malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0 |
calloc用法
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = (int*)calloc(5,sizeof(int));
for(int i=0; i<5; i++)
p[i]=i;
for(int i=0; i<5; i++)
printf("%d ",p[i]);
return 0;
}
(2)realloc
我们通过定义可以得知
当size_t大于旧地址的容量时,可对旧地址进行扩容操作。
例如
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i;
int*pn=(int*)malloc(5*sizeof(int));
if (!pn) {
printf("malloc fail\n");
exit(-1);
}
printf("malloc %p\n",pn);
for(i=0;i<5;i++)
pn[i]=i;
pn=(int*)realloc(pn,10*sizeof(int));
if (!pn) {
printf("realloc fail\n");
exit(-1);
}
printf("realloc %p\n",pn);
for(i=5;i<10;i++)
pn[i]=i;
for(i=0;i<10;i++)
printf("%3d",pn[i]);
free(pn);
pn = NULL;
return 0;
}
得出如下结果
为什么会这样呢,根据资料我们得出如下信息:
1.如果当前连续内存块足够 realloc 的话,只是将p所指向的空间扩大, |
2.如果当前连续内存块不够长度,再找一个足够长的地方,分配一块新的内存q,并将 p指向的内容 copy到 q,返回 q。并将p所指向的内存空间删除。 |
realloc的小结
1. realloc失败的时候,返回NULL |
2. realloc失败的时候,原来的内存不改变,不会释放也不会移动 |
3. 假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址 |
4. 如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。 |
6.传递给realloc的指针可以为空,等同于malloc。 |
三.结语
简短的动态内存管理就学习到这里了,谢谢大家。