관리 메뉴

Value Creator의 IT(프로그래밍 / 전자제품)

#7 [C++] 동적 메모리 할당 및 반환 본문

1. 프로그래밍/5) C++

#7 [C++] 동적 메모리 할당 및 반환

valuecreatort 2019. 8. 2. 18:45
반응형

#동적 메모리 할당

앞서서 프로그래밍 예제를 풀때 간혹가다 new를 쓰는 것을 보았을 것이다. 그것은 배열의 동적할당을 할 때 사용하는 것이다. 이번에는 그 동적 할당이라는 것을 자세히 알아보자. 동적 메모리 할당(이하 동적할당)은 개발자가 프로그램 작성단계에서 필요한 메모리를 확보할때 그때마다 필요한 만큼만 쓰게 하기 위해 만들어진 개념이다.

 

기존의 방식은 객체 배열의 메모리를 정적으로, 그러니까 프로그램 내부에서 정해진 수치안에서 작성하였다. 하지만 때로는 객체의 메모리를 사용할때 그 이하가 필요하거나 그 이상이 필요할때가 있다. 그때 필요한 만큼 할당받고 필요 없을 때 반환하는 동적할당이라는 개념이 필요하다.


물론 기존 C언어에서도 동적할당 및 반환이 가능했다. malloc()/free()가 그 예이다. 하지만 C++에서는 new/delete 연산자를 사용한다.

 

new연산자는 힙(heap)이라는 시스템 공간으로 부터 메모리를 할당받으며, delete는 그 할당받은 메모리를 힙으로 반환한다.

 

힙(heap)이란 프로그램 내부가 아닌 외부의 공간을 의미한다. 보통은 내부 프로그램안에 스택 메모리를 기본으로 20~60KB 정도의 작은 메모리가 제공되는데 보통함수는 그정도로도 충분하다만 데이터를 많이 다루게되면 그 메모리는 턱없이 부족해진다. 그래서 외부에서 메모리를 요청하는게 그것을 C++에서는 new라는 연산자로 OS에 요청을 한다. 그렇다면 OS는 힙에 메모리를 할당하며 그 주소를 포인터로 리턴한다. (그래서 선언할때 포인터변수를 쓰는 것이다.)

 

그리고 프로그램은 그 포인터 주소에 할당된 메모리를 마음것 사용하는 것이고, 다 사용한다면 delete라는 명령어로 사용이 끝난 메모리를 반환한다고 선언한다.

 

#new와 delete 연산자

new와 delete 연산자는 C++의 기본 연산자 이다. 사용 기본 형식은 아래와 같다.

 

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

delete 포인터변수; 

 

이렇게 작성하면 new 연산자는 데이터 타입의 크기만큼 힙으로 부터 메모리를 할당받고 주소를 리턴한다. 그 결과 포인터변수는 할당받은 메모리의 주소를 가진다. 그리고 그 메모리는 delete 연산자로 하여금 다시 힙으로 반환한다. 데이터 타입은 int, char, string 같은 기본 타입뿐 아니라 구조체(struct)나 클래스도 포함한다.


#동적할당 메모리 초기화

new를 이용하여 메모리를 할당받을때 new 다음에 오는 데이터타입뒤에 "(초기값)"을 작성하는 것으로 초기값을 지정하여 초기화 할 수 있다. 아래는 int 로 선언된 함수의 초기값 예다.

 

int *p = new int(2);//2로 초기화된 int공간 할당


#delete 사용시 주의할 점

delete로 메모리를 반환할때 주의점은 크게 두가지다.

 

첫째는 동적으로 할당받지 않은 포인터를 반환할때이다.

 

int i;

int *p = &i;

delete p; 

 

이 코드에서 *p는 i의 주소를 할당 받았지 동적으로 할당을 받은 포인터는 아니다. 그렇기에 delete연산자는 동적으로 할당받지 않은 메모리를 반환하여 실행 오류, 즉 컴파일 에러가 발생한다.

 


둘째는 이미 반환을 했는데 또 반환하는, 즉 동일한 포인터의 delete의 코드를 중복해서 작성했을때이다. 이미 반환되었으면 다시 반환할것이 없기 떄문에 컴파일 에러가 발생한다.

 

 

#C++ 배열의 동적 할당 및 반환

