笔记自取链接:动态内存管理笔记
众所周知~,内存的分配如下图所示:
我们已经不满足于
int a = 0; int b[3] = 0;
这种变量占有固定的字节数,修改不了
我们比较熟悉的是静态区和栈区的变量类型,那么堆区里面有什么?
接下来让我们一起了解一下动态内存分配类型的函数
需包含头文件:stdlib.h
返回值和参数
void* malloc (size_t size);
解读:在堆区上申请size大小的空间,返回堆区上这个空间的起始地址
如何使用:
int* p = (int *)malloc(4);//我们专门申请一块空间放整型
如果直接解引用
int* p = (int *)malloc(4); *p = 1;//有风险
malloc开辟失败会返回一个空指针
我们需要判断是否申请内存成功
if(p == NULL) { return -1;//分配失败 } else { *p = 3;//使用该空间 }
需包含头文件:stdlib.h
我们用完mellco函数申请的空间时,这块空间不想要了
用free函数释放空间
free函数的返回值和参数
void free (void* ptr);
解读:给free函数传一个指针(必须是动态空间的起始地址),指针所指向的空间释放掉,如果传NULL,什么都不执行
!!!!!!!!!!!!!!!但是!!!!!!!!!!!!!!!!
我们运行的时候 p的地址如下
当我们释放内存空间时
虽然空间释放掉了,p指针所指向的地址还是刚才的地方,p仍然可以访问,这样子就很危险,因为p现在是一个野指针
free(p); p = NULL;
把它变成空指针,这样就安全了
需包含头文件:stdlib.h
返回值和参数
void* calloc (size_t num, size_t size);
解读:在堆区上申请num个size大小的空间,返回堆区上这个空间的起始地址,并且把所有元素初始化成0
如何使用
int* p = (int*)calloc(10, 4);//40字节
其他功能和melloc类似
唯一区别就是melloc不会初始化
一段时间后,我们可能会觉得,之前申请的空间太小或者过大了,为了合理且灵活使用内存时,我们可以用realloc对动态内存空间进行大小的修改
返回值和参数
void* realloc (void* ptr, size_t size);
解读:
ptr 是要调整的内存地址
size是调整之后新大小
返回值为调整之后的内存起始位置
这个函数调整原内存空间大小的基础上,还**可能会将原来内存中的数据移动到新的空间**
realloc在调整内存空间两种情况:
- 原有空间之后有足够大的空间:直接原有内存之后直接追加空间,原来空间的数据不发生变化
- 原有空间之后没有足够多的空间:在堆空间上新找一个大小合适的连续空间来存放,realloc函数返回的是一个新的内存地址
但在使用过程中需要注意
int* p = (int*)malloc(10); //我想要20个字节 int* p = (int*)realloc(p, 20); //这样子写真的可以吗
如果遇到调整动态空间错误,realloc会返回空指针,这样我们原本的空间也丢失了
我们需要一个临时变量接受指针
int* ptr = (int*)realloc(p, 20); if(ptr != NULL) { p = ptr;//调整成功 } else { return -1; } free(p); p = NULL;
虽然动态内存空间使用很灵活,但我们还是需要注意以下常见的错误
对NULL(空)指针的解引用操作
注意,在申请内存空间时,可能失败,导致返回空指针
对动态开辟空间的越界访问
使用该空间时候,所申请超出空间的范围
对非动态开辟内存使用free释放
free只能释放动态内存!!!
使用free释放一块动态开辟内存的一部分
传递给free去释放的指针必须是所开辟动态空间的起始地址
开辟动态空间的起始地址不能随便++或–等操作改变地址
除非创建临时参数使用
对同一块动态内存多次释放
free(p); free(p);错误,不能连续释放
正确写法:
free(p); p = NULL; free(p); p = NULL;
动态开辟内存忘记释放(内存泄漏)
内存释放两种方式:
- free函数释放
- 程序运行结束自动释放
如果一个程序(比如服务器)一直运行,而你不释放这块内存,内存空间就一直被占用,浪费