Doubly Linked list not working properly, C - 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;
}

Related

I cannot print delete_first result in C (circular linkedlist)

I want to print delete_first result and delete_last result. But it can only print delete_last code. How can i solve this matter?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int element;
typedef struct ListNode {
element data;
struct ListNode* link;
} ListNode;
void print_list(ListNode* head)
{
ListNode* p;
if (head == NULL) return;
else {
p = head->link;
do {
printf("%d ", p->data);
p = p->link;
} while (p != head->link);
}printf("\n");
}
ListNode* insert_first(ListNode* head, element data)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->data = data;
if (head == NULL) {
head = node;
node->link = head;
}
else {
node->link = head->link;
head->link = node;
}
return head;
}
ListNode* insert_last(ListNode* head, element data)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->data = data;
if (head == NULL) {
head = node;
node->link = head;
}
else {
node->link = head->link;
head->link = node;
head = node;
}
return head;
}
I want to print delete_first result and delete_last result. But I can only print delete_last result. How can i print delete_first result?
This is my delete_first code.
ListNode* delete_first(ListNode* head) {
if (head == NULL)
{
return head;
}
if (head->link == head) {
free(head);
head = NULL;
return head;
}
ListNode* p = head->link;
head->link = p->link;
free(head);
head = NULL;
return head;
}
ListNode* delete_last(ListNode* head) {
if (head == NULL)
return head;
ListNode* p = head->link;
if (head->link == head) {
free(head);
head = NULL;
return head;
}
while (p->link != head) {
p = p->link;
}
p->link = head->link;
free(head);
head = p;
return head;
}
int main() {
ListNode* head = NULL;
head = insert_first(head, 10);
head = insert_first(head, 20);
head = insert_first(head, 30);
head = insert_first(head, 40);
head = insert_last(head, 50);
print_list(head);
head=delete_last(head);
print_list(head);
head = delete_first(head);
print_list(head);
return 0;
}
If you want to print the element being removed, then you cannot free() it, or you have to copy it to a local variable and return it by value.
If you want caller to be able to print what remains of the list, then you need to find the last node which has a link that points at head and have it point at head->next instead. Then return that value (instead of NULL):
ListNode* delete_first(ListNode* head) {
if(!head)
return NULL;
if(head == head->link) {
free(head);
return NULL;
}
ListNode* last;
for(last = head; last->link != head; last = last->link);
last->link = head->link;
free(head);
return last->link;
}
There is no point of setting head = NULL as the copy of that variable is lost the caller anyways.

Implementing LinkedList in 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);
}

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!!!

Inserting a node in ascending order

I try to insert a node that contains a string to the linkedlist in ascending order. It works if the initial of first element is higher than other initials of strings. For example,
"Zeynep"
"Ceylan"
"Demir"
this way works fine.
However if the initial of first string is smaller than any initial of strings in the list, it prints nothing.
"Ali"
"Zeynep"
"Ceylan"
This corrupts.
I traced the code but couldnt find.
struct friendNode
{
char firstName[30];
char lastName[30];
char gender[1];
char birthYear[10];
struct friendNode *next;
};
struct friendRecord
{
struct friendNode *head;
struct friendNode *tail;
int size;
};
void insertFriend(struct friendNode *node, struct friendRecord *list)
{
struct friendNode *temp_node;
temp_node = list->head;
if(temp_node->next == NULL)
{
temp_node->next = node;
list->tail = node;
}
else
{
while(strcmp(node->firstName, temp_node->next->firstName) >= 0 )
temp_node = temp_node->next;
if(temp_node->next == NULL)
{
temp_node->next = node;
list->tail = node;
return;
}
node->next = temp_node->next;
temp_node->next = node;
}
}
Inserting into a linked list is pretty basic stuff. Here is one way to do it:
void insertFriend(struct friendNode *node, struct friendRecord *list)
{
struct friendNode *pre = NULL;
struct friendNode *post = list->head;
while (post && strcmp(node->firstName, post->firstName) >= 0)
{
pre = post;
post = post->next;
}
if (pre == NULL)
{
list->head = node;
}
else
{
pre->next = node;
}
node->next = post;
if (post == NULL)
{
list->tail = node;
}
}
void insertFriend(struct friendNode *node, struct friendRecord *list)
{
struct friendNode *temp_node;
temp_node = list->head;
if(strcmp(node->firstName, list->head->firstName) < 0)
{
node->next = list->head;
list->head = node;
}
if(temp_node->next == NULL)
{
temp_node->next = node;
list->tail = node;
}
else
{
while(strcmp(node->firstName, temp_node->next->firstName) >= 0 )
temp_node = temp_node->next;
if(temp_node->next == NULL)
{
temp_node->next = node;
list->tail = node;
return;
}
node->next = temp_node->next;
temp_node->next = node;
}
}
you forgot to write code to append the node at the head of list if it is going to be the first element. I have not tried because i dont have full code. try out. if still doesn't work, i request to comment.

