doubly linked list insert at middle - c

Can anyone identify what is happening in my code that is causing the segmentation fault? Please modify/correct the wrong part.
void InsertAtMid (Node *head){
int num,count=0,i;
Node *ptr=head;
Node *newnode=NULL;
Node *newnode2=head;
printf("Enter node to be inserted: ");
scanf("%d", &num);
if (head==NULL){
newnode = head;
newnode=(Node *)malloc(sizeof(Node));
newnode->x=num;
newnode->next=NULL;
newnode->prev=NULL;
} else {
ptr=head->next;
while(ptr->x!=(count/2)){
ptr=ptr->next;
}
newnode->next=ptr->next;
newnode->prev=ptr;
ptr->next->prev=newnode;
ptr->next=newnode;
}
}

So, based on my understanding of your code - the following should [mostly] work:
void InsertAtMid (Node **head){
int num = 0;
int count = 0
int advance = 0;
Node *ptr = *head;
Node *newnode = NULL;
printf("Enter node to be inserted: ");
scanf("%d", &num);
if (*head == NULL) {
*head = (Node *)malloc(sizeof(Node));
ptr = *head;
ptr->x = num;
ptr->next = NULL;
ptr->prev = NULL;
} else {
// *** Count the number of items
ptr = *head;
while (ptr != NULL) {
ptr = ptr->next;
count++;
}
// *** Move to the middle of the list
ptr = *head;
while (advance < (count/2)){
ptr = ptr->next;
advance++;
}
// *** Insert the new value
newnode = (Node *)malloc(sizeof(Node));
newnode->x = num;
newnode->next = ptr->next;
newnode->prev = ptr;
ptr->next->prev = newnode;
ptr->next = newnode;
}
}
The following are the issues I fixed:
You are assigning to head at one point, but since "head" isn't passed in as a reference, the value isn't going to be maintained beyond the first time the function is called. Needless to say you need a pointer to a pointer of type node.
You never calculated the number of items in the list. Often "head" pointer would store this information and you would increment when you add a node, but since you don't have that the only way to determine it is to traverse the list till you find the count.
You never allocated space for the new node to insert except if you were initializing the head pointer. This was also an issue.
Hope that helps some. Best of luck!

