Unable to remove lowest value from linked-list - c

I created a linked-list in C. I'm trying to create a function that looks at the lowest value in the linked list (which is the head) and the removes the "right-most" instance of that value in the list.
Suppose the linked-list looks like this:
2 -> 2 -> 2 -> 4 -> 5 -> 6
The head in this list is 2. But it's not the head I want to remove. I want to remove the 2 that comes before the 4 (it is the right-most instance of the head).
Here's the function I created to implement this:
double removeLowestValue() {
struct node *temp;
struct node *ptr = head;
double val = ptr->value;
if(head == tail)
{
free(head);
head = NULL;
tail = NULL;
}
else
{
while(ptr->value == ptr->next->value)
{
temp = ptr;
ptr = ptr->next;
val = ptr->value
}
temp->next = NULL;
temp->next = ptr->next;
free(ptr);
return val;
}
}
Then I tried to test if the function works:
int main() {
insertNode(18.0);
insertNode(13.0);
insertNode(11.0);
insertNode(11.0);
insertNode(22.0);
printf("%d", removeLowestValue());
return 0;
}
Unfortunately, the program doesn't print out "11" as expected. Matter of fact, it doesn't print anything at all. What's going on here?
EDIT:
Here's how I implemented the insertNode function:
void insertNode(double value) {
struct node *new_node = create_new_node(value);
struct node *temp = head;
struct node *prev;
if (head == NULL) {
head = new_node;
tail = new_node;
} else {
while (value > temp->value && temp->next != NULL) {
prev = temp;
temp = temp->next;
}
if(value < temp->value || value == temp->value)
{
/*If the value of the new node equals to the value of temp
OR if the value of the new node is less than the value of temp,
then insert the new node right before temp*/
new_node->next = temp;
prev->next = new_node;
}
else if(value > temp->value)
{
temp->next = new_node;
tail = new_node;
}
}
}

your function corrected, of course that supposes the list is sorted :
double removeLowestValue() {
if (head == NULL)
return 0; /* ???? */
else {
node * ptr = head;
node * previous = 0; /* the cell before the cell to remove */
while ((ptr->next != NULL) && (ptr->value == ptr->next->value)) {
previous = ptr;
ptr = ptr->next;
}
/* ptr is now the cell to remove */
double val = ptr->value;
if (ptr == head) {
/* remove the first cell */
ptr = head->next;
free(head);
head = ptr;
if (head == NULL)
/* the list is empty */
tail = NULL;
}
else if (ptr->next == NULL) {
/* all the values are the same in the list
ptr is the last cell */
free(ptr);
/* previous is now the last cell */
previous->next = NULL;
tail = previous;
}
else {
/* ptr is not the first nor the last cell */
previous->next = ptr->next;
free(ptr);
}
return val;
}
}
Concerning insertNode :
it is better to move the declaration of the variables temp and prev where they are useful, they are useless if head null so at the top of the definition
(value < temp->value || value == temp->value) can be just (value <= temp->value) and the else if (...) after can be just an else
when (value <= temp->value) prev can be still unset but used for prev->next = new_node, that appends when you insert 13 after 18 in your main. When (temp == head) you have to update head setting it with new_node
So the corrected version can be :
void insertNode(double value) {
struct node *new_node = create_new_node(value);
if (head == NULL) {
head = new_node;
tail = new_node;
} else {
struct node *temp = head;
struct node *prev = 0; /* = 0 to be sure to have a crash if something wrong */
while ((value > temp->value) && (temp->next != NULL)) {
prev = temp;
temp = temp->next;
}
if (value <= temp->value)
{
/* insert the new node right before temp*/
new_node->next = temp;
if (temp == head)
head = new_node;
else
/* prev was set */
prev->next = new_node;
} else {
/* insert the new node at end */
temp->next = new_node;
tail = new_node;
}
}
}
Using the additional definitions
typedef struct node {
double value;
struct node * next;
} node;
node * create_new_node(double value)
{
node * r = (node *) malloc(sizeof(node));
r->value = value;
r->next = 0;
return r;
}
int main() {
insertNode(18.0);
insertNode(13.0);
insertNode(11.0);
insertNode(11.0);
insertNode(22.0);
printf("%g\n", removeLowestValue());
printf("%g\n", removeLowestValue());
printf("%g\n", removeLowestValue());
printf("%g\n", removeLowestValue());
printf("%g\n", removeLowestValue());
printf("%g\n", removeLowestValue());
return 0;
}
the execution writes (the last 0 indicate the list is empty)
11
11
13
18
22
0

