当前位置: 代码迷 >> 综合 >> Day 12 动态内存 3.28
  详细解决方案

Day 12 动态内存 3.28

热度:25   发布时间:2023-12-06 11:43:18.0

为什么需要动态内存管理

因为当我们创建类型时,int类型固定是四个字节,char arr[10]固定是十个字节。但是我们对与空间的需要是在程序运行的时候不断发生变化的,所以这个时候数组的开辟空间就很可能不能满足。这个时候就需要动态内存开辟。

栈区:局部变量,函数的形参。

堆区:malloc/free,calloc,realloc,动态内存分配。

静态区:全局变量,静态变量。

动态内存函数

malloc和free

malloc用于开辟内存块,返回的是一个void*的指针,指向开辟空间的起始地址。当开辟空间不足而申请失败时返回一个NULL(空指针)。

#include <stdlib.h>
//#include <malloc.h> 两者都可以void *malloc(size_t size);
int main()
{//int arr1[10];//40个字节//char arr2[40];//40个字节//申请空间int* ptr = (int*)malloc(40);    //空间过大,括号内为INT_MAX时会开辟失败。int* p = ptr;    //保存起始位置地址。if (p == NULL){perror("malloc");return 1;}int i = 0;for (i = 0; i < 10; i++){*p = i;p++;}//释放空间,指向起始位置的ptr。free(ptr);    //此时空间不属于ptr,但是ptr任然存放该空间首地址,所以为野指针。ptr = NULL;   //这样就让ptr没有任何有效空间。/*if (ptr != NULL){*ptr = 100;}*///*ptr = 100;//errreturn 0;
}
void free (void* ptr);//free同样也包含在头文件<stdlib.h>中。
//ptr指向的空间需要为动态开辟的,不是的话那么就会报错(free函数未定义)。
//ptr如果是NULL指针,那么函数声明也没不干。

free要求:

当我们不释放动态申请的内存的时候,当程序结束,动态申请的内存有操作系统自动回收,如果程序不结束,就会造成内存泄漏。因为动态内存不会自动回收。

calloc

void *calloc(size_t num, size_t size);
//num是元素的个数,size是元素的长度。
//例如:
int* p =(int *)calloc(10,sizeof(int)); 
//calloc申请的空间会被初始化成0。

与malloc不同的是calloc不仅申请了空间,还把空间初始化成了0。

realloc

用于内存的调整。

void *realloc(void *memblock,size_t size);
//memblock是扩容空间的起始地址,size是扩充空间的大小,单位为字节。
//头文件同前三个函数。

 realloc函数会遇到两种情况,

成功:

当起始地址往后的内存足够的时候,便追加空间,追加空间和原本空间和为size。然后返回起始地址。

当起始地址往后内存不够的时候,会寻找一块长度足够的内存空间,把原数据拷贝过来,然后返回新内存空间的首地址。把原内存不够的数据的空间free掉。

失败:

返回一个空指针。因此需要ptr来接收。

注意的错误事项

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;//0 1 2 3 4 5 6 7 8 9}//空间不够,希望能放20个元素,考虑扩容int*ptr = (int*)realloc(p, 80);if (ptr != NULL){p = ptr;}//扩容成功了,开始使用//不再使用,就释放free(p);p = NULL;return 0;
}

1.对NULL指针的解引用操作
解决办法:对malloc函数的返回值进行判断


int main()
{int* p = (int*)malloc(1000);int i = 0;if (p == NULL){//....return 1;}//使用for (i = 0; i < 250; i++){*(p + i) = i;}free(p);p = NULL;return 0;
}

2.对动态开辟空间的越界访问
对内存边界要检查


int main()
{int* p = (int*)malloc(100);int i = 0;if (p == NULL){//....return 1;}//使用//越界访问了for (i = 0; i <= 25; i++){*(p + i) = i;}return 0;
}

3.对非动态开辟内存使用free释放

int main()
{int a = 10;int* p = &a;//.....free(p);p = NULL;return 0;
}
//因为a不是动态开辟的空间,所以会报错。

4.使用free释放一块动态开辟内存的一部分

int main()
{int* p = (int*)malloc(100);if (p == NULL){return 1;}//使用int i = 0;for (i = 0; i < 10; i++){*p = i;p++;    //不断++的时候释放时不再位于起始位置。}//释放空间free(p);//errp = NULL;return 0;
}

5.对同一块动态内存多次释放

int main()
{int* p = malloc(100);if (p == NULL)return 1;free(p);//....free(p);//errp = NULL;return 0;
}

6.动态开辟内存忘记释放(内存泄漏)

void test()
{int* p = malloc(100);//使用
}int main()
{test();//.....while (1){;}return 0;
}