본문 바로가기

BackEnd/C

함수 포인터를 인자로 요구하는 표준 함수들(atexit, qsort, bsearch)

반응형

1. 프로그램 종료 시 호출하고픈 함수가 있다면 atexit(at exit)


표준함수에 정의된 atexit 함수를 이용하면 프로그램 종료 시 자동으로 호출하고픈 함수를 등록할 수 있다.



반환형과 매개변수 형이 void로 선언된 함수의 이름이(주소 값이) atexit 함수의 인자로 전달되어


한다. 그리고 이렇게 인자로 전달된 함수가 프로그램 종료 시 자동으로 호출 되며, 이렇게 자동


으로 호출되어야 할 함수는 32개 이상 등록할 수 있다.


예제를 보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <stdlib.h>
 
void FirstFunc(void);
void SecondFunc(void);
void ThirdFunc(void);
 
int main(void)
{
    if(!atexit(FirstFunc))
        printf("첫 번째 함수 정상적 등록\n");
 
    if(!atexit(SecondFunc))
        printf("두 번째 함수 정상적 등록\n");
 
    if(!atexit(ThirdFunc))
        printf("세 번째 함수 정상적 등록\n\n");
 
    return 0;
}
 
void FirstFunc(void)
{
    printf("첫 번째 등록 함수.\n");
}
 
void SecondFunc(void)
{
    printf("두 번째 등록 함수.\n");
}
 
void ThirdFunc(void)
{
    printf("세 번째 등록 함수.\n");
}
cs


1
2
3
4
5
6
7
첫 번째 함수 정상적 등록
두 번째 함수 정상적 등록
세 번째 함수 정상적 등록
 
세 번째 등록 함수.
두 번째 등록 함수.
첫 번째 등록 함수.
cs


10,13,16행 : atexit 함수를 이용해서 프로그램 종료 시 호출하고픈 함수를 등록하고 있다. 등록이 


성공하면 0(false)를 반환하기 때문에 이러한 형태로 if문 구성이 가능하다.


실행결과를 보면 등록된 순서의 역순으로 호출되고 있음을 알 수 있다. 그리고


atexit 함수를 통해서 등록된 함수는 프로그램이 정상적으로 종료될 때에만 호출된다.



2. qsort


정렬 알고리즘 중에 ‘퀵 정렬(quick sort)’이라는 것이 있다. 이름 그대로 빠른 속도로 정렬하도록 디


자인 된 알고리즘이다. 퀵 정렬 알고리즘 자체는 아니지만, 퀵 정렬 알고리즘 기능을 제공하는 함수


이다.



qsort 함수의 첫 번째, 두 번째, 세 번째 매개변수에는 정렬할 대상에 대한 정보를 전달한다.

 

예를 들어 다음과 같은 형태의 배열이 선언되었다고 가정하면


int arr[5]={3, 1, 2, 4, 5};


다음과 같은 형태로 함수를 호출해야 한다.

 


그러면 qsort 함수는 비교 대상에 대한 크기 정보를 파악할 수 있다.


arr에서부터 시작해서 4바이트씩 끊어서,총 5개의 요소를 정렬하게 된다.


그리고 qsort 함수 내부에서 대소 비교를 해야 할 때, qsort 함수의 마지막 전달인자인 함수 포인터


를 활용하게 된다. 예를 들어서 배열의 첫 번째 요소와 두 번째 요소의 대소 비교를 해야 한다면, 


다음 그림과 같이 함수 포인터 compare가 가리 키는 함수를 호출하면서, 첫 번째 요소의 주소 값


과 두 번째 요소의 주소 값을 인자로 전달한다



따라서 qsort 함수의 마지막 전달인자가 될 함수를 정의해야 하는데, 이 함수의 정의 규칙은 다 음과 같이 정해져 있다. 


• 반환 값 0  :  비교 대상의 정렬 순서가 동일한 경우


• 반환 값 1  :  두 번째 포인터(p2)가 가리키는 대상이 정렬 순서상 앞서는 경우


• 반환 값 -1 :  첫 번째 포인터(p1)가 가리키는 대상이 정렬 순서상 앞서는 경우


이 규칙을 지켜서 값을 반환만 해주면 qsort 함수는 퀵 정렬 알고리즘을 근거로 저장된 값의 위치


를 변경가면서 정렬을 진행한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <stdlib.h>
 
int ACDSort(const void *const void *);
 
int main(void)
{
    int arr[5]={31245};
    int i;
 
    qsort((void*)arr, sizeof(arr)/sizeof(int), sizeof(int), ACDSort);
    for(i=0; i<5; i++)
        printf("%4d", arr[i]);
 
    printf("\n");
    
    return 0;
}
 
