関数ポインタ
関数ポインタとは
ポインタとして保持できるのは、何も変数だけではありません。関数もまた、ポインタとして利用できます。これを、関数ポインタと言います。実際に、簡単なサンプルを見てみましょう。
listex3-fp-1:main.c#include <stdio.h> // 関数 void func1(); void func2(); void main() { void (*fp)() = func1; // 関数ポインタをfunc1で初期化 fp(); // 関数fpを実行 fp = func2; fp(); // 関数fpを実行 } // 関数1 void func1() { printf("func1¥n"); } // 関数2 void func2() { printf("func2¥n"); }
func1
func2
func2
このプログラムの8行目で定義されている、fpが、関数のポインタです。関数のポインタの書式は、以下の通りになっています。
期待される実行結果の例 関数ポインタの書式
型名 (*変数名)(引数)
という形になります。ここで用いている、func1()および、func2()は、戻り値の型がvoidであり、引数がないので、()無いが空白で、変数名がfpであることから、void (*fp)と宣言します。
型の定義の仕方こそ特殊ですが、関数ポインタも、ポインタ変数の一種です。ただ、そこに代入するのはあくまでも関数です。
引数のある場合のサンプル
続いて、関数に引数がある場合のケースを見てみましょう。以下のサンプルを実行してみてください。
listex3-fp-2:main.c#include <stdio.h> int max(int,int); int min(int,int); void main() { int (*cmp)(int,int) = max; // cmpの初期化と(max) int a = 1,b = 2; printf("%dと%dのうち、最大のものは、%d¥n",a,b,cmp(a,b)); cmp = min; // cmpにminを代入 printf("%dと%dのうち、最小のものは、%d¥n",a,b,cmp(a,b)); } // 最大値を返す関数 int max(int m,int n) { if(m > n){ return m; } return n; } // 最大値を返す関数 int min(int m,int n) { if(m < n){ return m; } return n; }
1と2のうち、最大のものは、2
1と2のうち、最小のものは、1
1と2のうち、最小のものは、1
関数の引数として関数ポインタを渡す
続いて、さらに高度な使い方を見てみましょう。関数ポインタは、さらに、他のポインタ同様、関数の引数として渡すことも可能です。ためしに、以下のサンプルを実行してみてください。
listex3-fp-3:main.c#include <stdio.h> // 関数ポインタを引数としてとる関数 void funcp(int (*)(int),int n); // 関数ポインタに用いる関数 int dbl(int); int hlf(int); void main() { funcp(dbl,8); // 引数として、関数を渡す funcp(hlf,8); // 引数として、関数を渡す } void funcp(int (*f)(int),int n) { printf("引数:%d 結果%d¥n",n,f(n)); } // 最大値を返す関数 int dbl(int n) { return n * 2; } int hlf(int n) { return n / 2; }
引数 8 : 結果16
引数 8 : 結果4
引数 8 : 結果4
4行目で、関数ポインタを引数として持つ関数、funcp()のプロトタイプ宣言をしています。プロトタイプ宣言の中で、関数ポインタを宣言するときは、以下のようになります。
引数内での関数ポインタの書式
型名 (*)(引数)
普通の引数と同様、関数ポインタの宣言から、変数名を抜いた形にすればよいことがわかります。関数名は、対応する関数の定義の中で記述します。15行目)
このサンプルでは、この引数として、関数dblおよび、hlfを与えています。引数として与えられた関数は17行目で実行されていますが。関数が違えば、当然のことながら実行結果は違ってきます。
このように、関数ポインタは、呼び出す関数を動的に変更する時に非常に便利です。