9-2-라.2차 배열 초기화

2차원 이상의 다차원 배열을 초기화하는 방법도 1차원 배열과 비슷하지만 차원이 높아지므로 좀 더 다양한 초기화 방법이 존재한다. 여기서는 유형별로 이차원 배열을 초기화하는 방법에 대해 알아보되 예제로 간단한 int ar[2][3] 배열을 사용하기로 하자.

 

 초기값 개수가 꼭 맞는 경우

배열 크기와 초기값 개수가 일치하면 가장 자연스럽고 이해하기도 쉽다. { } 괄호안에 초기식을 나열하기만 하면 된다. ar 배열의 총 크기는 2*3=6이므로 여섯 개의 초기값을 적어준다.

 

int ar[2][3]={1,2,3,4,5,6};

 

이 선언문에 의해 ar배열은 다음과 같이 초기화될 것이다.

앞쪽 세 개의 초기값 1,2,3이 첫 행인 ar[0][0]~ar[0][2]까지 차례대로 채워지고 나머지 세 개의 초기값이 다음 행에 채워진다. 다차원 배열도 메모리상에는 선형의 연속적인 공간에 생성되므로 초기값만 나열하여 등장하는 순서대로 배열 요소와 대응시키면 된다. 그러나 이렇게 초기값을 죽 나열해 버리면 어디서부터 어디까지가 한 행인지 구별이 잘 안되므로 행별로 초기값을 따로 묶어주는 것이 더 좋다.

 

int ar[2][3]={{1,2,3},{4,5,6}};

 

{1,2,3}이 첫 번째 행의 초기값이고 {4,5,6}이 두 번째 행의 초기값이라는 것이 분명히 표시되므로 차후에 초기값을 변경할 때 편리하다. 컴파일러는 { } 괄호가 있건 없건 순서대로 값을 읽기만 하면 되지만 이왕이면 사람도 이 선언문을 읽기 쉽게 해 두는 것이 좋다. 만약 이 배열이 ar[10][50] 정도의 크기를 가질 때 각 행별로 { }를 싸 놓지 않으면 ar[4][26] 번째 요소를 찾기가 아주 어려울 것이다.

이런 큰 배열을 선언 및 초기화할 때는 각 행 별로 { } 괄호를 싸고 또 가급적이면 각 행 다음에 개행을 해서 한눈에 배열 구조를 파악할 수 있도록 선언하는 것이 차후에 소스를 고치기에 편리하다. 2차 배열을 초기화하는 가장 좋은 방법은 다음과 같은 형식을 따르는 것이다.

 

int ar[2][3]={

     {1,2,3},

     {4,5,6},

};

 

소스가 조금 길어지기는 하겠지만 얼마나 보기 좋고 깔끔한가? 보기에 좋으면 유지, 보수할 때도 시간을 많이 절약할 수 있다. 여기서 마지막행 끝에 있는 여분 콤마는 컴파일러에 의해 무시되지만 마지막 행을 중간행과 똑같은 모양이 되도록 하여 행을 쉽게, 추가, 이동할 수 있도록 하는 역할을 한다. {1,2,3} 행과 {4,5,6}행의 순서를 바꾸고 싶으면 두 번째 행을 잘라 위에 붙여 넣기만 하면 된다. 여분 콤마를 인정하지 않으면 편집할 때마다 제일 끝행의 콤마만 삭제해야 하므로 무척 불편하며 사람들이 불편을 느끼면 표준은 개정되기 마련이다. 클래식 C는 마지막 요소의 여분 콤마를 인정하지 않았으나 수많은 사람들의 요청에 의해 ANSI C부터 이를 지원하기 시작했다. 표준이란 이런 식으로 여러 사람들의 노력에 의해 오랜 시간을 걸쳐 발전해 온 것이다.

 초기값이 모자랄 때

특정행의 나머지 요소를 모두 0으로 초기화할 때는 0을 일일이 밝히지 않아도 된다. 만약 첫 행의 두 번째 이후 요소가 전부 0이라면 다음과 같이 초기화한다.

 

int ar[2][3]={{1},{4,5,6}};

 

이 선언문에 의해 ar 배열은 다음과 같이 초기화된다.

첫 번째 행의 초기값이 하나밖에 없으므로 나머지 뒷부분은 모두 0이 될 것이고 두 번째 행은 초기값이 모두 있으므로 순서대로 초기화된다. 다음 두 선언문도 동일하다.

 

int ar[2][3]={{1,0,0},{4,5,6}};

int ar[2][3]={{1,},{4,5,6}};

 

