【C语言】动态内存管理
前言
什么是动态内存?
在C语言中,动态内存是指在程序运行时根据实际需求动态分配和释放的内存。与静态内存(在编译时分配,生命周期与程序或函数运行周期相同)不同,动态内存的分配和释放由程序员通过特定的函数手动控制,常用的函数为molloc、free、realloc、calloc,其开辟的空间在堆上
为什么需要动态内存?
int i = 20;
char arr[20];
上面的代码中,是程序在栈上开辟的空间,用于储存变量的,而在栈上开辟的空间有两个特点(都是静态的):
- 空间开辟大小是固定的
- 数组在申明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整
那么,对于程序员来说,我们有时候只有在程序运行后才知道要开辟多少空间给某个变量,而这些已经写死大小的内存就不符合我们的愿景了,所以我们需要动态内存管理,下面我们就对动态内存管理展开说说!
下面所讲的函数均处于 stdlib.h 库中
一、malloc函数
malloc函数是C语言中一个用来开辟内存的函数
void* malloc(size_t size)
- 参数 :
size
: 指定需要分配的内存大小,单位为字节;size_t 是一个无符号整数类型,通常用于表示大小 - 返回值:
如果开辟成功
,则返回一个指向开辟好空间的指针如果开辟失败
,则返回一个NULL 指针,因此malloc的返回值一定要做检查
注:
返回值的类型是void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自
己来决定;如果参数size 为0,malloc的行为是标准是未定义的,取决于编译器
#include <stdio.h>
#include <stdlib.h>
int main() {
int* arr = NULL;
int* tmp = (int*)malloc(sizeof(int) * 10);
if (tmp == NULL) {
perror("main()::malloc()");
}
else {
arr = tmp;
}
free(arr);
return 0;
}
这里我们就使用了malloc开辟了一块大小为40Byte的内存空间
二、calloc函数
calloc函数是C语言中用于动态分配内存的另一个重要函数,它与malloc类似,但在分配内存后会自动初始化为0
void* calloc(size_t num, size_t size);
- 参数:
num
:分配的元素个数
size
:每个元素的大小 - 返回值
如果开辟成功
,则返回一个指向开辟好空间的指针如果开辟失败
,则返回一个NULL 指针,因此calloc的返回值一定要做检查
malloc 与 calloc 的唯一区别是 calloc 会初始化开辟的空间,用法与 malloc 一样
三、realloc函数
如果我们前面使用了 malloc 或则 calloc 函数开辟了空间,但是我们发现开辟的空间不够用了,还想开辟多一点,或则说发现开辟大了,想缩小,那么我可以使用 realloc 函数,它可以改变之前分配的内存块的大小
void* realloc(void* ptr, size_t size);
- 参数:
ptr
:指向之前分配的内存块的指针,如果ptr为NULL,realloc的行为等同于malloc
size
:新的内存块的大小(以字节为单位) - 返回值:
如果调整成功
,返回指向新分配的内存的指针如果调整失败
,则返回一个NULL 指针,原内存块不变
对于realloc调整成功返回的指针,分两种情况:
- 情况一: 原有内存后面有足够多的剩余空间用于拓展,则在原有的空间后面直接拓展,并返回prt指针
- 情况二: 原有内存后面没有足够多的剩余空间用于拓展,扩展的方法是: 在堆空间上另找一个合适大小的连续空间来使用,这样函数返回的是一个新的内存地址
四、free函数
在C语言的库中,专门提供了一个free函数将开辟出来的动态内存释放掉的,函数原型如下:
void free (void* ptr);
注:
- 如果参数ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的
- 如果参数ptr 是NULL指针,则函数什么事都不做
#include <stdio.h>
#include <stdlib.h>
int main() {
int* arr = NULL;
int* tmp = (int*)malloc(sizeof(int) * 10);
if (tmp == NULL) {
perror("main()::malloc()");
}
else {
arr = tmp;
}
free(arr);
return 0;
}
如上,free释放了malloc开辟的动态内存
为什么需要释放内存
动态内存是由程序员开辟的,如果使用完之后不进行内存的释放,那么内存有可能导致堆积,内存泄露的风险,但是free不能对非动态内存进行释放,不然程序会报错
End
对于动态内存管理,我们就将到这里,关于动态内存管理,还有一个拓展点叫做柔性数组,这里我不在多讲啦,如果大家有兴趣可以自己百度一下!