본문 바로가기
C/코딩도장

[코딩도장] Unit 35. 메모리 사용하기

by 단월໒꒱ 2021. 7. 18.

1. 메모리 사용하기 

 

포인터에는 malloc 함수로 원하는 만큼 메모리를 할당할 수 있다.

 

메모리의 사용 패턴은 아래와 같다.

 

 

malloc 함수로 메모리를 할당하고 사용한 다음에 free 함수로 해제한다.

 

 

2. 메모리 할당하기

 

메모리를 사용하려면 malloc 함수로 사용할 메모리 공간을 확보해야 한다.

이때, 필요한 메모리 크기는 바이트 단위로 지정한다.

메모리를 할당하고, 해제하는 함수는 stdlib.h 헤더 파일에 선언되어 있다.

 

포인터 = malloc(크기);

   void *malloc(size_t_Size);

   성공하면 메모리 주소를 반환, 실패하면 NULL을 반환

 

 

 

메모리를 할당할 때 malloc 함수를 사용하여 할당할 메모리 공간의 크기를 넣어준다.

위의 코드를 보면 sizeof 연산자를 사용해서 int의 크기인 4바이트만큼 메모리를 할당하였다.

numPtr1에는 일반 변수의 메모리 주소를 할당했고, numPtr2에는 malloc 함수로 메모리를 할당하였는데, 같은 메모리 주소라도 내부적으로는 약간의 차이가 존재한다.

스택과 힙 두가지가 있는데, 변수는 스택 부분에 생성되고 malloc 함수로 메모리를 할당하면 힙 부분의 메모리를 사용한다.

 

스택과 힙의 큰 차이점은 메모리 해제이다.

스택에 생성된 변수는 사용한 뒤 따로 처리를 하지 않아도 되지만, malloc 함수로 힙에서 할당한 메모리는 반드시 해제를 해줘야 한다.

메모리 해제할 때는 free 함수를 사용하는데, free 함수에는 malloc 함수를 사용했을 때의 포인터를 넣어주면 된다.

 

free(포인터);

    void free(void *_Block);

 

메모리 해제는 필수이다!

메모리를 할당만 하고 해제를 해주지 않으면 메모리 사용량이 계속 증가하다가 결국엔 시스템의 메모리가 부족해진다.

그렇게 되면 운영체제가 프로그램을 강제종료시키거나 메모리 할당에 실패하게 된다.

 

 

3. 메모리에 값 저장하기

 

 

 

malloc 함수로 할당한 메모리에 값을 저장하려면, 위의 코드 10번째 줄처럼 포인터를 역참조해서 값을 저장하면 된다.

printf 함수로 값을 출력할 때에도 포인터를 역참조해서 저장된 값을 가져오면 된다.

 

 

4. 메모리 내용을 한꺼번에 설정하기

 

포인터를 역참조해서 값을 할당할 때는 해당 자료형 크기만큼만 할당이 가능하다.

 

memset 함수를 사용하면 메모리의 내용을 원하는 크기만큼 특정 값으로 설정할 수 있다.

이때, 설정하는 크기는 바이트 단위이다.

memset 함수는 string.h 또는 memory.h 헤더 파일에 선언되어 있다.

 

memset(포인터, 설정할값, 설정할크기);

    void *memset(void *_Dst, int_Val, size_t_Size);

    값 설정이 끝난 포인터를 반환

 

 

위의 코드 9번째 줄에 따르면, numPtr이 가리키는 메모리에는 16진수 27이 8개 들어가게 된다.

 

memset 함수는 아래와 같이 설정할 값을 0으로 지정해서 메모리 내용을 모두 0으로 만들 때 주로 사용한다.

 

 

5. 자료형의 크기와 포인터의 크기

 

memset 함수에 설정할 크기를 지정할 때 보통 숫자 대신 sizeof를 사용하는데, 이때 주의할 점이 있다.

 

위의 코드에서 메모리를 sizeof(long long) 크기만큼 할당했으므로 설정할 크기도 sizeof(long long) 과 같이 지정해야 한다.

