Language/C

[C] 메모리 동적 할당

nowkoes 2024. 1. 29. 14:38

동적 할당

개요

출처: 위키피디아

 

 이번 시간에는 C 언어의 핵심 요소 중 하나인 메모리 관리와 동적 할당에 대해 집중적으로 살펴보겠다. 동적 할당(Dynamic Allocation)프로그램 실행(런타임) 도중 필요한 메모리 공간을 할당하는 과정으로, 메모리 자원이 제한적인 환경에서 특히 중요하다. C 언어는 malloc, calloc, realloc, free와 같은 함수를 통해 개발자가 메모리를 효율적으로 관리할 수 있도록 지원한다. 이러한 동적 할당 메커니즘을 통해, 개발자는 필요한 메모리만을 할당하고, 사용이 끝난 메모리를 해제함으로써 시스템의 메모리 사용을 최적화할 수 있다. 


본문

사용 이유

 동적 메모리 할당과 해제는 C언어에서 메모리 사용의 효율성을 높이는 중요한 역할을 한다. 정적 할당 방식에서는 프로그램이 시작될 때 모든 필요한 메모리를 할당하며, 프로그램이 종료될 때까지 이 메모리를 유지한다. 이는 필요 이상의 메모리 자원을 소비하게 되며, 특히 메모리 자원이 제한적인 환경에서는 자원의 낭비를 야기한다. 반면, 동적 할당은 필요한 메모리를 프로그램 실행 중 필요한 시점에 할당하고, 더 이상 필요하지 않을 때 해제함으로써 메모리를 보다 유연하고 효율적으로 관리할 수 있게 한다. 이러한 방식은 메모리 사용을 최적화하고, 제한된 환경에서의 메모리 관리에 있어 효과적인 방법이 된다.

 

#include <stdio.h>
#include <stdlib.h>

#define true 1

int main() 
{
    int staticArray[1000]; 
    int* dynamicArray = (int*)malloc(1000 * sizeof(int)); 
    if (dynamicArray == NULL) 
        return 1;
    
    staticArray[0] = 1; 
    dynamicArray[0] = 1;

    printf("staticArray[0] = %d\n", staticArray[0]);
    printf("dynamicArray[0] = %d\n", dynamicArray[0]);
    free(dynamicArray);

    while (true)
    {

    }

    return 0;
}

 

 다음 코드에서는 staticArray는 정적으로 할당된 배열로, 컴파일 시간에 크기가 결정되며 프로그램 실행 동안 크기가 변하지 않는다. 이 배열은 프로그램 시작 시 1000개의 정수를 저장할 수 있는 공간을 메모리에 할당받고, 프로그램이 종료될 때까지 그 공간이 유지된다.

 반면, dynamicArray는 동적으로 할당된 배열이다(할당하고 해제하는 방법은 후술하도록 하겠다). 이 배열은 프로그램 실행 중 필요에 따라 메모리를 할당받으며, 사용이 끝난 후에는 free 함수를 통해 메모리를 해제할 수 있다. 위 코드의 예에서, dynamicArray에 할당된 메모리는 free 함수를 호출함으로써 해제되며, 이후로는 해당 메모리 공간을 다른 용도로 사용할 수 있게 된다.

 이 코드에 있는 while(true) 루프는 무한히 계속 실행된다. 이 루프가 실행되는 동안 staticArray는 계속해서 메모리를 차지하고 있지만, dynamicArray에 대한 메모리는 이미 해제되어 메모리를 사용하지 않고 있다. staticArray에 할당된 메모리는 프로그램이 종료될 때까지, 즉 main 함수가 리턴될 때까지 유지되며, 이는 코드에서 4000바이트(정수 하나당 4바이트로 가정)에 해당한다.


사용법 (1) - calloc

calloc의 정의

 

 C 언어에서 동적 할당은 calloc과 malloc 두 가지 함수를 사용할 수 있다. 먼저 calloc지정된 수의 요소에 대해 메모리를 할당하고, 모든 비트를 0으로 초기화하는 동적 할당 방법이다. calloc을 사용하려면 다음과 같은 절차를 따르면 된다.

 

1. 포인터 선언: 먼저, 포인터를 선언하여 메모리를 할당할 때 사용할 포인터를 생성한다. 동적 할당된 메모리는 프로그램의 힙 영역에 위치하며, 이 영역의 메모리는 직접적인 이름이나 변수로 접근할 수 없다. 따라서 포인터를 이용하여 메모리의 주소를 저장하고, 이 주소를 통해 할당된 메모리에 접근하고 조작해야 한다.

