避免内存错误(C++)
内存管理上的错误是C/C++程序设计是最为可怕的错误之一,这类错误不易调试查找,有时候是你程序关闭的时候才出现,如果你面对的是一个大型工程,那就相当令人头疼了,下面将该类错误出现的原因总结为如下四点:
- 内存泄露
顾名思义,内存泄露是指分配了一段内存之后,没有将其释放所致,这块没有释放而又没用的内存会随同程序运行一直存在。如果程序一味地分配内存而不予回收,可以想象,系统资源会很快耗尽,程序乃至于系统运行越来越慢,因此,必须杜绝这种现象发生。当然了,有人说我自己申请的内存肯定都会释放啊。那就请看下面的例子吧:
Void memory_Leak()
{
Int *list = new int[100];
….
If(End()) return;
…..
Delete[]
}
在上述例子中,函数也执行了内存释放啊,但是再看,如果程序满足End()条件,那么它就会在中途退出,内存就不会被释放。异常、错误和其他各种throw和catch语句经常是导致内存泄露的原因。
还有一种可能引起内存泄露的原因时忘记了释放一个数据结构的某些部分。例如:
Typedef struct{
Char *name;
Int Number;
Int age;
Char *address;
Int phone;
} student;
对于student这个结构有这样一个函数如下:
Void memory_Leak()
{
Student *s;
A = new Student;
s->name = new char[100];
…
s->address = new char[50];
….
Delete s;
}
在上面的例子中,一个student结构体被分配了内存并在函数结束的时候释放,但是这个结构体的一些域并没有被释放,例如name以及address,注意:结构体被释放并不表示他的域也被释放了。
- 重复释放
内存分配与释放应该是一一对应的,如果释放一个根本不存在的指针,或重复释放都会引起麻烦,这时可以写如下一个宏来避免该内错误:
#define SAFE_DELETE(p)
{
If((p) ! = NULL)
{
Delete (p);
(p) = NULL;
}
}
下面介绍一下可能重复释放的小例子吧:
Void Twice_Free(x)
{
…
Delete[] x;
}
Void main()
{
Int *x = new int[10];
…
Twice_Free(x);
…
Delete[] x;
}
上面的例子比较明显,在此就不多讲了,还有一种情况就是多个指针指向同一块内存,然后依次释放各个指针:
BYTE *p_buffer1 = new BYTE[100];
…
BYTE *p_buffer2 = p_buffer1;
….
Delete [] p_buffer1;
Delete [] p_buffer2;
如果继续继续使用一个已经释放了的指针也将会出现严重问题:
Void Twice_free(x)
{
…
Delete [] x;
}
Void main()
{
Int *x = new int[10];
..
Twice_free(x);
…
Function(x);//错误
}
- 坏指针问题
坏指针是一类问题的总称,他可能由多种原因引起,如一个指针没有指到预期位置,程序可能毫无征兆的崩溃,坏指针是从哪儿来的?
一个不可忽视的根源就是没有被很好的初始化的数据。所以一个指针你不知道合适的初始化值,就将其初始化为NULL吧,这是一个无效地址。
- 超量写内存
比如说访问数组越界啊什么的,分配内存不不足啊,例如:
#define array_size 100
Int *a = (int *)malloc(array_size) //应为Int *a = (int *)malloc(array_size * sizeof(int))
A[99] = 0;
还有就是字符串的最后没有结束符'\0',当然,现在都使用string,Cstring数据类型,这个问题就比较少了哈。
还有函数返回一个临时变量指针也会出错,如:
Int *p()
{
int i = 0;
return &I;
}
总之,C/C++程序中这类错误指针的情况是非常常见的,情况也比较多,而且十分隐蔽,很难被发现。最好的途径就是养成良好的编程习惯,已尽量避免他们的发生。
(源于《C++数据结构原理与经典问题求解》一书)