Real‑world examples of segmentation fault in dynamic memory allocation

If you write C or C++ long enough, you will eventually meet the segmentation fault – usually at 2 a.m., right before a deadline. Understanding real examples of segmentation fault in dynamic memory allocation is one of the fastest ways to stop guessing and start debugging with intent. In this guide, we’ll walk through several practical examples of segmentation fault in dynamic memory allocation, show why they happen, and how to fix them without sprinkling random printf calls everywhere. We’ll look at heap misuse in modern codebases, patterns that still bite developers in 2024, and how tools like AddressSanitizer and Valgrind expose the bug behind that unhelpful “Segmentation fault (core dumped)” message. Along the way, you’ll see examples of subtle off‑by‑one errors, double frees, mismatched new/delete usage, and use‑after‑free scenarios that appear only under load or in production. Think of this as a guided tour of the heap’s most common landmines, with concrete code you can recognize in your own projects.
Written by
Jamie
Published
Updated

Segmentation faults happen when your program touches memory it doesn’t own. With dynamic memory allocation, you’re manually asking the runtime for heap memory (malloc, calloc, realloc, new) and promising to use it correctly. Every time that promise is broken, you get another entry in the long list of real examples of segmentation fault in dynamic memory allocation.

Modern C/C++ projects still wrestle with these bugs in 2024, even inside high‑profile open source systems. Memory safety is a big enough problem that organizations like the U.S. Cybersecurity & Infrastructure Security Agency (CISA) now actively encourage migration away from memory‑unsafe languages in critical systems (CISA, 2024). Until that migration is complete, understanding these failure modes is part of everyday life for systems programmers.

Let’s walk through the best examples you’re likely to see in real code.


Classic example of heap overflow leading to segmentation fault

A very common example of segmentation fault in dynamic memory allocation is writing past the end of a heap buffer. It usually starts with a small off‑by‑one mistake.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    size_t len = 10;
    char *buf = malloc(len);  // space for 10 bytes
    if (!buf) return 1;

    // BUG: writes 11 bytes (10 chars + '\0') into a 10‑byte buffer
    strcpy(buf, "ABCDEFGHIJ");

    printf("%s\n", buf);
    free(buf);
    return 0;
}

On some runs, this might appear to work. On others, especially with modern allocators or when compiled with optimizations, you’ll see a segmentation fault. The write overruns the allocated block, corrupting adjacent heap metadata or another object. Tools like AddressSanitizer (-fsanitize=address) will flag this as a heap‑buffer‑overflow and often show exactly which write triggered the fault.

This is one of the clearest examples of examples of segmentation fault in dynamic memory allocation caused purely by a size mismatch.


Use‑after‑free: the sneakiest examples of segmentation fault in dynamic memory allocation

Use‑after‑free bugs are some of the best examples of “it worked on my machine” behavior. The code compiles, often passes basic tests, and then explodes under real load.

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

int main(void) {
    int *data = malloc(sizeof(int) * 4);
    if (!data) return 1;

    for (int i = 0; i < 4; ++i) {
        data[i] = i * 10;
    }

    free(data);

    // BUG: using memory after it has been freed
    printf("Value: %d\n", data[2]);  // undefined behavior, often segfault

    return 0;
}

After free, data still holds the same address, but the program no longer owns that memory. Any read or write is undefined behavior. In practice, that often becomes a segmentation fault, especially in hardened builds or when the allocator reuses or poisons freed memory.

Real examples of segmentation fault in dynamic memory allocation often look more complicated than this toy snippet: the free happens in a cleanup function, the use happens in another module, and the stack trace points somewhere completely different from where the bug originated.


Double free and mismatched allocation: examples include subtle lifetime bugs

Another family of examples of segmentation fault in dynamic memory allocation comes from freeing the same pointer twice or mixing allocation and deallocation APIs.

Double free example

#include <stdlib.h>

void cleanup(int *p) {
    if (p) {
        free(p);
    }
}

int main(void) {
    int *p = malloc(sizeof(int));
    if (!p) return 1;

    *p = 42;

    free(p);       // first free
    cleanup(p);    // second free via helper

    return 0;
}

The second free call hits memory the allocator has already reclaimed. Many modern allocators detect this and abort the program with a segmentation fault or similar crash.

Mismatched new/delete and malloc/free

In C++, mixing allocation families is undefined behavior and a common example of a segmentation fault in dynamic memory allocation:

#include <cstdlib>

int main() {
    int *p = (int*)malloc(sizeof(int));
    // BUG: should use free(p), not delete
    delete p;  // undefined behavior, potential segfault
    return 0;
}

