char* text =new char[100][50]; |
코드4. 2차원 배열의 동적할당? |
위와 같이 선언하시고 컴파일해보시기 바랍니다. 저는 마이크로소프트사의 C++ 컴파일러 v7.1을 사용하는데, 제 컴파일러의 경우에는 아래와 같은 컴파일 에러 메시지를 띄웁니다.
error C2440: '초기화 중' : 'char(*)[50]'에서 'char *'(으)로 변환할 수 없습니다. |
표1. 컴파일 에러 메시지 |
C++의 배정 연산자 '='은 좌측변수의 타입과 우측 값의 타입이 동일하거나 변환이 가능할 때 실행됩니다. 코드4의 경우에는포인터 배열을포인터 변수에 대입하려했기 때문에 에러가 난 것입니다.
포인터 배열이란 포인터 변수들로 이루어진 배열을 말합니다. 즉, 배열의 값으로 주소가 들어가는 배열을 말하죠.포인터 변수는 말 그대로 배열이 아닌 변수 하나입니다. 주소를 값으로 가지고 있는 하나의 변수지요. 코드4를 살펴보면 좌측값(l-value)에는 포인터 변수가 자리잡고 있습니다(문자 포인터형). 그런데 우측값(r-value)에는 2차원 배열이 있군요. 배열의 변수명은 포인터 변수처럼 사용할 수 있습니다. 즉 int a[50]을 선언했다면 a라는 배열이름은 포인터 변수처럼 쓸 수 있는 것이죠. 왜냐면 배열의 이름은 배열의 첫번째 인덱스의 주소값을 의미하기 때문입니다.
그렇게 생각해보면 코드4의 char[100][50]은 표1의 에러메시지처럼 char(*)[50]으로 바꿀 수 있습니다. 그래서 2차원 배열은 포인터 배열에 대입될 수 있는 것입니다. 그럼 코드4를 에러가 안나도록 고쳐보죠.
char(* text)[50] =new char[100][50]; |
코드5. 2차원 배열의 동적할당 수정 |
코드5처럼 고치면 정상적으로 할당이 되며 text는 완벽히 2차원 배열처럼 동작합니다. text가 메모리에 할당된 모습을 보도록 하죠. 참고로 각 배열값에 들어가 있는\0은 text를 NULL로 초기화했다는 가정아래 적은 값입니다.
그림4에서 보이는 것처럼 text 배열은 2차원 배열처럼 작동하지만 메모리 구조를 살펴보면 여전히 스택영역에 4바이트 * 50칸 = 200바이트를 차지하고 있습니다. 그다지 큰 값은 아니지만 스택영역의 일부를 차지하고 있다는 것을 보면 깔끔한 동적할당이라 볼 수 없습니다. 그럼 어떻게 동적할당을 해야 깔끔하게 가능할까요? 이를 그림으로 한 번 보겠습니다.
그림5처럼 할당을 한다면 스택영역에는 단 하나의 포인터인 4바이트만 소비하고 나머지는 모조리 힙영역에 할당되므로 이것이야말로 동적할당의 참모습이라 할 수 있습니다. 이렇게 할당하기 위해서는 text가 주소의 주소를 가리켜야 하므로 이중 포인터(doubly pointer)로 만들어야 합니다. 그래야 text의 값 또한 주소를 가질 수 있기 때문입니다.
char** text; |
코드6. 이중 포인터의 선언 |
코드6처럼 이중 포인터는 포인터 연산자 *를 두 번 씀으로써 사용이 가능합니다. 삼중 포인터라면 *를 세 개 붙이면 되겠죠. 이제 여기에 동적할당을 할 차례입니다. 동적할당은 그림5를 보면서 설명드리자면, 가운데 있는 50칸짜리 공간을 할당한 후, 반복문을 이용해서 50칸에 각각 100칸짜리 공간을 할당하는 방식을 씁니다. 코드6은 50칸짜리 공간을 할당하는 코드입니다.
char** text =new char*[50]; |
코드6. 이중 포인터를 이용한 배열의 동적할당 #1 |
코드6을 보면 text가 이중 포인터이기 때문에 new 연산자 오른쪽에 위치한 코드가 char[50]이 아닌 char*[50]으로 써있습니다. 이 부분에 주의하셔야 합니다. 그럼 50칸을 생성했으니 100칸을 생성해봅시다.
char** text =new char*[50]; for(inti =0; i <50; i++) text[i] =new char[100]; |
코드7. 이중 포인터를 이용한 배열의 동적할당 #2 |
코드7의 text[i]에 해당하는 그림이 바로 그림5의 가운데 있는 칸들입니다. 이 50개의 칸에 for문을 50번 돌리면서 100칸짜리 방(그림5의 오른쪽)을 만드는 것이죠. 이렇게 할당이 끝났으면 text는 또 다시 완벽한 2차원 배열처럼 사용이 가능합니다. 참고로 for문 내의 char[100]부분의 100이라는 숫자를 i에 따라 다르게 쓰시면 각 배열의 크기가 다른 2차원 배열도 만들 수 있습니다.
할당을 했으니 다 사용하신 후에 해제하는 방법도 아셔야죠.^^ 해제의 순서는 할당과 반대로 오른쪽에 있는 100칸짜리들부터 해제합니다. 50칸을 먼저 해제해버리면 100칸짜리들의 주소가 어딘지 알 수 없게 되버리니까요.
for(i =0; i <50; i++) delete[] text[i]; delete[] text; |
코드8. 이중 포인터를 이용한 배열의 해제 |
3. 고차원 배열의 동적할당
설명이 상당히 어설픈것 같았는데 이해가 가셨는지 모르겠네요-_-; 그럼 2차원을 확장해서 3차원 배열의 동적할당을 해봅시다. 방법은 2차원과 같습니다. 단지 반복문이 하나 더 늘어나고 포인터가 삼중이 되는 것일 뿐이죠. ^^ text[10][50][100]을 만드는 것으로 간단히 그림과 코드를 살펴보겠습니다.
// 할당 char*** text =new char**[10]; for(inti =0; i <10; i++) { text[i] =new char*[50]; for(intj =0; j <50; j++) text[i][j] =new char[100]; } // 해제 for(i =0; i <10; i++) { for(intj =0; j <50; j++) delete[] text[i][j]; delete[] text[i]; } delete[] text; |
코드9. 삼중 포인터를 이용한 배열의 동적할당 및 해제 |
4차원 배열은 쓸 일이 거의 없겠지만, 마찬가지 방법이겠죠? :)
이상 고차원 배열의 동적할당이었습니다^^
-벌나래 네트 에서..-