C言語には関数ポインタという関数への場所を指し示すポインタがあります。この関数ポインタの書き方(使い方)を忘れてしまうので、サンプルコードを載せておきます。使い方はコードを見ながら説明してみます。
コピペするなら、以下を使ってください。
#include <stdio.h>
/* 関数宣言 */
int func( int a, int b );
int main( void )
{
/* 関数ポインタ「funcptr」の宣言 */
int (*funcptr)(int, int);
/* 関数ポインタへの代入 */
funcptr = func;
/* 関数ポインタから関数の実行 */
printf("関数func()の戻り値:%d\n", (*funcptr)( 3, 4 ) );
return 0;
}
int func( int a, int b )
{
return( a * b );
}
main関数から整数の「3」と「4」をfunc関数に渡して、func関数では「3×4」の結果をmain関数に返しています。実行結果は「関数func()の戻り値:12」と画面に表示されます。
まず最初に、関数へのポインタを格納する変数を「funcptr」として宣言しています。func関数は2つのint型の変数を引数に取り、戻り値がint型の関数です。この関数へのポインタ宣言は以下となります。
int (*funcptr)(int, int);
あくまでポインタ変数の宣言であるためfuncptrの前には「*(アスタリスク)」が必要です。またfuncptrをカッコで囲っていますが、このカッコも必要です。もしカッコがなかった場合、
int *funcptr(int, int);
となりますが、これはfuncptrが2つのintを引数にしてintのポインタを返す「関数」ということになってしまいますので。
次に、関数ポインタに関数へのアドレスを代入します。それが以下となります。
funcptr = func;
ここで注意すべきはfuncにカッコがないことです。つまり「funcptr = func();」としてはダメです。もしfuncにカッコがあるとfunc関数の呼び出しが行われてしまうからです。またfunc関数の前に「&演算子」がないことにも気をつけましょう。関数の末尾にカッコをつけない形で関数を参照する場合、コンパイラは「その関数のアドレスを参照する」となっているためです。
最後に、関数ポインタが指し示すアドレスの関数を実行します。コード上では以下の部分です。
printf(“関数func()の戻り値:%d\n”, (*funcptr)( 3, 4 ) );
「(*funcptr)( 3, 4 )」の戻り値をprintf関数で印字しています。funcptrの前の「*(アスタリスク)」はポインタが指し示すオブジェクト(この場合は関数)にアクセスしなければならないため必要です。またfuncptrを囲むカッコも必要です。
ちなみに別の書き方として、以下でもコンパイルは通ります(gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)の場合)。
printf(“関数func()の戻り値:%d\n”, funcptr( 3, 4 ) );
こちらのほうが直感的にはわかりやすいかもしれません。どちらを使うかは、好みの問題でしょうか。
– – – – – – – – – –
追記しました。「ポインタを返す関数」への関数ポインタを使ったサンプルも載せておきます。
コピペするなら、以下を使ってください。
#include <stdio.h>
#include <string.h>
/* 関数宣言 */
char *func( char *c );
/* 外部変数 */
char message[100] = "Hello world. ";
int main( void )
{
/* 関数ポインタ「funcptr」の宣言 */
char *(*funcptr)(char *);
/* 関数ポインタへの代入 */
funcptr = func;
/* messageの出力 */
printf("%s\n", message );
/* 関数ポインタからmessageの書き換え */
printf("%s\n", (*funcptr)("HELLO WORLD!") );
return 0;
}
char *func( char *c )
{
strcat( message, c );
return message;
}
実行結果は以下となります。
$ ./a.out
Hello world.
Hello world. HELLO WORLD!
1つ目のサンプルコードとの違いは、関数ポインタの宣言の際に「*(アスタリスク)」がもう一つ付くことです(charのポインタを返す関数ということを示すため)。
char *(*funcptr)(char *);
関数ポインタへの代入や、関数ポインタからの関数の実行の仕方は同じになります。