这个指针指针是多余的吗?

时间:2014-07-28 04:11:31

标签: c pointers pointer-to-pointer

代码是这样的:

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)。如果不是为什么?

5 个答案:

答案 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)这似乎不正确,我认为临时节点应该用于遍历。