linkedlist: count=count->next gives segmentation fault - c

#include<stdio.h>
#include<malloc.h>
typedef struct nde{
int data;
struct nde *next;
}node,*pnode;
void inst_beg(node *,int);
void inst_end(node *,int);
void inst_any(node *,int,int);
int del_begin(node *);
int del_end(node *);
int del_any(node*,int);
void display(node *);
main()
{
pnode head= (node *)malloc(1*sizeof(node));
head->data=0;
head->next=NULL;
inst_any(head,1,1);
inst_any(head,2,2);
// inst_any(head,3,3);
display(head);
}
void inst_any(node *head,int pos, int data){
pnode nd=(node *)malloc(1*sizeof(node));
nd->data=data;
//pnode count=(node *)malloc(1*sizeof(node));
pnode count;
count=head;
printf("head: %p",head);
printf("count: %p",count);
int i=0;
while(i<pos-1){
count=count->next; //Problem is here for inst_any(phead,2,2)
}
nd->next=count->next;
count->next=nd;
//printf("done");
}
void display(node * head){
pnode count=head;
while(count->next!=NULL){
printf("%d",count->data);
count=count->next;
}
}
Value of count is becoming null inside loop so we are not able to deference it when it is coming second time when inst_any(head,2,2) is being called. Checked with gdb that first time count is successfully being pointed to head. And same is happening for second time also. After count=head it is giving correct value for second time. Dont know what is happening after that. Why when its coming inside the loop count's value is becoming zero.

Look at this code:
while(i<pos-1){
count=count->next; //Problem is here for inst_any(phead,2,2)
}
That's the whole loop. So either your condition i<pos-1 is false right away .... or it is true and stays true, as you never modify i nor pos in your loop.
In the latter case, you walk a linked list. Eventually, you'll find the end (count->next is NULL) and still assign this NULL to count. In the next iteration, you try to dereference NULL to access ->next. Trying to dereference NULL is undefined behavior, a segmentation fault is a typical consequence.
Go and rethink your program (e.g., check whether count->next is still not NULL in your loop condition).

I have corrected your code with comments below. Please read my comments in the codes else you can not realize your mistakes. Hope this will help you.
typedef struct nde{
int data;
struct nde *next;
}node,*pnode;
void inst_beg(node *,int);
void inst_end(node *,int);
void inst_any(node *,int,int);
int del_begin(node *);
int del_end(node *);
int del_any(node*,int);
void display(node *);
void main()
{
pnode head= (node *)malloc(sizeof(node)); //No need to multiply by one
head->data=0;
head->next=NULL;
inst_any(head,1,1);
inst_any(head,2,2);
inst_any(head,3,3);
display(head);
inst_any(head,4,4); //I am adding this statement so that you can better understand where it going to be inserted
display(head);
inst_any(head,7,7);
}
void inst_any(node *head,int pos, int data){
pnode nd=(node *)malloc(sizeof(node));
nd->data=data;
//pnode count=(node *)malloc(1*sizeof(node));
pnode count;
count=head;
printf("head: %p\n",head);
printf("count: %p\n",count);
int i=0;
while(i < (pos-1)){
if(count == NULL){
printf("No position available for request pos =%d\n", pos);
return;//This condition is important. If your position is not exist in the list and count reached the end of the list just return with a error message
}
count=count->next; //Problem is here for inst_any(phead,2,2)
i++;//you must increment i
}
nd->next=count->next;
count->next=nd;//Here count must not be null, else it will create Segmentation fault. Therefore inside from while loop above we have checked whether it is null or not. If null return from this method.
//printf("done\n");
}
void display(node * head){
pnode count=head;
while(count!=NULL){//You have to correct it to print last node of the list
printf("%d\n",count->data);
count=count->next;
}
}

the posted code for the function: inst_any() initializes the data field, but fails to initialize the next field.
Suggest:
nd->data=data;
nd->next = NULL;
Then this loop:
while(i<pos-1){
count=count->next; //Problem is here for inst_any(phead,2,2)
}
fails to update the counter i so the loop never exits. Also, when the linked list does not contain enough entries this loop will run right off the end of the list. So the loop also needs to be checking that the count->next is not NULL.

Related

using while in recursive function