Or the opposite:

int main() {
    int *p = new int(5);
    // BUG: should use delete, not free
    free(p);   // undefined behavior, potential segfault
    return 0;
}

These are real examples of segmentation fault in dynamic memory allocation that show up in mixed C/C++ codebases, especially where legacy C libraries are wrapped by C++ classes.


Uninitialized pointers: the fastest way to hit a segfault

Sometimes the problem isn’t that you freed memory; it’s that you never allocated it in the first place. This example of segmentation fault in dynamic memory allocation uses a pointer as if it pointed to valid heap memory, even though it doesn’t.

#include <stdio.h>

int main(void) {
    int *p;       // uninitialized pointer

    *p = 10;      // writing to an indeterminate address
    printf("%d\n", *p);
    return 0;
}

On most systems, this will immediately produce a segmentation fault because p holds a garbage address. A more realistic 2024‑style bug looks like this:

#include <stdlib.h>

void init_array(int **arr, size_t n) {
    // BUG: forgot to allocate
    for (size_t i = 0; i < n; ++i) {
        (*arr)[i] = (int)i;  // dereferencing uninitialized pointer
    }
}

int main(void) {
    int *arr = NULL;
    init_array(&arr, 5);  // crashes inside init_array
    return 0;
}

Here, the function looks like it’s responsible for initialization, but the allocation is missing. These are the kinds of real examples of segmentation fault in dynamic memory allocation that show up during code review in growing teams.


Out‑of‑bounds indexing on dynamically allocated arrays

Another example of segmentation fault in dynamic memory allocation appears when a loop index runs past the allocated size. It’s boring, but it’s everywhere.

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

int main(void) {
    size_t n = 5;
    int *arr = malloc(n * sizeof(int));
    if (!arr) return 1;

    for (size_t i = 0; i <= n; ++i) {  // BUG: should be i < n
        arr[i] = (int)i * 2;          // writes out of bounds when i == n
    }

    printf("%d\n", arr[0]);
    free(arr);
    return 0;
}

That single <= instead of < is responsible for a huge number of real examples of segmentation fault in dynamic memory allocation. Under sanitizers, you’ll see a precise error message; without them, you might only see a crash under certain inputs or platform configurations.

In high‑performance code (think financial trading systems or scientific computing libraries), this kind of off‑by‑one error can corrupt data silently before finally tripping a segmentation fault somewhere completely different.


Realloc pitfalls: examples include lost pointers and dangling references

realloc is powerful and dangerous. It can move your buffer, shrink it, or fail and leave you with the old pointer. Misusing it creates some of the more subtle examples of segmentation fault in dynamic memory allocation.

Losing the only pointer

#include <stdlib.h>

int main(void) {
    int *arr = malloc(5 * sizeof(int));
    if (!arr) return 1;

    // BUG: assigning directly to arr can lose the original pointer
    arr = realloc(arr, 10 * sizeof(int));
    if (!arr) {
        // original pointer is lost; memory leak, potential later misuse
        return 1;
    }

    // ... use arr ...
    free(arr);
    return 0;
}

This specific snippet is more about leaks than segfaults, but in real projects, people sometimes try to use arr even if realloc fails and returns NULL, which can then lead to a segmentation fault.

Dangling pointers after realloc

A more direct example of segmentation fault in dynamic memory allocation is keeping old pointers into a buffer that has been moved:

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

int main(void) {
    size_t n = 5;
    int *arr = malloc(n * sizeof(int));
    if (!arr) return 1;

    for (size_t i = 0; i < n; ++i) arr[i] = (int)i;

    int *middle = &arr[2];  // pointer into the middle of the array

    // may move the buffer to a new location
    int *tmp = realloc(arr, 20 * sizeof(int));
    if (!tmp) {
        free(arr);
        return 1;
    }
    arr = tmp;

    // BUG: middle still points to old location, now invalid
    printf("%d\n", *middle);  // undefined behavior, often segfault

    free(arr);
    return 0;
}

This is one of the best examples of segmentation fault in dynamic memory allocation that shows how pointer aliasing and buffer growth can interact badly.


Multithreaded heap misuse: modern, production‑grade failures

In 2024 and 2025, more C and C++ code is multithreaded than ever. That gives us a new category of real examples of segmentation fault in dynamic memory allocation: race conditions around the heap.

Imagine a shared object that one thread frees while another thread is still using it:

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

int *shared = NULL;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void *worker1(void *arg) {
    pthread_mutex_lock(&lock);
    shared = malloc(sizeof(int));

    *shared = 123;
    pthread_mutex_unlock(&lock);
    return NULL;
}

