関数ポインタ

非線形方程式などのサブルーチンを作成する場合、対象となる関数や方程式が替わるたびにサブルーチン内の関数名を書き換える必要がある。

しかし、サブルーチンの引数の一つに関数名を指定できるようにすれば、サブルーチンを呼び出すメイン側に関数名の決定権を譲ることになり、非常に汎用性の高いサブルーチンとなる。

それを実現するために使われるのが関数ポインタである(熊谷・玉城・白川「例題で学ぶ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
    -----------------------