Глиф Учебники

Segmentation fault: почему программа падает

Справочник · C++ · 2 минуты чтения

Segmentation fault (ошибка сегментации) — программа обратилась к памяти, которая ей не принадлежит, и система её остановила. Это ошибка при работе, а не при сборке: компилятор её не видит.

Как она выглядит:

Частые причины

1. Выход за границы массива или вектора. Индекс n у массива из n элементов, индекс −1, v[0] у пустого вектора, v.back() у пустого вектора. Проверьте границы всех циклов: i < n, а не i <= n.

2. Большой массив внутри функции. Локальные переменные лежат в стеке, а он небольшой: обычно 8 МБ в Linux и 1 МБ в программах Visual Studio. Массив int a[10000000] (40 МБ) внутри main его переполняет. Решение — объявить массив вне функций (глобальные переменные лежат не в стеке) или взять vector:

C++
#include <iostream>
#include <vector>
using namespace std;

const int N = 10000000;
int a[N];                      // глобальный: не в стеке, сразу заполнен нулями

int main() {
    vector<int> b(N);          // vector хранит элементы в куче
    a[N - 1] = 1;
    b[N - 1] = 2;
    cout << a[N - 1] + b[N - 1] << "\n";
    return 0;
}
Вывод
3

3. Бесконечная или слишком глубокая рекурсия. Нет базы рекурсии или она никогда не достигается — каждый вызов занимает место в стеке, и он кончается. Глубина в сотни тысяч вызовов тоже может переполнить стек даже у правильной функции.

4. Пустой или испорченный указатель. Разыменование nullptr, указателя без начального значения или указателя на уже освобождённую память (после delete).

5. Деление на ноль целых чисел в Linux тоже роняет программу, но с другим сообщением — Floating point exception.

Как найти место ошибки

Санитайзер адресов. В Linux и macOS соберите программу так:

Bash
g++ -std=c++17 -g -fsanitize=address,undefined -o prog prog.cpp
./prog

При выходе за границы программа остановится и напишет, в какой строке файла это случилось. Ключ -g добавляет в программу номера строк. В MinGW для Windows санитайзер обычно не работает; в Visual Studio есть свой — ключ /fsanitize=address.

Проверка индексов вектора. Ключ -D_GLIBCXX_DEBUG (только для g++) заставляет v[i] проверять индекс: при ошибке программа остановится с понятным сообщением. Тот же эффект в коде даёт v.at(i) вместо v[i].

Отладчик gdb (программа, которая запускает вашу и показывает, где она остановилась). Соберите с -g, запустите gdb ./prog, наберите run, а после падения — bt: он покажет цепочку вызовов до строки, где произошла ошибка.

Вывод по шагам. Самый простой способ: выводите промежуточные значения в cerr — поток для сообщений об ошибках, он не задерживает вывод (cerr << i << "\n";), — и смотрите, после какого вывода программа упала.

Выход за границы не всегда роняет программу сразу. Иногда она тихо портит соседние переменные и выдаёт неверный ответ. Если ответ странный, а логика верна, проверьте индексы.