• “指向指针的引用”小例子:忽然豁然开朗~


    之前没有碰到过这类情况,也不知道实际工程中有什么奥妙,先来一个小的测试例子看一下运行结果:

      int a = 1;

      int b = 2;  

      int *tmp = &a;

      int *p = tmp;// 第二种情况:int *&p = tmp;(此既是指向指针的引用)

      p = &b;

      *p = 5;

    1、测试此时的a, b , *tmp, *p分别是什么: a = 1, b = 5, *tmp = 1, *p = 5;

    2、如果是上述第二种情况,即指向指针的引用,那么这些变量又该是什么值呢?答案是:

      a = 1, b = 5, *tmp = 5, *p = 5;

      这是因为指向指针的引用,不仅改变了指针所指的对象,也改变了指针本身。

    下面以Essential C++ P177的代码举例:

    该代码是为了删除一个二叉树中等于某个值的节点:

     1 void BTnode::remove_value( const int& val, BTnode *& prev ) //二叉有序树中删除节点值_val == val的节点
    2 {
    3 if ( val < _val ) //往左子树遍历查找
    4 {
    5 if ( !_lchild )
    6 {
    7 return; //不在此二叉树中
    8 }
    9 else _lchild->remove_value( val, _lchild );
    10 }
    11 else
    12 if ( val > _val ) // 往右子树遍历查找
    13 {
    14 if ( !_rchild )
    15 {
    16 return; //不在此二叉树中
    17 }
    18 else _rchild->remove_value( val, _rchild );
    19 }
    20 else
    21 { //哈哈!~找到了~就是你啦!!
    22 if ( _rchild ) //看看这个要被删除的节点是否有右孩子
    23 { //果然有~~有点小麻烦了~~哎
    24 prev = _rchild;
    25 if ( _lchild ) //要删除的节点还有左孩子~得想办法把左孩子弄到右子树下面去,这样才能删除我这个节点
    26 {
    27 if ( !prev->_lchild ) //看看右子树是否有一堆左孩子
    28 {
    29 prev->_lchild = _lchild;
    30 }
    31 else BTnode::lchild_lead(_lchild, prev->_lchild);//遍历到右子树最左节点
    32 }
    33 }
    34 else prev = _lchild;
    35 delete this; //不用怕删除了本节点以后,我的孩子们连不到我的父辈节点们~~一句prev = _rchild解决了一切~~
    36 }
    37 }

     上面代码中红色部分是最关键的地方,比如下面这棵树: 

    其中的null是没有节点(我这样加个null是为了让6看起来是右孩子)。

    在这个图里,我要删除5节点。若函数中参数是指针,而不是指向指针的引用。那么上述程序,就会造成删除了5节点以后,二叉树断成两部分。(prev = _rchild;这里我们只把prev重新改变为_rchild的值,而并没有改变5这个地址所指向的值,但我们程序中这一句就要让5的地址也改变)

    而如果是指向指针的引用,prev = _rchild;这一句就会把5这个地址赋值为6的地址,这样删除5(即delete this;)之后就不会造成二叉树的断链问题。

    Essential C++ P177是这么描述的:

      为什么我们将prev以一个reference to pointer来传递呢?难道用单纯的pointer传递还不够吗?不,不够!以pointer来传递,我们能够更改的是该pointer所指之物,而不是pointer本身。为了该表pointer本身,我们必须再加一层间接性。如果将prev声明为reference to pointer,我们不但可以改变pointer本身,也可以改变由此pointer指向的对象。

  • 相关阅读:
    C++函数参数传参的本质解析
    C#值类型和引用类型详解
    C#学习笔记(转换)
    C#学习笔记(泛型)
    # Java反射2——获取实体所有属性和方法,并对属性赋值
    Java反射1——扫描某个包下的所有类
    JSR教程2——Spring MVC数据校验与国际化
    JSR教程1——JSR 303
    Github如何撤销提交并清除痕迹
    论文第5章:Android绘图平台的实现
  • 原文地址:https://www.cnblogs.com/ziyoudefeng/p/2413295.html
Copyright © 2020-2023  润新知