메모리 공간은 변수나 배열 선언을 하여 확보하는 것은 컴파일을 통해 할당된다.
동적 할당은 해당 코드 실행 시점에 공간이 할당된다.
malloc
: 프로그램 실행 중에 메모리 동적 할당하기free
: 할당된 공간 반환하기#include <stdio.h>
#include <stdlib.h> // malloc, free 함수 사용을 위함
int main()
{
int *pi; // 동적 할당 영역을 연결할 포인터
double *pd;
pi = (int *)malloc(sizeof(int)); // 메모리 동적 할당 & 포인터 연결
if(pi == NULL) // 동적 할당 실패하면
{
printf("# 메모리가 부족합니다.\n");// 에러 메시지 출력
exit(1); // 프로그램 종료
}
pd = (double *)malloc(sizeof(double));
}
int형 변수는 4바이트, double형 변수는 8바이트를 할당해야한다.
sizeof 연산자를 사용하여 이 크기를 계산하여 컴파일러가 해당 자료형만큼의 공간을 할당해준다.
void *malloc(unsigned int size)
(void *)을 반환하는 함수로 용도에 맞는 포인터형으로 형 변환이 되어 사용된다.
-> 포인터를 반환
void free(void *p)
void형 함수로 반환값이 없음
pi = (int *) malloc(sizeof(int));
1. 저장공간을 int형 변수의 크기만큼 할당하고 (void *)형 반환
2. 반환된 주소를 int형 변수의 주소로 형 변환
3. int형을 가리키는 포인터(pi)에 저장
1. malloc 함수의 반환값이 널 포인터
인지 확인하고 사용해야 한다.
원하는 크기의 공간을 할당하지 못하면 널 포인터(0번지를 가리킴)를 반환한다.
널 포인터를 참조하게 되면 에러가 발생한다.
이러한 에러는 평소에는 잘 실행되다가 갑자기 메모리가 부족하여 발생하게 되는 경우가 있을 수 있다.
2. 사용이 끝난 공간은 재활용할 수 있도록 반환해야 한다.
동적 할당된 저장 공간은 free 함수로 직접 반환되기 전에는 메모리에 남아 있는다. 따라서 main문 안에서는 굳이 반환할 필요가 없지만 함수에서 사용한 공간은 함수가 끝날 때반환하여 다른 함수에서 사용할 수 있도록 해야한다.
한 번에 많은 저장 공간을 동적 할당하여 배열
처럼 사용할 수 있다. 이때 할당한 저장 공간의 시작 위치만 포인터에 저장하면 포인터
를 배열처럼 쓸 수 있다.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *pi; // 동적 할당 영역을 연결할 포인터
int i, sum = 0; // 반복 제어 변수와 누적 변수
pi = (int *)malloc(5 * sizeof(int)); // 저장 공간 20바이트 할당 (5*4)
if (pi == NULL) // 메모리가 부족할 때의 예외 처리
{
printf("메모리가 부족합니다!\n");
exit(1);
}
printf("다섯 명의 나이를 입력하세요 : ");
for (i = 0; i < 5; i++) // i는 0부터 4까지 5번 반복
{
scanf("%d", &pi[i]); // 배열 요소에 입력
sum += pi[i]; // 배열 요소의 값 누적
}
printf("다섯 명의 평균 나이 : %.1lf\n", (sum / 5.0)); // 평균 나이 출력
free(pi); // 할당한 메모리 영역 반환
}
길이가 모두 다른 여러 단어를 2차원 배열에 저장하는 경우 가장 긴 단어의 길이에 맞춰 배열을 생성하게 된다. 이때 동적 할당을 활용하면 메모리를 더 효율적으로 사용할 수 있다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char temp[80]; // 임시 char 배열
char *str[3]; // 동적 할당 영역을 연결할 포인터 배열
int i; // 반복 제어 변수
for (i = 0; i < 3; i++)
{
printf("문자열을 입력하세요 : ");
gets(temp);
str[i] = (char *)malloc(strlen(temp) + 1); // 문자열 저장 공간 할당
strcpy(str[i], temp); // 동적 할당 영역에 문자열 복사
}
for (i = 0; i < 3; i++)
{
printf("%s\n", str[i]); // 문자열 출력
}
for (i = 0; i < 3; i++)
{
free(str[i]); // 동적 할당 영역 반환
}
}
char temp[80];
: 문자열을 입력하기 전에는 길이를 알 수 없으므로 임시로 입력받을 배열 할당
str[i] = (char *)malloc(strlen(temp) + 1);
: 입력받은 문자열의 길이 + 널 문자 만큼 공간 할당
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_str(char **ps) // 이중 포인터 선언
{
while (*ps != NULL) // 포인터 배열의 값이 널 포인터가 아닌 동안 반복
{
printf("%s\n", *ps); // ps는 포인터 배열의 요소를 가리킴
ps++;
}
}
int main()
{
char temp[80]; // 임시 char 배열
char *str[21] = { 0 }; // 문자열을 연결할 포인터 배열
int i = 0; // 반복 제어 변수
while (i < 20)
{
printf("문자열을 입력하세요 : ");
gets(temp);
if (strcmp(temp, "end") == 0) // end가 입력되면 반복 종료
break;
str[i] = (char *)malloc(strlen(temp) + 1); // 문자열 저장 공간 할당
strcpy(str[i], temp); // 동적 할당 영역에 문자열 복사
i++;
}
print_str(str);
for (i = 0; i < 3; i++)
{
free(str[i]); // 동적 할당 영역 반환
}
}