アプリ版:「スタンプのみでお礼する」機能のリリースについて

いつもお世話になっております。

最近C++を勉強し始めたばかりで、初心者丸出しの質問になってしまうと思うのですがひとつよろしくお願いします。

本を見ながらじゃんけんゲームを作っていて、サンプルとは別に自分で考えて作ってみたのですが、scanfの挙動がどうも思い通りにいきません。
以下がソースです。

int testJanken()
{
    int player=0;
    int computer;
    printf("【じゃんけんゲーム】\n");

    printf("じゃんけん・・・(グー:1 チョキ:2 パー:3 終了:9)>");
    scanf("%d",&player);    //入力受付

    while(player!=9)
    {
        if(0<player&&player<=3)
        {
            printf("\nあなたは:");
            showTe(player);
            
            srand(time(NULL));
            computer=rand()%3+1;
            printf("コンピューターは:");
            showTe(computer);

            showShouhai(player,computer);
        }
        else
        {
            printf("\n----------1~3,または9の値を入れてください!---------\n");

        }

        printf("\nじゃんけん・・・(グー:1 チョキ:2 パー:3 終了:0)>");
        player=0;
        scanf("%d",&player);    //入力受付
    }
    printf("\nバイバイー!!");

    return 0;
}
//勝敗決定表示
int showShouhai(int player, int computer)
{
    if(player==computer)
    {
        printf("あいこ!\n");
        return 0;
    }
    else if((player+1==computer)||(player-2==computer))
    {
        printf("あなたの勝ち!\n");
        return 1;
    }
    else
    {
        printf("コンピューターの勝ち・・・\n");
        return 2;
    }
}
//入力値からグーチョキパーを文字列で表示させる
int showTe(int su)
{
    switch(su)
    {
        case 1:
            printf("グー!\n");
            break;
        case 2:
            printf("チョキ!\n");
            break;
        case 3:
            printf("パー!\n");
            break;
        default:
            printf("???\n");
            break;
    }
    return 0;
}

【実現したい仕様はこちら】
1)じゃんけんの手(1,2,3のどれか)を入れれば通常通りじゃんけんが行われ、結果が表示される。
2)9が入力されたら終了
3)1,2,3,9以外が入力されたらメッセージの表示

この3がうまくいきません。
制御できないのは文字を入力した場合なのですが、例えばaと入力するとそれ以降永久ループとなり抜け出せなくなってしまいます・・・

ネットであちこち原因を調べてみたのですが、探し方が悪いのか解決策がわかりません・・・
今後の勉強のためにも原因と解決策を詳しく教えて頂けると嬉しいです。
よろしくお願いします。

A 回答 (6件)

3がうまくいかない原因はscanfで%dを指定しているためです。


%dは整数型の10進数のフォーマットなので数字データしか格納出来ません。
そのためアルファベットのように文字列型データをいれてしまうと
読み込み不一致が起こります。

それを回避するためには
atoi(str)
この関数を用います。
これは引数である文字列strをint型変数に変換して返すといった関数です。

scanf("%d",&player);    //入力受付
この部分を

char c[];
scanf("%s",&c);
player = atoi(c);
このようにすれば解決します。

簡単に説明するとscanfでは文字列を取得し、後にatoi()関数を使ってint型の
整数へと変えています。
こうすることで読み込み不一致を防げます。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
atoi調べました。参考になります。

入力のscanf("%d",&player);を以下のように変更
fgets(tmp,2,stdin);//入力受付
player = atoi(tmp);
while(getchar() != '\n');

※char tmp[2];を上で追加宣言してます。

これで仕様通り動くようになりました!
ありがとうございました。

お礼日時:2011/09/10 19:13

まず、scanf は初心者が使うには難しすぎる関数ですので、他の関数を使いましょう。

fgets+sscanfが比較的楽です。
また、少なくとも、scanf/sscanf/fscanf は必ず返値をチェックする習慣をつけましょう。

