我们对二叉树建立, 一般使用的方法是递归建立,这样的代码量最小,也最容易理解,但是这会牵扯到修改指针的值的问题,在看书中源码之时,我一直不太理解那段代码:
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
void CreateBiTree(BiTree* T) //传入的是指向指针的指针
{
TElemType ch;
scanf("%c",&ch);
if(ch == #')
{
*T = NULL;
}
else
{
*T = (BiTree )malloc( sizeof(BiTNode));
(*T)->data = ch;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
}
我一直很好奇,为什么我需要在这个递归建立二叉树的函数中传入指针的指针,因为我认为,我只需要传入节点的孩子就可以了,不需要传入指向孩子的指针。
所以,很荣幸,程序马上就崩溃了,我经历过反复调试,才发现,原来节点的左右孩子指针完全没有改变,这时我才明白,为什么需要传入指向指针的指针,原来我需要在函数中改变指针的值,也就是对指针进行重新赋值,并且这个副作用需要影响到实参。
这个程序加深了我对指针这个概念的理解,本身我对于指针的理解就是通过指针我可以改变指针指向的元素的值,而对于指针的指针我并不熟悉,因为我不清楚这个到底是需要使用在哪里。
如果你需要在函数中修改指针的值,而不是指针指向的元素的值,那么这个指针对于你来说就是一个元素,你在函数中获得的这个指针是原来指针的副本,只是指向同一个地址,所以你可以借助这个副本指针去修改实参中的值,但是你直接修改指针的值(改变指针指向的地址)是无法对实参产生影响的,因为他只是个副本指针。
所以你想通过函数对指针的值进行修改,在C++中有下面两种做法:
void function1(int ** p)
{
//这里传入的是指向指针的指针
(*p) = new int(5); //修改指针指向的地址
}
void function2(int* (&p))
{
//这里传入的是指针的引用
p = new int(5); //通过引用与指针绑定,直接修改指针的值
}
在自行编写过树的代码后,我才意识的一句话,在C++中能使用引用的地方尽量使用引用。我们若是想使用指针来修改元素值,那么我们需要确定元素的实际地址才行,因为函数中传递进去只是实参的副本,而引用为我们提供了一种简便的方法,直接将实参与形参绑定,这样我们就可以直接修改形参来影响到实参。