📚동적 메모리 할당

어떤 프로그램이 실행되면 운영체제는 프로그램 실행을 위해 기억공간을 할당하게 되는데, 이때 할당되는 기억공간의 위치는 데이터, 힙, 스택 영역으로 나누어 볼 수 있습니다.

구분 설명
데이터 영역 전역변수와 정적변수가 저장되는 영역
힙 영역 프로그래머의 필요에 의해 할당/소멸이 이루어지는 영역
스택 영역 지역변수와 매개변수가 저장되는 영역


동적 메모리 할당은 힙 영역을 이용하여 프로그램 실행 중에 입력되는 자료에 맞게 기억공간을 확보합니다. 하지만 동적 메모리 할당으로 생성된 저장공간은 이름이 없어 이름을 통해 접근할 수 없습니다.

따라서 이런 문제를 해결하기 위해 포인터를 사용합니다. 즉, 동적으로 할당된 저장공간을 포인터 변수가 가리키게 하여 접근할 수 있습니다.



📄new와 delete

동적 메모리 할당은 new 연산자를 이용합니다.

1
2
3
4
5
6
7
8
9
10
11
// 지정된 자료형의 데이터 1개를 저장할 수 있는 공간 할당
// 그 주소를 포인터 변수에 넣음
// 자료형은 포인터의 자료형과 일치해야 함
ptrVar = new TypeName;

// n은 양의 정수값을 내는 수식(상수가 아니어도 됨)
ptrVar = new TypeName[n];

// 메모리 공간 반환
delete ptrVar;
delete[] ptrVar;


예시

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream >

int main()
{
    int* ptr;
    ptr = new int;

    *ptr = 1;

    delete ptr;
    ptr = nullptr;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

int main()
{
    int * ptr;
    ptr = new int[3];

    *ptr = 1;
    *(ptr + 1) = 2;
    ptr[2] = 3;

    for (int i = 0; i < 3; ++i)
    {
        std::cout << ptr[i] << std::endl;
    }

    delete[] ptr;
    ptr = nullptr;
}



📄포인터 연산

할당된 배열 공간에서 각각의 저장공간을 액세스하려면 포인터 연산을 이용하여 기준 위치의 포인터 값으로부터의 상대 위치를 지정합니다. 임의의 포인터 ptr을 기준으로 첫 번째 값의 주소는 ptr, 두 번째 값의 주소는 ptr+1, 세 번째 값의 주소는 ptr+2 등으로 표현합니다.

포인터의 실제 주소는 포인터가 어떤 자료형의 포인터인가에 따라 다릅니다. ptr이 100번지 부터 시작하는 int형 데이터를 가리키는 포인터라고 했을 때 ptr+1이 가리키는 주소는 104번지, ptr+2가 가리키는 주소는 108번지가 됩니다.

연산 처리
ptr + n ptr의 n번째 뒤의 저장공간에 대한 포인터
ptr - n ptr의 n번째 앞의 저장공간에 대한 포인터
ptr++ ptr 현재 위치의 다음 값을 가리킴
ptr– ptr 현재 위치의 앞의 값을 가리킴
*(ptr + n) ptr로부터 n번째 뒤에 저장된 값
*(ptr - n) ptr로부터 n번째 앞에 저장된 값
*ptr++ 또는 *ptr– *ptr의 값을 현재 수식에 사용하고 ptr이 다음 또는 이전 값을 가리킴
*++ptr 또는 *–ptr 먼저 ptr이 다음 또는 이전 값을 가리키도록 한 후, 그 위치의 값을 수식에 사용
(ptr)++ 또는 (ptr)– ptr이 가리키는 곳의 값을 현재 수식에 사용한 후 그곳의 값을 1 증가 또는 감소
++(ptr) 또는 –(ptr) ptr이 가리키는 곳의 값을 1 증가 또는 감소시킨 후 그 값을 현재 수식에 사용



📄배열과 포인터

배열과 포인터는 매우 밀접한 관계에 있습니다. 배열의 이름은 배열의 첫 원소의 주소를 의미합니다. 이것은 포인터의 개념과 유사한데 배열변수는 포인터 변수가 아니므로 배열 이름이 가리키는 주소를 인위적으로 바꿀 수 없습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

int main()
{
    // 문자열의 끝을 알 수 있도록 널문자가 끝에 포함
    char str[12] = "hello world";
    char* ptr;

    std::cout << str << std::endl;

    // ptr이 배열 str을 가리킴(시작 주소)
    ptr = str;

    // 문자열의 끝이 아니면 반복
    while (*ptr)
    {
        // 소문자인 경우 대문자로 바꿈
        if (*ptr >= 'a' && *ptr <= 'z')
        { 
          *ptr = *ptr - 'a' + 'A';
        }

        // 다음 문자로 포인터 이동
        ptr++;
    }

    std::cout << str << std::endl;
}



Leave a comment