Question

What Is a Segmentation Fault in C and C++?

ccppsegmentation-fault

Question

What is a segmentation fault, and what does it mean when a program crashes with one?

Is a segmentation fault different in C and C++, or is it the same kind of error in both languages?

How are segmentation faults related to dangling pointers and invalid memory access?

Short Answer

By the end of this page, you will understand what a segmentation fault is, why it happens in C and C++, and how pointer mistakes such as dangling pointers can lead to crashes. You will also see common examples, debugging patterns, and practical ways to avoid these errors in real programs.

Concept

A segmentation fault (often shown as Segmentation fault or SIGSEGV) happens when a program tries to access memory that it is not allowed to use.

This is usually an operating system-level protection mechanism. Your program runs inside its own memory space, and the OS prevents it from reading or writing memory outside the valid regions assigned to it.

Common causes include:

  • dereferencing a NULL pointer
  • dereferencing an uninitialized pointer
  • using a pointer after the memory it points to has been freed
  • writing past the end of an array
  • writing to read-only memory
  • deep recursion that overflows the stack

In both C and C++, the underlying issue is the same: invalid memory access. The languages themselves do not define a special "segmentation fault" feature. Instead, they allow low-level memory operations, and if your program performs an illegal access, the operating system may terminate it with a segmentation fault.

So the short answer is:

  • In C and C++, a segmentation fault means the same kind of problem.
  • It is usually caused by undefined behavior involving memory.
  • A dangling pointer is one common source of such invalid access.

Why this matters in real programming:

  • Memory bugs are often hard to reproduce.
  • Some invalid accesses crash immediately.
  • Others silently corrupt data and fail later.
  • Understanding segmentation faults helps you debug pointer-heavy code safely and faster.

A key detail: not every invalid memory operation causes a segmentation fault. Sometimes a program may appear to work, crash later, or produce wrong output. That unpredictability is part of undefined behavior.

Mental Model

Think of your program's memory like a building with many rooms.

  • Some rooms belong to your program.
  • Some rooms are locked.
  • Some rooms used to be available, but the key was returned.

A segmentation fault happens when your program tries to:

  • enter a locked room
  • enter a room that does not exist
  • keep using a room after giving it back

A pointer is like a room number.

  • A valid pointer points to a room your program can use.
  • A NULL pointer is like saying "no room".
  • A dangling pointer is an old room number that used to work, but the room is no longer yours.

If you follow a dangling pointer, you are trusting an address that is no longer valid. Sometimes the OS catches this and stops the program with a segmentation fault. Sometimes it does not crash immediately, which makes the bug dangerous.

Take Quiz

Syntax and Examples

Common examples that can cause a segmentation fault

1. Dereferencing a NULL pointer

#include <stdio.h>

int main(void) {
    int *p = NULL;
    printf("%d\n", *p);  // invalid access
    return 0;
}

p does not point to a real integer. Dereferencing *p tries to read memory through a null address, which often causes a segmentation fault.

2. Using a dangling pointer in C

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

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

    *p = 42;
    free(p);

    printf("%d\n", *p);  // undefined behavior: p is dangling
    return 0;
}

After free(p), the memory is no longer valid for use. p still holds the old address, so it becomes a dangling pointer.

3. Using a dangling pointer in C++

#include <iostream>

int main() {
    int* p = new int(42);
    delete p;

    std::cout << *p << '\n';  // undefined behavior: p is dangling
    return 0;
}

After delete p, the pointer no longer points to usable memory.

4. Writing past the end of an array

#include <stdio.h>

int main(void) {
    int numbers[3] = {10, 20, 30};
    numbers[5] = 99;  // out-of-bounds write
    printf("done\n");
    return 0;
}

This writes outside the array. It may crash, corrupt nearby memory, or appear to work. It is still undefined behavior.

Safer habits

C

#include <stdlib.h>

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

    *p = 42;
    free(p);
    p = NULL;  // avoid accidental reuse

    return 0;
}

C++

#include <iostream>
#include <memory>

int main() {
    auto p = std::make_unique<int>(42);
    std::cout << *p << '\n';
    return 0;
}

In modern C++, smart pointers such as std::unique_ptr help prevent many manual memory errors.

Step by Step Execution

Consider this C example:

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

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

    *p = 7;
    free(p);
    printf("%d\n", *p);
    return 0;
}

