1 분 소요

❄️ David Malan 교수의 모두를 위한 컴퓨터 과학(CS50 2019)을 바탕으로 정리한 내용입니다.


지난 시간 마지막에 아래 코드를 작성했는데요, 사실 아래 코드에는 버그가 있습니다.

#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
  char *s = get_string("s: "); // emma 입력
  char *t = malloc(strlen(s) + 1);

  strcpy(t, s)
  t[0] = toupper(t[0]);

  printf("%s\n", s); // emma
  printf("%s\n", t); // Emma
}

malloc 함수를 이용하여 메모리를 할당한 후에는 free라는 함수를 이용하여 메모리를 해제해줘야 합니다.
그렇지 않은 경우 메모리에 저장한 값은 쓰레기 값으로 남게 되어 메모리 용량의 낭비가 발생하게 되기 때문이죠.
이러한 현상을 ‘메모리 누수’라고 일컫습니다.

해결 방법은 간단합니다. 코드 맨 마지막에 아래를 추가하면 됩니다.

free(t) // ✅ t는 `malloc`이 할당해 준 메모리 주소

위 코드를 통해 할당된 메모리를 반대로 해제할 수 있습니다.

valgrind 라는 프로그램을 사용하면 우리가 작성한 코드에서 메모리 누수(leak) 혹은 버퍼 오버플로우와 같이 메모리와 관련된 문제가 있는지를 쉽게 확인할 수 있습니다.

$ help50 valgrind ./filename

와 같은 명령어를 사용하면 filename 파일에 대한 valgrind의 검사 내용을 쉽게 확인할 수 있습니다.
아래 예제를 확인해 봅시다.

#include <stdlib.h>

void f(void)
{
  int *x = malloc(10 * sizeof(int));
  x[10] = 0; // ✅ 버퍼 오버플로우
}

int main(void)
{
  f();
  return 0;
}

f 함수를 살펴보면 먼저 포인터 x에는 int형의 사이즈(4바이트)에 10배에 해당하는 크기의 메모리, 즉 40바이트를 할당합니다.
그리고 x의 10번째 값으로 0을 할당합니다.
그리고 main 함수에서 f를 실행하게 되는데, 이 코드를 valgrind 로 검사해보면 1. 버퍼 오버플로우와 2. 메모리 누수 두 가지 에러를 확인할 수 있습니다.

먼저 버퍼 오버플로우는 x[10] = 0; 코드로 인해 발생합니다.
우리는 10개의 int형의 배열을 만들었는데 배열의 인덱스가 0부터 시작한다는 점을 감안하면 인덱스 10은 11번째 인덱스에 접근하겠다는 의미이고, 이는 정의되지 않은 것이기 때문에 버퍼 오버플로우가 발생하는 것이죠.
따라서 이 오류는 0에서 9 사이의 인덱스를 사용하면 해결할 수 있습니다.

또한 메모리 누수는 x라는 포인터를 통해 할당한 메모리를 해제하기 위해 free(x) 라는 코드를 추가해줌으로써 해결할 수 있습니다.

제한된 메모리를 가지고 프로그래밍을 할 때 메모리를 해제하지 않으면 어떤 문제가 발생할 수 있을까요?
메모리 누수로 인해 메모리 공간이 부족해지면서 프로그램의 성능이 저하되고 오류가 발생할 수 있습니다.



💛 개인 공부 기록용 블로그입니다. 👻

맨 위로 이동하기

태그:

카테고리:

업데이트: