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

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

 詳しくはこちら



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

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


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

No.20017

関数へのポインタ
投稿者---ニッキー(2005/02/16 21:51:31)


 >こんばんはニッキーです。
>今晩はご相談にやって参りました。
>CDプレーヤーの状態遷移を考えているのですが、ソース1ではしっかり正しい結果がでます。しかし、ソース2(関数にポインタ利用!)ではうまくいきません。(またポインタの使い方がいまいちわからないため。テキストの説明程度程ならなんとですが。ですからこれからもっともっと利用して身につけるためにもソース2を完成せねばということです。) 
 ソース2で関数の仮引数にポインタaを使っていますが、関数の中のif文では値aを使っているので移植性がダメということはわかっております。どうする場このケースに関数へのポインタが利用できるのか、どなたか糸口を教えていただけませんか?

 <ソース1>
<pre>#include&lt;stdio.h&gt;
//#include&lt;stdlib.h&gt;

int jotai(int a); /*プロトタイプ宣言*/

int main(void){

int i;

printf(&quot;現在の状態:POWER OFF\n&quot;);
while(1){

printf(&quot;INPUT EVEVNT\n&quot;);
printf(&quot;1.ON 2.OFF 3.PLAY 4.STOP 5.EXIT\n &gt;&quot;);
scanf(&quot;%d&quot;,&amp;i);

jotai(i);
if(i == 5)
break;
}


return 0;
}


int jotai(int a){
switch(a){

case 1:printf(&quot;現在の状態:POWER ON\n&quot;);break;
case 2:printf(&quot;現在の状態:POWER OFF\n&quot;);break;
case 3:printf(&quot;現在の状態:NOW PLAY!!\n&quot;);break;
case 4:printf(&quot;現在の状態:STOP\n&quot;);break;
case 5:printf(&quot;現在の状態:EXIT\n&quot;);break;
default:printf(&quot;入力ミスです。&quot;);
}
return a;
}

<ソース2>
#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;

void jotai(int *a); /*プロトタイプ宣言*/

int main(void){

int i;

printf(&quot;現在の状態:POWER OFF\n&quot;);
while(1){

printf(&quot;INPUT EVEVNT\n&quot;);
printf(&quot;1.ON 2.OFF 3.PLAY 4.STOP 5.EXIT\n &gt;&quot;);
scanf(&quot;%d&quot;,&amp;i);

jotai(i);
//if(j == 5)
//break;
}


return 0;
}


void jotai(int *a){

if(a ==1)
printf(&quot;現在の状態:POWER ON\n&quot;);
else if(a ==2)
printf(&quot;現在の状態:POWER OFF\n&quot;);
else if(a ==3)
printf(&quot;現在の状態:NOW PLAY!!\n&quot;);
else if(a == 4)
printf(&quot;現在の状態:STOP\n&quot;);
else {
printf(&quot;現在の状態:EXIT\n&quot;);
exit(0);
}

}

</pre>


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:関数へのポインタ 20018 あかま 2005/02/16 22:19:45
<子記事> Re:関数へのポインタ 20019 Blue 2005/02/16 22:20:45
<子記事> Re:関数へのポインタ 20020 RiSK 2005/02/16 22:22:42
<子記事> Re:関数へのポインタ 20022 円零 2005/02/16 22:26:54
<子記事> Re:関数へのポインタ 20024 南野骨茶 2005/02/16 22:39:24


No.20018

Re:関数へのポインタ
投稿者---あかま(2005/02/16 22:19:45)


文字化けしてるので直したのはっておきます。
#include<stdio.h>
//#include<stdlib.h>

int jotai(int a); /*プロトタイプ宣言*/

int main(void){

    int i;
    
    printf("現在の状態:POWER OFF\n");
    while(1){
    
        printf("INPUT EVEVNT\n");
        printf("1.ON 2.OFF 3.PLAY 4.STOP 5.EXIT\n >");
        scanf("%d",&i);
        
        jotai(i);
        if(i == 5)
            break;
    }
    
    
    return 0;
}


int jotai(int a){
    switch(a){
    
        case 1:printf("現在の状態:POWER ON\n");break;
        case 2:printf("現在の状態:POWER OFF\n");break;
        case 3:printf("現在の状態:NOW PLAY!!\n");break;
        case 4:printf("現在の状態:STOP\n");break;
        case 5:printf("現在の状態:EXIT\n");break;
        default:printf("入力ミスです。");
    }
    return a;
}

<ソース2>
#include<stdio.h>
#include<stdlib.h>

void jotai(int *a); /*プロトタイプ宣言*/

