Segmentation Fault When Traversing Linked List - c

I am trying to implement a linked list in C. I believe I am creating and inserting elements correctly, but there is a segmentation fault every time I try to loop through. Here is my code for the linked list:
struct node {
char **data;
struct node *next;
};
Two global variables to store pointers to head and tail:
struct node *head;
struct node *tail;
Code to insert an element:
void insert(char **args)
{
struct node* pointer = (struct node*)malloc(sizeof(struct node));
pointer -> data = args;
pointer -> next = NULL;
if( head == NULL ) {
head = pointer;
tail = pointer;
}
else {
tail -> next = pointer;
tail = pointer;
}
}
I then try to go through the list and print the data contents (this successfully prints the elements in the list, but then there is a segmentation fault):
int print_list(char **args)
{
struct node *curPointer = head;
if(curPointer == NULL) {
printf("%s", "List is empty\n");
}
else {
printf("%s", "List: ");
do {
int i;
while(curPointer->data[i] != NULL) {
printf("%s", tail->data[i]);
i++;
}
printf("%s", "\n");
curPointer = curPointer->next;
}while(curPointer->next != NULL);
}
return 1;
}
Other functions in my program that rely on looping through the list have a similar segmentation fault issue.

The value of local variable i having automatic storage duration is used without initializing, so it will invoke undefined behavior. Initialize i by replacing int i; to int i = 0;
When curPointer becomes NULL in curPointer = curPointer->next;, dereferencing curPointer in the condition curPointer->next != NULL have a big chance to cause Segmentation Fault.
Try using curPointer != NULL instead of curPointer->next != NULL for the condition.

Related

Function returns the oldest value in linked list

This is a function (last) that returns the oldest value in linked list (the last node):
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
}Elem, *Pointer;
Pointer init() { return NULL; }
void last(Pointer l)
{
while (l != NULL)
{
l = l->next;
}
printf("%d",l->val);
}
int main(void) {
Pointer myl =
insert(3, insert(7, insert(5,
insert(11, insert(1, init ())))));
last(myl);
}
so the function (last) takes a pointer that points to a linked list, and in a while loop it moves the pointer to the last node and then prints its value.
Error is: exited, segmentation fault.
Since checking for NULL l is your exit condition from the loop, when you reach the end of the loop
while (l != NULL)
{
l = l->next;
}
printf("%d",l->val);
l is NULL (otherwise you would still be looping!). So in the following printf you are dereferencing a NULL pointer and this results in a segmentation fault.
You can modify your function in the following way:
void last(Pointer l)
{
if ( l != NULL )
{
while (l->next != NULL)
{
l = l->next;
}
printf("%d",l->val);
}
}
Just peek in the next field of the element, after making sure that the list is not empty (NULL list pointer).
Never hide pointers behind the typedefs. It makes programs hard to read and error prone.
typedef struct node {
int val;
struct node *next;
}Elem;
This is something absilutelly horrible - avoid
insert(3, insert(7, insert(5,
insert(11, insert(1, init ())))));
The function. Check if the next value is NULL. IMO better return pointer and then do something with it. Also Always check if parameter is valid.
Elem *last(Elem *first)
{
if(first)
{
while(first -> next != NULL)
{
first = -first -> next;
}
}
return first;
}
Print it
printf("%d\n", last(myl) -> val);

Segmentation fault while creating a linked list

