CMD Simulator
Memory Managementsegmentation fault

Segmentation Fault in C - Complete Guide to Causes and Fixes

Learn what a segmentation fault (segfault) is in C, the most common causes like null pointer dereference and buffer overflows, and how to debug them effectively.

Rojan Acharya··Updated Mar 29, 2026
Share

A segmentation fault (often abbreviated as segfault) in C is a specific error caused by a program attempting to read or write to a memory location that the operating system has not granted it access to. This memory protection mechanism immediately terminates the program, usually outputting the terminal message Segmentation fault (core dumped). The most common culprits include dereferencing a NULL pointer, accessing out-of-bounds array indices, or writing to read-only memory.

Whether you're developing high-throughput network applications, writing low-level system drivers, or simply completing a university C programming assignment, encountering segmentation faults is an unavoidable rite of passage. Because C gives developers raw, unrestricted control over memory via pointers, the operating system serves as the final, unforgiving safeguard against memory corruption.

This comprehensive guide dissects exactly what a segmentation fault is under the hood, provides detailed examples of the code patterns that cause them, explains how to use debuggers like GDB and AddressSanitizer to track them down, and outlines professional best practices to write crash-free C code.

What Is a Segmentation Fault in C?

Modern operating systems utilize an architectural concept called virtual memory to isolate programs from one another. Every running C program (a process) is assigned its own private, isolated virtual address space. This space is divided into memory segments: the stack (local variables), the heap (dynamic variables), the data segment (global variables), and the text segment (executable code).

When your C program executes a memory read or write instruction (dereferencing a pointer or accessing an array), the CPU's Memory Management Unit (MMU) translates the virtual address into a physical RAM address. If the program attempts to access an address outside its legally allocated segments, or attempts a forbidden operation—such as writing to the read-only text segment—the MMU throws a hardware exception.

The operating system catches this exception, recognizes that the program has committed an illegal memory access, and instantly terminates the process to protect the rest of the system. The OS sends a signal called SIGSEGV (Signal 11) to your program, resulting in the infamous Segmentation fault error message. While frustrating, segfaults are actually a critical security and stability feature; without them, a buggy C program could silently overwrite the memory of other applications or the OS itself.

Common Causes and Mechanisms

While a segmentation fault represents a singular OS-level event, it can be triggered by a wide variety of C programming mistakes.

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

int main() {
    // 1. Dereferencing a NULL pointer (Most common cause)
    int *ptr = NULL;
    // *ptr = 100; // CRASH: Segmentation fault
    
    // 2. Writing to Read-Only memory
    char *str = "Hello";
    // str[0] = 'h'; // CRASH: Segmentation fault (Text segment is read-only)
    
    return 0;
}

Memory Access Violation Table

Violation TypeC Code ExampleWhy It Segfaults
Null Pointer Dereferenceint *p = NULL; *p = 5;Address 0 is strictly unmapped by the OS to catch initialization errors.
Out of Bounds Accessarr[10000] = 5;Accessing memory far outside the allocated stack/heap boundary.
Dangling Pointerfree(p); *p = 5;Accessing a heap block that the allocator returned to the OS.
Stack OverflowInfinite recursionThe stack grows beyond its maximum OS limit, hitting unmapped memory.
Read-Only Writechar *s = "Hi"; s[0]='A';Writing to string literals stored in the immutable .rodata segment.

Examples of Segmentation Fault Scenarios

1. Dereferencing an Uninitialized Pointer (Wild Pointer)

If you declare a pointer but forget to point it at a valid variable or allocate memory for it, it contains garbage data left over on the stack.

int *wild_ptr;
// *wild_ptr = 42; // ERROR: Segmentation fault!

Explanation: The pointer holds a random hexadecimal address. Dereferencing it attempts to write 42 to an arbitrary location in memory, which the OS almost certainly blocks.

2. The Dangling Pointer Use-After-Free

When you free() a pointer, the memory block is reclaimed. If you access it later, the program segfaults.

int *heap_ptr = malloc(sizeof(int));
free(heap_ptr);
// *heap_ptr = 99; // ERROR: Segmentation fault (or silent corruption)

Explanation: The allocator unmapped the memory page. Read or write access via heap_ptr generates an instant SIGSEGV.

3. Accessing Arrays Severely Out of Bounds

C arrays do not perform bounds checking. Small out-of-bounds accesses might silently corrupt adjacent variables, but large ones guarantee a segfault.

int buffer[10];
// buffer[10000] = 5; // ERROR: Segmentation fault

Explanation: Stepping 10,000 integers past the end of buffer pushes the program execution totally off the valid stack segment and into unmapped territory.

