동적 메모리 할당이란
일반적인 배열은 크기가 고정되어 있다. 이로 인해 많은 문제가 발생한다.
흔히 프로그램을 작성할 당시에는 얼마나 많은 입력이 있을지를 알 수 없기 때문이다.
만약 처음에 결정된 크기보다 더 큰 입력이 들어온다면 처리하지 못 할 것이고, 더 작은 입력이 들어온다면 남은 메모리 공간은 낭비될 것이다.
따라서 이런 문제들을 해결하기 위하여 C언어에서는 필요한 만큼의 메모리를 운영체제로부터 할당받아서 사용하고, 사용이 끝나면 시스템에 메모리를 반납하는 기능이 존재한다. 이것을 동적 메모리 할당(dynamic memory allocation)이라고 한다.
동적 메모리가 할당되는 공간을 히프(heap)라고 한다.
히프는 운영체제가 사용되지 않는 메모리 공간을 모아놓은 곳이다. 필요한 만큼만 할당을 받고 또 필요한 때에 사용하고 반납하기 때문에 메모리를 매우 효율적으로 사용할 수 있다. 전형적인 동적 메모리 할당 코드는 다음과 같다.
int *p;
p = (int *)malloc(sizeof(int)); //동적메모리 할당
*p = 1000; //동적메모리 사용
free(p); //동적메모리 반납
- malloc() 함수는 size 바이트 만큼의 메모리 블록을 할당한다. sizeof 키워드는 변수나 타입의 크기를 숫자로 반환한다. 크기의 단위는 바이트가 된다. sizeof(int)는 int형의 크기를 반환한다. malloc()은 동적 메모리 블럭의 시작 주소를 반환한다. 반환되는 주소의 타입은 void *이므로 이를 적절한 포인터로 형변환시켜야 한다. 메모리 확보가 불가능하면 NULL을 함수의 반환값으로 반환한다.
- 동적 메모리는 포인터로만 사용할 수 있다. *p는 p가 가리키는 장소이다. *p = 1000; 문장을 실행하면 p가 가리키는 장소에 1000이 저장된다.
- free() 함수는 할당된 메모리 블록을 운영체제에게 반환한다. 여기서 주의할 점은, malloc()함수가 반환했던 포인터 값을 잊어버리면 안된다는 것이다. 포인터값을 잊어버리면 동적메모리를 반환할 수 없다. malloc()은 시스템의 메모리가 부족해서 요구된 메모리를 할당할 수 없으면 NULL을 반환한다. 따라서 malloc()의 반환값은 항상 NULL인지 검사하여야 한다.
실습 1 ) 정수 10개를 저장할 수 있는 메모리를 동적으로 할당해보자.
#include <iostream>
using namespace std;
int main() {
int* p;
p = (int*)malloc(10 * sizeof(int));
if (p == NULL) {
cout << "메모리가 부족해서 할당할 수 없습니다." << '\n';
exit(1);
}
int num;
for (int i = 0; i < 10; i++) {
cin >> num;
p[i] = num;
cout << p[i] << ' ';
}
free(p);
return 0;
}
구조체와 포인터
포인터를 통하여 구조체의 멤버에 접근하는 편리한 표기법 "->"
(*ps).i
ps -> i
위의 두 줄은 같은 의미지만, 아랫줄처럼 쓰는 것이 더 편리하다.
구조체 자체를 함수로 전달하는 경우, 구조체가 함수로 복사되어 전달되기 때문에, 큰 구조체의 경우에는 구조체 포인터를 전달하는 것이 좋다.
실습 2) 동적 메모리 할당을 이용하여 구조체를 생성하고 데이터를 저장해보자.
#include <iostream>
using namespace std;
struct Student {
char name[10];
int age;
double gpa;
};
int main() {
Student *s;
s = (Student*)malloc(sizeof(Student));
if (s == NULL) {
cout << "메모리가 부족해서 할당할 수 없습니다." << '\n';
exit(1);
}
strcpy(s->name, "Park");
s->age = 20;
free(s);
return 0;
}
반응형