C++에서는 메모리를 동적으로 할당하고 해제할 수 있는 기능을 제공합니다. 동적 할당을 통해 프로그램 실행 중에 필요한 메모리를 할당받고 사용할 수 있습니다. 이번 포스트에서는 동적 할당의 기본 개념과 다양한 예제를 살펴보겠습니다.
#include <iostream>
using namespace std;
int main()
{
// 첫 번째 블록: 지역 변수와 정적 변수
{
int num0 = 0; // 지역 변수, 해당 블록 내에서만 접근 가능
static int num1 = 0; // 정적 변수, 프로그램 시작 시 할당되고 종료 시 해제
}
// 두 번째 블록: 자동 지역 변수와 정적 지역 변수
{
for (int i = 0; i < 3; ++i)
{
int num0 = 0; // 자동 지역 변수, 블록 내에서만 유효
static int num1 = 0; // 정적 지역 변수, 프로그램 시작 시 할당, 블록을 벗어나도 값 유지
++num0; // num0 값 증가
++num1; // num1 값 증가
cout << "num0 : " << num0 << endl; // 1 출력 (매번 새로 초기화됨)
cout << "num1 : " << num1 << endl; // 1, 2, 3 출력 (값이 유지됨)
}
}
// 세 번째 블록: 동적 할당 및 해제
{
int* pNum = new int; // 동적 할당된 메모리를 가리키는 포인터
delete pNum; // 할당된 메모리 해제
}
// 네 번째 블록: 메모리 누수 예제
{
// while (true)
// {
// int* num = new int; // 메모리 누수 발생, 해제되지 않음
// }
}
// 다섯 번째 블록: 동적 할당된 메모리의 공유와 해제
{
int* pNum0 = new int(123); // 동적 할당된 메모리 초기화
int* pNum1 = pNum0; // 같은 메모리를 가리키는 포인터
cout << *pNum0 << endl; // 123 출력
delete pNum0; // 메모리 해제
// 이미 해제된 메모리에 접근 (위험)
// cout << *pNum0 << endl;
// cout << *pNum1 << endl;
// 이미 해제된 메모리를 다시 해제 (위험)
// delete pNum0;
}
// 여섯 번째 블록: 지역 변수의 주소를 외부에서 사용하는 경우
{
int* pNum;
{
int n = 10;
pNum = &n; // n의 주소를 pNum에 저장
}
// 이미 해제된 메모리에 접근 (위험)
// cout << *pNum << endl;
}
// 일곱 번째 블록: 동적 할당을 통한 가변 배열 사용
{
int s;
cin >> s; // 배열 크기 입력
int* arr = new int[s]; // 동적으로 배열 할당
arr[0] = 1; // 첫 번째 요소에 값 할당
cout << arr[0] << endl; // 첫 번째 요소 출력
delete[] arr; // 배열 메모리 해제
}
// 여덟 번째 블록: 구조체와 동적 할당
{
struct Person
{
float weight;
float height;
};
Person* person = new Person{ 74.1f, 180.2f }; // 구조체 동적 할당 및 초기화
cout << (*person).weight << endl; // 74.1 출력
cout << person->weight << endl; // 74.1 출력 (간접 참조)
Person* persons[3] = {
new Person{56.1f, 174.f},
new Person{74.2f, 184.f}
}; // 구조체 배열 동적 할당 및 초기화
for (Person* person : persons)
{
person->weight = 0.0f; // 각 구조체의 weight 값 초기화
}
for (Person* person : persons)
{
cout << person->weight << endl; // 0.0 출력
}
// 동적 할당된 메모리 해제
delete person;
delete persons[0];
delete persons[1];
// persons[2]는 초기화되지 않았으므로 해제할 필요 없음
}
return 0;
}
첫 번째 블록에서는 지역 변수와 정적 변수를 살펴봅니다.
{
int num0 = 0; // 지역 변수, 해당 블록 내에서만 접근 가능
static int num1 = 0; // 정적 변수, 프로그램 시작 시 할당되고 종료 시 해제
}
num0
은 지역 변수로 해당 블록 내에서만 유효합니다.num1
은 정적 변수로 프로그램 시작 시 한 번 할당되고 프로그램 종료 시 해제됩니다.두 번째 블록에서는 자동 지역 변수와 정적 지역 변수를 비교합니다.
{
for (int i = 0; i < 3; ++i)
{
int num0 = 0; // 자동 지역 변수, 블록 내에서만 유효
static int num1 = 0; // 정적 지역 변수, 프로그램 시작 시 할당, 블록을 벗어나도 값 유지
++num0; // num0 값 증가
++num1; // num1 값 증가
cout << "num0 : " << num0 << endl; // 1 출력 (매번 새로 초기화됨)
cout << "num1 : " << num1 << endl; // 1, 2, 3 출력 (값이 유지됨)
}
}
num0
은 매번 새로 초기화되므로 항상 1이 출력됩니다.num1
은 정적 변수로 값이 유지되어 1, 2, 3이 출력됩니다.세 번째 블록에서는 동적 할당과 해제의 기본 개념을 다룹니다.
{
int* pNum = new int; // 동적 할당된 메모리를 가리키는 포인터
delete pNum; // 할당된 메모리 해제
}
new
키워드를 사용하여 메모리를 동적 할당합니다.delete
키워드를 사용하여 할당된 메모리를 해제합니다.네 번째 블록에서는 메모리 누수의 예를 보여줍니다.
{
// while (true)
// {
// int* num = new int; // 메모리 누수 발생, 해제되지 않음
// }
}
delete
를 사용하여 할당된 메모리를 해제하지 않으면 메모리 누수가 발생합니다.다섯 번째 블록에서는 동적 할당된 메모리를 여러 포인터가 가리킬 때의 위험성을 다룹니다.
{
int* pNum0 = new int(123); // 동적 할당된 메모리 초기화
int* pNum1 = pNum0; // 같은 메모리를 가리키는 포인터
cout << *pNum0 << endl; // 123 출력
delete pNum0; // 메모리 해제
// 이미 해제된 메모리에 접근 (위험)
// cout << *pNum0 << endl;
// cout << *pNum1 << endl;
// 이미 해제된 메모리를 다시 해제 (위험)
// delete pNum0;
}
여섯 번째 블록에서는 지역 변수의 주소를 외부에서 사용하는 경우의 위험성을 다룹니다.
{
int* pNum;
{
int n = 10;
pNum = &n; // n의 주소를 pNum에 저장
}
// 이미 해제된 메모리에 접근 (위험)
// cout << *pNum << endl;
}
합니다.
일곱 번째 블록에서는 동적 할당을 통해 가변 배열을 사용하는 방법을 다룹니다.
{
int s;
cin >> s; // 배열 크기 입력
int* arr = new int[s]; // 동적으로 배열 할당
arr[0] = 1; // 첫 번째 요소에 값 할당
cout << arr[0] << endl; // 첫 번째 요소 출력
delete[] arr; // 배열 메모리 해제
}
delete[]
를 사용하여 메모리를 해제합니다.여덟 번째 블록에서는 구조체와 동적 할당을 다룹니다.
{
struct Person
{
float weight;
float height;
};
Person* person = new Person{ 74.1f, 180.2f }; // 구조체 동적 할당 및 초기화
cout << (*person).weight << endl; // 74.1 출력
cout << person->weight << endl; // 74.1 출력 (간접 참조)
Person* persons[3] = {
new Person{56.1f, 174.f},
new Person{74.2f, 184.f}
}; // 구조체 배열 동적 할당 및 초기화
for (Person* person : persons)
{
person->weight = 0.0f; // 각 구조체의 weight 값 초기화
}
for (Person* person : persons)
{
cout << person->weight << endl; // 0.0 출력
}
// 동적 할당된 메모리 해제
delete person;
delete persons[0];
delete persons[1];
// persons[2]는 초기화되지 않았으므로 해제할 필요 없음
}