指针问题一直是C++工程中的让人头疼的问题,动不动给你报个"段错误",都不知道从何查起.这篇博客就C++中野指针的产生原因以及如何有效避免内存泄露的一些坑作一些总结,希望以后学习工作中,养成指针定义即初始化的好习惯,彻底理解内存的正确分配和释放方式,从源头避免内存泄露的问题.
一. 内存分配方式
1. 五个内存区
- 栈: 栈是线程独有的,每个线程的栈相互独立,每个函数都有自己的栈,栈由编译器自动分配和释放,存储通常定义的局部变量,特点是自动申请,自动释放,效率高,容量有限;
- 堆: 堆是大家共有的空间,程序猿手动使用malloc申请的内存,特点是手动申请(malloc),手动释放(free),效率较低,容量较大,只负责申请内存,无初始化;
- 自由存储区: 程序猿手动使用new申请的内存,特点是手动申请(new),手动释放(delete),效率较低,容量较大,申请内存,同时可调用构造函数初始化;
- 静态存储区: 全局变量,全局/局部静态变量,全局变量在main函数之前申请,局部静态变量在执行到该位置时开始申请,都在整个程序运行结束,才释放内存.
- 常量存储区: 常量池,不允许修改.
2. 正确使用malloc和new
2.1 malloc
- 原型:
extern void *malloc(unsigned int num_bytes);
- 说明: 分配长度为num_bytes字节的内存块。如果分配成功则返回指向被分配内存的指针,分配失败返回空指针NULL.
- 判断: 申请之后务必判断是否申请成功,使用
if(p != NULL){}
- 释放:
free(p); p = NULL;
- malloc只负责申请内存,不知道用户申请的是何种类型,返回void,用户需要用强制类型转换成想要的类型*.
int *p = (int*)malloc(sizeof(int)* 2);//申请了4个int大小的内存空间
if(p == NULL)//判断是否申请成功
exit(-1);
//赋值
p[0] = 1;
p[1] = 2;
cout << "p: " << *p << " " << *(++p) << endl;
free(p);//释放,此时p是一个悬挂指针
p = NULL;
2.2 new
- 说明: 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算;
- 判断: 申请之后务必判断是否申请成功,使用
if(p != NULL){}
; - 申请失败: new内存分配失败时,会跑出bac_alloc异常,不会返回NULL;
- 释放:
delete p; p = NULL;
或者delete[] p; p = NULL
; - new负责申请内存,自动计算内存大小,返回用户指定的类型.
int *p = new int;//申请一个int类型的指针,未初始化
int *p2 = new int(); //申请一个int类型的指针,初始化为0
int *p3 = new int(10);//申请一个int类型的指针,初始化为10
int *p4 = new int[10];//申请一个int类型的数组,未初始化
int *p5 = new int[10]();//申请一个int类型的数组,初始化为0
int *p6 = new int[10]{
1,2,3,4};//申请一个int类型的数组,前四个初始化为1,2,3,4,后面初始化为0
for(int i = 0;i < 10;i++)
cout << p6[i]