Page 23 関数ポインタ

関数ポインタとは 「int* foo()」といったもの返り値がポインタの関数ではありません。定義したポインタに関数を入れるという、大胆な方法です。使用例を見た方が早いので、下の例を見てみましょう。

#include <stdio.h>

int sub(){
	printf("A\n");
	return 0;
}

int main(){
	int (*func)();  /* 関数ポインタの宣言 */
	func = sub;     /* funcにsubをセットする */
	func();         /* funcを実行するとsubが実行される */
	return 0;
}

関数ポインタ宣言時の書き方に注意してください。ポインタをカッコで囲むところがポイントです。

型 (*関数ポインタ名)(引数...)

関数ポインタには型、引数の一致する任意の関数をセットできます。セットするときは、関数名をそのまま指定すればOKです。

上の例では、funcにsubがセットされているので、funcを呼ぶと、subが呼ばれます。

これだけだと、使い道がよくわからないので、もう少し例を見てみましょう。

構造体配列とともに

入力した値によって、呼び出す関数を変えるプログラムを作ります。まずは、関数ポインタを使わずに。

#include <stdio.h>

void func1(){
	printf("A\n");
}

void func2(){
	printf("B\n");
}

void func3(){
	printf("C\n");
}

int main(){
	char c[10];
	fgets(c, sizeof(c), stdin);
	switch(c[0]){
	case '1':
		func1();
		break;
	case '2':
		func2();
		break;
	case '3':
		func3();
		break;
	default:
		break;
	}
	return 0;
}

関数ポインタを使うとこの様にかけます。

#include <stdio.h>

void func1(){
	printf("A\n");
}

void func2(){
	printf("B\n");
}

void func3(){
	printf("C\n");
}

int main(){
	struct tagX {
		char key;
		void (*func)();
	} stX[] = { {'1', func1}, {'2', func2}, {'3', func3} };
	char c[10];
	int i;
	fgets(c, sizeof(c), stdin);
	for(i = 0; i < sizeof(stX)/sizeof(tagX); i++){
		if(c[0] == stX[i].key){
			stX[i].func();
			break;
		}
	}
	return 0;
}

関数の引数に関数をセットする

呼び出した関数の中で引数にセットした関数を呼び出します。

#include <stdio.h>

void func1(void (*func)(int)){ /* 引数に関数ポインタを指定 */
	func(1);
	func(3);
}

void func_A(int a){
	printf("%d",a);
}

void func_B(int a){
	printf("%d", a*2);
}

int main(){
	func1(func_A);
	func1(func_B);
	return 0;
}

関数ポインタなしで書くと、func1から値を取得→func_A、func_Bに代入、という流れになります。(当然func1はvoid型のままでは無理です。)

#include <stdio.h>

int func1(){
	return 1;
}

int func2(){
	return 3;
}

void func_A(int a){
	printf("%d",a);
}

void func_B(int a){
	printf("%d", a*2);
}

int main(){
	int i;
	/* func_A(func1())などという書き方もできるが、
		関数ポインタとの違いを明確にするため、この様な形にした。 */
	i = func1();
	func_A(i);	
	i = func2();
	func_A(i);	
	i = func1();
	func_B(i);
	i = func2();
	func_B(i);
	return 0;
}

関数ポインタは慣れないと使いどころが難しいですが、うまく使えばスマートなプログラミングが出きるようになりますので、いろいろやってみましょう。

戻る