Implementing LinkedList in C - c

I implemented a linked list for my school assignment but when I try to print out value of a node, the first node always get printed with memory address and I can't figure out why it's happening. 
I tried debugging and as I assign tail of list to the new node, the value of the node gets printed out as memory address.
Why is this happening?
int AppendLinkedList(LinkedListPtr list, int value) {
LinkedListNodePtr newNode = CreateLinkedListNode(value);
if (list->head == NULL) {
list->head = newNode;
list->tail = newNode;
return 0;
}
LinkedListNodePtr tailCopy = list->tail;
newNode->prev = tailCopy;
tailCopy->next = newNode;
list->tail = newNode;
return 0;
}
LinkedListNode *CreateLinkedListNode(int data) {
LinkedListNodePtr newNode;
newNode = (LinkedListNodePtr)malloc(sizeof(LinkedListNode));
newNode->data = data;
printf("%d\n", data);
return newNode;
}
int main() {
LinkedListPtr list = CreateLinkedList();
int data = 5;
AppendLinkedList(list, data);
}
typedef struct ll_node {
int data; // Data this node holds
struct ll_node *next; // next node in list, or NULL
struct ll_node *prev; // prev node in list, or NULL
} LinkedListNode, *LinkedListNodePtr;
typedef struct ll_head {
uint64_t num_elements; // # elements in the list
LinkedListNodePtr head; // head of linked list, or NULL if empty
LinkedListNodePtr tail; // tail of linked list, or NULL if empty
} *LinkedListPtr;
LinkedListPtr CreateLinkedList() {
LinkedListPtr list;
list = (LinkedListPtr)malloc(sizeof(LinkedListPtr));
if (list == NULL) {
return NULL;
}
return list;
}

There are multiple problems in your code:
you do not initialize the prev and next members to NULL in CreateLinkedListNode().
the allocation size is incorrect in CreateLinkedList(): you should use:
LinkedList *list = malloc(sizeof(*list));
and you should initialize the members num_elements to 0 and head and tail to NULL.
the order of definitions is inadequate and the header files are missing.
AppendLinkedList() does not update num_elements.
More generally, hiding pointers behind typedefs is error prone. The code is much more readable with the explicit pointer syntax.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
typedef struct ll_node {
int data; // Data this node holds
struct ll_node *next; // next node in list, or NULL
struct ll_node *prev; // prev node in list, or NULL
} LinkedListNode;
typedef struct ll_head {
uint64_t num_elements; // # elements in the list
LinkedListNode *head; // head of linked list, or NULL if empty
LinkedListNode *tail; // tail of linked list, or NULL if empty
} LinkedList;
LinkedList *CreateLinkedList() {
LinkedList *list = malloc(sizeof(*list));
if (list != NULL) {
list->num_elements = 0;
list->head = NULL;
list->tail = NULL;
}
return list;
}
LinkedListNode *CreateLinkedListNode(int data) {
LinkedListNode *newNode = malloc(sizeof(*newNode));
if (newNode != NULL) {
newNode->data = data;
newNode->prev = NULL;
newNode->next = NULL;
}
return newNode;
}
int AppendLinkedList(LinkedList *list, int value) {
if (list == NULL)
return -1;
LinkedListNode *newNode = CreateLinkedListNode(value);
if (newNode == NULL)
return -1;
if (list->head == NULL) {
list->head = newNode;
} else {
LinkedListNode *tail = list->tail;
newNode->prev = tail;
tail->next = newNode;
}
list->tail = newNode;
list->num_elements += 1;
return 0;
}
int main() {
LinkedList *list = CreateLinkedList();
int data = 5;
AppendLinkedList(list, data);
}

Related

linked list implemetation from scratch, segmentation fault

