Why can't I delete the first node (head node) directly? - c

I have created a simple linked list using c where we can insert and delete elements at any place in the list. The code worked properly until i tried to delete the first node using the following code.
typedef struct l_list
{
int data,index;
struct l_list *next_node;
}node;
static int total_node=0;
node *search(node *,int,node **);
int main()
{
int choice,key;
char ans;
node *new_node,*head, *p_node,*index_change,*cur;
node *get_node();
head=NULL;
printf("Program for Linked List.\n");
do
{
printf("\n1. Create Node");
printf("\n2. Delete Node");
printf("\n3. Traverse the List");
printf("\n4. Exit");
printf("\nEnter your choice: ");
scanf("%d",&choice);
switch(choice)
{
case 1:
do
{
total_node++;
new_node=get_node();
printf("\nEnter the data you want to insert: ");
scanf("%d",&new_node->data);
if(head==NULL)
{
head=new_node;
head->index=1;
}
else
{
printf("\nWhich node you want to insert it as:\n");
for(int i=1;i<=total_node;i++)
{
printf("%d ",i);
}
printf("==) ");
scanf("%d",&key);
//printf("\b\b-|-");
if(key==1)
{
new_node->next_node=head;
head=new_node;
}
else
{
p_node=search(head,key,&cur);
new_node->next_node=p_node->next_node;
p_node->next_node=new_node;
//p_node=NULL;
}
new_node->index=key;
index_change=new_node->next_node;
while(index_change!=NULL)
{
index_change->index=++key;
index_change=index_change->next_node;
}
}
printf("\nDo you want to insert more node in the linked list: [y/n]");
//ans=getch();
}while((ans=getch())=='y');
break;
//Deletion code.
case 2:
do
{
if(head==NULL)//head is first node of the list
{
printf("\nUNDERFLOW!\nThe linked list is already empty.\n");
}
else
{
printf("Which node you want to delete:\n");
for(inti=1;i<=total_node;i++)
printf("%d ",i); //total_node=variable taken
printf("==) "); //to track the total no of node
scanf("%d",&key); //key=node index to be deleted
//printf("\b\b-|-");
if(key==1)
{
//If we need to delete the first node when only one node is left
if(total_node==1)
{
//p_node=head;
head=NULL;
}
//If we need to delete the first node when more than one node are there
else
{
//p_node=head;
head=head->next_node;
}
total_node--;
}
else
{
p_node=search(head,key,&cur);//returns node just before the node to be deleted
p_node->next_node=cur->next_node;//cur gets the value of the node that is to be deleted.
total_node--;
}
index_change=p_node->next_node;
while(index_change!=NULL)//to change the index of following nodes.
{
index_change->index=key++;
index_change=index_change->next_node;
}
}
printf("\nDo you want to delete more nodes: [y/n]\n");
}while((ans=getch())=='y');
case 3:
if(head==NULL)
printf("\nThe linked list is empty.\n");
else
{
printf("\nThe elements of linked lists are as follows:\n\n");
p_node=head;
while(p_node!=NULL)
{
printf("[%d]->%d ",p_node->index,p_node->data);
p_node=p_node->next_node;
}
}
break;
}
}while(choice!=4);
return 0;
}
node *get_node()
{
node *temp1;
temp1= new node;
temp1->next_node=NULL;
return temp1;
}
node *search(node *head,int key,node **cur)
{
node *current,*prev;
current=head;
while(current!=NULL)
{
if(current->index==key)
{
return prev;
}
prev=current;
current=current->next_node;
*cur=current;
}
return prev;
}
using this code if i try to delete the first node the program gets crashed. And when i use a temporary variable such as
if(key==1)
{
if(total_node==1)
{
p_node=head;
head=NULL;
}
else
{
p_node=head;
head=p_node->next_node;
}
total_node--;
}
the program works properly. So what i want to ask is can we delete the head node directly or we always require another temporary structure pointer to delete the head node.

In this line :
index_change=p_node->next_node;
you dereference p_node. But in the cases where you delete the first node, you don't set a value for p_node. The crash you observe is likely because p_node does not hold a valid memory address.

