0

Code is like this:

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;
            }
        }
    }
}

Pointer is never used like root and is always used as (*root). Isn't it being TreeNode **root redundant? Can it be reduced in the argument to TreeNode *root and parts in the function body changed to just root from (*root). If not why?

Dulguun Otgon
  • 1,925
  • 1
  • 19
  • 38

5 Answers5

1

No, it's not redundant. C is a strict pass-by-value language and, if you want to change a parameter passed in (and you do, trust me), C emulates pass-by-reference with pointers.

In your case, you want to change a variable of type TreeNode *, so you need to pass a pointer to that variable, which is why you have double indirection.

Don't be fooled by the fact you seem to already have a pointer, in your case, it's conceptually the same as:

void changeInt (int *pXyzzy) { *pXyzzy = 42; }

except that's for changing an int. If you wanted to change an int *, you would need:

int some_int = 42;
void changeIntPtr (int **ppXyzzy) { *ppXyzzy = &some_int; }

noting the added level of indirection. This is more akin to what you need since you're changing a pointer to something (so you need a double-pointer to it).

Without passing in &some_treenode_pointer_variable and setting it via *some_treenode_pointer_variable = something, the changed value never finds its way back to the caller (the variable, being pass-by-value, is a local copy only).

It may help to examine the following code and its output. Method 1 tries to change the pointer by simply setting it, method 2 uses a pointer-to-pointer method to try and change it:

#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;
}

The output is:

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

You can see that, although the value of the local variable is changed in method 1, that doesn't get reflected back to the caller main. Method 2 does reflect the change back to the caller.


As an aside, you shouldn't cast the return value of malloc in C:

TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));

It can hide certain subtle errors and it's totally unnecessary since C explicitly casts void * to other pointer types. Better to use:

TreeNode *node = malloc (sizeof (TreeNode));

You should also check the return value of malloc to ensure you haven't gotten NULL back, lest the following line:

node->data = data;

will cause you no end of grief.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

If the original tree is empty, the root = NULL.

When the user call

TreeNode* tree = NULL;
insertNode(&tree, compare, data);

They expect tree to become the root node.

If you pass tree instead of &tree, the pointer is pass by value, and you have no way to make the tree variable to point to the newly created node. (Because you cannot know the address of tree. In the function, all you get is a NULL, so you cannot change its value)

Hsi-Hung Shih
  • 233
  • 1
  • 7
0

Not at all. The line *root = ... couldn't work unless the parameter was a pointer to the pointer.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0
if(*root == NULL) {
        *root = node;
        return;
}

Is saying: If root points to NULL, assign something to root. If you are receiving a TreeNode *p by parameter, and p == NULL, you can't assign anything to p for it to have effect on the caller.

That function can be used with a pointer-to-null variable, and after returning it will have a valid TreeNode * that does not point to NULL.

Remember: C receives all the values by-copy, if you want to modify a parameter, you should receive a pointer to that parameter. If you want to modify a TreeNode *, you should pass a TreeNode **

Marco
  • 2,796
  • 19
  • 24
0

it seems that purpose of line "*root = node;" is to make *root as root node of tree but at later stage during traversal root node is modified (*root = (*root)->left; *root = (*root)-> right) which seems incorrect, i think temporary node should be used for traversal.

inderjeet
  • 69
  • 2