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.
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.
Related
As most beginners in C, I'm implementing a simple linked list.
Each node for the list is defined as so:
typedef struct list_node {
void * data;
struct list_node * next;
} list_node_t;
I made a test program to create and iterate a list. Creation and insertion operations work correctly. However, the code below is giving me problems:
list_node_t * node = NULL;
list_iter_reset(list, node);
if (node == NULL) {
printf("Node is NULL.\n");
} else {
printf("Node is not NULL.\n");
}
fflush(stdout);
The function list_iter_reset() is defined below. Please note that list->head does not point to NULL, as I have inserted nodes in the list previously.
void list_iter_reset(list_t list, list_node_t * node)
{
node = list->head;
if (node == NULL) {
printf("Node is NULL.\n");
} else {
printf("Node is not NULL.\n");
}
fflush(stdout);
}
The output from executing that code is as follows:
Node is not NULL.
Node is NULL.
Since I'm passing a pointer to the node to the function, why is the created node in the test program still pointing to NULL after that function call?
I'm guessing a simple pointer arithmetic aspect went over my head here. I've been looking around and could not find a similar issue.
Thank you in advance.
The function is modifying the value of the pointer, but that never gets back to the caller. It seems you want to be passing a pointer to pointer (list_node_t**) to the function, not a regular pointer.
void list_iter_reset(list_t list, list_node_t** node)
{
*node = list->head;
...
}
The reasoning for this is that while a pointer is all you need to change the value of the thing it's pointing to, here you are trying to change the value of the pointer itself, i.e. where this pointer is pointing to.
As a comparison, imagine you would be passing an int to the function and expecting the function to modify that int. You would of course have to pass an int*, right? This is the same thing, except replace int with node*, and so you need to pass a pointer to that type, which in this case is node**
Assuming the relevant header files, functions for Singly Linked List in C are declared.
Is the following definition of Delete() correct?
/* The Structure for SLL
typedef struct SLL
{
int data;
struct SLL *next;
}node;
Function Delete() deletes a node*/
void Delete( node **head)
{
node *temp, *prev;
int key;
temp = *head;
if(temp == NULL)
{
printf("\nThe list is empty");
return;
}
clrscr();
printf("\nEnter the element you want to delete:");
scanf("%d", &key);
temp = search( *head , key);//search()returns the node which has key
if(temp != NULL)
{
prev = get_prev(*head, key);
if(prev != NULL)
{
prev->next = temp->next;
free(temp);
}
else
{
*head = temp->next;
free(temp);
}
printf("\nThe node is deleted");
getch();
}
}
1) What happens if I replace(node ** head) with (node *head)?
2) What happens if I replace void Delete (node **head) with node
*Delete(node *head)?
3) Is there an alternate way to delete a node in C?
Thanks in advance
This isn't a tutorial site, but here goes...
You do know that arguments in C are passed by value? Meaning the value is copied.
For example:
void some_function(int a)
{
// ...
}
When calling the function above, like
int x = 5;
some_function(x);
Then the value in x is copied into the argument a in the function. If the code inside the function assigns to a (e.g. a = 12;) then you only modify the local variable a, the copy. It does not modify the original variable.
Now, if we want the function to modify x, then we must emulate pass by reference, which is done using pointers and the address-of operator:
void some_function(int *a)
{
*a = 12; // Modify where a is pointing
}
Now to call that, we don't create a pointer variable and pass that (though it's possible as well), instead we use the address-of operator & to pass a pointer to the variable:
int x = 5;
some_function(&x); // Pass a pointer to the variable x
The pointer &x will be passed by value (since that's the only way to pass arguments in C), but we don't want to modify the pointer, we want to modify the data where it points.
Now back to your specific function: Your function wants to modify a variable which is a pointer, then how do we emulate pass by reference? By passing a pointer to the pointer.
So if you have
node *head;
// Initialize head, make it point somewhere, etc.
Now since the Delete function needs to modify where head points, we pass a pointer tohead`, a pointer to the pointer:
Delete(&head);
The Delete function of course must accept that type, a pointer to a pointer to node, i.e. node **. It then uses the dereference operator * to get where the pointer is pointing:
*head = temp->next;
1) If you replace node** head with node* head you won't modify the original head pointer. You probably have a head somewhere that marks the beginning of the linked list. When you delete a node, there's a chance that you want to delete head. In that case you need to modify head to point to the next node in the linked list.
*head = temp->next;
free(temp);
This part of your code does exactly that. Here, temp == head. We want head to point to head->next, but if we pass in node* head to the function, the pointer will get modified but the changes will disappear because you're passing the pointer by value. You need to pass in &head which will be of type node ** head if you want the changes to be reflected outside of the function.
2) You will then change the function definition to return a void pointer (which is a placeholder pointer that can be converted to any pointer. Take care to not break any aliasing rules with this. But the problem from (1) remains, although, you could return a modified head, and assign it to the returned value. In that case define the function won't fit well with other cases where the head doesn't need to be modified. So you could return a pointer for head if it's modified or return NULL when it doesnt. It's a slightly messier method of doing things imho, though.
3) Yes, but that depends on the way a linked list is implemented. For the datatype shown here, the basic delete operation is as given.
I saw this working code to converting a tree to its mirror.
struct node* mir(struct node *root)
{
if(root)
{
struct node * temp;
mir(root->left);
mir(root->right);
temp=root->left;
root->left=root->right;
root->right=temp;
}
Should not be there mir(struct node **) like we have in linked list?
All calls in C are call by value, which means the called functions cannot change the value of the argument in the caller's context. The called function receives just a copy of the arguments. However, you can effectively bypass this by passing a pointer to your variable, and then modifying its dereferenced state. What if the variable you want to change is a pointer? You pass a pointer to a pointer.
struct node* mir(struct node *root);
struct node* mir2(struct node **root);
...
/* following cannot change value of root */
x = mir(root);
/* following may change value of root */
x = mir2(&root);
I have posted the link to my BST code on ideone: http://ideone.com/P7850n
In the main function I am getting an error when I read values in the while loop and insert into BST, but it works fine if I use a for loop. What could be the possible explanation for this error which occurs only with the while loop ?
#include <stdio.h>
#include <stdlib.h>
//data struct for BST node
typedef struct BST
{
int data;
struct BST *left;
struct BST *right;
}node;
//make node from given data
node* makeNode(int data)
{
node *n=(node*)malloc(sizeof(node));
n->data=data;
n->left=NULL;
n->right=NULL;
return n;
}
//insert node in BST
node* insert(node* root,int key)
{
if(root==NULL)
return makeNode(key);
if(key < root->data)
root->left=insert(root->left,key);
else
root->right=insert(root->right,key);
return root;
}
//inorder printing prints in sorted order
void inorder(node* root)
{
if(root==NULL)
return;
inorder(root->left);
printf("%d ",root->data);
inorder(root->right);
}
//driver function
int main(void) {
// your code goes here
node *root;
int s,i,key;
scanf("%d",&s);
while(s--)
//for(i=0;i<s;i++)
{
scanf("%d",&key);
root=insert(root,key);
}
inorder(root);
return 0;
}
Most probably this is an uninitialized variable root.
The compiler re-uses the same memory for variables, either declared in your program or used internally, after they are not anymore needed, so that other variables later occupy the same memory. In C (unlike, say, Perl), when memory is assigned to a variable, it is not automatically cleared: you should do it yourself, which is called initialization: typically as soon as you declare a variable, you should assign it some value: int year = 2014;. If you use a variable before you assign it a value, it's value will be whatever happens to be in memory that it occupies, left from other variables or even other running programs.
In your case, when you initialize the for loop with i=0, this 0 probably uses the memory later used for root, so accidentally it works. When you initialize the while loop with non-zero s, root uses memory that happens to be non-zero.
The solution is to initialize root = NULL;, and in general it's a good habit to always initialize all variables.
Without node *root = NULL; you are trying to access undefined memory address as root will contain any random data. So you can get valid behavior or any other behavior including crash.
As root is not initialized in inser() function if(root==NULL) may or may not be true and hence you will get different behavior.
This has nothing to do with for or while loop.
its always to initialize any memory variable to NULL or any other variable to 0,while writing any piece of code,otherwise you will always get any unpredictable crash or result.
like in this case,do like this below:
node *root;
int s,i,key;
to
node *root = NULL;
int s =0;
int i = 0;
int key= 0;
So i need to define a destructive function BST insertbst(int i, BST t) that inserts i into BST t. That is, it modifies t to include i and returns the resulting tree. The running time must be O(height t).
I have come up with this version ... but gives me the following error's ideone.com/xhxb6
BST insertbst(int i, BST t) {
if (t == NULL) {
return BSTmake(i, NULL, NULL);
} else if (i < BSTkey(t)) {
return BSTmake(BSTkey(t), insertbst(i ,BSTleft(t)), BSTright(t));
} else {
return BSTmake(BSTkey(t), BSTleft(t), insertbst(i ,BSTright(t)));
}
}
The other functions used in my code can be found in: http://pastebin.com/TVYRE4Nd
Any suggestions to make it destructive, or to change it to avoid my heap error?
.h file: http://ideone.com/QeSTl
Test file: http://pastebin.com/9ca5i4My
You cannot use BSTmake() like you are doing now as you are creating a new BST node everytime it is called, where as you can definitely be sure that the new node should only be created only once for each insert.
Now for the following two statements in main
BST x = BSTmake(2, (BSTmake( 1, NULL, NULL)), (BSTmake(3, NULL,NULL)));
BST y = insertbst(4, x);
I don't know your assumption about where y should be pointing to. In general, implementations of a BST would just call insert on their own, passing in the node to be inserted and the root node. You will see that using this approach makes code much simpler to comprehend. You'll have to change your second line as insertbst( 4, &x) to use this pattern.
You would then have to change the implementation of your insertbst as below:
Pass the second argument as a pointer to the node pointer which represents the parent of the newnode.
if BST *t is null, create a new node and assign the pointer to the node to point to it.
if i < BSTkey(t) or i > BSTKey(t), you need to call insertbst() recursively by passing the pointer to either the left subtree or the right subtree as the second argument.
This is what it may look like:
BST insertbst(int i, BST *t) {
if (*t == NULL) {
*t = BSTMake( i, NULL, NULL);
}
else if (BSTkey(newnode) < BSTkey(*t)) {
insertbst( i, &t->left);
}
else {
insertbst( i, &t->right);
}
}
Also malloc() returns a void * which point to the allocated memory chunk. I am assuming BST is has been typedefed something like typedef struct bst_node * BST. Hence you should change the newnode declaration as BST newnode = (BST)malloc(sizeof(struct bst_node));.