Avoid Segmentation Fault with Empty Linked List - c

I have a List in C with the following data structures:
typedef struct node{
int in_id;
struct node *next;
} Node;
typedef struct List{
Node* head;
Node* tail;
}List;
My function for viewing the front of the list works fine if the list is occupied, however, if the list is empty and I take a peek inside the list, I receive a segmentation error. Which is completely understandable. However, I have been trying to think of a way to either prevent this or circumvent the segmentation error.
Node* front(List *q){
Node *temp;
temp = NULL;
if(q->head == NULL && q->tail == NULL){
printf("front function: this is empty \n");
return temp;
}
else{
temp = q->head;
return temp;
}
}
First idea is if I need to use front in an if(front(Node)->value == x), I get a segmentation error if its empty. However, I short circuit this by putting something else I need to test before front, if( something == TRUE && front(Node)->value == x).
What I also thought about doing was malloc() some dynamic memory to temp within front and assigning the relevant field that I'm testing for a value that I know is false if the head && tail == NULL. However, I feel this is memory leakage becuase I wouldn't be able to free() temp.
Is there a better way for me to handle peeking into this queue and not getting a segmentation fault if its empty?

I think you're trying to do too much in your one-liner function call. front(Node)->value is always going to try to dereference whatever is returned from that function, even if it is NULL, hence the seg fault when the list is empty and it returns NULL. You need to split that line up.. first retrieve the pointer from a call to front(...), then check it for NULL, and if not NULL, then proceed with the dereference:
Node* temp = front(list);
if (temp != NULL)
{
// proceed with dereference
if (temp->value == x) // this won't seg fault, do whatever with it
{
// ...
}
}
else
{
// print error or do nothing
}
There is probably a more clever way to one-line it, but if you're stuck and not constrained with a strict line requirement is it really worth it?

If the linked list is empty then head node is always null. And in your function your checking head and tail element of the empty node. that's why your getting segmentation fault .
just try below function
Node* front(List *q){
Node *temp;
temp = NULL;
if(q == NULL){
printf("front function: this is empty \n");
return temp;
}
else{
temp = q->head;
return temp;
}
}

Related

Why does my C Program crash when I try to delete a node out of a singe linked list

I am currently creating a Program in C which is basically a linked list inside of a linked list. The inner list being character and the outer list being words. Unfortunately I'm having Problems with deleting some of the outer Nodes (words) and freeing their memory. My program keeps crashing and I have no idea why. The compiler doesnt give me any warnings or errors and I've been looking for a fix for hours. Any help is apreciated for anyone who could look over the code! Thanks!
*void deleteWord (Node* Node, int index){
int counter = 0;
if (Node == NULL)
return;
while (Node->next != NULL && counter != (index - 1)){
Node = Node->next;
counter++;
}
struct node* wordTemp = Node->next;
//Node->next = Node->next->next;
while (wordTemp->word != NULL){
InnerNode* letterTemp = wordTemp->word->next;
free(wordTemp->word);
wordTemp->word = letterTemp;
}
free(wordTemp);
return;
}
Seems like you are freeing Node->next (stored in wordTemp), without re-assigning it, essentially breaking the link in the linked list, so now Node->next points to a deleted memory.

Merge Sort On Linked List in C

