非線形方程式などのサブルーチンを作成する場合、対象となる関数や方程式が替わるたびにサブルーチン内の関数名を書き換える必要がある。
しかし、サブルーチンの引数の一つに関数名を指定できるようにすれば、サブルーチンを呼び出すメイン側に関数名の決定権を譲ることになり、非常に汎用性の高いサブルーチンとなる。
それを実現するために使われるのが関数ポインタである(熊谷・玉城・白川「例題で学ぶC言語」の第11章 11.5 関数引数 pp.106-108 を参照のこと)。
例えば、後述する「二分法」のサブルーチン bisection で方程式 \(f(x)=0\) の左辺の関数 \(f(x)\) を任意の名前で呼び出せるようにするには、仮の関数名f
の前に*(アスタリスク)を付けてカッコで閉じた関数名(*f)
(これを関数ポインタという)を用い、これをサブルーチンの引数リスト内に関数の引数(型のみでよい)をつけてdouble (*f)(double)
のように定義しておく。
double bisection(double (*f)(double), double x1, double x2)
{
二分法の本体
}
さらに、このサブルーチン内部で関数を呼び出すときは
if (f(x1) * f(x3) < 0) x2 = x3;
というように引数リスト内で定義した仮の関数名(この場合は f( ) )で呼び出すようにしておく。
方程式の左辺の関数が実際には func1(x) という名前で定義されているなら、main関数で二分法のサブルーチンを呼び出すときに
x = bisection(func1, x1, x2);
と実際の関数名を引数なしで指定して呼び出せばよい。
◎以下のプログラムを実行して関数ポインタの使い方を確認せよ。
#include <stdio.h>
double func1(double x) // f(x) = x を返す関数
{
printf("# func1(% g) is called", x);
return x;
}
double func2(double x) // f(x) = x^2 を返す関数
{
printf("# func2(% g) is called", x);
return x*x;
}
double func_p(double (*f)(double), double x) // 関数引数を用いたサブルーチン
{
double y;
y = f(x); // ここでは仮の関数名 f() を用いる
printf(" in func_p().\n");
return y;
}
int main(void)
{
printf("func1(1) = % g\n", func_p(func1,1)); // func1 を指定して func_p を呼び出す
printf("func2(2) = % g\n", func_p(func2,2)); // func2 を指定して func_p を呼び出す
return 0;
}
[実行結果] ----------------------- # func1( 1) is called in func_p(). func1(1) = 1 # func2( 2) is called in func_p(). func2(2) = 4 -----------------------