OneDev

[C] 23. 메모리 동적 할당(Dynamic Memory Allocation) - malloc, free 본문

Language/C

[C] 23. 메모리 동적 할당(Dynamic Memory Allocation) - malloc, free

one_dev 2023. 7. 31. 18:26

동적 할당(Dynamic Memory Allocation)

  • "동적 할당" 이란 → 프로그램이 실행단계에서(프로그램 실행중에) 사용할 메모리 공간을 직접 할당하는 것
  • 컴파일 단계에서 메모리를 할당하는 정적(static) 할당과 비교된다
  • 상황에 따라 원하는 만큼 메모리를 할당할 수 있고, 이미 할당된 메모리라 해도 크기를 조절할 수 있다
  • malloc 함수를 이용해 메모리를 할당하고, free 함수를 이용해 할당을 해제해줘야 한다

◎ malloc, free 함수

  • <stdlib.h> 에 정의되어 있다 ( <stdlib.h> 를 include 해줘야 한다)
  • malloc 함수의 리턴형 : (void *) 형
  • malloc 함수를 이용해 메모리를 할당받은 메모리는 이후에 free 함수를 이용해 해제해주어야 한다 ( 해제하지 않을 시 메모리 누수 memory leak 이 발생)
  • 힙(Heap) 영역에 메모리를 할당
  • 상당히 느린 함수들 중 하나이다

 

◎ malloc 을 이용해 가변길이 배열 만들기

  • 배열의 크기를 정확히 모르거나 사용자의 입력에 따라 배열의 크기를 정의하고 싶을 때 사용
  • malloc 의 리턴 타입은 (void *) 형이기 때문에 원하는 형으로 형변환 해주면 된다
  • 메모리를 할당할 때 보통 [ sizeof(데이터타입) * 배열의 크기 ] 와 같이 할당한다
/* 예시 - 학생들의 총점 구하기 */
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char* argv) {
	int student; // 입력받고자 하는 학생 수
	int i, input;
	int *score; // 학생들의 점수 
    
	int sum = 0; // 총점
    
	printf("학생들의 수는? : "); // 배열의 크기 -> 사용자 입력
	scanf("%d", &student);

	score = (int *)malloc(student * sizeof(int)); // malloc 을 이용한 동적할당
    
	for (i = 0; i < student; i++) {
		printf("학생 %d 의 점수 : ", i);
		scanf("%d", &input);
		score[i] = input;
        sum += score[i];
	}
	
    printf("총점 : %d \n", sum);
    
    free(score); //할당받은 메모리 해제
    
	return 0;
}

 

  2차원 배열의 동적 할당

2차원 배열 또한 동적으로 할당할 수 있는데, 크게 두 가지 방법을 생각해 볼 수 있다

  1.  포인터 배열을 사용해 2차원 배열 처럼 동작하는 배열을 만드는 방법
  2.  실제로 2차원 배열 크기의 메모리를 할당한 뒤 2차원 배열 포인터로 참조하는 방법

(1) 포인터 배열을 이용해서 2차원 배열 할당하기

  • 포인터 배열 - 배열의 각 원소들이 모두 포인터인 배열
  • 먼저 포인터 배열을 동적으로 할당한 뒤, 각각의 원소들이 가리키는 일차원 배열을 다시 동적으로 할당
  • 이 방법으로는 진짜 2차원 배열처럼 메모리에 연속적으로 존재하는 배열을 만들 수는 없다
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char **argv) {
	int x, y;
	int** arr; // 이차원 배열 arr[x][y] 만들기

	scanf("%d %d", &x, &y);

	// 1. (int *) 형 원소를 x 개  가지는 1차원 배열 생성
	arr = (int**)malloc(sizeof(int) * x);

	// 2. x 개의 원소가 가리키는 1차원 배열들 각각 할당
	for (int i = 0; i < x; i++) {
		arr[i] = (int*)malloc(sizeof(int) * y);
	}

	// 해제는 역순
	for (int i = 0; i < x; i++) {
		free(arr[i]);
	}
	free(arr);

	return 0;

}

 

(2) 실제 2차원 배열 할당하기

  • 이 방법은 C99 이상의 버전 (VLA 를 지원하는 버전) 에서만 사용 가능하다.
  • 메모리에 연속적으로 존재하는 진짜 2차원 배열을 만들기 위해서는 반드시 malloc 을 통해 해당 공간을 할당해야 한다
  • 2차원 배열 포인터의 경우 포인터 연산을 수행하기 위해 반드시 포인터 타입 안에 행 길이가 들어가야 한다
  • 이를 고려하여 아래와 같이 2차원 배열 포인터를 정의할 수 있다
// arr[x][y];
int (*arr)[y] = (int (*)[y])malloc(x * y * sizeof(int));
  • (주의) 정의 할 때 반드시 행의 길이(y) 에 값이 들어간 후에 정의해야 한다
  • 이렇게 정의했을 경우 모든 데이터가 메모리에 연속적으로 있기 때문에 free 역시 arr에 대해 단 한 번만 수행하면 된다.

(예시)

int main() {
  int width, height;
  printf("배열 행 크기 : ");
  scanf("%d", &width);
  printf("배열 열 크기 : ");
  scanf("%d", &height);

    // Visual Studio 에서는 동작하지 않을 수도 있다
  int(*arr)[width] = (int(*)[width])malloc(height * width * sizeof(int));
  
  
  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
      int data;
      scanf("%d", &data);
      arr[i][j] = data;
    }
  }
  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }

  free(arr);
}

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

[C] 24. 매크로 함수 & 인라인(inline) 함수  (0) 2023.08.10
[C] memcpy  (0) 2023.08.01
[C] 22. 전처리기 (preprocessor) (#include, #define, #error, #ifdef)  (0) 2023.07.26
[C] 21. 구조체(struct)  (0) 2023.07.21
[C] 20.문자열(String)  (0) 2023.07.18
Comments