C - memory management in C

1. Memory in a C Program

When a C program runs, memory is typically divided into:

Memory Region Purpose Managed By
Code/Text Stores program instructions Compiler/OS
Global/Static Stores global and static variables Compiler/OS
Stack Stores function call frames, local variables Automatically managed (LIFO)
Heap Stores dynamically allocated memory You (via malloc, free, etc.)

2. Static vs Dynamic Memory

  • Static: Known at compile time (global variables, static variables, fixed-size arrays).

  • Automatic: Created on the stack, freed when function exits.

  • Dynamic: Allocated at runtime on the heap, must be manually freed.


3. Dynamic Memory Allocation Functions

From <stdlib.h>:

Function Purpose Notes
malloc(size) Allocates size bytes Contents uninitialized
calloc(n, size) Allocates n * size bytes Initializes to zero
realloc(ptr, new_size) Changes size of allocated memory May move memory
free(ptr) Frees allocated memory ptr must be from malloc, calloc, or realloc

Example:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr = malloc(5 * sizeof(int)); // allocate for 5 ints
    if (!arr) {
        printf("Memory allocation failed\n");
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        arr[i] = i + 1;
    }

    arr = realloc(arr, 10 * sizeof(int)); // resize
    if (!arr) {
        printf("Reallocation failed\n");
        return 1;
    }

    free(arr); // release memory
    return 0;
}

4. malloc vs calloc

  • malloc: Faster, memory not initialized

  • calloc: Slower, memory is initialized to zero

Example:

int *p = malloc(5 * sizeof(int));  // garbage values
int *q = calloc(5, sizeof(int));   // all values are 0

5. Common Memory Issues in C

  1. Memory leaks — forgetting to free() allocated memory

  2. Dangling pointers — using a pointer after freeing it

  3. Double free — freeing the same pointer twice

  4. Buffer overflow — writing beyond allocated size

  5. Uninitialized memory usage — reading before assigning


6. Best Practices

  • Always check if malloc/calloc/realloc returns NULL

  • free() everything you allocate before program exits

  • Set pointers to NULL after free() to avoid dangling pointers

  • Use sizeof(*ptr) instead of sizeof(type) to avoid type mismatches

  • Avoid memory allocation inside tight loops unless necessary


7. Visual Diagram

Imagine this code:

int x = 10;                // stack
int *p = malloc(sizeof(int)); // heap
*p = 20;

Memory layout:

Stack:
[ x=10 ]    [ p = 0x6000 ]

Heap:
0x6000 -> [ 20 ]

8. Detecting Memory Problems

Tools like:

  • Valgrind (Linux/Mac) — detects leaks and invalid memory access

  • AddressSanitizer (via -fsanitize=address in GCC/Clang)

 

 

Do you want me to make that?