转自 本文作者:Tocy e-mail: zyvj@qq.com

https://www.cnblogs.com/tocy/archive/2012/05/19/2508642.html

C++中内存错误通常属于运行时错误,只有在程序运行时才能发现,编译器无法自动检测到内存错误。多数情况下是程序逻辑或者参数存在某些错误。下面总结一下C++常见的内存错误:

1. 内存泄露

内存泄露是指应用程序未释放动态申请的且不再使用的内存,原因可能是程序员疏忽或者错误造成程序异常。

在C/C++中,动态申请的内存是在堆上的。内存管理器也不会自动回收不再使用的内存,也就是说如果忘记释放动态申请的内存,该内存区域是不允许重用的。如果发送此类的内存泄露,函数每执行一次就丢失一块内存。长时间运行改程序可能引起系统"内存耗尽"。

这个问题本身没有很好的解决思路。只能从编程习惯上入手,也就是说动态申请内存与释放内存必须匹配,亦即new和delete的调用次数必须相同。

2. 野指针

未初始化的指针称为野指针(另一种说法是指向不可用内存区域的指针,不过笔者认为前者更合适)。通常对野指针进行写操作会发生不可预知的错误。

通常的避免方法就是在指针定义的时候就初始化,初始为NULL或者一个有意义的内存地址。对于动态申请的内存地址,在该内存释放之后,对应指针最好立即赋值为NULL。并在具体使用指针的时候判断指针的值是否有效(通常检测是否为NULL)。

3. 内存越界访问

内存越界访问通常发生在数组、字符串或者连续内存的访问。有两种情况:

读越界,即读了非有效的数据。如果所读的内存地址是无效的,程序会立即崩溃。如果所读内存地址是有效的,读入的时候不会有错误,但是读入的数据是随机的,可能会产生不可控制的后果。举个简单的例子,字符串的输出,如果没有结束符,会输出一堆乱码也可能输出正常,也就是说结果是不可控的。

写越界,亦称为缓冲区溢出,通常写越界会发生错误。内存写越界造成的后果是非常严重的。例如访问数组越界可能会修改访问数组的循环变量,造成死循环。另一个比较经典的例子就是缓冲区溢出攻击,试试上就是利用越界修改程序的栈空间,达到控制操作系统或者执行某些特定任务的目的。

这类问题几乎没有很有效的解决思路,只能由程序员控制好内存的访问,小心处理各种内存有关的操作。

4. 返回指向临时变量的指针

最经典的例子是一道面试题中关于字符串指针的返回函数,代码如下:

char * getString(){char b[] = "Hello, Tocy!"; return b;}

栈里面的变量都是临时的,函数执行完成之后,相关的临时变量和参数都会被清除。这也是程序不允许返回指向这些临时变量的指针的原因,因为函数执行结束后这些指针指向的数据是随机的,给程序造成不可预知的后果。

通常此类错误编译器会给出警告。解决思路很简单,在任何情况下不要返回函数的局部变量的任何指针,如果需要传递参数可以考虑使用返回值、参数或者全局变量(不推荐)。

5. 试图修改常量

在普通变量前面加上const修饰符,只是给编译器做类型检查用的。编译器禁止修改这样的变量,但这并不是强制的,完全可以用强制类型转换来处理,一般不会出错。例如下面代码:

int func(void){ const int IMAX = 3; int * pi = (int *)(&IMAX); *pi = 4; cout << IMAX << endl;}

笔者在vc6和vs2008下运行该函数,输出都是3,编译运行没有任何错误和警告。至于有没有修改常量的值,有兴趣的读者可以自己看看反汇编的代码,相信你就会明白是否修改了常量的值(最终结果是修改了,只是编译器做了某些优化所以输出依然不变。)。

而对于全局常量和字符串使用强制类型转来处理在运行时仍然会出错,这是因为它们是存放在只读内存区("rodata"),只读内存区是不允许修改的。试图对其修改,会引发内存错误。

所以针对这种类型错误,笔者建议最好不要修改常量,除非万不得已。

6. 内存未分配成功,但已经使用

通常是由于程序员认为动态内存分配不会失败。解决思路很简单,在使用动态申请的内存时,首先检测指针是否为NULL(通常动态内存分配失败会返回空指针)。

7. 内存分配成功,但没有初始化

犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。

内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。

当然发生这种情况还有另外一个可能就是在动态创建类对象时类构造函数抛出异常(即申请动态内存成功,但是调用构造函数失败)。

