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
NULLpointer - 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
NULLpointer 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.
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:
-
int *p = malloc(sizeof(int));- Memory for one
intis requested from the heap. - If successful,
pstores the address of that memory.
- Memory for one
-
if (p == NULL)- The program checks whether allocation failed.
- If allocation failed, it exits safely.
-
*p = 7;- The value
7is written into the allocated memory. - This is valid because
pcurrently points to live memory.
- The value
-
free(p);- The memory is released back to the system allocator.
pstill contains the old address, but that address is no longer valid to use.pis now a dangling pointer.
-
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.
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::vectorinstead of manual dynamic arraysstd::stringinstead of raw character buffersstd::unique_ptrandstd::shared_ptrfor 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
gdborlldb - 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
| Concept | What it means | Same as a segmentation fault? |
|---|---|---|
| Segmentation fault | OS stops program for invalid memory access | Yes |
| Undefined behavior | Program does something the language does not define | No, but it can lead to a segmentation fault |
| Dangling pointer | Pointer refers to memory that is no longer valid | No, but using it can cause a segmentation fault |
| Null pointer dereference | Program dereferences NULL | Not the same term, but often causes a segmentation fault |
| Buffer overflow / out-of-bounds access | Access beyond valid array or buffer limits | Not always, but often leads to one |
| Memory leak | Allocated memory is never freed | No, usually does not directly cause a segmentation fault |
C vs C++
| Topic | C | C++ |
|---|---|---|
| Can invalid memory access happen? | Yes | Yes |
| Can dangling pointers exist? | Yes | Yes |
| Manual allocation examples | malloc / free | new / delete |
| Safer standard tools | Fewer built-in ownership abstractions | RAII, smart pointers, containers |
| Meaning of segmentation fault | Same OS-level crash type | Same OS-level crash type |
Dangling pointer vs null pointer
| Pointer type | What it points to | Safe to dereference? |
|---|---|---|
| Valid pointer | Live memory | Usually yes |
NULL pointer | No object | No |
| Dangling pointer | Old invalid memory | No |
A null pointer is clearly empty. A dangling pointer is more dangerous because it may look like a real address.
Cheat Sheet
- Segmentation fault: program tried to access memory it was not allowed to access.
- Often shown as:
Segmentation faultorSIGSEGV - Common causes:
- dereferencing
NULL - dereferencing uninitialized pointers
- use after
free/delete - out-of-bounds array access
- writing to read-only memory
- stack overflow
- dereferencing
- 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
NULLafterfreewhen 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.
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
NULLafter freeing it. - Avoid dereferencing the pointer after it has been freed.
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.