여기서 포인터의 크기를 지정하는 오류를 범할 수 있는데, 포인터의 크기는 메모리 주소의 크기일 뿐 실제 메모리가 차지하는 크기가 아니기 때문에 sizeof(long long *) 처럼 포인터의 크기를 지정하면 안된다.

 

sizeof(long long)은 8바이트인데 memset(numPtr, 0, sizeof(long long *)); 은 32비트에서 4바이트, 64비트에서 8바이트만큼 0으로 설정하므로 할당받은 메모리보다 작은 공간을 설정하게 되거나 크기가 일치할 뿐 잘못된 방법으로 메모리를 설정하게 된다.

 

따라서 memset 함수에서 sizeof를 사용할 때, 포인터의 크기는 실제 메모리가 차지하는 크기가 아니라는 점을 주의해야하 한다.

 

 

6. 널 포인터 사용하기

 

위와 같이 NULL이 들어있는 포인터를 '널 포인터'라고 하며 메모리가 할당되지 않은 포인터이다.

아무것도 가리키지 않는 상태이기 때문에 역참조는 할 수 없다.

 

실무에서는 포인터가 NULL인지 확인한 뒤 NULL이면 메모리를 할당하는 방식을 주로 사용한다고 한다.

 

 

# 퀴즈

 

1) 다음 중 메모리를 할당하는 방법으로 올바른 것을 고르세요.

    답 ->  d. int *numPtr = malloc(100);

 

2) 다음 중 C 언어에서 메모리를 사용하는 패턴으로 올바른 것을 고르세요.

    답 -> c. malloc → 사용 → free

 

3)  다음 중 int *numPtr = malloc(sizeof(int));에서 numPtr에 할당한 메모리에 10을 저장하는 방법으로 올바른 것을 고르세요.

    답 -> b. *numPtr = 10;

 

4) memset 함수가 메모리를 초기화하는 단위는 얼마인가요?

    답 -> a. 1바이트

 

5) 다음 중 memset 함수가 선언된 헤더 파일을 고르세요.

    답 -> d. string.h

 

6) 아무것도 가리키지 않는 포인터를 무엇이라고 부르나요?

    답 -> 널 포인터

 

 

# 연습문제

 

다음 소스 코드를 완성하여 2147483647 9223372036854775807이 출력되게 만드세요.

 

[코드 및 결과]

 

 

[설명]

일단 값을 저장하려면 메모리를 할당해줘야하기 때문에 malloc 함수를 이용해서 메모리를 할당하도록 했다.

numPtr1는 int형 포인터이므로 sizeof(int) 크기만큼, numPtr2는 long long형 포인터이므로 sizeof(long long) 크기만큼 할당하도록 각각 malloc 함수 안에 넣어주었다.

 

// sizeof(int)나 sizeof(long long)은 각각 4바이트, 8바이트이므로 굳이 sizeof 함수를 사용하지 않고 malloc 함수 안에 각각 4와 8을 넣어주어도 된다.

 

 

# 심사문제

 

표준 입력으로 두 정수가 입력됩니다(입력 값의 범위는 0~1073741824). 다음 소스 코드를 완성하여 입력된 두 정수의 합이 출력되게 만드세요. 정답에는 밑줄 친 부분에 들어갈 코드만 작성해야 합니다.

 

[코드 및 결과]

 

 

[설명]

이미 코드 내용 상 scanf로 정수로 선언된 num1과 num2를 받을 수 있는 상태였고, *numPtr1과 *numPtr2를 역참조하여 각각 num1과 num2를 저장한 상태였다.

또한 printf 함수로 입력받은 두 정수를 더한 값을 출력할 수 있었기 때문에 남은 건 각각의 포인터에 값을 저장할 메모리를 할당하는 것 뿐이었다.

위에서 언급했듯 num1과 num2는 정수로 선언된 상태였기에 포인터도 똑같이 int형으로 선언해주었다.

메모리 할당은 malloc 함수를 통해 하였고 할당할 메모리 크기는 둘 다 int형 포인터이기 때문에 모두 sizeof(int)를 넣어서 크기를 설정했다.

 

 

 

 

댓글