[KNK] CH17 - 포인터 활용 고급
CH 17 Advanced Uses of Pointers
동적 할당
Memory Allocation Functions
- malloc: Allocates a block of memory but doesn’t initialize it(most used)
- calloc: Allocates a block of memory and clears it
- realloc: Resizes a previously allocated block of memory
널(Null)포인터
아무것도 가리키지 않는 포인터로 어떤 함수가 널포인터를 리턴하면 적절한 조치를 취해야 한다.
널포인터의 논리값은 false, 널포인터가 아닌 포인터의 논리값은 true
NULL매크로가 정의된 헤더파일은 다음과 같다.
- locale.h
- stddef.h
- stdio.h
- stdlib.h
- string.h
- time.h
- wchar.h(c99)
동적 할당된 문자열
malloc으로 문자열을 위한 메모리 할당하기
void *malloc(size_t size); // prototype
p = malloc(n + 1); // example
동적 할당을 하고 나면 free 함수를 이용해서 메모리를 정리해야 한다.
동적할당된 배열
malloc으로 베열을 위한 메모리 할당하기
a = malloc(n * sizeof(int))
calloc 함수
void *calloc(size_t nmemb, size_t size); // prototype
a = calloc(n , sizeof(int)); // example
struct point { int x, y; } *p;
p=calloc(1, sizeof(struct point));
The realloc Function
void *realloc(void *ptr, size_t size);
ptr: 반드시 malloc, calloc, realloc으로 만들어진 메모리 공간에 대한 포인터야 한다.
- 메모리 블록이 확장되면 확장된 부분은 초기화가 되어 있지 않다.
- 메모리 블록이 요구대로 확장이 안된 경우 널포인터를 반환된다.
- ptr에 널포인터를 넣을 경우 malloc이랑 같다.
- size로 0을 넣으면 메모리를 free 시킨다.
(주의) 메모리 블록을 확장시킬 때 바이트가 사용중이면 다른 곳에 메모리 블록이 생성 됨. realloc을 사용 후에는 byte를 update
메모리 해제
memory leak이 생길 경우 해야 한다.
free 함수
prototype:
void free(void*ptr); // prototype
/* example */
p = malloc(...);
q = malloc(...);
free(p);
p=q;
(주의) 다른 포인터(예를 들면 변수나 배열에 대한 포인터)를 해제하면 undefined한 일이 발생할 수 있다.
Dangling 포인터
free 함수로 지운 메모리 블록에 접근하면 undefined 행동을 할 수 있다.
연결 리스트
연결리스트는 노드의 연결로 이루어지며 각 노드는 다음 노드에 대한 포인터를 가지고 있다. 장단점은 아래와 같다.
- 장점: 삽입/ 삭제가 용이하다.
- 단점: 랜덤 액세스를 할 수 없다.
노드 선언
struct node
{
int value;
struct node *next;
};
// structure tag is necessary if
노드 생성하기
- 노드를 위한 메모리 공간을 할당받는다.
- 노드에 데이터를 저장한다.
- 리스트에 노드를 연결한다.
struct node *new_node;
new_node = malloc( sizeof(struct node) );
// new_node가 아니라 struct node를 sizeof 연산자 안에 넣어야 한다.
(*new_node).value = 10;
The ‘->’ 연산자
(*new_node).value = 10;
// is same with
new_node->value = 10;
// you can use like
scanf("%d",&new_node->value);
연결 리스트 맨 앞에 노드 추가하기
struct node *first;
struct node *new_node;
first = NULL;
new_node = malloc(sizeof(struct node));
new_node->value = 10;
new_node->next = first;
first = new_node;
new_node = malloc(sizeof(struct node));
new_node->value = 20;
new_node->next = first;
first = new_node;
struct node *add_to_list(struct node *list, int n)
{
struct node *new_node;
new_node = malloc(sizeof(struct node));
if (new_node == NULL)
{
printf("Error: malloc failed in add_to_list\n");
exit(EXIT_FALURE);
}
new_node->value = n;
new_node->next=list;
return new_node;
}
위 함수를 이용한 주어진 정수로 linked list 만들기
struct node *read_numbers(void)
{
struct node *first=NULL;
int n;
printf("Enter a series of intergers (0 to terminate): ");
for(;;)
{
scanf("%d',&n);
if(n==0)
return first;
first = add_to_list(first, n);
}
}
연결 리스트 탐색
for (p = first; p != NULL; p=p->next)를 이용
struct node *search_list(struct node *list, int n)
{
struct node *p;
for(p=list; p!=NULL; p=p->next)
if(p->value ==n)
return p;
return NULL;
}
노드 삭제하기
- 지울 노드를 찾는다.
- 지울 노드 다음 노드에 대한 포인터를 저장한다.
- 노드를 free하고 2.에서 저장한 포인터로 삭제된 노드 양쪽의 노드를 연결한다.
struct node *delete_from_list(struct node *list, int n)
{
struct node *cur, *prev;
for(cur = list, prev = NULL;
cur != NULL && cur->value != n;
prev = cur, cur = cur-> next)
;
if(cur ==NULL)
return list;
if(prev == NULL)
list = list->next;
else
prev->next = cur->next;
free(cur);
return list;
}
정렬된 리스트
삽입은 어렵지만 탐색이 빨라진다.
포인터에 대한 포인터
‘add_to_list’함수의 인수는 파라미터 자체를 바꾸지 않는다. 함수를 처음에 다음과 같이 사용해야 한다.
add_to_list(first, 10)
void add_to_list(struct node **list, int n)
{
struct node *new_code;
new_code =malloc(sizeof(struct node));
if(new_code==NULL)
{
printf("Error: malloc failed in add_to list\n");
exit(EXIT_FAILFURE);
}
new_node->=n;
new_node->next=*list;
}
add_to_list(&first,10);
함수 포인터
double integrate(double (*f)(double), double a, double b)
//is same with
double integrate(double f(double), double a, doubleb)
- f(): function call
- f: pointer to function
Declaration of function pointer variables
int (*FuncPtr)(int,int)
// FuncPtr라는 변수가 생김(이 변수는 2개의 int형 parameter를 받고 int형을 return)
typedof int (*FuncPtr)(int,int)
// FuncPtr이라는 type이 생김 (FuncPtr f1, f2;같이 선언 가능)
쓰는 이유
- 함수를 파라미터로 쓸 수 있다.
- 함수를 변수에 저장할 수 있다.
제한된 포인터(Restricted Pointers) (c99)
잘 모름
Flexible Array Members
일종의 편법임
struct vstring
{
int len;
char chars[ 1 (dummy value) ];
};
struct vstring *str = malloc(sizeof(struct vstring) + n-1 );
str->len = n;
// or
struct vstring
{
int len;
char chars[];
};
struct vstring *str = malloc(sizeof(struct vstring) + n);
str->len = n;
댓글남기기