← C 강의 목록으로
⚙️
중급 (Intermediate)
1차원 · 2차원 · 인덱싱

3단원 — 배열

같은 자료형의 값을 **여러 개 한 묶음**으로 다루는 도구가 배열입니다. 변수 100개를 따로 만드는 대신, 100칸짜리 배열 하나로 처리할 수 있습니다.

arrayindex2D
소요 시간
1~2시간
난이도
📊 초급
선수 조건
🎯 중급 2단원
결과물
배열을 선언하고 순회한다

이 강의에서 배우는 것

  • 11차원/2차원 배열을 선언·초기화·인덱싱한다.
  • 2`sizeof` 트릭으로 배열 길이를 구한다.
  • 3메모리상 배열이 어떻게 놓이는지 그림으로 이해한다.
  • 4인덱스 범위 오류의 위험성을 안다.

왜 배열이 필요한가?

학생 5명의 점수를 변수 5개로 처리하면:

c
int s1=90, s2=85, s3=78, s4=92, s5=88;   // 동일한 처리를 5번 반복해야 함

배열로 바꾸면:

c
int score[5] = {90, 85, 78, 92, 88};
for (int i = 0; i < 5; i++) printf("%d\n", score[i]);

학생 수가 100명이 되어도 코드는 사실상 그대로입니다.

핵심 개념

1) 선언과 초기화

c
int a[5];                    // 쓰레기 값
int b[5] = {1, 2, 3};        // 나머지는 0으로 채움
int c[]  = {10, 20, 30};     // 크기를 컴파일러가 결정 (3)

2) 메모리상 배열은 "연속된 칸"

text
int arr[5] = {10, 20, 30, 40, 50};

주소:    0x100  0x104  0x108  0x10c  0x110
        ┌─────┬─────┬─────┬─────┬─────┐
        │ 10  │ 20  │ 30  │ 40  │ 50  │
        └─────┴─────┴─────┴─────┴─────┘
인덱스:   [0]   [1]   [2]   [3]   [4]

각 칸은 **`sizeof(int)`바이트** 만큼씩 떨어져 있습니다. **인덱스는 0부터 시작**합니다. 마지막 인덱스는 `길이 - 1`.

3) 길이 계산 — `sizeof` 트릭

c
int arr[10];
size_t n = sizeof(arr) / sizeof(arr[0]);   // 10

전체 바이트 수를 한 칸 바이트 수로 나눕니다. **주의**: 함수 매개변수로 받은 배열에는 안 됩니다(포인터로 변환되어 크기 정보가 사라짐).

4) 2차원 배열 (행렬)

c
int grid[3][4];     // 3행 4열
grid[i][j] = i * 4 + j;
text
grid[0]: ┌────┬────┬────┬────┐
        │ 0  │ 1  │ 2  │ 3  │
grid[1]: ├────┼────┼────┼────┤
        │ 4  │ 5  │ 6  │ 7  │
grid[2]: ├────┼────┼────┼────┤
        │ 8  │ 9  │ 10 │ 11 │
        └────┴────┴────┴────┘

C는 **행 우선(row-major)** 으로 메모리에 저장합니다 (한 행이 끝나야 다음 행).

예제로 보기

예제 1 — `ex01_basic.c` : 입력과 출력

c
int arr[5];
for (int i = 0; i < 5; i++) scanf("%d", &arr[i]);
for (int i = 0; i < 5; i++) printf("%d ", arr[i]);

**입력**: `10 20 30 40 50`

text
arr[0] 입력: arr[1] 입력: arr[2] 입력: arr[3] 입력: arr[4] 입력: 입력값: 10 20 30 40 50

핵심: `&arr[i]`처럼 **개별 원소의 주소**를 `scanf`에 전달합니다.

예제 2 — `ex02_max.c` : 최댓값 찾기

c
int max = arr[0];
for (size_t i = 1; i < n; i++)
    if (arr[i] > max) max = arr[i];

**실행 결과**

text
최댓값: 56 (인덱스 5)

핵심: "맨 처음 원소를 임시 답으로 잡고, 나머지를 비교" 가 정석 패턴.

예제 3 — `ex03_reverse.c` : 배열 뒤집기

c
for (size_t i = 0; i < n / 2; i++) {
    int t = arr[i];
    arr[i] = arr[n - 1 - i];
    arr[n - 1 - i] = t;
}

**실행 결과**

text
뒤집힌 결과: 7 6 5 4 3 2 1

핵심: **양 끝에서 안쪽으로 swap**. 반복은 `n/2`번이면 충분합니다.

예제 4 — `ex04_2d.c` : 2차원 배열 합

c
int A[2][3] = {{1, 2, 3}, {4, 5, 6}};
int B[2][3] = {{6, 5, 4}, {3, 2, 1}};
for (i...) for (j...) C[i][j] = A[i][j] + B[i][j];

**실행 결과**

text
A + B =
  7   7   7
  7   7   7

핵심: 2중 for로 행렬을 순회. 출력 시 행마다 `\n`을 잊지 말 것.

다른 시각으로 보기 — `arr[i]`는 사실 `*(arr + i)`

C 문법에서 `arr[i]`는 컴파일러가 자동으로 `*(arr + i)`로 변환합니다. 즉 배열 이름은 **첫 원소의 주소**처럼 동작합니다(자세한 내용은 [포인터](../../03_고급/01_포인터/) 단원).

text
   arr ─►  ┌────┬────┬────┬────┬────┐
           │ 10 │ 20 │ 30 │ 40 │ 50 │
           └────┴────┴────┴────┴────┘
              i=0   i=1   i=2   ...
   arr + 2 ──────────► (이 주소가 arr[2]의 주소)