Related

Inserting elements in a linked list in various indices using one function only

This is the code I tried writing down to add an element in a double linked list, that takes an index and a value and adds a new element to the original list.
It is taking index and value but just adds the elements I give like a stack.
node *add(node *head, int index, int val)
{
node *new = create(val);
node *temp = malloc(sizeof(node));
if (head == NULL)
{
head = new;
temp = head;
//printf(": %d",temp->data);
}
temp = head;
int i = 1;
while (i < (index - 1) && (temp->next != NULL))
{
i++;
temp = temp->next;
}
temp->next = new;
new->next = NULL;
new->prev = temp;
return head;
}
however this code(for a doubly linked list) just adds elements one after the other, disregarding the index passed.
My prof gave us a code for a singly linked list where he did something similar.
struct Node *insert(struct Node *listp, int pos, int info)
{
/*Inserts a Node in list at position pos with data info
pos>0. If pos>list length then new node added at end.
If pos<1 adds at beginning.
*/
struct Node *new=malloc(sizeof(struct Node)), *prev;// new is the new node we create everytime.
//create new node and initialize fields
new->data=info;
new->next=NULL;
if (listp==NULL) listp=new;
else
if (pos<=1) { //negative or 1 index.
new->next=listp; //first node bann gaya new
listp=new; //head is pointing at new
}
else {
//pos>1. Go to node at pos-1.
prev=listp;
int i=1;
while ((i++<pos-1) && prev->next!=NULL) { //indexing
prev=prev->next;
}
new->next=prev->next;
prev->next=new;
}
return listp;
}
how do I address this problem?
To implement a doubly linked list, your node needs to have pointers to the previous node and next node, then you can write something almost as similar to what your professor gave you for single linked list:-
#include <stdlib.h>
#include <stdio.h>
//Doubly linked list Node
typedef struct Node{
int info;
struct Node* next;
struct Node* prev;
} Node;
Node* insert(Node* listp, int pos, int info){
//Allocate memory for node and its previous neighbor
Node* new = malloc(sizeof(Node));
Node* prev = malloc(sizeof(Node)), *tail;
//initialize new node with these values
new->info = info;
new->next = NULL;
new->prev = NULL;
//if head doesn't exist then create one
if(listp == NULL){
/*
listp gets whatever new had, ie
listp->info = info
listp->next = NULL
listp->prev = NULL
*/
Node* tail = malloc(sizeof(Node));
tail->info = 0;
tail->next = NULL;
tail->prev = NULL;
listp = new;
listp->next = tail;
tail->prev = listp;
}
//Lets Loop through the List and insert node at pos
else {
if(pos <= 1){
/*
This should replace the current head
listp = new
*/
new->next = listp;
new->prev = listp->prev;
listp->prev = new;
listp = new;
}
else{
int i = 2;
prev = listp->next;
printf("%d\n", prev->prev->info);
while(i != pos){
printf("%d\n", new->info);
prev = prev->next;
i++;
}
new->next = prev;
new->prev = prev->prev;
prev->prev->next = new;
prev->prev = new;
}
}
return listp;
}
// Test case
int main(){
Node* listp;
listp = insert(NULL, 0, 2);
listp = insert(listp, 1, 3);
listp = insert(listp, 2, 5);
Node* cnt = listp;
printf("|");
while(cnt->next != NULL){
printf("--%d-->", cnt->info);
cnt = cnt->next;
}
printf("\n");
}
Try that. Make any typo corrections if any
#include <stdio.h>
#include <stdlib.h>
/**
* add_node_end - adds a new node at the end of a dllist list
* #head: head of linked list
* #n: integer value of node
*
* Return: address of new element, NULL if fails
*/
node *add_node_end(node **head, const int n)
{
node *new, *temp;
new = malloc(sizeof(node));
if (new == NULL)
return (NULL);
new->n = n;
new->next = NULL;
if (*head == NULL)
{
new->prev = NULL;
*head = new;
return (*head);
}
temp = *head;
while (temp->next)
{
temp = temp->next;
}
temp->next = new;
new->prev = temp;
return (new);
}
/**
* add_dnodeint - adds a new node at the beginning of a dlistint_t list
* #head: head of linked list
* #n: integer value of node
*
* Return: address of new element, NULL if fails
*/
node *add_node_start(node **head, const int n)
{
node *new;
new = malloc(sizeof(node));
if (new == NULL)
return (NULL);
new->n = n;
new->prev = NULL;
if (*head == NULL)
{
new->next = NULL;
*head = new;
return (*head);
}
new->next = *head;
(*head)->prev = new;
*head = new;
return (*head);
}
/**
* node_len - returns the number of elements in a dllist list
* #h: head of doubly linked list
*
* Return: number of nodes
*/
size_t node_len(const node *h)
{
int count = 0;
while (h)
{
count++;
h = h->next;
}
return (count);
}
/**
* insert_dnodeint_at_index - inserts a new node at a given position
* #h: a pointer to a pointer of the first node of node linked list
* #index: the position to add the new node
* #val: the data n of the new node
* Return: if the function fails = NULL
* otherwise - the address of the new node/element
*/
node *insert_dnodeint_at_index(node **h, unsigned int index, int val)
{
node *newNode, *current;
size_t list_length;
unsigned int i = 0;
if (h == NULL)
return (NULL);
if (index == 0)
return (add_node_start(h, n));
list_length = node_len(*h);
if (index == (list_length - 1))
return (add_node_end(h, n));
newNode = malloc(sizeof(node));
if (newNode == NULL)
return (NULL);
newNode->val = val;
if (*h == NULL)
{
newNode->prev = NULL;
newNode->next = NULL;
return (newNode);
}
current = *h;
while (current)
{
if (i == index)
{
newNode->next = current;
newNode->prev = current->prev;
current->prev->next = newNode;
current->prev = newNode;
return (newNode);
}
current = current->next;
i++;
}
free(newNode);
return (NULL);
}

