Memory leaks can leave you broke!

In C, a memory leak occurs when a program allocates memory dynamically (using functions like malloc or calloc) but fails to deallocate or release that memory when it is no longer needed. Memory leaks can lead to a gradual increase in memory usage by a program, potentially causing it to consume more and more memory until it crashes. Here are a few examples of memory leaks in C, along with explanations and suggestions for prevention:

  1. Not Freeing Allocated Memory:

     #include <stdlib.h>
    
     int main() {
         int *arr = (int *)malloc(5 * sizeof(int));
         // Some code using arr
         // Memory should be freed, but it's not.
         return 0;
     }
    

    Explanation: The malloc function is used to allocate memory for an integer array, but there's no corresponding call to free to release that memory.

    Prevention: Always free dynamically allocated memory using the free function when it is no longer needed.

     free(arr);
    
  2. Forgetting to Free Memory in Loops:

     #include <stdlib.h>
    
     int main() {
         for (int i = 0; i < 5; i++) {
             int *arr = (int *)malloc(10 * sizeof(int));
             // Some code using arr
             // Memory is not freed in each iteration
         }
         return 0;
     }
    

    Explanation: Memory is allocated inside a loop, but it's not freed inside the loop, leading to multiple allocations without deallocation.

    Prevention: Ensure that memory is freed inside the loop if it's no longer needed.

     for (int i = 0; i < 5; i++) {
         int *arr = (int *)malloc(10 * sizeof(int));
         // Some code using arr
         free(arr); // Free the memory before the next iteration
     }
    
  3. Lost Pointers:

     #include <stdlib.h>
    
     int *createArray() {
         int *arr = (int *)malloc(5 * sizeof(int));
         // Some code using arr
         return arr; // Memory is returned but not freed
     }
    
     int main() {
         int *arr = createArray();
         // Memory is lost since there's no reference to it and no way to free it.
         return 0;
     }
    

    Explanation: The pointer arr is returned from the function createArray, but there's no reference to it in main, and thus there's no way to free the allocated memory.

    Prevention: Keep track of all dynamically allocated pointers and ensure that they are freed when no longer needed.

     int *arr = createArray();
     // Some code using arr
     free(arr); // Free the memory when done using it
    
  4. Conditional Memory Allocation without Corresponding Deallocation:

     #include <stdlib.h>
    
     void processInput(int size) {
         int *arr;
         if (size > 0) {
             arr = (int *)malloc(size * sizeof(int));
             // Some code using arr
         }
         // Memory is not freed if size <= 0
     }
    
     int main() {
         processInput(5);
         processInput(0);
         return 0;
     }
    

    Explanation: Memory is allocated conditionally based on the input size, but if the condition is not met, the allocated memory is not freed.

    Prevention: Ensure that memory is freed in all possible code paths.

     void processInput(int size) {
         int *arr;
         if (size > 0) {
             arr = (int *)malloc(size * sizeof(int));
             // Some code using arr
             free(arr); // Free memory when size > 0
         }
         // No memory to free if size <= 0
     }
    
  5. Overwriting Pointers without Freeing Memory:

     #include <stdlib.h>
    
     int main() {
         int *arr = (int *)malloc(5 * sizeof(int));
         // Some code using arr
         arr = (int *)malloc(10 * sizeof(int)); // Overwriting the pointer without freeing the previous memory
         return 0;
     }
    

    Explanation: The original memory allocated for arr is lost when a new allocation is made without freeing the previous memory.

    Prevention: Free the previous memory before overwriting the pointer.

     free(arr); // Free the original memory
     arr = (int *)malloc(10 * sizeof(int)); // Allocate new memory
    
  6. Dynamic Memory Allocation in Functions without Proper Deallocation:

     #include <stdlib.h>
    
     void allocateMemory(int **arr, int size) {
         *arr = (int *)malloc(size * sizeof(int));
         // Some code using *arr
         // Memory is not freed before returning from the function
     }
    
     int main() {
         int *arr;
         allocateMemory(&arr, 5);
         // Memory is not freed after using arr
         return 0;
     }
    

    Explanation: Memory is allocated in the allocateMemory function, but it's not freed before returning to the calling function.

    Prevention: Free memory before returning from the function.

     void allocateMemory(int **arr, int size) {
         *arr = (int *)malloc(size * sizeof(int));
         // Some code using *arr
         free(*arr); // Free memory before returning
     }
    
  7. Incomplete Deallocation in Multi-Dimensional Arrays:

     #include <stdlib.h>
    
     int main() {
         int **matrix = (int **)malloc(3 * sizeof(int *));
         for (int i = 0; i < 3; i++) {
             matrix[i] = (int *)malloc(3 * sizeof(int));
             // Some code using matrix[i]
         }
    
         // Memory is not freed properly for the rows
         free(matrix);
         return 0;
     }
    

    Explanation: Although memory is allocated for rows of a 2D array, only the memory for the array of pointers is freed, not the memory for each row.

    Prevention: Free the memory for each row before freeing the array of pointers.

     for (int i = 0; i < 3; i++) {
         free(matrix[i]); // Free memory for each row
     }
     free(matrix); // Free the array of pointers
    
  8. Memory Leak in Linked List Nodes:

     #include <stdlib.h>
    
     struct Node {
         int data;
         struct Node *next;
     };
    
     int main() {
         struct Node *head = (struct Node *)malloc(sizeof(struct Node));
         // Some code using head
         // Memory is not freed for head
         return 0;
     }
    

    Explanation: Memory is allocated for the head of a linked list, but it's not freed before the program exits.

    Prevention: Free the memory for each node in the linked list before the program exits.

     free(head); // Free memory for the head node
    
  9. Memory Leak with strdup:

     #include <stdlib.h>
     #include <string.h>
    
     int main() {
         char *str = strdup("Memory Leak Example");
         // Some code using str
         // Memory is not freed for str
         return 0;
     }
    

    Explanation: The strdup function allocates memory for a duplicated string, but the memory is not freed.

    Prevention: Free the memory allocated by strdup using free.

     free(str); // Free memory allocated by strdup
    
  10. Memory Leak in a Function Using malloc:

    #include <stdlib.h>
    
    int *createArray(int size) {
        int *arr = (int *)malloc(size * sizeof(int));
        // Some code using arr
        return arr;
    }
    
    int main() {
        int *arr = createArray(5);
        // Memory is not freed for arr
        return 0;
    }
    

    Explanation: Memory is allocated in a function, but it's not freed after the function returns.

    Prevention: Free the memory in the calling function when it is no longer needed.

    free(arr); // Free memory in the calling function
    