int ACDSort(const void * p1, const void * p2)
{
    int n1= *((int *)p1);
    int n2= *((int *)p2);
    int ret;
 
    if(n1>n2)
        ret=1;
    else if(n1<n2)
        ret=-1;
    else
        ret=0;
 
    return ret;
}

cs


1
2
   1   2   3   4   5
cs

20행 : qsort 함수에 정렬의 규칙을 제공하기 위한 함수이다. 이 함수는 반환형이 int형이어야 하고, void형 포인터 두 개를 인자로 전달받아야 한다.


26~27행: 정렬 규칙을 알려주는 아주 중요한 힌트이다. n1이 n2보다 값이 큰 경우 1을 반환하도록 하


고 있다. 1은 n2에 저장된 값의 정렬 순서가 앞설 경우에 반환하는 값이다. 그런데 n1의 값이 n2보다 


더 클때 1을 반환하고 있으니, 이는 오름차순으로 정렬이 이뤄짐을 요구하는 것이다.



3. bsearch


bsearch 함수는 이진 검색 (binary search) 알고리즘을 구현한 함수이다.


간단히 말해서 원하는 데이터를 찾아주는 기능을 제공하는 함수이다.


다만 저장된 데이터가 정렬되어 있어야 한다. 


그래서 qsort 함수와 더불어 유용하게 사용할 수 있다.


더 자세한 내용은 링크를 참고하자.


https://cg-developer.tistory.com/19


https://cg-developer.tistory.com/26



이진 검색은 구현 방식에 따라서 검색의 대상이 오름차순 또는 내림차순으로 정렬되어 있어야 하


는데, bsearch 함수는 검색의 대상이 오름차순으로 정렬되어 있을 것을 요구한다.


우선 첫 번째 매개변수를 통해 찾고자 하는 데이터가 저장되어 있는 변수의 주소 값을 전달해야 한


다. 그리고 두 번째, 세 번째, 네 번째 매개변수는 qsort 함수의 첫 번째, 두 번째, 세 번째 매개변수


와 의미가 동일하다. 마지막 매개변수 compare에 대해 살펴보자.


compare에 전달될 함수는 다음과 같은 형태로 정의되어야 한다.


int compare(const void * key, const void * value)

if (key가 참조하는 값이 value가 참조하는 값보다 크다) 

return "양수”; 

else if (key가 참조하는 값이 value가 참조하는 값보다 작다) 

return "음수"; 

else // key가 참조하는 값과 value가 참조하는 값이 같다. 

return 0;

}


이 함수는 bsearch 함수 내부에서 호출이 되는데, bsearch 함수의 첫 번째 전달인자가 이 함수의 


첫 번 째 전달인자인 key가 된다. 그리고 이 함수는 반환 값을 참조하여 찾고자 하는 데이터를 찾았


을때, 주소 값을 반환하면서 bsearch 함수를 종료한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <stdio.h>
#include <stdlib.h>
 
int ACDSort(const void *const void *);
int Compare(const void *const void *);
 
int main(void)
{
    int arr[5]={31245};
    int srchValue=2;
    int * srchPtr;
    int i;
 
    /* 정렬 과정 */
    qsort((void*)arr, sizeof(arr)/sizeof(int), sizeof(int), ACDSort);
    for(i=0; i<5; i++)
        printf("%4d", arr[i]);
 
    printf("\n");
 
    /* 검색 과정 */
    srchPtr=
        (int*)bsearch((void*)&srchValue, arr, 
                      sizeof(arr)/sizeof(int), sizeof(int), Compare);
 
    if(srchPtr==NULL)
        printf("찾는 대상이 존재하지 않습니다. \n");
    else
        printf("찾는 대상 %d이(가) 저장되어 있는 위치: %#x \n"
               *srchPtr, srchPtr);
    
    return 0;
}
 
int ACDSort(const void * p1, const void * p2)
{
    int n1= *((int *)p1);
    int n2= *((int *)p2);
    int ret;
 
    if(n1>n2)
        ret=1;
    else if(n1<n2)
        ret=-1;
    else
        ret=0;
 
    return ret;
}
 
int Compare(const void * pKey, const void * pValue)
{
    int key= *((int*)pKey);
    int value= *((int*)pValue);
 
    return key-value;
 
}

cs

1
2
   1   2   3   4   5
찾는 대상 2이(가) 저장되어 있는 위치: 0x62fe24
cs


반응형