Reversing a Doubly Linked List Issues

I am trying to reverse a Doubly Linked List with no success. After reversing, the list appears to be empty.
Here is my implementation:
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef struct Item Item;
typedef struct DLL DLL;
struct Item {
int value;
Item* next;
Item* prev;
};
struct DLL {
Item* head;
Item* tail;
int size;
void(*add)(DLL*, int);
void(*addToTail)(DLL*, int);
};
void add(DLL* list, int val) {
Item* new_item = (Item*) malloc(sizeof(Item));
if (new_item == NULL) {
exit(-1);
}
new_item->value = val;
new_item->next = list->head->next;
list->head->next = new_item;
new_item->prev = list->head;
list->size++;
}
void addToTail(DLL* list, int val) {
Item* new_item = (Item*) malloc(sizeof(Item));
if (new_item == NULL) {
exit(-1);
}
new_item->value = val;
new_item->prev = list->tail->prev;
list->tail->prev = new_item;
new_item->next = list->tail;
list->size++;
}
Item* find(DLL* list, int val) {
Item* iter = list->head->next;
while (iter != list->tail) {
if (iter->value == val) {
return iter;
}
iter = iter->next;
}
return NULL;
}
void reverse(DLL* list) {
Item* current = list->head;
Item* temp = NULL;
while (current != NULL) {
temp = current->next;
current->next = current->prev;
current->prev = temp;
current = current->prev;
}
temp = list->head;
list->head = list->tail;
list->tail = temp;
}
void printList(DLL* list) {
Item* iter = list->head->next;
while (iter != list->tail) {
printf("%d\n", iter->value);
iter = iter->next;
}
}
DLL* initDLL() {
DLL* list = (DLL*) malloc(sizeof(DLL));
if (list == NULL) {
exit(-1);
}
// Creating head & tail
list->head = (Item*) malloc(sizeof(Item));
list->tail = (Item*) malloc(sizeof(Item));
if (list->head == NULL || list->tail == NULL) {
free(list);
exit(-1);
}
// Initializing head & tail values just for testing
list->head->value = 100;
list->tail->value = 200;
list->head->prev = NULL;
list->head->next = list->tail;
list->tail->prev = list->head;
list->tail->next = NULL;
list->size = 0;
list->add = add;
list->addToTail = addToTail;
return list;
}
int main() {
DLL* my_list = initDLL();
my_list->add(my_list, 1);
my_list->add(my_list, 2);
my_list->add(my_list, 3);
printList(my_list);
// Outputs:
// 3
// 2
// 1
reverse(my_list);
printList(my_list);
// Prints nothing since list->head->next == list->tail
}
I expected
3
2
1
1
2
3
but get only
3
2
1
The first printList() works as expected, but the second produces no output.
Looking into the problem I've found that after reversing the list, for some reason list->head->next is pointing to list->tail, even though there are 3 elements in the list.
I've searched online for examples but stumbled upon implementations which don't use a DLL structure such as mine, but only Node structure.
In your add function, you need to set new_item->next->prev to new_item after setting new_item->next = list->head->next;
void add(DLL* list, int val) {
Item* new_item = malloc(sizeof *new_item);
if (new_item == NULL) {
exit(EXIT_FAILURE);
}
new_item->value = val;
new_item->next = list->head->next;
new_item->next->prev = new_item; // <--- This is missing in your code
list->head->next = new_item;
new_item->prev = list->head;
list->size++;
}
Similar issue is in your addToTail(). There you need to set new_item->prev->next to new_item.

Resources