Linked List not accepting values - c

I need to make a calendar planner with a linked list in C. Im inserting a couple of Elements, and I want to insert them in a sorted order. If I try to print the List, It doesn't show any output for the description of the appointment.
Code:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <stdbool.h>
// Appointment
typedef struct
{
time_t start;
char *description;
} Appointment;
// List element
typedef struct Element
{
Appointment *appointment;
struct Element *next;
} Element;
// List of appointments
typedef struct
{
Element *head, *tail;
} List;
void printAppointment(Appointment *appointment)
{
/*
Print the Appointment structure
*/
char *description = appointment->description;
time_t startTime = appointment->start;
printf("Appointment(%s, %ld)\n", description, startTime);
}
Appointment createAppointment(char *description, time_t start)
{
Appointment appointment = {0};
appointment.description = description;
appointment.start = start;
return appointment;
}
List createList()
/*
Create a linked list with a head and a tail element
*/
{
Element *head;
Element *tail;
head = malloc(sizeof(Element));
tail = malloc(sizeof(Element));
head->next = tail;
List *list;
list = malloc(sizeof(List));
list->head = head;
list->tail = tail;
return *list;
}
void clearList(List list)
/*
Free the list from all memory allocated, but keep the head and the tail
*/
{
Element *temp;
// Free elements as long as the head is not pointing to the tail
while (list.head->next != list.tail)
{
// Extract the element after the head into temp, point head at the element after
temp = list.head->next;
list.head->next = temp->next;
// Free the exctracted element
free(temp);
}
}
void debugList(List list)
/*
Print the list to the console
*/
{
struct Element *current = list.head->next;
while (current->appointment != NULL)
{
printf("%s ", current->appointment->description);
current = current->next;
}
printf("\n");
}
void insertElement(List list, char *description, time_t start)
/*
Insert a new element into the list based on its value
*/
{
printf("Inserting element %s with start time %ld\n", description, start);
Element *new_element = malloc(sizeof(struct Element));
Appointment new_appointment = createAppointment(description, start);
new_element->appointment = &new_appointment;
new_element->next = NULL;
if (list.head->next == list.tail)
{
// List is empty, insert new element after the head
printf("Head is pointing to tail, inserting %s in the middle\n", description);
new_element->next = list.tail;
list.head->next = new_element;
return;
}
else
{
// Find the correct position for the new node in the list
struct Element *current = list.head->next;
struct Element *prev = list.head;
int index = 0;
while (1)
{
// If the new value is bigger than the current value, insert it before the current element
if (current->appointment->start >= start)
{
printf("Inserting element %s at position %d\n", description, index);
prev->next = new_element;
new_element->next = current;
return;
}
// Iterate forwards
prev = current;
current = current->next;
index++;
// If the new element is bigger than all elements, insert it at the end
if (current == list.tail)
{
prev->next = new_element;
new_element->next = list.tail;
return;
}
}
}
}
Element *findElement(List list, char *description)
{
/*
Find a element in the list based on its value. Returns nullptr if the element is not found.
*/
Element *current = list.head->next;
while (current->next != list.tail)
{
Appointment currentAppointment = *current->appointment;
printf("Appointment(%s, %ld)\n", currentAppointment.description, currentAppointment.start);
return NULL;
}
printf("Returning NULL, no element found!");
return NULL;
}
_Bool deleteElement(List list, char *description)
{
/*
Find a element in the list based on its value and delete it. Returns true if the element has been deleted.
*/
Element *current = list.head->next;
Element *prev = list.head;
while (current->next != list.tail)
{
char *currentDescription = current->appointment->description;
if (*currentDescription == *description)
{
prev->next = current->next;
free(current);
return true;
}
prev = current;
current = current->next;
}
return false;
}
int main()
{
// Create the list
List list = createList();
// Insert some nodes
insertElement(list, "test1", time(NULL) - 1000);
insertElement(list, "test3", time(NULL) - 3000);
insertElement(list, "test2", time(NULL) - 2000);
insertElement(list, "test4", time(NULL) - 4000);
insertElement(list, "test8", time(NULL) - 8000);
// Print the list
debugList(list);
return 0;
// Search the element with value 3
Element *el = malloc(sizeof(Element));
el = findElement(list, "test3");
//printAppointment(el->appointment);
//printAppointment(el->next->appointment);
// Delete the element with value 3
deleteElement(list, "test3");
debugList(list);
// clear the list
clearList(list);
// print the list again;
debugList(list);
return 0;
}
I can't change any of the structs since those are a given requirement. Im fairly new to C so I dont really know why this is happening and I have absolutely no Idea on how to fix this.
The program has been compiled with gcc -g -Wall -pedantic-errors main.c

