C言語ホーム > 関数へのポインタ前ページ次ページ
サイト内検索:

C言語での関数へのポインタについて

関数にもアドレスが割り当てられています。そのアドレスを格納するポインタが関数へのポインタです。C言語での関数へのポインタについて説明します。

関数へのポインタとは

関数は変数ではありませんが、変数と同様にアドレスが割り当てられています。このアドレスを格納するためのポインタが関数へのポインタです。関数へのポインタを利用してポインタが指している関数を実行することができます。

関数へのポインタは次の2つのケースでよく使用されます。

一つは関数をコールする際に、引数として関数へのポインタを渡し、呼び出した関数の中でポインタが指している関数を実行する、というケースです。

もう一つは関数へのポインタを配列に格納、テーブル化しておくことによりif文やswitch文の条件分岐等をなくしプログラムを簡素化する、というケースです。



関数へのポインタの宣言は次のように行います。


戻り値の型 (*ポインタ名)(引数リスト);

(*ポインタ名)の部分を関数名とみなしてみると、この宣言は関数のプロトタイプ宣言と同じ形であることがわかります。このことを意識すると宣言方法を覚えやすいでしょう。関数へのポインタの宣言時に指定されている戻り値や引数の型と個数は、関数へのポインタに格納する関数の戻り値や引数の型と個数と一致している必要があります。

具体的に例を書くとこうなります。fに戻り値がintでint型の引数を1つとる関数のアドレスが代入できます。


int (*f)(int n);

関数へのポインタを宣言する際には、あらかじめtypedefで新しい型名をつけておくと便利です。


typedef int (*MYFUNC)(int n);

このようにtypedefしておくと関数へのポインタの宣言を下記のように簡潔な表現にすることができます。


MYFUNC f;

関数へのポインタの使用例 その1

簡単な関数へのポインタの使用例を書いてみます。標準ライブラリのatexit()は指定の関数をプログラム終了時に呼び出すように登録する関数です。引数に登録したい関数へのポインタを指定します。


#include <stdio.h>
#include <stdlib.h>

/* atexit()に登録する関数のプロトタイプ宣言 */
void dispEnd(void);

int main(int argc, char *argv[])
{
	/* プログラム開始を表示 */
	printf("%s¥n", "Start");

	/*
	標準ライブラリのatexit()を使って
	プログラム終了時に実行する関数を登録

	#include <stdlib.h>
	int atexit(void (*関数)(void));

	atexit()は複数回呼ぶことも可.
	登録関数は登録順と逆順に呼び出される
	戻り値は成功の場合は0,成功以外は0以外の値.
	*/
	atexit(dispEnd);	/* 関数へのポインタを渡す */

	/* プログラム処理中を表示 */
	printf("%s¥n", "...");

	return 0;
}

void dispEnd(void)
{
	/* プログラム終了を表示 */
	printf("%s¥n", "End");
}

関数へのポインタの使用例 その2

もう一つ関数へのポインタの使用例を挙げておきます。コマンドラインから数値を引数として渡すとその数に関係のあることわざ・慣用句を表示するプログラムです。関数へのポインタを格納してあるテーブルを使用することによりswitch文を使用せずに分岐を実現しています。

<proverb.c  数に関係することわざを表示>

/*
	proverb.c
	指定の数に関係することわざ・慣用句を表示する
*/
/* インクルード */
#include <stdio.h>

/* プロトタイプ宣言 */
void proverb0(void);
void proverb1(void);
void proverb2(void);
void proverb3(void);
void proverb4(void);
void proverb5(void);
void proverb6(void);
void proverb7(void);
void proverb8(void);
void proverb9(void);
void proverbOthers(void);

/* typedef */
typedef void (*PROVERB_FUNC)(void);

int main(int argc, char *argv[])
{
	int n = 0;
	PROVERB_FUNC f[] = {
		proverb0, proverb1, proverb2, proverb3, proverb4, proverb5, 
		proverb6, proverb7, proverb8, proverb9, proverbOthers
	};

	/* 引数のチェック */
	if (argc != 2) {
		printf("Usage: %s <number> ¥n", argv[0]);
		return 0;
	}

	/* 引数をintに変換 */
	n = atoi(argv[1]);
	if ((n < 0) || (n > 9)) {
		n = 10;
	}

	/* 引数に対応する関数テーブル上の関数をコール */
	(*f[n])();

	return 0;
}

void proverb0(void)
{
	printf("%s¥n", "【零の数がつくことわざ・慣用句】");
	printf("%s¥n", "零零細細");
}