to display a linked list, I am using a recursive function. which was running infinite loop thanks to while loop.
when replaced with "if" the program worked without any issues.
looking for expert opinion on usage of
while
inside a recursive function.
recursive function with while
int display(node *curr){
if((curr->next != NULL) ){ //<--replace "if" with "while" and it runs infinite loop
printf("%d :: ",curr->data);
display(curr->next);
}
return 0;
}
complete code with create and display function
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
struct node {
int data;
struct node *next;
};
typedef struct node node;
int create(node *head);
int display(node *head);
int main(int argc, char *argv[]){
int ch,n=0;
node *head,*tail,*current;
head=(node*)malloc(sizeof(node));
create(head);
printf("\n");
display(head);
return 0;
}
int create(node *curr){
int data;
node *next;
printf("Enter the Data Value (Enter -1 to Finish): ");
scanf("%d",&data);
curr->data=data;
if(data == -1)
{
curr->next=NULL;
//return curr;
}
else
{
curr->next=(node*)malloc(sizeof(node));
create(curr->next);
}
return 0; }
int display(node *curr){
if((curr->next != NULL) ){
printf("%d :: ",curr->data);
display(curr->next);
}
return 0; }
The reason why you cannot use the while(curr->next != NULL) loop to index through and print the list is because for each call of the function display(), the value of curr->next is constant. This seems like it will successfully print the data in your linked list, and then infnitely print the second to last data point, as the comparison for the last data point will continually fail.
as suggested by Ritwick Dey, using
int display(node *curr)
{
while (curr)
{
printf("%d",curr->data);
curr = curr->next;
}
}
should work for you; by changing the pointer of the current node, you modify the conditional of the while loop every iteration. a value of NULL will cause this check to fail, so you can print the final data point without issue. this implementation has the added benefit of avoiding the cost of the recursive function call.
Though the question is not fully clear, I think you are asking why the code is working after changing the 'while' statement to 'if'. The explanation is below:
1.)You are not advancing your next pointer.
2.)Let's assume you have advanced your next pointer even then your code will run infinitely.
A simple dry run should be enough for this:
Let's take an example suppose your Singly link list of positive integers looks like this:
8-->9-->7-->NULL
Then following will be your recursion tree which illustrates on which condition your code is running infinitely.
display(8)
while(8->next)->display(9)
        while(9->next)->display(7)
               while(7->next)->display(NULL)--return
After returning from display(NULL) this will run infinitely for this case: while(7->next)---->display(NULL) and it will continue to loop around the same.
The correct function to display the link list is already pointed out in the Ritwick's answer.
int display(node *curr)
{
while (curr)
{
printf("%d",curr->data);
curr = curr->next;
}
}
Simple......
You get an infinite loop because you never advance the in the list, that's: l = l->next(); so, you never reach null

Why does using free() lead to infinite looping