Circular linked list crashes when displayed

I'm trying to make a circular linked list. When I try to display the list after creating it, the program keeps on crashing. Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node * next;
} node;
node * createList(int);
void display(node * head);
int main() {
struct node * head;
head = createList(5);
display(head);
}
node * createList(int n) {
int i = 0,data = 0;
struct node * head = NULL;
struct node * temp = NULL;
struct node * p = NULL;
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
temp->next = head;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = temp;
}
}
return head;
}
void display(node * head) {
struct node * temp = head->next;
while (temp != head) {
printf("%d-> \t",temp->data);
temp = temp->next;
}
printf("\n");
}
What am I doing wrong?
You have set every temp's next to head in temp->next = head; but did it too early (the first is just NULL). Then you tested p->next against NULL in while (p->next != NULL) { but you should have tested against head. Alternatively, you can continue to test against NULL but then you need to initialize temp->next to NULL and assign head to temp->next only after the for loop.
Your display code started from the second link.
Here is a fixed code using the first option in 1. above:
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != head) {
p = p->next;
}
p->next = temp;
}
temp->next = head;
}
Here is a fixed code using the alternative option in 1. above. You still need to initialize temp->next to NULL since malloc() does not initialize.
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
temp->next = NULL;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = temp;
}
}
if (temp != NULL) {
temp->next = head;
}
But in reality, there is no need to "walk" from the head on every creation. You can simply keep the previous and link it to the next:
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
if (head == NULL) {
head = p = temp;
} else {
p = p->next = temp;
}
}
if (temp != NULL) {
temp->next = head;
}
Here is a fix for the display():
void display(node * head) {
struct node * temp = head;
if (temp != NULL) {
do {
printf("%d-> \t",temp->data);
temp = temp->next;
} while (temp != head);
}
printf("\n");
}
The problem is on the first node you initialize:
struct node *head = NULL;
...
for (i = 0; i < n; i++) {
...
temp->next = head;
So tmp->next == NULL on the first iteration leaving head->next == NULL. That will not work for a circular list. When you attempt to insert the 2nd node:
p = head;
while (p->next != NULL) {
What was head->next again?? (oh, NULL) Dereferencing a NULL pointer (BOOM Segfault!)
Do your circular list correctly. On insertion of the first node set:
if (head == NULL) {
head = temp;
head->next = temp; /* you must set head->next to temp */
} ...
So on the insertion of the remaining nodes you simply need:
} else {
p = head;
while (p->next != head) { /* iterate to last node */
p = p->next;
}
p->next = temp; /* now set p->next = temp */
}
Now, you handle your display() function the same way, e.g.
void display (node *head)
{
if (!head) { /* validate list not empty */
puts ("(list-empty)");
return;
}
struct node *temp = head;
do { /* same loop problem fixed in display() */
printf ("%d-> \t", temp->data);
temp = temp->next;
} while (temp != head);
putchar ('\n');
}
If you make the changes, then you can test your list with:
int main (void) {
struct node *head, *tmp;
head = createList(5);
display (head);
puts ("\niterate from mid-list");
tmp = head;
tmp = tmp->next;
tmp = tmp->next;
display (tmp);
}
Example Use/Output
$ ./bin/lls_circular_fix
0-> 1-> 2-> 3-> 4->
iterate from mid-list
2-> 3-> 4-> 0-> 1->
Lastly, you are not multiplying the type node by head in struct node * head = NULL; Write it as struct node *head = NULL; (the same for all your function declarations as well) Much more readable.
When you go to delete a note from the list, you must create a special case for both head and tail (the last node). In this sense, the singly-linked list takes a bit more effort than a doubly-linked list due to not having a prev node pointer to track the prior node.
Look things over and let me know if you have questions.
A full example would be:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node;
node *createList (int);
void display (node *head);
int main (void) {
struct node *head, *tmp;
head = createList(5);
display (head);
puts ("\niterate from mid-list");
tmp = head;
tmp = tmp->next;
tmp = tmp->next;
display (tmp);
}
node *createList (int n)
{
int i = 0,data = 0;
struct node *head = NULL;
struct node *temp = NULL;
struct node *p = NULL;
for (i = 0; i < n; i++) {
if (!(temp = malloc (sizeof *temp))) {
perror ("malloc-temp");
return NULL;
}
temp->data = data++;
temp->next = head; /* head is NULL on 1st node insertion */
if (head == NULL) {
head = temp;
head->next = temp; /* you must set head->next to temp */
} else {
p = head;
while (p->next != head) { /* iterate to last node */
p = p->next;
}
p->next = temp; /* now set p->next = temp */
}
}
return head;
}
void display (node *head)
{
if (!head) { /* validate list not empty */
puts ("(list-empty)");
return;
}
struct node *temp = head;
do { /* same loop problem fixed in display() */
printf ("%d-> \t", temp->data);
temp = temp->next;
} while (temp != head);
putchar ('\n');
}

Linked List, delete tail function

I am trying to build a head delete and tail delete function for Linked Lists.
I have succeeded in head delete, but my tail delete function does not actually delete the tail.
First, how my Linked List is created:
typedef struct node
{
int data;
struct node *next;
} node;
typedef struct LinkedList
{
node *head;
node *tail;
} LinkedList;
node *createNode(int data)
{
node *new_node;
if ((new_node = malloc(sizeof(node))) == NULL)
return NULL;
new_node->data = data;
new_node->next = NULL;
return new_node;
}
LinkedList *createLinkedList(void)
{
LinkedList *LL;
if ((LL = calloc(1, sizeof(LinkedList))) == NULL)
return NULL;
return LL;
}
void tailInsert(LinkedList *LL, int data)
{
if (LL == NULL)
return;
if (LL->tail == NULL)
{
LL->head = LL->tail = createNode(data);
return;
}
LL->tail->next = createNode(data);
LL->tail = LL->tail->next;
}
These are the two functions:
This one does not work:
int tail_Delete(LinkedList *list)
{
int retval;
node *temp;
if (list == NULL || list->head == NULL)
return EMPTY_LIST_ERR;
// if only one node
if (list->head->next == NULL)
{
retval = list->head->data;
free(list->head);
list->head = NULL;
list->tail = NULL;
return retval;
}
// make temp the node before the tail
for (temp = list->head; temp->next != list->tail; temp = temp->next)
;
retval = list->tail->data;
free(list->tail);
list->tail = temp;
return retval;
}
This one does work:
int head_delete(LinkedList *list)
{
int retval;
node *temp;
if (list == NULL || list->head == NULL)
return EMPTY_LIST_ERR;
retval = list->head->data;
temp = list->head->next;
free (list->head);
list->head = temp;
if (list->head == NULL)
list->tail = NULL;
return retval;
}
Print function and main:
void print_Linked_list(LinkedList *LL)
{
node *temp;
if (LL == NULL || LL->head == NULL)
return;
for (temp = LL->head; temp != NULL; temp = temp->next)
printf("%d%c", temp->data, (temp->next == NULL) ? '\n' : ' ');
}
int main(void)
{
LinkedList *LL;
int val;
LL = createLinkedList();
tailInsert(LL, 1);
tailInsert(LL, 2);
tailInsert(LL, 3);
print_Linked_list(LL);
val = tail_Delete(LL);
//val = head_delete(LL);
printf("%d\n", val);
print_Linked_list(LL);
return 0;
}
Output for head_delete:
1 2 3
Deleted node: 1
2 3
Output for tail_delete:
1 2 3
Deleted node: 3
1 2 3
It may be a simple mistake, but they seem to be practically equivalent functions.
Thank you for your help.
A tail delete needs to be managed from the node before the tail. If you don't have a back pointer in the list (doubly linked), then you'll need to walk forward to the tail.
Untested, tail delete (with no back pointer) should look like this.
LinkedList *node = list->head;
LinkedList *next = node->next;
while(next != list->tail) { // walk to the end
node = next;
next = node->next;
}
// now node is the node before the tail and next is the tail
int retval = next->data;
free(next);
// this is why we needed to walk here
node->next = NULL;
You should assign 0 to temp->next pointer when for loop was executed. By this you indicate that this element is last one.
for (temp = list->head; temp->next != list->tail; temp = temp->next)
;
temp->next = 0; // <---
retval = list->tail->data;

linked list garbage value c

I'm trying to do some programming puzzles to learn C and I'm having trouble with getting a linked list deletion to work when deleting the head node. I think the problem is super simple but I can't find it!! The problem I'm having is with the delete() function, when I try to remove the head of a linked list it doesn't remove it, but instead changes it to a garbage value.
Can anyone help me out please? Thank you so much!
Here's example output:
Generating list...
Inserted: 0
Inserted: 1
Inserted: 2
Inserted: 3
Inserted: 4
List:
0 1 2 3 4
Deleted: 4
List:
0 1 2 3
Deleted: 0
List:
8344720 1 2 3
Here is my source code:
#include <stdlib.h>
#include <stdio.h>
typedef struct Node {
int value;
struct Node* next;
} node;
// Append a node to the end of the linked list
int insert(node* head, int value) {
node* current = head;
/* Check for sentinel value. If first element inserted, overwrite head instead of appending. */
if (head->value == 420) {
head->value = value;
head->next = NULL;
printf("\tInserted:\t%d\n", head->value);
return 0;
}
/* Traverse to end to append node */
while (current->next != NULL)
current = current->next;
/* Build new node and append to tail*/
current->next = malloc(sizeof(node));
current->next->value = value;
current->next->next = NULL;
printf("\tInserted:\t%d\n", current->next->value);
return 0;
}
/* Accept a number and delete all nodes containing that value */
int del(node* head, int value){
node* curr = head;
node* prev = NULL;
node* del = NULL;
printf("\tDeleted:\t%d\n", value);
if (head == NULL) {
printf("Can't delete value from empty list!\n");
return 1;
}
/* Search list remove all instances of value. Watch for edge cases. */
while (curr != NULL) {
if (curr->value == value){
/* Head case (lol) */
if (curr == head) {
del = head;
head = head->next;
curr = head;
free(del);
}
/* Tail case */
else if (curr->next == NULL) {
del = curr;
curr = prev;
curr->next = NULL;
free(del);
return 0; /* End of list, break out of loop to avoid segfaulting */
}
/* Body case (base case) */
else {
del = curr;
curr = curr->next;
prev->next = curr;
free(del);
}
}
prev = curr;
curr = curr->next;
}
return 0;
}
/* Accept head pointer and print until end of list */
int traverse(node* head) {
node* current = head;
if (head == NULL){
printf("Can't traverse null list!\n");
return 1;
}
printf("List:\n");
while(current != NULL) {
printf(" %d ", current->value);
current = current->next;
}
printf("\n");
return 0;
}
/* Let's begin our crazy experiment.... */
int main() {
node* head = NULL;
head = malloc(sizeof(node));
head->value = 420;
head->next = NULL;
printf("Generating list...\n");
int value;
for (value = 0; value < 5; value++)
insert(head, value);
traverse(head);
del(head, 4);
traverse(head);
del(head, 0);
traverse(head);
return 0;
}
You are modifying the head inside the del() function and using the old head from the main(). You need to pass the address of the head to del and modify it so that the change will reflect in main. You may need something like this.
int del(node **head, int value){
node* curr = *head;
....
And from the main
del(&head);

C double linked list insertion sort memory fault

I wanted to implement insertion sort on dl_list containing char* values but I got a segmentation fault after running program (no warnings, I use gcc).
This is my structure:
struct node;
typedef struct node {
char *name;
char *surname;
char *birth_date;
char *email;
char *phone;
char *address;
struct node *next;
struct node *prev;
} node;
//doubly linked_list
typedef struct dl_list {
node *head;
node *tail;
} dl_list;
I sort it by surname, later name. When values are same it return 0, if alpha should be before beta it return -1, otherwise 1:
int compare(node *alpha, node *beta) {
int a_surn_len = strlen(alpha->surname);
int b_surn_len = strlen(beta->surname);
for (int i = 0; i < ((a_surn_len > b_surn_len) ? b_surn_len : a_surn_len); i += 1) {
if (alpha->surname[i] > beta->surname[i]) return 1;
if (alpha->surname[i] < beta->surname[i]) return -1;
//if (alpha->surname[i] == beta->surname[i]) continue;
}
if (a_surn_len != b_surn_len) return a_surn_len > b_surn_len ? 1 : -1;
int a_n_len = strlen(alpha->name);
int b_n_len = strlen(beta->name);
for (int j = 0; j < ((a_n_len > b_n_len) ? b_n_len : a_n_len); j += 1) {
if (alpha->name[j] > beta->name[j]) return 1;
if (alpha->name[j] < beta->name[j]) return -1;
//if (alpha->surname[i] == beta->surname[i]) continue;
}
if (a_n_len != b_n_len) return a_n_len > b_n_len ? 1 : -1;
return 0;
}
And here insertion algorithm on my list:
dl_list *list_sort(dl_list *list) {
// zero or one element in list
if (list->head == NULL || list->tail == NULL)
return list;
// new_head is the first element of resulting sorted list
node *new_head = NULL;
while (list->head != NULL) {
node *current = list->head;
list->head = list->head->next;
// insert the first element into an empty sorted list
if (new_head == NULL) {
current->next = new_head;
new_head = current;
new_head->prev = NULL;
// or as the head of the sorted list
} else
if (compare(current, new_head) == -1) {
current->next = new_head;
new_head->prev = current;
new_head = current;
new_head->prev = NULL;
} else {
// insert current element into proper position in non-empty sorted list
node *ptr = new_head;
while (ptr != NULL) {
// middle of the list
if (compare(current, ptr->next) == -1) {
current->next = ptr->next;
ptr->next->prev = current;
ptr->next = current;
current->prev = ptr;
break; //done
// last element of the sorted list
} else
if (ptr->next == NULL) {
current->next = ptr->next;
ptr->next = current;
current->prev = ptr;
break;//done
}
ptr = ptr->next;
}
}
}
list->head = new_head;
node *ptr2;
for (ptr2 = list->head; ptr2->next != NULL; ptr2 = ptr2->next);
list->tail = ptr2;
return list;
}
I tried to check this code on paper and it seems to work fine, on some 4-5 elements lists.
The problem is in the insertion loop: you must check if ptr->next is not NULL before comparing current with node ptr->next:
// insert current element into proper position in non-empty sorted list
node *ptr = new_head;
while (ptr != NULL) {
if (ptr->next == NULL) {
current->next = ptr->next;
ptr->next = current;
current->prev = ptr;
break;
} else
if (compare(current, ptr->next) < 0) {
current->next = ptr->next;
ptr->next->prev = current;
ptr->next = current;
current->prev = ptr;
break;
}
ptr = ptr->next;
}
You could also simplify the comparison function with strcmp():
int compare(const node *alpha, const node *beta) {
int res;
if ((res = strcmp(alpha->surname, beta->surname)) != 0)
return res;
if ((res = strcmp(alpha->name, beta->name)) != 0)
return res;
return 0;
}
And you should just compare the return value with 0 instead of explicitly with -1 or 1.
Here is a simplified version:
dl_list *list_sort(dl_list *list) {
// zero or one element in list
if (list->head == NULL || list->tail == NULL)
return list;
// new_head is the first element of resulting sorted list
node *new_head = NULL;
while (list->head != NULL) {
node *current = list->head;
list->head = list->head->next;
if (new_head == NULL) {
// insert the first element into an empty sorted list
current->prev = current->next = NULL;
new_head = current;
} else
if (compare(current, new_head) < 0) {
// or as the head of the sorted list
current->next = new_head;
current->prev = NULL;
new_head->prev = current;
new_head = current;
} else {
// insert current element into proper position in non-empty sorted list
node *ptr = new_head;
while (ptr != NULL) {
if (ptr->next == NULL) {
current->next = NULL;
ptr->next = current;
current->prev = ptr;
break;
} else
if (compare(current, ptr->next) < 0) {
current->next = ptr->next;
ptr->next->prev = current;
ptr->next = current;
current->prev = ptr;
break;
}
ptr = ptr->next;
}
}
}
list->head = new_head;
node *ptr2;
for (ptr2 = list->head; ptr2->next != NULL; ptr2 = ptr2->next)
continue;
list->tail = ptr2;
return list;
}
Your code is quite long and it will be hard to debug without a minimal example. Maybe , you can compile with the -g flag and use valgrind. That tool will give you the line of the memory fault :)
Just use: valgrind --track-origins=yes ./executable
Your problem is that your insertion loop doesn't really make sense:
node *new_head=NULL;
while(list->head != NULL){
node *current=list->head;
list->head=list->head->next;
// insert the first element into an empty sorted list
if(new_head == NULL){
current->next=new_head;
new_head=current;
new_head->prev=NULL;
1) You set new_head to be a pointer to NULL
2) You take keep a reference of head in current and make head=head->next
3) On your first loop new_head is still NULL, so you enter the if statement and set current->next=new_head. But new_head points to NULL, so this causes problems!
4) Now when you set new_head=current, current/new_head's next pointer points to NULL.
5) Finally you set new_head->prev to NULL, meaning that now current/new_head point to NULL in both directions, but your loop is waiting for list->head to be NULL! This never happens, so once you've done an iteration and try to move forward you end up in your else block
} else{
// insert current element into proper position in non-empty sorted list
node *ptr=new_head;
while(ptr != NULL){
// middle of the list
if(compare(current, ptr->next) == -1){
current->next=ptr->next;
ptr->next->prev=current;
ptr->next=current;
current->prev=ptr;
break; //done
// last element of the sorted list
} else if(ptr->next == NULL ){
current->next=ptr->next;
ptr->next=current;
current->prev=ptr;
break;//done
}
ptr=ptr->next;
}
}
6) This block tries to compare current to new_head->next. But new_head->next is NULL!

Resources