30. 2차원 배열
1. 키워드
- 2차원 배열
2. 2차원 배열 사용하기
- 2차원 배열은 다음과 같이 행과 열 형태로 이루어져 있으며 행과 열 모두
0
부터 시작한다.
3. 2차원 배열을 선언하고 요소에 접근하기
- 2차원 배열은
[]
(대괄호)를 두 번 사용하여 선언하며 첫 번째[]
에는 행 크기, 두 번째[]
에는 열 크기을 지정한다.
- 다음은 행 크기가
3
, 열 크기가4
인int
타입 2차원 배열을 선언하는 방법이다. - 2차원 배열을 선언하면서 초기화하려면
{}
(중괄호)를 사용하는데 열을 먼저 묶어주고, 열을 행 크기만큼 다시 묶어준다. {}
안의 값과 줄 개수는 행, 열 크기보다 작아도 되지만 크면 안 된다.
{}
를 사용하여 배열에 값을 할당하는 방법은 배열을 선언할 때만 사용할 수 있으며, 이미 선언된 배열에는 사용할 수 없다.
- 2차원 배열의 요소에 접근하려면 배열 뒤에
[]
를 두 번 사용하며[]
안에 행 인덱스와 열 인덱스를 지정해 주면 된다.
- 즉, 다음과 같이 2차원 배열에서 행 인덱스
1
, 열 인덱스2
인 요소의 값을 가져올 수 있다.
- 이제 2차원 배열을 선언하고 요소의 값을 출력해 보자.
#include <stdio.h>
int main()
{
int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
{11, 22, 33, 44},
{55, 66, 77, 88},
{99, 110, 121, 132}
};
// ↓ 행 인덱스
printf("%d\n", numArr[0][0]); // 행 인덱스 0, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[1][2]); // 행 인덱스 1, 열 인덱스 2인 요소 출력
printf("%d\n", numArr[2][0]); // 행 인덱스 2, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[2][3]); // 행 인덱스 2, 열 인덱스 2인 요소 출력
// ↑ 열 인덱스
return 0;
}
// 11
// 77
// 99
// 132
- 행 크기
3
, 열 크기4
인int
타입 2차원 배열은 선언하고, 값을 초기화했다.
int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
{11, 22, 33, 44},
{55, 66, 77, 88},
{99, 110, 121, 132}
};
- 2차원 배열도 인덱스는
0
부터 시작한다. - 따라서 배열
numArr
의 행 첫 번째, 열 첫 번째 요소는numArr[0][0]
이 된다.
배열의 초기화
- 다음과 같이 2차원 배열을 초기화할 때 열 요소를
{}
로 묶지 않아도 컴파일은 잘 되고, 결과도 열 요소를{}
로 묶었을 때와 같다. - 하지만 이렇게 작성하면 이해하기가 어려워서 잘 쓰이지 않는 방법이다.
4. 2차원 배열을 초기화하기
- 2차원 배열의 요소를 간단하게
0
으로 초기화해 보자.
#include <stdio.h>
int main()
{
int numArr[3][4] = { // 2차원 배열의 요소를 모두 0으로 초기화
0,
};
// ↓ 행 인덱스
printf("%d\n", numArr[0][0]); // 행 인덱스 0, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[1][2]); // 행 인덱스 1, 열 인덱스 2인 요소 출력
printf("%d\n", numArr[2][0]); // 행 인덱스 2, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[2][3]); // 행 인덱스 2, 열 인덱스 2인 요소 출력
// ↑ 열 인덱스
return 0;
}
// 0
// 0
// 0
// 0
- 2차원 배열을 선언할 때
{0,}
을 할당하여 배열의 요소를 모두0
으로 초기화했다. - 이렇게 하면 초기화할 때
0
을 일일이 나열하지 않아도 된다.
5. 2차원 배열의 요소에 값 할당하기
- 이번에는 배열을 선언할 때 값을 초기화하지 않고, 배열의 요소에 각각 할당해 보자.
#include <stdio.h>
int main()
{
int numArr[3][4];
numArr[0][0] = 11; // 행 인덱스 0, 열 인덱스 0인 요소에 값 할당
numArr[0][1] = 22; // 행 인덱스 0, 열 인덱스 1인 요소에 값 할당
numArr[0][2] = 33; // 행 인덱스 0, 열 인덱스 2인 요소에 값 할당
numArr[0][3] = 44; // 행 인덱스 0, 열 인덱스 3인 요소에 값 할당
numArr[1][0] = 55; // 행 인덱스 1, 열 인덱스 0인 요소에 값 할당
numArr[1][1] = 66; // 행 인덱스 1, 열 인덱스 1인 요소에 값 할당
numArr[1][2] = 77; // 행 인덱스 1, 열 인덱스 2인 요소에 값 할당
numArr[1][3] = 88; // 행 인덱스 1, 열 인덱스 3인 요소에 값 할당
numArr[2][0] = 99; // 행 인덱스 2, 열 인덱스 0인 요소에 값 할당
numArr[2][1] = 110; // 행 인덱스 2, 열 인덱스 1인 요소에 값 할당
numArr[2][2] = 121; // 행 인덱스 2, 열 인덱스 2인 요소에 값 할당
numArr[2][3] = 132; // 행 인덱스 2, 열 인덱스 3인 요소에 값 할당
printf("%d\n", numArr[0][0]); // 행 인덱스 0, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[1][2]); // 행 인덱스 1, 열 인덱스 2인 요소 출력
printf("%d\n", numArr[2][0]); // 행 인덱스 2, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[2][3]); // 행 인덱스 2, 열 인덱스 3인 요소 출력
return 0;
}
// 11
// 77
// 99
// 132
- 2차원 배열의 요소를 출력할 때와 마찬가지로
[]
에 인덱스를 지정한 뒤 값을 할당하면 된다.
- 2차원 배열에서 범위를 벗어난 인덱스에 접근하면 어떻게 되는지 확인해 보자.
#include <stdio.h>
int main()
{
int numArr[3][4];
numArr[0][0] = 11; // 행 인덱스 0, 열 인덱스 0인 요소에 값 할당
numArr[0][1] = 22; // 행 인덱스 0, 열 인덱스 1인 요소에 값 할당
numArr[0][2] = 33; // 행 인덱스 0, 열 인덱스 2인 요소에 값 할당
numArr[0][3] = 44; // 행 인덱스 0, 열 인덱스 3인 요소에 값 할당
numArr[1][0] = 55; // 행 인덱스 1, 열 인덱스 0인 요소에 값 할당
numArr[1][1] = 66; // 행 인덱스 1, 열 인덱스 1인 요소에 값 할당
numArr[1][2] = 77; // 행 인덱스 1, 열 인덱스 2인 요소에 값 할당
numArr[1][3] = 88; // 행 인덱스 1, 열 인덱스 3인 요소에 값 할당
numArr[2][0] = 99; // 행 인덱스 2, 열 인덱스 0인 요소에 값 할당
numArr[2][1] = 110; // 행 인덱스 2, 열 인덱스 1인 요소에 값 할당
numArr[2][2] = 121; // 행 인덱스 2, 열 인덱스 2인 요소에 값 할당
numArr[2][3] = 132; // 행 인덱스 2, 열 인덱스 3인 요소에 값 할당
printf("%d\n", numArr[-1][-1]); // 음수이므로 잘못된 인덱스
printf("%d\n", numArr[0][4]); // 열 인덱스가 배열의 범위를 벗어남
printf("%d\n", numArr[4][0]); // 행 인덱스가 배열의 범위를 벗어남
printf("%d\n", numArr[5][5]); // 행, 열 인덱스 모두 배열의 범위를 벗어남
return 0;
}
// -858993460 (쓰레기 값)
// 55 (원하지 않는 요소 [1][0]에 접근)
// 4687800 (쓰레기 값)
// 2359296 (쓰레기 값)
- 2차원 배열의 요소에 접근할 때 인덱스로 음수를 지정하거나, 배열의 크기를 벗어난 인덱스를 지정해도 컴파일 에러가 발생하지 않는다.
- 하지만 실행을 해보면 쓰레기 값이 출력된다.
- 즉, 배열의 범위를 벗어난 인덱스에 접근하면 배열이 아닌 다른 메모리 공간에 접근하게 된다.
- 특히 2차원 배열은 값이 일렬로 쭉 늘어서 있으므로
numArr[0][4]
와 같이 열 인덱스가 범위를 벗어나도록 지정하면 그다음 행 인덱스 요소인numArr[1][0]
에 접근하게 된다.
6. 2차원 배열의 크기 구하기
- 2차원 배열을 선언한 뒤 배열의 행, 열 크기를 늘려야 할 경우 관련된 반복문의 조건식도 함께 수정해야 하는데 빠뜨리고 넘어갈 수가 있다.
- 따라서 2차원 배열의 행, 열 크기를 구해놓고 반복문에 사용하면 실수를 방지할 수 있다.
- 2차원 배열이 차지하는 전체 공간과 행, 열 요소의 개수는
sizeof
연산자로 구할 수 있다.
#include <stdio.h>
int main()
{
int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
{11, 22, 33, 44},
{55, 66, 77, 88},
{99, 110, 121, 132}
};
printf("%d\n", sizeof(numArr)); // 4바이트 크기의 요소가 12(4*3)개이므로 48
int col = sizeof(numArr[0]) / sizeof(int); // 2차원 배열의 열 크기를 구할 때는
// 행 한 줄의 크기를 요소의 크기로 나눠줌
int row = sizeof(numArr) / sizeof(numArr[0]); // 2차원 배열의 행 크기를 구할 때는
// 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠줌
printf("%d\n", col);
printf("%d\n", row);
return 0;
}
// 48
// 4
// 3
sizeof
로 2차원 배열의 크기를 구해 보면 배열이 차지하는 전체 공간이 출력된다.
- 열의 요소 개수를 구하려면
sizeof(numArr[0])
와 같이 행 한 줄의 크기를 구한 뒤 요소의 크기로 나누면 된다.
- 행의 요소 개수는 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠주면 된다.
int row = sizeof(numArr) / sizeof(numArr[0]); // 2차원 배열의 행 크기를 구할 때는
// 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠줌
7. 반복문으로 2차원 배열의 요소를 모두 출력하기
- 반복문을 사용하여 2차원 배열의 요소를 모두 출력해 보자.
#include <stdio.h>
int main()
{
int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
{11, 22, 33, 44},
{55, 66, 77, 88},
{99, 110, 121, 132}
};
int col = sizeof(numArr[0]) / sizeof(int); // 2차원 배열의 열 크기를 구할 때는
// 행 한 줄의 크기를 요소의 크기로 나눠줌
int row = sizeof(numArr) / sizeof(numArr[0]); // 2차원 배열의 행 크기를 구할 때는
// 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠줌
for (int i = 0; i < row; i++) // 2차원 배열의 행 크기만큼 반복
{
for (int j = 0; j < col; j++) // 2차원 배열의 열 크기만큼 반복
{
printf("%d ", numArr[i][j]); // 2차원 배열의 인덱스에 반복문의 변수 i, j를 지정
}
printf("\n"); // 열 요소를 출력한 뒤 다음 줄로 넘어감
}
return 0;
}
// 11 22 33 44
// 55 66 77 88
// 99 110 121 132
- 먼저 배열의 행 크기와 열 크기를 구해 준다.
- 그리고
for
반복문으로 행부터 반복한 뒤 열를 반복하면서 2차원 배열의 요소를 출력한다.
for (int i = 0; i < row; i++) // 2차원 배열의 행 크기만큼 반복
{
for (int j = 0; j < col; j++) // 2차원 배열의 열 크기만큼 반복
{
- 반복문의 변수
i
와j
는 변화식을 통해1
씩 증가하므로 2차원 배열의 행 인덱스에는i
, 열 인덱스에는j
를 넣으면 배열의 요소를 순서대로 접근할 수 있다.
- 다음과 같이 역순으로도 출력할 수 있다.
#include <stdio.h>
int main()
{
int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
{11, 22, 33, 44},
{55, 66, 77, 88},
{99, 110, 121, 132}
};
int col = sizeof(numArr[0]) / sizeof(int); // 2차원 배열의 열 크기를 구할 때는
// 행 한 줄의 크기를 요소의 크기로 나눠줌
int row = sizeof(numArr) / sizeof(numArr[0]); // 2차원 배열의 행 크기를 구할 때는
// 배열이 차지하는 전체 공간을 행 한 줄의 크기로 나눠줌
for (int i = row -1 ; i >= 0; i--) // 행 크기 - 1부터 역순으로 반복
{
for (int j = col - 1; j >= 0; j--) // 열 크기 - 1부터 역순으로 반복
{
printf("%d ", numArr[i][j]); // 2차원 배열의 인덱스에 반복문의 변수 i, j를 지정
}
printf("\n"); // 열 요소를 출력한 뒤 다음 줄로 넘어감
}
return 0;
}
// 132 121 110 99
// 88 77 66 55
// 44 33 22 11
- 반복문의 초깃값에 배열의 행 크기와 열 크기를 바로 넣어버리면 처음부터 배열의 인덱스를 벗어난 상태가 된다.
- 즉, 배열의 인덱스는
0
부터 시작하므로 마지막 요소의 인덱스는 요소의 개수에서1
을 빼준다. - 그리고
0
까지 반복할 수 있도록 조건식을i >= 0
과 같이 지정하면 된다.
for (int i = row -1 ; i >= 0; i--) // 행 크기 - 1부터 역순으로 반복
{
for (int j = col - 1; j >= 0; j--) // 열 크기 - 1부터 역순으로 반복
{
8. 2차원 배열을 포인터에 넣기
- 2차원 배열을 포인터에 담으려면 다음과 같이 특별한 방법이 필요하다.
- 즉, 포인터를 선언할 때
*
과 포인터 이름을()
(괄호)로 묶어준 뒤[]
에 열 크기를 지정한다.
- 위의 코드를 풀어서 설명하면 열 크기가
4
인 배열을 가리키는 포인터라는 뜻이다.
int *numPtr[4]
int (*numPtr)[4]
에서()
를 뺀int *numPtr[4]
는int
타입 포인터4
개를 담을 수 있는 배열이라는 뜻이다.- 즉,
()
가 있으면 배열을 가리키는 배열 포인터,()
가 없으면 포인터를 여러 개 담는 포인터 배열이다.
- 이제 2차원 배열을 포인터에 할당해서 사용해 보자.
#include <stdio.h>
int main()
{
int numArr[3][4] = { // 행 크기 3, 열 크기 4인 int 타입 2차원 배열 선언
{11, 22, 33, 44},
{55, 66, 77, 88},
{99, 110, 121, 132}
};
int(*numPtr)[4] = numArr;
printf("%p\n", *numPtr); // 2차원 배열 포인터를 역참조하면 행 첫 번째의 주소가 나옴
// 컴퓨터마다, 실행할 때마다 달라짐
printf("%p\n", *numArr); // 2차원 배열을 역참조하면 행 첫 번째의 주소가 나옴
// 컴퓨터마다, 실행할 때마다 달라짐
printf("%d\n", numPtr[2][1]); // 2차원 배열 포인터는 인덱스로 접근할 수 있음
printf("%d\n", sizeof(numArr)); // sizeof로 2차원 배열의 크기를 구하면
// 배열이 메모리에 차지하는 공간이 출력됨
printf("%d\n", sizeof(numPtr)); // sizeof로 2차원 배열 포인터의 크기를 구하면
// 포인터의 크기가 출력됨
return 0;
}
// 0x002bfe5c
// 0x002bfe5c
// 110
// 48
// 4
int (*numPtr)[4] = numArr;
와 같이 2차원 배열을 포인터에 바로 할당할 수 있다.- 단, 자료형과 열 크기가 일치해야 한다.
- 2차원 배열을 포인터에 할당한 뒤 포인터를 역참조해 보면 배열의 행 첫 번째 주솟값이 나온다.
- 즉, 배열이 시작하는 주소이다.
- 마찬가지로 2차원 배열 자체도 역참조해 보면 배열의 행 첫 번째 주솟값이 나온다.
printf("%p\n", *numPtr); // 2차원 배열 포인터를 역참조하면 행 첫 번째의 주소가 나옴
// 컴퓨터마다, 실행할 때마다 달라짐
printf("%p\n", *numArr); // 2차원 배열을 역참조하면 행 첫 번째의 주소가 나옴
// 컴퓨터마다, 실행할 때마다 달라짐
- 2차원 배열 포인터는
[]
를 두 번 사용하여 배열의 요소에 접근할 수 있다.
- 배열과 포인터가 다른 점은
sizeof
로 크기를 계산했을 때이다. sizeof
로 배열의 크기를 구해 보면 배열이 메모리에 차지하는 공간이 출력되지만sizeof
로 배열의 주소가 들어있는 포인터의 크기를 구해 보면 그냥 포인터의 크기만 나온다.
3차원 배열
- 3차원 배열은 다음과 같이 높이, 행, 열 형태로 이루어져 있다.
- 3차원 배열은
[]
에 높이, 행 크기, 열 크기를 지정하여 선언한다. - 값을 초기화할 때는 면 단위로
{}
를 묶어주면 편리하다.
- 다음은 3차원 배열 예제이다.
int numArr[2][3][4] = {
{{11, 22, 33, 44},
{55, 66, 77, 88},
{99, 110, 121, 132}},
{{111, 122, 133, 144},
{155, 166, 177, 188},
{199, 1110, 1121, 1132}}};
- 3차원 배열에 접근하려면
[]
를 세 번 사용하여 높이, 행, 열 인덱스를 지정해 주면 된다.
- 3차원 배열의 높이, 행, 열을 구하는 방법은 다음과 같다.
int depth = sizeof(numArr) / sizeof(numArr[0]); // 3차원 배열이 차지하는 전체 공간을 면의 크기로 나눠줌
int row = sizeof(numArr[0]) / sizeof(numArr[0][0]); // 한 면의 크기를 행 한 줄의 크기로 나눠줌
int column = sizeof(numArr[0][0]) / sizeof(int); // 행 한 줄의 크기를 요소의 크기로 나눠줌
- 3차원 배열을 포인터에 할당하려면 행과 열로 구성된 면을 가리키는 포인터를 선언하면 된다.
References
- https://dojang.io/mod/page/view.php?id=306
- https://dojang.io/mod/page/view.php?id=307
- https://dojang.io/mod/page/view.php?id=308
- https://dojang.io/mod/page/view.php?id=309
- https://dojang.io/mod/page/view.php?id=310
- https://dojang.io/mod/page/view.php?id=311
- https://dojang.io/mod/page/view.php?id=312