[02] 2차원 배열 (2D Array)

2차원 배열

참고 문헌 (Ch37): https://dojang.io/mod/page/view.php?id=306

2차원 배열의 선언 및 요소 접근

배열 선언: (자료형) (배열이름)[행 크기][열 크기] = 초기 값;

1
2
3
4
5
int numArr[3][4] = { // 3행 4열 짜리 행렬을 선언
{ 가로 요소 4개 }, // 첫번째 행의 초기 값
{ 가로 요소 4개 }, // 두번째 행의 초기 값
{ 가로 요소 4개 }, // 세번째 행의 초기 값
}; // ↑ 세로 3줄

원소 접근: (배열이름)[행 인덱스][열 인덱스]

1
int num1 = numArr[1][2];    // 2차원 배열에서 세로 인덱스 1, 가로 인덱스 2인 요소에 접근
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#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]); // 11 : 행 인덱스 0, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[1][2]); // 77 : 행 인덱스 1, 열 인덱스 2인 요소 출력
printf("%d\n", numArr[2][0]); // 99 : 행 인덱스 2, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[2][3]); // 132: 행 인덱스 2, 열 인덱스 2인 요소 출력
// ↑ 가로 인덱스

return 0;
}

2차원 배열 요소 0으로 초기화

1차원 배열에서 요소를 0으로 초기화하는 것과 같은 방법으로 진행된다!

1
2
3
4
5
6
7
8
9
10
int main(){
int numArr[3][4] = {0, }; // 2차원 배열의 요소를 모두 0으로 초기화

printf("%d \n", numArr[0][0]); // 0: 행 인덱스 0, 열 인덱스 0인 요소 출력
printf("%d \n", numArr[1][2]); // 0: 행 인덱스 1, 열 인덱스 2인 요소 출력
printf("%d \n", numArr[2][0]); // 0: 행 인덱스 2, 열 인덱스 0인 요소 출력
printf("%d \n", numArr[2][3]); // 0: 행 인덱스 2, 열 인덱스 3인 요소 출력

return 0;
}

2차원 배열의 요소에 값 할당하기

원소 값 할당: (배열이름)[행 인덱스][열 인덱스] = 값;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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]); // 11 : 행 인덱스 0, 열 인덱스 0인 요소 출력
printf("%d\n", numArr[1][2]); // 77 : 행 인덱스 1, 열 인덱스 2인 요소 출력
printf("%d\n", numArr[2][0]); // 99 : 행 인덱스 2, 열 인덱스 0인 요소 출력
printf("%d\n", 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;
}

2차원 배열의 크기 구하기

1차원 배열과 마찬가지로 “sizeof”를 이용하여 구한다.
배열 전체에 sizeof를 적용하고, 한 행의 sizeof로 나눠주면 행의 개수가 나오고, 한 행에서 sizeof를 적용하고, 원소를 이루고 있는 자료형의 크기로 나눠주면 열의 개수가 나온다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

int main(){
int numArr[3][4] = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};

printf("%d \n", sizeof(numArr)); // int의 크기 * 배열의 원소 갯수인 값이 나온다.

int row = sizeof(numArr) / sizeof(numArr[0]); // 행의 크기, 전체 배열의 크기에서 한 행의 크기를 나눈다.

int col = sizeof(numArr[0]) / sizeof(int); // 열의 크기, 한 행의 크기에서 원소의 자료형의 크기를 나눈다.

printf("%d\n", row);
printf("%d\n", col);

return 0;
}

2차원 배열 요소 모두 출력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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); // 4: 2차원 배열의 열 크기를 구할 때는 한 행의 크기를 요소의 크기로 나눠줌

int row = sizeof(numArr) / sizeof(numArr[0]); // 3: 2차원 배열의 행 크기를 구할 때는 배열이 차지하는 전체 공간을 한 행의 크기로 나눠줌

for (int i = 0; i < row; i++) // 2차원 배열의 행 크기만큼 반복
// for (int i = row - 1; i >= 0; i--) // 행 크기 - 1부터 역순으로 반복, -1부터 하는 이유는 인덱스 시작이 0이기 때문
{
for (int j = 0; j < col; j++) // 2차원 배열의 열 크기만큼 반복
//for (int j = col - 1; j >= 0; j--) // 열 크기 - 1부터 역순으로 반복, -1부터 하는 이유는 인덱스 시작이 0이기 때문
{
printf("%d ", numArr[i][j]); // 2차원 배열의 인덱스에 반복문의 변수 i, j를 지정
}
printf("\n"); // 열 요소를 출력한 뒤 다음 줄로 넘어감
}

return 0;
}

2차원 배열을 포인터에 넣기

단순한 생각: 1차원 배열 - 단일 포인터 -> 2차원 배열 - 이중 포인터

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h.>

int main(void){
int numArr[3][4] = { // 세로 크기 3, 가로 크기 4인 int형 2차원 배열 선언
{ 11, 22, 33, 44 },
{ 55, 66, 77, 88 },
{ 99, 110, 121, 132 }
};

int **numPtr = numArr; // 자료형이 다르다는 경고 발생

printf("%d\n", numPtr[0][0]); // 실행 에러

return 0;
}
// 아래와 같은 에러 발생
// g:\Dropbox\Workspace\C_Study\TestPage.c: In function 'main':
// g:\Dropbox\Workspace\C_Study\TestPage.c:60:20: warning: initialization of 'int **' from incompatible pointer
// type 'int (*)[4]' [-Wincompatible-pointer-types]
// int **numPtr = numArr; // ?1;35mm^~~~~~

2차원 배열 포인터 선언: (자료형) ((배열포인터이름)*)**[열 크기]

1
int (*numPtr)[4]; // 2차원 배열 포인터 선언

주의사항

1
2
3
int *numPtr[4]; // int형 포인터 4개를 담을 수 있는 배열 선언
int num1, num2, num3, num4;
int *numPtr[4] = { &num1, &num2, &num3, &num4 }; // int형 포인터를 4개 담는 배열

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#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]); // 110: 2차원 배열 포인터는 인덱스로 접근할 수 있음

printf("%d\n", sizeof(numArr)); // 48: sizeof로 2차원 배열의 크기를 구하면 배열이 메모리에
// 차지하는 공간이 출력됨

printf("%d\n", sizeof(numPtr)); // 4 : sizeof로 2차원 배열 포인터의 크기를
// 구하면 포인터의 크기가 출력됨(64비트라면 8)

return 0;
}

// 내가 실행시켰을 떄의 결과
// 0061FE9C
// 0061FE9C
// 110
// 48
// 4

2차원 배열 포인터도 일반적인 배열과 동일한 방법으로 원소 접근이 가능하다!
결과에서 볼 수 있는 것처럼 배열 포인터가 더 작은 메모리를 사용한다.

3차원 배열

3차원 배열 선언: (자료형) (배열이름)[높이][행 크기][열 크기]

예시

1
2
3
4
5
6
7
8
9
10
11
12
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차원 배열 원소 값 대입: (배열이름)[높이][행 인덱스][열 인덱스] = 값;

3차원 배열 포인터에 할당: (자료형) ((포인터 이름)*)**[행 크기][열 크기]