You should pass a pointer to a list when you insert elements. Right now you're passing a copy, to which you add an element, but this is not applied to your variable but to a copy of your variable. Change your function signature to:
void insertElement(List* list, char *description, time_t start)
and change all code inside the function accordingly to deal with a pointer instead of a value. Your main will look like this:
int main()
{
// Create the list
List list = createList();
// Insert some nodes
insertElement(&list, "test1", time(NULL) - 1000);
insertElement(&list, "test3", time(NULL) - 3000);
insertElement(&list, "test2", time(NULL) - 2000);
insertElement(&list, "test4", time(NULL) - 4000);
insertElement(&list, "test8", time(NULL) - 8000);
// Print the list
debugList(list);
return 0;
}
and the insertElement function:
void insertElement(List* list, char *description, time_t start)
/*
Insert a new element into the list based on its value
*/
{
printf("Inserting element %s with start time %ld\n", description, start);
Element *new_element = malloc(sizeof(struct Element));
Appointment new_appointment = createAppointment(description, start);
new_element->appointment = &new_appointment;
new_element->next = NULL;
if (list->head->next == list->tail)
{
// List is empty, insert new element after the head
printf("Head is pointing to tail, inserting %s in the middle\n", description);
new_element->next = list->tail;
list->head->next = new_element;
return;
}
else
{
// Find the correct position for the new node in the list
struct Element *current = list->head->next;
struct Element *prev = list->head;
int index = 0;
while (1)
{
// If the new value is bigger than the current value, insert it before the current element
if (current->appointment->start >= start)
{
printf("Inserting element %s at position %d\n", description, index);
prev->next = new_element;
new_element->next = current;
return;
}
// Iterate forwards
prev = current;
current = current->next;
index++;
// If the new element is bigger than all elements, insert it at the end
if (current == list->tail)
{
prev->next = new_element;
new_element->next = list->tail;
return;
}
}
}
}
PS There are more functions in your code where you should pass a pointer to a list instead of a copy.
Not recommended but for completion:
Another solution is to return your list everytime you insert an element, but this will be slower and you have to reassign your list everytime you insert a new element, so NOT recommended but here is the function signature anyway:
List insertElement(List list, char *description, time_t start)

Related

Removing unique elements in a doubly linked list in C