int main(void){

    int i;
    
    printf("現在の状態:POWER OFF\n");
    while(1){
        
        printf("INPUT EVEVNT\n");
        printf("1.ON 2.OFF 3.PLAY 4.STOP 5.EXIT\n >");
        scanf("%d",&i);
        
        jotai(i);
        //if(j == 5)
        //break;
    }


    return 0;
}


void jotai(int *a){
    
    if(a ==1)
        printf("現在の状態:POWER ON\n");
    else if(a ==2) 
        printf("現在の状態:POWER OFF\n");
    else if(a ==3)
        printf("現在の状態:NOW PLAY!!\n");
    else if(a == 4)
        printf("現在の状態:STOP\n");
    else {
        printf("現在の状態:EXIT\n");
        exit(0);
    }

}



この投稿にコメントする

削除パスワード

No.20021

Re:関数へのポインタ
投稿者---あかま(2005/02/16 22:24:48)


>ソース2で関数の仮引数にポインタaを使っていますが、関数の中のif文では値aを使っているので移植性がダメということはわかっております。どうする場このケースに関数へのポインタが利用できるのか、どなたか糸口を教えていただけませんか?
移植性がダメとはこれいかに?
たぶんそんなことはないと思いますが。


関数にポインタを渡すときは

jotai(&i);

です。
関数内でポインタの指しているデータを読み出すときは

if(*a == 1)

です。


この投稿にコメントする

削除パスワード

No.20019

Re:関数へのポインタ
投稿者---Blue(2005/02/16 22:20:45)


ここでソースのここが違うといわれても、ピンとこないし曖昧な知識になってしまいます。
ポインタについての学習が必要だと思います。
初心者のためのポイント学習C言語 10章ポインタを参考に学習してください。

そのあと、自分のソースのどこが悪かったか示してもらいたいです。



この投稿にコメントする

削除パスワード

No.20023

Re:関数へのポインタ
投稿者---Blue(2005/02/16 22:33:34)


>そのあと、自分のソースのどこが悪かったか示してもらいたいです。

解答がでちゃいましたね。
でも、流さないで勉強しといたほうがいいですよ。




この投稿にコメントする

削除パスワード

No.20020

Re:関数へのポインタ
投稿者---RiSK(2005/02/16 22:22:42)


#include<stdio.h>
void jotai(const int * a) {
    switch (*a) {
    case 1: printf("現在の状態:POWER ON\n"); break;
    case 2: printf("現在の状態:POWER OFF\n"); break;
    case 3: printf("現在の状態:NOW PLAY!!\n"); break;
    case 4: printf("現在の状態:STOP\n"); break;
    case 5: printf("現在の状態:EXIT\n"); break;
    }
}
int main(void) {
    int i;
    printf("現在の状態:POWER OFF\n");
    while(1) {
        printf("INPUT EVEVNT\n");
        printf("1.ON 2.OFF 3.PLAY 4.STOP 5.EXIT\n >");
        scanf("%d", &i);
        jotai(&i);
        if (i == 5) break;
    }
    return 0;
}



この投稿にコメントする

削除パスワード

No.20022

Re:関数へのポインタ
投稿者---円零(2005/02/16 22:26:54)


ええと、そういうのは「関数へのポインタ」とは言いません。
単なるポインタ型の引数ですね。

書き換えについては、常に型を考えるようにすればおのずわかってくると思います。

#include <stdio.h>

void jotai(int *a);

int main(void){
    int i;

    printf("現在の状態:POWER OFF\n");
    while(1){
        printf("INPUT EVEVNT\n");
        printf("1.ON 2.OFF 3.PLAY 4.STOP 5.EXIT\n >");
        scanf("%d", &i);
        jotai(&i);
        //if(j == 5)
        //break;
    }
    return 0;
}


void jotai(int *a){
    if(*a == 1) printf("現在の状態:POWER ON\n");
    else if(*a == 2) printf("現在の状態:POWER OFF\n");
    else if(*a == 3) printf("現在の状態:NOW PLAY!!\n");
    else if(*a == 4) printf("現在の状態:STOP\n");
    else {
        printf("現在の状態:EXIT\n");
        exit(0);
    }
}




この投稿にコメントする

削除パスワード

No.20024

Re:関数へのポインタ
投稿者---南野骨茶(2005/02/16 22:39:24)


ソース2をもとに、関数へのポインタを「本当に」使った
プログラムを書いてみました。
ご参考になりましたら幸いです。


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

void jotai(int a); /*プロトタイプ宣言*/
void ON(void);
void OFF(void);
void PLAY(void);
void STOP(void);
void EXIT(void);