Merge sort is often preferred for sorting a linked list. The slow random-access performance of a linked list makes some other algorithms (such as quicksort) perform poorly, and others (such as heapsort) completely impossible.
I have been struggling to do Merge Sort on a linked list. It keeps throwing back an error. I'm providing the code I've tried to execute. Please do help me out.
It keeps giving runtime error.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *SortedMerge(struct node *a, struct node *b);
void FrontBackSplit(struct node *source, struct node *frontref, struct node *backref);
struct node *Create(struct node *head, int num) {
struct node *newnode, *temp;
newnode = (struct node *)malloc(sizeof(struct node));
newnode->data = num;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
temp = newnode;
} else {
temp->next = newnode;
temp = temp->next;
}
temp->next = NULL;
return head;
}
struct node *display(struct node *head) {
struct node *temp;
temp = head;
while (temp != NULL) {
printf("%d->", temp->data);
temp = temp->next;
}
printf("NULL");
return head;
}
struct node *MergeSort(struct node *head) {
struct node *headref, *a, *b;
headref = head;
if ((head == NULL) || (head->next) == NULL) {
return;
}
FrontBackSplit(headref, a, b);
MergeSort(a);
MergeSort(b);
head = SortedMerge(a, b);
return head;
}
void FrontBackSplit(struct node *source, struct node *frontref, struct node *backref) {
struct node *fast, *slow;
slow = source;
fast = source->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
frontref = source;
backref = slow->next;
slow->next = NULL;
}
struct node *SortedMerge(struct node *a, struct node *b) {
struct node *result;
result = NULL;
if (a == NULL) {
return (b);
}
else if (b == NULL) {
return (a);
}
if (a->data <= b->data) {
result = a;
result->next = SortedMerge(a->next, b);
} else {
result = b;
result->next = SortedMerge(a, b->next);
}
return result;
}
int main() {
struct node *head = NULL;
int i, n, num;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &num);
head = Create(head, num);
}
head = MergeSort(head);
display(head);
}
There are a couple of problems with the code, and which one triggers the error you are seeing I cannot say, but I will point out a few of them below. Take Create():
struct node *Create(struct node *head, int num)
{
struct node *newnode, *temp;
newnode=(struct node *)malloc(sizeof(struct node));
newnode->data=num;
newnode->next=NULL;
if(head==NULL) {
head=newnode;
temp=newnode;
} else {
temp->next=newnode;
temp=temp->next;
}
temp->next=NULL;
return head;
}
I cannot work out exactly what it is supposed to do, to be honest. Maybe add a new node to a list, represented by a head link? It doesn't do that. You create a new node
newnode=(struct node *)malloc(sizeof(struct node));
which I would suggest you write as
newnode = malloc(sizeof *newnode);
You don't need to cast void *, so you don't need to cast the result of malloc(), and using sizeof *newnode rather than sizeof(struct node) is safer. But the code works correctly in the form you have, so there is not a problem there. However, what happens with that node depends on head. If head is NULL, you point it at the new node, and through temp you (re)assign the new node's next to NULL. So now you will return an updated head that consists of the new node as a single element list. That matches my guess at what the function should do.
However, if head is not NULL, you put the new node in temp->next, which is a problem, since temp isn't initialised. You write to temp in the if(head==NULL) branch, but you dereference it in the else branch, where it can point anywhere. I am surprised if you don't get a segmentation fault from time to time here. It isn't necessary to assign the new node to temp->next, though, because immediately afterwards you change temp to point to temp->next, which is where you just put newnode, so temp = newnode would do the trick, without the segfault. But not all is well if we do that. We now would have the new node in temp (with the next pointer, again, reassigned to NULL) and then we return head. We didn't connect head with newnode anywhere, if we took the else branch. So calling Create() with a non-NULL head creates a new node, throws it away (and leaking memory), and that is all that does.
So while my guess is that Create() should add a new to a list, represented by head, or something to that effect, what it actually does is create a single-element list if the first argument is NULL, and leak sizeof(struct node) memory while doing nothing if head != NULL.
That being said, the code might work by pure luck of course. When I tried it with clang with zero optimisation, I somehow managed to build a list correctly. This is luck, though. It won't work in general. I suspect that what happens is that the repeated calls to Create() in the loop in main() happens to leave the last node you created (and wrote to temp) at the same stack location as the uninitialised temp in the next call. So by pure luck, putting the new node in temp's next appends the new node to the last node you created. It was really interesting working that one out :) But don't rely on this, of course. It is a combination of several lucky circumstances. Add optimisation flags, and the compiler will change the stack layout, and the code will break. Call other functions between successive calls to Create() and the stack will change, and then you don't have the last link on the stack any longer. And the code will break. It is a very unstable situation if this works at all.
If you just want to add a new node to a list, make a prepend function. Something like
struct node *prepend(int val, struct node *list)
{
struct node *n = malloc(sizeof *n);
if (n) {
n->data = val;
n->next = list;
}
return n;
}
(I haven't tested it, so there might by syntax errors, but it will be something like that...you need to figure out what to do if malloc() fails, but you could just abort() if you don't want to deal with it).
There is nothing wrong with display(), except that I don't understand why it is in lower-case when the other functions are in camel-case. You don't need temp, you can use head in the while-loop, but that is a style choice. The function works as intended.
With MergeSort(), however, we have another problem. I am surprised that your compiler didn't scream warnings at you here. It should really give you an error, with the right flags, but at the very least an error. When you test if the list is empty or a singleton, you return, but not with a node. The function should return a struct node *, so just using return will not give you anything useful.
if((head==NULL) || (head->next)==NULL){
return;
}
If the base case of the recursion returns garbage, obviously the whole recursion tumbles. Otherwise, assuming that the FrontBackSplit() and SortedMerge() work, the function looks okay. You don't need the extra headref variable, it is just a synonym for head, but there is nothing wrong with having it. The compiler will get rid of it for you. There isn't any need to assign the merged lists to head and then return head either. You can just return SortedMerge(a,b). But again, your compiler will handle that for you, once you turn on optimisation. Except for the base case, I believe the function should work.
In FrontBackSplit(), I get the impression that you want to get the frontref and backref values back to the caller. Otherwise, the function doesn't do anything. But when you are modifying the function parameters, you are not changing the variables in the caller's scope. You need to pass the two pointers by reference, which means that you need to use pointers to pointers. Change it to something like this:
void FrontBackSplit(struct node *source,
struct node **frontref,
struct node **backref)
{
struct node *fast, *slow;
slow=source;
fast=source->next;
while(fast!=NULL) {
fast=fast->next;
if(fast!=NULL) {
slow=slow->next;
fast=fast->next;
}
}
*frontref=source;
*backref=slow->next;
slow->next=NULL;
}
When you call the function, use the addresses of the parameters for the second and third argument, so use FrontBackSplit(headref,&a,&b); instead of FrontBackSplit(headref,a,b);.
As far as I can see, SortedMerge() should work (with a modified FrontBackSplit()). It is recursive, but not tail-recursive, so you might have problems with overflowing the stack for long lists. It isn't hard to make iterative, though.
You should make main() either int main(void) or int main(int, char**). You should return 0 for success.
My guess is that one of three things are breaking your code. When you Create() your lists, you do not get the lists you want. In just the right circumstances, with just the right compiler and function call configurations, however, you might get lucky (and maybe that is what you have seen). In that case, it might be the return in MergeSort(). Return head instead, there, that is probably what you want. If you have an empty list or a list of length one, you should return that list. So change return; to return head;. And if it isn't that either, it is probably because you recurse on random data in MergeSort(), because a and b aren't initialised in the recursion. They are uninitialised when you call FrontBackSplit() and the call doesn't change them, because they are passed by value and not reference. The change I listed above will fix that.
There might be more that I have overlooked, but at least those three issues are enough to break the code, each of them on their own, so it is a good place to start with debugging.

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).

