15. 동적 할당과 배열의 차이
동적 할당과 배열은 일차원보다 다차원에서 차이점을 쉽게 구분할 수 있다.
일차원은 차이가 거의 없다.
결론부터 말하면 일차원에서 동적 할당과 배열은 한가지 부분을 제외하고는 차이가 없다.
동적 할당은 선언 할 때 상수/변수 상관없이 생성할 수 있지만 배열은 상수만 된다.
▼ 일차원에서 동적 할당과 배열의 코드
#include <cstdio>
#include <cstdlib>
int main()
{
const int arrMax = 5;
// INIT STATIC ARRAY
int iArr[arrMax] = { 0,1,2,3,4 };
// PRINT STATIC ARRAY
printf("== STATIC ARRAY ==\n");
for (int i = 0; i < arrMax; i++)
{
printf("<%p> iArr[%d] : %d\n", (iArr + i), i, iArr[i]);
}
printf("\n");
// INIT DYNAMIC ARRAY
int* pArr = new int[arrMax] {4,3,2,1,0};
// PRINT DYNAMIC ARRAY
printf("== DYNAMIC ARRAY ==\n");
for (int i = 0; i < arrMax; i++)
{
printf("<%p> pArr[%d] : %d\n", (pArr + i), i, pArr[i]);
}
// DELETE DYNAMIC ARRAY
delete[] pArr;
return (0);
}
일차원 배열도 동적 할당도 연속적으로 메모리를 저장한다.
언제나 고정적인 상수만을 받는 배열과 달리 동적 할당은 프로그램 중간에도
언제든지 마음대로 크기를 정할 수 있다는 점에서 큰 장점을 가진다.
출력할 때도 둘 다 같은 방법으로 출력할 수 있다.
다차원에서 차이가 큰 경우
다차원의 경우엔 동적 할당을 어떻게 사용하는지에 따라 크게 차이 날 수도 있다.
먼저 크게 차이가 나는 경우를 살펴본다.
▼ 이차원에서 동적 할당과 배열의 차이 가 큰 코드
#include <cstdio>
#include <cstdlib>
int main()
{
const int rowMax = 2;
const int colMax = 3;
int num = 0;
// INIT STATIC ARRAY
int miArr[rowMax][colMax] = {};
// SET STATIC ARRAY
for (int row = 0; row < rowMax; row++)
{
for (int col = 0; col < colMax; col++)
{
miArr[row][col] = num;
num++;
}
}
// PRINT STATIC ARRAY
printf("==== STATIC ARRAY ====\n");
for (int row = 0; row < rowMax; row++)
{
for (int col = 0; col < colMax; col++)
{
printf("<%p>mdArr[%d][%d] : %d\n",
*(miArr + row) + col, row, col, *(*(miArr + row) + col));
}
}
printf("\n");
num = 0;
// INIT DYNAMIC ARRAY
int** mdArr = new int* [rowMax] {};
// SET DYNAMIC ARRAY
for (int row = 0; row < rowMax; row++)
{
*(mdArr + row) = new int[colMax] {};
for (int col = 0; col < colMax; col++)
{
*(*(mdArr + row) + col) = num;
num++;
}
}
// PRINT DYNAMIC ARRAY
printf("==== DYNAMIC ARRAY ====\n");
for (int row = 0; row < rowMax; row++)
{
for (int col = 0; col < colMax; col++)
{
printf("<%p>mdArr[%d][%d] : %d\n",
*(mdArr + row) + col, row, col, *(*(mdArr + row) + col));
}
}
// DELETE DYNAMIC ARRAY
delete[] mdArr;
return (0);
}
이 코드에 따르면 이차원 배열은 역시나 연속된 메모리 주소를 가지고 있는 반면,
이차원 동적 할당은 깊이에 따라 메모리 시작 주소가 다르다.
이는 동적 할당과 배열의 메모리 저장 방식의 차이를 알면 쉽게 이해할 수 있다.
이차원 배열
▼ 이차원 배열의 메모리 저장 방식
이차원 배열은 이차원 배열의 형식으로 생성하기 때문에 배열 속에 배열에 있다고 생각하기 쉽다.
하지만 이차원 배열도 실제로 내부에서는 일차원 배열과 같이 연속적으로 메모리가 할당된다.
이차원 배열은 선언할 때와 접근할 때 이차원 배열 형식을 사용하는 것 말고는 일차원 배열과 다르지 않다.
반면 이차원 동적 할당의 경우엔 조금 다르게 작동한다.
동적 할당을 할 때 메모리를 할당하는 위치를 프로그래머가 지정할 수 없다는 점에서 차이가 발생한다.
이차원 동적 할당
▼ 이차원 동적 할당의 메모리 저장 방식
동적 할당은 다르게 말하면 배열 안에 배열을 넣어둔 형태다.
즉, mdArr 배열은 mdArr[2] = {A[3], B[3]} 과 같다.
엄연히 하나의 배열이기 때문에 이 배열 속의 값 두 개는 주소는 연속된 값을 가질 수 있다.
문제는 A[3]과 B[3] 이 각각의 배열들은 또 별개의 배열이기 때문에 내부 인자들은 다른 메모리를 할당 받는다.
결과적으로 A[3]에 있는 인자들끼리 연속적인 메모리를 가지고
B[3]에 있는 인자들끼리 연속적인 메모리를 가진다.
그렇다면 이차원 배열과 같은 방법으로 동적 할당을 사용할 수는 없는걸까?
물론 가능하다.
다차원에서 차이가 상대적으로 작은 경우
▼ 이차원에서 동적 할당과 배열의 차이가 상대적으로 작은 코드
#include <cstdio>
#include <cstdlib>
int main()
{
const int rowMax = 2;
const int colMax = 3;
int num = 0;
// INIT STATIC ARRAY
int miArr[rowMax][colMax] = {};
// SET STATIC ARRAY
for (int row = 0; row < rowMax; row++)
{
for (int col = 0; col < colMax; col++)
{
miArr[row][col] = num;
num++;
}
}
// PRINT STATIC ARRAY
printf("==== STATIC ARRAY ====\n");
for (int row = 0; row < rowMax; row++)
{
for (int col = 0; col < colMax; col++)
{
printf("<%p>mdArr[%d][%d] : %d\n",
*(miArr + row) + col, row, col, *(*(miArr + row) + col));
}
}
printf("\n");
num = 0;
// INIT DYNAMIC ARRAY
int* dArr = new int[rowMax * colMax]{};
int** mdArr = new int* [rowMax] {};
// SET DYNAMIC ARRAY
for (int row = 0; row < rowMax; row++)
{
*(mdArr + row) = dArr + ((long long)row * colMax);
for (int col = 0; col < colMax; col++)
{
*(dArr + ((long long)row * colMax) + col) = num;
num++;
}
}
// PRINT DYNAMIC ARRAY
printf("==== DYNAMIC ARRAY ====\n");
for (int row = 0; row < rowMax; row++)
{
for (int col = 0; col < colMax; col++)
{
printf("<%p>mdArr[%d][%d] : %d\n",
*(mdArr + row) + col, row, col, *(*(mdArr + row) + col));
}
}
// DELETE DYNAMIC ARRAY
delete[] dArr;
delete[] mdArr;
return (0);
}
위 코드와는 반대의 방법을 사용한다.
아예 처음부터 연속된 일차원 동적 할당 dArr을 만든 다음 이차원 동적 할당 mdArr에 나눠서 담아준다.
이미 하나의 동적 할당으로 연속적인 메모리를 확보 했기 때문에
이차원 동적 할당에 처음과 중간 주소를 대입해주기만 하면 이차원 배열과 동일한 기능을 가질 수 있다.