Step by step:

  1. int *p = malloc(sizeof(int));

    • Memory for one int is requested from the heap.
    • If successful, p stores the address of that memory.
  2. if (p == NULL)

    • The program checks whether allocation failed.
    • If allocation failed, it exits safely.
  3. *p = 7;

    • The value 7 is written into the allocated memory.
    • This is valid because p currently points to live memory.
  4. free(p);

    • The memory is released back to the system allocator.
    • p still contains the old address, but that address is no longer valid to use.
    • p is now a dangling pointer.
  5. printf("%d\n", *p);

    • The program dereferences a dangling pointer.
    • This is undefined behavior.
    • Possible outcomes:
      • segmentation fault
      • garbage output
      • apparently correct output by accident
      • crash later somewhere else

The important lesson is that the bug starts at free(p) followed by continued use of p, not at printf alone. The crash may appear later than the actual mistake.

Real World Use Cases

Understanding segmentation faults is useful in many real situations:

Systems programming

Operating systems, drivers, embedded software, and performance-sensitive tools often use C or C++. These programs frequently manage memory directly, so invalid access bugs matter a lot.

Native libraries and game engines

Large C++ codebases often use raw memory, custom allocators, or low-level buffers. Out-of-bounds writes and use-after-free bugs can cause intermittent crashes.

Interfacing with hardware or binary data

Programs that parse files, network packets, or hardware input often use pointers and arrays. A wrong offset or invalid pointer can lead to memory faults.

Debugging production crashes

A user may report that a CLI tool or server process crashed with Segmentation fault. Knowing what that means helps narrow the cause to memory misuse, stack overflow, or invalid pointer operations.

Security

Memory access bugs are not just crash bugs. Buffer overflows and use-after-free bugs can become security vulnerabilities if attackers can influence memory layout or input.

Take Quiz

Real Codebase Usage

In real projects, developers try to structure code so invalid memory access is less likely.

Common patterns

Guard clauses

Check pointers before use when NULL is possible.

if (buffer == NULL) {
    return -1;
}

This does not solve every memory problem, but it prevents some obvious crashes.

Ownership rules

Teams decide clearly:

  • who allocates memory
  • who frees memory
  • how long data must stay alive

Many bugs happen when ownership is unclear.

Reset pointers after freeing

In C, a common defensive habit is:

free(p);
p = NULL;

This does not fix aliases to the same memory, but it reduces accidental reuse through that variable.

Prefer containers and RAII in C++

Real C++ projects often avoid raw new and delete in application code.

  • std::vector instead of manual dynamic arrays
  • std::string instead of raw character buffers
  • std::unique_ptr and std::shared_ptr for ownership
  • stack objects where possible

Bounds-aware code

Developers use sizes together with buffers and check indexes carefully.

if (index >= values.size()) {
    return;
}

Debugging tools

Real codebases often use:

  • compiler warnings
  • AddressSanitizer
  • Valgrind
  • debuggers such as gdb or lldb
  • static analysis tools

These tools can detect use-after-free, double free, and out-of-bounds access much faster than manual inspection.

Common Mistakes

1. Assuming every bad pointer causes an immediate segmentation fault

Broken idea:

int *p;
printf("%d\n", *p);

This is undefined behavior, but it may not always crash the same way. Do not judge correctness by whether it crashes.

2. Using memory after free or delete

Broken code in C:

int *p = malloc(sizeof(int));
*p = 10;
free(p);
*p = 20;  // use after free

Broken code in C++:

int* p = new int(10);
delete p;
std::cout << *p << '\n';

Avoid it by treating freed memory as unusable immediately.

3. Returning pointers to local variables

Broken code:

int* bad_function(void) {
    int x = 5;
    return &x;  // x stops existing after the function returns
}

x lives on the stack and is destroyed when the function ends. The returned pointer becomes dangling.

4. Writing outside array bounds

Broken code:

int arr[3] = {1, 2, 3};
arr[3] = 4;  // valid indexes are 0, 1, 2

Always track valid index ranges carefully.

5. Confusing NULL checks with full safety

This is not enough:

if (p != NULL) {
    printf("%d\n", *p);
}

A dangling pointer is often not NULL. It can still hold a non-null address that is invalid.

6. Double free

Broken code:

int *p = malloc(sizeof(int));
free(p);
free(p);  // undefined behavior

After freeing, set the pointer to NULL if that variable might be reused.

