Deleting a whole linked list - c

I am working with linked lists and i fill the structure but when I delete the whole structure and try to print the contents of the linked list (should be null), a list of numbers appear. I know it is probably a memory problem. Any suggestions of how to fix it?
Code for deleting whole linked list:
void destroy(set_elem *head)
{
set_elem *current = head;
set_elem *next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
head = NULL;
}

While your delete function works correctly, it doesn't set the head in the caller to NULL when you do head = NULL; as you are only modifying a local pointer, which causes to your later logic where you are trying to print the values by checking the value of head.
To modify the original pointer, pass a pointer to head and set *head=NULL;
void destroy(set_elem **head)
{
set_elem *current = *head;
/* rest is the same */
*head = NULL;
}

when you copy head pointer passed into the function, head node is unaffected. You have to pass reference to the pointer to the head,then you will be able to delete head pointer. This can be also done by passing a pointer to the pointer to the head of the linked list but I find passing a reference more convenient. Following are the changes to your code.
void destroy(set_elem*& head)
{
set_elem* current = head;
set_elem* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
*head = NULL;
}

You are not changing the original head. You should pass the pointer to this head i.e. pointer to a pointer or should return changed head to the caller. Following is the code to return changed head to the caller. There are other answers showing pointer to pointer approach.
set_elem* destroy(set_elem *head) {
set_elem *current = head;
set_elem *next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
head = NULL;
return head;
}
in caller,
head = destroy(head);

You're modifying only the local head pointer
Use a double pointer to modify the head, which would be later used for printing/processing
void destroy(set_elem** head)
{
set_elem* current = *head;
set_elem* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
*head = NULL;
}

Related

create linked list using char array as data

I am having a problem on assigning char array after I create a node.
I am having trouble on this function I created which it would make a new node and then assign character array into the created node. I don't have any problems when it comes to int but I can't seem to run when I switched to character array.
I get a run time error when I try to run my code.
Any help would be much appreciated.
Thank You!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct node{
char data[MAX];
struct node *next;
};
typedef struct node* nodePtr;
void create(nodePtr head, char data[]);
int main()
{
nodePtr head = NULL;
char str[] = "HELLO";
create(head, str);
return 0;
}
void create(nodePtr head, char data[])
{
if (head == NULL)
{
// empty list
head = (nodePtr) malloc(sizeof(struct node)); // create root
strcpy(head->data, data);
head->next = NULL;
}
else
{ // list not empty
nodePtr current = head; // start at the beginning...
while (current->next != NULL)
{
current = current->next; // walk to the end of the list
}
current->next = (nodePtr) malloc(sizeof(struct node));
current = current->next;
strcpy(current->data, data);
}
}
There is more than one problem with your program.
To begin with, when you add elements to a list that already has a head, are not initializing the next member. This will cause multiple list insertions to fail.
current->next = malloc(sizeof(struct node));
current = current->next;
strcpy(current->data, data);
current->next = NULL; //<-- you forgot this
The other big issue is that you are also leaking your entire list, because you pass the head pointer by value into the function. When the list is empty, the function modifies this value but it's a copy so when the function returns, the value of head in main is still NULL.
There are two options. Either you change your function to expect a pointer to the head-pointer, or you use what's called a "dummy head".
Using a dummy head actually simplifies lists a lot. What this means is your head is actually an unused node whose sole responsibility is to store the actual head in its next-pointer:
struct node head = {}; // dummy head node
create(&head, str);
The above will never actually hit the head == NULL part of the create function because dummy heads guarantee the head is always a valid node. So if you set your list up that way, then your create function can be simplified.
If you don't want to do this, then you need to pass a pointer to your head pointer. That means your create function becomes:
void create(nodePtr *head, char data[])
{
if (*head == NULL)
{
*head = malloc(sizeof(struct node));
strcpy((*head)->data, data);
(*head)->next = NULL;
}
else
{
nodePtr current = *head;
while (current->next != NULL) current = current->next;
current->next = malloc(sizeof(struct node));
current = current->next;
if (current != NULL)
{
strcpy(current->data, data);
current->next = NULL;
}
}
}
And you would invoke the above as:
nodePtr head = NULL;
create(&head, str);
One extra thing you might wish to do is make the function return the node that it created. The reason you might want to do this is that currently if you're inserting many items into the list you have to search to the end every time. If instead you pass the last node as the next head, then no searching is necessary:
nodePtr head = NULL;
nodePtr tail = head;
tail = create(head, "goodbye");
tail = create(tail, "cruel");
tail = create(tail, "world");
This would mean a small modification to your function, but I'm sure you can work that out.

Explanation for base case return value in recursive linked list reverse algorithm

