関数へのポインタ

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

関数へのポインタは、C, C++, Dやその他多くのプログラミング言語におけるポインタの一種である。関数へのポインタをデリファレンスすれば、そのポインタが指し示す関数サブルーチン)を呼び出せる。応用例としては、switch文を置き換えるテーブルジャンプを実装する、などといったものがある。

関数オブジェクトは、関数へのポインタに似ているが、コード領域中のエントリポイントを指す単なるポインタである関数へのポインタと違い、データ領域上に実体を持つオブジェクトであるという点が異なっている(実装の詳細は言語や処理系により異なるが)。そのため、関数オブジェクトはデータを保持でき、クロージャを再現することもできる。ゆえに、関数オブジェクトは、「関数へのポインタ」ではなく「関数」という型と値を持つようなものと言え、より強力である。

Javaなどでは、関数へのポインタを使用できないが、そのような言語では、メソッドを1つだけ持つインタフェースで同様のことを行える。また、C#Visual Basic .NETなどといった.NET Framework用の言語には、デリゲートがある。

第一級オブジェクトとして関数を使用できる(第一級関数がある)言語では、関数も引数で渡したり、戻り値で返したり、他の関数から動的に作成したりできるなどデータ同様に扱えるため、関数へのポインタは必要とされない。

Cでの例[編集]

この例では、関数へのポインタとしてnew_functionが宣言され、そこへ関数my_functionのアドレスを割り当てている。そしてnew_functionを通じて関数を呼び出している。

#include <stdio.h>
 
static int my_function(int a)
{
    printf("my_function: %d\n", a);
    return 2 * a + 3;
}
 
int main(void)
{
    int (*new_function)(int a) = my_function;
    int  x;
 
    x = (*new_function)(10);
    printf("main: %d\n", x);
    return 0;
}

註:(*fp)(arg)という構文は、関数へのポインタfpを通じて関数を呼び出す構文である。しかしCではfp(arg)という構文も認められている[1]

次の例では、関数へのポインタを引数として他の関数に渡している。ここでは、関数functionが、先の例のように関数へのポインタを通じて呼び出される。関数callerは、引数として関数へのポインタと整数値を1つ取る。引数の整数値は、その関数へのポインタを通じて関数を呼び出すときに渡す引数として用いられる。そこで宣言されている関数へのポインタのプロトタイプに適合しさえすれば、callerの第一引数には、どんな関数でも渡すことが可能である。

#include <stdio.h>
 
static void function(int a)
{
     printf("my_function: %d\n", a);
}
 
static void caller(void (*new_function)(int a), int p)
{
    (*new_function)(p);
}
 
int main(void)
{
    caller(function, 10);
    return 0;
}

3番目の例でも関数へのポインタを引数として他の関数に渡して用いている。関数fは、指定された区間で積分\textstyle\int_{a}^{b} f(x)\;dxの近似を計算する関数integへ渡されている。xの値を求めるためにf(x)integから呼び出されている。integでは、double型の引数を1つ取り、double型の値を返しさえすれば、どんな関数でも計算させることが可能である。

double integ(double a, double b, double (*f)(double x))
{
    double  sum = 0.0;
    double  x;
    int     n;
 
    // 積分{a,b} f(x) dxの計算
    for (n = 0;  n <= 100;  n++)
    {
        x = (n/100.0)*(b-a) + a;
        sum += (*f)(x) * (b-a)/101.0;
    }
    return sum;
}

関数へのポインタを定義する際には、typedefを用いるのが便利である。

#include <stdio.h>
#include <math.h>
 
typedef double (*Fx)(double x);
 
int main(void)
{
    Fx f[3];
 
    f[0] = cos;
    f[1] = sin;
    f[2] = tan;
 
    printf("From 0 to pi/4:\n");
 
    printf("\t integ of cos = %g\n", integ(0, M_PI/4, f[0]));
    printf("\t integ of sin = %g\n", integ(0, M_PI/4, f[1]));
    printf("\t integ of tan = %g\n", integ(0, M_PI/4, f[2]));
 
    return 0;
}

脚注[編集]

  1. ^ Summit, Steve; 北野 欽一 (1996年2月26日). “C FAQ 4”. 4.12: 関数を呼ぶのに、ポインターを通す方法をみたことがある。どうなってるの。. 2008年10月14日閲覧。

関連項目[編集]

外部リンク[編集]