【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.22828

関数のポインタに関しまして
投稿者---ohyama(2005/08/26 15:53:20)


はじめまして、主にこのサイトでC言語の勉強をさせていただいている者で、いつもお世話になっております。

 このサイトでの学習を一通り追え、他の本でのソースを覗くとたまに以下のような、関数のポインタが出てきます。変数や配列、構造体を指すポインタは、他の本を併用することで、一応の理解をする事ができたのですが、以下のような関数を指すポインタの理解に只今苦しんでおります。

int * function()
{
...
}

どうか、ご教授の程、よろしくお願いいたします。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:関数のポインタに関しまして 22829 Blue 2005/08/26 15:57:13
<子記事> Re:関数のポインタに関しまして 22830 nop 2005/08/26 15:57:30


No.22829

Re:関数のポインタに関しまして
投稿者---Blue(2005/08/26 15:57:13)


> 関数を指すポインタ
ではありません。

int* 型の値を返す関数です。
考え方としてはint型や構造体をreturnするのと同じです。
# 若干気をつけなければならないこともあるが。。。



この投稿にコメントする

削除パスワード

No.22830

Re:関数のポインタに関しまして
投稿者---nop(2005/08/26 15:57:30)


>以下のような関数を指すポインタの理解に只今苦しんでおります。
>int * function()

これは関数ポインタではなく、
関数の戻り値が「int *」である、と言う事。

関数ポインタなら「int (*hoge)();」の様な宣言になる。


この投稿にコメントする

削除パスワード

No.22839

Re:関数のポインタに関しまして
投稿者---孝太郎(2005/08/27 01:26:30)


>関数の戻り値が「int *」である、と言う事。
int型のポインタ(アドレス)が返ってくるということ
でしょうか。
受け側としては、ポインタで待機していればいんでしょうか。
>
>関数ポインタなら「int (*hoge)();」の様な宣言になる。
どのような時につかうのですか。
サンプルなんか。



この投稿にコメントする

削除パスワード

No.22840

Re:関数のポインタに関しまして
投稿者---si(2005/08/27 01:43:37)


>>関数の戻り値が「int *」である、と言う事。
>int型のポインタ(アドレス)が返ってくるということ
>でしょうか。
>受け側としては、ポインタで待機していればいんでしょうか。

その通りです。(int配列を受け取る場合など)

>>関数ポインタなら「int (*hoge)();」の様な宣言になる。
>どのような時につかうのですか。
>サンプルなんか。

C を学ぶとき、最初に出会うサンプルが、sort でしょう。
(sort の comp,exch 関数を ポインタとして渡す)
sort(char *v[],int n,int (*comp)(),int (*exch)());


この投稿にコメントする

削除パスワード

No.22841

Re:関数のポインタに関しまして
投稿者---孝太郎(2005/08/27 02:44:35)


>C を学ぶとき、最初に出会うサンプルが、sort でしょう。
>(sort の comp,exch 関数を ポインタとして渡す)
>sort(char *v[],int n,int (*comp)(),int (*exch)());
そうですか。
見てないのですが、たぶん参考にした本の違いですか。
関数の配列なんですか。
int (*func[])() = { comp };

関数のポインタというのは何バイトなんですか。



この投稿にコメントする

削除パスワード

No.22842

Re:関数のポインタに関しまして
投稿者---επιστημη(2005/08/27 02:59:49)


>関数のポインタというのは何バイトなんですか。

訊くまでもないでしょう。やってみればいい。
printf("%d",sizeof(調べたいもの));




この投稿にコメントする

削除パスワード

No.22844

Re:関数のポインタに関しまして
投稿者---Blue(2005/08/27 03:07:25)


> 関数のポインタというのは何バイトなんですか。
sizeofで調べてみればどうでしょうか?
(おそらく環境依存)

以下は関数ポインタを使った一例です。
# 関数ポインタ以外のところは突っ込まないでください。

#include <stdio.h> int add( const int a, const int b ) { return a + b; } int sub( const int a, const int b ) { return a - b; } int mul( const int a, const int b ) { return a * b; } int div( const int a, const int b ) { return a / b; } int mod( const int a, const int b ) { return a % b; } typedef int ( *func )( const int, const int ); int main( void ) { func calc[] = { &add, &sub, &mul, &div, &mod }; const char* funcname = "addsubmuldivmod"; const int a = 10, b = 3; int i; printf( "a = %d, b = %d\n", a, b ); for ( i = 0; i < sizeof( calc ) / sizeof( func ); i++ ) { printf( "%.3s( a, b ) : %d\n", funcname + i * 3, calc[ i ]( a, b ) ); } return 0; }



