动态内存管理以及常见错误

存在的意义

我们的内存开辟方式主要是:

int a=0;//开辟4字节的空间
int arr[5]={
    
    0};//开辟20字节的空间

这样开辟存在着几个问题:
由于变量开辟是在内存中的栈中,空间比较有限。
只能开辟固定的内存空间,不方便后续调整。
在特定的场景下我们并不能获取需要开辟的内存大小。

所以我们有动态开辟空间来解决一些特定情景下的问题。

1.不能确定需要的内存大小,或者是一个变化的内存大小
2.可以开辟较大的空间来操作(动态开辟的内存空间在内存堆上,空间大于变量所在的栈空间)
3.不过虽然很好,但是动态开辟的内存空间需要我们申请的人主动释放,否则会造成严重的内存泄漏。

内存泄漏可以说是一个很致命的问题,尤其是在一些连续运行的地方,如服务器代码。严重的会导致服务器瘫痪。

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些
    存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有
    限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
  2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似
    于链表。

相关函数

1.malloc

C语言提供了一个动态内存开辟的函数:

void* malloc(size_t  size);
//size是指开辟空间的字节数

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

1.开辟成功,则返回一个指向所开辟空间的指针。失败返回NULL;
2.返回值泛型,所以我们可以自己决定。
3.如果参数 size 为0,malloc的行为是标准是未定义的.

我们一般使用malloc的这样用:

int* arr=(int*)malloc(4);

int a[5]={
    
    0};
char* arr1=(char*)malloc(sizeof(int)*5);
//malloc搭配sizeof更方便
//malloc一般使用是带一个强制类型转换

2.free

C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收的,函数原型如下:

void free(void*arr);

要点:

free函数用来释放动态开辟的内存。
1.如果参数 arr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
2.如果参数 arr 是NULL指针,则函数什么事都不做。

int* arr=(int*)malloc(4);
free(arr);

int a[5]={
    
    0};
char* arr1=(char*)malloc(sizeof(int)*5);
free(arr1);

3.calloc

他和malloc一样都是开辟堆内存,只不过他会将开辟的空间全部初始化为0;
他和malloc的形参有不同之处,需要注意。

void* calloc (size_t num, size_t size);
//开辟num个大小为size字节的空间

1.函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
2.与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

int *arr = calloc(10, sizeof(int));
free(arr);
//不用的时候就一定要free掉内存,虽然我们的代码很短,
//在程序结束自动释放,但是大项目就不一定了。

在这里插入图片描述

4.realloc

realloc函数的出现让动态内存管理更加灵活。
他可以改变我们申请的堆空间大小。

void* realloc (void* ptr, size_t size);
//ptr 是要调整的内存地址
//size 调整之后新大小
//返回值为调整之后的内存起始位置。
int *arr = calloc(10, sizeof(int));
int *p=realloc(arr,20);
free(p);
//将calloc出来的40字节变成了20字节

注意:
realloc改变空间大小会出现两种情况:
1.空间起始位置不变(原有空间足够大)
在这里插入图片描述
2.起始位置改变
在这里插入图片描述

常见错误

1.没有判空

INT_MAX是一个宏定义,代表我们可以向操作系统申请内存空间的最大值,正常情况下无法完成,所以说malloc返回了NULL,而我们对于空指针解引用,属于未定义行为。

void test(){
    
    
int *p = (int *)malloc(INT_MAX);
*p = 10;
free(p);
}

2.越界

越界属于未定义行为。不管是动态开辟还是栈空间的变量,都不可以越界访问。

int* arr=(int *)malloc(sizeof(int)*4);
for(int i=0;i<=4;i++){
    
    
	*(p+i)=1;
}

3.非动态开辟free

free仅支持动态开辟的内存,否则会报错

int arr[5]={
    
    0};
free(arr);

4.未完全释放

未完全释放,造成内存泄漏

int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置

5.重复释放

这个重复释放内存空间属于未定义行为。

int *arr = calloc(10, sizeof(int));
int *p=realloc(arr,20);
free(p);
free(arr);

6.没有释放空间

动态开辟的内存空间,不用的时候一定要释放。

int* p=(int*)malloc(12);

猜你喜欢

转载自blog.csdn.net/zhaocx111222333/article/details/114630735