Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Stack and heap memory in C

After this lesson: I can say where a variable lives and what malloc and free do.

55 min lesson6 commandsCompilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

Two places a C program keeps data

The stack and the heap are the two places where a C program keeps its variables. The stack holds local variables and cleans itself up, while the heap holds memory you ask for with malloc and must give back with free.

A till program that forgets to free a receipt on every sale runs out of memory by the end of the day.

By the end of this lesson

Note

I can say where a variable lives and what malloc and free do.

Key words

WordWhat it meansExample
Stackmemory for local variables, tidied up when a function returns
Heapmemory a program asks for and gives back by hand
malloca function that asks the heap for a number of bytesmalloc(40)
freea function that gives heap memory backfree(p)
Memory leakheap memory that is never given back
Dangling pointera pointer to memory that has been freed

The cells students fill in are left blank in this preview.

Local variables live on the stack

Each time a function is called, C reserves a block of the stack for it, called a stack frame. It holds the function's arguments and local variables.

When the function returns, its frame is thrown away and the variables are gone. The next call starts with a new frame, so locals do not remember anything.

Worked example: the stack while add runs

FrameFunctionHolds
Top, newestadda = 4, b = 5
MiddletotalThe prices and a running sum
Bottom, oldestmainThe shopping basket
After add returnsadd is gonetotal is the top frame again

The cells students fill in are left blank in this preview.

A local starts fresh on every call

Code: c
int fresh(void) { int n = 0; n = n + 1; return n; }
// static keeps n out of the stack frame, so it survives between calls.
int kept(void)  { static int n = 0; n = n + 1; return n; }

// fresh() gives 1 every time. kept() gives 1, then 2, then 3.

Write and build the two functions

Command
printf '%s\n' '#include <stdio.h>' 'int fresh(void) { int n = 0; n = n + 1; return n; }' 'int kept(void) { static int n = 0; n = n + 1; return n; }' 'int main(void) {' '  int a = kept();' '  int b = kept();' '  int c = kept();' '  printf("fresh: %d\n", fresh());' '  printf("fresh: %d\n", fresh());' '  printf("kept: %d %d %d\n", a, b, c);' '  return 0;' '}' | gcc -Wall -x c - -o frames

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Call each one and compare

Command
./frames

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

malloc asks the heap for memory

malloc(n) asks the heap for n bytes and gives back a pointer to them, or NULL if there is no room. That memory stays yours until you call free on the same pointer.

Use the heap when memory must outlive the function that made it, or when its size is not known until the program runs.

Stack and heap side by side

StackHeap
Made byA function callmalloc
Lasts untilThe function returnsfree is called
Tidied up byThe program itselfYou
Mistakes causeCrashesLeaks and crashes

The cells students fill in are left blank in this preview.

Write and build a malloc program

Command
printf '%s\n' '#include <stdio.h>' '#include <stdlib.h>' 'int main(void) {' '  int *p = malloc(3 * sizeof(int));' '  if (p == NULL) return 1;' '  p[0] = 4; p[1] = 5; p[2] = 6;' '  printf("sum %d\n", p[0] + p[1] + p[2]);' '  free(p);' '  p = NULL;' '  printf("freed, pointer reset: %d\n", p == NULL);' '  return 0;' '}' | gcc -Wall -x c - -o heap

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Use heap memory, then free it

Command
./heap

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Compare an array with a pointer

Command
printf '%s\n' '#include <stdio.h>' '#include <stdlib.h>' 'int main(void) {' '  int local[10];' '  int *onheap = malloc(10 * sizeof(int));' '  printf("array %zu, pointer %zu\n", sizeof(local), sizeof(onheap));' '  free(onheap);' '  return 0;' '}' | gcc -Wall -x c - -o sz

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Print the two sizes

Command
./sz

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Leaks and dangling pointers are heap bugs

A memory leak happens when the last pointer to a block is lost before free. The block can never be returned, so a long-running program slowly fills memory.

A dangling pointer happens when you use a pointer after free. The memory may now belong to something else, so reading or writing it gives wrong data or a crash.

One leak and one use after free

Code: c
void leak(void) {
  int *p = malloc(100);
  p = NULL;       // the only pointer is lost: 100 bytes leaked
}

void dangling(void) {
  int *q = malloc(100);
  free(q);
  q[0] = 7;       // use after free: undefined behaviour
}

A common mistake

Warning

Many people think free(p) erases the data and sets p to NULL. It only hands the bytes back. p still holds the old address, so set p = NULL yourself straight after free. Freeing the same pointer twice can crash the program.

About this lab and its source: Compilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.