指针参数在函数中不能改变指针指向的原因和解决

系统 1873 0

 

原始问题

      实现二叉树排序,需要使用一个数组构建一个二叉排序树,最开始写的代码如下:

      
        struct
      
      
         BST{

    
      
      
        int
      
       number; 
      
        //
      
      
        保存数组元素的值
      
      
        struct
      
       BST*
      
         left;

    
      
      
        struct
      
       BST*
      
         right;

};




      
      
        void
      
       insertBST(BST* tree, 
      
        int
      
      
         v) {

    
      
      
        if
      
       (tree ==
      
         NULL) {

        tree 
      
      = 
      
        new
      
      
         BST;

        tree
      
      ->left=tree->right=
      
        NULL;

        tree
      
      ->number=
      
        v;

        
      
      
        return
      
      
        ;

    }

    
      
      
        if
      
       (v < tree->
      
        number)

        insertBST(tree
      
      ->
      
        left, v);

    
      
      
        else
      
      
        

        insertBST(tree
      
      ->
      
        right, v);

}




      
      
        void
      
       createBST(BST* tree, 
      
        int
      
       a[], 
      
        int
      
      
         n) {

    tree 
      
      =
      
         NULL;

    
      
      
        for
      
       (
      
        int
      
       i=
      
        0
      
      ; i<n; i++
      
        )

        insertBST(tree, a[i]);

}
      
    

      结果发现每次进入insertBST的时候,tree指针都是空的。用简单的例子做实验,发现如果一个指针为NULL,那么在函数中指向一个对象,函数返回后指针依旧为空,即函数中更改指针指向的对象无效。

      
        void
      
       tmp(
      
        int
      
      *
      
         a)

{

        
      
      
        if
      
       (a==
      
        NULL)

        {

              a
      
      =
      
        new
      
      
        int
      
      
        ;

              
      
      *a=
      
        200
      
      
        ;

         }

         
      
      
        else
      
      

              *a=
      
        100
      
      
        ;

}




      
      
        int
      
      
         main()

{

    
      
      
        int
      
      * b=
      
        NULL;

    tmp(b);

    
      
      
        if
      
       (b ==
      
         NULL)

        cout 
      
      << 
      
        "
      
      
        b is null
      
      
        "
      
      
        ;

    
      
      
        else
      
      
        

        cout 
      
      << *b << 
      
        "
      
      
        "
      
      
        ;

}
      
    

      运行上述代码,发现输出“b is null”,即b指针在tmp函数中被赋值无效。

      而如果b指针预先执行一个对象,那在tmp函数中改变其值是有效的。即在int*b = NULL下边加上一行b=new int;的代码,可以输出改变后值为100.

 

      如果希望在函数中为指针复制,可以使用额外一层的指针,具体代码如下:

      
        void
      
       tmp(
      
        int
      
      **
      
         a)

{

        
      
      
        if
      
       (*a==
      
        NULL)

        {

              
      
      *a=
      
        new
      
      
        int
      
      
        ;

              
      
      **a=
      
        200
      
      
        ;

         }

         
      
      
        else
      
      

              **a=
      
        100
      
      
        ;

}




      
      
        int
      
      
         main()

{

    
      
      
        int
      
      * b=
      
        NULL;

    tmp(
      
      &
      
        b);

    
      
      
        if
      
       (b ==
      
         NULL)

        cout 
      
      << 
      
        "
      
      
        b is null
      
      
        "
      
      
        ;

    
      
      
        else
      
      
        

        cout 
      
      << *b << 
      
        "
      
      
        "
      
      
        ;

}
      
    

此时可以输出200.

 

问题分析

      为NULL的指针在函数中指向一个对象无效。而初始化之后可以改变指向对象的值。

      指针本身也是一个值,它的值是所指向对象的地址。 指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值 传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即 在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成 为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操 作都是作为局部变量进行,不会影响主调函数的实参变量的值。

      回到上述例子上,指针在传递时,相当于,在被调函数中,申明了一个int*的变量,其值就是传递进来的int*.即调用tmp(b)时,会执行 int* c=int*b; 那么在被调函数的堆栈中修改局部变量int*c是 当然也是不会影响到int*b的地址。

      但是当b指针不为NULL的时候,改变b指针的值会有效,这是因为局部变量c和参数b指向的是同一个对象,针对这个地址的修改在函数返回式依然有效。

 

解决方法

      双重星号的方式是有效的。

      此时传递的不再是b指针的值,而是通过&b传递的b指针的地址,此时是参数是引用传递的,引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈 中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量 的地址。被调 函数对形参的任何操作都被处理成间接寻址,即通过栈 中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对 形参做的任何操作都影响了主调函数中的实参变量。因此可以在函数中改变b指针的值,也就是指针指向的对象。

 

      可以看出,对指针取地址,函数定义的时候使用双重星号的作用不仅仅是为指针赋初始值,还可以在函数中改变指针指向哪个对象,而在普通的指针参数传递中,函数只能改变指针指向对象的值,不能改变指针具体指向哪个对象。

 

      说到底,出现该问题的原因还是对指针的理解以及对参数传递方式的理解不够到位。

 

      完整的二叉树排序代码见上一篇博客: http://www.cnblogs.com/zhaoshuai1215/p/3448154.html

 

指针参数在函数中不能改变指针指向的原因和解决方法


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论