Using Pass by reference with linked lists - c

So I've use pass by reference on my linked list code but the problem is it's not printing soo how do I actually fix this?
my code:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int x;
struct node *next;
};
void add(struct node **root, int x)
{
struct node *conductor;
if(root==NULL)
{
(*root)=malloc(sizeof(struct node));
(*root)->x=x;
(*root)->next=NULL ;
}
else
{
conductor = *root;
while(conductor->next!=NULL)
{
conductor = conductor -> next;
}
conductor->next=malloc(sizeof(struct node));
conductor->next->x=x;
conductor->next->next=NULL;
}
}
void display(struct node *root)
{
struct node *conductor;
conductor=root;
while(conductor!=NULL)
{
printf("%d",conductor->x);
conductor = conductor ->next;
}
}
int main()
{
struct node *root;
root=NULL;
add(&root,5);
add(&root,4);
display(root);
free(root);
system("pause");
}
In better form
http://codepad.org/CPdUvK0x
Isn't it all nodes in my program are linked?

void add(struct node **root, int x)
{
struct node *conductor;
if(root==NULL)
That should be if (*root == NULL)
Since you're calling add(&root... root will never be NULL.

The check:
if(root==NULL)
should be
if(*root==NULL)
as root is being passed by address.
Also you do free(root) to free the entire list which is incorrect as it frees only the first node and makes the other nodes unreachable causing memory leak. To fix this you need to free the nodes one by one as:
struct node *tmp = root;
while(root) {
tmp = root->next;
free(root);
root = tmp;
}

the problem is in add():
if(root==NULL)
this test is wrong: root being passed by reference is never NULL (see in the main, it contains the address of the root node). you should correctly test if the rrot node is NULL:
if (*root == NULL)
i would also add that your way of freeing the memory allocated for the ist is wrong:
free(root)
will only free the root node, but will leak the child nodes...

Related

Are dynamically allocated nodes of lists accessible throughout program?

I have created a linked list in C. I dynamically allocate memory as
'''
struct node* createNode(value) {
struct node* newNode =
malloc(sizeof(struct node));
newNode->data = value;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
struct node* insertLeft(struct node* root, int value) {
root->left = createNode(value);
return root->left;
}
int main() {
struct node* root = createNode(1);
insertLeft(root,12);
//Create more nodes
postorder(root);
}
void postorder(struct node* root) {
if (root == NULL) return;
postorder(root->left);
postorder(root->right);
printf("%d ->", root->data);
}
'''
Now the root node I am getting after insertion is of the newly inserted element.Because I return this new node. How come while traversing the top-most root is passed to postorder.
Also if I don't return this new node it should still exist in the memory so why return?
Now the root node I am getting after insertion is of the newly inserted element.Because I return this new node.
That's not the case. When you call insertLeft(), you don't assign its return value to anything. So root still points to the node with data == 1.

Inserting element in binary tree

The code is for inserting an element in a binary tree using level order traversal. I'll first tell u how it works. It first goes through the nodes in each level and if there is any node which doesn't have both children it inserts the node as a child to that node and it use's queue for storing and retrieving the nodes addresses. My problem is that every time I call the create function the root value which is passed is always null even after inserting a node the root value is not changed and it's still a null. I am unable to figure out what's wrong in this. Can anyone help me out?
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left,*right;
}*root;
struct queue
{
int capacity,rear,front;
struct node **qu;
};
void enqueue(struct queue *q,struct node *n)
{
q->front=(++(q->front))%q->capacity;
(q->qu)[q->front]=n;
if(q->rear==-1)
q->rear++;
}
struct node* dequeue(struct queue *q)
{
struct node *temp;
temp=q->qu[q->rear];
if(q->front==q->rear)
q->front=q->rear=-1;
else
q->rear=(++(q->rear))%q->capacity;
}
int isempty(struct queue *q)
{
return(q->rear==-1);
}
struct queue* create(unsigned int capacity)
{
struct queue *p;
p=(struct queue*)malloc(sizeof(struct queue));
p->capacity=capacity;
p->front=p->rear=-1;
p->qu=(struct node**)malloc(sizeof(struct node)*capacity);
return p;
}
void insert(struct node *root)
{
int n;
struct node *p,*q;
struct queue *tmp;
p=(struct node*)malloc(sizeof(struct node));
p->left=p->right=NULL;
scanf("%d",&n);
p->data=n;
if(root==NULL)
{
root=p;
return;
}
tmp=create(20);
enqueue(tmp,root);
while(isempty(tmp))
{
q=dequeue(tmp);
printf("%d %d\n",p,root);
if((!q->right)||(!q->left))
{
if(!q->right)
q->right=p;
else
q->left=p;
return;
}
else
{
enqueue(tmp,q->left);
enqueue(tmp,q->right);
}
}
}
void traverse(struct node *root)
{
if(!root)
return;
traverse(root->left);
printf("%d ",root->data);
traverse(root->right);
}
void main()
{
int i,n;
while(1)
{
printf("1.insert\n2.exit\n");
scanf("%d",&n);
switch(n)
{
case 2:goto end;
case 1:insert(root);
}
}
end:
traverse(root);
}
Thanks.
You've defined root as a global variable, but your insert function also defines it's own local version of root which takes precedence. Because you're passing root in by value rather than reference, changing it's value has no effect. You have two options on how to fix this.
Pass root by reference
You change insert to be void insert(struct node **root) and then replace all instances of root in the function with (*root). You'll also need to pass a pointer to root when you call it - insert(&root)
Return the new value of root
Change the return type to struct node * and make sure you return root at the end and at any point where you're already returning from the function. When you call it you'll assign the return value to root like root=insert(root)
Both are equally valid options.

