세그먼테이션 오류란 무엇인가?
세그먼테이션 오류(Segmentation Fault), 흔히 '세그폴트(segfault)'라고 부르는 이 오류는 프로그램이 접근 권한이 없는 메모리 영역에 접근하려고 할 때 발생하는 런타임 오류입니다.
운영체제는 실행 중인 각 프로그램(프로세스)에 사용할 수 있는 메모리 범위를 미리 할당해 줍니다. 그런데 프로그램이 이 허용된 범위를 벗어난 메모리를 읽거나 쓰려고 하면, 운영체제가 이를 감지하고 프로그램을 강제로 종료시킵니다. 이때 터미널에는 다음과 같은 메시지가 출력됩니다.
Segmentation fault (core dumped)
세그먼테이션 오류의 주요 원인
세그먼테이션 오류는 대부분 포인터를 잘못 사용할 때 발생합니다. 대표적인 원인은 다음과 같습니다.
- 초기화되지 않은 포인터 사용: 포인터를 선언만 하고 유효한 메모리 주소로 초기화하지 않은 채 역참조(dereference)하면, 어디를 가리키는지 알 수 없는 메모리에 접근하게 됩니다.
- 해제된 메모리 접근 (댕글링 포인터):
free()또는delete로 이미 반환한 메모리를 포인터가 여전히 가리키고 있을 때, 그 포인터를 다시 사용하면 오류가 발생합니다. - 배열 인덱스 범위 초과: 배열의 크기를 벗어난 인덱스로 접근하면, 배열 바깥의 허용되지 않은 메모리 영역을 침범하게 됩니다.
- NULL 포인터 역참조: 아무것도 가리키지 않는 NULL 포인터를 역참조하는 경우에도 세그먼테이션 오류가 발생합니다.
- 스택 오버플로: 종료 조건 없는 재귀 호출처럼 스택 메모리를 과도하게 사용하는 경우에도 발생할 수 있습니다.
오류가 발생하는 코드 예시
#include <stdio.h>
int main(void) {
int *ptr; // 초기화되지 않은 포인터
*ptr = 10; // 세그먼테이션 오류 발생!
return 0;
}
위 코드에서 ptr은 유효한 주소로 초기화되지 않았기 때문에, *ptr = 10;이 실행되는 순간 프로그램이 비정상 종료됩니다.
디버깅 및 예방 방법
- 포인터 선언 시 반드시 초기화하고, 사용 전에 유효성을 확인하세요.
- 메모리 해제 후 포인터에 NULL을 대입하여 댕글링 포인터를 방지하세요.
- 배열 인덱스가 항상 유효 범위 내에 있는지 반복문 조건을 꼼꼼히 점검하세요.
- gdb로 코어 덤프를 분석하면 오류가 발생한 정확한 위치를 찾을 수 있습니다.
- Valgrind나 AddressSanitizer(-fsanitize=address) 같은 도구를 활용하면 메모리 오류를 사전에 잡아낼 수 있습니다.
정리
세그먼테이션 오류는 운영체제가 허용하지 않은 메모리에 프로그램이 접근했음을 알려주는 신호입니다. 대부분 초기화되지 않은 포인터, 해제된 메모리의 재사용, 배열 범위 초과와 같은 포인터 관련 실수에서 비롯되므로, 포인터 사용 습관을 개선하고 디버깅 도구를 적극적으로 활용하면 충분히 예방할 수 있습니다.