I am writing a small program which stores data and key inside a linked list structure, and retrieves data based on a key from the user. The program also checks whether it is a unique key and if it so it stores the data by creating a node at the front of the list. But the below code throws segmentation fault all the time.
#include<stdlib.h>
/* Node having data, unique key, and next */.
struct node
{
int data;
int key;
struct node *next;
}*list='\0',*p;
/* Create a node at the front */
void storeData(int data_x,int key_x)
{
int check_key;
position *nn; //nn specifies newnode
nn=(position)malloc(sizeof(struct node));
/* Segmentation Fault occurs here */
if(list->next==NULL)
{
nn->next=list->next;
nn->data = data_x;
nn->key = key_x;
list->next = nn;
}
else
{
check_key=checkUniqueKey(key_x);
if(check_key != FALSE)
{
printf("The entered key is not unique");
}
else
{
nn->data = data_x;
nn->key = key_x;
nn->next=list->next;
list->next=nn;
}
}
}
/* Retreive data based on a key */
int retreiveData(int key_find)
{
int ret_data = NULL;
p=list->next;
while(p->next != NULL)
{
if(p->key == key_find)
{
ret_data = p->data;
break;
}
p=p->next;
}
return(ret_data);
}
/* Checks whether user key is unique */
int checkUniqueKey(int key_x)
{
int key_check = FALSE;
p=list->next;
while(p->next != NULL)
{
if(p->key == key_x)
{
key_check = TRUE;
break;
}
p=p->next;
}
return(key_check);
}
The segmentation fault occurs in the storeData function after the dynamic allocation.
There are some problems in your code:
your list handling is flawed: you always dereference the global pointer list, even before any list items are created. You should instead test if the list is empty by comparing list to NULL.
type position is not defined. Avoid hiding pointers behind typedefs, this is a great cause of confusion, which explains your mishandling of list pointers.
avoid defining a global variable with the name p, which is unneeded anyway. Define p as a local variable in the functions that use it.
NULL is the null pointer, 0 a zero integer value and \0 the null byte at the end of a C string. All 3 evaluate to 0 but are not always interchangeable.
For better portability and readability, use the appropriate one for each case.
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
/* Node having data, unique key, and next */.
struct node {
int data;
int key;
struct node *next;
} *list;
/* Create a node at the front */
void storeData(int data_x, int key_x) {
if (checkUniqueKey(key_x)) {
printf("The entered key is not unique\n");
} else {
/* add a new node to the list */
struct node *nn = malloc(sizeof(struct node));
if (nn == NULL) {
printf("Cannot allocate memory for node\n");
return;
}
nn->data = data_x;
nn->key = key_x;
nn->next = list;
list = nn;
}
}
/* Retrieve data based on a key */
int retrieveData(int key_find) {
struct node *p;
int ret_data = 0;
for (p = list; p != NULL; p = p->next) {
if (p->key == key_find) {
ret_data = p->data;
break;
}
}
return ret_data;
}
/* Checks whether user key is unique */
int checkUniqueKey(int key_x) {
struct node *p;
int key_check = FALSE;
for (p = list; p != NULL; p = p->next) {
if (p->key == key_x) {
key_check = TRUE;
break;
}
}
return key_check;
}
You try to cast your address on a position structure instead of a position*
nn=(position)malloc(sizeof(struct node));
Compile your code with gcc flags -Wextra and -Wall to prevent this kind of issue.
Moreover I don't know is it is a mistake but malloc a size of struct node and your nn variable is a pointer on position.
When you initialized your list pointer you set it to NULL(as '\0'), when the program accesses address 0x00 it goes out of its boundaries and the operating system kills the process.
To avoid the segfault you can have "list" of non pointer type thus allocating on stack, when you want to access list as pointer you can do &list. Another solution would involve having variable on stack "root_node" and initialize list pointer as list = &root_node.

Array of linked List not working properly in C

I'm trying to make an array of nodes,and enter values from S[] array to it. But I keep getting a segmentation fault.
My struct looks like this:
typedef struct Node {
int num;
struct Node *next;
}ListNode;
Initialized array of S[10] with random numbers:
printf("list is:");
for(i=0;i<10; i++)
{
RN= (random()+1);
S[i]=RN;
printf("%d ",S[i]);
}
printf("\n");
Here is how I initialized my array of nodes:
ListNode *bucket[Radix];
for(j=0; j<Radix; j++)
{
bucket[i]=(ListNode*)malloc(sizeof(ListNode));
bucket[i]->next=NULL;
}
And this is the function I use to read array numbers from S[] into the array of linked list, bucket[]:
for(y=0;y<(sizeof(S)/sizeof(int));y++) // S is size of a normal array
{
digit=bucketNumber(S[y],1);// returns the first digit values
pointer= bucket[digit];
number= S[y];
insert_tail(pointer, number);
}
my insert_tail function look like this:
ListNode *insert_tail(ListNode *tail, int data)
// insert and element at tail
{
if (tail==NULL)
{ tail=(ListNode *)malloc(sizeof(ListNode));}
else
{
while(tail->next !=NULL)
tail->next = (ListNode *)malloc(sizeof(ListNode));
tail= tail->next;
}
tail->num= data;
tail->next=NULL;
}
this is the bucketNumber function:
int bucketNumber(int num,int digit)
{
int x, y;
y= 10*digit;
x= num%y;
if(digit>=2)
{
num= num%y;
x= num/(y/10);
}
return (x);
}
I think the reason for segmentation fault is that my function is not creating the links in the array properly. I'm not sure thou, there could be something else wrong!
I think the problem is in this section of insert_tail():
else
{
while(tail->next !=NULL)
tail->next = (ListNode *)malloc(sizeof(ListNode));
tail= tail->next;
}
tail->num= data;
tail->next=NULL;
Since the while() loop doesn't have curly braces following it, the below line gets executed if and only if tail->next != NULL:
tail->next = (ListNode *)malloc(sizeof(ListNode));
...which is sort of the opposite of what you want; you want to allocate a new node for next if next is NULL. As is, next is likely NULL, and so tail gets moved forward to next, but next is not allocated--it's NULL. The bottom two lines above would each cause a segmentation fault in that case, since you can't dereference a NULL pointer, which is what -> is doing.

