我们在使用指针时,经常会出现下面几种错误:

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。导致产生“野指针”。

使用指针过程中我们应该遵循下面几条原则:

【规则1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。

【规则2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。

【规则3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。

【规则4】动态内存的申请与释放必须配对,防止内存泄漏。

【规则5】用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。

下面来看一个可能出现野指针的例子:

我们在使用结构体内循环嵌套结构体指针的问题,错误隐蔽。请看如下代码:

//定义一个结构体A,包含一个int变量btypedef struct
{
     int b;
}A;//定义一个结构体B,包含一个A结构体指针a和一个int变量c
typedef struct
{
     A* a;
     int c;
}B;//初始化B结构体指针
void Initialization( B* myB )
{
      myB->c=;
}
void main( int argc,char* argv )
{
      A myA;
      myA.b=;
      B* myB;
      Initalization( myB );
      myB->a->b=;
      printf( "the values of c:%d", myB->c );
}

模块1和模块2都是很正常的结构体声明,没有任何问题。而模块3和模块4就涉及指针问题,需要我们慎重考虑,而以上代码在编译器上运行时也会报告段错误。

解决方法:我们在声明类型的指针变量时一定要同时初始化,不能把它变成野指针。模块3和模块4都是同样的问题,指针变量本身申请的内存空间,但其指向那一片的类型地址却没有得到定义,所以我们要为其申请空间并初始化指针变量:

typedef struct
{
     int b;
}A;
typedef struct
{
     A* a;
     int c;
}B;
void Initialization( B* myB )
{
     myB->a = malloc(sizeof(A));/*不要忘了初始化*/
     myB->c=;
}
void main( int argc,char* argv )
{
     A myA;
     myA.b=;
     B* myB = malloc(sizeof(B));/*使用前要初始化*/
     Initalization(myB);
     myB->a->b=;
     printf( "the values of c:%d", myB->c );
}

这样就不会出现段错误了,你会发现代码能正常运行了。最后别忘了用free(myB).....释放自己在堆中分配的内存,养成良好的习惯。

总结:指针变量是用来存放内存地址的,而其本身也是一个变量,也要在内存中分配地址,而程序员往往把本身要存储的地址当成是以存储的其它类型地址,所以导致访问时其指针变量并没有存储地址,到时访问违规,出现段错误。在我们声明指针变量时,一定要只要它要用来干什么,并在声明时就初始化它。

C++指针之防不胜防的更多相关文章

  1. NULL指针、零指针、野指针

    1.1.空指针 如果 p 是一个指针变量,则 p = 0; p = 0L; p = '\0'; p = 3 - 3; p = 0 * 17;p=(void*)0; 中的任何一种赋值操作之后, p 都成 ...

  2. [3] 智能指针std::auto_ptr

    [1]std::auto_ptr 对于编译器来说,智能指针实质是一个栈对象,而并非指针类型. 智能指针通过构造函数获取堆内存的管理所有权,而在其生命期结束时,再通过析构函数释放由它所管理的堆内存. 所 ...

  3. 野指针、NULL指针和void*

    一.野指针 “野指针”不是NULL指针,是指向“垃圾”内存的指针. “野指针”的成因主要有三种: (1)指针变量没有被初始化.任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱 ...

  4. 浅谈 “空指针、野指针、void*”

            Author: JW. Zhou Date: 2014/7/2 一.空指针(0/NULL) 返回NULL和返回0是完全等价的,因为NULL和0都表示空指针,换句话说:空指针是什么,就是 ...

  5. (转) 谈C/C++指针精髓

    原文:http://www.cnblogs.com/madengwei/archive/2008/02/18/1072410.html   [摘要]    指针是C和C++语言编程中最重要的概念之一, ...

  6. 【C++】智能指针详解(一):智能指针的引入

    智能指针是C++中一种利用RAII机制(后面解释),通过对象来管理指针的一种方式. 在C++中,动态开辟的内存需要我们自己去维护,在出函数作用域或程序异常退出之前,我们必须手动释放掉它,否则的话就会引 ...

  7. 智能指针剖析(上)std::auto_ptr与boost::scoped_ptr

    1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...

  8. C语言野指针

    本文转载自:http://blog.csdn.net/xwdok/article/details/576497 "野指针"不是NULL指针,是指向"垃圾"内存的 ...

  9. C++智能指针剖析(上)std::auto_ptr与boost::scoped_ptr

    1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...

随机推荐

  1. WCF服务接口多,客户端在引用时出错!报WCF The maximum nametable character count quota (16384) has been exceeded while reading XML data错误

    WCF服务接口多,客户端在引用时出错!报WCF The maximum nametable character count quota (16384) has been exceeded while ...

  2. Ant执行Jmeter工程模版

    <?xml version="1.0" encoding="GB2312"?><project name="ant-jmeter-t ...

  3. 怎么理解Android版本兼容???

    程序中设置了minSdkVersion和targetSdkVersion如下: <uses-sdk android:minSdkVersion="8" android:tar ...

  4. 什么是FOUC?如何避免FOUC?///////////////////////////zzzz

     一个新的名词叫做 FOUC 浏览器样式闪烁,之前也听说过一些类似的东西,比如样式突变等等,但这东西竟然有学名的..什么是FOUC(文档样式短暂失效)?如果使用import方法对CSS进行导入,会导致 ...

  5. Gulp学习指南之CSS合并、压缩与MD5命名及路径替换(转载)

    本文转载自: Gulp学习指南之CSS合并.压缩与MD5命名及路径替换

  6. 理解NDCG

    关于NDCG,wiki给点解释很详细,这里我谈谈我的理解. NDCG(Normalized discounted cumulative gain):是用来衡量排序质量的指标. 其中一种计算公式如下: ...

  7. 编写高性能Web应用程序的10个技巧

    这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...

  8. 操作SSIS之前的准备工作

    SSIS的历史概述: 在SQL Server7.0中,微软成立了一个很小的开发团队开发SQL Server中一个非常低调的功能,该功能被称为DTS(数据转换服务),该功能一直被沿用到SQL2000. ...

  9. postgresql流复制配置

    一.配置环境: 示例环境 主机名 IP 角色 系统版本 数据目录 pg版本 db1 192.168.128.128 主库 RedHat5.3 /app/postgreSQL/data 9.1.7 db ...

  10. oracle 金额格式化

    一般金额要显示成 XXX,XXX,XXX.XX的格式,可以这样做: to_char(column, 'FM999,999,999,990.00')