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를 없애면 실행할 때 오류 발생.
흠.. 아직까진 아리까리하다 ..
'개인공부 > C언어 자료구조' 카테고리의 다른 글
연결리스트로 스택 구현 (2) | 2019.04.14 |
---|---|
C언어 연결 리스트 (0) | 2019.04.14 |
[C언어 자료구조]자체 참조 구조체 (0) | 2019.04.14 |
[C언어 자료구조] 헷갈리는 포인터연산 (0) | 2019.04.14 |
이중포인터 설명 (0) | 2019.04.09 |