Linked list printing & adding elements

So the idea is I have a Doubly linked list defined as a struct
struct Node
{
struct Node *next;
struct Node *prev;
char value[5];
};
struct DoubleLinkedList
{
int size;
struct Node *head;
struct Node *tail;
};
and I'm inserting into the list using the InsertionSort function. I pass the pointer to my Doubly Linked list as a parameter to that and it gets modified with the addition of a new 4 character string node to the list(lexicographically sorted Linked list). I then print the linked list with the addition of each string node.
The printing is proving to be problematic. Right now, with the code below, the output is always something like (assume the strings being inserted at every step are aaaa,bbbb,cccc...)
aaaa
bbbb -> bbbb
cccc -> cccc -> cccc
For some reason the linked list structure is changing each and every node to the value of the new string to be inserted; I have no idea why! And also, if I try shifting the print block to the main function, it prints out gibberish.
int main()
{
struct DoubleLinkedList strings;
while (1)
{
sleep(1);
char s[5];
GenerateRandomString(s,4);
InsertionSort(&strings, s);
}
return 0;
}
void InsertionSort(struct DoubleLinkedList *sorted, char *randomstring)
{
struct Node new;
strcpy(new.value,randomstring);
printf("Newvalue %s\n", new.value);
if ((*sorted).size == 0)
{
new.next = NULL;
new.prev = NULL;
(*sorted).head = &(new);
(*sorted).tail = &(new);
}
else
{
printf("TEST %s\n", (*(*sorted).head).value);
struct Node *current;
current = (*sorted).head;
printf("CURRENT %s\n", (*current).value);
while (strcmp(randomstring,(*current).value) > 0)
{
current = (*current).next;
if (current = NULL)
{
break;
}
}
new.next = current;
if (current != NULL)
{
new.prev = (*current).prev;
if ((*current).prev != NULL)
{
(*(*current).prev).next = &(new);
}
else
{
(*sorted).head = &(new);
}
(*current).prev = &(new);
}
else
{
new.prev = (*sorted).tail;
(*((*sorted).tail)).next = &(new);
(*sorted).tail = &(new);
}
}
(*sorted).size++;
struct Node *printing;
printing = (*sorted).head;
int i;
for (i = 0; i < (*sorted).size - 1; i++)
{
printf("%s -> ", (*printing).value);
printing = (*printing).next;
}
printf("%s\n",(*printing).value);
}
You haven't allocated memory for the value in
strcpy(new.value,randomstring);
you're lucky your subsequent printf works.
You can do for example
new.value = strdup(randomstring);
(don't forget to release memory with free(new.value) when you delete your Node if you do so, because strdup calls malloc).
Er, you're not allocating memory for new either, so when you exit InsertionSort, the Node is dangling.
Should be in InsertionSort
new = (struct Node *)malloc(sizeof(struct Node));
then adjusting everything to use a pointer (that is new -> stuff instead of new.stuff and new instead of &new).
Also in main strings.size in uninitialized
strings.size = 0;
seems missing.
Last one, when you write
if (current = NULL)
I think you mean
if (current == NULL)
(in some C tradition, you'd write if (!current))
With these modifications, it seems to work.

C: pop function in double linked list

I am working with a double linked list and I have run into a problem with my pop() function.
//QueueElement describe the block in the cache
typedef struct _queue_ele_
{
char *content; //the data of the block
struct _queue_ele_ *prev;
struct _queue_ele_ *next;
}QueueElement;
typedef struct _queue_
{
int queue_len;
int max_queue_size;
QueueElement *head;
QueueElement *tail;
}MyQueue;
The pop function works until there is an input of 2 elements ( I clear the queue by poping one by one and freeing the memory)
pop:
// head is removed and returned
QueueElement* pop(MyQueue* myqueue)
{
// if empty
if(myqueue->queue_len == 0) return NULL;
QueueElement *p = myqueue->head;
// if one element
if(myqueue->queue_len == 1)
{
myqueue->queue_len--;
myqueue->head = NULL;
myqueue->tail = NULL;
return p;
}
else
{
myqueue->queue_len--;
//remove the head from the queue
myqueue->head = myqueue->head->prev;
myqueue->head->next = NULL; //******************Seg Fault here
p->prev = NULL;
return p;
}
}
The error I get when there are two elements is a segmentation fault in line shown, but it works for queues with more. Why wont it let me assign NULL to myqueue->head->next???
Change this:
myqueue->head = myqueue->head->prev;
myqueue->head->next = NULL; //******************Seg Fault here
To:
myqueue->head = myqueue->head->prev;
if (myqueue->head != NULL) {
myqueue->head->next = NULL;
}
It is likely that you are trying to dereference a NULL pointer. It also would appear that you may have a memory leak from not calling free on the nodes you are deleting, but it is possible you do that elsewhere in the code.

Resources