Double free error with doubly linked list

So I'm trying to do a method to clear a doubly linked list for school where the doubly linked list and nodes are defined as:
struct word_entry
{
char *unique_word ;
int word_count ;
} ;
struct node
{
struct word_entry one_word ;
struct node *p_previous ;
struct node *p_next ;
} ;
struct linked_list
{
struct node *p_head ;
struct node *p_tail ;
struct node *p_current ;
} ;
I have a method to clear a linked list by doing
int clear_linked_list( struct linked_list *p_list ) //return how many nodes were cleared
{
if (p_list->p_head == NULL) {
return 0;
}
else {
int count = 0;
struct node *curr = p_list->p_head;
while (curr != NULL) {
struct node *next = curr->p_next;
free(curr->one_word.unique_word);
free(curr);
curr = next;
count++;
}
return count;
}
}
I do a free() on curr->one_word.unique_word because it's a malloc'd char array. I was taught to free when I use malloc, so that's there.
The issue I run into is I get a "bogus pointer (double free?)" and a core dump when I run the test file provided by my professor. I've worked on this for a few hours and can't seem to find out where (or how) I'm calling free twice.
When you loop through the list, you should constantly change the position of the head, so that even if you repeat clear_linked_list, you will not get an error.
int clear_linked_list(struct linked_list* p_list) // return how many nodes were cleared
{
if (p_list->p_head == NULL) {
return 0;
} else {
int count = 0;
while (p_list->p_head != NULL) {
struct node* curr = p_list->p_head;
p_list->p_head = p_list->p_head->p_next;
free(curr->one_word.unique_word);
free(curr);
count++;
}
return count;
}
}
When freeing memory it is a good practice to set NULL to pointers that were freed to avoid this kind of problems.
So you should do:
free(curr->one_word.unique_word);
curr->one_word.unique_word=NULL;
//if that one_word.unique_word was shared between multiples nodes that free could cause problems if you dont set it to NULL afterwards
free(curr);
curr=NULL; //or curr=next...
Also. Check that when you create the nodes that:
*p_next is NULL on the last node of the double linked list
*p_previous is NULL on the first node of the list
You don't null out p_head before you leave the clear function.
So, if you called it twice, you'd have problems (i.e. p_head would point to an already freed node). Likewise for p_tail.
Also, if you tried to add to the list again, you'd have similar problems.
Otherwise, your clear code is just fine.
So, can you prove that the list is constructed correctly (e.g. before you free, add a printf that prints out all the node's pointers before you free anything).

How do I get rid of a NULL segmentation fault?

I am creating a linked list program in C and I keep on getting a segmentation fault. I've narrowed the problem down to a few lines of code and I believe it has to do with checking for NULL. How can I fix this? Here's the code:
typedef struct node
{
int contents;
struct node *nextNode;
} Node;
deleteNode(Node *currentNode)
{
while((currentNode->contents) != NULL)
{
//.....Do Stuff.....
currentNode = currentNode->nextNode;
}
}
Thanks
Try checking to make sure that currentNode isn't NULL at the start of deleteNode(). I.e.
deleteNode(Node *currentNode)
{
if (currentNode == NULL) return;
// ...
// ...
}
If the problem is as I suspect, currentNode is a null pointer. Just ensure that currentNode is not null before you attempt to access it.
deleteNode(Node* currentNode)
{
while ((currentNode != NULL) && (currentNode->contents != NULL))
{
/* ... */
currentNode = currentNode->nextNode;
}
}
Well, I'm suspicious that this line:
while((currentNode->contents) != NULL)
is comparing the contents field of your Node structure, which is an int, with NULL... I would guess that this was supposed to be checking currentNode->nextNodeinstead!
So, probably: none of your contents are zero, so this test is true for every item in the list. Then the last item has a NULL currentNode->nextNode, which is assigned to currentNode, and it blows up dereferencing it the next time round the loop.
what happens when currentNode is NULL?. It is dereferencing a NULL memory in the while condition.

Resources