I need a little help removing unique characters in a doubly linked list in C. So here's the logic I tried implementing: I counted the occurrence of each character in the doubly linked list. If it's occurrence is 1 time, then it is unique element and needs to be deleted. I'll be repeating the process for all elements. But my code in remove_unique_dll() function isn't working properly, please help me fix it. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
int len;
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
newNode->data = data;
if (head == NULL)
{ //If dll is empty
head = tail = newNode; //Both head and tail will point to newNode
head->prev = NULL; //head's previous will point to NULL
tail->next = NULL; //tail's next will point to NULL, as it is the last node of the list
}
else
{
tail->next = newNode; //newNode will be added after tail such that tail's next points to newNode
newNode->prev = tail; //newNode's previous will point to tail
tail = newNode; //newNode will become new tail
tail->next = NULL; //As it is last node, tail's next will point to NULL
}
}
void remove_unique_dll()
{
struct node *current = head;
struct node *next;
struct node *prev;
int cnt;
while (current != NULL)
{
next = current->next;
cnt = 1;
//printf("!%c ",next->data);
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if (cnt == 1)
{
prev = current->prev;
//printf("#%c %d",prev->data,cnt);
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
if (next == NULL)
{
tail = prev;
}
else
{
next->prev = prev;
}
}
current = current->next;
//printf("#%c ",current->data);
}
head = current;
}
void display()
{
struct node *current = head; //head the global one
while (current != NULL)
{
printf("%c<->", current->data); //Prints each node by incrementing pointer.
current = current->next;
}
printf("NULL\n");
}
int main()
{
char s[100];
int i;
printf("Enter string: ");
scanf("%s", s);
len = strlen(s);
for (i = 0; i < len; i++)
{
addNode(s[i]);
}
printf("Doubly linked list: \n");
display();
remove_unique_dll();
printf("Doubly linked list after removing unique elements: \n");
display();
return 0;
}
The output is like this-
If you uncomment the printf() statements inside remove_unique_dll() you'll notice that no code below inner while loop is being executed after inner while loop ends. What's the issue here and what's the solution?
Sample input- aacb
Expected output- a<->a<->NULL
Some issues:
You shouldn't assign head = current at the end, because by then current is NULL
The next you use in the deletion part is not the successor of current, so this will make wrong links
As you progress through the list, every value is going to be regarded as unique at some point: when it is the last occurrence, you'll not find a duplicate anymore, as your logic only looks ahead, not backwards.
When you remove a node, you should free its memory.
Not a big issue, but there is no reason to really count the number of duplicates. Once you find the first duplicate, there is no reason to look for another.
You should really isolate the different steps of the algorithm in separate functions, so you can debug and test each of those features separately and also better understand your code.
Also, to check for duplicates, you might want to use the following fact: if the first occurrence of a value in a list is the same node as the last occurrence of that value, then you know it is unique. As your list is doubly linked, you can use a backwards traversal to find the last occurrence (and a forward traversal to find the first occurrence).
Here is some suggested code:
struct node* findFirstNode(char data) {
struct node *current = head;
while (current != NULL && current->data != data) {
current = current->next;
}
return current;
}
struct node* findLastNode(char data) {
struct node *current = tail;
while (current != NULL && current->data != data) {
current = current->prev;
}
return current;
}
void removeNode(struct node *current) {
if (current->prev == NULL) {
head = current->next;
} else {
current->prev->next = current->next;
}
if (current->next == NULL) {
tail = current->prev;
} else {
current->next->prev = current->prev;
}
free(current);
}
void remove_unique_dll() {
struct node *current = head;
struct node *next;
while (current != NULL)
{
next = current->next;
if (findFirstNode(current->data) == findLastNode(current->data)) {
removeNode(current);
}
current = next;
}
}
You have at least three errors.
After counting the number of occurrences of an item, you use next in several places. However, next has been used to iterate through the list. It was moved to the end and is now a null pointer. You can either reset it with next = current->next; or you can change the places that use next to current->next.
At the end of remove_unique_dll, you have head=current;. There is no reason to update head at this point. Whenever the first node was removed from the list, earlier code in remove_unique_dll updated head. So it is already updated. Delete the line head=current;.
That will leave code that deletes all but one occurrence of each item. However, based on your sample output, you want to leave multiple occurrences of items for which there are multiple occurrences. For that, you need to rethink your logic in remove_unique_dll about deciding which nodes to delete. When it sees the first a, it scans the remainder of the list and sees the second, so it does not delete the first a. When it sees the second a, it scans the remainder of the list and does not see a duplicate, so it deletes the second a. You need to change that.
Let's consider your code step by step.
It seems you think that in this declaration
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
the both pointers head and tail are explicitly initialized by NULL. Actually only the pointer tail is explicitly initialized by NULL. The pointer head is initialized implicitly as a null pointer only due to placing the declaration in file scope. It to place such a declaration in a block scope then the pointer head will be uninitialized.
Instead you should write
struct node *head = NULL, *tail = NULL; //Represent the head and tail of the doubly linked list
Also it is a very bad approach when the functions depend on these global variables. In this case you will be unable to have more than one list in a program.
Also the declaration of the variable len that is used only in main as a global variable
int len;
also a bad idea. And moreover this declaration is redundant.
You need to define one more structure that will contain pointers head and tail as data members as for example
struct list
{
struct node *head;
struct node *tail;
};
The function addNode can invoke undefined behavior when a new node can not be allocated
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
//...
You should check whether a node is allocated successfully and only in this case change its data members. And you should report the caller whether a node is created or not.
So the function should return an integer that will report an success or failure.
In the function remove_unique_dll after this while loop
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if cnt is equal to 1
if (cnt == 1)
//..
then the pointer next is equal to NULL. And using the pointer next after that like
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
is wrong.
Also you need to check whether there is a preceding node with the same value as the value of the current node. Otherwise you can remove a node that is not a unique because after it there are no nodes with the same value.
And this statement
head = current;
does not make sense because after the outer while loop
while (current != NULL)
the pointer current is equal to NULL.
Pay attention that the function will be more useful for users if it will return the number of removed unique elements.
Here is a demonstration program that shows how the list and the function remove_unique_dll can be defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct list
{
struct node *head;
struct node *tail;
};
int addNode( struct list *list, char data )
{
struct node *node = malloc( sizeof( *node ) );
int success = node != NULL;
if (success)
{
node->data = data;
node->next = NULL;
node->prev = list->tail;
if (list->head == NULL)
{
list->head = node;
}
else
{
list->tail->next = node;
}
list->tail = node;
}
return success;
}
size_t remove_unique_dll( struct list *list )
{
size_t removed = 0;
for ( struct node *current = list->head; current != NULL; )
{
struct node *prev = current->prev;
while (prev != NULL && prev->data != current->data)
{
prev = prev->prev;
}
if (prev == NULL)
{
// there is no preceding node with the same value
// so the current node is possibly unique
struct node *next = current->next;
while (next != NULL && next->data != current->data)
{
next = next->next;
}
if (next == NULL)
{
// the current node is indeed unique
struct node *to_delete = current;
if (current->prev != NULL)
{
current->prev->next = current->next;
}
else
{
list->head = current->next;
}
if (current->next != NULL)
{
current->next->prev = current->prev;
}
else
{
list->tail = current->prev;
}
current = current->next;
free( to_delete );
++removed;
}
else
{
current = current->next;
}
}
else
{
current = current->next;
}
}
return removed;
}
void display( const struct list *list )
{
for (const node *current = list->head; current != NULL; current = current->next)
{
printf( "%c<->", current->data );
}
puts( "null" );
}
int main()
{
struct list list = { .head = NULL, .tail = NULL };
const char *s = "aabc";
for (const char *p = s; *p != '\0'; ++p)
{
addNode( &list, *p );
}
printf( "Doubly linked list:\n" );
display( &list );
size_t removed = remove_unique_dll( &list );
printf( "There are removed %zu unique value(s) in the list.\n", removed );
printf( "Doubly linked list after removing unique elements:\n" );
display( &list );
}
The program output is
Doubly linked list:
a<->a<->b<->c<->null
There are removed 2 unique value(s) in the list.
Doubly linked list after removing unique elements:
a<->a<->null
You will need at least to write one more function that will free all the allocated memory when the list will not be required any more.

