Home » 레퍼런스 » C » c언어 함수 포인터 왜 사용하는지 알아봅시다.

c언어 함수 포인터 왜 사용하는지 알아봅시다.

c언어 함수 포인터 인자는, 의외로 자주 볼 수 있습니다. 특히, 정렬이나 이진 탐색 method는 반드시 들어가는데요. 여기에서는 문법을 다루지 않습니다. 왜 쓰는지 알아보고, qsort case를 확장해서 이해해 보도록 하겠습니다.


c언어 함수 포인터

먼저, function pointer는, 함수를 가리키는 포인터입니다. 이게 무슨 소리인가? 함수는 실행 흐름입니다. 이걸 가리킬 수 있다는 것입니다. 아래 상황을 봅시다.

void (*t)(void) = f; 라고 되어 있어요. 함수 f와 g는 아무 것도 리턴하지 않고, 아무 인자도 받지 않습니다. 이 말의 의미는 아무 것도 리턴하지 않고, 아무 것도 받지 않는 함수를 가리키는 포인터 t가, f를 가리킨다는 의미입니다. 이 경우, t(); 문장은 함수 f를 호출합니다.

만약에, 이 t에 g를 대입하면 어떻게 될까요?

t가 g를 가리키게 되므로, t(); 문장은, f 함수를 호출하는 것이 아니라, g 함수를 호출합니다. 이는, t가 어떤 함수를 가르키는지에 따라 실행 흐름이 바뀔 수 있다는 의미입니다. 이제, 아래 예제를 보겠습니다.

[그림 1] 예제 1번 프로그램

먼저, 아무 것도 리턴하지 않고, 아무런 인자도 받지 않는 함수 f와 g가 있습니다. 그리고, 3번째 func 함수는, 아무것도 리턴하지 않고, 아무런 인자도 받지 않는 함수를 가리키는 포인터를 넘깁니다.

[그림 2] func 함수

func 함수는, 함수 포인터 work를 받아, work를 실행합니다. 이 work는 func가 결정하지 않습니다. func가 받았다는 것이 중요해요. 즉, func 내에서 실행하고 싶은 실행 흐름을, func 내부에서 받은 게 아니라 외부에서 받은 것이 매우 중요합니다.

이렇게 되면, 어떤 것이 유리해 질까요? 현재 Hello f를 출력하게 하고 있어요. 이를, Hello g를 출력해게끔 바꾸고 싶다고 해 봅시다. 그런데, 우리는 work를 받게 했단 말이죠.

이를 그리면 위와 같습니다. func는 user가 바꿀 수 없는 함수라고 해 보겠습니다. 그래서 회색으로 표시했습니다. func는 work를 받습니다. 즉, func는 work에 의존하게 됩니다. 현재 Hello f를 출력하게 했다면, 상황이 아래와 같았을 겁니다.

work가 함수 f의 흐름을 받았습니다. 그리고 이 work를 func가 의존하게 됩니다. 따라서 work(); 에서, 함수 f가 호출되어 Hello f가 출력됩니다. 이것을 user가 호출하는 곳에서 g로 바꿔버리면 어떻게 될까요?

work는 함수 g의 흐름을 받았습니다. 따라서, work(); 에서, 함수 g가 호출되어 Hello g가 출력됩니다. 중요한 것은 무엇일까요? 우리는, func를 바꾸지 않고도, func 내부의 work가 가리키는 함수를 바꾸었습니다. 그래서, 흐름을 바꿀 수 있었다는 것입니다. 결과를 보겠습니다.

[그림 3] 1번 프로그램의 결과

Hello f와 Hello g가 차례대로 출력됩니다.


c언어 qsort 함수

qsort 함수의 원형은 아래와 같습니다.

[그림 4] qsort 함수의 원형

여기서 중요하게 보아야 할 것은 4번째 인자입니다.

  • int (*compare)(const void*, const void*)

const void * 2개를 받고, int형을 돌려주는 함수 포인터를 받겠다는 의미입니다. 왜 이게 들어갔는가? 대부분의 sort는 키 값 2개를 비교합니다. const void * type의 2개는 키 2개를 의미합니다. 그런데, 우리는 정렬을 여러 기준으로 하게 됩니다. 예를 들어, 오름차순, 내림차순 등입니다.

[그림 5] 예제 2번 프로그램

2번 프로그램을 봅시다. qsort를 호출해서 정렬하는 것입니다. cmp1과 cmp2는 key 2개를 비교하는 것인데요. a의 값과 b의 값을 비교했을 때 음수가 나오면 a가 b보다 앞에 나옵니다. 0보다 큰 수가 나오면 뒤에 나오게 됩니다.

그러므로, cmp1은 오름차순으로, cmp2는 내림차순으로 정렬하기 위한 key를 비교하는 것임을 알 수 있어요. 상황은 아래와 같이 그려집니다.

오름차순 정렬을 하기 위한 키 값 비교 함수가 qsort에 inject 되었습니다. 결과는 어떻게 나올까요?

[그림 6] 예제 2번의 결과

오름차순으로 정렬됩니다. 만약에, 내림차순으로 정렬하고 싶으면 어떻게 하면 될까요? qsort 내부를 바꿔야 할까요? 아닙니다.

단지, 내림차순으로 정렬하기 위한 키 값 비교 함수로 바꾸면 됩니다. qsort는 제가 정의한 키 값 비교 함수를 씁니다. 따라서, 정렬 기준이 바뀌더라도 qsort가 바뀔 일이 없습니다. 그러면 예제 2번에서 어느 부분만 바꾸면 될까요?

qsort의 4번째 인자만 바꾸면 됩니다.

[그림 7] 바뀐 예제 2번 프로그램

cmp1 대신에 cmp2로 바꾼 것을 볼 수 있어요. 이제, 결과를 볼까요?

[그림 8] 2번 프로그램의 결과

아까와는 다르게 내림차순으로 정렬되었음을 알 수 있습니다. 즉, qsort 함수는 두 키를 비교하는 흐름을 user가 넘겨주는 것에 따라 바꾸는 것입니다.

Leave a Comment

12 + 15 =