1. 为什么存在动态内存分配 *动态内存开辟在堆区*
我们已经掌握的开辟内存方式是类型直接定义变量,开辟的内存是固定的,像:2. 动态内存函数的介绍
int a=20; //在栈空间上开辟四个字节
还有数组,我们可以指定开辟空间的大小,像:
char arr[10] = {0}; ///在栈空间上开辟10个字节的连续空间
但在程序运行时,很多时候我们会遇到内存不够或者内存过多引起的浪费问题,那么有没有那种使用多少内存开辟多少内存的方法?这就是本篇文章要介绍的动态内存。
2.1 malloc和free malloc和free都声明在 stdlib.h 头文件中2.2 calloc
void* malloc (size_t size); //向内存申请一块连续可用的空间,并返回指向这块空间的指针
如果开辟成功,则返回一个指向开辟好空间的指针。 如果开辟失败,则返回一个NULL指针。 返回值的类型是 void* ,malloc函数并不知道开辟空间的类型,在使用的时候自己来决定。
void free (void* ptr); //free函数用来释放动态开辟的内存
如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。
举例:
#include #include #include #include
int main() { //开辟10个整型空间 int* p = (int*)malloc(40); if (NULL==p) { printf("%s\n",strerror(errno)); //判断开辟失败的原因 return 0; } //使用 //释放 free(p); //将空间还给系统,但是里面的内容没有改变,还可以通过p来找到地址 p = NULL; //因此要将地址置为空指针 return 0; }
2.3 reallocvoid* calloc (size_t num, size_t size); //num为元素个数,size为每个元素的大小
注:与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0
文章图片
当用calloc来开辟10个整型空间时
int* p = (int*)calloc(10,sizeof(int));
文章图片
3. 常见的动态内存错误void* realloc (void* ptr, size_t size); //ptr 是要调整的内存地址size 调整之后新大小 //返回值为调整之后的内存起始位置
realloc在调整内存空间的是存在两种情况:
1.当原地址后有足够的空间时,可以接着原地址连续开辟空间,最后返回起始地址。
2.当原地址后空间不足以开辟我们所需要的空间时,那么realloc会自动寻找一块足以存放我们需要的的空间,并将原地址的内容复制到新空间中,释放掉原地址中的内容,返回开辟出空间的初始地址。
文章图片
我们可以先判断是否开辟成功,再将地址赋予p
文章图片
3.1对NULL指针的解引用操作 开辟动态内存时,一定要注意对返回空指针的函数要进行判断,防止对空指针进行解引用,以免程序出现问题。
3.2对动态开辟空间的越界访问int *p = (int *)malloc(10*sizeof(int)); //开辟内存 if(NULL == p)//判断是否开辟成功 { exit(EXIT_FAILURE); } int i=0; for(i=0; i<=10; i++) { *(p+i) = i; //当i是10的时候越界访问 } free(p);
文章图片
这块可以像理解数组一样,不能访问下标为10的地址,会造成越界访问。
3.3对非动态开辟内存使用free释放void test() { int a = 10; int *p = &a; free(p); }int main() { test(); return 0; }
文章图片
不是动态内存开辟的空间内存不在堆区,没必要用free释放,在栈区开辟的空间在出了作用域后会自动还给系统,没有必要,也不允许用free进行释放。
3.4 使用free释放一块动态开辟内存的一部分void test() { int *p = (int *)malloc(100); p++; free(p); //p不再指向动态内存的起始位置 }
文章图片
不支持释放一部分内存,这样的写法不支持不可取。只能从动态内存开辟的起始位置来进行释放。
3.5 对同一块动态内存多次释放void test() { int *p = (int *)malloc(100); free(p); free(p); //重复释放 }
重复释放也会报错
文章图片
当p第一次释放后,将p=NULL,再次释放的话就不会有问题;写代码是要避免重复释放的情况,同时要记住每次释放完之后都要将地址置为空指针。
【笔记|动态内存管理分析理解】若忘记释放开辟的空间,就会造成内存泄漏的问题(在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费)
推荐阅读
- 笔记|堆的实现+堆排序
- 笔记|顺序表的实现
- XingleiGao的日常|Atlas 200 DK开发者套件基于CANN的垃圾分类实验踩坑指南
- 学习交流|C语言关键字auto,case,default,switch应该如何使用
- C编程语言|《c陷阱与缺陷》1-3章笔记
- 学习交流|C语言sizeof与strlen的区别与使用
- C语言|C语言打印字符,转义字符,注释(小白版)
- 读书笔记|C陷阱与缺陷--笔记
- C++|C++STL详解(一)(string类的介绍以及基本使用)