char line[20];
とでもしておいて、
scanf("%d",&player); 
の代わりに、

fgets(line, sizeof line, stdin); /* line[] に一行入力 */
if( sscanf(line,"%d",&player)==1 ) {/* 数字があれば取り出す。返値が1なら成功 */
 player に数値が入ってるので処理する;
}else{
 数字の取り出しが失敗→数字で無いものが入力されたときの処理;
}
    • good
    • 0
この回答へのお礼

scanfはバグ要素になりやすいらしいですね・・・
その割にシンプルだからとテキスト等では良く使用されているとかなんとか。
戻り値のチェック大切ですね。すっかり戻り値の存在を忘れていまして、先程チェックしてみたら無限ループに入ってから0が返ってくるようになってました。

ソースまで提示してくださってありがとうございます。
似たような感じで
fgets(tmp,2,stdin);//入力受付
player = atoi(tmp);
while(getchar() != '\n');
の3行+tmpの宣言に置き換えることで何とかできるようになりました。
本当、勉強になります。
ありがとうございました。

お礼日時:2011/09/10 19:24

言い忘れていたことを少し。


解っているかもしれませんが
char型配列の宣言は他の変数宣言と同じところでしておいてください。
後、配列のサイズが抜けていましたので適当な値を放り込まないといけません。
例:char c[10];

それからatoi関数について補足ですが
scanf("%s", c);
player = atoi(c);
としてscanfで文字列cに数字が入れられた場合はそのままatoi関数でint型の数字に
変えられますが、アルファベット等数字以外のデータが入った場合は全て0に変わります。
    • good
    • 0
この回答へのお礼

atoi関数への補足ありがとうございます。
今回の仕様では他は0で構わなかったので良かったですが、今後のためにもちゃんと勉強しておきます。
ありがとうございました。

お礼日時:2011/09/10 19:18

既に回答が出ていますが、「sscanf scanf」で検索してみてください。



下記など参考になるかと思います。
http://ja.wikipedia.org/wiki/Scanf
http://www.6809.net/tenk/html/cgokai/scanf.htm
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
参考URL拝見しました。
詳しく載っていて、とても勉強になりました。
ありがとうございます!

お礼日時:2011/09/10 19:15

>scanfの前にfflush(stdin);を入れる。



入力ストリームに対してfflushするのは、確か未定義動作であったはずです。

さて、質問者さんの問題を解決するには、たぶん、
fgets
とか
sscanf
あたりの関数が必要になるのではないかと思います。

scanf

"%d"
という書式文字列に対して
a
という入力を食わせたときにそうなってしまうのは、ある意味致し方ないことだと思います。
    • good
    • 0
この回答へのお礼

回答ありがとうございました。
scanfは何かとバグ要素になる事が多いようですね・・・
テキストでこれが使われていたので何の疑問も持たずに使用していました・・・
fgetsとsscanf、調べてみました。入力に使える関数はたくさんあるんですね。

今回の仕様ではfgetsとgetcharを使用することで事足りたので、他の入力関連の関数は今後また別の面で使用する際のために後でよく勉強しておきます。

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

お礼日時:2011/09/10 19:07

scanf("%d",&player); をscanf("%02x", &player);に変更する。


もしくはscanfの前にfflush(stdin);を入れる。

\nがバッファに残っちゃってるんだと思います。%d、%s、%cを使うときは注意が必要。
動かなかったらごめんね。もう現役じゃないから。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
後で回答された方が
「入力ストリームに対してfflushするのは、確か未定義動作」
と言われていたので、ちょっと調べてみました。
試しに使ってもみましたが、動くものの上記のとおり不安要素が拭えなかったので別の方法にしました。

今回の仕様ではfgetsとgetcharを使用することで事足りたので、他の入力関連の関数も今後また別の面で使用する際のためによく勉強しておきます。

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

お礼日時:2011/09/10 19:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!