C++ 초급 - 5. 포인터와 참조 (Pointers and References) (2 - 동적 메모리 할당 (new, delete))

2025. 2. 12. 18:42프로그래밍 언어/C++

📌 5.2 동적 메모리 할당 (new, delete)

C++에서는 new와 delete 키워드를 사용하여 런타임(Run-time)동적으로 메모리를 할당 및 해제할 수 있다.

동적 메모리 할당을 활용하면 프로그램 실행 중 필요한 만큼 메모리를 할당할 수 있으며,
전역 변수나 지역 변수로 선언할 수 없는 대량의 데이터 처리나 가변적인 크기의 배열 관리가 가능하다.

그러나, 할당한 메모리를 해제하지 않으면 메모리 누수(Memory Leak)가 발생할 수 있으므로 delete를 사용하여 반드시 해제해야 한다.


📌 1. new와 delete를 사용한 동적 메모리 할당 및 해제

🔹 (1) new 키워드: 동적 메모리 할당

  • new 키워드는 힙(Heap) 영역에 메모리를 동적으로 할당한다.
  • 사용이 끝나면 반드시 delete로 해제해야 한다.

💡 기본 문법

데이터타입* 포인터변수 = new 데이터타입;

💡 예제: 동적 메모리 할당

#include <iostream>

int main() {
    int* ptr = new int;  // 정수형 데이터를 위한 메모리 할당
    *ptr = 42;  // 값 할당

    std::cout << "할당된 메모리의 값: " << *ptr << std::endl;

    delete ptr;  // 메모리 해제
    return 0;
}

🔹 출력 결과

할당된 메모리의 값: 42

💡 설명

  • new int → 정수형 크기만큼 힙 영역에 메모리 할당.
  • *ptr = 42; → 할당된 메모리에 값 저장.
  • delete ptr; → 메모리 해제.

🔹 (2) delete 키워드: 동적 메모리 해제

  • delete 키워드는 동적 메모리 할당된 데이터를 해제한다.
  • delete를 사용하지 않으면 메모리 누수(Memory Leak)가 발생할 수 있다.

💡 기본 문법

delete 포인터변수;

💡 예제: 메모리 누수 방지

#include <iostream>

int main() {
    int* num = new int(100);  // 동적 메모리 할당 및 초기화

    std::cout << "num의 값: " << *num << std::endl;

    delete num;  // 메모리 해제
    num = nullptr;  // 안전한 포인터 초기화

    return 0;
}

🔹 출력 결과

num의 값: 100

💡 설명

  • new int(100); → 정수형 메모리를 동적으로 할당하고 100으로 초기화.
  • delete num; → 할당된 메모리를 해제.
  • num = nullptr; → 해제된 포인터를 nullptr로 설정하여 잘못된 접근 방지.

📌 2. 배열의 동적 할당 (new[], delete[])

  • 단일 변수뿐만 아니라 배열도 동적으로 할당 가능하다.
  • new[]을 사용하여 배열을 할당하고, delete[]를 사용하여 해제해야 한다.

💡 기본 문법

데이터타입* 포인터변수 = new 데이터타입[배열크기];  // 배열 동적 할당
delete[] 포인터변수;  // 배열 메모리 해제

💡 예제: 배열 동적 할당 및 해제

#include <iostream>

int main() {
    int size = 5;
    int* arr = new int[size];  // 정수형 배열 동적 할당

    // 배열 초기화
    for (int i = 0; i < size; i++) {
        arr[i] = i * 10;
    }

    // 배열 출력
    std::cout << "배열 요소: ";
    for (int i = 0; i < size; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    delete[] arr;  // 배열 메모리 해제

    return 0;
}

🔹 출력 결과

배열 요소: 0 10 20 30 40

💡 설명

  • new int[size] → size 크기의 정수 배열을 동적으로 할당.
  • delete[] arr; → 배열 전체를 해제.

주의: 단일 변수는 delete, 배열은 delete[]를 사용해야 함!

잘못된 코드 예시 (delete[] 없이 배열 삭제)

delete arr;  // ❌ 배열 할당에 delete[]를 사용해야 함.

잘못된 코드 예시 (delete 없이 배열 사용)

int* arr = new int[5];
arr[0] = 10;
std::cout << arr[0] << std::endl;
// delete[] arr;  // ❌ 메모리 해제를 하지 않으면 메모리 누수 발생!

📌 3. 메모리 누수 방지 및 올바른 해제 방법

동적 메모리 할당 시 올바르게 해제하지 않으면 프로그램이 종료될 때까지 메모리를 차지하게 되어
**메모리 누수(Memory Leak)**가 발생할 수 있다.

(1) 메모리 누수가 발생하는 코드

#include <iostream>

void memoryLeak() {
    int* ptr = new int(50);  // 메모리 할당
    std::cout << "값: " << *ptr << std::endl;
    // delete ptr;  // ❌ 메모리 해제하지 않음 → 누수 발생!
}

int main() {
    memoryLeak();  // 여러 번 호출하면 메모리 누적됨
    return 0;
}

🔹 문제점

  • delete ptr;을 호출하지 않으면, 프로그램이 종료될 때까지 할당된 메모리가 반환되지 않음.
  • 메모리 누수 확인 방법:
    • 프로그램 실행 후 메모리 사용량을 확인하면 지속적으로 증가하는 현상이 발생.

(2) 안전한 메모리 해제 방법

void safeMemory() {
    int* ptr = new int(50);
    std::cout << "값: " << *ptr << std::endl;
    
    delete ptr;  // ✅ 메모리 해제
    ptr = nullptr;  // ✅ 포인터 초기화 (잘못된 접근 방지)
}

🔹 올바른 메모리 해제 방식

  • delete를 사용하여 할당된 메모리를 해제.
  • ptr = nullptr;을 사용하여 해제된 포인터를 nullptr로 설정하여 잘못된 접근 방지.

📌 4. 정리

개념  설명
new 키워드 동적 메모리 할당 (new int;, new int[5];)
delete 키워드 단일 메모리 해제 (delete ptr;)
delete[] 키워드 배열 메모리 해제 (delete[] ptr;)
nullptr 사용 안전한 포인터 초기화 (int* ptr = nullptr;)
메모리 누수 방지 사용 후 반드시 delete 호출 및 nullptr 초기화