関数ポインタについて
関数ポインタ(Function Pointer)は、コードメモリ上の関数のアドレスを格納するための変数です。これを利用することで、プログラムの実行時に動的に呼び出す関数を切り替えることが可能になります。主にコールバック処理やイベント駆動型の設計、あるいは関数テーブル(ジャンプテーブル)の実装において非常に重要な役割を果たします。
実装手順
- 宣言: ポインタが指し示す対象となる関数と同じ戻り値型および引数リストを持つポインタ型を定義します。
- 初期化: 関数ポインタ変数に、具体的な関数のアドレス(関数名)を代入します。
- 呼び出し: 通常の関数と同様の構文で、ポインタを通じて関数を実行します。
サンプルコード
以下の例では、数値の2乗と3乗を計算する関数を定義し、関数ポインタを使って動的に呼び分けています。
#include <stdio.h>
// 2乗を計算する関数
int compute_square(int val) {
return val * val;
}
// 3乗を計算する関数
int compute_cube(int val) {
return val * val * val;
}
/* 関数ポインタの宣言
* int型の引数を1つ取り、int型を返す関数を指すポインタ 'algorithm' を宣言
*/
int (*algorithm)(int);
int main() {
int input = 3;
// 関数ポインタに compute_square のアドレスを代入
algorithm = compute_square;
printf("2乗の結果: %d\n", algorithm(input));
// 関数ポインタを compute_cube に切り替え
algorithm = compute_cube;
printf("3乗の結果: %d\n", (*algorithm)(input)); // 間接参照演算子を使った呼び出しも可能
return 0;
}
実行結果:
2乗の結果: 9
3乗の結果: 27
関数ポインタを返す関数について
ここで解説する「関数ポインタを返す関数」は、その実行結果として別の関数へのポインタを返す関数です。これにより、関数内部のロジックや条件に基づいて、動的に適切な処理(関数)を選択して返却することができます。戦略パターン(Strategy Pattern)の実装や、状態に応じた処理の振り分けに利用されます。
構文の詳細
戻り値が関数ポインタであるため、宣言の構文は少し複雑になります。戻り値型 (*関数名(引数))(引数) のように記述し、外側の括弧が関数名とその引数を、内側のアスタリスクを含む括弧が「ポインタであること」および「返される関数のシグネチャ」を示します。
サンプルコード
以下の例では、引数に応じて異なる計算ロジック(2乗または3乗)を返す関数 get_strategy を定義しています。
#include <stdio.h>
int compute_square(int val) {
return val * val;
}
int compute_cube(int val) {
return val * val * val;
}
/* 関数ポインタを返す関数の宣言
* 引数 'mode' に基づいて、適切な計算関数へのポインタを返す
*/
int (*get_strategy(int mode))(int) {
if (mode == 0) {
return compute_square;
} else {
return compute_cube;
}
}
int main() {
// 戻り値を受け取るための関数ポインタ変数
int (*math_operation)(int);
// モード0で取得(2乗を返す)
math_operation = get_strategy(0);
printf("モード0の計算結果: %d\n", math_operation(4));
// モード1で取得(3乗を返す)
math_operation = get_strategy(1);
printf("モード1の計算結果: %d\n", math_operation(4));
return 0;
}
実行結果:
モード0の計算結果: 16
モード1の計算結果: 64
まとめ
関数ポインタは関数のアドレスを保持し、実行時に関数を選択する仕組みを提供します。対して、関数ポインタを返す関数は、関数内の条件判定結果に基づいて、呼び出し元へ適切な関数ポインタを動的に提供する仕組みです。これら2つの概念を組み合わせることで、C言語においても柔軟な動的呼び出しや関数ポインタ配列などを用いた高度な制御フローを実現できます。