この投稿にコメントする

削除パスワード

No.22846

Re:関数のポインタに関しまして
投稿者---Blue(2005/08/27 03:41:02)


>        printf( "%.3s( a, b ) : %d\n", funcname + i * 3, calc[ i ]( a, b ) );
なんか、違う気がしてきた。

calc[ i ]( a, b )じゃなくて( *clac[ i ] )( a, b )のほうが正しいですね。
コンパイル的に問題ないのは、代入時と同様になんか保管してくれるのかな。



この投稿にコメントする

削除パスワード

No.22847

Re:関数のポインタに関しまして
投稿者---かずま(2005/08/27 04:02:41)


> calc[ i ]( a, b )じゃなくて( *clac[ i ] )( a, b )のほうが正しいですね。
> コンパイル的に問題ないのは、代入時と同様になんか保管してくれるのかな。

コンパイルできるのは、どちらも正しいからです。

関数呼び出し演算子 ( ) は後置演算子で、その前にあるのがオペランドです。
そして、オペランドは「関数へのポインタ」でなければならないと、規格書に
記述されています。

calc[i] は「関数へのポインタ」ですから何も問題ありません。

それにひきかえ、*calc[i] は「関数へのポインタ」ではなく「関数」です。

しかし、関数型は、単項&演算子のオペランドである場合と sizeof演算子の
オペランドである場合を除いて、「関数へのポインタ」に変換されることに
なっています。

これは、配列型が、単項&演算子のオペランドである場合と sizeof演算子の
オペランドである場合を除いて、「配列の先頭要素へのポインタ」に変換さ
れることによく似ています。

ということで、「関数型」である *calc[i] は、「関数へのポインタ」に
暗黙のうちに変換され、関数呼び出し演算子 ( ) が適用されているのです。


この投稿にコメントする

削除パスワード

No.22850

Re:関数のポインタに関しまして
投稿者---かずま(2005/08/27 08:23:37)


> しかし、関数型は、単項&演算子のオペランドである場合と sizeof演算子の
> オペランドである場合を除いて、「関数へのポインタ」に変換されることに
> なっています。

補足します。

func calc[] = { &add, &sub, &mul, &div, &mod }; は、
func calc[] = { add, sub, mul, div, mod }; と書いてもかまいません。

関数 add は「関数へのポインタ]に暗黙のうちに変換されるからです。
&add と書いた場合の add は「関数」のままです。そして 単項&演算子に
より「関数へのポインタ」に変換されます。

次のプログラムは、正しいプログラムです。

#include <stdio.h>

int main(void)
{
    (&printf)("alpha\n");
    (*printf)("beta\n");
    (**printf)("gamma\n");
    (***printf)("delta\n");
    (****************printf)("omega\n");
    return 0;
}


> これは、配列型が、単項&演算子のオペランドである場合と sizeof演算子の
> オペランドである場合を除いて、「配列の先頭要素へのポインタ」に変換さ
> れることによく似ています。

calc[i] は、*(calc + i) の略記に過ぎません。配列と整数を足すことはでき
ませんが、配列 calc が「配列の先頭要素へのポインタ」に暗黙に変換される
ことから、足し算ができるのです。

calc[i](a, b) は、(*(calc + i))(a, b) とも書けますが、そんな風に書く
人はいないでしょう。



この投稿にコメントする

削除パスワード

No.22857

Re:関数のポインタに関しまして
投稿者---Blue(2005/08/27 14:03:46)


> しかし、関数型は、単項&演算子のオペランドである場合と sizeof演算子の
> オペランドである場合を除いて、「関数へのポインタ」に変換されることに
> なっています。
なるほど。理解できました。
# 22844のプログラムのままでよかったんですね。(゜▽゜;A アセ

長々とご教授ありがとうございました。



この投稿にコメントする

削除パスワード

No.22845

Re:関数のポインタに関しまして
投稿者---孝太郎(2005/08/27 03:26:56)


επιστημηさんの言う通りです。
わからないことは自分で調べろですね。

Blueさんサンプルありがとうございます。
動かしてみます。



この投稿にコメントする

削除パスワード

No.22856

Re:関数のポインタに関しまして
投稿者---ohyama(2005/08/27 12:46:56)


回答をくださり、ありがとうございます。

分かってしまうと簡単な事で、なぜ今まで分からなかったのだろう、と思うと、自分に少し嫌気が射してきます。

以降、もっと考えて、自分自身で「なぜ今まで分からなかったのだろう」と思えるようになりたいです。

ありがとうございました。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