C언어 동적 메모리 할당[Dynamic memory allocation]

2019. 4. 11. 13:10개인공부/C언어 자료구조

동적 메모리 할당을 알기 전에 정적 메모리 할당을 알아봅시다.

 

 


int i; // int형 변수 i를 정적으로 할당
int A[10]; // 길이가 10인 배열을 정적으로 할당.

 

정적 메모리 할당은 다음과 같이 변수를 선언했을 때 이루어집니다.

 

int 변수 선언으로 메모리의 어딘가에 4바이트를 할당했고

 

배열변수 선언으로 메모리 어딘가에 40바이트의 공간이 할당되었습니다.

 

그러나 메모리 할당이 정적으로 이루어질 때 다음과 같은 문제가 발생합니다.

 

1. 메모리의 크기는 프로그램이 시작하기 전(컴파일을 하면서) 결정되므로 실행 도중에 크기를 변경할 수 없습니다.

 

2. 더 큰 입력이 들어온다면 처리하지 못합니다. 예를 들어 int A[10]; 으로 길이가 10인 배열에 20개의 값을 넣을 수가 없다는 말입니다.

 

3. 더 작은 입력이 들어온다면 메모리가 낭비된다. 2번과 반대입니다. 길이가 10인 배열을 선언하였을 경우 5개의 값만 저장한다면 나머지 5개의 공간은 낭비가 됩니다.

 

 


	int i; // int형 변수 i를 정적으로 할당
	int A[10] = { 1, 2, 3, 4, 5 }; // 길이가 10인 배열을 정적으로 할당.
	for (i = 0; i < 10; i++)
	{
		printf("%d", A[i]);
		printf("\n");
	}

 

길이가 10인 배열에 1~5까지의 값을 넣어줬습니다.   

// 참고로 배열을 선언하면서 함과 동시에 위 코드와 같이 값을 저장할 수 있지만 선언 후에 값을 저장할 때는 반복문을 사용해서 넣어야 합니다.

 

실행 결과는 다음과 같습니다.

 

 1~5의 값은 쓰고 있지만

 

나머지는 0으로 저장되어 있는 것을 확인할 수 있습니다.

 

5개의 공간이 낭비된 것이죠.

 

 

 

 

 

 

 

이런 낭비를 없애기 위해서 동적 메모리 할당을 해주는 것입니다.

 

다음과 같이 하면 동적으로 메모리 할당을 할 수 있겠지요?

 

 


	int len; // 배열의 길이
	scanf("%d", &len); // 배열의 길이를 입력 받음
	int A[len]; // 입력 받은 길이만큼 배열을 선언

 

안타깝게도 다음과 같은 코드는 컴파일 에러가 납니다.

 

배열선언에서 배열의 크기는 반드시 상수가 되어야 하기 때문입니다.

 

따라서 동적 메모리 할당 라이브러리 함수를 이용하여야 합니다

 

#include stdlib.h로 헤더파일을 추가해준 후

 

다음과 같이 쓰면 됩니다. 외우면 편합니다.

 

 


	int len; // 배열의 길이
	scanf("%d", &len); // 배열의 길이를 입력 받음
	int* p = (int*)malloc(sizeof(int)*len); //int형의 크기*len 만큼의 메모리할당

 

위 코드는 배열을 선언하는 것이 아닌 메모리를 할당하는 코드입니다.

 

sizeof(int)는 4이고, 배열의 길이를 입력 받아서 총 4*len 만큼의 메모리를 할당합니다.

 

 


	int len; // 배열의 길이
	scanf("%d", &len); // 배열의 길이를 입력 받음
	int* p = (int*)malloc(sizeof(int)*len); //int형의 크기*len 만큼의 메모리할당

	for (int i = 0; i < len; i++)
	{
		p[i] = i + 1;
	}

	for (int i = 0; i < len; i++)
	{
		printf("%d\n", p[i]);
	}

 

두 번째 for문에서 p[i]는 포인터 변수 p가 가지고 있는 주소에 있는 값을 나타냅니다. 인덱스가 마치 배열과 같죠?

 

 

14는 내가 입력한 값이고

 

첫 번째 for문을 통해 1~14까지의 값을 저장하도록 하였습니다

 

두 번째 for문에서 p[i]대신 *(p+i)를 사용하더라도 그 결과는 같습니다.

 

 

 

 

 

 

 

 

malloc을 통해서 선언된 메모리공간에 값을 저장하지 않는다면 어떻게 될까?

 


	int len; // 배열의 길이
	scanf("%d", &len); // 배열의 길이를 입력 받음
	int* p = (int*)malloc(sizeof(int)*len); //int형의 크기*len 만큼의 메모리할당

	for (int i = 0; i < len-4; i++)
	{
		p[i] = i + 1;
	}

	for (int i = 0; i < len; i++)
	{
		printf("%d\n", *(p+i));
	}

 

첫 번째 for문에서 i < len-4로 i=len-3일 때 까지만 값이 입력되도록 하였습니다.

 

 

 

쓰레기 값을 저장하고 있었다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

기본 값을 0으로 하고 싶다면 calloc이라는 함수를 사용하면 된다.

 

malloc과 선언하는데서 차이가 있으니 주의하자.

 

 


	int len; // 배열의 길이
	scanf("%d", &len); // 배열의 길이를 입력 받음
	int* p = (int*)calloc(len ,sizeof(int)); //int형의 크기의 메모리 공간을 len개 만큼 할당.

	for (int i = 0; i < len-4; i++)
	{
		p[i] = i + 1;
	}

	for (int i = 0; i < len; i++)
	{
		printf("%d\n", p[i]);
	}

 

malloc에서는 전체크기를 지정해줬다면 calloc은 유닛의 크기와 그 갯수를 지정해주면 된다.

 

 

 

나머지 공간에는 0이 저장된 것을 확인할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

calloc은 기본 unit의 크기를 알고 있으므로 나머지 공간에 0을 넣을 수가 있었다.

 

malloc은 총 크기만 알고 있으므로 어떤 값을 가지고 있을지 알 수가 없다.

 

갑자기 궁금해졌다. malloc의 크기에 4의 배수가 아닌 수를 넣는다면 어떻게 될까?

 

 


	int len; // 배열의 길이
	scanf("%d", &len); // 배열의 길이를 입력 받음
	int* p = (int*)malloc(5*len); //int형의 크기의 메모리 공간을 len개 만큼 할당.

	for (int i = 0; i < (len*5)/4; i++)
	{
		p[i] = i + 1;
	}

	for (int i = 0; i < 1000; i++)
	{
		printf("%d\n", p[i]);
	}

 

길이의 5의 배수를 넣고 실행해봤다.

 

 

14*5/4가 17.5이므로 p[17]까지 값이 저장됐다.

 

추가로 여러가지 값을 바꿔서 해봤는데

 

malloc으로 할당한 크기를 벗어나는 메모리에 접근하면

 

컴파일은 정상적으로 되지만 실행할 때 오류가 생긴다.

 

ex, 첫 번째 for문에서 /4를 없애면 실행할 때 오류 발생.

 

흠.. 아직까진 아리까리하다 ..