Quick Answer

A segmentation fault means your program touched memory it does not own, so the operating system killed it. The usual causes are dereferencing a null or uninitialised pointer, indexing past the end of an array, using memory after freeing it, stack overflow from runaway recursion, writing to a string literal, and returning a pointer to a local variable. Compile with -g -fsanitize=address and the crash reports the exact line and the reason.

What a Segfault Actually Is

Every process gets its own region of memory. The operating system enforces the boundary. When your program reads or writes outside what it legitimately owns, the OS terminates it immediately with SIGSEGV.

Segmentation fault (core dumped)

That is the entire message — no line number, no variable name. It is a protection mechanism firing, not a compiler diagnostic, which is why it feels so unhelpful.

The important consequence: the crash location is not always the bug location. Writing past the end of an array may corrupt memory that is only used much later, so the program dies somewhere entirely unrelated. This is why adding print statements can be misleading — the corruption already happened.

It is also why a segfault can appear intermittently. Whether out-of-bounds memory happens to be mapped decides whether you crash or silently corrupt data, and that can vary between runs, machines and compilers. A program that "works on my machine" and segfaults on the judge is usually this.

Causes 1 to 3: Pointers

Dereferencing a null pointer. The classic.

int* p = nullptr;
*p = 42;                  // segfault

Node* head = nullptr;
std::cout << head->data;  // segfault — very common in linked list code

Always check before dereferencing anything that might be null, especially when walking a linked structure.

Uninitialised pointers. Worse than null, because the value is whatever rubbish was in that memory.

int* p;        // not initialised — holds garbage
*p = 42;       // writes to a random address

Sometimes this crashes, sometimes it silently corrupts something. Always initialise: int* p = nullptr;.

Use after free. The pointer still holds the old address, but the memory no longer belongs to you.

int* p = new int(5);
delete p;
std::cout << *p;   // undefined behaviour — may print, may crash

delete p;          // double delete — also undefined behaviour

Set the pointer to nullptr after deleting, or better, stop managing raw memory by hand. std::unique_ptr and std::shared_ptr free automatically and cannot be double-deleted, which removes this whole category.

Causes 4 to 6: Bounds, Stack and Literals

Array out of bounds. C++ does not check indexes.

int arr[5];
arr[10] = 1;        // no error, no warning — writes past the array

std::vector<int> v(5);
v[10] = 1;          // operator[] does NOT bounds check either
v.at(10) = 1;       // at() DOES — throws std::out_of_range

The at() distinction is worth internalising: it converts silent memory corruption into a catchable exception with a clear message. Use it while developing.

Off-by-one in loops is the usual trigger — for (int i = 0; i <= n; i++) touches one element past the end.

Stack overflow from recursion. Every call consumes stack space, and the stack is finite.

int f(int n) { return f(n - 1); }   // no base case — segfault, not a crash message

Deep but correct recursion can also overflow. If depth may reach hundreds of thousands, convert to an iterative solution with an explicit stack.

Writing to a string literal. Literals live in read-only memory.

char* s = "hello";   // deprecated: points into read-only memory
s[0] = 'H';          // segfault

char s[] = "hello";  // correct: a modifiable copy on the stack
s[0] = 'H';          // fine

Finding the Line in Under a Minute

Do not guess. Three tools will tell you exactly where and why.

AddressSanitizer is the fastest option and should be your default while developing. It is built into g++ and clang++.

g++ -g -fsanitize=address -fno-omit-frame-pointer main.cpp -o main
./main

Instead of "segmentation fault" you get the offending line, the kind of error, and the allocation it relates to:

ERROR: AddressSanitizer: heap-buffer-overflow on address 0x...
WRITE of size 4 at 0x... thread T0
    #0 0x... in main main.cpp:12
0x... is located 0 bytes to the right of 40-byte region
allocated by thread T0 here:
    #0 0x... in operator new[]

gdb when you need to inspect state at the moment of the crash:

g++ -g main.cpp -o main
gdb ./main
(gdb) run
(gdb) backtrace      # the call chain that led here
(gdb) print p        # inspect any variable

Valgrind catches leaks and uninitialised reads that sanitizers may miss:

valgrind --leak-check=full ./main

The -g flag is essential in all cases — without debug symbols you get addresses instead of line numbers.

Writing Code That Does Not Segfault

Modern C++ exists largely to remove these failure modes. Using it is more effective than debugging harder.

  • Prefer std::vector and std::string to raw arrays and char*. They manage their own memory and know their size.
  • Use smart pointers. std::unique_ptr and std::shared_ptr free automatically, cannot be double-deleted, and make ownership explicit.
  • Use range-based for loops. for (int x : v) cannot go out of bounds because there is no index to get wrong.
  • Initialise everything at declaration. Uninitialised pointers and variables are a large share of intermittent crashes.
  • Never return a pointer or reference to a local. The variable is destroyed when the function returns, leaving a dangling pointer. Return by value — modern compilers optimise the copy away.
  • Turn on warnings. -Wall -Wextra catches many of these at compile time, before they ever run.
g++ -g -Wall -Wextra -fsanitize=address,undefined main.cpp -o main

Make that your standard development command. The undefined-behaviour sanitizer also catches integer overflow and other silent problems that produce wrong answers rather than crashes.

Frequently Asked Questions

What causes a segmentation fault? Accessing memory your process does not own — dereferencing a null or uninitialised pointer, indexing past an array, using memory after freeing it, overflowing the stack through recursion, or writing to a string literal in read-only memory.
Why does my program crash on the judge but work locally? Out-of-bounds access is undefined behaviour, so whether it crashes depends on how memory happens to be laid out. A different compiler, optimisation level or input size changes that. Run with -fsanitize=address to expose it locally.
How do I find which line caused the segfault? Compile with -g -fsanitize=address and run normally — AddressSanitizer reports the exact line and error type. Alternatively run under gdb and use backtrace after the crash to see the call chain.
Does vector operator[] check bounds? No, it behaves like a raw array and silently reads or writes out of range. Use at() instead while developing, which throws std::out_of_range with a clear message rather than corrupting memory.
How do I avoid segfaults in competitive programming? Size arrays with margin, use vector with at() while testing, check loop bounds carefully for off-by-one, and avoid recursion deeper than a few thousand levels. Compile locally with -fsanitize=address before submitting.