void proverb1(void)
{
	printf("%s¥n", "【一の数がつくことわざ・慣用句】");
	printf("%s¥n", "ローマは一日にして成らず");
	printf("%s¥n", "一を聞いて十¥を知る");
	printf("%s¥n", "一寸先は闇");
	printf("%s¥n", "一年の計は元旦にあり");
	printf("%s¥n", "一意専心");
	printf("%s¥n", "一朝一夕");
	printf("%s¥n", "一期一会");
	printf("%s¥n", "一石二鳥");
	printf("%s¥n", "一言居士");
	printf("%s¥n", "一長一短");
	printf("%s¥n", "一難去ってまた一難");
	printf("%s¥n", "一騎当千");
	printf("%s¥n", "大山鳴動して鼠一匹");
	printf("%s¥n", "氷山の一角");
	printf("%s¥n", "紅一点");
	printf("%s¥n", "間一髪");
	printf("%s¥n", "鶴の一声");
	printf("%s¥n", "一事が万事");
	printf("%s¥n", "十¥把一からげ");
	printf("%s¥n", "千載一遇");
	printf("%s¥n", "千里の道も一歩から");
	printf("%s¥n", "百害あって一利なし");
	printf("%s¥n", "百聞は一見に如かず");
}

void proverb2(void)
{
	printf("%s¥n", "【二の数がつくことわざ・慣用句】");
	printf("%s¥n", "一石二鳥");
	printf("%s¥n", "二枚舌を使う");
	printf("%s¥n", "二番煎じ");
	printf("%s¥n", "二足のわらじ");
	printf("%s¥n", "二階から目薬");
	printf("%s¥n", "人を呪わば穴二つ");
	printf("%s¥n", "瓜二つ");
	printf("%s¥n", "青二才");
}

void proverb3(void)
{
	printf("%s¥n", "【三の数がつくことわざ・慣用句】");
	printf("%s¥n", "三度目の正直");
	printf("%s¥n", "三日坊主");
	printf("%s¥n", "三顧の礼");
	printf("%s¥n", "仏の顔も三度まで");
	printf("%s¥n", "早起きは三文の徳");
	printf("%s¥n", "朝三暮四");
	printf("%s¥n", "石の上にも三年");
}

void proverb4(void)
{
	printf("%s¥n", "【四の数がつくことわざ・慣用句】");
	printf("%s¥n", "四苦八苦");
	printf("%s¥n", "四面楚歌");
	printf("%s¥n", "朝三暮四");
}

void proverb5(void)
{
	printf("%s¥n", "【五の数がつくことわざ・慣用句】");
	printf("%s¥n", "一寸の虫にも五分の魂");
	printf("%s¥n", "五里霧中");
}

void proverb6(void)
{
	printf("%s¥n", "【六の数がつくことわざ・慣用句】");
	printf("%s¥n", "六一銀行");
	printf("%s¥n", "六根清浄");
	printf("%s¥n", "総領の甚六");
}

void proverb7(void)
{
	printf("%s¥n", "【七の数がつくことわざ・慣用句】");
	printf("%s¥n", "なくて七癖");
	printf("%s¥n", "七転び八起き");
	printf("%s¥n", "七転八倒");
	printf("%s¥n", "親の七光り");
}

void proverb8(void)
{
	printf("%s¥n", "【八の数がつくことわざ・慣用句】");
	printf("%s¥n", "七転び八起き");
	printf("%s¥n", "八つ当たり");
	printf("%s¥n", "八方美人");
	printf("%s¥n", "八面六臂");
	printf("%s¥n", "口八丁手八丁");
	printf("%s¥n", "四苦八苦");
	printf("%s¥n", "岡目八目");
	printf("%s¥n", "当るも八卦当らぬも八卦");
	printf("%s¥n", "村八分");
	printf("%s¥n", "胸突き八丁");
}

void proverb9(void)
{
	printf("%s¥n", "【九の数がつくことわざ・慣用句】");
	printf("%s¥n", "九死に一生を得る");
	printf("%s¥n", "九牛の一毛");
}

void proverbOthers(void)
{
	printf("%s¥n", "【数のつくことわざ・慣用句(その他)】");
	printf("%s¥n", "かわいさ余って憎さ百倍");
	printf("%s¥n", "一を聞いて十¥を知る");
	printf("%s¥n", "一事が万事");
	printf("%s¥n", "五十¥歩百歩");
	printf("%s¥n", "人の噂¥も七十¥五日");
	printf("%s¥n", "六十¥の手習い");
	printf("%s¥n", "十¥人十¥色");
	printf("%s¥n", "十¥把一からげ");
	printf("%s¥n", "千載一遇");
	printf("%s¥n", "千里の道も一歩から");
	printf("%s¥n", "悪事千里を走る");
	printf("%s¥n", "百害あって一利なし");
	printf("%s¥n", "百聞は一見に如かず");
	printf("%s¥n", "百里の道は九十¥里が半ば");
	printf("%s¥n", "雀百まで踊り忘れず");
	printf("%s¥n", "鶴は千年亀は万年");
}

下記のように文字列の中に¥が記述されている箇所があります。これは漢字に対応していないコンパイラのワーニングを回避するためのものです。不要ならば取り除いてください。


printf("%s¥n", "一を聞いて十¥を知る");
C言語ホーム > 関数へのポインタ前ページ次ページ
© 2009 C言語サイト管理人