• C++指针之防不胜防


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

     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变量b
    typedef struct { int b; }A;
    //定义一个结构体B,包含一个A结构体指针a和一个int变量c typedef
    struct { A* a; int c; }B;
    //初始化B结构体指针
    void Initialization( B* myB ) { myB->c=8; } void main( int argc,char* argv ) { A myA; myA.b=8; B* myB; Initalization( myB ); myB->a->b=9; 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=8;
    }
    void main( int argc,char* argv )
    {
         A myA;
         myA.b=8;
         B* myB = malloc(sizeof(B));/*使用前要初始化*/
         Initalization(myB);
         myB->a->b=9;
         printf( "the values of c:%d", myB->c );
    }

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

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

  • 相关阅读:
    浅谈移动前端的最佳实践(转)
    程序员的个人发展注意事项(转)
    SQL Server 维护计划实现数据库备份(Step by Step)
    每日一SQL-善用DATEADD和DATEDIFF
    Entity Framework Code First (一)Conventions
    臣服不代表解放你的手
    写在那个毕业五年的日子(转)
    测试驱动开发实践
    领域驱动设计实践上篇(转)
    WebAPI使用多个xml文件生成帮助文档(转)
  • 原文地址:https://www.cnblogs.com/Arthurian/p/6188657.html
Copyright © 2020-2023  润新知