Having trouble removing all nodes from a linked-list

This code deletes all nodes except the last one. But I want it to delete all nodes. Can anyone tell me what am I doing wrong?
deleteall(struct node **start)
{
struct node*temp,*curr;
while ((*start)->next!=NULL)
{
temp=*start;
*start=(*start)->next;
free(temp);
curr=(*start);
}
if ((*start)->next==NULL)
{
free(curr);
}
}
I created a basic implementation of a linked list and tested your code. It's not particularly pretty, but it works:
#include <stdlib.h>
#include <stdio.h>
struct node { struct node *next; };
struct node* create_node(struct node *next) {
struct node* node = malloc(sizeof(struct node));
node->next = next;
printf("created %p\n", node);
return node;
}
void deleteall(struct node **start)
{
struct node*temp,*curr;
while ((*start)->next!=NULL)
{
temp=*start;
*start=(*start)->next;
free(temp);
printf("free'd %p\n", temp);
curr=(*start);
}
if ((*start)->next==NULL)
{
free(curr);
printf("free'd %p\n", curr);
}
}
int main(int argc, char** argv) {
// create root node
struct node * ll = create_node(0);
// insert three nodes
ll->next = create_node(ll->next);
ll->next = create_node(ll->next);
ll->next = create_node(ll->next);
// delete all nodes (including root)
deleteall(&ll);
return 0;
}
The output is:
$ gcc test.c && ./a.out
created 0xc3c010
created 0xc3c030
created 0xc3c050
created 0xc3c070
free'd 0xc3c010
free'd 0xc3c070
free'd 0xc3c050
free'd 0xc3c030
As you can see, all nodes that are allocated are actually free'd.
Maybe you are confused by the fact, that the root node is not set to 0, but apparantly still contains the remains of the object previously located at that place. You could fix that if you assign 0 to the start pointer after you freed the nodes: *start = 0; (or by eliminating the additional curr pointer, as suggested in the other answer).
Consider that you could alternatively delete the nodes of your list recursively:
void delete_node_recursively(struct node *node) {
if (node) {
delete_node_recursively(node->next);
free(node)
}
}
If you want to have the root node set to 0 in the end, you can add a wrapper:
void delete_list(struct node **root) {
delete_node_recursively(*root);
*root = 0;
}
try this:
This was to simplify your code.
And Finally *start become NULL. (your code not become NULL)
deleteall(struct node **start){
struct node *temp;
while(*start){
temp = *start;
*start=(*start)->next;
free(temp);
}
}

