1차원 배열은 값을 한 줄로 늘어놓습니다. 그런데 학생 여러 명의 여러 과목 점수, 지하철 요금표, 게임 판처럼 현실의 데이터는 대개 표 모양입니다. 가로줄과 세로줄이 만나는 칸마다 값이 하나씩 들어가는 격자이고, 이 표를 담는 그릇이 2차원 배열입니다. 1차원 배열 여러 개를 위아래로 쌓아 놓은 것이라고 생각하면 편합니다.
15.1 표 모양을 담는 2차원 배열
2차원 배열은 대괄호를 두 번 써서 선언합니다. 앞 숫자가 행, 즉 가로줄의 개수이고 뒤 숫자가 열, 즉 세로줄의 개수입니다.
int table[2][3] = {
{1, 2, 3}, // 0번 행
{4, 5, 6} // 1번 행
};
table[2][3]은 2행 3열, 칸이 여섯 개인 표입니다. 중괄호 한 쌍이 한 행이고, 그 안의 값들이 그 행의 열입니다. 이 표를 그림으로 그리면 이렇게 됩니다.
0열 1열 2열
0행 1 2 3
1행 4 5 6
15.2 행과 열로 한 칸 집기
![[C 15] 다차원 배열, 표처럼 다루기](https://img.thenullpage.com/posts/6550/6550_1_c4b9bf.webp)
표에서 한 칸을 꺼낼 때는 table[행][열]로 씁니다. 행 번호도 열 번호도 1차원 배열과 똑같이 0부터 셉니다.
#include <stdio.h>
int main(void) {
int table[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
printf("1행 2열: %d\n", table[1][2]);
table[0][0] = 99; // 한 칸만 바꾸기
printf("0행 0열: %d\n", table[0][0]);
return 0;
}
출력은 이렇습니다.
1행 2열: 6
0행 0열: 99
table[1][2]는 1번 행 {4, 5, 6}의 2번 열이니 6입니다. 표에서 아래로 한 칸, 오른쪽으로 두 칸 옮긴 자리라고 손가락으로 짚으면 됩니다. 한 칸에만 값을 새로 넣을 때도 table[0][0] = 99처럼 그 칸만 지정하면 됩니다.
15.3 중첩 반복으로 표 전체 훑기
표의 모든 칸을 하나씩 방문하려면 반복문을 두 겹으로 겹칩니다. 바깥 반복이 행을 하나 고르고, 그 안에서 안쪽 반복이 그 행의 열을 왼쪽부터 훑습니다. 성적표를 그대로 찍어 보겠습니다.
#include <stdio.h>
int main(void) {
int score[2][3] = {
{80, 90, 100},
{70, 60, 50}
};
for (int r = 0; r < 2; r++) {
for (int c = 0; c < 3; c++) {
printf("%4d", score[r][c]);
}
printf("\n"); // 한 행 끝나면 줄바꿈
}
return 0;
}
출력은 이렇습니다.
80 90 100
70 60 50
안쪽 반복이 한 행을 다 찍고 바깥 반복으로 돌아갈 때 printf("\n")으로 줄을 바꾸는 것이 핵심입니다. 함정. 이 줄바꿈을 안쪽 반복 안에 넣으면 숫자마다 줄이 갈려 표 모양이 무너집니다. %4d는 폭 네 칸으로 오른쪽 정렬해 자릿수가 달라도 열을 맞춰 줍니다.
15.4 계산식으로 격자 채우기
표를 손으로 다 적지 않고 각 칸을 규칙에 따라 채울 수도 있습니다. 행 번호와 열 번호를 계산에 넣으면 됩니다. 곱셈표를 만들어 보겠습니다.
#include <stdio.h>
int main(void) {
int grid[3][3];
for (int r = 0; r < 3; r++)
for (int c = 0; c < 3; c++)
grid[r][c] = (r + 1) * (c + 1);
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++)
printf("%3d", grid[r][c]);
printf("\n");
}
return 0;
}
출력은 이렇습니다.
1 2 3
2 4 6
3 6 9
한 번의 중첩 반복으로 값을 채우고, 그다음 중첩 반복으로 출력했습니다. r과 c가 0부터 시작하므로 (r + 1) * (c + 1)로 1단부터 3단까지의 곱을 각 칸에 넣었습니다.
15.5 한 학생의 평균, 행 단위 계산
표에서 한 행만 붙잡고 그 행의 열을 훑으면 그 행의 합계가 나옵니다. 학생별 평균을 구해 보겠습니다.
#include <stdio.h>
int main(void) {
int score[2][3] = {
{80, 90, 100},
{70, 60, 50}
};
for (int s = 0; s < 2; s++) {
int sum = 0;
for (int k = 0; k < 3; k++)
sum += score[s][k];
printf("%d번 학생 평균: %.1f\n", s + 1, (double)sum / 3);
}
return 0;
}
출력은 이렇습니다.
1번 학생 평균: 90.0
2번 학생 평균: 60.0
주의. 합계 변수 sum을 바깥 반복 안에서 매번 0으로 다시 놓는 것이 중요합니다. 학생이 바뀔 때마다 합을 처음부터 새로 세야 하기 때문입니다. sum을 바깥 반복 밖에 두면 앞 학생 점수까지 섞여 엉뚱한 평균이 나옵니다. 정수끼리 나눌 때는 소수점이 버려지므로 (double)sum으로 형변환해 평균을 소수로 얻습니다.
15.6 과목별 합계, 열 단위 계산
이번에는 반대로 열을 붙잡습니다. 열 번호를 바깥 반복에 두고 행을 훑으면 세로 방향, 곧 과목별 합계가 나옵니다.
#include <stdio.h>
int main(void) {
int score[2][3] = {
{80, 90, 100},
{70, 60, 50}
};
for (int c = 0; c < 3; c++) {
int sum = 0;
for (int r = 0; r < 2; r++)
sum += score[r][c];
printf("%d번 과목 합계: %d\n", c + 1, sum);
}
return 0;
}
출력은 이렇습니다.
1번 과목 합계: 150
2번 과목 합계: 150
3번 과목 합계: 150
바깥이 열, 안쪽이 행으로 뒤바뀌었을 뿐 뼈대는 앞 예제와 같습니다. 인덱스는 언제나 score[행][열] 순서라서, 열을 고정하고 행만 0, 1로 훑으면 세로 한 줄을 더하게 됩니다.
15.7 문자로 그리는 지도와 게임 판
2차원 배열에 숫자만 담으라는 법은 없습니다. 문자를 담으면 지도나 게임 판이 됩니다. 우물 정 기호를 벽, 점을 길로 삼은 작은 미로를 찍어 보겠습니다.
#include <stdio.h>
int main(void) {
char map[3][4] = {
{'#', '.', '.', '#'},
{'#', '.', '#', '#'},
{'#', '.', '.', '.'}
};
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 4; c++)
printf("%c", map[r][c]);
printf("\n");
}
return 0;
}
출력은 이렇습니다.
#..#
#.##
#...
각 칸이 지도의 한 자리입니다. 캐릭터의 위치를 행과 열 두 숫자로 기억해 두고, map[r][c]가 우물 정 기호인지 검사해 벽에 부딪혔는지 판정하는 식으로 게임 로직을 붙여 갑니다.
15.8 자주 걸려 넘어지는 곳
2차원 배열에서 초보자가 반복해서 만나는 함정을 몇 가지 짚겠습니다.
함정. 행과 열의 개수를 헷갈려 반복 조건을 잘못 쓰면 배열 밖을 건드립니다. score[2][3]에서 유효한 행 번호는 0과 1, 열 번호는 0, 1, 2뿐입니다. r < 2, c < 3처럼 선언한 크기와 정확히 맞춰야 하며, 여기서 벗어나면 배열 경계를 넘어 정의되지 않은 동작(undefined behavior, 표준이 결과를 보장하지 않는 상태)이 됩니다. 값이 이상하게 찍히거나 프로그램이 갑자기 죽는 원인 대부분이 이것입니다.
주의. 초기값을 일부만 적으면 나머지 칸은 자동으로 0으로 채워집니다. int a[2][3] = {{1, 2}};는 첫 행이 {1, 2, 0}, 둘째 행 전체가 {0, 0, 0}이 됩니다. 반대로 모든 칸을 0으로 시작하고 싶으면 int a[2][3] = {0}; 한 번이면 충분합니다.
함정. table[행][열]의 순서를 table[열][행]으로 뒤집어 쓰는 실수가 흔합니다. 대괄호 둘은 곱셈처럼 자리를 바꿔도 되는 것이 아니라, 앞이 반드시 행이고 뒤가 열입니다. 순서를 바꾸면 엉뚱한 칸을 읽거나 경계를 넘어 버립니다.
2차원 배열은 결국 1차원 배열을 행으로 쌓은 표이고, 다루는 도구는 대괄호 두 개와 중첩 반복 하나가 전부입니다. 바깥 반복이 행, 안쪽 반복이 열이라는 짝만 손에 붙이면 성적표든 곱셈표든 지도든 같은 골격으로 풀립니다. 새 표를 만날 때마다 무엇이 행이고 무엇이 열인지부터 정해 두면, 나머지 코드는 위 예제들의 작은 변형으로 이어집니다.