• ベストアンサー

関数ポインタの利点

こんにちは。 C言語初心者ですが今勉強中です。 その中でポインタについては理解できたのですが、 関数ポインタの利点、使うべき所などが理解できません。 ポインタの基本は理解しています。 値渡し、アドレス渡しも理解しています。 関数ポインタを使うと何がいい、またはどんなとき使わなければならないのか 教本を読んでいてもさっぱりわかりません。 サンプルプログラムを打っても何のために使ってるのかわからないです。 どなたか教えていただけませんでしょうか? よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

実際に関数へのポインタを使用している事例を調べるのが一番手っ取り早いと思います。 標準関数だけでも、atexit、bsearch、qsort、signalが関数へのポインタを使用しています。一度、触ってみるとよいでしょう。 ところで、余談かもしれませんが、関数へのポインタがなければ関数を呼び出すことができません。 関数呼出し演算子(括弧演算子)がオペランドとして要求するのは、関数型ではなく、関数へのポインタ型だからです。すなわち、 voif func(void); func(); のようにfuncを呼び出す場合でも、funcは関数へのポインタ型(ここではvoid(*)(void)型)に暗黙的に型変換され、関数呼出し演算子のオペランドになっているわけです。

その他の回答 (5)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.6

これまでの回答で、ほぼ出揃ったと思いますが、要約すると、 ・(広い意味で)コールバックとして使用する。 ・関数テーブルとして使用する。 というのが一般的な使い方です。 コールバックは、特定の状況に対するハンドラを設定するために使用することが大多数です。 関数テーブルは、例えばswitch文の代わりに、処理を表引きさせたい場合などに有効です。特に、switch文では、データと処理の関係を動的に変更できませんが、関数テーブルであれば、どのようにでもできます。 テーブルを引き当てるのは、何も連番でなくてもよいわけで、文字列等を使って連想配列にすることも可能です。 標準関数のatexitやsignalは、上記の2つをあわせた特徴を持っています。ユーザーには見えませんが、これらの関数は、内部的に関数テーブルを管理しているのです。 C++では、関数へのポインタから一歩進んで、関数オブジェクト(あるいはファンクタ)というものを使いますが、これはどちらかというとコールバック的な概念です。

  • linus1974
  • ベストアンサー率19% (71/370)
回答No.5

そうですねえ。gtk+のイベントなんか参考に なりますかね。 極論をいうとライブラリやフレームワークを 作る人のためのものじゃないかと思います。 一般のソフト開発ではほとんどつかわないですね。 私が知っているのは、 組込み系でC++で開発したいけど、そのマイコン のコンパイラはCしかないとき、オブジェクト 指向のポリモーフィズムを 関数ポインタで解決することはあります。

  • FAY
  • ベストアンサー率49% (95/193)
回答No.4

あとはダイナミックリンクライブラリ内でエクスポートされた 関数のアドレスを取得するGetProcAddress()なども 関数のアドレスを戻り値として返すので これを関数ポインタで受け取ったりします。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

#1でも挙げられていますが、 例えば、qsort の様な汎用のソート関数の場合、 例えば、構造体のような汎用なデータを比較する必要があるわけですが、そのどの部分で比較すればいいのかわかりませんから、その手順としての(比較)関数を渡して使うというようなコトがあります。 あと、例えばFORTHのような処理系を作成することを考えると、 FORTHはいってみれば関数呼び出しの固まりみたいなものなんですが、このようなインタプリタについては、呼び出す関数が実行時でないと決まらないので、関数名で関数の呼び出しができません。 そのような場合に関数のポインタを使って関数を呼び出します。

  • peko_pee
  • ベストアンサー率53% (45/84)
回答No.2

ちょっと高度な用法ですが、関数ポインタを Type (*func[ ])(.....) = { func0, func1, func2, .... }; のように配列にしておくと func[ ](.....); の [ ] 内の数値を変えるだけで呼び出す 関数を変えられるという使い方ができます。 逆に、複数の関数に同じ引数を与えるような処理をしたい場合も上のように配列に なっていると、 for (i = 0; i < XX ; i++) func[i](.....); と記述できます。 呼び出す関数が3つ4つなら if 文でも呼び分けられますが、多くなればなるほど こういう形にせざるを得ないと思います。 関数ポインタは標準関数の引数として必要になることはもちろんですが、実際に プログラムを作るときには単独よりも配列で使うことのほうが多いのではないかな という気がします。