C Segmentation fault when implementing insertiong of a node in a binary tree

I try to implement a binary tree in C with only one operation for the moment - insertion of a node to the tree. The problem I am facing is that I have a segmentation fault. The problem comes from the function insert, in the root = leaf instruction but I can't figure out how can I fix it. I've tried to write the function in a slightly different way. Instead of passing a leaf, I tried to pass a value to the insert function and to create a node of the binary tree inside the insert function. It didn't work out.
Can you please me tell me where I am wrong in my code? Thank you
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct binaryTree
{
int data;
struct binaryTree *left;
struct binaryTree *right;
};
//the seg fault comes from the function insert
void insert(struct binaryTree *leaf,struct binaryTree *root)
{
if(root == NULL)
{
//this is the problematic instruction
root = leaf;//construct the tree if it has not been constructed before
root->left = NULL;
root->right = NULL;
}
else if(leaf->data > root->data)
{
insert(leaf, root->right);
}
else if(leaf->data < root->data)
insert(leaf,root->left);
else
{
printf("The element is in the tree already.\n");
}
}
void print(struct binaryTree *root)
{
printf("-------Print--------\n");
if(root == NULL) return;
print(root->left);
printf("%d\n", root->data);
print(root->right);
}
void createNode(int value,struct binaryTree *node)
{
printf("-------CreateNode--------\n");
node = malloc(sizeof(struct binaryTree));
node->data = value;
node->left = NULL;
node->right = NULL;
}
void destroy(struct binaryTree *root)
{
if(root != NULL)
{
destroy(root->right);
destroy(root->left);
free(root);
}
}
int main()
{
struct binaryTree *root = NULL,*a,*b,*c;
createNode(42,a);
createNode(13,b);
createNode(20,c);
insert(a,root);
insert(b,root);
insert(c,root);
print(root);
destroy(root);
return 0;
}
The problem:
At the beginning of main(), root is NULL and a is untitialised.
The problem is that createNode(42,a); will create and allocate a node, but it's address will be lost. Only the local parameter node will be set by this function and lost forever as soon as it returns. This value will not be copied to a, which hence remain unitialized.
Then you try to instert(a, root): a is still an unitialised pointer and root is still NULL. The first thing that will hapen in insert() is that you'll copy the unitialised pointer into root, and then you dereference this invalid pointer by trying to set some structure members to NULL. That causes the segmentation fault !
How to solve it:
Make sure that createNode() returns the value:
struct binaryTree *createNode(int value)
{
printf("-------CreateNode--------\n");
struct binaryTree *node = malloc(sizeof(struct binaryTree));
node->data = value;
node->left = NULL;
node->right = NULL;
return node;
}
and change min accordingly:
a = createNode (42);
...
You then have a similar problem in insert(), with the root argument. You could here do a similar technique, by rewriting your function:
struct binaryTree *insert(struct binaryTree *leaf,struct binaryTree *root) {...}
But it requries a little bit more gynmnastics as with createNode().
I propose you therefore another alternative, passing as argument a pointer to a root pointer: this pemits you to change the value of the root poniter
void insert(struct binaryTree *leaf,struct binaryTree **root) // pointer to pointer
{
if(*root == NULL)
{
//this is the problematic instruction
*root = leaf;//construct the tree if it has not been constructed before
(*root)->left = NULL;
(*root)->right = NULL;
}
else if(leaf->data > (*root)->data)
{
insert(leaf, &root->right);
}
else if(leaf->data < (*root)->data)
insert(leaf,&root->left);
else
{
printf("The element is in the tree already.\n");
}
}
In main you'd then call it:
insert(a,&root);