typedef void (*FUNC)(void);

FUNC func[] = { ON, OFF, PLAY, STOP, EXIT, };

int main(void)
{
    int i;
    
    printf("現在の状態:POWER OFF\n");
    while (1) {
        printf("INPUT EVENT\n");
        printf("1.ON 2.OFF 3.PLAY 4.STOP 5.EXIT\n >");
        scanf("%d",&i);
        
        if (1 <= i && i <= 5) {
            jotai(i-1);
        }
        if (i == 5) {
            break;
        }
    }
    
    return 0;
}


void jotai(int a)
{
    func[a]();
}

void ON(void)
{
    printf("POWER ON\n");
}

void OFF(void)
{
    printf("POWER OFF\n");
}

void PLAY(void)
{
    printf("NOW PLAY!!\n");
}

void STOP(void)
{
    printf("STOP\n");
}

void EXIT(void)
{
    printf("EXIT\n");
}





この投稿にコメントする

削除パスワード

No.20026

Re:関数へのポインタ
投稿者---南野骨茶(2005/02/16 22:52:30)


>ソース2をもとに、関数へのポインタを「本当に」使った
>プログラムを書いてみました。

というわけですので、他の方々が回答のつもりで
ご提示されたソースでは、「関数へのポインタ」を
全く使っていません。



この投稿にコメントする

削除パスワード

No.20027

Re:関数へのポインタ・ありがとうございます。
投稿者---ニッキー(2005/02/16 23:04:06)


>というわけですので、他の方々が回答のつもりで
ご提示されたソースでは、「関数へのポインタ」を
全く使っていません。

 みなさん早速の返信ありがとうございます。みなさんのアドバイスの下また勉強して、また疑問におもったら質問しに来ます。
 大変恐縮ですが、南野骨茶がそういわれている理由をできればお聞きしてもよろしいでしょうか。 今後のキーとなりそうなので。


この投稿にコメントする

削除パスワード

No.20028

Re:関数へのポインタ・ありがとうございます。
投稿者---RiSK(2005/02/16 23:28:57)


「関数へのポインタ」と「ポインタ変数を関数へ渡す」事は別


この投稿にコメントする

削除パスワード

No.20030

Re:関数へのポインタ・ありがとうございます。
投稿者---南野骨茶(2005/02/16 23:36:34)


>「関数へのポインタ」と「ポインタ変数を関数へ渡す」事は別

#20020でご提示になったソースは関数へのポインタを使っていなかった、
ということをご理解くださったと解釈してよろしいでしょうか。


この投稿にコメントする

削除パスワード

No.20031

Re:関数へのポインタ・ありがとうございます。
投稿者---円零(2005/02/16 23:52:42)


>>「関数へのポインタ」と「ポインタ変数を関数へ渡す」事は別
>
>#20020でご提示になったソースは関数へのポインタを使っていなかった、
>ということをご理解くださったと解釈してよろしいでしょうか。


そういう当てこすりめいた発言はやめましょうよ。


この投稿にコメントする

削除パスワード

No.20033

Re:関数へのポインタ・ありがとうございます。
投稿者---南野骨茶(2005/02/17 00:06:13)


>そういう当てこすりめいた発言はやめましょうよ。

当てこすりなどという意図は全くございません。
そのように解釈されたということは、私の言葉が足りなかったのでしょう。
申し訳ありません。


この投稿にコメントする

削除パスワード

No.20032

Re:関数へのポインタ・ありがとうございます。
投稿者---RiSK(2005/02/16 23:59:26)


>>「関数へのポインタ」と「ポインタ変数を関数へ渡す」事は別
>
>#20020でご提示になったソースは関数へのポインタを使っていなかった、
>ということをご理解くださったと解釈してよろしいでしょうか。

No.20017のソースを読んだ時点でニッキーさんが「関数へのポインタ」が何であるかを勘違いしているのは分かりました。
ただ,その指摘をしなかっただけです。
# つまり,初めから区別は付いていたって事です (^^;


この投稿にコメントする

削除パスワード

No.20034

Re:関数へのポインタ・ありがとうございます。
投稿者---南野骨茶(2005/02/17 00:07:04)


>ただ,その指摘をしなかっただけです。
># つまり,初めから区別は付いていたって事です (^^;

了解いたしました。どうもありがとうございます。


この投稿にコメントする

削除パスワード

No.20029

Re:関数へのポインタ・ありがとうございます。
投稿者---南野骨茶(2005/02/16 23:32:01)