int num,count=0,i;
...
ptr=head->next;
while(ptr->x!=(count/2)){
ptr=ptr->next;
count is initialized to 0 and never changed.
So unless you enter "0" for x, that while loop is just going to walk off the end of the list, every time.

Test to work out under what circumstances your code segfaults.
You'll find that it works OK when head == NULL, but fails if head is not null.
So you know that your error is somewhere in the else block.
Step through your running code in a debugger (if you don't know how, it's never too early to learn: whenever you solve a problem with a debugger, you think "why didn't I turn to this sooner?").
Work out what you expect to happen, watch the variables in the debugger, and when the actual values deviate from your expectations, reason about why.
It's not clear to me what you expect to happen in your code, but what will actually happen for a list with one node, is that:
it will execute ptr=head->next; -- so ptr is now NULL.
then for the while condition it will try to dereference ptr->x, and since ptr is NULL, it will segfault.
A quick fix for that would be:
while(ptr != NULL && ptr->x ....) {
But you need to think about whether that's the actual logic you want; and once you get past that, you'll hit other problems (for example, count never changes), which can be sorted out with a debugger in the same way.

Related

Why am I getting segmentation fault on my code?

I am trying to add an item to the linked list by traversing the list to create the next node. and the last node in the list to point to the newly created node. But I am getting a core dump segmentation fault on it.
void linked_list_add(list_node_t *head, void *item)
{
list_node_t *temp = head;
while(temp->next != NULL)
{
temp = temp->next;
}
list_node_t *new_node = (list_node_t *)malloc(sizeof(list_node_t));
new_node->data = item;
new_node->next = NULL;
new_node->prev = temp;
//if(temp != NULL)
// temp->next = new_node;
// new_node->prev = temp;
}
TEST_F(LinkedList, Add)
{
int i = 3;
linked_list_add(list, &i);
ASSERT_EQ(list->next->data, &i);
i = 4;
linked_list_add(list, &i);
ASSERT_EQ(list->prev->data, &i);
i = 5;
linked_list_add(list, &i);
ASSERT_EQ(list->next->data, &i);
}
This is an answer to summarize the comments.
There are likely at least 3 issues with the code as written:
When the code void linked_list_add(list_node_t *head, void *item) is passed arguments, you generally want to be able to handle a NULL pointer for head. It looks like the while loop immediately goes into searching for the end of the list even if the head is null.
The newly added node, new_node gets the prev pointer updated so that the backwards searchs will be and shouldn't segfault. However, the forward searching isn't preserved. By this I mean that the last non-NULL node in the linked list doesn't have the next pointer pointing to the new_node.
The test ASSERT_EQ(list->prev->data, &i); is likely accessing either a random memory location or a NULL pointer. Given that the OP didn't post the declaration of the list struct it is difficult to say what the default values are/will be. However, unless this list is circular, the value of list->prev is an uninitialized pointer. Depending on your setup (e.g. if there is setup code for the linked list that sets the pointers to null, you could be accessing a NULL pointer there too.
I hope this helps the OP solve their coding problem(s).

Can't seem to ever get the print function in linked list in c

cant print the linked list, it gets stuck in an infinite loop cant understand where i'm going wrong.
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int data;
struct node *next;
}node;
node *head = NULL;
void print(node *head){
node *temp = head;
while(temp!=NULL);
{
printf("%d => ",temp->data);
temp = temp->next;
}
printf("NULL");
}
node *clist(int n){
node *temp = NULL;
node *p = NULL;
int i;
for(i=0;i<n;i++)
{
temp = (node*)malloc(sizeof(node));
printf("Enter the elements of the list.\n");
scanf("%d",&temp->data);
}
if(head!=NULL)
{
while(p->next!=NULL)
p=p->next; //shifting p here node by node
p->next = temp; //last node which was just created
}
else
{
head = temp;
}
return head;
}
node *binsert(int x){
node *temp = NULL;
node *p = NULL;
temp = (node*)malloc(sizeof(node));
if(head!=NULL)
{
temp->next = head;
temp = head;
}
else
{
p = head = temp;
}
return head;
}
int main ()
{
int a, s, i, n,f;
printf("Choose an option : \n1.Create a list.\n2.Exit.\n");
scanf("%d",&s);
switch(s)
{
case 1:
printf("Very Well! Input the number of nodes\n");
scanf("%d",&n);
head = clist(n);
printf("Link List created successfully.\n");
print(head);
break;
default:
exit (0);
}
printf("Choose the operation you want to perform on the linked list:\n1.Add an element to the beginning.\n2.Add an element to the end.\n3.Add an element at a a particular position.\n");
scanf("%d",&a);
switch(a)
{
case 1:
printf("Enter the element you want to insert at the beginning.\n");
scanf("%d",&f);
binsert(f);
printf("Inserted Successfully.\n");
print(head);
break;
case 2:
printf("Error E162B");
}
return 0;
}
I tried changing the head to a global variable. re-wrote the code 7 times. please help.
First:
for(i=0;i<n;i++)
{
temp = (node*)malloc(sizeof(node));
printf("Enter the elements of the list.\n");
scanf("%d",&temp->data);
}
This loop repeats several times so that the user can enter the elements of the list. But it never adds any of the nodes to the linked list. Each iteration of the loop changes temp to point to a newly-allocated node but doesn't add the nodes to the linked list.
Second:
while(temp!=NULL);
This is an endless loop right here. If temp is not NULL, it's not changed anywhere in the loop, so it will never become NULL. You don't want that semicolon there.
Third:
node *head = NULL;
void print(node *head){
node *temp = head;
Don't do this to yourself. You have a global variable called head and you have a parameter called head. When you do node *temp = head; how obvious is it which head that's referring to. Don't give two variables the same name if their scope overlaps.
Fourth:
if(head!=NULL)
{
temp->next = head;
temp = head; // **** here
}
else
{
p = head = temp;
}
return head;
What's the point of temp = head;? The value of temp isn't accessed anywhere. So that can't be right.
Lastly:
I think you didn't ask the right question though. You asked us to explain where you're going wrong, and I've done that. But I don't think that's what you actually need. Maybe you need help developing the algorithm to solve the problem? Perhaps ask a new question describing what you think the algorithm should be (just in words, no need to use code) and ask for help fixing the algorithm.
And, to be blunt, the number of mistakes suggests that you are attempting a task that is significantly beyond your knowledge. This is frustrating and not a good way to learn programming. You should seriously consider attempting simpler tasks first.
You may have stripped it out to keep the question simple, but your real code should contain lots of extra checking and logging to help you understand it. Log when you enter a function. Log each decision the function makes. Log what functions return. That will help you determine where the program's actual operation is deviating from you think it should be doing. Or, if you prefer, learn to use your platform's debugging facilities. That way, you won't be making random changes and hoping that they make everything work but will instead know where the code is first going awry and be able to fix one thing at a time confident that you are not breaking things that were working.

Link list program crash on malloc

I'm fairly new to C and coding in general so please bear with me. I've been trying to implement a linked list recently and this is the code i came up with
typedef struct something{
int data;
struct something *next;
} thing ;
int main ()
{
thing *head, *current;
head=malloc(sizeof(thing));
puts("head=malloc(sizeof(thing));");
if (head != NULL)
puts("malloc success");
head=NULL;
current=head;
puts("current=head;");
if (current == NULL)
puts("current is NULL");
puts("while");
while (current!=NULL)
{
current = current->next;
}
puts("end while");
current->next=malloc(sizeof(thing));
puts("current->next=malloc(sizeof(thing));");
//free at end of program
}
While the compiler shows 0 errors, when i run the program it only runs until the final malloc part before crashing. It doesnt run the final puts so i will assume it's something to do with the way i'm trying to use malloc.
I'll gladly appreaciate for someone to tell me what im doing wrong.
The problem is that your while loop goes to far. You want to stop when current points to the last element of the list, so you can add to it. But you're going one step further, and stopping when current == NULL. It's then too late to assign to current->next.
First, you need to initialize head->next to NULL.
head = malloc(sizeof(thing));
head->next = NULL;
Get rid of the line:
head = NULL;
as this is overwriting the result of malloc().
Then your while loop needs to test current->next, not current itself:
while (current->next != NULL) {
current = current->next;
}
And when you add the new node, you have to set its next pointer to NULL as well:
current->next = malloc(sizeof(thing));
current->next->next = NULL;
These should fix your problem.
You allocate head and then immediately after few checks point its pointer to NULL
// Allocation here
head=malloc(sizeof(thing));
puts("head=malloc(sizeof(thing));");
// Not a null
if (head != NULL)
puts("malloc success");
// Point to NULL again ???
head=NULL;
Then your current points to head viz NULL again that makes current NULL
current=head;
puts("current=head;");
if (current == NULL)
puts("current is NULL");
and then you dereference current and try to malloc
puts("while");
while (current!=NULL)
{
current = current->next;
}
puts("end while");
current->next=malloc(sizeof(thing)); //current is NULL here NULL->next is invalid
puts("current->next=malloc(sizeof(thing));");

Delete single linked list recursively in C

It looks there is no duplicate questions...so i want a function to free all nodes in a single linked list, and i want to do it recursively. I come up with a close one that i thought it would work, but it does not. It seems that after it removed one node, the upper stack function will not excuse, recursively. I am wondering how to modify the code to make it work.
#include <stdlib.h>
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
if(!(begin_list->next))
{
free(begin_list);
begin_list = NULL;
}
}
int main()
{
struct Node* head = NULL;
struct Node* second = NULL;
struct Node* third = NULL;
// allocate 3 nodes in the heap
head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));
head->data = 1; //assign data in first node
head->next = second; // Link first node with second
second->data = 2; //assign data to second node
second->next = third;
third->data = 3; //assign data to third node
third->next = NULL;
ft_list_clear(head);
return 0;
}
You're pretty close
void ft_list_clear(struct Nude *list)
{
if (!list) { return; }
ft_list_clear(list->next);
list->next = null;
free(list);
}
Explaining the code
The first if checks if the list is currently null and exits the recursion if so.
If the list isn't null recursively call the function.
This repeats until the end of the list null.
Then since the next has been cleared by the recursive call you can set it to null in this call (not strictly necessary since this clears everything).
Finally actually free this node prior to returning to the previous call (this node's parent).
You can also do the delete in the opposite order if you want
void ft_list_clear(string Node *list)
{
if (!list) { return; }
struct Node *next = list->next;
free(list);
ft_list_clear(next);
}
Same principles just deletes this node before going to the next. This means you don't need to fix the next pointers but you will need to copy them first so you don't lose the reference.
I think it's because you're just freeing nodes, but you miss to nullify the next members. Try this. I haven't run this so goodluck.
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
{
ft_list_clear(begin_list->next);
begin_list->next = NULL; // <-- you should nullify the next of the current after you free the node which it points to.
}
if(!(begin_list->next)) // <-- even if the next node was deleted, this won't run if you didn't nullify begin_list->next
{
free(begin_list);
begin_list = NULL;
}
}
`void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
free(begin_list);
begin_list = NULL;
printf("God bless America");
}`
Hopefully, if God blesses America thrice, your code is working, I've committed some changes in your code, and all I did was remove the second if statement because usually, we don't need that in recursion (I'm not saying we don't need more than one if statement). Test it yourself and you'll understand why it's so. Hope it helps.
The problem with this
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
if(!(begin_list->next))
{
free(begin_list);
begin_list = NULL;
}
}
is:
In the first call, begin_list is equal to head.
head->next is not NULL, so ft_list_clear(second) is executed
second->next is not NULL, so ft_list_clear(third) is executed
third->next is NULL, so free(third) happens. The begin_list = NULL
line does nothing here, its pointless.
The third iteration returns, back to the second. The next line to execute is
if(!(begin_list->next))
begin_list->next is not NULL (it's been only freed), hence the condition is evaluated to false and the free
is not executed.
Same happens with the first iteration.
This is recursion that would work:
void ft_list_clear(struct Node *begin_list)
{
if(begin_list == NULL)
return;
ft_list_clear(begin_list->next);
free(begin_list);
}
Recursively deleting a linked is a bad idea. Each recursive call requires a stack frame, and whether you free the list node memory as you descend or ascend the recursion, you need O(n) memory for what is a simple operation. Each stack call requires local variable storage, room for return pointer, previous stack frame pointer, and possibly other stuff (at least 12-24 bytes per node).
Better to iterate through the list. I have provided three variants of the free (iterative, and two recursive, one free's node on descent, one free's node on ascent).
#include <stdlib.h>
#include <stdio.h>
typedef struct Node
{
int data;
struct Node* next;
} node_t;
long list_clear_iter(node_t* p) {
if(!p) return 0;
long n = 0; //count;
for( ; p->next; ) {
node_t* fp = p; //free this
p = p->next;
free(fp);
++n;
}
return n;
}
//list clear, recursive, (pre)free
long ft_list_clear_pr(node_t* p) {
if(!p) return 0;
node_t* np = p->next;
free(p); //free on descend
long n = ft_list_clear_pr(np);
return(n+1);
}
//list clear recursive, free(post)
long ft_list_clear_rp(node_t* p) {
if(!p) return 0;
long n = ft_list_clear_rp(p->next);
free(p); //free on ascend
return(n+1);
}

Single linked list in C

I am trying to write a singly-linked list in C. So far, I just get segmentation faults.
I am probably setting the pointers wrong, but I just couldn't figure how to do it correctly.
The list should be used for "processors" sorted from highest priority (at the beginning of the list) to lowest priority (at the end of the list). Head should point to the first element, but somehow I am doing it wrong.
First of all here is the code:
struct process {
int id;
int priority;
struct process *next;
}
struct process *head = NULL;
void insert(int id, int priority) {
struct process * element = (struct process *) malloc(sizeof(struct process));
element->id = id;
element->priority = priority;
while(head->next->priority >= priority)
head = head->next;
element->next = head->next;
head->next = element;
// I put here a printf to result, which leads to segmenatition fault
// printf("%d %d\n", element->id, element->priority);
}
/* This function should return and remove element with the highest priority */
int pop() {
struct process * element = head->next;
if(element == NULL)
return -1;
head->next = element->next;
free(element);
return element->id;
}
/* This function should remove a element with a given id */
void popId(int id) {
struct process *ptr = head;
struct process *tmp = NULL;
while(prt != NULL) {
if(ptr->id == id) {
ptr->next = ptr->next->next;
tmp = ptr->next;
} else {
prt = ptr->next;
}
}
free(tmp);
}
Unfortunately, I could not try out pop() and popId() due to the segmentation fault.
May anyone tell me what I am doing wrong?
EDIT: Now, I edited the insert function. It looks like this:
void insert(int id, int priority) {
struct process * element = (struct process *) malloc(sizeof(struct process));
struct process * temp = head;
element->id = id;
element->priority = priority;
if(head == NULL) {
head = element; // edited due to Dukeling
element->next = NULL;
} else {
while(temp->next != NULL && temp->next->priority >= priority)
temp = temp->next;
element->next = head->next;
head->next = element;
}
// I put here a printf to result, which leads to segmenatition fault
// printf("%d %d\n", element->id, element->priority);
}
But I still get segmentation fault for pop() and popId(). What did I miss here?
You don't check if head is NULL in insert.
You actually don't check if head is NULL in any function. You should, unless you want to put some dummy element on head, to simplify the code.
For insert:
About these lines:
while(head->next->priority >= priority)
head = head->next;
If head is NULL, that's not going to work. This may not actually be a problem if head can never be NULL for whichever reason (e.g. it has a dummy element as gruszczy mentioned).
You're changing head, thus you're getting rid of the first few elements every time you insert. You probably need a temp variable.
You need to also have a NULL check in case you reach the end of the list.
So, we get:
struct process *temp = head;
while (temp->next != NULL && temp->next->priority >= priority)
temp = temp->next;
For pop:
If the first element isn't a dummy element, then you should be returning the ID of head, not head->next (and you were trying to return a value of an already freed variable - this is undefined behaviour).
if (head == NULL)
return -1;
int id = head->id;
struct process *temp = head;
head = head->next;
free(temp);
return id;
For popId:
You're checking ptr's ID, but, if it's the one we're looking for, you're removing the next element rather than ptr. You should be checking the next one's ID.
head == NULL would again need to be a special case.
The free should be in the if-statement. If it isn't, you need to cater for it not being found or finding multiple elements with the same ID.
You should break out of the loop in the if-statement if there can only be one element with that ID, or you want to only remove the first such element.
I'll leave it to you to fix, but here's a version using double-pointers.
void popId(int id)
{
struct process **ptr = &head;
while (*ptr != NULL)
{
if ((*ptr)->id == id)
{
struct process *temp = *ptr;
*ptr = (*ptr)->next;
free(temp);
}
else
{
prt = &(*ptr)->next;
}
}
}
Note that the above code doesn't break out of the loop in the if-statement. This can be added if you're guaranteed to only have one element with some given ID in the list, or you want to just delete the first such element.
Your not checking your pointers before accessing their values for dereference. This will automatically lead to undefined behavior if the pointer is invalid (NULL or indeterminate). With each implementation below, note we don't access data via dereference unless the pointer is first-known as valid:
Implementation: insert()
void insert(int id, int priority)
{
struct process **pp = &head;
struct process *element = malloc(sizeof(*element);
element->id = id;
element->priority = priority;
while (*pp && (*pp)->priority >= priority)
pp = &(*pp)->next;
element->next = *pp;
*pp = element;
}
Implementation: pop()
Your pop() function appears to be designed to return the popped value. While this isn't entirely uncommon it has the undesirable side-effect of having no mechanism for communicating to the caller that the queue is empty without a sentinel-value of some sort (such as (-1) in your case. This is the primary reason most queues have a top(), pop(), and isempty() functional interface. Regardless, assuming (-1) is acceptable as an error condition:
int pop()
{
struct process *tmp = head;
int res = -1;
if (head)
{
head = head->next;
res = tmp->id;
free(tmp);
}
return res;
}
Implementation: popId()
Once again, looking for a specific node can be accomplished with a pointer-to-pointer in a fairly succinct algorithm, with automatic updating done for you due to using the actual physical pointers rather than just their values:
void popId(int id)
{
struct process ** pp = &head, *tmp = NULL;
while (*pp && (*pp)->id != id)
pp = &(*pp)->next;
if (*pp)
{
tmp = *pp;
*pp = tmp->next;
free(tmp);
}
}
I strongly advise stepping through each of these with a debugger to see how they work, particularly the insert() method, which has quite a lot going on under the covers for what is seemingly a small amount of code.
Best of luck

Resources