It is difficult to say what is happening without the exact error you are getting, and the complete program.
One thing that immediately looks wrong is that you assign nodes (your struct Linked_List), which includes the data. This is not what you want with a linked list. In a linked list, you just want to modify pointers, and prevent copying the data.
Also, you program is very badly structured. Consider moving the specific operations into separate functions, and write tests for each of these. This will also allow you to post a concise, complete code sample with your question.
In order to close in on the error, you can either use a debugger, or you can add print statements to your code that tell you what is happening.

In this line:
p_node=search(head,key,&cur);//returns node just before the node to be deleted
you pass head pointer which is already set to NULL if you try to delete 1st node.
So you can not dereference the head pointer inside the search function which your code must be doing (as I believe) since you do not have any other way to get to the start of linked list.

Related

Linked List Operations In C (Segmentation Error Core Dumped!)

I have been trying to implement Linked List operations in c from the past few days, but I keep stumbling upon the same error again and again which says "Segmentation Error Core Dumped". I'm not able to figure out what part of the logic is going wrong. It is strange as after resolving all the warnings and Errors the code just doesn't execute. It would also be great if someone points out to me if I am using a linked list and pointers correctly. My code seems to be huge to post but I just couldn't shorten it out. And again, I would be grateful to all those who can help me out and make this code more readable and reduce the ambiguities.
#include<stdio.h>
#include<stdlib.h>
struct nodes
{
int data;
struct nodes* next;
};
typedef struct nodes* node;
node head=NULL;
void InsertFront()
{
node temp=NULL;
printf("Enter The Value Of Node\n");
scanf("%d",&temp->data);
if(head==NULL)
{
head->data=temp->data;
}
else
{
temp->next=head;
head=temp;
}
}
void InsertBack()
{
node temp,newnode;
printf("Enter The Value Of Node\n");`enter code here`
scanf("%d",&newnode->data);
if(head==NULL)
{
head->data=newnode->data;
}
else
{
temp=head;
while(temp->next!=NULL)
{
temp=temp->next;
}
newnode=temp->next;
}
}
void InsertPosition()
{
node previousnode,newnode,nextnode,temp;
int position,count=0;
printf("Enter the Position At Which New Node Has To Be Inserted");
scanf("%d",&position);
printf("Enter The Value Of Node\n");
scanf("%d",&newnode->data);
if(head==NULL)
{
head->data=newnode->data;
}
else
{
temp=head;
while(temp->next!=NULL && count<position);
{
previousnode=temp;
temp=temp->next;
count=count+1;
nextnode=temp;
}
previousnode->next=newnode;
newnode->next=nextnode;
}
}
void DeleteFront()
{
node temp;
if(head->next==NULL)
{
head==NULL;
}
else
{
head->next=temp;
head=NULL;
head=temp;
}
}
void DeleteBack()
{
node temp;
if(head->next==NULL)
{
head==NULL;
}
else
{
temp=head;
while(temp->next!=NULL)
{
temp=temp->next;
}
temp=NULL;
}
}
void DeletePosition()
{
node temp,nextnode,deletenode;
int position,count=0;
printf("Enter The Position At Which The Node Has To Be Deleted");
scanf("%d",&position);
if(head->next==NULL)
{
head==NULL;
}
else
{
temp=head;
while(temp->next!=NULL && count!=position)
{
temp=temp->next;
count=count+1;
}
deletenode=temp->next;
nextnode=deletenode->next;
deletenode->next=NULL;
temp->next=nextnode;
}
}
void Display()
{
node temp;
temp=head;
if(head==NULL)
{
printf("Linked List Seems To Be Empty");
}
while(temp->next!=NULL)
{
printf("%d -> ",temp->data);
}
}
int main()
{
int choice;
printf("\nLINKED LIST OPERATIONS\n\n");
printf("Select An Option\n1 - Insert From Front\t 2 - Insert From Back\n3 - Insert At
A Position 4 - Delete At The Front\n5 - Delete At The Back\t 6 - Delete At A
Position\n7 - Display\t 8 - Exit\n\n");
scanf("%d",&choice);
switch(choice)
{
case(1) :
{
InsertFront();
}
case(2) :
{
InsertBack();
}
case(3) :
{
InsertPosition();
}
case(4) :
{
DeleteFront();
}
case(5) :
{
DeleteBack();
}
case(6) :
{
DeletePosition();
}
case(7) :
{
Display();
}
case(8) :
{
exit(0);
}
default :
{
printf("Invalid Input\n");
exit(0);
}
}
}
Off the cuff, your first function you may want to pass the head pointer as an argument to the function or have the return value be a node* so it is more versatile. Neither the head nor the temp were initialized which happens three ways: You assign an existing variable address to the pointer, you make a malloc call to assign storage, and the third way I cant remember, check out the resources below. They will help! You have allocated a pointer variable by declaring a local and global node*, they are compatible however you have not initialized either of them with a reference to another variable; you have simply declared them. A pointer must be initialized with a reference assignment to another address either from malloc, &addressof, etc. Null simply marks them as bad pointers without throwing a segfault when tested. Think of it like a file name without any storage allocated...You can't save to it but its there. Since neither are initialized, when you try to assign to them, you get a memory error because no storage has been set aside yet. Which means...segfault! There are three components to a pointer superficially: [Pointer address for the alias/named region of storage/object|memory block reserved to hold whatever size you declare you need, in this case, you set that aside as such: head = malloc(sizeof(struct node *)), this allocates most likely an 8 byte address space which points a suitable region of storage->|*dereferenced value of the address the storage is reffering to]
Try running gdb and setting a break on each of the two pointers in your first function. I hope that helps and hope I haven't given you bad advice...
I struggled with these too quite a bit, here are some good resources that will be worth your time:
Stanfor CS Library
-CONCISELY covers pointers, linked lists, binary trees, debugging to find out exactly what line of code is generating your error;
http://cslibrary.stanford.edu/

Why passing an argument of structure pointer in a function which creates link list node isn't working?

I'm trying to make link list which represents polynomial.
Each node consists of coefficient,power of x,link to the next node
I have tried this program without passing arguments it worked .
but when when tried passing arguments the link list isn't being created.
pls help to rectify my program..
*****THIS IS MY PROGRAM WITH STRUCTURE POINTERS AS AN
ARGUMENT IN THE INSERT FUNCTION*****
#include<stdio.h>
#include<stdlib.h>
struct node
{
float coff;
int expo;
struct node *next;
};
struct node *start1=NULL,*current1=NULL;
void insert(struct node *start,struct node *current)
{
struct node *new_node;
new_node=(struct node*)malloc(sizeof(struct node));
if(start==NULL)
{
start=new_node;
current=new_node;
}
else
{
current->next=new_node;
current=new_node;
}
printf("\nEnter coefficient:");
scanf("%f",&new_node->coff);
printf("\nEnter power of x:");
scanf("%d",&new_node->expo);
new_node->next=NULL;
}
void show(struct node *start)
{
struct node *ptr;
ptr=start;
while(ptr!=NULL)
{
printf(" %.2fx^%d",ptr->coff,ptr->expo);
ptr=ptr->next;
}
}
void find(float scoff,int sexpo,struct node *start)
{
//scoff=search coefficient, sexpo=search exponent
int flag=0;
struct node *ptr;
ptr=start;
while(ptr!=NULL)
{
if(ptr->coff==scoff && ptr->expo==sexpo)
{
printf("your term found-> %.1fx^%d",ptr->coff,ptr->expo);
flag=1;
break;
}
else
ptr=ptr->next;
}
if(flag==0)
printf("\nSorry term couldn't be found!!");
else
printf("\nSearch success!!");
}
int main()
{
int c=1,ex=0;
float cf=0;
while(1)
{
insert(start1,current1);
printf("\nWant to continue(1/0)?");
scanf("%d",&c);
if(c==0)
break;
}
show(start1);
while(1)
{
printf("\nEnter coff and expo respectively:");
scanf("%f%d",&cf,&ex);
find(cf,ex,start1);
printf("\nWant to continue(1/0)?");
scanf("%d",&c);
if(c==0)
break;
}
return 0;
}
The problem is that you're modifying a local copy of the start and current pointers (i.e. the copies passed as the function arguments), thus not actually changing the linked list. You should instead modify the start1 and current1 pointers. There's no need for the insertion function to take start and current parameters as it can simply modify the global variables. (I should note that this is a bad design choice.)
More specifically, the problem is when initializing the list in
if (start==NULL)
{
start=new_node;
current=new_node;
}
you only modify the local copy that gets destroyed when it goes out of scope. So start1 and current1 are still NULL after the function returns.
Change the insert function to
void insert(struct node *start,struct node *current)
{
struct node *new_node;
new_node=(struct node*)malloc(sizeof(struct node));
if(start1==NULL)
{
start1=new_node; // You previously had start instead of start1
current1=new_node; // You previously had current instead of current1
}
else
{
current1->next=new_node;
current1=new_node;
}
printf("\nEnter coefficient:");
scanf("%f",&new_node->coff);
printf("\nEnter power of x:");
scanf("%d",&new_node->expo);
new_node->next=NULL;
}
Beware: after this modification, you can call insert() (i.e. no need for insert to have parameters) as the function will operate on the global variables. The other option---better, but more time-consuming---is to somehow initialize the linked list and then use the functions in their current form (except for minor modifications).

Creating two link list using one function

This is a program to print two link lists using one function.
I have used two functions i.e create and display.Create() is to create the linklist and display() to display the result of linklist.
But this code is printing NULL. I'm not not getting where is the error???
`#include<stdio.h>
#include<conio.h>
struct node
{
int data;
struct node* next;
}
*start=NULL,*start1=NULL;
//to create the linklist
struct node* create(struct node* ptr)
{ int ch;
do
{
struct node* new_node=(struct node*)malloc(sizeof(struct node));
struct node* current;
printf("enter the data\n");
scanf("%d",&new_node->data);
new_node->next=NULL;
if(ptr==NULL)
{
ptr=new_node;
current=new_node;
}
else
{
current->next=new_node;
current=new_node;
}
printf("Do u want to add more ");
scanf("%d",&ch);
}while(ch!=0);
return ptr;
}
//to display the linklist
void display(struct node* temp)
{
while(temp!=NULL)
{
printf("%d--->",temp->data);
temp=temp->next;
}
printf("NULL\n");
}
int main()
{
clrscr();
create(start);
display(start);
printf("\n 2nd linklist\n");
create(start1);
display(start1);
getch();
return 0;
}
First problem
current must be declared outside the do/while loop, otherwise you will get undefined behaviour because there is no guarantee that current will keep it'svalue from one iteration to the next. However with certain compilers you may get away with it.
Second problem
Calling create(start); will not modify start because variables in C are passed by value. You need to write start = create(start);. See also this SO question. In your program start is still NULL after the call to the create function. You could have found out that easily by yourself.

Doubly Linked List Insert After Function

I already posted something similar before but this is another part of a problem that I'm having and I would appreciate your ideas and if you can help me fix my mistake.
As stated on my title i'm building a Doubly Linked List and I would like to know if my function insert_after works or not. When I run the full code I can't insert after the value that I chose which is why I'm posting this. Please let me know if I'm not clear or if this question is wrongly asked. I'm new in C and just need your help understanding.
This is my struct:
struct node
{
char data[100];
struct node *previous; // Points to the previous node
struct node *next; // Points out to the next node
}*head, *last;
This is my function to insert after a the chosen word:
char insert_after(char words[99], char loc[99])
{
struct node *temp, *var, *temp1;
var=(struct node *)malloc(sizeof(struct node));
strncpy(var->data, words,100);
if (head==NULL)
{
head=var;
head->previous=NULL;
head->next=NULL;
}
else
{
temp=head;
while ((temp!=NULL) && (temp->data!=loc))
{
temp=temp->next;
}
if (temp==NULL)
{
printf("\n %s not presented at list\n", loc);
}
else
{
temp1=temp->next;
temp->next=var;
var->previous=temp;
var->next=temp1;
temp1->previous=var;
}
}
last=head;
while (last->next!=NULL)
{
last=last->next;
}
return 0;// take it out after
}
And this is my main: --> Case 3 is my problem
int main()
{
char loc[99];
char words[99];
int i, dat;
head=NULL;
printf("Select the choice of operation on link list");
printf("\n1.) Insert At Begning\n2.) Insert At End\n3.) Insert At Middle");
printf("\n4.) Delete From End\n5.) Reverse The Link List\n6.) Display List\n7.)Exit");
while(1)
{
printf("\n\n Enter the choice of operation you want to do ");
scanf("%d",&i);
switch(i)
{
case 1:
{
printf("Enter a word you want to insert in the 1st node ");
scanf(" %s",words);
insert_beginning(words);
display();
break;
}
case 2:
{
printf("Enter a word you want to insert in the last node ");
scanf(" %s",words);
insert_end(words);
display();
break;
}
case 3:
{
printf("After which data you want to insert your new data ");
scanf(" %s",words);
printf("Enter the data you want to insert in list ");
scanf(" %s",loc);
insert_after(words, loc);
display();
break;
}
I didn't put the full code because it's pretty long which is why i posted the important stuff.
Please let me know if my question is not clear.
Thanks
This is a problem:
while ((temp!=NULL) && (temp->data!=loc))
temp->data != loc is not comparing strings, it just compares pointer addresses.
You could use strcmp or a similar string comparision function. strcmp returns non-zero if
the two parameters differ.
while ((temp!=NULL) && (strcmp(temp->data, words))
Note that it is words that is to compared to the values in the list as words is the value that loc is to be inserted after.
If you use char arrays as the parameters to insert_after function care will be needed to ensure that the entire length of the array is initialised correctly.
Note that a check on the following node is necessary in case there is only one node in the list (the following node will be NULL in this case).
char insert_after(char *words, char *loc)
{
struct node *temp, *var;
var=(struct node *)malloc(sizeof(struct node));
strcpy(var->data, loc);
if (head==NULL)
{
head=var;
head->previous=NULL;
head->next=NULL;
}
else
{
temp=head;
while ((temp!=NULL) && (strcmp(temp->data, words)))
{
temp=temp->next;
}
if (temp==NULL)
{
printf("\n %s not presented at list\n", words);
}
else
{
struct node * followingNode = temp->next;
temp->next=var;
var->previous=temp;
var->next= followingNode;
if (followingNode)
followingNode->previous = var;
}
}
}
Issues
char words[99] has 99 elements but you're allowing up to 100 here, strncpy(var->data, words,100);. That may cause a problem if words is not '\0' terminated. You could unintentially write word[99] to var->data which shouldn't be allowed. Change the statement to this:
strncpy(var->data, words, 99);
var->data[99] = '\0'; // In case words wasn't a string
You cannot compare strings like this, temp->data!=loc. You're actually comparing addresses. Change this line to the following:
while((temp != NULL) && (strcmp(temp->data, loc) != 0));
var->next=temp1 is incorrect. We're at the end of the list so this line should be rewritten as follows:
var->next = NULL;
You must use memcmp or, better yet, strcmp for string comparison instead of !=.

C Program to copy one binary search tree to another

So, here i have come up with Binary search tree prgram, where i am creating 2 binary trees tmp and tmp2, where i am trying to copy whole tmp2 to tmp, the node which is taken as input from user. But i am getting some segmentation fault, also i am not so sure if the logic is right.
Here is the whole program, please lemme know where is it going wrong in t_cpy() or please just fix it for me..
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *rlink;
struct node *llink;
}*tmp=NULL,*tmp2=NULL,*tmp3=NULL;
typedef struct node NODE;
NODE *create();
void inorder(NODE *);
void insert(NODE *);
void t_cpy(NODE *,NODE *);
int main()
{
int n,m;
do
{
printf("\n1.create tree 1\n2.Insert element to tree1\n3.create tree 2\n4.Insert element to tree2\n5.Inorder tree1\n6.Inorder tree2\n7.Copy tree2 to tree1\n8.exit\n\n");
printf("\nEnter ur choice: ");
scanf("%d",&m);
switch(m)
{
case 1: tmp=create();
break;
case 2: insert(tmp);
break;
case 3: tmp2=create();
break;
case 4:
insert(tmp2);
break;
case 5: printf("\n\nInorder Tree1: ");
inorder(tmp);
break;
case 6: printf("\n\nInorder Tree 2: ");
inorder(tmp2);
break;
case 7: t_cpy(tmp,tmp2);
break;
case 8: return(0);
}
}while(n!=8);
return(0);
}
void insert(NODE *root)
{
NODE *newnode;
if(root==NULL)
{
newnode=create();
root=newnode;
}
else
{
newnode=create();
while(1)
{
if(newnode->data<root->data)
{
if(root->llink==NULL)
{
root->llink=newnode;
break;
}
root=root->llink;
}
if(newnode->data>root->data)
{
if(root->rlink==NULL)
{
root->rlink=newnode;
break;
}
root=root->rlink;
}
}
}
}
NODE *create()
{
NODE *newnode;
int n;
newnode=(NODE *)malloc(sizeof(NODE));
printf("\n\nEnter the Data ");
scanf("%d",&n);
newnode->data=n;
newnode->llink=NULL;
newnode->rlink=NULL;
return(newnode);
}
void t_cpy(NODE *t1,NODE *t2)
{
int val,opt=0;
NODE *temp;
if(t1==NULL || t2==NULL)
{
printf("Can not copy !\n");
}
inorder(t1);
printf("\nEnter the node value where tree 2 should be copied\n");
scanf("%d",&val);
temp=t1;
while(temp!=NULL)
{
if(val<temp->data)
temp=temp->llink;
else
temp=temp->rlink;
}
if(temp->llink!=NULL || temp->rlink!=NULL)
printf("Not possible to copy tree to this node\n");
else
{
printf("Copy tree to \n 1.Left Node \n 2.Right Node\n Enter your choice : ");
scanf("%d",&opt);
if(opt==1)
{
temp->llink=t2;
}
else if(opt==2)
{
temp->rlink=t2;
}
else
printf("Invalid choice\n");
}
printf("Tree1 after copying is\n");
inorder(temp);
}
void inorder(NODE *tmp)
{
if(tmp!=NULL)
{
inorder(tmp->llink);
printf("%d",tmp->data);
inorder(tmp->rlink);
}
}
EDIT : Thanks to #xaxxon , who helped me with this.
Just update the while to make it work :
while(temp!=NULL&&temp->data!=val)
{
if(val<temp->data)
temp=temp->llink;
else
temp=temp->rlink;
if(temp->llink==NULL && temp->rlink==NULL && temp->data!=val)
{
printf("Invalid Node value entered !\n");
//break;
return 0;
}
and, Now it works fine for if entered value is present in the tree.
Thanks :)
Among other possible problems, you traverse temp until it is null, and on the next line you dereference it.
while(temp!=NULL)
{
if(val<temp->data)
temp=temp->llink;
else
temp=temp->rlink;
}
if(temp->llink!=NULL || temp->rlink!=NULL)
printf("Not possible to copy tree to this node\n");
You most likely mean to break out of this loop if val == temp->data, but you don't. Also, you still need to check to see if temp is null after the loop in case you didn't find val in your tree. Most likely you just meant to say:
if(temp==NULL)
printf("Not possible to copy tree to this node\n");
Also, you can't ask which side of the found node the user wants to copy a tree to. If you have a binary search tree, it has to be the side where the value should go. If you say to copy it to the right side, but all the values are less than the node, it's no longer a BST. In fact, you can't even ask where the value should go and still have a binary search tree. Each node has to be traversed from the root of the tree you want to put the other tree into to maintain the BST mechanics.
When you first use insert(tmp) the value of tmp does not change after you call insert(). Pass the address of tmp to insert(), using a *root within it instead of root.

Resources