# Dynamic Memory in C — malloc, calloc, realloc, free and Linked Lists

Source: https://skills101.in/learn/c-programming/c-dynamic-memory — Skills101 free tutorial (C Programming). Updated 2026-11-09.

Arrays need their size at compile time. **Dynamic memory** lets you decide the size **while the program runs** — for example, after reading how many students there are.

![int *arr on the stack points to five ints allocated on the heap with malloc; they stay until free(arr). Forgetting free causes a leak; using memory after free causes crashes](https://skills101.in/learn-img/c-programming/malloc-heap.svg)

All functions are in **`<stdlib.h>`**.

## 1. malloc and free

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

int main(void) {
    int n = 5;
    int *arr = malloc(n * sizeof(int));     /* n ints on the heap */
    if (arr == NULL) {                       /* always check */
        printf("out of memory\n");
        return 1;
    }
    for (int i = 0; i < n; i++) arr[i] = i * i;
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");
    free(arr);                               /* give it back */
    arr = NULL;                              /* avoid a dangling pointer */
    return 0;
}
```

```text
0 1 4 9 16
```

## 2. malloc vs calloc

| | `malloc(bytes)` | `calloc(count, size)` |
|---|---|---|
| Arguments | total bytes | number of items, size of each |
| Initial values | **garbage** | **all zero** |
| Speed | slightly faster | zeroing costs a little |

```c
int *a = calloc(5, sizeof(int));   /* {0, 0, 0, 0, 0} */
```

## 3. realloc: grow or shrink

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

int main(void) {
    int cap = 2, n = 0;
    int *v = malloc(cap * sizeof(int));
    for (int x = 1; x <= 5; x++) {
        if (n == cap) {                         /* full → double the capacity */
            cap *= 2;
            int *bigger = realloc(v, cap * sizeof(int));
            if (!bigger) { free(v); return 1; }
            v = bigger;
        }
        v[n++] = x * 10;
    }
    printf("n=%d cap=%d last=%d\n", n, cap, v[n - 1]);
    free(v);
    return 0;
}
```

```text
n=5 cap=8 last=50
```

This "double when full" idea is exactly how Python lists and Java ArrayLists grow.

> Assign realloc's result to a **temporary** first: if it fails it returns NULL, and writing `v = realloc(v, …)` would lose the original pointer (a leak).

## 4. Common memory bugs

| Bug | What happens | Prevent it |
|---|---|---|
| **Memory leak** | memory never freed; long-running programs grow until they crash | `free` everything you `malloc` |
| **Dangling pointer** | using memory after `free` | set the pointer to NULL after free |
| **Double free** | freeing the same block twice → crash | NULL after free (free(NULL) is safe) |
| **Buffer overflow** | writing past the allocated size | track sizes carefully |

Tools like **Valgrind** and **AddressSanitizer** find these bugs.

## 5. A linked list

![A linked list: head points to node 10, which points to 20, which points to 30, which points to NULL. Each node holds data and a next pointer](https://skills101.in/learn-img/c-programming/linked-list.svg)

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

typedef struct Node {
    int data;
    struct Node *next;
} Node;

Node *push_front(Node *head, int value) {
    Node *n = malloc(sizeof(Node));
    n->data = value;
    n->next = head;
    return n;                     /* the new node is the new head */
}

int main(void) {
    Node *head = NULL;
    for (int v = 30; v >= 10; v -= 10) head = push_front(head, v);
    for (Node *p = head; p != NULL; p = p->next) printf("%d -> ", p->data);
    printf("NULL\n");
    while (head) {                /* free every node */
        Node *next = head->next;
        free(head);
        head = next;
    }
    return 0;
}
```

```text
10 -> 20 -> 30 -> NULL
```

Linked lists grow one node at a time and insert at the front in O(1); see the [DSA linked list tutorial](https://skills101.in/learn/dsa/linked-list) for more.

## Common mistakes

- Not checking malloc's return value for NULL.
- `malloc(n)` instead of `malloc(n * sizeof(int))`.
- Freeing a list node and then reading `node->next`.

## Quick recap

- malloc (garbage), calloc (zeros), realloc (resize), free (release) — from stdlib.h.
- Always check for NULL; free what you allocate; set freed pointers to NULL.
- Leaks, dangling pointers, double free and overflows are the classic bugs.
- Linked lists are built from malloc'd nodes connected by pointers.


Practice quiz and free certificate: https://skills101.in/learn/c-programming/c-dynamic-memory