동적할당

Jaemyeong Lee·2024년 8월 7일
0

FastCampusC++

목록 보기
33/78

C++ 동적 할당 (Dynamic Memory Allocation)

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;
}

1. 지역 변수와 정적 변수

첫 번째 블록에서는 지역 변수와 정적 변수를 살펴봅니다.

{
    int num0 = 0; // 지역 변수, 해당 블록 내에서만 접근 가능
    static int num1 = 0; // 정적 변수, 프로그램 시작 시 할당되고 종료 시 해제
}
  • num0은 지역 변수로 해당 블록 내에서만 유효합니다.
  • num1은 정적 변수로 프로그램 시작 시 한 번 할당되고 프로그램 종료 시 해제됩니다.

2. 자동 지역 변수와 정적 지역 변수

두 번째 블록에서는 자동 지역 변수와 정적 지역 변수를 비교합니다.

{
    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이 출력됩니다.

3. 동적 할당 및 해제

세 번째 블록에서는 동적 할당과 해제의 기본 개념을 다룹니다.

{
    int* pNum = new int; // 동적 할당된 메모리를 가리키는 포인터
    delete pNum; // 할당된 메모리 해제
}
  • new 키워드를 사용하여 메모리를 동적 할당합니다.
  • delete 키워드를 사용하여 할당된 메모리를 해제합니다.

4. 메모리 누수 예제

네 번째 블록에서는 메모리 누수의 예를 보여줍니다.

{
    // while (true)
    // {
    //     int* num = new int; // 메모리 누수 발생, 해제되지 않음
    // }
}
  • 주석 처리된 코드는 무한 루프에서 동적 할당을 수행하므로 메모리 누수가 발생합니다.
  • delete를 사용하여 할당된 메모리를 해제하지 않으면 메모리 누수가 발생합니다.

5. 동적 할당된 메모리의 공유와 해제

다섯 번째 블록에서는 동적 할당된 메모리를 여러 포인터가 가리킬 때의 위험성을 다룹니다.

{
    int* pNum0 = new int(123); // 동적 할당된 메모리 초기화
    int* pNum1 = pNum0; // 같은 메모리를 가리키는 포인터

    cout << *pNum0 << endl; // 123 출력
    delete pNum0; // 메모리 해제

    // 이미 해제된 메모리에 접근 (위험)
    // cout << *pNum0 << endl;
    // cout << *pNum1 << endl;

    // 이미 해제된 메모리를 다시 해제 (위험)
    // delete pNum0;
}
  • 메모리를 해제한 후 해당 포인터를 다시 사용하거나 해제하면 정의되지 않은 동작이 발생합니다.

6. 지역 변수의 주소를 외부에서 사용하는 경우

여섯 번째 블록에서는 지역 변수의 주소를 외부에서 사용하는 경우의 위험성을 다룹니다.

{
    int* pNum;
    {
        int n = 10;
        pNum = &n; // n의 주소를 pNum에 저장
    }
    // 이미 해제된 메모리에 접근 (위험)
    // cout << *pNum << endl;
}
  • 지역 변수가 소멸된 후 해당 변수의 주소를 사용하면 정의되지 않은 동작이 발생

합니다.

7. 동적 할당을 통한 가변 배열 사용

일곱 번째 블록에서는 동적 할당을 통해 가변 배열을 사용하는 방법을 다룹니다.

{
    int s;
    cin >> s; // 배열 크기 입력
    int* arr = new int[s]; // 동적으로 배열 할당
    arr[0] = 1; // 첫 번째 요소에 값 할당
    cout << arr[0] << endl; // 첫 번째 요소 출력

    delete[] arr; // 배열 메모리 해제
}
  • 동적 할당을 통해 가변 배열을 생성하고, 사용 후 delete[]를 사용하여 메모리를 해제합니다.

8. 구조체와 동적 할당

여덟 번째 블록에서는 구조체와 동적 할당을 다룹니다.

{
    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]는 초기화되지 않았으므로 해제할 필요 없음
}
  • 동적 할당을 통해 구조체를 생성하고, 포인터를 사용하여 구조체 멤버에 접근합니다.
  • 동적 할당된 메모리는 사용 후 반드시 해제해야 합니다.
profile
李家네_공부방

0개의 댓글