Add names into a Multi-linked list

I am creating a multi-linked list of first name, last name, and phone number. I have an add function that allocates memory for the list but I don't know how to add into this list that will link first and last name in alphabetical order. How do I add to a multi-linked list? Is it much different from adding into a single linked list?
structures:
typedef struct node {
char *first;
char *last;
long number;
struct node *nextFirst;
struct node *nextLast;
} Node;
typedef struct mlist {
Node *headFirstName;
Node *headLastName;
} MultiLinkedList;
add function:
MultiLinkedList *add(MultiLinkedList *list, char *first, char *last, long num) {
// allocate a new node
Node *newNode = malloc ( sizeof(Node) );
newNode->first = malloc ( strlen(first) + 1 );
strcpy(newNode->first, first);
newNode->last = malloc ( strlen(last) + 1 );
strcpy(newNode->last, last);
newNode->number = num;
// add this new node at the head of the "byFirst" list
newNode->nextFirst = list->headFirstName;
list->headFirstName = newNode;
// add this new node at the head of the "byLast" list
newNode->nextLast = list->headLastName;
list->headLastName = newNode;
// return the multi-list object with updated head pointers
return list;
}
Edit: Here I have added in an updated code of my add function that I modified with adding to a list that I have used for a single linked list
MultiLinkedList *add(MultiLinkedList *list, char *first, char *last, long num) {
Node *tempf = list->headFirstName;
Node *templ = list->headLastName;
while (tempf && templ) {
if (strcasecmp(tempf->first, first) == 0 && strcasecmp(templ->last, last) == 0) {
printf("Error - name %s %s already exists\n", first, last);
return list;
}
tempf = tempf->nextFirst;
templ = templ->nextLast;
}
// allocate a new node
Node *newNode = malloc ( sizeof(Node) );
newNode->first = malloc ( strlen(first) + 1 );
strcpy(newNode->first, first);
newNode->last = malloc ( strlen(last) + 1 );
strcpy(newNode->last, last);
newNode->number = num;
newNode->nextFirst = NULL;
newNode->nextLast = NULL;
if(list == NULL)
return newNode;
if(strcasecmp(first, list->headFirstName->first) < 0){
newNode->nextFirst = list->headFirstName;
return newNode;
}
Node *prevf = list->headFirstName;
Node *currf = list->headFirstName->nextFirst;
while(currf && strcasecmp(currf->first, first) < 0){
prevf = currf;
currf = currf->nextFirst;
}
prevf->nextFirst = newNode;
newNode->nextFirst = currf;
if (list == NULL)
return newNode;
if (strcasecmp(last, list->headLastName->last) < 0) {
newNode->nextLast = list->headLastName;
return newNode;
}
Node *prevl = list->headLastName;
Node *currl = list->headLastName->nextLast;
while (currl && strcasecmp(currl->last, last) < 0) {
prevl = currl;
currl = currl->nextLast;
}
prevl->nextLast = newNode;
newNode->nextLast = currl;
// add this new node at the head of the "byFirst" list
newNode->nextFirst = list->headFirstName;
list->headFirstName = newNode;
//list->headFirstName = addToFirstNameList(list->headFirstName, newNode);
// add this new node at the head of the "byLast" list
newNode->nextLast = list->headLastName;
list->headLastName = newNode;
//list->headLastName = addToLastNameList(list->headLastName, newNode);
// return the multi-list object with updated head pointers
return list;
}
I'm not going to write out the entire code for this, but here's the algorithm you want to use:
For the last names list, every time you insert, iterate through the list until you reach a last name that comes after the name you're trying to insert. Insert your current last name before this one. If you don't find one, insert it at the end.
Do the same for the first names list.

