C++ 메모리 정적 할당 vs 동적 할당 (Stack vs Heap)
Memory 영역 (Stack vs Heap)
컴퓨터에서 메모리 영역은 아래와 같이 나뉘어있다.
- Code : 실행한 프로그램의 코드가 저장됨
- Data : 전역변수와 static변수가 저장되며 프로그램 종료 시까지 사라지지 않고 남아있음
- Heap : 동적으로 할당된 메모리영역이며 프로그래머에 의해 할당( C++ : new, C : malloc ) 및 해제( C++ : delete, C : free )됨
- Stack : 지역변수와 매개변수가 할당되고 함수를 빠져나가면 자동 소멸됨
정적 메모리 할당 vs 동적 메모리 할당
프로그래밍 관점에서 메모리 영역에는 크게 stack과 heap 메모리 공간이 있다.
정적으로 메모리를 할당하면 컴파일 시 stack 영역에 할당되며, 함수를 빠져나갈 때 소멸된다.
프로그램 컴파일 시 stack에 얼마만큼의 크기로 할당을 해야하는지 결정되기 때문에, 컴파일 이후 크기가 변경될 수 없다.
따라서 정적 배열 선언 시 크기를 가변적으로 명시하면 문제가 될 수 있으므로 반드시 상수로 명시해야 한다.
int main() {
int n = 10;
int arr[n]; // 불가능
int arr[10]; // 가능
}
반면 동적으로 메모리를 할당하는 경우 데이터가 heap 영역에 할당된다.
위에서 다루었듯이 heap은 프로그래머에 의해 할당(new)되거나 소멸(delete)된다.
따라서 프로그래머가 원할 때 원하는 크기로 할당할 수 있는 것이다.
참고로 포인터 변수는 stack에 할당된다.
int main() {
int n = 10;
int* arr = new int[n]; // arr 포인터 변수는 stack에 할당되며, arr 배열은 heap에 할당됨
}
new & delete
위에서 했던 이야기지만, 정적 메모리는 Compile 시에 stack 영역에 할당되고 함수를 빠져나올 때 소멸된다.
반면 동적 메모리는 Runtime 시 프로그래머의 의도대로 heap 영역에 할당되고 소멸된다.
따라서 동적 메모리를 control 하기 위해 규칙을 정해놓았으며, C++에서는 할당 시 new 연산자를 사용하며 소멸 시엔 delete 연산자를 사용한다.
heap 영역에 동적 할당되는 메모리의 경우 전적으로 프로그래머에 의해 관리되므로, 사용이 끝난다면 반드시 delete를 해주어야 한다.
참고로 동적 배열을 delete 하는 경우 배열이라는 것을 명시하기 위해 delete[] 연산자를 사용해야만 한다.
// 할당
int *pData = new int;
int *array = new int[size];
// 소멸
delete pData;
delete[] array;
2차원 배열의 동적 할당
2차원 배열을 동적할당 하는 경우 아래와 같은 구조를 가진다.
- mat : int**형
- mat[i] : int*형
- mat[i][j] : int형
2차원 동적 배열은 단순하게 한 줄로 선언하기 힘들고 loop를 돌며 일일이 할당 및 해제를 해줘야 한다.
#include <iostream>
using namespace std;
// int형 2차원 배열 동적 할당
int** alloc2DArr (int rows, int cols){
if(rows <= 0 || cols <= 0) return NULL;
int** mat = new int* [rows];
for (int i=0 ; i<rows ; i++ )
mat[i] = new int[cols];
return mat;
}
// int형 2차원 배열 동적 해제
void free2DArr ( int** mat, int rows, int cols=0){
if(mat != NULL){
for(int i=0 ; i<rows ; i++)
delete[] mat[i];
delete[] mat;
}
}
int main() {
int **mat;
int rows, cols;
cin >> rows >> cols;
// mat 할당
mat = alloc2DArr(rows, cols);
// mat[][] 랜덤 입력
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
mat[i][j] = rand()%100;
}
}
// mat 출력
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
cout << mat[i][j] << " ";
}
cout << endl;
}
// mat 해제
free2DArr(mat, rows, cols);
return 0;
}
참고로 2중 loop를 돌리는 것보다 memset (#include <string.h>)을 사용하는 것이 유용하다.
또한 이보다 vector를 사용하는 것이 더욱 편리하고 빠르다.