동적 메모리란?
프로그램이 메모리를 할당하는 방식에는 2가지 방법이 있다. 우리가 처음부터 써왔던 방법은 '정적 메모리 할당(static memory allocation)'이다. '정적 메모리 할당'은 미리 정해놓은 만큼의 메모리를 할당받는 것이다. 이 방법은 간편하지만 단점이있다. 공간의 낭비가 있을 수 있기 때문이다. 예를 들어서, 학생들 성적을 저장하기위해서 미리 100개의 정수를 저장할 수 있는 배열을 만들었다고 가정해보자.
int scores[100]
하지만, 이 배열에 70명의 학생의 성적만이 입력된다면, 나머지 30개의 공간은 낭비되게 된다. 그렇다면 필요한 공간만 그때그때 할당받으면 메모리를 더욱 효율적으로 사용할 수 있게된다. 이것이 '동적 메모리 할당(dynamic memory allocation)'이다.
크기가 100인 동적메모리를 생성한다고 가정하면,
scores = (int *)malloc(100 * sizeof(int));
scores는 100개의 정수를 저장할 수 있게된다. 형식을 좀 살펴보면 (int형 포인터)malloc(할당할 갯수 * int사이즈);
int형 포인터로 반환을 받을 것이고, 4바이트만큼의 사이즈를 가지는 공간을 100개 할당 받을 것이다! 라는 뜻이다.
동적 메모리 할당 순서 그리고 할당함수 malloc
기본적으로
동적메모리 할당 -> 동적 메모리 사용 -> 동적 메모리 반납 이 3가지 순서로 진행된다.
동적 메모리를 사용한 후에 반납하지 않는다면, 다른 프로그램이 이 메모리부분을 사용할 수 없기 때문이다.
50개의 성적을 저장할 수 있는 동적 배열을 생성해보자.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *score;
int i;
score = (int *) malloc(50 * sizeof(int));
if(score = NULL){
printf("할당오류\n");
}
for(i = 0; i < 100; i++){
score[i] = i;
}
free(score);
return 0;
}
설명) malloc함수는 반환형이 포인터 형식이다. 그러므로 score도 포인터변수여야 한다. int사이즈만큼의 공간을 50개 할당 하고 반환형은 int형 포인터로 한다. for문을 돌리면서 생성된 50개의 공간에 i를 증가시키며 대입한다. 끝. 동적메모리를 동적 배열처럼 생각하고 접근시, score[i]이런식으로 접근하는것이 일반적이다.
그리고 free(score)을 해서 동적메모리 반납을 해야한다.
동적 메모리 할당의 응용
malloc은 바이트를 저장할 수 있는 공간을 할당받는 함수이다. 100바이트를 할당받고 여기서 알파벳을 저장하고, 화면에 출력해보자.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *pc = NULL;
int i;
pc = (char *) malloc(100 *sizeof(char) );
if(pc == NULL){
printf("메모리할당 오류\n");
exit(1);
}
for(i = 0; i < 26; i++){
pc[i] = 'a' + i;
}
for(i = 0; i < 26; i++){
printf("%c ", pc[i]);
}
return 0;
}
설명) 영문자는 1글자당 1바이트씩 차지하므로 char형 포인터를 반환하는 malloc, 그리고 100공간 크기는 char크기만큼 할당 받는다. 즉, char형의 사이즈를 가지는 공간 100개를 할당받았다. 알파벳은 26개로 이루어져 있으며, a(아스키코드로 97)가 그 시작이니, 1씩 더해나가면 b, c, d, e, ...쭉 저장가능하다. 그리고 printf문으로 출력해보면 된다. 사실 100개의 공간이 필요하지도 않다. 26개의 공간만이 필요하니, (char *)malloc(26 * sizeof(char))이렇게 하여도 된다.
구조체를 저잘할 수 있는 공간도 할당 받는게 가능하다. 학생정보를 담고있는 구조체를 동적할당을 사용해서 구현해보는 예제를 살펴보자.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student {
int number;
char name[20];
};
int main(void)
{
struct student *p = NULL;
p = (struct student *) malloc(2 * sizeof(struct student));
/*첫번째 구조체에 자료저장*/
p[0].number = 2291048;
strcpy(p[0].name, "jin");
/*두번째 구조체에 자료저장*/
p[1].number = 2299948;
strcpy(p[1].name, "minu");
/*출력*/
for(int i = 0; i < 2; i++){
printf("%d %s\n", p[i].number, p[i].name);
}
return 0;
}
설명) 일단 학생구조체를 정의한다. 그리고 구조체 형식으로 포인터 p를 선언하고 일단 NULL로 초기화한다. malloc으로 메모리 할당을 하는데, struct student 포인터 형식으로 반환받을거라서 (struct student *), struct student크기의 사이즈를 2공간 받을거라서 2 * sizeof(struct student)를 한다. 그리고 그 구조체에 데이터를 넣는다. 그리고 출력.
또다른 할당함수 calloc, realloc
calloc함수는 0으로 초기화된 동적 메모리를 할당한다. malloc을 사용한다면, 할당했을때 쓰레기값이 데이터로 저장되어있을 것이다. 하지만 calloc으로 할당하면 0이 데이터로 저장된다.
realloc함수는 할당했던 메모리 블록의 크기를 변경한다. 예를 들어서, malloc으로 5개의 저장소를 할당했다고 가정해보자. realloc으로 5개의 저장소를 7개, 또는 원하는 갯수로 변경이 가능하다.
int *p;
p = (int *)malloc(5 * sizeof(int)); //크기가 int인 5개의 저장소 할당
realloc(p, 7 * sizeof(int)); //5개였던 저장소를 7개로 변경
'C프로그래밍 > 개인 공부' 카테고리의 다른 글
C언어 - 이중 포인터 (0) | 2023.01.03 |
---|---|
C언어 - 연결리스트 (0) | 2022.12.20 |
C언어 - 열거형(enumeration) (0) | 2022.12.11 |
C언어 - 구조체와 함수 (0) | 2022.12.11 |
C언어 - 구조체안에 문자배열? or 문자형을 가르키는 포인터? (0) | 2022.12.11 |