7. Thinking the fault is a C-only or C++-only error

Segmentation faults are not language-specific features. Both languages can trigger them because both allow low-level memory access.

Comparisons

Segmentation fault vs related ideas

ConceptWhat it meansSame as a segmentation fault?
Segmentation faultOS stops program for invalid memory accessYes
Undefined behaviorProgram does something the language does not defineNo, but it can lead to a segmentation fault
Dangling pointerPointer refers to memory that is no longer validNo, but using it can cause a segmentation fault
Null pointer dereferenceProgram dereferences NULLNot the same term, but often causes a segmentation fault
Buffer overflow / out-of-bounds accessAccess beyond valid array or buffer limitsNot always, but often leads to one
Memory leakAllocated memory is never freedNo, usually does not directly cause a segmentation fault

C vs C++

TopicCC++
Can invalid memory access happen?YesYes
Can dangling pointers exist?YesYes
Manual allocation examplesmalloc / freenew / delete
Safer standard toolsFewer built-in ownership abstractionsRAII, smart pointers, containers
Meaning of segmentation faultSame OS-level crash typeSame OS-level crash type

Dangling pointer vs null pointer

Pointer typeWhat it points toSafe to dereference?
Valid pointerLive memoryUsually yes
NULL pointerNo objectNo
Dangling pointerOld invalid memoryNo

A null pointer is clearly empty. A dangling pointer is more dangerous because it may look like a real address.

Take Quiz

Cheat Sheet

  • Segmentation fault: program tried to access memory it was not allowed to access.
  • Often shown as: Segmentation fault or SIGSEGV
  • Common causes:
    • dereferencing NULL
    • dereferencing uninitialized pointers
    • use after free / delete
    • out-of-bounds array access
    • writing to read-only memory
    • stack overflow
  • Dangling pointer: a pointer that still stores an address after the object or memory is no longer valid.
  • Using a dangling pointer is undefined behavior.
  • Undefined behavior may:
    • crash immediately
    • crash later
    • print garbage
    • appear to work
  • In C and C++, segmentation faults mean the same kind of invalid memory access at runtime.

Quick examples

int *p = NULL;
*p = 5;  // likely segmentation fault
int *p = malloc(sizeof(int));
free(p);
*p = 5;  // dangling pointer use
int a[3];
a[5] = 10;  // out-of-bounds write

Safer habits

  • initialize pointers
  • check allocation results
  • do not use memory after freeing it
  • set pointer to NULL after free when helpful
  • avoid raw memory management in C++ when possible
  • prefer std::vector, std::string, and smart pointers
  • use sanitizers and debuggers

FAQ

What does a segmentation fault mean?

It means the program tried to access memory in an invalid way, and the operating system stopped it.

Is a segmentation fault the same in C and C++?

Yes. In both languages, it usually comes from invalid memory access such as bad pointers or out-of-bounds writes.

Does every dangling pointer cause a segmentation fault?

No. Using a dangling pointer is undefined behavior. It might crash, print garbage, or seem to work temporarily.

Is a segmentation fault a compiler error?

No. It is usually a runtime crash, not a compile-time error.

Can array index mistakes cause segmentation faults?

Yes. Accessing outside array bounds can corrupt memory or trigger a segmentation fault.

Is NULL the same as a dangling pointer?

No. NULL means no valid object is pointed to. A dangling pointer holds an old address that used to be valid.

How do I debug a segmentation fault?

Use a debugger such as gdb or lldb, enable compiler warnings, and run tools like AddressSanitizer or Valgrind.

Can memory leaks cause segmentation faults?

Not directly in most cases. A memory leak means memory was not released, while a segmentation fault is invalid memory access.

Take Quiz

Mini Project

Description

Build a small C program that demonstrates safe pointer usage with dynamic memory. The project simulates storing a single integer value, printing it, freeing it correctly, and preventing accidental reuse. This helps reinforce the difference between valid pointers, dangling pointers, and safer cleanup habits.

Goal

Create a program that allocates memory, uses it correctly, frees it safely, and avoids dereferencing invalid pointers.

Requirements

  • Allocate memory for one integer using malloc.
  • Check whether allocation succeeded before using the pointer.
  • Store and print a value through the pointer.
  • Free the memory when finished.
  • Set the pointer to NULL after freeing it.
  • Avoid dereferencing the pointer after it has been freed.
Take Quiz

Keep learning

Related questions

View more