欢迎进入内存这片雷区,伟大的Bill Gates曾经失言:
640k ought to be enough for everybody
--Bill Gates 1981
发生内存错误是件非常麻烦的事情,编译器不能自动发觉这些错误,通常在程序运行时才会出现,而这些错误大多没有明显的症状,时隐时现,增加了改错的难度,有时用户怒气冲冲地把你找来,程序却没有发生任何问题,你一走了问题又开始做乱。
常见的内存错误及对策有以下几种:
1)内存未分配成功,就使用了它。
一般程序员都不会意识到内存会分配不成功,而直接使用了该指针;常用的解决方法:在使用内存之前检查指针是否为NULL,如果P是函数的参数,则需要在函数入口处用Assert(p!=NULL)进行检查;如果是用malloc或new来动态申请内存,则应该用if(p==NULL)或if(p!=NULL)
进行防错处理;常见的现象:程序运行一段时间后出现内存访问异常,但重启机器后又能正常运行;
2)内存虽然分配成功了,但未进行初始化就引用
内存的初始值究竟是什么,没有任何标准规定,尽管有时候是全零,但我们在分配完一块内存后,应该进行初始化;否则可能会导致一些莫名奇妙的问题出现,且很有可能无法重现的问题;
3)内存分配成功且初始化,但操作超过了内存边界;
例如在使用数组时经常发生下标“多1”或“少1”的操作,特别在for循环中,循环次数很容易搞错,导致数组越界,经典案例:
char Arr[10];
for(i=1;i<=10;i++)
{
Arr[i]=i;
}
在数组越界的时候,什么样的问题都有可能发生,在VC6.0下可能是死循环,在VC2003下则提示数组访问越界等;
4)忘记释放内存,造成内存泄露
有这种问题的函数调用一次丢失一块内存,占的内存大,问题很快就出现,占的内存小,可能过一个月甚至一年或者更长时间才出现;为了避免类似问题,在使用malloc及free的次数一定要相等;
5)释放了内存却继续使用
<1>程序中的对象调用关系复杂,实在难以搞清楚某个对象是否已经释放了内存;
<2>函数的return语句写错了,注意不要返回指向栈空间的指针或者引用,因为该内存在函数退出时自动被销毁;
<3>使用了free及delete后,没有将指针改成NULL,导致了“野指针”;
640k ought to be enough for everybody
--Bill Gates 1981
发生内存错误是件非常麻烦的事情,编译器不能自动发觉这些错误,通常在程序运行时才会出现,而这些错误大多没有明显的症状,时隐时现,增加了改错的难度,有时用户怒气冲冲地把你找来,程序却没有发生任何问题,你一走了问题又开始做乱。
常见的内存错误及对策有以下几种:
1)内存未分配成功,就使用了它。
一般程序员都不会意识到内存会分配不成功,而直接使用了该指针;常用的解决方法:在使用内存之前检查指针是否为NULL,如果P是函数的参数,则需要在函数入口处用Assert(p!=NULL)进行检查;如果是用malloc或new来动态申请内存,则应该用if(p==NULL)或if(p!=NULL)
进行防错处理;常见的现象:程序运行一段时间后出现内存访问异常,但重启机器后又能正常运行;
2)内存虽然分配成功了,但未进行初始化就引用
内存的初始值究竟是什么,没有任何标准规定,尽管有时候是全零,但我们在分配完一块内存后,应该进行初始化;否则可能会导致一些莫名奇妙的问题出现,且很有可能无法重现的问题;
3)内存分配成功且初始化,但操作超过了内存边界;
例如在使用数组时经常发生下标“多1”或“少1”的操作,特别在for循环中,循环次数很容易搞错,导致数组越界,经典案例:
char Arr[10];
for(i=1;i<=10;i++)
{
Arr[i]=i;
}
在数组越界的时候,什么样的问题都有可能发生,在VC6.0下可能是死循环,在VC2003下则提示数组访问越界等;
4)忘记释放内存,造成内存泄露
有这种问题的函数调用一次丢失一块内存,占的内存大,问题很快就出现,占的内存小,可能过一个月甚至一年或者更长时间才出现;为了避免类似问题,在使用malloc及free的次数一定要相等;
5)释放了内存却继续使用
<1>程序中的对象调用关系复杂,实在难以搞清楚某个对象是否已经释放了内存;
<2>函数的return语句写错了,注意不要返回指向栈空间的指针或者引用,因为该内存在函数退出时自动被销毁;
<3>使用了free及delete后,没有将指针改成NULL,导致了“野指针”;