0까지 같이 다 적어도 효과는 동일하되 다만 요소 개수가 많으면 효율적이지 못하다. 가장 좋은 방식은 첫 번째 행의 초기값 1다음에 콤마를 하나 찍어 나머지 요소가 모두 0으로 초기화된다는 것을 분명히 표시하는 것이다. 컴파일러는 이 콤마를 완전히 무시하지만 소스를 읽는 사람을 위해 붙이는 것이 좋다. 세 가지 형식 모두 동일하지만 다음 선언문은 의미가 다르다.

 

int ar[2][3]={1,4,5,6};

 

중괄호가 없으므로 초기식에 나타나는 순서대로 배열 요소를 채워 나가다가 남는 요소를 0으로 초기화하므로 0이 되는 배열 요소가 달라져 버린다.

중간에 있는 행의 나머지 요소에 대한 초기값을 생략할 때는 행단위로 중괄호를 반드시 싸야 한다.

 초기값 개수가 남는 경우

1차원 배열에서와 마찬가지로 초기값이 남으면 too many initializer에러가 된다. 다음 두 선언문 모두 에러이다.

 

int ar[2][3]={{1,2,3},{4,5,6,7}};

int ar[2][3]={{1,2},{4,5,6,7}};

 

위쪽 선언문은 초기값이 7개이며 배열 크기보다 더 많은 초기값이 있으므로 당연히 에러다. 아래쪽 선언문은 초기값은 6개가 맞지만 두 번째 행의 초기값이 4개이므로 이것도 역시 에러로 처리된다. 만약 이 선언문에서 중괄호를 없애 버리면 에러로 처리되지 않는다.

 

int ar[2][3]={1,2,4,5,6,7};

 

이렇게 되면 배열 크기와 초기값 개수가 일치하므로 초기화는 잘 되겠지만 이것이 원하는 결과는 아니었을 것이다. 첫 번째 행을 1,2,0으로 초기화하려고 마지막 요소를 생략했는데 두 번째 행의 초기값이 하나가 남게 되면 서로 상충되어 아주 정상적인 선언문이 되어 버린 것이다. 이런 실수를 방지하기 위해 행별로 중괄호를 싸는 것이다.

 배열의 크기를 생략하는 방법

2차원 배열도 1차원 배열과 마찬가지로 배열의 크기를 생략할 수 있되 1차 첨자의 크기만 생략 가능하며 나머지 첨자는 반드시 밝혀야 한다.

 

int ar[][3]={{1,2,3},{4,5,6}};

 

1차 첨자의 크기를 생략해도 행이 두 개임이 명백하기 때문에 컴파일러는 1차 첨자 크기가 2라는 것을 알 수 있다. 열의 개수가 3개임을 명백히 밝혀 주었으므로 세 개씩 묶어보면 필요한 행의 개수가 자동으로 계산된다. 설사 중괄호가 없더라도 배열 크기를 계산하는데는 아무 문제가 없다. 이 상태에서 행을 더 늘리고 싶으면 초기식을 더 적기만 하면 된다.

 

int ar[][3]={{1,2,3},{4,5,6},{7,},{8,9,10}};

 

이 선언문에 의해 ar 배열은 4행이 될 것이다. 세 번째 행의 뒷부분이 0으로 지정되어 있으므로 이 경우는 중괄호를 생략할 수 없다. 3차원, 4차원의 다차원 배열도 첫 번째 첨자 크기만 생략할 수 있다. 두 번째 이후의 첨자까지 같이 생략해 버릴 수 없는 이유는 두 번째 첨자 이후는 배열의 모양을 지정하기 때문이다.

 

int ar[][]={{1,2,3},{4,5,6}};

 

이렇게 선언해 버리면 이 배열이 2행 3열인지 3행 2열인지 또는 1행 6열인지 구분되지 않는 모호함이 생긴다. 물론 사람은 중괄호를 보고 2행 3열이라는 추측을 할 수 있겠지만 중괄호는 강제 문법이 아니기 때문에 이를 보고 컴파일러가 배열의 모양을 정확하게 파악하는 것은 불가능하다.

이상으로 2차원 배열의 초기화 방법에 대해 알아보았다. 차원이 높기 때문에 괜히 복잡해 보이지만 개수와 크기를 꼭꼭 맞추어준다면 특별히 어려울 것도 없다. 아직 배열에 익숙치 않은 상태에서 신체의 편안함을 도모해 보고자 괜히 중괄호나 배열 크기를 생략하는 것은 당분간 자재하고 정석대로 초기화를 하면 별 문제가 없을 것이다.