본문으로 건너뛰기

배열

정보처리기사 목차프로그래밍 기초레슨 130 / 233

목차

배열(array)은 같은 자료형의 칸을 메모리에 붙여 놓고 한 이름으로 묶은 것입니다. 점수 다섯 개를 변수 다섯 개에 두면 반복으로 돌 수 없지만, 배열에 두면 a[i]처럼 번호로 칸을 짚어 반복 하나로 모두 다룹니다. 시험은 인덱스로 짚은 칸의 값, 두 칸을 맞바꾼 결과, 2차원 배열의 위치를 묻습니다. 아래 그림은 두 칸의 값이 임시 변수를 거쳐 맞바뀌는 모습을 한 줄씩 보입니다.

6단계 중 1단계. 이 그림 읽는 법: 칸 위 작은 수가 인덱스입니다. 4번 줄 — 배열 a에 10 · 20 · 30을 넣습니다. 첫 칸이 a[0], 끝 칸이 a[2]입니다.

1선언과 인덱스 — 0부터

int a[5] = {3, 1, 4, 1, 5};⁠는 int 칸 다섯을 붙여 만들고, 칸마다 a[0]부터 a[4]까지 번호를 붙입니다. 이 번호가 인덱스(index)이고 자료에 따라 첨자라고도 부릅니다. 크기가 n이면 마지막 인덱스는 n − 1입니다.

선언칸에 든 값
int a[5] = {1, 2};1 2 0 0 0 — 모자란 칸은 0
int b[] = {7, 8, 9};7 8 9 — 크기를 비우면 값의 개수

배열 밖 칸(a[5])을 짚어도 C는 막지 않고, 무엇이 일어날지 정해지지 않습니다. 그래서 칸을 도는 반복은 i < 5처럼 크기보다 작을 때까지만 돕니다.

2맞바꾸기 세 줄 — 임시 변수

두 칸의 값을 맞바꾸려면 한쪽 값을 잠시 맡겨 둘 임시 변수(temporary variable) t가 있어야 합니다.

t = a[0];
a[0] = a[2];
a[2] = t;

a[0] = a[2];부터 하면 a[0]의 옛 값을 잃어 두 칸이 같은 값이 됩니다. 선택·버블·삽입 정렬의 정렬 코드가 이 세 줄로 칸을 바꿉니다.

32차원 배열 — 행 순서로 한 줄

int b[2][3]은 2행 3열이고 b[행][열]로 칸을 짚습니다. 메모리에는 행 0의 칸 셋 다음에 행 1의 칸 셋이 이어집니다. 이 차례를 행 우선(row-major order)이라 합니다. 그래서 b[i][j]는 첫 칸에서 i × 열 수 + j칸 뒤에 있고, 주소는 시작 주소 + 그 칸 수 × 칸 크기입니다. int m[3][4]가 100번지에서 시작하고 int가 4바이트면, m[2][1]은 2 × 4 + 1 = 9칸 뒤라 100 + 9 × 4 = 136번지입니다. 두 겹 for로 돌 때 바깥 i가 행, 안쪽 j가 열을 짚으면 메모리에 놓인 차례대로 칸을 지납니다.

예제

배열 인덱스 출력을 묻는 꼴입니다. a[a[3]]은 안쪽 a[3]을 먼저 값으로 바꿉니다. 찍힐 값을 먼저 정해 보세요.

#include <stdio.h>

int main(void) {
  int a[4] = {3, 1, 4, 2};
  int i, s = 0;
  for (i = 0; i < 4; i++) {
    if (a[i] > 2) {
      s += a[i];
    }
  }
  printf("%d %d\n", s, a[a[3]]);
  return 0;
}
실행 결과 보기
실행 결과
7 4

i가 0부터 3까지 칸을 하나씩 짚고, 2보다 큰 a[0]의 3과 a[2]의 4만 더해 s는 7입니다. a[3]이 2라 a[a[3]]은 a[2]이고, 그 값 4를 찍습니다.

같은 코드를 Java·Python으로

CJavaPython
선언int a[4] = {3, 1, 4, 2};int[] a = {3, 1, 4, 2};a = [3, 1, 4, 2]
칸 수sizeof a / sizeof a[0]a.lengthlen(a)
배열 밖막지 않음 — 정해지지 않음예외로 멈춤오류(IndexError)로 멈춤
맞바꾸기세 줄세 줄a[0], a[2] = a[2], a[0]
a[-1]배열 밖배열 밖끝 칸

시험 포인트

  • 필기: 인덱스는 0부터라 크기 n인 배열의 끝 칸은 n − 1번이고, 초기값이 모자라면 나머지 칸은 0입니다. 2차원 배열은 행 우선으로 이어져, b[i][j]의 주소는 시작 주소 + (i × 열 수 + j) × 칸 크기입니다.
  • 실기: 출력을 그대로 씁니다. a[a[3]]처럼 겹친 인덱스는 안쪽부터 값으로 바꾸고, 맞바꾸기 세 줄은 한 줄씩 칸의 값을 적어 따라갑니다. 이름은 인덱스(Index)·행 우선(Row-major Order)으로 씁니다.

확인 문제

1. int m[4][5];의 시작 주소가 300번지이고 int가 4바이트일 때, m[2][3]의 주소를 고르세요.

  • ① 320
  • ② 344
  • ③ 352
  • ④ 356
정답

