1-9 동적 메모리 할당
1. 동적 메모리 할당
- 동적 메모리 할당 또는 메모리 동적 할당은 프로그램이 실행 시간(runtime) 동안
또는 실행 중에 사용할 메모리 공간을 할당하는 것을 의미 - 동적 할당은 스택(stack)이 아닌 힙(heap) 영역을 사용
2. 동적 메모리 할당 함수
- 사용자가 동적으로 메모리를 할당할 수 있도록 표준 라이브러리에서는 다음의 3가지 함수를 제공하며
이 함수는 sodlib.h 파일에서 찾을 수 있음 - void *malloc(size_t size): 힙 영역에 메모리 할당
- void *realloc(void *ptr, size_t size): 기존의 할당된 메모리의 크기를 변경
- void *calloc(size_t elength, size_t esize): 힙 영역에 메모리 할당 후, 0으로 초기화
- 힙에 생성된 메모리는 프로그램이 종료될 때까지 유지되므로
사용이 끝난 동적 할당 메모리는 반드시 해제해야 하며
동적 할당된 메모리를 해제하는 함수는 다음과 같다 - void free(void *p): 동적 할당된 메모리를 해제
- 동적 할당은 항상 성공하는 것이 아니며, 동적 메모리 할당에 실패할 경우, 동적 메모리 할당 함수는 널(NULL)을 반환
- 동적 할당 함수 호출 후의 반환 값을 조사한 다음 사용해야 함
#include <stdio.h>
#include <stdlib.h>
int main()
{
//static allocation(stack)
int age = 10;
printf("age = %d\n", age);
//dynamic allocation(heap)
int *pAge = malloc(sizeof(int));
if(pAge == NULL){
fprintf(stderr, "malloc error");
return;
}
*pAge = 10;
printf("*pAge = %d\n, *pAge");
free(pAge);
}
3. 동적 메모리 할당의 필요성
- 프로그램을 구현하는 단계에서 필요한 메모리의 크기를 결졍하는 것을 정적 할당이라고하며
변수나 배열의 선언이 이에 해당됨
#include <stdio.h>
void main()
{
char names[3][32]; // 정적 할당
int i;
for(i = 0; i < 3; i++){
printf("Input your name: ");
scans("%s", names[i]);
}
for(i = 0; i < 3; i++)
printf("%d. %s\n", i + 1, names[i]);
}
- 구현 단계에서 입력된 데이터의 범위를 예측하는 것은 어렵기 때문에 프로그램이 실행중에
입력된 데이터의 범위에 맞게 메모리를 확보활 필요가 있으며 이를 동적 할당이라고 함
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
char *names[3];
int i;
for(i = 0; i < 3; i++){
char buf[32];
printf("Input your name: ");
scans("%s", buf);
names[i] = malloc(strlen(buf) + 1);
strcpy(names[i], buf);
}
for(i = 0; i < 3; i++)
printf("%d. %s\n", i + 1, names[i]);
for(i = 0; i < 3; i++)
free(names[i]);
return 0;
}
4. 배열의 동적 할당
- 1차원 배열의 경우, 배열의 전체 크기를 계산하여 그 크기만큼 힙에 할당하고
할당된 객체의 시작 주소를 원소의 타입에 대한 포인터 변수로 가리키면 됨
#include <stdio.h>
#include <stdlib.h>
void main()
{
// static allocation(in stack)
int arr[10];
int i;
for(i = 0; i < 10; i++){
arr[i] = i;
printf("arr[i] = %d\n", i, arr[i]);
}
// dynamic allocation(in heap)
int *pArr = malloc(sizeof(int) * 10);
for(i = 0; i < 10; i++){
pArr[i] = i;
printf("pArr[%d] = %d\n", i, pArr[i]);
}
free(pArr);
}
- 2차원 배열을 동적으로 할당하려면 2차원 배열의 전체 크기를 계산하여 그 크기만큼 할당하고
할당된 객체의 시작 주소를 배열 포인터에 저장하면 됨
#include <stdio.h>
#include <stdlib.h>
void main()
{
// static allocation(in stack)
int arr[2][3] = { 0, };
int i, j;
for(i = 0; i < 2; i++){
for(j = 0; j < 3; j++)
printf("%d ", arr[i][j]);
}
getchar();
// dynamic allocation(in heap)
int (*pArr)[3] = calloc(2 * 3, sizeof(int));
for(i = 0; i < 2; i++){
for(j = 0; j < 3; j++)
printf("%d ", arr[i][j])
printf("\n");
}
free(pArr);
}
1-10 이중 포인터
1. 이중 포인터(Double Pointer to)
- 포인터 변수의 주소를 저장하는 포인터 변수를 의미
#include <stdio.h>
void main()
{
int age = 10;
int *pAge = &age;
int **ppAge = &pAge;
printf("**ppAge = %d\n", **ppAge);
}
2. 이중 포인터를 사용하는 이유
- 이중 포인터를 사용하는 이유는 일반적으로 다른 지역에 선언된 일중 포인터 변수에 접근하기 위함
#include <stdio.h>
void init_ptr(int **pPtr)
{
*pPtr = 0;
}
void main()
{
int *ptr;
printf("ptr = %d\n", ptr);
init_ptr(&ptr);
printf("ptr = %d\n", ptr);
}
1-11 함수 포인터
함수의 시그니처란? 함수의 선언에서 함수명을 뺀 나머지를 의미한다.
1. 함수 포인터(Pointer of Function)
- 함수를 가리키는 포인터를 의미
- 함수 포인터의 선언 방법: 리턴타입(*변수명)([매개변수,...]);
- 함수의 주소를 얻는 방법: 함수의 이름은 함수의 시작 주소로 해석됨
- 함수 포인터를 사용한 함수 호출 방법: 함수 호출(0) 연산자 사용
#include <stdio.h>
void foo(int a) { printf("called foo(%d)\n", a); }
void main()
{
void(*fptr)(int);
fptr = foo;
fptr(10);
}
2. 함수 포인터의 다양한 사용
- 함수 포인터는 다른 함수의 인자 또는 반환 값으로 사용 가능
#include <stdio.h>
void foo(int a) { printf("called foo(%d)\n", a); }
void goo(void(*fp)(int), int a)
{
fp(a);
}
void(*hoo())(int)
{
return foo;
}
void(*zoo(void(*fp)(int)))(int)
{
return fp;
}
void main()
{
foo(10);
goo(foo, 10);
hoo()(10);
zoo(foo)(10);
}
3. 복잡한 함수 포인터 선언 문제 해결
- typedef 키워드를 사용하여 해결
#include <stdio.h>
void foo(int a) { printf("called foo(%d)\n", a); }
typedef void(*FP)(int)
void goo(FP fp, int a) //void goo(void(*fp)(int), int a)
{
fp(a);
}
FP hoo() //void(*hoo())(int)
{
return foo;
}
FP zoo(FP fp) //void(*zoo(void(*fp)(int)))(int)
{
return fp;
}
void main()
{
foo(10);
goo(foo, 10);
hoo()(10);
zoo(foo)(10);
}
1-12 가변 배열
1. 가변 배열(Jagged Array)
- 기존의 2차원 배열의 동적 할당의 단점은 열이 고정되어 있음
- 포인터 배열과 동적 메모리 할당을 조합하면 행과 열이 고정되지 않은 가변 배열을 생성할 수 있다.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int i, j;
int row = 2, col = 3;
int **arr = malloc(sizeof(int*) * row);
for(i = 0; i < row; i++)
arr[i] = calloc(col, sizeof(int));
for(i = 0; i < row; i++){
for(j = 0; j < col; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
for(i = 0; i < row; i++)
free(arr[i]);
free(arr);
}
반응형
'Software' 카테고리의 다른 글
Secure Cordng C - Preprocessor (0) | 2018.07.23 |
---|---|
Secure Cordng C - Coding Style (0) | 2018.07.20 |
Secure Cordng C - 포인터의 개념과 이해 #2 (0) | 2018.07.18 |
Secure Cordng C - 포인터의 개념과 이해 #1 (0) | 2018.07.09 |
DSP란 무엇인가? (1) | 2016.11.21 |