자주 하는 실수

  1. **인덱스 오버런**: `int a[5]; a[5] = 0;` → 정의되지 않은 동작.
  2. **루프 조건 부등호 실수**: `for (i = 0; i <= n; i++)` 로 한 칸 더 접근.
  3. **함수에서 `sizeof(arr) / sizeof(arr[0])`**: 매개변수에서는 항상 `포인터 / 원소`가 되어 깨짐.
  4. **2D 배열 행/열 혼동**: `arr[i][j]`의 `i`가 행, `j`가 열.
  5. **VLA(가변 길이 배열) 의존**: `int a[n];` 은 C99 가변 배열로 가능하지만, 큰 n은 스택 오버플로 위험.

정리

  • 배열은 같은 자료형의 값을 메모리에 연속으로 놓은 묶음.
  • 인덱스는 **0부터** 시작하며, 마지막은 `길이 - 1`.
  • `sizeof(arr) / sizeof(arr[0])`은 지역 배열에서만 유효.
  • 2차원 배열은 `[행][열]` 순서로 접근하며 행 우선으로 저장된다.
  • 인덱스 범위 검사는 컴파일러가 안 해주므로 **개발자가 책임**진다.

직접 해 보기

bash
cd src
gcc -std=c11 -Wall -o ex01 ex01_basic.c   && echo "10 20 30 40 50" | ./ex01
gcc -std=c11 -Wall -o ex02 ex02_max.c     && ./ex02
gcc -std=c11 -Wall -o ex03 ex03_reverse.c && ./ex03
gcc -std=c11 -Wall -o ex04 ex04_2d.c      && ./ex04

응용:

  • `ex02`에서 **최솟값**도 같이 찾도록 확장해 보세요.
  • `ex04`를 5x5 행렬로 바꿔 단위 행렬(대각선만 1)을 출력해 보세요.

💻 예제 (examples)

실제로 컴파일·실행해 결과를 확인할 수 있는 예제입니다.

ex01_basic.c입력과 출력
CODE
#include <stdio.h>

int main(void) {
    int arr[5];

    for (int i = 0; i < 5; i++) {
        printf("arr[%d] 입력: ", i);
        scanf("%d", &arr[i]);
    }

    printf("입력값: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    putchar('\n');
    return 0;
}
ex02_max.c최댓값 찾기
CODE
#include <stdio.h>

int main(void) {
    int arr[] = {12, 7, 38, 21, 9, 56, 3, 44};
    size_t n = sizeof(arr) / sizeof(arr[0]);

    int max = arr[0];
    int idx = 0;
    for (size_t i = 1; i < n; i++) {
        if (arr[i] > max) { max = arr[i]; idx = (int)i; }
    }

    printf("최댓값: %d (인덱스 %d)\n", max, idx);
    return 0;
}
▶ 실행 결과
최댓값: 56 (인덱스 5)
ex03_reverse.c배열 뒤집기
CODE
#include <stdio.h>

int main(void) {
    int arr[] = {1, 2, 3, 4, 5, 6, 7};
    size_t n = sizeof(arr) / sizeof(arr[0]);

    for (size_t i = 0; i < n / 2; i++) {
        int t = arr[i];
        arr[i] = arr[n - 1 - i];
        arr[n - 1 - i] = t;
    }

    printf("뒤집힌 결과: ");
    for (size_t i = 0; i < n; i++) printf("%d ", arr[i]);
    putchar('\n');
    return 0;
}
▶ 실행 결과
뒤집힌 결과: 7 6 5 4 3 2 1
ex04_2d.c2차원 배열 합
CODE
#include <stdio.h>

int main(void) {
    int A[2][3] = {{1, 2, 3}, {4, 5, 6}};
    int B[2][3] = {{6, 5, 4}, {3, 2, 1}};
    int C[2][3];

    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 3; j++)
            C[i][j] = A[i][j] + B[i][j];

    printf("A + B =\n");
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) printf("%3d ", C[i][j]);
        putchar('\n');
    }
    return 0;
}
▶ 실행 결과
A + B =
  7   7   7
  7   7   7

📝 과제 (exercises)

직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.

과제 1

문제 1 (hw01.c)

목표: 정수 10개를 입력받아 합계와 평균(소수점 둘째 자리)을 출력하세요.

요구사항
  • 파일명: hw01.c
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    int arr[10];
    int sum = 0;

    printf("정수 10개 입력: ");
    for (int i = 0; i < 10; i++) {
        scanf("%d", &arr[i]);
        sum += arr[i];
    }

    printf("합계: %d\n", sum);
    printf("평균: %.2f\n", sum / 10.0);
    return 0;
}
과제 2

문제 2 (hw02.c)

목표: 배열 `{5, 3, 8, 1, 9, 2}`를 **버블 정렬**로 오름차순 정렬해 출력하세요.

요구사항
  • 파일명: hw02.c
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    int arr[] = {5, 3, 8, 1, 9, 2};
    int n = (int)(sizeof(arr) / sizeof(arr[0]));

    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                int t = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = t;
            }
        }
    }

    printf("정렬 결과: ");
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    putchar('\n');
    return 0;
}
과제 3

문제 3 (hw03.c)

목표: `int A[3][3]`을 입력받아 **전치 행렬**을 출력하세요.

요구사항
  • 파일명: hw03.c
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    int A[3][3];
    int T[3][3];

    printf("3x3 행렬 입력 (총 9개):\n");
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            scanf("%d", &A[i][j]);

    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            T[j][i] = A[i][j];

    printf("전치 행렬:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) printf("%4d", T[i][j]);
        putchar('\n');
    }
    return 0;
}
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