0Pricing
C Academy · Lesson

Detecting Leaks

memcheck basics.

Detecting Leaks is a free C Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What A Leak Is

A memory leak happens when you allocate heap memory with malloc, calloc, or realloc and lose every pointer to it before calling free.

The block stays reserved but unreachable until the process exits. In long-running programs, leaks accumulate until memory runs out.

A Minimal Leak

This program leaks one block of 40 bytes.

The pointer p is a local variable. When main returns, p disappears but the heap block it pointed at is never freed.

#include <stdlib.h>

int main(void) {
    int *p = malloc(10 * sizeof(int));
    p[0] = 1;
    return 0; /* never free(p) */
}

Running memcheck

memcheck is the default tool, so you can leave the tool name off.

Add --leak-check=full to get a stack trace for each leaked allocation.

gcc -g -O0 -o leak leak.c
valgrind --leak-check=full ./leak

The Leak Summary

At exit Valgrind prints a LEAK SUMMARY. For the program above it reads roughly:

definitely lost: 40 bytes in 1 blocks

The trace points to the exact malloc call site, so you know precisely which allocation was never freed.

The Four Leak Categories

memcheck classifies lost memory into four buckets:

  • definitely lost — no pointer remains; a true leak
  • indirectly lost — reachable only through a definitely-lost block
  • possibly lost — only an interior pointer remains
  • still reachable — a pointer exists at exit but you never freed it

Definitely vs Still Reachable

definitely lost is the urgent category: those bytes can never be recovered while the program runs.

still reachable is milder. The block is leaked at exit but a global or static pointer still references it, so it is usually a one-time allocation you simply never bothered to free.

Indirect Leaks

When you lose the head of a linked structure, every node becomes unreachable.

The head shows as definitely lost and the rest as indirectly lost. Fixing the root cause, the lost head, recovers all of it.

struct Node { int v; struct Node *next; };

struct Node *make(void) {
    struct Node *h = malloc(sizeof *h);
    h->next = malloc(sizeof *h);
    h->next->next = NULL;
    return h;
}
/* if the caller drops the returned head, both nodes leak */

The Fixed Version

Free what you allocate. This version leaks nothing.

Under Valgrind it reports All heap blocks were freed -- no leaks are possible.

#include <stdlib.h>

int main(void) {
    int *p = malloc(10 * sizeof(int));
    p[0] = 1;
    free(p);
    return 0;
}

Counting Allocations

Even without leaks, the HEAP SUMMARY tells you how busy your program was:

total heap usage: 1 allocs, 1 frees, 40 bytes allocated

When allocs and frees match, you have a clean run. A mismatch is your first clue something escaped.

Showing Reachable Blocks

By default memcheck does not list still reachable blocks in detail. To audit those too, add:

--show-leak-kinds=all

This forces a trace for every category, useful when you want a program that frees absolutely everything before exit.

valgrind --leak-check=full --show-leak-kinds=all ./leak

Leaks On Error Paths

The sneakiest leaks hide on early-return paths. Here, if the second allocation fails, the first block leaks.

Run-of-the-mill testing rarely hits these branches, but memcheck catches them whenever the path executes. Always free what you hold before returning on error.

char *a = malloc(100);
char *b = malloc(100);
if (!b) {
    /* bug: a is leaked here */
    return -1;
}
/* fix: free(a); before returning */

Quick Check

Pick the leak category that demands the most urgent attention.

Recap

You can now detect leaks with memcheck:

  • Run valgrind --leak-check=full ./prog on a -g binary
  • Read the LEAK SUMMARY and HEAP SUMMARY
  • Prioritize definitely lost, then chase indirect leaks to their root
  • Use --show-leak-kinds=all to audit still-reachable blocks

Next: invalid memory access.

Frequently asked questions

Is the “Detecting Leaks” lesson free?

Yes — the full text of “Detecting Leaks” is free to read here on the web, and the C Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C Academy course, upgrade to CoddyKit PRO.

What will I learn in “Detecting Leaks”?

memcheck basics. You practise C Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C Academy?

No prior experience is required. C Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Detecting Leaks” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C Academy lesson?

Yes. Every C Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Why Valgrind
  2. Detecting Leaks
  3. Invalid Access
  4. Reading Reports
← Back to C Academy