When I run the following code, it gives me an infinite looping result. However if I comment out the free pointer lines in the insert function i.e. free(ptr) and free(ptrnext) then it works fine. Can anybody explain why is it so?
I am pretty sure that the print and takeInput works fine, and hence can be ignored.
#include<stdio.h>
#include<stdlib.h>
typedef struct Nodes{
struct Nodes * next;
int val;
}Node;
//Function to create a linked list
Node * takeInput(){
int data;
Node *start =NULL ;
Node *tail=NULL;
printf("Enter the number of nodes");
int num,i;
scanf("%d",&num);
for(i=1;i<=num;i++){
if(start==NULL){
start=malloc(sizeof(Node));
puts("Enter data");
scanf("%d",&data);
start->val=data;
start->next=NULL;
tail=start;
}
else{
Node * ptr = malloc(sizeof(Node));
puts("Enter data" );
scanf("%d",&data);
ptr->val=data;
tail->next=ptr;
tail=tail->next;
}
}
tail->next=NULL;
return start;
}
//Function to print
void print(Node * head){
Node*ptr=head;
while(ptr!=NULL){
printf("%d->",ptr->val);
ptr=ptr->next;
}
}
//Function to insert a node in given linked list
Node * insert(Node *start){
int i,data;
puts("Enter pos");
scanf("%d",&i);
puts("Enter data");
scanf("%d",&data);
Node * ptr=malloc(sizeof(Node));
ptr->val=data;
ptr->next=NULL;
if(i==1){
ptr->next=start;
start=ptr;
free(ptr);
}
else{
Node * ptrnext=start;
while(i!=1){
ptrnext=ptrnext->next;
i--;
}
ptr->next=ptrnext->next;
ptrnext->next=ptr;
free(ptr);
free(ptrnext);
}
return start;
}
int main(void){
Node * start =takeInput();
start=insert(start);
print(start);
}
When I run the following code, it gives me an infinite looping result. However if I comment out the free pointer lines in the insert function i.e. free(ptr) and free(ptrnext) then it works fine.
This is undefined behavior. (when you don't comment the free() functions)
Once you've freed memory you must remember not to use it any more.
Note : the pointer might or might not point the same block after freeing, it's undefined behavior
so don't free the pointer unless you want to destroy or delete the node.
so don't use the free() in the insert function as you are not deleting any node.
Apart from that, I don't see any function to deallocate the memory at the end of the program.
Always make sure to deallocate the allocated memory at the end using a delete() function.
Here's a typical implementation of delete function
void delete(Node* start)
{
Node* temporary = NULL;
while(start != NULL)
{
temporary = start->next; //saving next node address
free(start); //freeing current node
start = temporary; //assigning start with next node address
}
printf("successfully destroyed the list!"); //function exit message
}
Call it at the end of main() function or when you wish to delete the entire list

linked list implementation using pointer to pointer in C

I am unable to append a new node in the linked list. I have already identified the problem area but after much research and trying many things I am still unable to resolve the issue.
The problem is with the for loop in insert_node(char,struct **) function and traverse(struct *) function both of which never seem to terminate:
// program that stores name of the user using linkedlist
#include<stdio.h>
#include<stdlib.h>
typedef struct LIST{
int flag;
char name;
struct LIST *next;
} LISTNODE;
LISTNODE *head=NULL,*newnode=NULL;// global pointers
LISTNODE* initialize(); //initializes struct node with default values and returns a node
void insertNode(char c,LISTNODE** temp);
void traverselist(LISTNODE *temp);
int main(){
char ans,ch;
printf("\n\nEnter your name and hit enter-\n\n");
do{
printf("your name:");
fflush(stdin);
scanf("%c",&ch);
insertNode(ch,&head);
printf("\n\ninsertnode-back to main()");
printf("Want to continue?(Y?N):");
fflush(stdin);
scanf("%c",&ans);
}while(ans=='y'||ans=='Y');
printf("\n\ntraverselist-leaving main()");
traverselist(head);
printf("\n\ntraverselist-back to main()");
return 0;
}
void insertNode(char c, LISTNODE **temp){
printf("\n\ninto insertnode: before initialize");
LISTNODE* temp2;
newnode=initialize();
printf("\n\nback to insertnode:after initialize");
//printf("\nnewnode->name=%c",newnode->name);
//printf("\nnewnode->flag=%d",newnode->flag);
newnode->name=c;
//printf("\nnewnode->name=%c",newnode->name);
//printf("\nnewnode->flag=%d",newnode->flag);
//for(;(*temp)!=NULL;temp=&(*temp)->next);
/*while((*temp)->next!=NULL){
temp=&(*temp)->next;
printf("\n\nIn while!");
}
*/
for(;*temp!=NULL;temp=&((*temp)->next))
printf("\n\nIn for!") ;
//printf("\n\nout of while!");
(*temp)=newnode;
}
LISTNODE* initialize(){
static int count=0;
LISTNODE *tempnewnode;
printf("\n\nINto inintialize!");
tempnewnode=(LISTNODE*)malloc(sizeof(LISTNODE));
if(tempnewnode==NULL){
printf("No memory available. Aborting!");
exit(0);
}
else{
tempnewnode->flag=0;
tempnewnode->name='*';
tempnewnode->next=NULL;
if(count==0){
head=tempnewnode;
count++;
}
}
return tempnewnode;
}
void traverselist(LISTNODE *temp){
printf("\n");
for(;temp!=NULL;temp=temp->next){
printf("%c",temp->name);
}
}
Please help!
The problem is inside the insert_node function, specifically with the loop:
for(;*temp!=NULL;temp=&((*temp)->next))
printf("\n\nIn for!");
You'd be better advised not to use the reference temp in your loop, as it overwrites the head->next back to itself. Create another temporary pointer.
I changed the insertNode(char, LISTNODE**) to the following:
void insertNode(char c, LISTNODE *temp){
LISTNODE** temp2=&temp;
newnode=initialize();
printf("\n\nback to insertnode:after initialize");
newnode->name=c;
for(;(*temp2)!=NULL;temp2=&(*temp2)->next)
printf("\n\nIn for!") ;
(*temp2)=newnode;
}
and function is called like this:
insertNode(ch,head);
It works just fine!
The problem is this portion of your insertNode function
for(;*temp!=NULL;temp=&((*temp)->next))
printf("\n\nIn for!") ;
//printf("\n\nout of while!");
(*temp)=newnode;
Here you should first check if the link list is empty or not if it is empty then you can create the new node and assign the address of it to temp.
If not then depending upon whether you want to insert the new element in the end, beginning or middle of the list you should traverse the list then perform the insertion.
For example if you want to perform insertion at the beginning then after creating the new node you should assign the address of the start pointer of the list to the next of newly created node and move the start to the new node as you have to keep track of the start pointer.

Trouble passing a struct to a thread function in C

We are trying to add nodes to a linked list in one thread, and delete nodes from the linked list in the other thread.
We believe the following line is our problem: if(time(NULL) == llnode->time)
.We are trying to access the time in the head node of the list. I'm not sure if we are passing the correct arguments to the functions. The thread to create nodes is working correctly, but the thread to delete nodes isn't. It's resulting in a segmentation fault. It'd be greatly appreciated if anyone could point me in the right direction, as I've been stuck on this for a while.
/* Link list node */
struct node
{
int roomNo;
time_t time;
struct node* next;
};
void * addThread(void *n)
{
struct node *llnode = n;
time_t date;
int room;
struct tm * timeptr;
pthread_mutex_lock(&lock);
while (pending < 5)
{
printf("Adding node.\n");
insert(&llnode, getRandRoom(), getRandTime());
date = getRandTime();
room = getRandRoom();
timeptr = localtime(&date);
printf("Registered: %d %s", room, asctime(timeptr));
sleep(1);
pending++;
}
pthread_mutex_unlock(&lock);
}
void * wakeThread(void *n)
{
struct node *llnode = n;
while(1)
{
if(time(NULL) == llnode->time)
{
printf("Deleting head node.\n");
pthread_mutex_lock(&lock);
deleteNode(&llnode);
pending--;
expired++;
pthread_mutex_unlock(&lock);
}
}
}
int main()
{
struct node* head;
head = NULL;
signal(SIGINT, ctrlc_catch);
pthread_t addWakeup, makeWakeup;
pthread_create(&addWakeup, NULL, addThread, (void*)head);
sleep(6);
pthread_create(&makeWakeup, NULL, wakeThread, (void*)head);
pthread_join(addWakeup, NULL);
pthread_join(makeWakeup, NULL);
return 0;
}
Here are the prototypes for our functions that aren't shown in the code(functions have been tested outside the threads and are fully functional):
void insert(struct node** head_ref, int new_room, time_t new_time);
void deleteNode(struct node** head_ref);
Essentially, head starts off as NULL and remains NULL for the lifetime of your program. The NULL pointer gets passed to wakeThread, which proceeds to dereference it (llnode->time). This is what triggers the segfault.
To fix, you need to make sure that any changes that the addThread makes to head are visible to the wakeThread. One way to do it is by passing a pointer to head to both threads. If you do this, make sure you get the locking right!
head in main() is a pointer to struct node. It's initialized to NULL and passed to the thread functions. They both receive a NULL pointer. Then addThread() might be able to grow its own node list with insert(), but wakeThread() is definitely not going to delete any of it with deleteNode(), because it just doesn't have the right pointer, all it has is a NULL pointer, which it tries to dereference and crashes.

Appending a List--Segmentation fault

I am trying to append one list with another . If i pass a pointer-to-the-pointer of both the lists and just display them, then , the code works fine. But if i use code to reach the NULL pointer of the first list and then equate it to the first one of the second, then it gives a segmentation fault. Please let me know what the mistake is. Code is below :
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node* next;
}*Head,*New;
void display(struct node **p)
{
struct node *curptr;
curptr=*p;
if(curptr==NULL)
printf("list is empty");
else
{
while(curptr)
{
printf("->%d",curptr->data);
curptr=curptr->next;
}
}
}
void combine(struct node **a,struct node **b)
{
//display(&(*a));
struct node *aptr;
aptr=*a;
while(aptr)
aptr=aptr->next;
aptr->next=*b;
*b=NULL;
display(&(*a));
//display(&(*a));
//display(&(*b));
}
void main()
{
Head=NULL;
New=NULL;
int choice;
while(1)
{
case 9:
{
printf("Combining two lists");
combine(&Head,&New);
break;
}
The problem is here:
while(aptr)
aptr=aptr->next;
aptr->next=*b
When you break out of the while loop aptr will be NULL next when you try to do aptr->next you get the SEGV.
To fix this break out of the loop when you reach the last node(aptr->next will be NULL) rather than aptr becoming NULL.
Something on these line:
// if fist list does not exist.
if(*a == NULL) {
*a = *b;
return;
}
struct node *aptr;
aptr=*a;
// loop till you reach the last node of fist list.
while(aptr->next)
aptr=aptr->next;
// append.
aptr->next=*b;
*b=NULL;
while(aptr)
aptr=aptr->next;
runs till aptr is NULL, after that
aptr->next=*b;
causes a segmentation fault since you dereference NULL.

Resources