> 大変恐縮ですが、南野骨茶がそういわれている理由をできればお聞きしてもよろしいでしょうか。 今後のキーとなりそうなので。

なぜって、関数の引数としてポインタを渡すことと
関数へのポインタを扱うこととは全く別の話だからです。

ところで、先ほど私が提示したソースのどこで関数へのポインタを
使っているか、おわかりになりますか?


この投稿にコメントする

削除パスワード

No.20049

Re:関数へのポインタ
投稿者---ニッキー(2005/02/17 17:11:33)


開発環境:winMe、ボーランド5.0

>ソース2をもとに、関数へのポインタを「本当に」使った
>先ほど私が提示したソースのどこで関数へのポインタを
使っているか、おわかりになりますか?
/*関数へのポインタを格納するための変数の宣言*/
/*FUNCは引数を取らない関数へのポインタ型変数*/



<pre>typedef void (*FUNC)(void);/*ここですよね

FUNC func[] = { ON, OFF, PLAY, STOP, EXIT, };/*他のページではfuncの位置にFUNCがあり、mainの関数呼び出しでも(*FUNC[i])(void);のような形で使われていたのですが。 いまいち意味と使い方がわからないのが現状です。 もしおわかりでしたらもう一度ご教授できませんか?*/

int main(void)

               >>>>>>>>
</pre>

