为什么存在动态内存分配?
首先,动态内存分配是计算机中一种重要的内存管理方法,它主要解决了静态内存分配无法灵活应对变化需求的问题。以下是几个存在动态内存分配的原因:
-
灵活性:动态内存分配允许程序在运行时根据需要动态地分配和释放内存。这对于需要动态改变内存使用情况的应用来说非常重要,比如动态数据结构、动态数组或者不确定大小的数据等。
-
节省内存:动态内存分配可以根据需求精确地分配所需大小的内存,避免了静态分配过多内存的浪费,并且可以回收不再使用的内存,提高内存的利用率。
-
动态数据结构支持:一些常见的数据结构,比如链表、树等,需要根据运行时的需求动态地分配内存来存储数据。动态内存分配可以满足这些数据结构的需要,使得程序能够更灵活地处理各种数据。
-
多任务支持:操作系统中的多任务环境下,每个任务需要独立的内存空间来存储自己的数据。动态内存分配允许每个任务根据需要独立分配内存,从而实现任务间的数据隔离,提高系统的安全性和可靠性。
其次值得注意的是,动态内存分配也需要注意管理好分配和释放内存的过程,避免内存泄漏或者其他内存管理问题。
动态内存管理函数
void* malloc(size_t size)
成功返回:开辟好空间的首地址,不会初始化空间内容,当程序退出时,还给操作系统,,当程序不退出,动态申请的内存,不会主动释放的
错误返回:NULL指针------NULL指针不可以使用,所以要对malloc返回的指针做检查
向内存申请一块连续可以的空间,并返回指向这块空间的指针
void* calloc(size_t num, size_t size);
num
:要分配的元素个数。size
:每个元素的大小。- calloc函数会分配num * size字节的内存空间,并将所分配的内存块中的每个字节都初始化为0。这与使用malloc分配内存后手动初始化为0的效果相同。
void* realloc(void *ptr, size_t size);
ptr
:指向之前分配的内存块的指针。(简单来说就是提前申请过的一块内存空间首地址)size
:要重新分配的内存块的大小。realloc
函数可以用来扩大或缩小已分配内存的大小。当ptr
为NULL时,realloc
的行为与malloc
相同,即分配一块新的内存空间。当ptr
不为NULL时,realloc
会尝试重新分配ptr
指向的内存块,将其大小调整为size
所指定的大小。- (1)当新的大小
size
小于或等于原内存块的大小时,realloc
会尝试缩小内存块的大小,并返回指向缩小后内存的指针。可能会丢失部分原有数据。 -
(2)当新的大小
size
大于原内存块的大小时,realloc
会尝试扩大内存块的大小。如果扩大成功,会返回指向扩大后内存的指针。扩大后的新增内存区域的内容是未定义的。如果扩大失败,会保持原有内存块不变,并返回NULL。 -
(3)当
ptr
为NULL时,realloc
会等同于malloc(size)
,即分配一块新的大小为size
的内存块,并返回指向该内存块的指针。
由于这个函数很特别,下面通过一段代码结合画的内存图,方便大家理解
int main()
{
int* p=(int*)malloc(40);
if(p==NULL)
{
perror("malloc");
return 1;
}
int i=0;
for(i=0;i<10;i++)
{
p[i]=i+1;
}
p=realloc(p,80);
return 0;
}
下面是申请成功的情况,红色区域代码后边有占用的数据
第二种情况步骤
1.开辟新空间
2.将旧空间数据拷贝到新空间
3.释放旧空间
4.返回新空间起始地址
还有一种是内存申请失败的情况会造成内存泄漏
为了避免内存泄漏可以把
p=realloc(p,80);这段代码替换成
int* ptr=(int*)realloc(p,80);
if(ptr!=NULL)
{
p=ptr;
ptr=NULL;
}
else
{
perror("realloc");
return 1;
}
//释放
free(p);
void* free(void* ptr)
释放掉ptr所指的内存空间