另外如果出现下图

基本可以断定是内存问题,极有可能是指针异常引起的。当然还有其他原因,需要视具体情况而定。

C++常见内存错误及解决方案相关推荐

  1. Java常见内存溢出(OOM)解决方案

    Java 常见内存溢出(OOM)解决方案 一,jvm内存区域   1,         程序计数器 一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器. 2,         java栈 与 ...

  2. PCL安装常见的错误集合解决方案(一)

    常见的错误集合解决方案(一) No.1 提示错误 'Microsoft.VC90.CRT,version="9.0.21022.8" 把Microsoft.NET Framewor ...

  3. 使用虚拟机安装Linux系统常见的错误以及解决方案

    使用虚拟机安装Linux系统常见的错误以及解决方案 参考文章: (1)使用虚拟机安装Linux系统常见的错误以及解决方案 (2)https://www.cnblogs.com/yanjiexiansh ...

  4. 大内高手—常见内存错误

    大内高手-常见内存错误 转载时请注明出处:http://blog.csdn.net/absurd 随着诸如代码重构和单元测试等方法引入实践,调试技能渐渐弱化了,甚至有人主张废除调试器.这是有道理的,原 ...

  5. 大内高手 常见内存错误

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 大内高手 ...

  6. 基于C++中常见内存错误的总结

    在系统开发过程中出现的bug相对而言是比较好解决的,花费在这个上面的调试代价不是很大,但是在系统集成后的bug往往是难以定位的bug(最好方式是打桩,通过打桩可以初步锁定出错的位置,如:进入函数前打印 ...

  7. SqlServer 内存篇(五)—— 常见内存错误与解决方法

    内存错误与内存瓶颈不同,当出现内存错误时,轻则某些特殊操作不能完成,重则整个sqlserver无响应,对sqlserver影响通常很大. sqlserver常见的内存错误主要有以下三种: 701 -- ...

  8. C++常见内存错误及解决办法

    发生内存错误是件非常麻烦的事情.编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到.而这些错误大多没有明显的症状,时隐时现,增加了改错的难度.有时用户怒气冲冲地把你找来,程序却没有发生任何问题, ...

  9. 微服务轮子项目(49) -常见JVM内存错误及解决方案

    文章目录 1. Java heap space 1.1 原因分析 1.2 解决方案 2. GC overhead limit exceeded 3. Permgen space 3.1 原因分析 3. ...

最新文章

  1. 浅谈JDBC与ODBC的区别与应用
  2. NYOJ 14 会场安排问题 贪心算法 之 选择不相交区间
  3. 第三次学JAVA再学不好就吃翔(part70)--BigInteger类
  4. vscode open in browser 默认浏览器
  5. Java中的全局变量与局部变量
  6. 通过JDBC来理解反射机制
  7. 浅谈C#托管程序中的资源释放问题 (转载)
  8. python爬取今日头条新闻,js解密
  9. MyBatis-Plus学习
  10. 408计算机及格要什么水平,2019考研计算机408难度水平?
  11. DHCP DHCPv6
  12. 《BDD100K: A Diverse Driving Dataset for Heterogeneous Multitask Learning》论文阅读笔记
  13. win7计算机无法远程桌面连接,解决win7无法被远程桌面连接教程
  14. 【高等数学】第 5 讲 偏导数
  15. 自建魔兽世界sf服务器,魔兽世界80自己搭服务器,热度却持续不到一天,全部用命令!...
  16. 如何在Windows系统上设置Tor
  17. Python的特点(优点和缺点)
  18. wasm(jsC++)0-开发环境搭建
  19. mysql截取邮箱后缀_截取邮箱格式以及统计邮箱总数
  20. AR Kit Core ML 将救百万iOS开发者于水深火热中

热门文章

  1. uniappH5+springboot微信授权登录获取用户数据(非静默授权)
  2. 【数据结构】树与二叉树
  3. Lucene入门及操作详解
  4. java cdata xml 解析_解析XML CDATA块
  5. 【嵌入式系统开发13】采用串口中断方式完成单字符接受与字符串接受
  6. 前端开发:JS的构造函数
  7. ROM、FLASH 和 RAM 的区别
  8. SpringBoot实现基础的sso单点登录
  9. php 检测表格双击操作,PHP+jQuery实现双击修改table表格功能示例
  10. Centos6 安装RepoForge(又叫RPMForge)