Connect preorder predecessor with its successor in a binary search tree

Actually in an interview i was asked to write a code through which every node in a binary search tree is having a extra pointer namely "next" we have to connect this pointer of every node to its pre order successor ,can any one suggest me the code as i was not able to do so. the tree nodes has above structure :-
struct node {
int data ;
struct node *left,*right;
struct node *next; //this pointer should point to pre order successor
};
thank you .
Cracked the the solution thanks to you guys ,below is the whole code written in c :-
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left,*right,*next;
};
struct node* getNode(int data)
{
struct node* temp=(struct node*)malloc(sizeof(struct node));
temp->left=temp->right=NULL;
temp->data=data;
return temp;
}
void insert(struct node**root,int data)
{
if(!*root)
{
*root=(struct node*)malloc(sizeof(struct node));
(*root)->left=(*root)->right=NULL;
(*root)->data=data;
}
else if(data<(*root)->data)
insert(&((*root)->left),data);
else if(data>(*root)->data)
insert(&((*root)->right),data);
}
struct node* preorderSuccessor(struct node* root,struct node* p)
{
int top,i;
struct node *arr[20];
if(!root || !p)
return NULL;
if(p->left)
return p->left;
if(p->right)
return p->right;
top=-1;
while(root->data!=p->data)
{
arr[++top]=root;
if(p->data<root->data)
root=root->left;
else
root=root->right;
}
for(i=top;i>=0;i--)
{
if(arr[i]->right)
{
if(p!=arr[i]->right)
return arr[i]->right;
}
p=arr[i];
}
return NULL;
}
void connect(struct node* parent,struct node *r)
{
if(r)
{ connect(parent ,r->left);
r->next = preorderSuccessor(parent,r);
connect(parent,r->right);
}
}
int main()
{
struct node* root=NULL,*temp=NULL;
int arr[]={10,11,2,3,9,8,4,5},size,i;
size=sizeof(arr)/sizeof(arr[0]);
for(i=0;i<size;i++)
insert(&root,arr[i]);
connect(root,root);
struct node *ptr = root;
while(ptr){
// -1 is printed if there is no successor
printf("Next of %d is %d \n", ptr->data, ptr->next? ptr->next->data: -1);
ptr = ptr->next;
}
return 0;
}
As Eugene said: So traverse the tree with preorder traversal and connect. To do that, you need to know which node, if any, you visited last.
You can do that with the usual recursive approach by passing a reference to the previous node. This must be the address of a variable that is valid throughout the recursion, because the previous node is not necessarily closer to the root. You could use a global variable, but a variable created in a wrapper function may be better:
void connect_r(struct node *node, struct node **whence)
{
if (node) {
if (*whence) (*whence)->next = node;
*whence = node;
connect_r(node->left, whence);
connect_r(node->right, whence);
}
}
void connect(struct node *head)
{
struct node *p = NULL;
connect_r(head, &p);
if (p) p->next = NULL;
}
The pointer p in connect, whose address is passed to the recursive function connect_r holds the node whose next pointer should be updated next. The update doesn't happen on the first visited node. and the next member of the last visited node must explicitly be set to NULL after the recursion.
Alternatively, you can connect the nodes iteratively by using a stack:
void connect(struct node *head)
{
struct node *p = NULL;
struct node **prev = &p;
struct node *stack[32]; // To do: Prevent overflow
size_t nstack = 0;
if (head) stack[nstack++] = head;
while (nstack) {
struct node *node = stack[--nstack];
*prev = node;
prev = &node->next;
if (node->right) stack[nstack++] = node->right;
if (node->left) stack[nstack++] = node->left;
}
*prev = NULL;
}
The connected next pointers are a snapshot of the current tree. Insertions, deletions and rearrangements of nodes will render the next chain invalid. (But it can be made valid again by calling connect provided that the tree's left and right links are consistent.)

Resources