I want to implement linked list from scratch. I programmed it, but when I run it gives me a Segmentation fault in my node_adder(int data) function. I don't know what caused this.
struct linked_list
{
int value;
struct linked_list *next;
};
struct linked_list *head = NULL;
struct linked_list *tail = NULL;
void node_adder(int data)
{
struct linked_list *new = NULL;
new->value = data;
new->next = NULL;
if (head == NULL)
{
head = new;
tail = new;
printf("head added\n");
}
else
{
tail->next = new;
tail = new;
printf("tail added\n");
}
}
In node_adder(), you are not allocating any memory for the new node before accessing its members.
Try this instead:
struct linked_list
{
int value;
struct linked_list *next;
};
struct linked_list *head = NULL;
struct linked_list *tail = NULL;
void node_adder(int data)
{
struct linked_list *newNode;
// ADD THIS!!!
// in C:
newNode = malloc(sizeof(struct linked_list));
// in C++:
newNode = new linked_list;
//
newNode->value = data;
newNode->next = NULL;
if (head == NULL)
{
head = tail = newNode;
printf("head added\n");
}
else
{
tail->next = newNode;
tail = newNode;
printf("tail added\n");
}
}
This line initializes a pointer to a node to NULL:
struct linked_list *new = NULL;
Yet, no memory is allocated for this node. Therefore, in this line, attempting to assign a value to one of the members of the node leads to a segmentation fault:
new->value = data;
You probably meant to do this:
struct linked_list *new = malloc(sizeof(struct linked_list));
Of course, a corresponding free(..) should also be added when the allocated memory will no longer be used.
For starters it is a bad idea to declare global variables and define functions that depend on the global variables as you are doing
struct linked_list *head = NULL;
struct linked_list *tail = NULL;
because in this case you will not be able to define for example more than one list.
It is much better to introduce one more structure like for example
struct node
{
int value;
struct node *next;
};
struct linked_list
{
struct node *head;
struct node *tail;
};
As for your problem then you are using a null pointer to access memory that results in undefined behavior
void node_adder(int data)
{
struct linked_list *new = NULL;
new->value = data;
new->next = NULL;
//...
You need to allocate a node dynamically as for example
int node_adder(int data)
{
struct linked_list *new = malloc( sizeof( *new ) );
int success = new != NULL;
if ( success )
{
new->value = data;
new->next = NULL;
if (head == NULL)
{
head = new;
}
else
{
tail->next = new;
}
tail = new;
}
return success;
}
But using the approach I showed in the beginning of my answer You could write instead
struct node
{
int value;
struct node *next;
};
struct linked_list
{
struct node *head;
struct node *tail;
};
int node_adder( struct linked_list *list, int data )
{
struct node *new = malloc( sizeof( *new ) );
int success = new != NULL;
if ( success )
{
new->value = data;
new->next = NULL;
if (list->head == NULL)
{
list->head = new;
}
else
{
list->tail->next = new;
}
list->tail = new;
}
return success;
}
and in main you can write
int main( void )
{
struct linked_list list = { .head = NULL, .tail = NULL };
node_adder( &list, 10 );
//...
}

Segment Fault - Linked List in C

I am creating a basic linked list in C but I am getting a segment fault when my add to back function is called in my test file. It seems to have a problem because the head of the list is NULL, but I don't see why this is an issue. When I use the cgdb tool, it tells me the error is occurring on the line: prev->next = new_node. I have attached the full code below, please let me know what I am not seeing to fix this.
header file
#ifndef LINKED_LIST_H
#define LINKED_LIST_H
typedef struct Node {
int data;
struct Node *next;
} Node;
Node *create_node(int data);
void free_list(Node *head);
void add_to_front(struct Node **head, int data);
void print_list(struct Node *head);
void reverse_list(struct Node **head);
void add_to_back(Node **head, int data);
#endif // LINKED_LIST_H
.c file
#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"
/* returns a new node whose data is set to DATA and next is set to NULL */
Node *create_node(int data) {
struct Node *new_node = malloc(sizeof(struct Node));
if (new_node == NULL) {
perror("Malloc failed\n");
}
new_node->data = data;
new_node->next = NULL;
return new_node;
}
/* Frees the list starting at HEAD */
void free_list(Node *head) {
while (head != NULL) {
Node *temp = head->next;
free(head);
head = temp;
}
}
/* Creates a new node whose data is set to DATA and adds it to the front of the
list pointed to by HEAD.
*/
void add_to_front(struct Node **head, int data) {
/* Check if the head is NULL to make sure that we do not dereference a NULL pointer
because that would result in a segfault */
if (head == NULL) return;
struct Node *new_node = create_node(data);
if (*head != NULL) {
/* The list is not empty */
/* The new node's next should point to the head */
new_node->next = *head;
}
/* We must set HEAD using the following line in order to change the original list */
*head = new_node;
/* The following line would not work because it would only change our local copy of HEAD */
/* head = new_node */
}
/* Prints out a linked list starting at HEAD */
void print_list(struct Node *head) {
struct Node *curr;
for (curr = head; curr != NULL; curr = curr->next) {
printf("%d->", curr->data);
}
printf("NULL\n");
}
/* Iteratively reverses a linked list whose first node is HEAD */
void reverse_list(struct Node **head) {
if (head == NULL || *head == NULL) {
return;
}
struct Node *curr = *head;
struct Node *next = (*head)->next;
curr->next = NULL;
while (next != NULL) {
struct Node *temp = next->next;
next->next = curr;
curr = next;
next = temp;
}
*head = curr;
}
/* Creates a new node with a data field set to DATA and adds the node
to the back of the list pointed to by HEAD */
void add_to_back(Node **head, int data) {
if (head == NULL || *head == NULL) {
return;
}
Node *new_node = create_node(data);
Node *prev;
for (Node *curr = *head; curr != NULL; curr = curr->next) {
prev = curr;
}
prev->next = new_node;
}
test file
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"
int main(int argc, char **argv) {
printf("Running tests...\n\n");
Node *head = NULL;
/*********** reverse_list test ***********/
reverse_list(&head);
for (int i = 0; i < 5; ++i) {
add_to_front(&head, i);
reverse_list(&head);
}
int expected_values[] = {3, 1, 0, 2, 4};
Node *curr = head;
for (int i = 0; i < 5; ++i) {
assert(curr->data == expected_values[i]);
curr = curr->next;
}
free_list(head);
printf("Congrats! You have passed the reverse_list test!\n\n");
/************ add_to_back test ***********/
Node *head_2 = NULL;
add_to_back(&head_2, 15);
add_to_back(&head_2, 12);
add_to_back(&head_2, 18);
int expected_values_2[] = {15, 12, 18};
Node *curr_2 = head_2;
for (int i = 0; i < 3; ++i) {
assert(curr_2->data == expected_values_2[i]);
curr_2 = curr_2->next;
}
free_list(head_2);
printf("Congrats! All of the test cases passed!\n");
return 0;
}
The if statement in the function add_to_back
if (head == NULL || *head == NULL) {
return;
}
does not make a sense because it does not allow to append a node to an empty list.
The function can be defined for example like
void add_to_back( Node **head, int data )
{
if ( head == NULL ) return;
Node *new_node = create_node(data);
while ( *head ) head = &( *head )->next;
*head = new_node;
}
Or using your approach then
void add_to_back( Node **head, int data )
{
if ( head == NULL ) return;
Node *new_node = create_node(data);
Node *prev = NULL;
for ( Node *curr = *head; curr != NULL; curr = curr->next )
{
prev = curr;
}
prev == NULL ? ( *head = new_node ) : ( prev->next = new_node );
}
In general this statement
if ( head == NULL ) return;
is also redundant. If the user will pass a null pointer then the function just will have undefined behavior.
On the other hand the function create_node should be written the following way
Node * create_node( int data )
{
struct Node *new_node = malloc(sizeof(struct Node));
if ( new_node != NULL )
{
new_node->data = data;
new_node->next = NULL;
}
return new_node;
}
Correspondingly for example the function add_to_back can be written like
int add_to_back( Node **head, int data )
{
Node *new_node = create_node( data );
int success = new_node != NULL;
if ( success )
{
Node *prev = NULL;
for ( Node *curr = *head; curr != NULL; curr = curr->next )
{
prev = curr;
}
prev == NULL ? ( *head = new_node ) : ( prev->next = new_node );
}
return success;
}
The problem is in the add_to_back() function. Because of first line in that function if (head == NULL || *head == NULL) { return; }, it will keep returning and not executing rest of the code. So, if you print your list after three calls of the add_to_back function, your list has nothing but NULL and that is the reason you are getting a segmentation fault. I did the following change and your code is working fine
`
void add_to_back(Node **head, int data) {
Node *new_node = create_node(data);
if (*head == NULL){
*head = new_node;
return;
}
Node *prev;
for (Node *curr = *head; curr != NULL; curr = curr->next) {
prev = curr;
}
prev->next = new_node;
}
`

What is the problem with this piece of code?

I am writing for deleting the last node of a doubly linked list. But, every time this function is giving me segmentation fault when I have 2 or more than 2 elements in the list.
void deleteEnd()
{
struct node *ptr;
if(head==NULL)
printf("\nList is empty.First add some numbers");
else if(head->next==NULL)
{
head = NULL;
free(head);
}
else
{
ptr = head;
while(ptr->next != NULL)
{
ptr = ptr -> next;
}
ptr -> prev -> next = NULL;
free(ptr);
}
}
Normally, when you are deleting a node from a linked list it is a good practice to pass a reference to the first node of the list as an argument of the function. In your case you are not showing us where the head is coming from, and I think that it could be quite a useful info, and I bet that the error hides there.
That is how the implementation could look like:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
// insert end node: this is for testing purposes
struct node *insertEnd(struct node *head, int value) {
struct node *ptr, *new_node;
ptr = head;
new_node = (struct node *) malloc(sizeof(struct node));
new_node->data = value;
new_node->next = NULL;
// The list is empty
if (head == NULL) {
head = new_node;
return head;
}
// Non empty list
while (ptr->next != NULL) {
ptr = ptr->next;
}
ptr->next = new_node;
return head;
}
// delete end node
struct node *deleteEnd(struct node *head) {
struct node *ptr, *preptr;
ptr = head;
preptr = NULL;
// The list is empty
if (head == NULL) {
printf("The list is empty. Nothing to delete.\n");
return head;
}
while(ptr->next != NULL) {
preptr = ptr;
ptr= ptr->next;
}
free(ptr);
if (preptr == NULL) {
head = NULL;
}
else {
preptr->next = NULL;
}
return head;
}
int main(void) {
struct node *llist;
llist = NULL;
llist = insertEnd(llist, 10);
llist = insertEnd(llist, 20);
llist = insertEnd(llist, 30);
llist = deleteEnd(llist);
llist = deleteEnd(llist);
llist = deleteEnd(llist);
return 0;
}
It is always a great idea to maintain a global variable head and update it after every push/pop. See this:
struct node
{
int data;
struct node *next;
};
struct node *start = NULL;
struct node *deleteEnd(struct node *start)
{
struct node *ptr = start;
if(ptr==NULL)
{
printf("\nList is empty!!!");
return start;
}
else if(ptr->next == NULL)
{
free(ptr);
start = NULL;
return start;
}
else
{
while((ptr->next)->next!=NULL) //by doing this you dont have to maintain a prev pointer
{
ptr=ptr->next;
}
struct node *temp = ptr->next;
free(temp);
ptr->next = NULL;
return start;
}
}
Hope this helps!!!

linked list c programming error by inserting new element

I am trying to insert an element but it get the error "Process finished with exit code 11"
struct node {
int key;
struct node *next;
};
struct node* init(){
struct node *head =NULL;
return head;
}
void create(struct node * head,int num) {
struct node * tmp = head;
struct node * prev = NULL;
struct node* new = malloc(sizeof(struct node));
new->key = num;
prev = tmp;
tmp = tmp->next;
while(tmp!= NULL && tmp->key < num){
prev = tmp;
tmp = tmp->next;
}
new->next = tmp;
prev->next = new;
if (tmp== NULL)
head=tmp;
}
int main() {
int num;
struct node* head;
head=init()
printf("Enter data:");
scanf("%d",&num);
create(head,num);
}
i am trying to insert an element into a linked list and the element should be sorted and entered at the same time.can someone tell me that the error is ? i cannot seem to find out the error.
It's not clear what your function create()
void create(struct node * head, int num) {
struct node * tmp = head;
struct node * prev = NULL;
struct node* new = malloc(sizeof(struct node));
new->key = num;
prev = tmp;
tmp = tmp->next;
while (tmp != NULL && tmp->key < num) {
prev = tmp;
tmp = tmp->next;
}
new->next = tmp;
prev->next = new;
if (tmp == NULL)
head = tmp;
}
is supposed to do. You effectively pass it a NULL pointer and return void, so everything it does is meaningless to the outside world.
Thetm starting point for every no bs linked list implementation:
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct node_tag {
int value;
struct node_tag *next;
} node_t;
// write functions to encapsulate the data and provide a stable interface:
node_t* node_create_value(int value)
{
node_t *new_node = calloc(1, sizeof *new_node);
if(new_node) new_node->value = value;
return new_node;
}
node_t* node_advance(node_t const *node) { return node->next; }
typedef struct list_tag { // a list usually consists of
node_t *head; // a pointer to the first and
node_t *tail; // a pointer to the last element
// size_t size; // one might want to add that.
} list_t;
list_t list_create(void)
{
list_t list = { NULL, NULL };
return list;
}
// make code based on these functions "speak" for itself:
node_t* list_begin(list_t const *list) { return list->head; }
node_t* list_end (list_t const *list) { return list->tail; }
bool list_is_empty(list_t const *list) { return !list_begin(list); }
// common operations for lists:
node_t* list_push_front(list_t *list, int value)
{
node_t *new_node = node_create_value(value);
if (!new_node)
return NULL;
new_node->next = list->head;
return list->head = new_node;
}
node_t* list_push_back(list_t *list, int value)
{
// push_back on an empty list is push_front:
if (list_is_empty(list))
return list->tail = list_push_front(list, value);
node_t *new_node = node_create_value(value);
if (!new_node)
return NULL;
list->tail->next = new_node;
return list->tail = new_node;
}
node_t* list_insert_after(list_t *list, node_t *node, int value)
{
if (list_end(list) == node)
return list_push_back(list, value);
node_t *new_node = node_create_value(value);
if (!new_node)
return NULL;
new_node->next = node->next;
return node->next = new_node;
}
node_t* list_insert_sorted(list_t *list, int value)
{
// first handle the special cases that don't require iterating the whole list:
if (list_is_empty(list) || value < list_begin(list)->value)
return list_push_front(list, value);
if (value > list_end(list)->value)
return list_push_back(list, value);
// the general (worst) case:
for (node_t *current_node = list_begin(list); node_advance(current_node); current_node = node_advance(current_node))
if (value < node_advance(current_node)->value)
return list_insert_after(list, current_node, value);
return NULL; // should never happen
}
void list_print(list_t const *list)
{
for (node_t *current_node = list_begin(list); current_node; current_node = node_advance(current_node))
printf("%d\n", current_node->value);
}
void list_free(list_t *list)
{
for(node_t *current_node = list_begin(list), *next_node; current_node; current_node = next_node) {
next_node = current_node->next;
free(current_node);
}
}
// user code should not be required to know anything about the inner workings
// of our list:
int main(void)
{
list_t list = list_create();
for (int i = 1; i < 10; i += 2) {
if (!list_push_back(&list, i)) {
list_free(&list);
fputs("Not enough memory :(\n\n", stderr);
return EXIT_FAILURE;
}
}
list_print(&list);
putchar('\n');
for (int i = 0; i < 11; i += 2) {
if (!list_insert_sorted(&list, i)) {
list_free(&list);
fputs("Not enough memory :(\n\n", stderr);
return EXIT_FAILURE;
}
}
list_print(&list);
list_free(&list);
}
Output:
1
3
5
7
9
0
1
2
3
4
5
6
7
8
9
10

Doubly Linked list not working properly, C

#include <stdio.h>
#include <stdlib.h>
typedef struct list_item {
int value;
struct list_item *next;
struct list_item *prev;
} list_item_t;
typedef struct single_list {
list_item_t *head;
list_item_t *tail;
} slist_t;
void init(slist_t *list) {
list->head = NULL;
list->tail = NULL;
}
void add(slist_t *list, int value) {
list_item_t *newNode = (list_item_t *)malloc(sizeof(list_item_t));
// Case for empty list
if (list->head == NULL) {
list->head = newNode;
list->tail = newNode;
newNode->value = value;
newNode->prev = NULL;
newNode->next = NULL;
}
// Case for nonempty list
else {
newNode->prev = list->tail;
newNode->value = value;
newNode->next = NULL;
list->tail = newNode;
}
}
void print(slist_t *list) {
if (list->head == NULL) {
printf("The list is empty\n");
return;
}
list_item_t *currentNode = list->head;
while (currentNode != NULL) {
printf("%d ", currentNode->value);
currentNode = currentNode->next;
}
printf("\n");
}
int main() {
slist_t myList;
init(&myList);
add(&myList, 5);
add(&myList, 2);
add(&myList, 6);
print(&myList);
}
Ok I got rid of my bus error but now when I try to print my list all it prints out is:
1
Is the problem in init function or my add function? I was wondering if since I don't use malloc in the init function that the list gets erased after every function call of add? Is that true? I have tried allocating it like this:
slist_t *list = (slist_t *)malloc(sizeof(slist_t))
but it gives me an error.
Failing to link old tail's next to the new tail.
// Case for nonempty list
else {
// Add. `list->tail->next` should be NULL before this code.
list->tail->next = newNode;
newNode->prev = list->tail;
newNode->value = value;
newNode->next = NULL;
list->tail = newNode;
}

Resources