저번에 배열에 대해서 배웠었다. 그렇다면 여기서 똑똑한 사람은 이러한 질문을 할 수 있다.
배열안에 배열이 있을 수 있을까?
배열의 배열을 생각하는 대단한 생각이다. 배열의 배열이라는 말을 좀 더 명확하게 이해해보자
' int
형의 배열' 이라는 말은 배열의 각 원소가 int
형 변수인 것이다. 그렇다면
' int
형의 배열의 배열' 이라는 말은 무엇일까? 이 말은, 배열의 각 원소가 int
형의 배열인 것이다.
이러한 배열의 형태는 아래와 같이 표현할 수 있다.
(배열의 형) (배열의 이름)[?][?]
?
에는 배열의 크기가 오면 된다. 이전에 기본적인 배열은 (배열의 형) (배열의 이름)[?]
이런 형태였는데 2차원 배열은 옆에 ?
가 하나 더 붙는다.
다음 예시를 보자
int arr[3][2];
배열을 원소로 가진 배열이라고 생각하면 된다. 원소가 2개인 배열을 원소 하고 이 원소가 3개 있는 배열이다. 이를 arr[3][2]
라고 표현하는 2차원 배열이다.
즉 arr[0]
은 int
형의 원소를 2개 가지고 있는 배열을 의미하고 그 배열의 원소는 각각 arr[0][0]
, arr[0][1]
이다.
arr[3]
은 아파트에 집이 3개 있는거고 arr[3][2]
는 집이 3개 인데 각 집에 방이 2개 있는 것이다.
따라서 arr[m][n];
같이 배열을 선언 한다면 (m과 n은 임의의 정수) m x n 개의 변수를 가지는 배열을 선언한것이다.
그런데 아직 '2차원 배열' 이라는 말을 하지 않았다. 사실 메모리에는 모든 배열이 1차원 배열과 다름없이 들어간다.
#include <stdio.h>
int main() {
int arr[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
printf("arr 배열의 2 행 3 열의 수를 출력 : %d \n", arr[1][2]);
printf("arr 배열의 1 행 2 열의 수를 출력 : %d \n", arr[0][1]);
return 0;
}
arr 배열의 2 행 3 열의 수를 출력 : 6
arr 배열의 1 행 2 열의 수를 출력 : 2
2차원 배열이나 1차원 배열이나 메모리상에서는 모두 연속적으로 나란히 존재한다. (메모리는 항상 1차원이다.)
하지만 2차원 배열을 생각할 때 마치 해당 원소들이 2차원 공간상에 배치 되어 있다고 생각해도 된다.
arr[x][y]
한다면 x
는 몇 번째 줄에 있는지, y
는 몇 번째 열에 있는지를 나타낸다. 결론적으로 말하자면 일차원 배열은 한개의 원소를 인덱스로 원소에 접근하고 이차원 배열은 2개의 원소를 인덱스로 원소에 접근한다.
앞선 예제에서
int arr[2][3] = {1, 2, 3, 4, 5, 6};
이와 같은 방식으로 2차원 배열을 정의 하였다. 하지만 이 방법 말고
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
이런식으로 정의해도 앞선 방법과 전혀 차이가 없다. 따라서 본인의 기호에 맞게 사용하면 된다.
그리고 다음과 같이 배열을 선언할 수 있다.
int arr[] = {1, 2, 3, 4};
위와 같이 정의 할 수 있는 이유는 컴파일러가 원소의 개수를 정확하게 알고 있기 때문이다. 즉, 컴파일러는 우리가 배열을 정의한 것을 보고 ' int
형 원소가 4개인 배열을 선언하는 것이구나' 라고 단번에 알게 되어서 대괄호 []
안에 자동적으로 4를 집어 넣게 된다. 따라서
int arr[4] = {1, 2, 3, 4};
이렇게 정의 한 것과 같게 보는 것이다.
그러나 아래와 같이 선언하면 안된다.
int arr[];
그 이유는 '배열의 크기는 임의로 정해지지 않기 때문이다.' 즉 위와 같은 배열을 정의한다면 컴파일러는 우리가 어떠한 크기의 배열을 정의하고 싶은지 모른다. 그렇기 때문에 오류가 발생한다.
이와 같은 아이디어는 2차원 배열에서도 사용할 수 있다.
int arr[][3] = {{4, 5, 6}, {7, 8, 9}};
위와 같은 예시에서 대괄호 안에 들어갈 숫자를 예측할 수 있을까? 물론 가능하다 바로 2 이다. 왜냐하면 {4,5,6}
를 원소로 가지는 arr[3]
배열 하나와 {7,8,9}
를 원소로 가지는 arr[3]
배열 하나 총 2개의 배열을 정의 했기 때문에 arr[2][3]
이다.
그렇다면 다음과 같은 예시도 가능할까??
int arr[][2] = {{1, 2}, {3, 4}, {5, 6}, {7}};
마지막에 원소 {7}
하나만 있기 떄문에 아마도 대부분 불가능 할 것이라고 생각할 수 있는데 사실 가능하다.
arr[][2]
라고 했기 때문에 무조건 원소가 2개인 1차원 배열들이 생기게 된다. 즉, 7이 속한 1차원 배열은 원소개 한 개 인 것이 아니라 마치 arr[3] ={1}
을 해도 상관이 없던 것 처럼 8번째 들어갈 원소의 자리를 비워둔 것이다. 따라서 위 문장은 틀린 것이 아니다.
int arr[2][] = {{4, 5, 6}, {7, 8, 9}};
그렇다면 이 문장은 어떨까? 아마도 대부분 가능할 것이라고 생각하지만 사실 컴파일 오류가 발생한다.
C언어에서 다차원 배열은 선언 할 때 맨 앞의 크기를 제외한 나머지 크기들은 확실히 정의해줘야 오류가 발생하지 않는다.
2차원 배열을 잘 이해 했다면 3차원 배열을 이해하는 것도 큰 어려움이 없다.
(배열의 형)(배열의 이름)[x][y][z]; // 여기서 x,y,z 는 배열의 크기를 말합니다.
이제 머리속에 그림을 그려봅시다.
int arr[3][4];
는 가로의 길이가 4이고 세로의 길이가 3인 평면위에 int
형 변수들이 하나 씩 올라가 있다고 상상해보자.
그렇다면 다음을 보자
int brr[2][3][4];
이는 단순히 위에서 생각했던 평면이 2층으로 쌓여 있다고 생각하면 된다.
하지만 문제는 4차원이다.
우리는 3차원에는 익숙하지만 4차원은 상상하기 힘들다. 그래서 4차원 배열, 그리고 그 이후에 고차원 배열은 머리속으로 그려보기가 힘들다.
그런데 아까 위에서 이런 얘기를 한 적이 있다.
일차원 배열은 한개의 원소(x)를 인덱스로 원소에 접근하고 이차원 배열은 2개의 원소(x,y)를 인덱스로 원소에 접근한다.
이를 확장해서 생각해보면 3차원 배열은 3개의 값(x,y,z) 을 가지고 원소에 접근하는 것이다. 우리의 원소가
몇 층(x)에 있고 그 층에서 몇 행(y), 그리고 몇 열(z)에 있는지 알 수 있다면 int
형 변수에 정확하게 접근이 가능하다.
4차원도 마찬가지이다. 4차원 배열은 4개의 값(x,y,z,w)를 가지고 원소에 접근하는 것이고, 5차원 배열은 5개의 값을 가지고, n차원은 n개의 값을 가지고 원소에 접근하는 것이다. 이러한 아이디어를 적용시키면 어떠한 차원의 배열이 프로그래밍에서 필요하다 하더라고 문제 없이 해결 할 수 있다.