一、野指针
-
指针变量没有被初始化。任何指针变量刚被创建时不会自动成为nullptr指针,它的缺省值是随机的,所以指针变量在创建的同时应当被初始化,要么将指针设置为nullptr,要么让它指向合法的内存。
-
指针p被free或者delete之后,没有置为nullptr,让人误以为p是个合法的指针。
-
指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:
class A
{
public:
void Func(void) { std::cout << " test" << std::endl; }
};
void Test()
{
A* p;
{
A a;
p = &a; // 注意a的生命期
}
p->Func(); // p是野指针
}
二、解引用
使用*
解引用
解引用再取地址和指针有什么区别???本质上是一样的,可以去实现一下stl容器的迭代器。
三、动态数组初始化
四、重载new和delete
五、内存池
六、内存泄漏
如何判断是否有内存泄漏
使用Purify检测内存是否泄漏
不用工具判断内存是否有泄漏:new和delete是否匹配
怎么解决内存泄漏
七、new失败、内存耗尽如何处理
-
判断指针是否为NULL,如果是则马上用return语句终止本函数
-
判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行。
-
为new和malloc设置异常处理函数。
八、free()崩溃
free或delete异常
-
释放的指针地址是否和new或malloc出来的一致
-
释放的指针大小是否被改变
-
越界、漏写sizeof()、realloc()第二个参数写错
-
改变指针的指向
-
重复释放内存
-
释放不是动态申请的内存
八、获取new或malloc出来的指针指向的实际内存大小
九、注意
-
delete只是把指针所指的内存给释放掉,但并没有把指针本身干掉。
-
❓ 程序崩溃或退出后系统会自动释放内存,为什么在程序退出前还要释放内存?
示例代码:
点击查看代码
#include <iostream>
#include <string>
int main()
{
int* p0 = new int[3](); //为一个大小为三的数组申请内存空间,p0保存的是首地址,数组所有元素的值为0,内置基本数据类型最好使用()初始化
int* p1 = new int[3]; //为一个大小为三的数组申请内存空间,p1保存的是首地址,数组所有元素的值未知
int* p2 = new int(3); //申请一个内存空间,里面的值为3
std::string* str1 = new std::string[3]; //调用默认构造函数,str1为空,
std::string* str2 = new std::string[3](); //调用默认构造函数,str2为空
std::string* str3 = new std::string("Hello"); //初始化为Hello
for (int i = 0; i < 3; i++)
{
p1[i] = 3 * i;
}
for (int i = 0; i < 3; i++)
{
std::cout << *p1 + i << std::endl; //0,1,2 *p1 值的基础上 +i 先解引用后++
std::cout << *(p1 + i) << std::endl; //0,3,6 将地址 +i,再解引用得到下一个地址对应的值
}
std::cout << *p2 << std::endl;
delete[] p0;
delete[] p1; //基本数据类型,new的时候使用了[],delete也最好使用[],
delete p2;
delete[] str1; //类类型(自定义数据类型),new的时候使用了[],delete必须使用[],不然会存在潜在风险
delete[] str2;
delete str3;
p0 = nullptr;
p1 = nullptr; //如果不指向nullptr,delete之后,p1将是一个随机值,成为一个野指针
p2 = nullptr; //我们在删除一个指针之后,编译器只会释放该指针所指向的内存空间,而不会删除这个指针本身
str1 = nullptr;
str2 = nullptr;
str3 = nullptr;
return 0;
}