本文へスキップ
BecomeCoder

C言語コース · 第10章 関数ポインタと標準ライブラリ活用 · レッスン39

関数ポインタ ― 関数を変数のように扱う

ブラウザで完結

導入

「足し算」と「引き算」のどちらを行うかを、実行時の状況によって切り替えたい――そんなとき if/switch で毎回分岐を書くこともできますが、C言語には「使う関数そのものを変数に入れて、後で切り替える」というもっと直接的な方法があります。

説明

関数は名前を書くだけで、そのメモリ上の場所(アドレス)を表す関数ポインタとして扱えます。宣言の形は少し独特です。

#include <stdio.h>

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }

int main(void) {
    int (*fp)(int, int);   // int を返し、int, int を受け取る関数へのポインタ

    fp = add;
    printf("add: %d\n", fp(3, 4));

    fp = sub;
    printf("sub: %d\n", fp(3, 4));

    return 0;
}

int (*fp)(int, int); は「fp は、int を2つ受け取り int を返す関数へのポインタだ」という宣言です。(*fp) を丸括弧で囲むのが重要で、これがないと意味がまったく変わってしまいます(丸括弧なしの int *fp(int, int) は「int* を返す関数」の宣言になります)。

fp = add; のように、関数名をそのまま代入できます(配列名と同じで、関数名を書くとその先頭アドレスとして扱われるため & は不要です)。あとは fp(3, 4) と、普通の関数呼び出しと同じ書き方で呼び出せます。

flowchart LR
  fp["変数 fp"] -->|"fp = add;"| addf["関数 add"]
  fp -.->|"fp = sub; で切り替え"| subf["関数 sub"]

関数ポインタを配列にまとめれば、番号で使う関数を選ぶこともできます。

#include <stdio.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; }

int main(void) {
    int (*ops[3])(int, int) = { add, sub, mul };

    for (int i = 0; i < 3; i++) {
        printf("ops[%d](6, 2) = %d\n", i, ops[i](6, 2));
    }
    return 0;
}

ops は「関数ポインタの配列」です。ops[i](6, 2) のように、配列の要素をそのまま関数として呼び出せます。

やってみよう

fpaddsub を切り替えて代入し、結果が変わることを確かめましょう。ops の配列にもう1つ関数を追加してみてください。

演習

掛け算を行う関数 int mul(int a, int b) { return a * b; } を定義してください。関数ポインタ fpmul を代入し、fp(4, 5) の結果を printf で表示してください(結果は 20)。

ヒント1を見る

int (*fp)(int, int); fp = mul; のように宣言と代入をします。

ヒント2を見る

呼び出しは普通の関数と同じ書き方で fp(4, 5) です。

実際に動かしてみよう

下のエディタにCを書いて「実行」を押すと、ブラウザ内のインタプリタで出力が表示されます。本文の例をそのまま試したり、書き換えたりしてみましょう(scanf を使う回は「標準入力」欄に値を入れてから実行します)。

C/C++ — ブラウザ内で実行

ブラウザ内でC/C++を動かす学習用インタプリタ(JSCPP)を読み込みます(入門向けのサブセットです)。
スクロールして表示された時点でも自動で読み込まれます。