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

来源:岁月联盟 编辑:exp 时间:2012-03-26

之前没有碰到过这类情况,也不知道实际工程中有什么奥妙,先来一个小的测试例子看一下运行结果:
  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指向的对象。

 摘自 ziyoudefeng