0

I'm trying to create a method for inserting nodes into a BST with the following structs:

// node structure
struct Node {
    int val;
    struct Node* left;
    struct Node* right;
};

// binary tree structure
struct BinaryTree {
    struct Node* root;
};

Originally I created this method for adding nodes to the tree:

// add value to binary tree
void _AddNode(struct Node* node, int val) {
    if (node == NULL)
        *(&node) = CreateNode(val);
    else if (val <= node->val)
        _AddNode(node->left, val);
    else
        _AddNode(node->right, val);
}
void AddNode(struct BinaryTree* tree, int val) {
    _AddNode(tree->root, val);
}

Using this function to construct the tree, I get a Segmentation fault: 11 error when I try to traverse, print, access data from the tree.

However, when I modified the function to pass in a double pointer and effectively do the same thing it worked:

// add value to binary tree
void _AddNode(struct Node** node, int val) {
    if (*node == NULL)
        *node = CreateNode(val);
    else if (val <= (*node)->val)
        _AddNode(&(*node)->left, val);
    else
        _AddNode(&(*node)->right, val);
}
void AddNode(struct BinaryTree* tree, int val) {
    _AddNode(&tree->root, val);
}

Why does the latter work, but the former doesn't.

7
  • For all sorts of graphs, my common advice is to use pen and paper to solve the most common problems. Draw a tree on paper, using small squares for the nodes, and write the value inside the squares, and then use arrows for the pointers. "Rearrange" the tree by erasing arrows and redrawing them. Commented Aug 5, 2019 at 18:43
  • 1
    In the "Originally I created" code *(&node) isn't right. node (as a parameter) is declared local to the function and is equivalent to simply node. Commented Aug 5, 2019 at 18:43
  • They are not the same -- in the first case you can't change the pointer and in the 2nd you can. Commented Aug 5, 2019 at 18:44
  • Sorry, I was looking at the "Originally I created" and should have been more clear. Commented Aug 5, 2019 at 18:45
  • Unrelated to your problem, but in C all symbols beginning with an underscore and followed by an upper-case letter (like _AddNode) are reserved. See e.g. this reserved identifier reference for details. Commented Aug 5, 2019 at 18:45

1 Answer 1

1

However, when I modified the function to pass in a double pointer and effectively do the same thing it worked

Substantially the same thing, on fundamentally different data. The (&node) in your original attempt gives you a pointer to a local variable. When you dereference that and assign to the result, you are therefore modifying the local variable. Such a modification is not visible in any way to the caller.

On the other hand if you pass (say) a suitable double pointer to your function, say _AddNode(&(*node)->left, 42), then the value of the function parameter points to the same thing: the (*node)->left of the caller. If you dereference that pointer and assign to the result then naturally that is visible to the caller.

It seems that both the original and modified function are identical

Clearly, they are not lexically identical. You seem to mean that they appear to you to be equivalent, but since the difference in behavior disproves such an equivalence, it stands to reason that the manifest differences in the two functions in fact produce different semantics. The key thing that seems to have confused you is that in C, function arguments are always passed by value, so each function parameter starts with the value passed by the caller, but is not an alias for the caller's corresponding argument. Parameters of pointer type are no exception.

Sign up to request clarification or add additional context in comments.

2 Comments

that makes a lot of sense, arguments that are passed to the function are local, so if I want to edit the value of a pointer I'd need to pass in the reference to that pointer (just like you would for a variable). Thanks!
Yes, @JayMody, that's it exactly. And you seem now to have grasped a point that causes many people trouble: pointers are just another data type, and pointer values are just values of that type, thoroughly analogous in that sense to 42 as a value of type int.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.