関数ポインタとは、関数のアドレスを格納するためのポインタ変数です。
ほとんどのコンピュータは、プログラムもデータもメインメモリ(主記憶装置)に配置され、CPUで実行されます。
メモリ上に配置されているということは、プログラムにもデータにもアドレスが割り当てられているはずです。
データ(変数など)のアドレスはポインタのところで色々と説明しました。
プログラムのアドレスも見てみましょう。
まずは、main関数のアドレスを表示してみます。
<sample program 174-01>
#include <stdio.h> int main(void) { printf("main = %p\n", main); return 0; } |
<実行結果>
main = 012C128F 続行するには何かキーを押してください・・・
※実行結果(アドレス部分)は毎回変わる可能性があります。
関数名のみを書くことで、その関数の先頭アドレスが表示出来ます。。
関数名に( )を付けることで、その関数を呼び出しているのです。
このまま、main関数内で
main() |
と書いてしまうと「スタックオーバーフロー」になりますので、別の関数を作ることにしましょう。
<sample program 174-02>
#include <stdio.h> void Hello(void); int main(void) { printf("Hello = %p\n", Hello); return 0; } void Hello(void) { printf("Hello\n"); } |
<実行結果>
Hello = 00D912FD 続行するには何かキーを押してください・・・
※実行結果(アドレス部分)は毎回変わる可能性があります。
Hello関数を作成し、アドレスを表示しました。
Hello関数は引数も戻り値もありません(どちらも void です)。
次のプログラムで、関数ポインタを使います。
<sample program 174-03>
#include <stdio.h> void Hello(void); int main(void) { void(*pHello)(void); printf("Hello = %p\n", Hello); pHello = Hello; printf("pHello = %p\n", pHello); return 0; } void Hello(void) { printf("Hello\n"); } |
<実行結果>
Hello = 011A12FD pHello = 011A12FD 続行するには何かキーを押してください・・・
※実行結果(アドレス部分)は毎回変わる可能性があります。
まずは関数ポインタの宣言についてです。
Hello関数は引数も戻り値も無し(どちらも void)と書きました。
void(*pHello)(void); |
宣言の先頭は「戻り値の型」です。
「*」の後ろが「関数ポインタ名」です。
※関数ポインタ名は、変数として使える名前であれば何でも良いです。
後ろの括弧に入っている部分が、「引数の型」です。
この関数ポインタには、
引数、戻り値がvoidである関数のアドレス
であれば、どんな関数のアドレスでも格納する事が出来ます。
それでは、関数ポインタ経由で関数を呼び出してみます。
アドレスの表示は消しますね。
<sample program 174-04>
#include <stdio.h>
void Hello(void);
int main(void)
{
void(*pHello)(void);
pHello = Hello;
pHello();
return 0;
}
void Hello(void)
{
printf("Hello\n");
}
|
<実行結果>
Hello 続行するには何かキーを押してください・・・
関数ポインタ名に( )を付ける事で、Hello関数を呼び出す事が出来ました。
上でも書きましたが、同じ戻り値、引数を持つ関数であれば、アドレスを格納することが出来ます。
<sample program 174-05>
#include <stdio.h> void Hello(void); void World(void); int main(void) { void(*pHello)(void); pHello = Hello; pHello(); pHello = World; pHello(); return 0; } void Hello(void) { printf("Hello\n"); } void World(void) { printf("World\n"); } |
<実行結果>
Hello World 続行するには何かキーを押してください・・・
関数ポインタpHelloに、新しく追加したWorld関数の先頭アドレスを格納し、呼び出しました。
特に問題なく、実行出来ています。
pHello(); |
と書いた時、関数ポインタにどの関数の先頭アドレスが入っているかで呼び出される関数を変えることが出来るのです。
これは、色々な場面で応用出来る考え方です。
応用編は次回以降に回すとして、基礎を最後まで書きましょう。
引数や戻り値がある場合の書き方を説明しておきます。
例えば、足し算をする Add関数を作ったとします。
プロトタイプ宣言は↓の通り。
int Add(const int lhs, const int rhs); |
戻り値の型は int型
引数の型は const int型 と const int型
このような場合、次のように関数ポインタを宣言して使います。
<sample program 174-06>
#include <stdio.h> int Add(const int lhs, const int rhs); int main(void) { int(*pAdd)(const int, const int); pAdd = Add; printf("4 + 3 = %d\n", pAdd(4, 3)); return 0; } int Add(const int lhs, const int rhs) { return lhs + rhs; } |
<実行結果>
4 + 3 = 7 続行するには何かキーを押してください・・・
戻り値の型、引数の型と数、これを元に宣言すれば良いだけです。
では、次回からは応用編ということで、関数ポインタを利用したプログラムを紹介します。