この記事では,関数ポインタの基礎的な使い方について解説したいと思います.
関数もアドレスを持っている##
関数も変数と同じようにメモリ領域に保存されているので,アドレスを持っています.
まずは,そのことを確かめてみます.
# include <stdio.h>
int main(void){
printf("%p\n", main);
return 0;
}
0x563c3dc4c64a
実行結果は環境によって異なりますが,関数名が関数のアドレスを表していることがわかりました.
関数ポインタの宣言##
関数ポインタは以下のように宣言することが出来ます.
戻り値の型 (*ポインタ変数名)(引数情報);
これだけではよくわからないと思うので,例を見てみましょう.
例えば,2つの整数の内,大きい方の整数を返す関数int max(int, int);
を保持するポインタp_func
の宣言をしてみます.
int (*p_func)(int, int);
関数ポインタの使い方##
まず,関数ポインタへ関数のアドレスを代入します.最初に確認したように,関数名が関数のアドレスを表しているので以下のように代入を行えます.
p_func = max; //ポインタ変数名 = 関数名
次に,関数の呼び出しです.
(*p_func)(3, 5);
関数ポインタを間接参照することによって,p_func
に代入されている関数max
を呼び出すことができます.
もっと簡単に呼び出すこともできます.
p_func(3, 5);
1つめの呼び出し方の方がポインタを使っている感じはしますが,こちらの方が簡単でいいですね.
まとめ##
ここまでに説明したものをまとめたものが以下のプログラムになります.
# include <stdio.h>
int max(int a, int b){
int max = a;
if (max < b)
max = b;
return max;
}
int main(void){
int (*p_func)(int, int);
p_func = max;
printf("(1)(*p_func)(3, 5) = %d\n", (*p_func)(3, 5)); //(1)
printf("(2)p_func(3, 5) = %d\n", p_func(3, 5)); //(2)
}
(1)(*p_func)(3, 5) = 5
(2)p_func(3, 5) = 5
おまけ(関数ポインタと配列)##
関数ポインタは配列と組み合わせて使用されることが多いです.if文やswitch文などの処理分岐をする必要がなくなり,簡潔にプログラムを書けるようになることがあるからです.
以下のようにすると,関数ポインタの配列を宣言できます.
戻り値の型 (*ポインタ変数名[配列の要素数])(引数情報);
先ほどの例で言うと,次のようにします.
int (*p_func[2])(int, int);
同じ戻り値の型,引数の関数しか格納できませんが,それぞれの要素に関数のアドレスを格納して使います.
最後に例を示しておきます.
# include <stdio.h>
int max(int a, int b){
int max = a;
if (max < b)
max = b;
return max;
}
int min(int a, int b){
int min = a;
if (min > b)
min = b;
return min;
}
int main(void){
int (*p_func[2])(int, int);
p_func[0] = max;
p_func[1] = min;
for (int i = 0; i < 2; i++)
printf("p_func[%d](3, 5) = %d\n", i, p_func[i](3, 5));
}
p_func[0](3, 5) = 5 //maxが呼び出されている
p_func[1](3, 5) = 3 //minが呼び出されている