To prevent memory leaks in C:

  • Always pair dynamic memory allocation (malloc, calloc, realloc) with corresponding deallocation (free).

  • Free memory as soon as it is no longer needed.

  • Be cautious with pointers returned from functions, and ensure you have a plan for releasing the associated memory.

  • Use tools like valgrind to detect memory leaks and other memory-related issues in your C programs.

0
Subscribe to my newsletter

Read articles from Jyotiprakash Mishra directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jyotiprakash Mishra
Jyotiprakash Mishra

I am Jyotiprakash, a deeply driven computer systems engineer, software developer, teacher, and philosopher. With a decade of professional experience, I have contributed to various cutting-edge software products in network security, mobile apps, and healthcare software at renowned companies like Oracle, Yahoo, and Epic. My academic journey has taken me to prestigious institutions such as the University of Wisconsin-Madison and BITS Pilani in India, where I consistently ranked among the top of my class. At my core, I am a computer enthusiast with a profound interest in understanding the intricacies of computer programming. My skills are not limited to application programming in Java; I have also delved deeply into computer hardware, learning about various architectures, low-level assembly programming, Linux kernel implementation, and writing device drivers. The contributions of Linus Torvalds, Ken Thompson, and Dennis Ritchie—who revolutionized the computer industry—inspire me. I believe that real contributions to computer science are made by mastering all levels of abstraction and understanding systems inside out. In addition to my professional pursuits, I am passionate about teaching and sharing knowledge. I have spent two years as a teaching assistant at UW Madison, where I taught complex concepts in operating systems, computer graphics, and data structures to both graduate and undergraduate students. Currently, I am an assistant professor at KIIT, Bhubaneswar, where I continue to teach computer science to undergraduate and graduate students. I am also working on writing a few free books on systems programming, as I believe in freely sharing knowledge to empower others.