導入
「足し算」と「引き算」のどちらを行うかを、実行時の状況によって切り替えたい――そんなとき 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) のように、配列の要素をそのまま関数として呼び出せます。
やってみよう
fp に add/sub を切り替えて代入し、結果が変わることを確かめましょう。ops の配列にもう1つ関数を追加してみてください。
演習
掛け算を行う関数 int mul(int a, int b) { return a * b; } を定義してください。関数ポインタ fp に mul を代入し、fp(4, 5) の結果を printf で表示してください(結果は 20)。
ヒント1を見る
int (*fp)(int, int); fp = mul; のように宣言と代入をします。
ヒント2を見る
呼び出しは普通の関数と同じ書き方で fp(4, 5) です。