美文网首页
[转]C/C++野指针

[转]C/C++野指针

作者: 杰米 | 来源:发表于2016-10-13 00:42 被阅读75次

    一、 莫名的恐惧感
    对于指针确实有种莫名的恐惧感,从刚开始学习的时候就被老师灌输的概念是指针功能很强大,但是用得不够好,会有很大的副作用。什么叫用得够好?初学者谁都不会用,那且不是都不能用了?如果都这样,指针都没人用了,还要指针做什么?
    陷入了上述困局的原因在于我们的这种莫名的恐惧感,指针如此之神秘,以至于如我一样大多数的人都望而生畏,无所适从,被迫放弃。

    二、野指针
    诚如当初老师的忠告一样, 指针是个很强大的工具,可是正因为它太强大,所以要操作它不是件易事。操作不当造成的野指针,甚至会引起系统死机等比较严重的后果。
    如果程序定义了一个指针,就必须要立即让它指向一个我们设定的空间或者把它设为NULL,如果没有这么做,那么这个指针里的内容是不可预知的,即不知道它 指向内存中的哪个空间(即野指针),它有可能指向的是一个空白的内存区域,可能指向的是已经受保护的区域,甚至可能指向系统的关键内存,如果是那样就糟 了,也许我们后面不小心对指针进行操作就有可能让系统出现紊乱,死机了。所以我们必须设定一个空间让指针指向它,或者把指针设为NULL,这是怎么样的一 个原理呢,如果是建立一个与指针相同类型的空间,实际上是在内存中的空白区域中开辟了这么一个受保护的内存空间,然后用指针来指向它,那么指针里的地址就 是这个受保护空间的地址了,而不是不可预知的啦,然后我们就可以通过指针对这个空间进行相应的操作了;如果我们把指针设为NULL,我们在头文件定义中的 #define NULL 0 可以知道,其实NULL就是表示0,那么我们让指针=NULL,实际上就是让指针=0,如此,指针里的地址(机器数)就被初始化为0了,而内存中地址为0 的内存空间……不用多说也能想象吧,这个地址是特定的,那么也就不是不可预知的在内存中乱指一气的野指针了。

    还应该注意的是,free和delete只是把指针所指的 内存给释放掉,但并没有把指针本身干掉。指针p被free以后其地址仍然不变(非NULL),只是该地址对应的内存是垃圾,p成了“野指针”。如果此时不 把p设置为NULL,会让人误以为p是个合法的指针。用free或delete释放了内存之后,就应立即将指针设置为NULL,防止产生“野指针”。内存 被释放了,并不表示指针会消亡或者成了NULL指针。(而且,指针消亡了,也并不表示它所指的内存会被自动释放。)
    三 例说野指针
    例子1:
    首先请诸位看以下一段“危险”的C++代码:

    void function( void )  
    {  
        char* str = new char[100];  
        delete[] str;  
        // Do something  
        strcpy( str, "Dangerous!!" );  
    }       
    
        之所以说其危险,是因为这是一段完全合乎语法的代码,编译的时候完美得一点错误也不会有,然而当运行到strcpy一句的时候,问题就会出现,因为在这之 前,str的空间已经被delete掉了,所以strcpy当然不会成功。对于这种类似的情况,在林锐博士的书中有过介绍,称其为“野指针”。
    

    例子2:——指针初始化引出的问题
    对指针初始化时,引出的应该注意的问题小结:
    (1)先看例子:

    include

    void main()
    {
    char p,p1="hello first!";
    while((*(p++) = *(p1++)) != 0);

    cout<
    }
    错处:
    p定义时没有初始化,p是指向不定,是一个野指针。
    p++可能引用得空间为非法的。
    编译时不会出错,但运行时会造成程序崩溃。
    (2)把上面的p初始化为NULL

    include

    void main()
    {
    char p=NULL,p1="hello first!";
    while((*(p++) = *(p1++)) != 0);

    cout<
    }
    也错:
    NULL表示没有任何指向。p++没有任何意义,运行时会造成程序崩溃。这里就应该想到不能对NULL的指针进行直接操作。
    (3)现在为p初始化为" ":
    void main()
    {
    char p=" ",p1="hello first!";

    while((*(p++) = *(p1++)) != 0);

    cout<
    }
    还错:
    p指向的是一个const常量的内容,可以通过*(p++)形式引用该值,但是不能改变它指向const的内容。
    (4)

    include

    include

    void main()
    {
    char c[]="";
    char p=c,p1="hello first!";
    char p_start=p;
    while((
    (p++) = *(p1++)) != 0);

    cout<
    }
    问题:
    此时数组是一系列的变量了,也就是p一有指向,二不是指向常量的而是指向变量的。所以按理应该行的。问题出在c太小,造成了数组越界,所以错掉!把c的大小改来不比"hello first!"小就行了。
    5)对于的就想到用new来初始化了:

    include

    include

    void main()
    {
    char p,p1="hello first!";
    p=new char;
    char p_start=p;
    while((
    (p++) = *(p1++)) != 0);

    cout<
    }
    现在就可以了,哈,不过,我认为在new时最好还是把它的大小给指出来,如new char[strlen(p1)+1];如果不指定大小,我想p++会指向一些已用得地址,而这些地址又不能随便改,就会造成诸如野指针样程序崩溃了。
    小结:对于前面的问题,不防这样来写:

    include

    include

    void main()
    {
    char p=NULL,p1="hello first!";
    p=new char[strlen(p1)+1];
    //p=new char; //觉得最好别这样子,new char只相当于得到一个char对
    char p_start=p; //象,分配一个字符的空间。
    while((
    (p++) = *(p1++)) != 0);

    cout<
    }
    四 造成野指针的原因
    1、指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的默认值是随机的,它会乱指一气。
    2、指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
    3、指针操作超越了变量的作用范围。这种情况让人防不胜防。

    五 正确使用指针
    通常避免野指针的办法是正确的使用指针
    1.声明一个pointer的时候注意初始化为null :
    int* pInt = NULL;

    2.分配完内存以后注意ASSERT:
    pInt = new int[num];
    ASSERT(pInt != NULL);

    3.删除时候注意用对操作符:
    对于new int类型的,用delete
    对于new int[]类型的,用delete []

    4.删除完毕以后记得给他null地址:
    delete [] pInt;
    pInt = NULL;

    5.记住,谁分配的谁回收,不要再一个函数里面分配local pointer,送到另外一个函数去delete。

    6.返回local address是非常危险的,如必须这样做,请写注释到程序里面,免得忘记。

    原文

    相关文章

      网友评论

          本文标题:[转]C/C++野指针

          本文链接:https://www.haomeiwen.com/subject/ttcwyttx.html