Stack and heap Ready
main.c

                

Ready

Statements run 0 Lines printed 0
Ready

Keyboard: ← → step · Space play / pause · R reset · Esc exit classroom mode

How it works

The ideas behind the lab

Exactly what you watched happen, in plain steps.

Stack vs heap

The stack holds local variables: fast, automatic, but limited in size and gone when the function returns. The heap is a big pool you manage yourself: malloc(bytes) reserves a block and returns its address (or NULL if it fails); the block stays until you call free on it. Use the heap when the size is only known at run time, when data is large, or when it must outlive the function that created it.

#include <stdlib.h>

int n = 10;
int *a = malloc(n * sizeof *a);   // n ints, garbage values
if (a == NULL) { /* out of memory */ }
a[0] = 5;                         // use it like an array

free(a);                          // give it back — once
a = NULL;                         // no dangling pointer
The four functions of stdlib.h
Call What it does Contents Returns
malloc(bytes) Reserves a block garbage address or NULL
calloc(count, size) Reserves count × size bytes all zero address or NULL
realloc(p, bytes) Resizes a block (may move it) old values kept new address or NULL
free(p) Gives the block back — nothing; free(NULL) does nothing

Allocating

  1. malloc takes a size in bytes: n * sizeof *a works for any type.
  2. It returns void *, which C converts to your pointer type automatically.
  3. Always check for NULL before using the memory.
  4. calloc(n, size) is like malloc but fills the block with zeros.
  5. The block is used like an array: a[i] or *(a + i).

Resizing and freeing

  1. realloc(p, newSize) keeps the old contents and may move the block.
  2. Store its result in a temporary pointer: if it fails, p is still valid.
  3. free(p) returns a block; every malloc / calloc needs exactly one free.
  4. After free, set the pointer to NULL so it cannot be used by mistake.
  5. A function may return heap memory — the caller must then free it.

The classic bugs

  1. Memory leak: the last pointer to a block is lost before free.
  2. Dangling pointer / use after free: using memory after free.
  3. Double free: calling free twice on the same block — the program aborts.
  4. Freeing memory that was not from malloc (a local array) — undefined behaviour.
  5. Tools like Valgrind or -fsanitize=address find these bugs.
Walkthrough

A function that builds an array on the heap

Every line, explained.

1 #include <stdio.h>
2 #include <stdlib.h> malloc and free live here.
3
4 int *makeSquares(int n)
5 {
6 int *a = malloc(n * sizeof *a); n ints on the heap.
7 if (a == NULL)
8 return NULL; Pass the failure on to the caller.
9 for (int i = 0; i < n; i++)
10 a[i] = (i + 1) * (i + 1);
11 return a; Fine: heap memory outlives the function (a local array would not).
12 }
13
14 int main(void)
15 {
16 int n = 5;
17 int *sq = makeSquares(n);
18 if (sq == NULL) {
19 printf("out of memory\n");
20 return 1;
21 }
22 for (int i = 0; i < n; i++)
23 printf("%d ", sq[i]); Prints 1 4 9 16 25
24 printf("\n");
25 free(sq); The caller frees what it received.
26 sq = NULL;
27 return 0;
28 }
Common mistakes

Spot the bug

Mistakes almost every beginner makes — and how to fix them.

Forgetting sizeof

✗ Wrong
int *a = malloc(10);              // 10 BYTES = 2 ints
✓ Right
int *a = malloc(10 * sizeof *a);  // 10 ints

malloc counts bytes. Multiply by the size of one element.

Not checking for NULL

✗ Wrong
int *a = malloc(n * sizeof *a);
a[0] = 1;   // crash if malloc failed
✓ Right
int *a = malloc(n * sizeof *a);
if (a == NULL) return 1;
a[0] = 1;

When memory runs out, malloc returns NULL — and writing to NULL crashes.

Losing the block (leak)

✗ Wrong
p = malloc(100);
p = malloc(200);   // the first 100 bytes are lost
✓ Right
p = malloc(100);
free(p);
p = malloc(200);

Once no pointer holds a block's address, it can never be freed.

a = realloc(a, …)

✗ Wrong
a = realloc(a, 2 * n * sizeof *a);   // NULL → old block lost
✓ Right
int *t = realloc(a, 2 * n * sizeof *a);
if (t != NULL) a = t;

If realloc fails it returns NULL but keeps the old block — which you just overwrote.

Using memory after free

✗ Wrong
free(p);
printf("%d", *p);
✓ Right
printf("%d", *p);
free(p);
p = NULL;

After free the block may be reused for something else: reading it is undefined behaviour.

Practice

Check your understanding

Answer each question — you will see the explanation straight away.

0 / 5 correct
Question 1

Which call reserves room for 8 ints?

Question 2

What does malloc return when no memory is available?

Question 3

What is the difference between malloc and calloc?

Question 4

How many times must a block from malloc be freed?

Question 5

Why is it safe for a function to return a pointer from malloc but not &local?

Assessment

Dynamic Memory quiz

Test yourself: 10 questions, 70% to pass. Create a free account to take the quiz, save your progress and work towards the certificate.