一週間で身につくC言語の基本

おさえておきたいプログラミングの基本

【応用編:3日目】 ポインタと配列

3-1.関数ポインタ

(1) 関数ポインタとは

ポインタとして保持できるのは、何も変数だけではありません。関数もまた、ポインタとして利用できます。これを、関数ポインタと言います。実際に、簡単なサンプルを見てみましょう。

listex3-fp-1:main.c
#include <stdio.h>

// 関数のプロトタイプ宣言
void func1();
void func2();

int main(int argc,char** argv){
    void (*fp)() = func1;	//	関数ポインタをfunc1で初期化
	fp();	//	関数fpを実行
	fp = func2;
	fp();	//	関数fpを実行
    return 0;
}

//	関数1
void func1(){
	printf("func1\n");
}

//	関数2
void func2() {
	printf("func2\n");
}
実行結果
func1 func2

このプログラムの8行目で定義されている、fpが、関数のポインタです。関数のポインタの書式は、以下の通りになっています。

期待される実行結果の例 関数ポインタの書式
型名 (*変数名)(引数)

という形になります。ここで用いている、func1()および、func2()は、戻り値の型がvoidであり、引数がないので、()無いが空白で、変数名がfpであることから、void (*fp)と宣言します。

型の定義の仕方こそ特殊ですが、関数ポインタも、ポインタ変数の一種です。ただ、そこに代入するのはあくまでも関数です。

関数ポインタが代入された変数は関数として扱うことが出来、関数名(引数)の組み合わせで呼び出すことができます。

関数ポインタで関数を実行する
fp();

この時実行されるのは、fpに代入された関数です。


(2) 引数のある関数の場合

続いて、関数に引数がある場合のケースを見てみましょう。以下のサンプルを実行してみてください。

listex3-fp-2:main.c
#include <stdio.h>

// 引数のある関数ポインタ
int max(int,int);
int min(int,int);

int main(int argc,char** args){
    int (*cmp)(int,int) = max;	//	cmpの初期化と(max)
	int a = 1,b = 2;
	printf("%dと%dのうち、最大のものは、%d\n",a,b,cmp(a,b));
	cmp = min;	//	cmpにminを代入
	printf("%dと%dのうち、最小のものは、%d\n",a,b,cmp(a,b));
    return 0;
}

//	最大値を返す関数
int max(int m,int n)
{
	if(m > n){
		return m;
	}
	return n;
}

//	最小値を返す関数
int min(int m,int n)
{
	if(m < n){
		return m;
	}
	return n;
}
実行結果
1と2のうち、最大のものは、2 1と2のうち、最小のものは、1

ここで宣言されている2つの関数min、maxはともに引数として2つの整数、戻り値の型がintです。そのため、以下のように宣言された変数に代入することが可能です。(8行目)

関数ポインタ変数の宣言
int (*cmp)(int,int) = max;

変数cmpには、初期値としてmac関数のポインタが代入されていますが、同じ引数の組み合わせ、同じ戻り値の型の関数minのポインタを代入できます。(11行目)

(3) 関数の引数として関数ポインタを渡す

続いて、さらに高度な使い方を見てみましょう。関数ポインタは、さらに、他のポインタ同様、関数の引数として渡すことも可能です。ためしに、以下のサンプルを実行してみてください。

listex3-fp-3:main.c
#include <stdio.h>

//	関数ポインタを引数としてとる関数
void funcp(int (*)(int),int n);
//	関数ポインタに用いる関数
int dbl(int);
int hlf(int);

int main(int argc,char** args){
	funcp(dbl,8);	//	引数として、関数を渡す
	funcp(hlf,8);	//	引数として、関数を渡す
    return 0;
}

void funcp(int (*f)(int),int n){
	printf("引数:%d 結果%d¥n",n,f(n));
}

//	最大値を返す関数
int dbl(int n){
	return n * 2;
}
int hlf(int n){
	return n / 2;
}
実行結果
引数 8 : 結果16 引数 8 : 結果4

4行目で、関数ポインタを引数として持つ関数、funcp()のプロトタイプ宣言をしています。プロトタイプ宣言の中で、関数ポインタを宣言するときは、以下のようになります。

引数内での関数ポインタの書式
型名 (*)(引数)

普通の引数と同様、関数ポインタの宣言から、変数名を抜いた形にすればよいことがわかります。関数名は、対応する関数の定義の中で記述します。15行目)

このサンプルでは、この引数として、関数dblおよび、hlfを与えています。引数として与えられた関数は17行目で実行されていますが。関数が違えば、当然のことながら実行結果は違ってきます。

このように、関数ポインタは、呼び出す関数を動的に変更する時に非常に便利です。


応用編3日目のメインページに戻る

練習問題 : 問題3.

一週間で学べるコースの一覧
Udemy
...
2024/10/01

Udemyでも学びましょう!

一週間でわかるC言語・C++言語がオンライン講座になりました!動画音声によってさらにわかりやすくなりました!! 1講座で2つの言語を学ぶことができる上に、練習問題の回答もダウンロードできます。

Read →
Impress一週間シリーズ
1週間でC言語の基礎が学べる本
2024/10/01

書籍化された一週間シリーズ

本講座が「1週間でC言語の基礎が学べる本」として書籍化されました!サイトの内容プラスアルファでより学習しやすくなっています!Impressより発売中です!!

Read →
Impress一週間シリーズ
...
2024/10/01

書籍化された一週間シリーズ

一週間シリーズは書籍化されています。こちらもどうぞ!

Read →
プログラマーなら欲しいグッズ
プログラミンググッズ

プログラミンググッズ

快適なプログラミング環境を構築したい人々にぜひとも揃えてほしいグッズです。

Read →
制作・管理
シフトシステム株式会社

シフトシステム株式会社

このサイトはシフトシステム株式会社によって制作・管理がなされています。

Read →