반응형
동적 메모리 할당 (Dynamic Memory Allocation)
1. 동적 메모리 할당이란?
- 동적 메모리 할당은 프로그램 실행 중에 메모리를 동적으로 요청하고 해제하는 기능입니다.
- C 언어에서는 malloc, calloc, realloc, **free**를 사용하여 메모리를 관리합니다.
- 장점:
- 컴파일 타임이 아닌 런타임에 필요한 만큼 메모리를 할당 가능.
- 프로그램의 유연성과 효율성 증가.
- 단점:
- 메모리 누수 가능성.
- 프로그래머가 직접 메모리를 해제해야 함.
2. 동적 메모리 할당 함수
1) malloc (Memory Allocation)
- 메모리를 초기화하지 않고 필요한 크기만큼 할당.
- 반환값: 할당된 메모리의 시작 주소를 가리키는 포인터.
사용법:
void* malloc(size_t size);
예제:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = (int *)malloc(5 * sizeof(int)); // 정수 5개 크기의 메모리 할당
if (p == NULL) { // 메모리 할당 실패 시
printf("메모리 할당 실패\n");
return 1;
}
for (int i = 0; i < 5; i++) {
p[i] = i + 1; // 메모리 초기화
}
for (int i = 0; i < 5; i++) {
printf("%d ", p[i]); // 메모리 내용 출력
}
free(p); // 메모리 해제
return 0;
}
출력 결과:
1 2 3 4 5
2) calloc (Contiguous Allocation)
- 초기화된 메모리를 할당. 할당된 모든 바이트는 0으로 초기화됨.
- 반환값: 할당된 메모리의 시작 주소를 가리키는 포인터.
사용법:
void* calloc(size_t num, size_t size);
예제:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = (int *)calloc(5, sizeof(int)); // 정수 5개 크기의 메모리 할당 및 초기화
if (p == NULL) {
printf("메모리 할당 실패\n");
return 1;
}
for (int i = 0; i < 5; i++) {
printf("%d ", p[i]); // 초기값 확인 (0으로 초기화됨)
}
free(p); // 메모리 해제
return 0;
}
출력 결과:
0 0 0 0 0
3) realloc (Reallocate)
- 이미 할당된 메모리의 크기를 재조정.
- 기존 데이터를 유지하며 메모리 크기를 늘리거나 줄임.
사용법:
void* realloc(void* ptr, size_t new_size);
예제:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = (int *)malloc(3 * sizeof(int)); // 정수 3개 크기의 메모리 할당
if (p == NULL) {
printf("메모리 할당 실패\n");
return 1;
}
for (int i = 0; i < 3; i++) {
p[i] = i + 1; // 초기화
}
// 메모리 크기 확장 (3개 -> 5개)
p = (int *)realloc(p, 5 * sizeof(int));
if (p == NULL) {
printf("메모리 재할당 실패\n");
return 1;
}
p[3] = 4;
p[4] = 5;
for (int i = 0; i < 5; i++) {
printf("%d ", p[i]);
}
free(p); // 메모리 해제
return 0;
}
출력 결과:
1 2 3 4 5
4) free (Free Memory)
- 동적으로 할당된 메모리를 해제.
- 메모리 해제 후에는 해당 포인터를 더 이상 사용할 수 없습니다.
사용법:
void free(void* ptr);
예제:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = (int *)malloc(5 * sizeof(int));
if (p == NULL) {
printf("메모리 할당 실패\n");
return 1;
}
free(p); // 메모리 해제
return 0;
}
3. 동적 메모리 할당 주요 특징
1) 메모리 누수 (Memory Leak)
- free를 호출하지 않으면 메모리 누수가 발생.
- 메모리 누수는 프로그램이 종료되어도 메모리가 해제되지 않는 문제를 야기.
#include <stdlib.h>
void memoryLeakExample() {
int *p = (int *)malloc(100 * sizeof(int));
// free(p); -> 메모리 해제 누락으로 누수 발생
}
2) NULL 포인터 확인
- 메모리 할당이 실패하면 반환값이 NULL.
- 항상 메모리 할당 후 NULL 여부를 확인.
int *p = (int *)malloc(100 * sizeof(int));
if (p == NULL) {
printf("메모리 할당 실패\n");
return;
}
3) 사용 후 초기화
- free를 호출한 후 포인터를 NULL로 설정하는 것이 좋습니다.
free(p);
p = NULL; // 더 이상 유효하지 않은 메모리를 참조하지 않도록 설정
4. 동적 메모리 할당을 활용한 심화 예제
1) 배열 확장
- 동적으로 크기가 변하는 배열 구현.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int size = 3, new_size;
int *arr = (int *)malloc(size * sizeof(int));
for (int i = 0; i < size; i++) {
arr[i] = i + 1; // 초기화
}
printf("기존 배열: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
// 배열 크기 확장
new_size = 5;
arr = (int *)realloc(arr, new_size * sizeof(int));
for (int i = size; i < new_size; i++) {
arr[i] = i + 1;
}
printf("\n확장된 배열: ");
for (int i = 0; i < new_size; i++) {
printf("%d ", arr[i]);
}
free(arr); // 메모리 해제
return 0;
}
출력 결과:
기존 배열: 1 2 3
확장된 배열: 1 2 3 4 5
2) 2차원 배열 동적 할당
- 동적으로 할당된 2차원 배열 구현.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int rows = 3, cols = 4;
int **matrix = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
matrix[i] = (int *)malloc(cols * sizeof(int));
}
// 값 초기화
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j + 1;
}
}
// 값 출력
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
// 메모리 해제
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
return 0;
}
출력 결과:
1 2 3 4
5 6 7 8
9 10 11 12
5. 동적 메모리 할당의 장단점
장점
- 유연성: 런타임 시 필요한
메모리만 할당. 2. 효율성: 메모리 낭비 최소화. 3. 다차원 데이터 구조 구현: 배열, 연결 리스트 등.
단점
- 메모리 누수 가능성.
- 프로그래머가 관리해야 함: 메모리 해제를 잊으면 누수 발생.
- 속도 문제: 동적 메모리 할당은 정적 메모리보다 느림.
반응형
'Computer Science > C 언어' 카테고리의 다른 글
[C #16] 문자열 입력 기본 함수와 상황별 선택 (3) | 2024.12.14 |
---|---|
[C #15] 문자열 (Strings) (0) | 2024.12.13 |
[C #13] 포인터와 배열 (Pointers and Arrays) (1) | 2024.12.11 |
[C #12] 포인터 (Pointers) (1) | 2024.12.10 |
[C# 11] Makefile 분석 (0) | 2024.12.09 |