void *worker2(void *arg) {
    pthread_mutex_lock(&lock);
    int *local = shared;
    pthread_mutex_unlock(&lock);

    // Simulate some work without holding the lock
    if (local) {
        // Another thread might free 'shared' here in real code
        printf("Value: %d\n", *local);  // potential use‑after‑free
    }
    return NULL;
}

This simplified sketch hints at a pattern: the lifetime of shared isn’t clearly owned by any single thread. In real systems (servers, databases, browsers), similar patterns produce some of the hardest‑to‑reproduce examples of segmentation fault in dynamic memory allocation.

Organizations like the Linux Foundation and academic researchers regularly analyze these bugs in large codebases; if you want to see real‑world data, check out memory safety research from universities such as MIT or Stanford (MIT CSAIL).


How to catch these examples early in 2024–2025

The good news: the tooling story has improved. If you’re tired of collecting your own personal catalog of examples of segmentation fault in dynamic memory allocation, modern sanitizers and analyzers help a lot.

Some practical steps:

  • Compile with AddressSanitizer: On Clang or GCC, -fsanitize=address -g -O1 immediately flags heap overflows, use‑after‑free, and many of the examples we’ve discussed.
  • Use Valgrind on Linux: valgrind --leak-check=full ./your_program can detect invalid reads/writes, use‑after‑free, and double frees.
  • Enable static analysis: Tools like clang-tidy or commercial analyzers can spot suspicious patterns before runtime.
  • Adopt safer abstractions: In C++, prefer std::vector, std::string, and smart pointers (std::unique_ptr, std::shared_ptr) over manual new/delete.
  • Consider memory‑safe languages: For new components, many teams are moving performance‑sensitive code to Rust or using safer subsets of C++ to reduce the number of real examples of segmentation fault in dynamic memory allocation they have to debug.

The National Institute of Standards and Technology (NIST) maintains resources on software assurance and memory safety that are worth browsing if you’re working on long‑lived systems (NIST Software Assurance).


FAQ: common questions about segmentation faults and dynamic memory

What are some common examples of segmentation fault in dynamic memory allocation?

Common examples include:

  • Writing past the end of a heap buffer (off‑by‑one errors, missing space for the null terminator).
  • Using memory after it has been freed (use‑after‑free).
  • Freeing the same pointer twice (double free) or mixing new/delete with malloc/free.
  • Dereferencing uninitialized or NULL pointers that were supposed to point to allocated memory.
  • Keeping stale pointers into a buffer that has been reallocated and moved.

These are the best examples to study if you want to recognize patterns that lead to segmentation faults.

Can a memory leak cause a segmentation fault by itself?

A pure leak (memory that is allocated and never freed) usually does not cause an immediate segmentation fault. The program just uses more and more memory. However, in long‑running processes, leaks can push the system into low‑memory conditions. At that point, future allocations may fail, and if the code doesn’t check for NULL or exceptions, you can absolutely end up with a segmentation fault. So while a leak is not a direct example of segmentation fault in dynamic memory allocation, it often sets the stage for one.

How do I debug a segmentation fault from dynamic memory allocation?

Start by running under a debugger (like gdb or lldb) to get a stack trace. Then recompile with symbols and sanitizers enabled. For many of the real examples of segmentation fault in dynamic memory allocation shown above, AddressSanitizer will immediately tell you if it’s a heap‑buffer‑overflow, use‑after‑free, or double free, and point to the exact line. Combine that with static analysis and code review to find the underlying lifetime or ownership mistake.

Is using malloc and free always a bad idea in 2025?

Not inherently. They’re still standard C APIs and power a lot of high‑performance software. The problem is that manual memory management is error‑prone, and the examples of segmentation fault in dynamic memory allocation we’ve walked through are evidence of how easy it is to get wrong. In new C++ code, prefer higher‑level abstractions; in C, encapsulate allocation and deallocation behind clear interfaces and test them aggressively.

Where can I learn more about memory safety and segmentation faults?

For deeper reading on memory safety and debugging patterns similar to these examples of segmentation fault in dynamic memory allocation, look at:

  • University systems programming courses, such as those published by major CS departments (Harvard CS50).
  • Official compiler documentation for sanitizers (Clang, GCC).
  • Security guidance from agencies like CISA and NIST, which increasingly highlight memory safety as a major risk factor.

Studying real bugs from open source projects is also a great way to see how these patterns appear in production‑grade code.

Explore More Segmentation Faults

Discover more examples and insights in this category.

View All Segmentation Faults