いつもお世話になっております。
最近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と入力するとそれ以降永久ループとなり抜け出せなくなってしまいます・・・
ネットであちこち原因を調べてみたのですが、探し方が悪いのか解決策がわかりません・・・
今後の勉強のためにも原因と解決策を詳しく教えて頂けると嬉しいです。
よろしくお願いします。
No.3ベストアンサー
- 回答日時:
3がうまくいかない原因はscanfで%dを指定しているためです。
%dは整数型の10進数のフォーマットなので数字データしか格納出来ません。
そのためアルファベットのように文字列型データをいれてしまうと
読み込み不一致が起こります。
それを回避するためには
atoi(str)
この関数を用います。
これは引数である文字列strをint型変数に変換して返すといった関数です。
scanf("%d",&player); //入力受付
この部分を
char c[];
scanf("%s",&c);
player = atoi(c);
このようにすれば解決します。
簡単に説明するとscanfでは文字列を取得し、後にatoi()関数を使ってint型の
整数へと変えています。
こうすることで読み込み不一致を防げます。
回答ありがとうございます。
atoi調べました。参考になります。
入力のscanf("%d",&player);を以下のように変更
fgets(tmp,2,stdin);//入力受付
player = atoi(tmp);
while(getchar() != '\n');
※char tmp[2];を上で追加宣言してます。
これで仕様通り動くようになりました!
ありがとうございました。
No.6
- 回答日時:
まず、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{
数字の取り出しが失敗→数字で無いものが入力されたときの処理;
}
scanfはバグ要素になりやすいらしいですね・・・
その割にシンプルだからとテキスト等では良く使用されているとかなんとか。
戻り値のチェック大切ですね。すっかり戻り値の存在を忘れていまして、先程チェックしてみたら無限ループに入ってから0が返ってくるようになってました。
ソースまで提示してくださってありがとうございます。
似たような感じで
fgets(tmp,2,stdin);//入力受付
player = atoi(tmp);
while(getchar() != '\n');
の3行+tmpの宣言に置き換えることで何とかできるようになりました。
本当、勉強になります。
ありがとうございました。
No.5
- 回答日時:
言い忘れていたことを少し。
解っているかもしれませんが
char型配列の宣言は他の変数宣言と同じところでしておいてください。
後、配列のサイズが抜けていましたので適当な値を放り込まないといけません。
例:char c[10];
それからatoi関数について補足ですが
scanf("%s", c);
player = atoi(c);
としてscanfで文字列cに数字が入れられた場合はそのままatoi関数でint型の数字に
変えられますが、アルファベット等数字以外のデータが入った場合は全て0に変わります。
atoi関数への補足ありがとうございます。
今回の仕様では他は0で構わなかったので良かったですが、今後のためにもちゃんと勉強しておきます。
ありがとうございました。
No.4
- 回答日時:
既に回答が出ていますが、「sscanf scanf」で検索してみてください。
下記など参考になるかと思います。
http://ja.wikipedia.org/wiki/Scanf
http://www.6809.net/tenk/html/cgokai/scanf.htm
No.2
- 回答日時:
>scanfの前にfflush(stdin);を入れる。
入力ストリームに対してfflushするのは、確か未定義動作であったはずです。
さて、質問者さんの問題を解決するには、たぶん、
fgets
とか
sscanf
あたりの関数が必要になるのではないかと思います。
scanf
で
"%d"
という書式文字列に対して
a
という入力を食わせたときにそうなってしまうのは、ある意味致し方ないことだと思います。
回答ありがとうございました。
scanfは何かとバグ要素になる事が多いようですね・・・
テキストでこれが使われていたので何の疑問も持たずに使用していました・・・
fgetsとsscanf、調べてみました。入力に使える関数はたくさんあるんですね。
今回の仕様ではfgetsとgetcharを使用することで事足りたので、他の入力関連の関数は今後また別の面で使用する際のために後でよく勉強しておきます。
ありがとうございました。
No.1
- 回答日時:
scanf("%d",&player); をscanf("%02x", &player);に変更する。
もしくはscanfの前にfflush(stdin);を入れる。
\nがバッファに残っちゃってるんだと思います。%d、%s、%cを使うときは注意が必要。
動かなかったらごめんね。もう現役じゃないから。
回答ありがとうございます。
後で回答された方が
「入力ストリームに対してfflushするのは、確か未定義動作」
と言われていたので、ちょっと調べてみました。
試しに使ってもみましたが、動くものの上記のとおり不安要素が拭えなかったので別の方法にしました。
今回の仕様ではfgetsとgetcharを使用することで事足りたので、他の入力関連の関数も今後また別の面で使用する際のためによく勉強しておきます。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# 至急教えてください!プログラミングの問題です。 割られる整数と割る整数を受け取って、商と余りを出力す 3 2022/07/05 10:23
- C言語・C++・C# C言語 プログラミング 4 2022/05/22 11:53
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分 1 2022/07/19 17:03
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
*をユーザーが入力した数字の数...
-
正負を反転させて出力するプロ...
-
Linuxで入力待ちなしkeyread関...
-
数字以外が入力されたらエラー...
-
scanfが2回使えない・・・?;
-
至急お願いします。プログラミ...
-
C言語 for文をつかって記号を表...
-
C言語scanf_sで何故か2回入力に...
-
プログラミング初心者です。 Py...
-
C言語 逆ピラミッドの作り方
-
Eclipseコンソール表示を、リセ...
-
scanf が無視されます
-
cout関数を使っているのですが...
-
C言語について
-
java初心者です。入力されたの...
-
Eclipseでコマンドラインを入力...
-
double型が正常に認識されてい...
-
enterでループ終了
-
if文の条件にscanf関数を使うと…?
-
プログラミングの問題です 「金...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
double型が正常に認識されてい...
-
プログラミング初心者です。 Py...
-
正負を反転させて出力するプロ...
-
Excel VBAで、Application.Inpu...
-
C言語について。
-
batプログラム上で文字列を入力...
-
*をユーザーが入力した数字の数...
-
cout関数を使っているのですが...
-
漢字のソートについて
-
数字以外が入力されたらエラー...
-
Userformの入力順序をタブオー...
-
ワードで文字を入力する時の変...
-
Linuxで入力待ちなしkeyread関...
-
java初心者です。入力されたの...
-
EDITコントロールで入力できる...
-
Eclipseコンソール表示を、リセ...
-
小数か整数かを判定する方法
-
C言語scanf_sで何故か2回入力に...
-
VB.NETで16進数+16進数や16進...
-
Linuxプログラミングで、キーボ...
おすすめ情報