배열(array)은 같은 자료형의 칸을 메모리에 붙여 놓고 한 이름으로 묶은 것입니다. 점수 다섯 개를 변수 다섯 개에 두면 반복으로 돌 수 없지만, 배열에 두면 a[i]처럼 번호로 칸을 짚어 반복 하나로 모두 다룹니다. 시험은 인덱스로 짚은 칸의 값, 두 칸을 맞바꾼 결과, 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 4i가 0부터 3까지 칸을 하나씩 짚고, 2보다 큰 a[0]의 3과 a[2]의 4만 더해 s는 7입니다.
a[3]이 2라 a[a[3]]은 a[2]이고, 그 값 4를 찍습니다.
같은 코드를 Java·Python으로
| C | Java | Python | |
|---|---|---|---|
| 선언 | int a[4] = {3, 1, 4, 2}; | int[] a = {3, 1, 4, 2}; | a = [3, 1, 4, 2] |
| 칸 수 | sizeof a / sizeof a[0] | a.length | len(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 |
|---|---|---|---|
| 6 | t | 7 8 9 | 7 |
| 7 | a[0] | 8 8 9 | 7 |
| 8 | a[1] | 8 7 9 | 7 |
| 9 | t | 8 7 9 | 9 |
| 10 | a[2] | (가) | 9 |
| 11 | a[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 810번 줄이 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 17i가 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차원 배열' 레슨에서 같은 규칙을 처음부터 천천히 봅니다.