Programming Language/C++

[C/C++] 함수 포인터

lumana 2024. 6. 28. 23:28

함수 포인터

  • 모든 명령어들은 전부 0과 1로 메모리에 저장이 되기 때문에, 메모리 저장 공간의 주소를 가지고 있다

    • 함수 포인터는 함수에 대한 포인터를 가지고 있다.
bool compare(int a, int b) {
    return a == b;
}

int main() {
    bool (*fp)(int, int);
    int *a;
}
  • int *a를 a를 역참조하면 int형이 나온다라고 해석할 수 있다.

  • 이런 것처럼 fp를 역참조를 하면 bool을 리턴하고 int 2개를 매개변수로 받는 함수다 라고 해석할 수 있다.

    • fp는 int 2개를 받고 bool을 반환하는 함수를 가리키는 포인터이다.
bool compare(int a, int b) {
    return a == b;
}

int main() {
    bool (*fp)(int, int);
    fp = &compare;
        // fp = compare;도 가능하다. &를 붙이나 안 붙이나 같은 의미로 같게 동작한다. 위와 차이가 없다
    bool res = (*fp)(2, 3);
}
  • fp를 역참조를 하게되면 compare와 같게 작동하게 된다

  • fp = compare;도 가능하다. &를 붙이나 안 붙이나 같은 의미로 같게 동작한다.

  • 선언과 동시에 초기화도 가능하다

int main() {
    int arr[3];
    bool (*fp)(int, int) = compare;
    int (*ap)[3] = &arr;
    bool res = (*fp)(2, 3);
    cout << res << endl;
}

함수 포인터를 사용하는 이유?

#include <iostream>
using namespace std;

int arrMin(const int arr[], int n) {
    int min = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] < min) {
            min = arr[i];
        }
    }
    return min;
}

int main() {
    int arr[7] = { 3, 1, -4, 1, 5, 9, -2};
    cout << arrMin(arr, 7) << endl;
}
  • 만약 위 코드에서 arr의 원소를 특정 연산이나 함수를 돌린 값으로 바꾼 결과로 부터 최솟값을 구하고 싶다고 해보자

    • ex) 제곱한 값 중 최소를 구하는 함수를 만들어보자
#include <iostream>
using namespace std;

int arrMin(const int arr[], int n) {
    int min = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] < min) {
            min = arr[i];
        }
    }
    return min;
}

int arrSquareMin(const int arr[], int n) {
    int min = arr[0] * arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] * arr[i] < min) {
            min = arr[i] * arr[i];
        } 
    }
    return min;
}

int main() {
    int arr[7] = { 3, 1, -4, 1, 5, 9, -2};
    cout << arrSquareMin(arr, 7) << endl;
}
  • 만약 제곱이 아니라, 더 복잡한 함수를 통해서 나온 값들의 최소를 구해야 할 필요가 있을 수 있다.

    • f(3), f(1), f(-4), f(1)... 의 최솟값을 찾을 수 있는 함수가 있으면 좋겠다

    • 함수 포인터를 사용해보자

int arrFnMin(const int arr[], int n, int (*f)(int)) {
    int min = f(arr[0]);
    for (int i = 1; i < n; i++) {
        if (f(arr[i]) < min) {
            min = f(arr[i]);
        }
    }
    return min;
}
  • 함수의 매개변수에 임의의 함수를 가리키는 함수 포인터를 받아서 호출을 해줄 수 있다.
#include <iostream>
using namespace std;

int square(int x) { return x * x; }
int myFunc(int x) { return x * (x - 15) / 2; }

int arrFnMin(const int arr[], int n, int (*f)(int)) {
    int min = f(arr[0]);
    for (int i = 1; i < n; i++) {
        if (f(arr[i]) < min) {
            min = f(arr[i]);
        }
    }
    return min;
}

int main() {
    int arr[7] = { 3, 1, -4, 1, 5, 9, -2};
    cout << arrFnMin(arr, 7, square) << endl;
    cout << arrFnMin(arr, 7, myFunc) << endl;
}
  • square()와 myFunc() 함수에서 반환한 값을 기준으로 최솟값을 찾고 있다.

  • 세제곱해주는 함수를 만들어서 최솟값을 찾을 수도 있고, 무궁무진한 아무 함수를 만들어서 사용할 수 있다.

  • 어떠한 함수든지 매개변수 타입과 리턴 타입만 갖다면 어떤 함수든지 가리킬 수 있기에 유용하다

    • 타입이 다르면 에러가 발생한다(가리킬 수 없다)

    • 이런 특징 때문에 인공지능에서 종종 사용된다고 한다(주어진 데이터에 대해 모델 성능을 측정하는 경우를 생각해보자)

참조) 두들낙서 C/C++ 강좌