関連するQ&A

  • 関数へのポインタ

    超初心者です。 C言語を使ってsin波を生成して音を鳴らそうとしているのですが・・ネットで調べてもよくワカリマセン・・ 超初心者な私でも理解できるようなサイトを教えて下さい. また、関数へのポインタも勉強しているのですが, char *(*func)(void); といったchar 型へのポインタを返す関数へのポインタというのがあったとして,関数へのポインタは理解できたのですがさらにchar 型へのポインタとなると一体これが何を指しているのかさっぱりで・・・・ ご協力お願いします.

  • 関数へのポインタ渡しでの配列の初期化について

    はじめまして、C言語の基本的な質問をさせてください。 C言語で、外部関数へポインタで引数を渡す場合に、 関数に渡されるのはアドレスですよね? で、渡された関数側でそのポインタの配列の初期化を するときにはアドレスだけの情報だと、要素数がいくつ あるか分からず、領域の破壊をしてしまいそうな気が するのですが?いかがでしょうか? また、関数かなんかで、配列の要素数が分かる関数が あったような気がするのですが、それもアドレスだけ でわかるのでしょうか?

  • ポインタについての良いテキストを探しています。

    ポインタ完全制覇、秘伝問答ポインタ編は読了しました。 しかし、ダブルポインタ(便宜上こう書きますが、ポインタのポインタのことです)や トリプルポインタが出てくると、いきなり分からなくなってしまいます。 アドレスと値の関係を図解してみても、なぜこんな風にする必要があるのだろう?その必然性は? となってしまい、本質的な理解ができていないと感じています。 関数に渡すときの値渡しと参照渡しについては理解できているつもりです。 ですが、それに、構造体や、構造体のメンバーに文字列がある場合、mallocなどが関わってくると ゴチャゴチャになっていきなり分からなくなってしまいます。 上記の本は、文字列と配列とポインタあたりは解説してあり、そのあたりは理解しているつもりなのですが、ダブルポインタやトリプルポインタについては明確な記載がありません。 以前の質問で、 http://okwave.jp/qa/q6478987.html >3次元の構造を持つなら 3次元配列が必要であり, それを動的に確保しようとしたら「ポインタのポインタのポインタ」は自然な発想だと思う. とご回答を頂いたことがあるのですが、"自然に"だけでなくじっくり考えても理解できていません。 その他のご回答もなぜそのような状況でそのようなポインタの使い方が必要になるのかなど理解出来ないところが多いです。 基礎が大事だというのは十分理解しているつもりですが、 基礎だけでなく、その上のレベルでのポインタの解説や勉強に役立つテキストを教えてください。 なにとぞよろしくお願いいたします。 また、所要のため土日はネットに繋ぐことができませんのでお返事が遅れることをご了承ください。

  • ポインタによる関数への配列渡し

    林晴比古さんの「新C言語入門」でC言語を勉強している初心者です。 現在ポインタの勉強をしています。色々教科書の文例等をポインタで書くとどうなるか試しております。 上書P200練習問題2に「配列の最大値を返す(その際配列の長さを渡す)」プログラムがあり、それをポインタで渡すプログラムに直してみました。 仮引数に「maxdata」を設定し、そのアドレスを関数側に渡し、関数側ではポインタとして受け取る(そうすれば関数側からはreturnで値を返す必要がない)、と考え、下記のように書いてみました。 #include <stdio.h> void max_of_array(int n[], int len, int *ans); int main(void) { int dt[6] = {50,20,80,30,10,40}; int maxdata; max_of_array(dt,6,&maxdata); printf("最大値=%d\n", maxdata); return 0; } void max_of_array(int n[], int len, int *ans) { int i; ans = &n[0]; for (i=1; i<len; i++){ if (*ans < n[i]) *ans = n[i]; } } しかしコンパイルすると、何故か「最大値=1」となってしまいます。(正しくは80です) 他にも色々試してみましたがうまくいかず、かなり考えてみたのですがどうしても分かりません。お分かりの方、どうすれば正しくなるのが教えてください、よろしくお願いします。

  • 関数ポインタについて

    C言語によるUNIXシステムにプログラミング入門という本を読みながらC言語を勉強しています。 しかし、サンプルとして提示された下記の内容の意味がわかりません。 分からない箇所が「関数ポインタ」と呼ばれるものがついているということが分かった程度で、どういう意図で記述されているのかがわかりません。 分からないプログラムの処理内容は、ファイル内のデータを16進数で表示するというものです。 分からない箇所を記します。 #include <stdio.h> #define BUFF 17 /*buffer*/ #define ERR -1 /*system call error*/ void usage(void); /*put usage message*/ char *command_name /*command name*/ FILE *fpin; /*file pointer*/ main(int argc,char *argv[ ]){ char *rindex(const char*s,int c); /*末尾から文字列検索*/ void hexdump(void); ... ... } void hexdump(void){ ... ... } void usage(){ ... ... } 不明なのは、main関数の中の char *rindex(const char*s,int c); /*末尾から文字列検索*/ void hexdump(void); です。 Cについて、不明なところが多いので、利用する関数は使う前に宣言しなければいけない程度の理解ですが、そうだとしてもusageメソッドはmain関数の外であるのに、rindexとhexdumpは何故main関数の中で宣言されているのでしょうか。 上記の不明点とは別で、rindexの前にポインタが付いていると思うのですが、hexdumpやusageにはついていません。 知人からは、関数までのポインタを返すとのことでしたが、用途もいまいち理解できません。 全てではなくてもいいので、ヒントをいただけるとうれしいです。 よろしくお願いします。

  • C#で、Cのファイルポインタ(?)のような機能

    プログラムの初心者、かつ、C#の初心者です。  C言語では、ファイルポインタを関数から関数へ渡すことができると思うのですが、C# ではどのようにすれば良いのですか? C#を使っていますが、C言語のような構造でプログラムを書いています。  やりたいことは、ファイルポインタを渡しながら、各関数で、ドカドカと計算結果をファイル内に書いていくということです。  宜しくお願いいたします。

  • 関数へのポインタ渡し

    下位関数へポインタのアドレスを渡して(器を渡して) 内容を設定してもらうというのは、よくやることと おもいます。 そのポインタの領域は、普通は上位関数で実体を確保する と思っていたのですが、下位関数での実体確保することは 可能なのでしょうか? 対象はc言語です。 宜しく御願い致します。

  • C言語のポインタとスタックポインタ

    プログラム始めて1ヶ月の初心者です。 C言語のポインタとスタックポインタというのは同じなのでしょうか。 スタックポインタの考えは大体理解出来たのですが C言語のポインタとなるとコードを見てもサッパリ分かりません。 ネットで調べても出てこなかったのでどなたか教えて下さい。 よろしくお願いします。

  • 【なぜポインタを使うのか】

    私は、ポインタのメリット・デメリットを以下のように考えています。 ◆メリット メモリを多く確保しなければならないオブジェクトについて、コピー処理を行うことなく省メモリでインタフェースできる。 ◆デメリット ・関数内でしか使用しない非ポインタのローカル変数に比べ、  アクセス可能な場所が多くなってしまい、色んな箇所から値が変更されうる。(影響範囲の限定がしずらい) ・可読性が低くなる。(若いエンジニアはCの経験者は少なくっていくと思われるため、保守コストが若干割高になる) そのため、よっぽどメモリを多く使うようなオブジェクトでなければ、 (もしくは速度を重視する必要があるプログラムでなければ) 値渡しにしても良いのではと考えています。 しかし、度々目にするソースは、何でもかんでもポインタで処理しているものも多々見受けられます。 特に、int型のようなメモリを大量に使用しないものでも、ポインタで変数宣言しているケースもよく見ます。 なぜなのでしょうか? (熟練のC言語プログラマが、昔ながらの記述を踏襲しているというのはあるのかなと考えていますが)

  • アドレスとポインタがどうしても理解できない

    C言語を独学しているのですが、どの参考書読んでも、アドレスとポインタの理解ができません。アドレスとポインタを使わなくても別に開発できるのではないかと思います。どなたか、アドレスとポインタを初心者でも分かるように分かりやすく教えて頂けないでしょうか?