4. Stack Overflow via Infinite Recursion

The stack is a finite memory segment (often 8MB on Linux). Infinite recursion consumes all of it.

void infinite() {
    int large_array[1024]; // Consume more stack space
    infinite();
}

int main() {
    // infinite(); // ERROR: Segmentation fault (Stack Overflow)
    return 0;
}

Explanation: Every function call allocates a new stack frame. When the stack hits its hard limit, the OS denies further allocation, causing a segfault.

5. Writing to String Literals

String literals declared with char * are inherently read-only in C.

char *greeting = "LearnMandu";
// greeting[0] = 'l'; // ERROR: Segmentation fault

Explanation: The compiler places "LearnMandu" in the read-only data segment (.rodata). Trying to mutate it is a hardware-level violation. To fix, use an array: char greeting[] = "LearnMandu";.

Common Use Cases Where Segfaults Occur

Segmentation faults often manifest in specific, complex software architectures where pointer math bounds are difficult to track.

  1. String Manipulation: Writing custom strlen or strcpy functions frequently results in reading or writing past the null terminator \0, sliding off the end of valid memory blocks.
  2. Linked Data Structures: Traversing linked lists or trees without meticulously checking if node != NULL before accessing node->next guarantees a NULL pointer dereference.
  3. File Parsing: When parsing complex binary files or network packets, miscalculating offsets can cause pointers to jump wildly out of the bounds of the loaded buffer.
  4. Multithreaded Race Conditions: If one thread frees a shared chunk of memory while another thread is simultaneously trying to read it, the reader thread will instantly segfault.
  5. Dynamic Library Loading (dlopen): If you load a shared library but fail to properly cast the function pointers returned by dlsym(), calling them executes arbitrary, unmapped memory.
  6. Command Line Arguments (argv): Accessing argv[2] without first checking if argc > 2 is a classic newbie segfault, as argv[2] will be NULL.
  7. scanf Formatting Errors: Passing variable values instead of their addresses (e.g., scanf("%d", num) instead of scanf("%d", &num)) tells scanf to write memory to the address equal to num's current value, crashing instantly.

Tips and Best Practices to Prevent Segfaults

  1. Initialize Pointers Immediately: Never leave a pointer wild. Initialize them to NULL if you aren't allocating memory for them yet: int *ptr = NULL;.
  2. Check for NULL Always: Before jumping into a linked list node or processing a malloc return value, perform a strict null-check. if (ptr == NULL) return ERROR;.
  3. Set Freed Pointers to NULL: Eradicate use-after-free segfaults by permanently pairing free() with nullification. free(ptr); ptr = NULL;.
  4. Use Arrays for Mutable Strings: If you intend to alter a string's characters, declare it as a stack array (char str[] = "text";) or dynamically allocate it (strdup), never as a literal pointer.
  5. Prefer Safer Standard Functions: Function variations that enforce bounds, such as strncpy, snprintf, and strncat, inherently prevent buffer overruns that lead to segmentation faults.
  6. Mind Your Array Indices: Off-by-one errors (e.g., for (int i = 0; i <= size; i++)) often access the first byte past the array. Ensure loop conditions are strictly i < size.
  7. Understand scanf Pointers: Always pass the memory address operator & to scanf for non-pointer types to ensure it writes to the correct stack location.
  8. Test Edge Cases Thoroughly: A function might work perfectly on typical data but segfault when passed an empty string or a 0-length buffer. Test limits aggressively.

Troubleshooting Common Issues

Catching the Segfault with GDB

Problem: The program prints Segmentation fault (core dumped) and exits. You have no idea which line caused it. Cause: The OS killed the program silently. Solution: Compile your code with debugging symbols (gcc -g main.c). Run the program inside the GNU Debugger: gdb ./a.out. Type run. When the segfault happens, GDB halts execution and shows the exact file and line number. Type backtrace (or bt) to see the function call stack that led to the crash.

Utilizing AddressSanitizer (ASan)

Problem: The segfault ONLY happens sometimes, or GDB shows the crash occurring inside a generic malloc loop. Cause: The memory corruption (like a buffer overflow) happened silently earlier, and the segfault was merely a delayed symptom. Solution: Compile with -fsanitize=address -g. AddressSanitizer adds runtime checks that halt the program the instant an illegal memory read/write occurs, not when it eventually crashes the heap.

Valgrind for Memory Tracking

Problem: The segfault is caused by a complex Use-After-Free scenario spread across thousands of lines. Cause: Dangling pointers logic errors. Solution: Run valgrind ./a.out. Valgrind acts as a virtual CPU that detects "Invalid read of size X" and tells you exactly where the memory was originally explicitly freed.

