C言語 mainループ内の条件分岐を減らす方法(関数ポインタ)
閉じる
閉じる

新しい記事を投稿しました。シェアして読者に伝えましょう

×

C言語 mainループ内の条件分岐を減らす方法(関数ポインタ)

2013-07-03 15:13
    記念すべき初投稿です。

    C言語の関数ポインタを使ってmain関数内の条件分岐(if文)をなるべく減らしたいと思います。
    以下、参考にしたURL一覧

    「UeSyuのプログラミングのネタ!」様
    http://www.geocities.jp/uesyu2002/prog_03.html
    「C言語の分からないところ」様
    http://studiokingyo.fc2web.com/dxlib/c/c1.html


    動作環境について

    苦しんで覚えるC言語様のサイトにある初心者向けのC言語開発環境を使用しました。

    http://9cguide.appspot.com/p_9cide.html



    ゲームプログラミングを打っていると条件分岐がややこしくなりすぎて死んでしまいます。
    とにかく、つらい

    そこで、関数ポインタを使うことでタイムテーブルを組むことにしました。
    ある程度、決まった時間に切り替えしを予定しているものに使えます。

    プログラムの説明は後ろの方でします。

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

    #define NIGHT 0
    #define MORNING 1
    #define AFTERNOON 2

    #define TIMELINE 1 //1秒経つと次の関数に切り替え
    #define TIMEUP 30 //30秒で実行を打ち切り

    typedef int (*P_F)(time_t);
    time_t timer;

    int night_count=0,morning_count=0,
    afternoon_count=0,loop_count=0,
    void_count=0;

    int N(time_t t)
    {
    if(t<=timer-1){
    printf("GOOD NIGHT\n");
    night_count++;
    return NIGHT;
    }

    timer = (time(NULL)+TIMELINE);
    void_count++;

    return MORNING;
    }

    int M(time_t t)
    {
    if(t<=timer-1){
    printf("GOOD MORNING\n");
    morning_count++;
    return MORNING;
    }

    timer = (time(NULL)+TIMELINE);
    void_count++;

    return AFTERNOON;
    }

    int A(time_t t)
    {
    if(t<=timer-1){
    printf("GOOD AFTERNOON\n");
    afternoon_count++;
    return AFTERNOON;
    }

    timer = (time(NULL)+TIMELINE);
    void_count++;

    return NIGHT;
    }



    int main(void)
    {
    P_F func_po[3] = {N,M,A};
    time_t def_t = time(NULL),t = time(NULL);
    int i=MORNING,j;
    double mor,nig,aft,loo,voi;

    def_t+=TIMEUP;
    timer=(time(NULL)+TIMELINE);

    //mainループ
    while(t<=def_t){
    loop_count++;
    j = func_po[i](t);
    i = j;
    t = time(NULL);
    }

    mor=(double)morning_count;
    nig=(double)night_count;
    aft=(double)afternoon_count;
    loo=(double)loop_count;
    voi=(double)void_count;

    printf("\n\n---------- ---------- result ---------- ----------\n\n");

    printf(" morning=\t%d\n night=\t\t%d\n afternoon=\t%d\n loop=\t\t%d\n void=\t\t%d\n\n"
    ,morning_count,night_count,afternoon_count,loop_count,void_count);

    printf(" loop-(morning+night+afternoon+void)=%d\n\n",
    loop_count-(morning_count+night_count+afternoon_count+void_count));

    printf(" morning%% =\t%.1lf%%\n night%% =\t%.1lf%%\n afternoon%% =\t%.1lf%%\n void%% =\t%.1lf%%\n\n",
    (mor/loo)*100,(nig/loo)*100,(aft/loo)*100,(voi/loo)*100);

    printf("---------- ---------- result ---------- ----------\n\n");

    return 0;
    }

    以上がプログラムです。

    全体の動作としては1秒経つと次の関数に切り替わり出力文字が変わります。
    また、このループ動作はプログラム実行から30秒経つと終了します。


    重要箇所はプログラム内の11行目と64行目です。
    12 : typedef typedef int (*P_F)(time_t);
    65 : P_F func_po[3] = {N,M,A};

    typedefは自分でint型やchar型のように型を宣言できます。
    11行目については関数ポインタ型であるP_F型を定義しています。
    64行目はP_F型を使って、関数ポインタ型の配列変数func_poを宣言しています。

    func_po[3] = {N,M,A}について、”M(clock_t)”関数の”(clock_t)”を取っ払って”M”だけを指定することで関数ポインタとして認識されます。
    配列変数に初期値として関数ポインタを代入することで配列で関数を管理することができます。

    実行方法としてはプログラム内の75行目と76行目(メインループ内)”j = func_po[i](t); i = j;”で実行することが可能です。
    配列に格納した関数が戻り値としてint型を持っています。
    ”j”はM,N,A関数のなかで指定した次の関数の配列番号(戻り値)を格納します。
    このM,N,A関数の戻り値”j”を”i”に格納することで次の関数へと状態遷移が可能となります。

    mainループ内の条件分岐がなくなりすっきりとしていますね。
    これなら、困らなくて済みそうです。

    広告
    コメントを書く
    コメントをするには、
    ログインして下さい。