③입니다. 한 행이 5칸이라 m[2][3]은 첫 칸에서 2 × 5 + 3 = 13칸 뒤이고, 300 + 13 × 4 = 352번지입니다.

  • ① 행 번호에 열 수를 곱하지 않고 2 + 3 = 5칸으로 셌습니다.
  • ② 열 수 5 대신 행 수 4를 곱해 2 × 4 + 3 = 11칸으로 셌습니다.
  • ④ 떨어진 칸 수 13을 몇째 칸(14)으로 바꿔 300 + 14 × 4로 셌습니다.

2. 예제 코드의 7번 줄에서 a[i] > 2를 a[i] >= 2로 바꿨습니다. 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

#include <stdio.h>

int main(void) {
  int a[4] = {3, 1, 4, 2};
  int i, s = 0;
  for (i = 0; i < 4; i++) {
    if (a[i] >= 2) {
      s += a[i];
    }
  }
  printf("%d %d\n", s, a[a[3]]);
  return 0;
}
정답

받는 답:

실행 결과
9 4

>=라 2도 들어가 s는 3 + 4 + 2로 9입니다. a[a[3]]은 바뀌지 않은 4입니다.

  • 틀리는 꼴 7 4: 2가 >= 2에 드는 것을 놓쳤습니다.
  • 틀리는 꼴 9 2: a[a[3]]을 a[3]의 값 2로 봤습니다. 2는 다시 인덱스로 쓰여 a[2]의 4를 짚습니다.

3. 다음 코드는 맞바꾸기 세 줄을 두 번 쓰려다 마지막 줄을 잘못 썼습니다. 줄마다 a의 칸을 적은 표의 (가)·(나)를 채운 뒤 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

줄바뀐 이름a[0] a[1] a[2]t
6t7 8 97
7a[0]8 8 97
8a[1]8 7 97
9t8 7 99
10a[2](가)9
11a[0](나)9
#include <stdio.h>

int main(void) {
  int a[3] = {7, 8, 9};
  int t;
  t = a[0];
  a[0] = a[1];
  a[1] = t;
  t = a[2];
  a[2] = a[0];
  a[0] = a[2];
  printf("%d %d %d\n",
      a[0], a[1], a[2]);
  return 0;
}
정답

(가) 8 7 8 · (나) 8 7 8이고, 출력은 다음과 같습니다.

실행 결과
8 7 8

10번 줄이 a[2]에 a[0]의 8을 넣어 9는 t에만 남습니다. 11번 줄은 a[0] = t;여야 맞바뀌는데, a[2]의 8을 다시 a[0]에 넣어 그대로 8입니다.

  • 틀리는 꼴 9 7 8: 세 줄을 보자마자 '맞바꾼다'고 읽었습니다. 11번 줄은 t가 아니라 a[2]를 넣습니다.
  • 틀리는 꼴 8 7 9: 10·11번 줄이 서로 되돌린다고 봤습니다. 10번 줄이 a[2]의 9를 8로 덮어, 11번 줄은 a[0]에 8을 다시 넣을 뿐입니다.

4. 다음 코드의 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

#include <stdio.h>

int main(void) {
  int m[2][3] = {
      {1, 2, 3},
      {4, 5, 6},
  };
  int i, j, s = 0;
  for (i = 0; i < 2; i++)
    for (j = i; j < 3; j++)
      s += m[i][j];
  printf("%d %d %d\n", i, j, s);
  return 0;
}
정답

받는 답:

실행 결과
2 3 17

i가 0이면 j는 0·1·2라 1 + 2 + 3, i가 1이면 j가 1부터라 5 + 6을 더해 s는 17입니다. 안쪽 for는 바깥 한 바퀴마다 j = i로 다시 시작합니다. 끝난 뒤 i는 조건을 처음 어긴 2, j는 마지막 안쪽 반복이 끝난 3입니다.

  • 틀리는 꼴 2 3 21: j가 늘 0부터 시작한다고 보아 4까지 더했습니다.
  • 틀리는 꼴 1 2 17: 끝난 뒤 i와 j가 마지막으로 몸을 돈 값에 남는다고 봤습니다.

5. 다음 (가)·(나)의 이름을 한글 이름과 영문으로 함께 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

  • (가) 칸 이름 a[3]의 대괄호 안 3처럼, 배열에서 칸의 자리를 0부터 세는 번호
  • (나) b[2][3]을 메모리에 놓을 때 b[0][0] · b[0][1] · b[0][2] 다음에 b[1][0]이 오는 차례
정답

받는 답: (가) 인덱스(Index) · (나) 행 우선(Row-major Order)

(가)는 '0부터 세는 칸 번호', (나)는 '앞 번호가 같은 칸끼리 먼저 모두 놓임'이 실마리입니다. (가)는 첨자도 받습니다.

  • 같은 이름의 다른 꼴: Index만 쓴 꼴 — 한글 이름과 영문을 함께 써야 합니다.
  • 틀리는 꼴 열 우선 — (나)에: b[0][0] 다음에 b[1][0]이 오는 차례입니다. C는 뒤 번호가 먼저 바뀌는 행 우선입니다.

처음이라면: C 언어 과목(준비 중)의 '배열: 붙어 있는 칸 줄' · '배열 돌기와 가장 큰 값' · '맞바꾸기와 버블 정렬' · '2차원 배열' 레슨에서 같은 규칙을 처음부터 천천히 봅니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

정보처리기사 목차로