TreeNode* root与TreeNode* &root作为函数参数的区别是什么?
TreeNode* root和TreeNode* &root作为函数形参的区别 这两种写法实际效果存在本质区别,绝对不能混用。
1. 传TreeNode* root的本质:值传递的指针
- 函数接收到的是实参指针的拷贝副本,形参和实参是两个独立的指针变量,只是初始时指向同一块TreeNode内存。
- 在函数内通过这个指针修改指向的TreeNode对象内容(比如修改
root->val、给root->left/root->right赋值),因为操作的是同一块内存,外部的实参能感知到变化。 - 但如果在函数内直接修改形参指针本身的指向(比如写
root = new TreeNode()、root = nullptr),改动只作用在本地副本上,外部的实参指针不会有任何变化。
2. 传TreeNode* &root的本质:指针的引用传递
- 形参是外部实参指针的别名,没有拷贝过程,形参和实参完全是同一个东西。
- 除了能正常修改指向的TreeNode对象内容之外,在函数内修改指针本身的指向(给root重新赋值新地址、置空),改动会直接作用在外部的实参指针上,函数执行完外部能直接拿到改动后的指针值。
直观代码示例
#include <iostream> using namespace std; struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; // 值传递指针 void func1(TreeNode* root) { root = new TreeNode(100); // 仅修改本地副本指针 } // 引用传递指针 void func2(TreeNode* &root) { root = new TreeNode(200); // 直接修改外部实参指针 } int main() { TreeNode* p = nullptr; func1(p); cout << "After func1, p is nullptr? " << (p == nullptr ? "Yes" : "No") << endl; // 输出Yes,func1的改动没有影响外部p func2(p); cout << "After func2, p->val = " << p->val << endl; // 输出200,func2直接改了外部p的指向 return 0; }
常见使用场景
- 日常做二叉树遍历、查询、修改已有节点属性的操作时,用
TreeNode* root就足够,不会有问题。 - 当需要在函数内修改传入的指针本身的指向——比如写二叉树插入/删除节点逻辑、递归建树时需要给上层返回新创建的根地址、处理空节点要挂载新节点的场景,必须用
TreeNode* &root,否则对指针本身的赋值无法传递到函数外,会出现逻辑错误。
最常见的踩坑场景:写二叉搜索树插入递归函数时用值传递指针,递归到空节点位置给root赋了新节点,运行完发现树里根本没插入新节点,本质就是值传递只改了副本指针,上层的左右孩子指针根本没被更新。
内容的提问来源于stack exchange,提问作者arpit jain
相关产品推荐
相关产品推荐

