为何修改C++二叉树push函数参数后程序无法运行?
核心原因是C++默认的参数传递是值传递,哪怕是指针类型的参数,传递的也是指针的副本,而非指针本身。下面分别分析两个版本的差异:
原程序(node**参数)的工作逻辑
原程序的push函数接收node** t,也就是指针的指针,传递的是原指针的内存地址(比如调用push(s, &tree)时,&tree是全局变量tree的地址)。
在函数中,(*t)直接操作的是原指针本身:
if ((*t) == NULL) { (*t) = new node; // 这里修改的是原指针(比如全局的tree)的指向 (*t)->data = a; (*t)->left = (*t)->right = NULL; return; }
第一次调用push时,(*t)就是初始为NULL的全局tree,执行(*t)=new node后,tree会被修改为指向新创建的节点;后续递归调用通过&(*t)->right/&(*t)->left传递子节点指针的地址,确保修改的是原树结构中的指针指向,最终能正确构建二叉树。
修改后程序(node*参数)的问题
修改后的push函数接收node* t,此时传递的是指针的副本:调用push(s, tree)时,会把tree的值(初始为NULL)复制给临时变量t,函数内对t的修改只会作用于这个副本,和原指针tree毫无关系。
比如第一次调用时:
if ((t) == NULL) { (t) = new node; // 这里只修改了副本t的指向,原tree还是NULL (t)->data = a; (t)->left = (t)->right = NULL; return; }
函数执行完后,副本t被销毁,全局的tree仍然是NULL。后续所有调用都不会改变tree的指向,最终print函数接收的是NULL,自然不会输出任何内容。
关于你做的测试代码
你写的这段测试代码存在未定义行为,不能作为指针逻辑的参考:
int *tree; int **treePointer; cout << (tree = *treePointer) <<endl; // Shows 1 i.e. true
tree和treePointer都是未初始化的野指针,*treePointer访问的是随机内存地址,赋值给tree后输出的结果完全不可靠,无法说明指针的工作机制。
修复修改后程序的方法
如果想让修改后的程序正常工作,可以把参数改成指针的引用,这样函数内的修改会直接作用于原指针:
void push(int a, node* &t) // 使用node*&,即指针的引用 { if (t == NULL) { t = new node; t->data = a; t->left = t->right = NULL; return; } if (a > t->data) push(a, t->right); else push(a, t->left); }
调用时直接传tree即可:push(s, tree),此时函数内对t的修改就是对原tree的修改,能正常构建二叉树。
内容的提问来源于stack exchange,提问作者bababoah