I am learning how to reverse a linked list recursively. I am confused with the last 4 lines.
node *reverse_linked_list_rec(node *head){
if (head->next==NULL){
return head;
}
node *smallans= reverse_linked_list_rec(head->next);
node *tail = head->next;
tail->next = head;
head->next = NULL;
return smallans;
}
Let's say I am reversing
1 2 3 NULL
by recursion, it reaches at 3 NULL and then by base case returns
2 3 NULL
here head=2, smallans=2 (not sure).
Why we are returning smallAns here and how it is changing?
smallans is a confusing variable name because it's actually the old tail being passed back through the list to become the new head which is ultimately returned to the caller.
Its next pointer changes when these lines execute in the parent function call:
// when head->next->next == NULL ...
node *tail = head->next; // ... `tail` points to the old tail (new head) ...
tail->next = head; // ... and this sets the new tail's next pointer to
// the old second-to-last node (new second node).
tail is a misleading name here--I associate a "tail" with a single node that terminates the entire list, not a previous node. new_prev or old_next seem more appropriate here depending on whether you want to name things relative to the node roles in the new list or the original list.
As a minor point, I recommend using if (!head || !head->next) to avoid a potential null pointer dereference.
I'd write the function as follows:
node *reverse_linked_list_rec(node *head) {
if (!head || !head->next) {
return head;
}
node *old_tail = reverse_linked_list_rec(head->next);
node *old_next = head->next;
old_next->next = head;
head->next = NULL;
return old_tail;
}
Aside from intellectual curiosity, recursion is a poor choice for linked list operations since it adds function call overhead, you can blow the stack and the logic isn't any easier to follow than iterative, in most cases.
Case in point, here's a complete example with an iterative version:
#include <stdio.h>
#include <stdlib.h>
struct node {
int id;
struct node *next;
};
struct node *make_node(int id) {
struct node *n = malloc(sizeof(*n));
if (!n) exit(1);
n->id = id;
n->next = NULL;
return n;
}
struct node *reverse_linked_list(struct node *head) {
struct node *prev = NULL;
for (struct node *curr = head; curr;) {
struct node *old_next = curr->next;
curr->next = prev;
prev = curr;
curr = old_next;
}
return prev;
}
void print_linked_list(struct node *head) {
for (; head; head = head->next) {
printf("%d->", head->id);
}
puts("");
}
void free_linked_list(struct node *head) {
while (head) {
struct node *tmp = head;
head = head->next;
free(tmp);
}
}
int main() {
struct node *head = make_node(1);
head->next = make_node(2);
head->next->next = make_node(3);
print_linked_list(head); // => 1->2->3->
head = reverse_linked_list(head);
print_linked_list(head); // => 3->2->1->
free_linked_list(head);
return 0;
}
As another minor point, since the linked list is being mutated I'd probably go for a header like void reverse_linked_list(struct node **head);. Otherwise, it seems too easy to call the non-void function, ignore the return value and wind up with a memory leak or crash when head in the caller scope (which has become a tail pointing to null) is dereferenced.

Destroy a full linked list (c programming)

I am a beginner to C programming and am a bit stuck on pointers. i am trying to create a function that deletes all the elements of the linkes list. However my code deletes all elements except for the head.
I cannot alter the
void destroy(node *h)
parameters due to assignment title.
void destroy(set_element* head){
set_element* temp ;
set_element* curr = head;
if(head){
curr = head->next;
head->next = NULL;
while(curr !=NULL){
temp = curr->next;
free(curr);
curr = temp;
}
head =NULL;
}
}
thanks in advance.
The problem is this line
curr = head->next;
Here you make curr point to the next node. You need to make curr point directly to head.
A simpler version of the function might be e.g. this:
void destroy(set_element **head)
{
set_element *next;
for (set_element *curr = *head; curr; curr = next)
{
next = curr->next;
free(curr);
}
*head = NULL;
}
Note that I pass the head pointer by reference, otherwise the assignment to NULL will only change the local copy of the pointer.
If all you want to do is delete the entire linked list (head node included) and don't care whether the caller is left with a dangling pointer, this gets significantly simpler:
void destroy(set_element* head)
{
set_element* temp;
while (head)
{
temp = head;
head = head->next;
free(temp);
}
}
Invoked on the caller side as:
destroy(head);
That said, if you want to modify the callers passed-in pointer you cannot do it with this function signature. Like all other things in C (arrays not withstanding) parameters are passed by value, and if you need to modify the callers data, the parameter must be a pointer, and the passed-in value an address:
void destroy(set_element** headp)
{
set_element* temp;
while (*headp)
{
temp = *headp;
*headp = temp->next;
free(temp);
}
}
Invoked on the caller side as
destroy(&head);
Both of these assume your list is properly terminated with NULL.

How to pop from linked list?