Core Dump Files Not Generating

Problem: The terminal says Segmentation fault, but no core file appears. Cause: Your operating system limits core dump sizes by default. Solution: Run ulimit -c unlimited in your shell session. Run the application again. A core file will generate, which you can load into GDB (gdb ./a.out core) to inspect the offline crash state.

Related Commands and Concepts

SIGSEGV (Signal 11)

The POSIX signal sent to a process when it makes an invalid memory reference. You can technically write a signal handler in C to catch SIGSEGV and print a custom error before dying, but you cannot safely resume execution.

Buffer Overflows

Writing past the end of an array. If a buffer overflow is small, it corrupts adjacent variables. If it is large enough to hit an unmapped memory page, it immediately triggers a segmentation fault.

Null Pointer Dereference

The act of attempting to access the value at address 0 (or NULL). This is the absolute most frequent source of segmentation faults in all of C programming.

Stack Overflow

When recursive function calls exhaust the maximum contiguous memory block allocated for the stack thread, the program hits a "guard page," which strictly forces a segmentation fault to halt the runaway iteration.

Frequently Asked Questions

Why is it called a "Segmentation" fault?

The term originates from older computer architectures, which utilized actual physical memory "segments" for isolation. Modern operating systems use "paging" instead of true segmentation, but the historical term stuck for any invalid memory access.

Can a Segmentation Fault damage my computer hardware?

No. Operating systems are specifically designed to isolate and kill crashing programs. A segfault in a user-space C application cannot damage your RAM, your hard drive, or the OS kernel itself.

How do I find exactly which line caused a Segmentation Fault?

You must use a debugger. Compile your code with the -g flag (e.g., gcc -g program.c), run it within GDB (gdb ./a.out), execute it (run), and when it crashes, the debugger will point to the exact offending line of code.

Does printf() cause Segmentation Faults?

Yes, frequently. If you use the %s format specifier to print a string, but pass it an uninitialized pointer, a dangling pointer, or NULL, printf will attempt to dereference it to read characters, triggering an immediate crash.

How do I fix a Segmentation Fault in my code?

You must identify why the pointer is invalid. Track the pointer's lifecycle back to its creation. Ensure it was properly allocated (malloc), check that bounds were respected during loops, and verify you didn't accidentally overwrite it.

Why does my program segfault sometimes, but not always?

This indicates an uninitialized pointer (wild pointer) or a subtle out-of-bounds array read. Because memory layout changes slightly each time a program runs (Address Space Layout Randomization - ASLR), the garbage data or out-of-bounds hit might coincidentally land on a valid memory page during some executions, and an invalid one during others.

Can I catch a segmentation fault in C?

Yes, using the signal() or sigaction() functions from <signal.h>. You can define a custom function to run when SIGSEGV is received to perform emergency logging. However, it is fundamentally impossible to safely recover from a segfault; the program must exit.

What is a "core dumped" message?

When a segfault occurs, the OS writes the entire contents of the program's RAM, CPU registers, and stack trace to a file on the disk called a "core dump." Developers use this snapshot to perform post-mortem debugging.

Quick Reference Card

Fault CauseFix / Correct Syntax
Null Pointerif (ptr == NULL) return;
Wild PointerInitialize at variable declaration: int *p = NULL;
Out of Bounds ArrayStrictly check index < array_size before accessing
Dangling Pointerfree(p); p = NULL;
String MutabilityUse char str[] = "text"; instead of char *str = "text";
scanf Syntax Errorscanf("%d", &num); (Always pass the & address)
Debug Compilationgcc -g -O0 -fsanitize=address main.c

Summary

A segmentation fault (SIGSEGV) is an operating system's emergency response mechanism. When a C program attempts to dereference a NULL pointer, access array elements wildly out of bounds, write to read-only string literals, or utilize memory that has already been freed, the system hardware intercepts the illegal translation and terminates the process immediately.

Because C trusts developers entirely with raw memory addressing, avoiding segmentation faults requires immense discipline. Most faults stem from logical flaws in pointer lifecycles or off-by-one errors in buffer iterations. Developing an instinct to defensively null-check every pointer, paired with the habit of compiling code using AddressSanitizer (-fsanitize=address) or relentlessly testing via Valgrind, is the only sustainable strategy.

When a crash inevitably happens, relying strictly on "printf debugging" is insufficient. Mastery over GDB—running the code to generate precise stack traces—is the hallmark of a professional C developer. Tracking down and closing the memory leaks, out-of-bounds arrays, and dangling pointers behind segfaults ultimately yields high-performance, rock-solid applications.