<pre>if (1 &lt;= i &amp;&amp; i &lt;= 5) {
            jotai(i-1);
        }
        if (i == 5) {
            break;

</pre>





*最後に、実際に関数ポインタが効力を発揮するのは、状態によって呼ぶ関数が決まっており、その状態を多次元配列テーブルで定義できる場合です。このような場合には、関数ポインタの入る多次元配列を用意しておけば、それによって呼ぶべき関数呼び出しを簡単に制御することができるため、複雑な作業を、かなりシンプルなプログラムで表現できと、あの後お聞きしました。 つまりこのケースだなっと思いました。


この投稿にコメントする

削除パスワード

No.20050

Re:関数へのポインタ
投稿者---ニッキー(2005/02/17 17:35:21)


>失礼しました。
 typedefがあるからそうなると過去ログを調べながら知りました。


この投稿にコメントする

削除パスワード

No.20064

Re:関数へのポインタ
投稿者---南野骨茶(2005/02/18 00:23:38)


>/*関数へのポインタを格納するための変数の宣言*/
>/*FUNCは引数を取らない関数へのポインタ型変数*/

FUNCは変数ではありません。データ型です。
「引数をとらず、戻り値がない関数へのポインタ」を示す型をFUNCとして
定義しています。

その次の行で、FUNC型の配列funcを定義しています。
こちらが変数の定義です。



この投稿にコメントする

削除パスワード

No.20085

Re:関数へのポインタ
投稿者---ニッキー(2005/02/19 18:41:32)


>FUNCは変数ではありません。データ型です。
>「引数をとらず、戻り値がない関数へのポインタ」を示す型をFUNCとして
>定義しています。
>
>その次の行で、FUNC型の配列funcを定義しています。

 あれからもう一度関数へのポインタをテキスト(著林ハルヒコ・シニア)などをみながら考えました。
 この前南野さんが提供してくださったソースはちょっとわかりにくかったので、(jotai関数など)テキストの形式に手直ししてコンパイルしましたが無事実行結果も大丈夫でした。
 ここで質問ですが修正前と修正後の違い(特徴):質問1、質問2の箇所のでどのような感じで関数呼び出しをやっているのか教えていただけません。いまいちニュアンスみたいのがわかなくて頭に入ってこないので。
 *質問1・2は下のソースの注があります。


修正後:
#include <stdio.h>

void ON(void);  /*プロトタイプ宣言*/
void OFF(void);
void PLAY(void);
void STOP(void);

typedef void (*FUNC)(void);

FUNC func[] = { ON, OFF, PLAY, STOP, }; /*質問1*/ /*ここは修正後ならmain内でもokなのはなぜでしょう?*/



int main(void)
{
    int i;
    

    printf("現在の状態:POWER OFF\n");
    while (1) {
        printf("INPUT EVENT\n");
        printf("1.ON 2.OFF 3.PLAY 4.STOP 5.EXIT\n >");
        scanf("%d",&i);
        
        if (1<= i && i <= 4) {
            func[i-1]();/*jotai(i-1)*/  /*質問2*/
        }
        else if(i == 5) {
            break;
        }
    }
    
    return 0;
}

void ON(void)
{
    printf("POWER ON\n現在の状態 : POWER ON\n");
}

void OFF(void)
{
    printf("POWER OFF\n現在の状態 : POWER OFF\n");
}

void PLAY(void)
{
    printf("NOW PLAY!!\n現在の状態 : PLAY\n");
}

void STOP(void)
{
    printf("STOP\n現在の状態 : STOP\n");
}





この投稿にコメントする

削除パスワード

No.20087

Re:関数へのポインタ
投稿者---南野骨茶(2005/02/19 23:37:34)


>FUNC func[] = { ON, OFF, PLAY, STOP, }; /*質問1*/ /*ここは修正後ならmain内でもokなのはなぜでしょう?*/

今回の場合、funcという変数を直接扱っているのはmain関数だけです。
したがって、funcがmain関数の中にあっても外にあっても
プログラムは同じ動きをします。

>            func[i-1]();/*jotai(i-1)*/  /*質問2*/

質問2の内容はどういったものでしょうか。



この投稿にコメントする

削除パスワード

No.20088

Re:関数へのポインタ
投稿者---南野骨茶(2005/02/20 07:15:52)


> ここで質問ですが修正前と修正後の違い(特徴):質問1、質問2の箇所のでどのような感じで関数呼び出しをやっているのか教えていただけません。いまいちニュアンスみたいのがわかなくて頭に入ってこないので。

>            func[i-1]();/*jotai(i-1)*/  /*質問2*/

入力したiの値によって、関数へのポインタの配列であるfunc[]に入っている
ONなどの関数を呼び出しています。省略せずに書くと(*func[i-1])();となります。
私が示した版ではこの部分をjotai関数で担当していましたが、
今回ご提示になっているようにしても全く同じことです。


この投稿にコメントする

削除パスワード

No.20091

Re:関数へのポインタ
投稿者---ニッキー(2005/02/20 18:21:41)


>質問2はどういうことですか?
 南野さんが2番目のレスで返答してくださったことでオーケーです。

>今回の場合、funcという変数を直接扱っているのはmain関数だけです。
>したがって、funcがmain関数の中にあっても外にあっても
>プログラムは同じ動きをします。

つまり修正前はmain内とjotai関数内で使っていたからということですよね。









この投稿にコメントする

削除パスワード

No.20092

Re:追加(流れ図)
投稿者---ニッキー(2005/02/21 13:41:46)


 追加です。 web検索したのですが載ってなかったので。
 関数のポインタでのmain前の定義やプロトタイプ宣言は流れ図に普通いれるんですか?
 あと、関数呼び出しでは、サブルーチンを使ってもいいんですかね。
 流れ図も使っているんですが、サブルーチンの細かい使い方の媒体がみつからなかったので。
 


この投稿にコメントする

削除パスワード

No.20093

Re:追加(流れ図)
投稿者---南野骨茶(2005/02/21 20:12:40)


> 関数のポインタでのmain前の定義やプロトタイプ宣言は流れ図に普通いれるんですか?

流れ図…。なつかしい響きです。
ここしばらく実物を見たことがありませんので、どういう風に書くものなのか
すっかり忘れてしまいました。

> あと、関数呼び出しでは、サブルーチンを使ってもいいんですかね。

流れ図の中で「他の関数を呼び出す」を表現するために
サブルーチンの表現を使ってもいいか、という問いですか?
もしそうだとして、流れ図の記号の中に他に適切なものがなければ、
使っていいのではないでしょうか。

# ドキュメントとして流れ図が適切かどうかは、脇へ置いておきます。


この投稿にコメントする

削除パスワード

No.20094

Re:追加(流れ図多少詳しい方いますか?)
投稿者---ニッキー(2005/02/22 10:35:18)


>> 流れ図の中で「他の関数を呼び出す」を表現するために
サブルーチンの表現を使ってもいいか、という問いですか?
>そうです。
>>もしそうだとして、流れ図の記号の中に他に適切なものがなければ、
使っていいのではないでしょうか。
>貴重なご意見ありがとうございます。

>他の方でも流れ図に少しでも詳しい方がおりましたら、追加情報よろしかったらお願いします。




この投稿にコメントする

削除パスワード

No.20118

Re:追加(流れ図多少詳しい方いますか?)
投稿者---南野骨茶(2005/02/22 20:25:48)


>>他の方でも流れ図に少しでも詳しい方がおりましたら、追加情報よろしかったらお願いします。

ここの掲示板の「利用上の注意」の枠のすぐ下にある「ホームページ」から、
掲示板管理人であるTOMOJIさんのサイトへ行けます。
そこに、「JIS流れ図記号一覧表」のリンクがあります。


この投稿にコメントする

削除パスワード

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