ANSI C S-Linked List - deleteLast() not functioning correctly

When trying to run my deleteLast() function twice (to get an empty list) on a linked list with two nodes, I am running into a problem. The code compiles and runs, but when I call traverse() on my empty linked list, I get an infinite while loop, and I cannot determine why.
Oddly enough, if I call deleteFirst() twice instead of deleteLast(), the program runs and terminates properly.
Below is the code for my methods:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
struct NODE
{
struct NODE *link;
int value;
};
typedef struct NODE Node;
/* Deletes the first item in the list and returns next item */
Node *deleteFirst(Node **ptrToHeadPtr)
{
Node *current;
// If list is empty do nothing
if (*ptrToHeadPtr == NULL)
return NULL;
else
{
current = *ptrToHeadPtr;
*ptrToHeadPtr = current->link;
free(current);
}
return *ptrToHeadPtr;
}
/* Inserts a new Node to the end of the list and returns it */
Node *insertLast(Node **ptrToHeadPtr, int val)
{
Node *current, *lastNode;
lastNode = (Node *)malloc( sizeof (Node) );
// Check if malloc was successful
if(!lastNode) return NULL;
lastNode->value = val;
lastNode->link = NULL;
if (*ptrToHeadPtr == NULL)
*ptrToHeadPtr = lastNode;
else
{
current = *ptrToHeadPtr;
// Walk to the end of the list
while(current->link != NULL)
current = current->link;
// Insert new item at the end of the list
current->link = lastNode;
}
return lastNode;
}
/* Deletes the last Node in the list and returns*/
Node *deleteLast(Node **ptrToHeadPtr)
{
Node *current, *previous;
/* If list is empty do nothing */
if (*ptrToHeadPtr == NULL)
return NULL;
current = *ptrToHeadPtr;
previous = NULL;
/* If list has one item delete it and return NULL */
if (current->link == NULL)
{
*ptrToHeadPtr == NULL;
free(current);
return NULL;
}
else
{
/* Walk to the end of the list */
while (current->link != NULL)
{
previous = current;
current = current->link;
}
previous->link = NULL;
free(current);
return previous;
}
}
/* Traverses the list, printing the value of each Node */
void traverse(Node*p)
{
while( p!= NULL )
{
printf("%d ",p->value);
p=p -> link;
}
}
/* Walks through the linked list, freeing memory of each Node */
void freeList(Node *p)
{
Node *temp;
while( p != NULL )
{
temp = p;
p = p-> link;
free(temp);
}
}
int main()
{
Node *headPtr = NULL;
insertLast( &headPtr, 33 );
insertLast( &headPtr, 35 );
traverse(headPtr);
printf("\n");
deleteFirst ( &headPtr );
traverse(headPtr);
printf("\n");
deleteLast ( &headPtr );
traverse(headPtr);
freeList(headPtr);
return 1;
}
In your deleteLast() function (They're called functions in C, just so you know, not methods. Not trying to sound snarky.)
/* If list has one item delete it and return NULL */
if (current->link == NULL)
{
*ptrToHeadPtr == NULL; // CHANGE THIS TO =, NOT ==
free(current);
return NULL;
}
edit: Just like the above poster suggested, you should definitely compile with -Wall (the W is case sensitive, must be capitalized.) It would have caught this.

Doubly Linked List insertion before given element

I am trying to learn how to correctly work with pointers in C. Currently, I am trying to create function that would insert new node before the one, which value is given. My function looks like this:
struct list *listAddBefore(struct list *element, int insertWhat, int insertBefore)
{
element = listToFirst(element);
while (element -> next)
{
if (element -> value == insertBefore)
{
struct list *temp = listCreateElement(insertWhat, element->prev, element);
element -> prev -> next = temp;
element -> prev = temp;
return temp;
}
element = element -> next;
}
return NULL;
}
struct list *listToFirst(struct list *element)
{
while (element -> prev)
element = element -> prev;
return element;
}
struct list *listCreateElement(int value, struct list *prev, struct list *next)
{
struct list *element = (struct list *) malloc(sizeof(struct list));
element -> value = value;
element -> prev = prev;
element -> next = next;
return element;
}
What is the problem? Compiler gives me segmentation error.
Your code has one important problem
while (element->next)
should be
while (element)
since for the first element element->next = NULL and hence your function will return NULL immediately. Then you will pass again the head element and repeat that behavior on every call to this function.
Here
element->prev->next = temp;
you will dereference element->prev which must be NULL for the first node, you must check if it is valid or not, otherwise you will cause a segmentation fault. This is the correct way to link the nodes though.
I fixed your code to help you learn how to work with linked lists
struct list *listToFirst(struct list *element)
{
if (element == NULL) /* check before dereferencing */
return NULL;
while (element->previous != NULL)
element = element->previous;
return element;
}
struct list *listCreateElement(int value, struct list *prev, struct list *next)
{
struct list *element = (struct list *)malloc(sizeof(struct list));
if (element == NULL) /* check the return value of malloc before dereference */
return NULL;
element->value = value;
element->previous = prev;
element->next = next;
/*
* here we test if there is a previous node, if there is one
* we relink the node to point to element as it's next node.
*/
if (prev != NULL)
prev->next = element;
return element;
}
struct list *listAddBefore(struct list *element, int insertWhat, int insertBefore)
{
element = listToFirst(element);
while (element != NULL) /* here is the most important fix */
{
if (element->value == insertBefore)
return listCreateElement(insertWhat, element->previous, element);
/*
* Since the listCreateElement function takes care of linking the nodes
* this is all we have to do here.
*
* note: Doing the linking in the listCreateElement, makes it more clear.
*/
element = element->next;
}
return NULL;
}
/* you should also add a free function, since you allocated the structs using malloc */
void freeList(struct list *list)
{
struct list *current;
current = list;
while (current != NULL)
{
struct list *next;
next = current->next;
free(current);
current = next;
}
}
int main(int argc, char **argv)
{
struct list *element;
element = listCreateElement(0, NULL, NULL);
element = listAddBefore(element, 1, 0);
element = listAddBefore(element, 2, 1);
element = listAddBefore(element, 3, 2);
/* do something with the list */
/* free the allocated memory */
freeList(element);
return 0;
}

How to Delete the last element in a linked list in C?

I don't know how to delete the first and last element in a linked list in c. Below is my program, that uses a linked list. I have no idea how to actually delete the last element but I am able to find it. the element consists of an integer and the next pointer. if someone could please help me, it would be much appreciated.
struct ListNode{
int value;
struct ListNode *next;
};
typedef struct ListNode Link;
void deleteLast(Link *);
void printList(Link *);
void deleteFirst(Link *);
int main(){
Link *myList;
Link *curr, *newlink;
int i;
curr = myList;
for(i = 0; i < 10; i++){
newlink = (Link*) malloc(1*sizeof(Link));
newlink->value = i*i;
curr->next = newlink;
curr = newlink;
}
curr->next = NULL;
curr = myList->next;
deleteFirst(curr);
printList(curr);
printf("\n");
}
void deleteLast(Link *head)
{
Link *curr;
curr = head->next;
while (curr->next!=NULL)
{
curr = curr->next;
}
free(curr->next);
curr->next = NULL;
}
void printList(Link *head){
Link *curr;
curr = head->next;
printf("[");
if(curr!=NULL){
printf("%d",curr->value);
curr = curr->next;
}
while(curr != NULL){
printf(", %d", curr->value);
curr = curr->next;
}
printf("]\n");
}
void deleteFirst(Link *head){
Link *curr;
curr = head->next;
free(curr->value);
free(curr->next);
printf("%d\t",curr->value);
}
Nothing I try works, please can you help me.
You have many errors in your code.
When you create your list:
You don't have to cast the return value of malloc
You are doing curr->next = newlink; where curr = myList with initialized value. You can change your loop to
Link *myList = NULL;
Link *curr, *newlink;
int i;
curr = myList;
for(i = 0; i < 10; i++){
newlink = malloc(1*sizeof(Link));
newlink->value = i*i;
if (curr != NULL)
curr->next = newlink;
else
myList = newlink;
curr = newlink;
}
When you remove the last element you are going to far, that's why it's not working
Link *curr;
curr = head->next;
while (curr->next != NULL) {
head = curr;
curr = curr->next;
}
free(head->next);
head->next = NULL;
When you want to remove the first element of your list
You don't have to free the field value since you have not allocated it with malloc
Even if you remove the first element of your list, you are not changing the value of the begining of your list in the main. It's why you must take as a param a Link**
void deleteFirst(Link **head){
Link *curr;
curr = (*head)->next;
free(*head);
*head = curr;
}
And you can call this function from the main by giving the address of the beginning of your list:
deleteFirst(&myList);
deleteLast(myList);
printList(myList);
of course in all your functions you must check if you have at least some values in the list and not an empty pointer NULL
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct node Node;
struct node{
int element;
Node *next;
};
Node* head = NULL;
bool put(int data)
{
bool retVal = false;
Node* temp;
do
{
if (head == NULL)
{
head = malloc(sizeof(Node));
if (head)
{
printf("New head created\n");
head->element = data;
head->next = NULL;
printf("Element %d stored\n", data);
retVal = true;
break;
}
else
{
printf("Could not create new head\n");
break;
}
}
temp = head;
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = malloc(sizeof(Node));
temp->next->element = data;
temp->next->next = NULL;
printf("Element %d stored\n", data);
retVal = true;
break;
} while(1);
return retVal;
}
bool get(int *pData)
{
bool retVal = false;
Node* temp;
if (head != NULL)
{
retVal = true;
Node *prevNode = head;
temp = prevNode;
while (temp->next)
{
prevNode = temp;
temp = temp->next;
}
*pData = temp->element;
printf("Element %d retrieved\n", *pData);
free(temp);
printf("Node freed\n");
if (temp == head)
{
head = NULL;
}
else
{
prevNode->next = NULL;
}
}
return retVal;
}
int main(void)
{
int retrievedNum;
int num;
for (num = 0; num < 5; num++)
{
put(num);
}
printf("\n");
for (num = 0; num < 6; num++)
{
get(&retrievedNum);
}
put(num);
get(&retrievedNum);
printf("Element retrieved: %d\n", retrievedNum);
return 1;
}
This code will work for deleting last element in linklist:
void dellast()
{
r=head;
struct node* z;
do
{
z=r;
r=r->next;
if(r->next==NULL)
{
z->next=NULL;
free(r->next);
}
}while(z->next!=NULL);
}
The Code works like this:
Keep the track of current node and its previous node.
If current->next==NULL means it is the last node.
So do previous->next=NULL and free the current node
I've made my own (singly) LinkedList example in C, its proven to work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/********** GLOBALS *******************************/
#define OK 0
#define ERROR -1
/********** STRUCT AND TYPES DEFINTIONS ***********/
/* a node with key, data and reference to next node*/
typedef struct Node {
int key;
char string[1024];
struct Node *next; // pointer to next node
} Node;
/* the actual linked list: ref to first and last Node, size attribute */
typedef struct LinkedList {
struct Node *first;
struct Node *last;
int size;
} LinkedList;
/********** FUNCTION HEADERS **********************/
LinkedList* init_list();
void insert_end(LinkedList *list, int key, char string[]);
void insert_beginning(LinkedList *list, int key, char string[]);
int remove_end(LinkedList *list);
int remove_beginning(LinkedList *list);
int print_list(LinkedList *list);
void free_list(LinkedList *list);
char * get_string(LinkedList *list, int key);
/*********** FUNCTION DEFINITIONS ***************/
/**
* init_list Returns an appropriately (for an empty list) initialized struct List
*
* #return LinkedList * ..ptr to the newly initialized list
*/
LinkedList * init_list() {
printf("initializing list...\n");
LinkedList *list = (LinkedList*) malloc(sizeof(LinkedList));
list->first = NULL;
list->last = NULL;
list->size = 0;
return list;
}
/**
* Given a List, a key and a string adds a Node containing this
* information at the end of the list
*
* #param list LinkedList * ..ptr to LinkedList
* #param key int .. key of the Node to be inserted
* #param string char[] .. the string of the Node to be inserted
*/
void insert_end(LinkedList *list, int key, char string[]) {
printf("----------------------\n");
list->size++; // increment size of list
// intialize the new Node
Node* newN = (Node*) malloc(sizeof(Node));
newN->key = key;
strcpy(newN->string, string);
newN->next = NULL;
Node* oldLast = list->last; // get the old last
oldLast->next = newN; // make new Node the next Node for oldlast
list->last = newN; // set the new last in the list
printf("new Node(%p) at end: %d '%s' %p \n", newN, newN->key, newN->string,newN->next);
}
/**
* Given a List, a key and a string adds a Node, containing
* this information at the beginning of the list
*
* #param list LinkedList * ..ptr to LinkedList
* #param key int .. key of the Node to be inserted
* #param string char[] .. the string of the Node to be inserted
*/
void insert_beginning(LinkedList *list, int key, char string[]) {
printf("----------------------\n");
list->size++; // increment size of list
Node* oldFirst = list->first; //get the old first node
/* intialize the new Node */
Node* newN = (Node*) malloc(sizeof(Node));
newN->key = key;
strcpy(newN->string, string);
newN->next = oldFirst;
list->first = newN; // set the new first
/* special case: if list size == 1, then this new one is also the last one */
if (list->size == 1)
list->last = newN;
printf("new Node(%p) at beginning: %d '%s' %p \n", newN, newN->key,newN->string, newN->next);
}
/**
* Removes the first Node from the list
*
* #param list LinkedList * .. ptr to the List
*
* #return OK | ERROR
*/
int remove_beginning(LinkedList *list) {
printf("----------------------\n");
if (list->size <= 0)
return ERROR;
list->size--;
Node * oldFirst = list->first;
printf("delete Node(%p) at beginning: '%d' '%s' '%p' \n", oldFirst,oldFirst->key, oldFirst->string, oldFirst->next);
free(list->first); //free it
list->first = oldFirst->next;
oldFirst = NULL;
return OK;
}
/**
* Removes the last Node from the list.
*
* #param list LinkedList * .. ptr to the List
*
* #return OK | ERROR
*/
int remove_end(LinkedList *list) {
printf("----------------------\n");
/* special case #1 */
if (list->size <= 0)
return ERROR;
/* special case #2 */
if (list->size == 1) {
free(list->first);
list->first = NULL;
list->last = NULL;
return OK;
}
printf("delete Node(%p) at end: '%d' '%s' '%p' \n", list->last,list->last->key, list->last->string, list->last->next);
list->size--; // decrement list size
Node * startNode = list->first;
/* find the new last node (the one before the old last one); list->size >= 2 at this point!*/
Node * newLast = startNode;
while (newLast->next->next != NULL) {
newLast = newLast->next;
}
free(newLast->next); //free it
newLast->next = NULL; //set to NULL to denote new end of list
list->last = newLast; // set the new list->last
return OK;
}
/**
* Given a List prints all key/string pairs contained in the list to
* the screen
*
* #param list LinkedList * .. ptr to the List
*
* #return OK | ERROR
*/
int print_list(LinkedList *list) {
printf("----------------------\n");
if (list->size <= 0)
return ERROR;
printf("List.size = %d \n", list->size);
Node *startN = list->first; //get first
/* iterate through list and print contents */
do {
printf("Node#%d.string = '%s', .next = '%p' \n", startN->key,startN->string, startN->next);
startN = startN->next;
} while (startN != NULL);
return OK;
}
/**
* Given a List, frees all memory associated with this list.
*
* #param list LinkedList * ..ptr to the list
*/
void free_list(LinkedList *list) {
printf("----------------------\n");
printf("freeing list...\n");
if (list != NULL && list->size > 0) {
Node * startN = list->first;
Node * temp = list->first;
do {
free(temp);
startN = startN->next;
temp = startN;
} while (startN != NULL);
free(list);
}
}
/**
* Given a List and a key, iterates through the whole List and returns
* the string of the first node which contains the key
*
* #param list LinkedList * ..ptr to the list
* #param key int .. the key of the Node to get the String from
*
* #return OK | ERROR
*/
char * get_string(LinkedList *list, int key) {
printf("----------------------\n");
Node *startN = list->first; //get first
/* iterate through list and find Node where node->key == key */
while (startN->next != NULL) {
if (startN->key == key)
return startN->string;
else
startN = startN->next;
}
return NULL;
}
/*************** MAIN **************/
int main(void) {
LinkedList *list = init_list();
insert_beginning(list, 1, "im the first");
insert_end(list, 2, "im the second");
insert_end(list, 3, "im the third");
insert_end(list, 4, "forth here");
print_list(list);
remove_end(list);
print_list(list);
remove_beginning(list);
print_list(list);
remove_end(list);
print_list(list);
printf("string at node with key %d = '%s' \n",2,get_string(list, 2));
free_list(list);
return OK;
}
Hope this implementation example helps.

Resources