How to Release the Allocated Memory for Nodes in the Linked List in C

Mehvish Ashiq Feb 02, 2024
How to Release the Allocated Memory for Nodes in the Linked List in C

Today, we will see how to free or release the allocated memory for nodes in the linked list in C.

Release the Allocated Memory for Nodes in the Linked List in C

In this article, we are using the free() function to release the memory that was reserved or allocated by the malloc() function. It means that whenever we call the malloc() function, we must call the corresponding free() function at some point to release the memory.

While using the linked list in C programming, every node of a linked list is assigned a memory as soon as the malloc() function is called. Therefore, we release the allocated memory by calling the free() method whenever the node or complete linked list is no longer needed.

Suppose we have a linked list containing the 3 nodes, and we decided that this linked list is not required now. We can use the loop to iterate over the linked list and free the allocated memory for each node.

Remember, we cannot expect the whole structure of a linked list to be freed by calling the free() function from the root node. To understand it practically, we are using two code examples.

  1. Print a complete linked list and release the allocated memory for all nodes
  2. Print the current node, save the pointer of the next node, and free the memory for the current node. This means we are printing and releasing the allocated memory in one loop.

To learn this scenario practically, we define the linked list nodes as follows. Notice that we define the structure in the recursive manner, which C programming allows.

Further, we are using the typedef struct instead of struct only to write a more organized and clean code. The difference between the typedef struct and struct is explained in detail here.

typedef struct node {
  int data;
  struct node* next;
} nodes;

Populate all the nodes using the makeList() function. Here, we have only three nodes in the linked list.

struct node* makeList() {
  nodes* headNode = NULL;
  nodes* secondNode = NULL;
  nodes* thirdNode = NULL;

  headNode = malloc(sizeof(nodes));
  secondNode = malloc(sizeof(nodes));
  thirdNode = malloc(sizeof(nodes));

  headNode->data = 1;
  headNode->next = secondNode;

  secondNode->data = 2;
  secondNode->next = thirdNode;

  thirdNode->data = 3;
  thirdNode->next = NULL;

  return headNode;
}

The printList() method (below) iterates over the linked list and prints every list node. Here, we created the currentNode that references the headNode.

Then, we use a while loop to check if the currentNode is NULL. If not, then print the currentNode data and save the next node’s address in currentNode.

This process continues until the currentNode equals the NULL.

void printList(nodes* headNode) {
  nodes* currentNode = headNode;
  while (currentNode != NULL) {
    printf("The current element is %d\n", currentNode->data);
    currentNode = currentNode->next;
  }
}

After printing the entire linked list, the freeList() function (below) releases the allocated memory for each node.

The freeList() function checks if the headNode is NULL. If it is NULL, the list is empty, so we immediately return from this function.

Secondly, save the headNode in a currentNode variable, and make the headNode point to the immediate next node in our list. We are doing it in headNode = headNode->next;.

Thirdly, we safely release the allocated memory using free(currentNode). Now, the headNode points to the remaining list and goes back to the first step.

void freeList(nodes* headNode) {
  nodes* currentNode;
  while (headNode != NULL) {
    currentNode = headNode;
    headNode = headNode->next;
    free(currentNode);
  }
}

Finally, we use the main() method to call the functions as follows and accomplish the goal.

int main() {
  nodes* headNode = makeList();
  printList(headNode);
  freeList(headNode);
  return 0;
}

Complete Example Code

The whole program looks as shown below when we assemble all the code chunks.

#include <stdio.h>

typedef struct node {
  int data;
  struct node* next;
} nodes;

struct node* makeList() {
  nodes* headNode = NULL;
  nodes* secondNode = NULL;
  nodes* thirdNode = NULL;

  headNode = malloc(sizeof(nodes));
  secondNode = malloc(sizeof(nodes));
  thirdNode = malloc(sizeof(nodes));

  headNode->data = 1;
  headNode->next = secondNode;

  secondNode->data = 2;
  secondNode->next = thirdNode;

  thirdNode->data = 3;
  thirdNode->next = NULL;

  return headNode;
}

void printList(nodes* headNode) {
  nodes* currentNode = headNode;
  while (currentNode != NULL) {
    printf("The current element is %d\n", currentNode->data);
    currentNode = currentNode->next;
  }
}

void freeList(nodes* headNode) {
  nodes* currentNode;
  while (headNode != NULL) {
    currentNode = headNode;
    headNode = headNode->next;
    free(currentNode);
  }
}

int main() {
  nodes* headNode = makeList();
  printList(headNode);
  freeList(headNode);
  return 0;
}

Output:

The current element is 1
The current element is 2
The current element is 3

In this code example, we are printing the current node, saving the address for the next node, and releasing the allocated memory for the current node.

Everything is the same as in the previous example except for two things. First, we don’t have the freeList() function and second, we have printAndFreeList() instead of the printList().

In the printAndFreeList() function, we are iterating over the list, printing the current node, saving the pointer for the rest of the linked list, and releasing the memory for the current node.

This process continues until the NULL is found.

void printAndFreeList(nodes* currentNode) {
  nodes* tempNode;
  while (currentNode != NULL) {
    tempNode = currentNode;
    printf("The current element is %d\n", currentNode->data);
    currentNode = currentNode->next;
    free(tempNode);
  }
}

Complete Example Code

The whole program looks as follows.

#include <stdio.h>

typedef struct node {
  int data;
  struct node* next;
} nodes;

struct node* makeList() {
  nodes* headNode = NULL;
  nodes* secondNode = NULL;
  nodes* thirdNode = NULL;

  headNode = malloc(sizeof(nodes));
  secondNode = malloc(sizeof(nodes));
  thirdNode = malloc(sizeof(nodes));

  headNode->data = 1;
  headNode->next = secondNode;

  secondNode->data = 2;
  secondNode->next = thirdNode;

  thirdNode->data = 3;
  thirdNode->next = NULL;

  return headNode;
}

void printAndFreeList(nodes* currentNode) {
  nodes* tempNode;
  while (currentNode != NULL) {
    tempNode = currentNode;
    printf("The current element is %d\n", currentNode->data);
    currentNode = currentNode->next;
    free(tempNode);
  }
}

int main() {
  nodes* headNode = makeList();
  printAndFreeList(headNode);
  return 0;
}

Output:

The current element is 1
The current element is 2
The current element is 3
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

Related Article - C Memory