Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

関数ポインタ

関数ポインタは「関数のアドレスを格納するポインタ」です。呼び出す関数を実行時に切り替えたり、関数を引数として渡したりする「コールバック」の実装に使います。

構文
// 関数ポインタ型の宣言です。
// 戻り値の型 (*ポインタ変数名)(引数の型, ...);
int (*fp)(int, int);

// 関数のアドレスを代入します(関数名がそのままアドレスです)。
fp = 関数名;

// 関数ポインタを通じて関数を呼び出します。
fp(引数1, 引数2);
(*fp)(引数1, 引数2); // 明示的な間接参照も同じ動作です。

// typedef で関数ポインタ型に名前を付けると読みやすくなります。
typedef 戻り値の型 (*型名)(引数の型, ...);
型名 変数名 = 関数名;
関数ポインタの用途
用途概要
コールバック処理の一部を呼び出し元から注入します。ソート・フィルタ・イベント処理などで使われます。
ディスパッチテーブル関数ポインタの配列を作り、インデックスで呼び出す関数を切り替えます。switch文の代替になります。
策略(Strategy)パターンアルゴリズムを関数ポインタで差し替えることで、構造体に振る舞いを持たせられます。
qsort / bsearch標準ライブラリの汎用ソート・探索関数は比較関数を関数ポインタで受け取ります。
サンプルコード
#include <stdio.h>
#include <stdlib.h>

// 操作対象となる関数を定義します。
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }

// 関数ポインタを引数に受け取るコールバック関数です。
void apply(int x, int y, int (*op)(int, int), const char *name) {
    printf("%s(%d, %d) = %d\n", name, x, y, op(x, y));
}

// typedef で読みやすくします。
typedef int (*BinaryOp)(int, int);

// qsort 用の比較関数です(昇順)。
int compare_asc(const void *a, const void *b) {
    return (*(int *)a - *(int *)b);
}

// qsort 用の比較関数です(降順)。
int compare_desc(const void *a, const void *b) {
    return (*(int *)b - *(int *)a);
}

int main(void) {
    // 関数ポインタに関数を代入して呼び出します。
    int (*fp)(int, int) = add;
    printf("add(3, 5) = %d\n", fp(3, 5)); // 『add(3, 5) = 8』と出力されます。

    fp = sub;
    printf("sub(10, 3) = %d\n", fp(10, 3)); // 『sub(10, 3) = 7』と出力されます。

    // コールバックとして渡します。
    apply(6, 2, add, "add"); // 『add(6, 2) = 8』と出力されます。
    apply(6, 2, sub, "sub"); // 『sub(6, 2) = 4』と出力されます。
    apply(6, 2, mul, "mul"); // 『mul(6, 2) = 12』と出力されます。

    // ディスパッチテーブル(関数ポインタの配列)です。
    BinaryOp ops[] = {add, sub, mul};
    const char *names[] = {"add", "sub", "mul"};
    for (int i = 0; i < 3; i++) {
        printf("%s(10, 4) = %d\n", names[i], ops[i](10, 4));
    }

    // qsort で関数ポインタを使います。
    int arr[] = {5, 1, 4, 2, 3};
    qsort(arr, 5, sizeof(int), compare_asc);
    printf("昇順: ");
    for (int i = 0; i < 5; i++) printf("%d ", arr[i]); // 『1 2 3 4 5』と出力されます。
    printf("\n");

    qsort(arr, 5, sizeof(int), compare_desc);
    printf("降順: ");
    for (int i = 0; i < 5; i++) printf("%d ", arr[i]); // 『5 4 3 2 1』と出力されます。
    printf("\n");

    return 0;
}
概要

関数ポインタはC言語で高階関数(関数を引数や戻り値として扱う仕組み)を実現する手段です。標準ライブラリの『qsort()』や『bsearch()』は比較ロジックを関数ポインタで受け取ることで、任意の型のデータを汎用的に処理できます。

『typedef』を使って関数ポインタ型に分かりやすい名前を付けると、コードの可読性が大幅に向上します。関数ポインタの宣言は括弧の位置が重要で、『int *fp(int)』は「int *を返す関数」となり、『int (*fp)(int)』とは全く別の意味になります。

関数ポインタを構造体に組み込むとオブジェクト指向的な設計が可能になります。構造体については『struct(構造体)』を、型の別名については『typedef』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。