앞서 new 연산자로 배열을 할당받고 delete로 반환하였듯이 배열또한 동일한 방법으로 할당/반환된다.

 


배열의 동적 할당/반환에 대한 기본 형식은 아래와 같다.

 

int *p = new int[100];

delete [] p; 

포인터 p는 크기가 100인 정수형 배열을 동적 할당 받았다는 뜻이다. 그리고 그 아래는 배열에 대한 반환 방법이다.

할당받은 배열은 앞으로 기존 배열과 동일한 방법으로 사용된다. 그 예는 아래와 같다.

 

p[i] = i; 


주의할 점은 배열을 동적 할당 받을떄는 초기값을 지정할 수 없다는 점이다.

 

[예제]

예제는 사용자로부터 정수의 갯수를 입력받아 배열을 동적으로 할당받고, 하나씩 정수를 입력받은 뒤 합을 구하는 프로그램이다.

#include<iostream>

using namespace std;

 

int main()

{

    cout << "입력하고 싶은 정수의 갯수를 입력해주세요 : ";

    int n = 0;

    cin >> n;

    if (n <= 0)return 0;

    int *p = new int[n];

    if (!p)//메모리를 할당받았는지 유무 검사.

    {

        cout << "메모리를 할당할 수 없습니다." << endl;

        return 0;

    }

    for (int i = 0; i < n; i++)

    {

        cout << i + 1 << "번째 정수 : ";

        cin >> p[i];

    }

    int sum = 0;

    for (int i = 0; i < n; i++)

    {

        sum += p[i];

    }

    cout << "모든 수의 합은 : " << sum << endl;

    delete [] p;

}

 

 

 

 

 

 

#C++ 객체와 객체 배열의 동적 생성 및 반환

 

앞에서는 기본 형식과 배열의 동적 할당에 대해 배웠다 그렇다면 이번에는 객체와 객체배열의 동적할당에 대해서 알아보자.

 


#객체의 동적 생성 및 반환

아래는 기본 예제로서 기존과 별 다를게 없다.(객체에 대한 예는 기존의 Circle 클래스다.)

 

클래스이름 *포인터변수 = new 클래스이름;//기본생성자 호출

클래스이름 *포인터변수 = new 클래스이름(생성자매개변수);//매개변수있는 생성자 호출

---------------------------------------------------

Circle *p = new Circle;//Circle클래스의 기본생성자 호출

Circle *p = new Circle(30);//반지름이 30인 Circle생성자 호출(매게변수있는생성자호출) 

 

그리고 delete를 이용한 객체반환은 아래와 같다.

 

delete 포인터 변수;

--------------------

delete p;

그리고 이때 소멸자는 delete로 인해 객체를 반환하기 전에 실행된다.

delete 주의 사항은 기존의 주의 사항과 같다.

 


그렇다면 기존의 Circle클래스를 또 재활용하여 객체의 동적 생성 및 반환을 해보자.

#include"Circle.h"

 

int main()

{

    Circle *p = new Circle;

    Circle *p2 = new Circle(20);

 

    cout << p->getArea() << "   " << p2->getArea() << endl;

    delete p;

    delete p2;

}

 

 


#객체 배열의 동적 생성 및 반환

객체 배열의 동적 생성의 기본 예는 아래와 같다.

클래스이름 *포인터변수 = new 클래스이름[배열크기];

---------------------------------------------

Circle *p = new Circle[3];//크리가3인 Circle 객체배열을 동적 할당 

다만 배열을 동적으로 생성할때 매개변수가 있는 생성자를 호출할 수 있는 방법은 없으니 심심하면 해보자.

 

 

 

동적으로 생성된 배열도 기존 배열과 동일하게 사용한다. delete 연산자도 다른 배열과 동일하다.

delete [] 포인터변수;

-------------------------

delete [] *p; 

 

그렇다면 이번에도 객체배열의 동적할당과 반환의 대한 예제를 작성해보자.

 

 

#include"Circle.h"

 

int main()

{

    Circle *p = new Circle[3];

    p[0].setRadius(3);

    p[1].setRadius(5);

    p[2].setRadius(7);

 

    for (int i = 0; i < 3; i++)

    {

        cout << i + 1 << "번째 Circle 넓이 : " << p[i].getArea() << endl;

    }

    delete[] p;

}

 

반응형
Comments