C/C++常见指针错误 and 内存访问越界

您所在的位置:网站首页 c语言越界访问是什么意思啊 C/C++常见指针错误 and 内存访问越界

C/C++常见指针错误 and 内存访问越界

2024-07-07 20:19| 来源: 网络整理| 查看: 265

1) 内存分配未成功,却使用了它。

   编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。

2) 内存分配虽然成功,但是尚未初始化就引用它。

   犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。

3) 内存分配成功并且已经初始化,但操作越过了内存的边界。

   例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。

4) 忘记了释放内存,造成内存泄露。

   含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete同理)。

5) 释放了内存却继续使用它。 

有三种情况: (1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。 (2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。 (3)使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。 【规则7-2-1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。 【规则7-2-2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。 【规则7-2-3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。 【规则7-2-4】动态内存的申请与释放必须配对,防止内存泄漏。 【规则7-2-5】用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。

参见http://hi.baidu.com/wangysh/blog/item/56275bc2114b6e36e5dd3bc1.html

自己编写的一个不小的程序一直在运行退出时出错,我对指针的使用很仔细但很长时间检查不到错误,最后发现在一个地方没有遵照规则【7-2-5】,大家如果指针出错,一定要仔细的慢慢检查,相信自己。

《c++内存访问越界》

1. 原理分析

经常有些新C++程序员问:C++的类的成员个数是不是有限制,为什么我加一个变量后程序就死了?或者说:是不是成员变量的顺序很重要,为什么我两个成员变量顺序换一换程序就不行了?凡此种种之怪现象,往往都是内存访问越界所致。 何谓内存访问越界,简单的说,你向系统申请了一块内存,在使用这块内存的时候,超出了你申请的范围。例如,你明明申请的是100字节的空间,但是你由于某种原因写入了120字节,这就是内存访问越界。内存访问越界的后果是:你的写入破坏了本不属于你的空间。 下面是一个简单的例子: int a; char b[16]="abcd"; int c; a = 1; c = 2; printf("a=%d,c=%d\n", a,c); memset(b, 0,32); //注意这里访问越界了,你只有16字节空间,却修改了32字节 printf("a=%d,c=%d\n", a,c); 你可以看出,在memset前后,两个printf语句打印出来的值并不一样,因为memset越界后修改了a或者c的值(由于不同编译器对变量在空间中顺序的安排可能有不同策略,因此我用两个变量,希望能抓到越界信息。对于VC,debug模式下系统添加了很多填充字节,你可能需要增加越界的数量才能看到效果) 2. 为什么增加一个变量后程序就崩溃了? 增加一个变量后,内存中变量的布局也发生了变化。如果一个内存越界破坏了一个不含指针的结构,程序虽然逻辑不对,但是不至于崩溃。但是如果增加变量后,内存访问越界破坏了一个指针,则会导致程序崩溃。 例如:(这个例子没看明白,好像有点问题) int a; char b[128]; //bool c; char* d=new char[128]; int e; b[136] = '\0'; b[137] = '\0'; b[138] = '\0'; b[139] = '\0'; strcpy(d, "haha"); 注意, b访问越界了8个字节位置处的4个字节。如果没有c,那么越界破坏了e变量,不会导致程序崩溃。但是加上c之后,破坏的变量可能就是d了,由于指针被破坏后,一旦访问就是内存访问违例,导致程序崩溃。 这也解释了为什么交换顺序会导致程序崩溃。如果上面情况没有变量c,你交换e和d,结构也是类似的,程序也一样要崩溃。 3. 为什么有些情况越界了程序也没错? 这主要是说这个话的人对什么是“错”没有正确的认识。程序不是只有崩溃了才是错!你破坏了别的变量,那个变量总有被使用的时候,尽管那个变量不会导致诸如程序崩溃、报警之类的严重错误,但是其计算结果必然是错误的。你说“程序没错”,是因为你根本没有发现错误而已。这种情况甚至比程序直接崩溃还要恶劣,因为程序一旦崩溃你肯定会去查,可以在导致真正严重的问题之前就把问题解决了。而如果计算错误隐藏到很晚,你的损失就可能很大了。(例如,一颗卫星上天了,你才发现一台仪器由于软件故障无法测量真正的数据,那得多少损失?) 4. 如何解决内存访问越界问题? 老实说没有好的方法。遇到这种问题,首先你得找到哪里有内存访问越界,而一个比较麻烦得问题在于,出现错误得地方往往不是真正内存越界得地方。对于内存访问越界,往往需要进行仔细得代码走查、单步跟踪并观察变量以及在调试环境得帮助下对变量进行写入跟踪(如VC6就有一旦变量被修改就break得机制)。

更重要得是,程序员要养成良好的编程习惯,在修改每个数组时一定要对这个数组有多少空间有清醒的认识,否则一旦出错,找到原因是很痛苦的事情。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3