代码是这样的:
void insertNode(TreeNode **root, COMPARE compare, void* data) {
TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));
node->data = data;
node->left = NULL;
node->right = NULL;
if(*root == NULL) {
*root = node;
return;
}
while(1){
if(compare((*root)->data, data) > 0) {
if((*root)->left != NULL) {
*root = (*root)->left;
} else {
(*root)->left = node;
break;
}
} else {
if ((*root)->right != NULL) {
*root = (*root)-> right;
} else {
(*root) -> right = node;
break;
}
}
}
}
指针永远不会像root
那样使用,并始终用作(*root)
。它不是TreeNode **root
多余的吗?可以在TreeNode *root
的参数中减少,并且函数体中的部分从root
更改为(*root)
。如果不是为什么?
答案 0 :(得分:1)
不,它不是多余的。 C是一种严格的按值传递语言,如果你想更改传入的参数(你确实相信我),C模拟带有指针的传递引用。
在您的情况下,您想要更改TreeNode *
类型的变量,因此您需要传递指向该变量的指针,这就是您具有双重间接的原因。
不要被你似乎已经指针的事实所迷惑,在你的情况下,它在概念上与以下相同:
void changeInt (int *pXyzzy) { *pXyzzy = 42; }
除了用于更改int
之外。如果您想更改int *
,则需要:
int some_int = 42;
void changeIntPtr (int **ppXyzzy) { *ppXyzzy = &some_int; }
注意间接的附加级别。这更像是你需要的东西,因为你将指针改为某个东西(所以你需要一个双指针)。
如果没有传递&some_treenode_pointer_variable
并通过*some_treenode_pointer_variable = something
进行设置,则更改后的值永远不会找回返回调用者的方式(变量,是按值传递,只是本地副本。)
检查以下代码及其输出可能会有所帮助。方法1尝试通过简单设置来更改指针,方法2使用指针指针方法尝试更改它:
#include <stdio.h>
static int someInt;
static void method1 (int *pXyzzy) {
printf ("Pointer on calling method1 = %p\n", pXyzzy);
pXyzzy = &someInt;
printf ("Pointer on exiting method1 = %p\n", pXyzzy);
}
static void method2 (int **ppXyzzy) {
printf ("Pointer on calling method2 = %p\n", *ppXyzzy);
*ppXyzzy = &someInt;
printf ("Pointer on exiting method2 = %p\n", *ppXyzzy);
}
int main (void) {
int *plugh = NULL;
printf ("Pointer in main on start = %p\n", plugh);
method1 (plugh);
printf ("Pointer in main after method1 = %p\n", plugh);
method2 (&plugh);
printf ("Pointer in main after method2 = %p\n", plugh);
return 0;
}
输出结果为:
Pointer in main on start = 0x0
Pointer on calling method1 = 0x0
Pointer on exiting method1 = 0x404018
Pointer in main after method1 = 0x0
Pointer on calling method2 = 0x0
Pointer on exiting method2 = 0x404018
Pointer in main after method2 = 0x404018
您可以看到,虽然方法1中更改了局部变量的值,但它并没有反映回调用者main
。方法2 将更改反映给调用者。
顺便说一句,你不应该在C中强制转换malloc
:
TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));
它可以隐藏某些微妙的错误,因为C显式地将void *
转换为其他指针类型,所以它完全没有必要。更好用:
TreeNode *node = malloc (sizeof (TreeNode));
您还应该检查 malloc
的返回值,以确保您没有NULL
返回,以免下列行:
node->data = data;
会让你无缘无故。
答案 1 :(得分:1)
如果原始树为空,则root = NULL。
当用户致电
时TreeNode* tree = NULL;
insertNode(&tree, compare, data);
他们希望树成为根节点。
如果传递树而不是&amp;树,则指针将按值传递,并且您无法使树变量指向新创建的节点。 (因为你不知道树的地址。在函数中,你得到的只是一个NULL,所以你不能改变它的值)
答案 2 :(得分:0)
完全没有。除非参数是指向指针的指针,否则行*root = ...
无法工作。
答案 3 :(得分:0)
if(*root == NULL) {
*root = node;
return;
}
说:如果root
指向NULL
,请为root
分配内容。如果您收到TreeNode *p
参数和p == NULL
,则无法为p分配任何内容,以使其对来电者有效。
该函数可以与指向null的变量一起使用,并且在返回后它将具有不指向TreeNode *
的有效NULL
。
请记住:C按副本接收所有值,如果要修改参数,则应接收指向该参数的指针。如果您想修改TreeNode *
,则应传递TreeNode **
答案 4 :(得分:0)
似乎行&#34; * root = node;&#34;的目的是* root作为树的根节点,但在遍历根节点的后期阶段被修改(* root =(* root) - &gt; left; * root =(* root) - &gt; right)这似乎不正确,我认为临时节点应该用于遍历。