动态内存管理(4种)

 

首先我们需要知道

一、在程序执行期间,变量存储空间有三种:
1、静态存储区。内存在程序编译的时候就已经分配好了,这块内存在程序执行期间都存在,
存储全局变量和静态变量。
2、栈存储区。内存是在程序执行期间才分配的,函数内局部变量及函数参数的存储单元,当
函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率
高但容量小。
3、堆存储区。在程序执行时由程序员用malloc或new申请的内存,程序员自己负责何时用
free或delete释放分配的内存。频繁的分配和释放不同大小的堆内存将会产生堆内碎片。

 

二、程序将操作系统分配给它运行的内存分成五个区域:
1、栈区,存放局部变量,函数参数,返回数据,返回地址等。
2、堆区,由程序员分配及释放。
3、静态存储区,存放全局变量、静态变量和常量。具体由三部分组成:
1>已初始化的全局变量和静态变量。
2>未初始化的全局变量和静态变量。
3>常量数据区。
4、文字常量区,程序中使用的常量字符串,程序结束后由系统释放。
5、程序代码区,存放函数体的二进制代码。

现在我们知道这次要研究的动态内存函数是存放在堆区的。

为什么需要动态内存分配呢?

我们之前知道,内存开辟可以在栈空间上开辟

int val = 20 ; // 在栈空间上开辟四个字节
char arr[10] = {0};//在栈空间上

但在栈中开辟空间会有限制条件

1. 空间开辟大小是固定的。
2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,
那数组的编译时开辟空间的方式就不能满足了。
这时候就只能试试动态存开辟了。

常见的内存函数有

malloc
free
calloc
realloc

我们现在开始进行认识

 

一.malloc和free

我们常常将这两个放在一起研究是因为

1.mallocfree一般成对出现。申请了内存不使用时候需要释放掉。

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所指向的空间扩大,
并返回p的指针地址。 这个时候 q 和 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时只会释放一维,使用时谨防内存泄露

5. 传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的

6.传递给realloc的指针可以为空,等同于malloc。

三.结语

简短的动态内存管理就学习到这里了,谢谢大家。

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值