[C/C++] 18. 배열

찰규

·

2026년 8월 31일 (오늘)

앞서 재귀 함수의 장단점과 팩토리얼 및 피보나치 수열 구현을 알아보았다. 이번 글에서는 동일한 자료형의 데이터를 묶어 관리하는 배열(Array)의 선언과 메모리 연속성, 0부터 시작하는 인덱스 규칙, 그리고 인덱스 범위 초과(Out of Bounds) 시 발생하는 메모리 오염 위험을 정리한다.

1. 배열(Array)의 개념과 선언

동일한 자료형의 변수가 여러 개 필요할 때, 개별 변수를 매번 선언(int a, b, c...)하는 비효율을 줄이기 위해 사용하는 문법이 배열이다.

  • 선언 문법: 자료형 배열이름[크기];

  • int arr[10];을 선언하면 4바이트 정수형 공간 10개(총 40바이트)가 연속으로 할당된다.

  • 0 초기화: int arr[10] = {};와 같이 중괄호를 비워두면 배열의 모든 요소를 0으로 초기화할 수 있다.

#include <stdio.h>

int main() {
    int arr[10] = {}; // 10개의 int 공간을 모두 0으로 초기화
    
    arr[0] = 10; // 첫 번째 요소에 10 대입
    arr[4] = 50; // 다섯 번째 요소에 50 대입

    printf("arr[0]: %d\n", arr[0]);
    printf("arr[4]: %d\n", arr[4]);
    return 0;
}

2. 제로 기반 인덱스(0-Based Index)

배열의 개별 요소는 대괄호 [] 안에 들어가는 인덱스(Index)를 통해 접근한다.

  • 배열의 인덱스는 항상 0부터 시작한다.

  • 크기가 NN인 배열의 유효 인덱스 범위는 00부터 N1N-1까지다.

    • 크기가 10인 배열 arr[10]의 첫 번째 요소는 arr[0]

    • 마지막(10번째) 요소는 arr[9]

    • arr[4]는 네 번째가 아닌 다섯 번째 요소를 의미한다.

3. 배열의 연속 메모리 구조와 범위 초과 접근(Out of Bounds)

배열의 가장 큰 물리적 특징은 메모리 공간에 빈틈없이 연속적으로 배치된다는 점이다.

array|700

  • 인덱스 범위 초과: 크기가 10인 배열에서 arr[10]이나 arr[20]에 접근하는 것은, 배열에 할당된 40바이트 경계를 넘어 다른 변수가 사용 중인 메모리 영역을 강제로 침범하는 행위다.

  • 메모리 오염(Data Corruption): C/C++ 컴파일러는 실행 속도를 위해 배열 접근 시 경계 검사를 강제하지 않는 경우가 많다. 따라서 잘못된 인덱스 접근이 즉시 에러를 내지 않고, 인접한 다른 변수의 값을 멋대로 덮어씌워(오염시켜) 원인을 찾기 극도로 어려운 버그를 유발한다.

  • 빌드 모드별 차이: 디버그(Debug) 모드에서는 런타임 에러로 감지될 수 있지만, 릴리즈(Release) 모드에서는 오류 없이 실행되다가 프로그램이 돌연 비정상 종료(Crash)될 수 있어 각별한 주의가 필요하다.

4. 포인터(Pointer) 학습과의 연계성

배열은 내부적으로 시작 메모리 주소를 기반으로 오프셋(거리)을 계산하여 각 요소에 접근하는 방식으로 동작한다.

이러한 메모리 참조 방식은 C/C++의 핵심이자 난관인 포인터(Pointer) 개념과 직접적으로 연결된다. 배열의 연속 메모리 구조를 명확히 이해해 두어야 추후 포인터 연산과 주소 참조 문법을 흔들림 없이 학습할 수 있다.

마무리하며

  • 배열은 동일한 타입의 변수들을 메모리에 연속적으로 할당하여 관리하는 문법이다.

  • 인덱스는 0부터 시작하므로 크기 NN인 배열의 마지막 인덱스는 N1N-1이다.

  • 인덱스 범위를 벗어난 접근은 인접 메모리를 오염시켜 치명적인 런타임 버그를 유발하므로 인덱스 계산 범위를 엄격하게 통제해야 한다.