I've implemented a Linked-List with a Pop function in C:
Node * pop (Node * head) {
Node * temp = head;
printf("Temp is: %s\n", temp->val);
if (head->next != NULL) {
*head = *head->next;
}
printf("Temp is: %s\n", temp->val);
return temp;
}
And the output when I pop would be something like:
Temp is: node1 value
Temp is: node2 value
That is to say that temp is becoming temp->next when I assign *head = *head->next.
So how can I get the value of the current head and return it while also moving the head of the Linked-list to head->next?
Doing head = head->next does NOT remove the reference to the first node. (i.e. When I print the list, the first node is still there).
First, note that your code (and some of the previous solutions) will never pop the last element off the list. You want
if (*head != NULL) ...
Next, passing a pointer to a pointer will work. But it's actually better to make a list header like this:
typedef struct node_s {
struct node_s *next;
... data declaration here
} Node;
typedef struct list_s {
struct node_s *head;
} List;
void init_list(List *list) {
list->head = NULL;
}
Now declare a list like this:
List list[1];
init_list(list);
Declaring an array of one element makes every reference to list a pointer automatically, which eliminates lots of &'s in your code. Then it's nice and clean to implement push and pop:
void push(List *list, Node *node) {
node->next = list->head;
list->head = node;
}
Node *pop(List *list) {
Node *head = list->head;
if (head) {
list->head = head->next;
head->next = NULL;
}
return head;
}
Why is this better? Say you decide later to keep a count of items in the list. With the separate header node this is very easy:
typedef struct list_s {
struct node_s *head;
int length;
} List;
void init_list(List *list) {
list->head = NULL;
length = 0;
}
void push(List *list, Node *node) {
node->next = list->head;
list->head = node;
++list->length;
}
Node *pop(List *list) {
Node *head = list->head;
if (head) {
list->head = head->next;
head->next = NULL;
--list->length;
}
return head;
}
Note no calling code needs to change. With the pointer to pointer approach you are at a dead end. There are many other use cases where having a separate list header makes your code more flexible for future changes.
Your need to pass the address of head for your function to modify it. Then your function needs to dereference this address. Further, the last pop() needs to change *AddressOfHead as well
Node *pop(Node **AddressOfHead) {
Node *temp = *AddressOfHead;
if (temp) {
*AddressOfHead = temp->next;
}
return temp;
}
...
// Usage example
Node *TopOfList = pop(&Head);
Others have told you how to fix it, let me answer why temp changed..
Node * pop (Node * head) {
You are passing head as a pointer to a Node.
Thus when you do
*head = *head->next;
I think it is parsed as
*head = *(head->next);
And thus COPIES the object that is in next into the object at head, which is ofcourse the same object at temp.
Pointers are passed by value. That is, when you pass a pointer to the stack, a change in the called function to what the pointer points to is not reflected in the calling function.
In order for the value of the node pointer to be changed in the calling function, you need to pass the stack as a pointer to a pointer:
Node* pop (Node** head) {
Node* temp = *head;
if (temp) {
*head = temp->next; // to update stack in calling function
temp->next = NULL; // to detach temp from the rest of the list
}
return temp;
}
You do not need to check if ((*head)->next) or in this case if (temp->next) before updating the value of *head, because if you are at the last node of the stack and the next node is NULL, you want the list to be NULL anyway.
Karthik T's answer has the right explanation for why the value of temp was changing in your original code.
void pop(struct node** tol) {
struct node* t = *tol;
while (t->link->link != NULL){
t = t->link;
}
t->link = NULL;
}

Deallocates all of its memory and sets its head pointer to NULL (the empty list)

Got a question in my exam.
Write a function DeleteList() that takes a list, deallocates all of its memory and sets its
head pointer to NULL (the empty list).
Solution was given as
void DeleteList(struct node** headRef) {
struct node* current = *headRef;
struct node* next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
*headRef = NULL;
}
My solution :
void DeleteList(struct node** headRef) {
struct node* current = *headRef;
while (current != NULL) {
*headRef = *headRef->next;
free(current);
current = * headRef;
}
free(current);
*headRef = NULL;
}
Is this correct approach?
Thanks,
Your solution does not do this "and sets its head pointer to NULL" because the final line of your proposal (*headRef = NULL;) is no longer setting the incoming headRef value to NULL, but rather the final Next point in the list (which already is null).
free(current); //you should remove this line after the while loop because when while loop breaks the current is already NULL so free(NULL) makes no sense.
*headRef = NULL;
look here Free(NULL).
The rest must work according to me.
void DeleteList(struct node **headRef)
{
struct node *current = *headRef;
while (current) {
*headRef = (*headRef)->next;
free(current);
current = *headRef;
}
*headRef = NULL;
}

Resources