C Mastery / Ownership, Lifetime, Leaks, and Dangling Pointers
Part 4 — Memory Management

Ownership, Lifetime, Leaks, and Dangling Pointers

This chapter defines ownership as a discipline for managing allocated memory, and explains the two failure modes that ownership prevents: leaks and dangling pointers.

Why This Matters

C has no garbage collector. Whether a block is freed, and when, is entirely your responsibility. Ownership is the rule that makes this tractable; leaks and dangling pointers are what happen when it is absent.

Prerequisites

Core Concept

Ownership

Every allocated block has exactly one owner — the code responsible for freeing it. Ownership can be:

frees it.

reference-counting scheme manages it).

The rule: the owner frees, exactly once.

Leaks

A memory leak is a block that is no longer reachable but was never freed. Leaks waste memory; in long-running programs they accumulate and eventually exhaust memory.

void f(void)
{
    int *p = malloc(sizeof *p);  /* allocated */
    /* ... no free, no transfer ... */
}   /* p goes out of scope; block leaks */

Dangling pointers

A dangling pointer is a pointer to an object whose lifetime has ended. The classic case is free(p) followed by *p (use-after-free).

int *p = malloc(sizeof *p);
free(p);
*p = 5;   /* use-after-free: UB */

Examples

Ownership transfer

int *make_int(int value)
{
    int *p = malloc(sizeof *p);
    if (p) *p = value;
    return p;   /* ownership transferred to caller */
}

int main(void)
{
    int *p = make_int(42);
    /* caller now owns p */
    free(p);
    return 0;
}

Setting a freed pointer to NULL

int *p = malloc(sizeof *p);
free(p);
p = NULL;   /* helps catch use-after-free, but not a cure-all */

Setting to NULL prevents accidental reuse through p, but it does not fix other copies of the pointer that may still dangle.

How It Works

The heap has no notion of "reachable." A leak is purely a property of your program's logic: if no pointer variable can reach a block, it is leaked. A dangling pointer exists when the object is gone but a pointer value still refers to its former address.

Variations

Reference counting

Shared ownership can be implemented by a count that is incremented on each new reference and decremented on release; when it reaches zero, the block is freed. This is the basis of retain/release patterns.

Arenas

An arena owns many allocations and frees them all at once (c.mem.arena), simplifying ownership for short-lived groups of objects.

Common Mistakes

Undefined Behavior

Portability

behavior. The consequences (memory exhaustion, corruption) are universal.

Under the Hood

A dangling pointer still holds the old address; the allocator may have reused that memory for a different object. Reading through it yields whatever is now there — often corrupting unrelated data. This is why use-after-free is so dangerous.

Practical Usage

new object the caller must free").

ownership.

Exercises

1. Write a function that returns an allocated object and document ownership. 2. Write a function with two error paths and show a leak, then fix it with goto cleanup. 3. Demonstrate use-after-free and observe it under ASan. 4. Explain why p = NULL after free helps but is insufficient.

Deep Challenge

Design a small reference-counted string type with create, retain, release, and accessor functions. Ensure release frees exactly once when the count reaches zero, and explain the thread-safety implications (and how atomics would help).

References

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.mem.ownership07
c.mem.leaks06
c.mem.dangling07