int *ptr

 

 

2. 메모리 할당 및 초기화: calloc 함수는 메모리 할당과 동시에 초기화를 수행한다. 이 함수는 할당할 원소의 수와 각 원소의 크기를 인자로 받는다. calloc의 반환형은 void*이며, 이는 어떤 타입의 객체도 가리킬 수 있는 일반 포인터다. 이러한 설계는 calloc을 특정 타입에 구속되지 않고, 다양한 데이터 타입의 메모리 할당에 유연하게 사용할 수 있도록 한다. 따라서 앞선 포인터의 자료형을 int 형으로 선언하였기 때문에, 해당 자료형의 데이터를 다루기 위해 (int*) 형으로 형변환을 해주어야 한다.

ptr = (int*)calloc(1000, sizeof(int));

 

3. 포인터 사용: 할당된 메모리를 사용한다. calloc에 의해 할당된 메모리는 모두 0으로 초기화되었기 때문에, 초기화된 값을 확인하거나 새로운 값을 할당할 수 있다.

if(ptr != NULL)
{
    ptr[0] = 10;
    printf("First element: %d\n", ptr[0]);
}

 

4. 메모리 해제: 동적으로 할당된 메모리는 더 이상 필요하지 않을 때 free 함수를 통해 해제해야 한다. 이는 메모리 누수(leak, 프로그램이 동적으로 할당한 메모리를 해제하지 않아 발생하는 문제)를 방지하는 데 중요한 역할을 한다.

free(ptr);

사용법 (2) - malloc

 

 malloc지정된 크기의 메모리를 할당하지만, calloc과 달리 할당된 메모리를 초기화하지 않는다. 이로 인해 메모리에는 임의의 데이터, 즉 쓰레기 값이 남아 있을 수 있지만 calloc에 비해 빠르다는 특징이 있다. malloc 또한 calloc과 같은 과정을 거쳐 사용할 수 있다.

 

1. 포인터 선언: 먼저, 포인터를 선언하여 메모리를 할당할 때 사용할 포인터를 생성한다. 

int *ptr

 

 

2. 메모리 할당 및 초기화: malloc 함수는 할당할 메모리의 크기를 바이트 단위로 인자로 받는다.

ptr = (int*)malloc(1000 * sizeof(int));

 

3. 포인터 사용: 할당된 메모리를 사용한다. malloc에 의해 할당된 메모리는 초기화되지 않았으므로, 사용 전에 적절한 초기화가 필요할 수 있다.

if(ptr != NULL) 
{
    memset(ptr, 0, 1000 * sizeof(int)); // 메모리 초기화
    ptr[0] = 10; 
    printf("First element: %d\n", ptr[0]);
}

 

4. 메모리 해제: 동적으로 할당된 메모리는 더 이상 필요하지 않을 때 free 함수를 통해 해제해야 한다. 이는 메모리 누수를 방지하는 데 중요한 역할을 한다.

free(ptr);

사용법 (3) - realloc

 

 만약 이미 할당된 메모리 블록의 크기를 변경하고 싶으면 어떻게 해야 할까? c언어에서는 메모리의 크기를 확장하거나 축소할 때 realloc 함수를 사용한다. 즉, 새로운 메모리 영역을 할당하고 기존 데이터를 복사한 후, 기존 메모리를 해제한다. 이 과정에서 메모리 크기를 줄일 때, 초과하는 부분의 데이터는 손실될 수 있고, 메모리 크기를 확장할 때, 추가된 메모리 영역은 초기화되지 않는다.

 

#include <stdio.h>
#include <stdlib.h>

int main() 
{
    int* ptr = malloc(100 * sizeof(int)); 
    if (ptr == NULL) 
    {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    ptr = realloc(ptr, 200 * sizeof(int));
    if (ptr == NULL) 
    {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    free(ptr);
}

요약

동적 할당
1. 정의: 프로그램 실행(런타임) 도중 필요한 메모리 공간을 할당하는 과정
2. 과정
 a. 포인터 초기화
 b. 메모리 할당
 c. 포인터 사용
 d. 메모리 해제
3. 함수: malloc, calloc, realloc, free
반응형

'Language > C' 카테고리의 다른 글

[C] 구조체(Structure)  (2) 2024.01.31
[C] 포인터(Pointer)  (2) 2024.01.22