- 締切済み
While()の事でおしえてください
名前入力関数を作ったのですが、名前の入力を確定してもWhile()から抜け出せません。 「名前を確定しました」の後に、「キャラクターの名前を入力してください」に戻ります。 あと、名前入力関数の中にWhile()を入れてみても駄目でした。 うまく処理を終わらせて、main()関数に戻れるようにするには、どうすればいいでしょうか? #pragma warning(disable : 4996) //warning C4996: 'scanf':を消すため #include <stdio.h> #include <stdlib.h> void show_title(void); //タイトル表示関数の宣言 char make_character(void); //名前入力関数の宣言 int main() { char result='n'; //初期化 show_title(); result=make_character(); while((result!='y')||(result!='Y')){ make_character(); } return 0; } void show_title(void) //タイトル表示関数 { system("cls"); //画面を初期化 system("color b"); //文字を青色にする printf("見習い魔道師の挑戦\n\n"); //タイトル表示 } char make_character(void) //名前入力関数 { char name[30]; //名前用の変数 char confirmation; //Y/N用の変数 main()に戻す値 printf("キャラクターの名前を入力してください:"); scanf("%s",name); printf("キャラクターの名前は%sでよろしいですか?(Y/N)",name); scanf("%*c%c",&confirmation); //一回目のscanf()のEnterをクリアする if((confirmation=='y')||(confirmation=='Y')){ printf("名前を確定しました\n"); return confirmation; //戻り値 } else if((confirmation=='n')||(confirmation=='N')){ printf("名前を変更します\n"); return confirmation; //戻り値 warning C4715:用 } else{ printf("Y/N以外が入力されました\n"); return confirmation; //戻り値 warning C4715:用 } }
- みんなの回答 (8)
- 専門家の回答
みんなの回答
- S117
- ベストアンサー率40% (18/45)
ほぼ解決してると思いますが、一応。 >#4お礼 while(!(result=='y')||(result=='Y')){ これ、なんでこうなってるんですか? 私が示した式と違うのですが。 もしかして、 2項演算子 || 単項演算子 ! の優先順位をご存じないですか? もしもそうでしたら、今すぐ参考書で演算子の表で優先順位を確認してください。 ! は || よりも優先順位が高いのです。 || はかなり優先順位が低いので、たいていの演算は括弧をつけなくても問題ありません。また、たいていのプログラマはつけません。 余計な括弧は読みづらくし、うっかりつけ間違えることになります。 また、コードを読む人間に疑念を抱かせます。たいていの場合、余分なことをしているときには、必要なことをしていないものです。 式が立て込んでいるときは、括弧をつけて明示するのもよく知られた手法ですが、いずれにせよ本当に必要な括弧を忘れてはなりません。 ここのループは要するにmake_character内で名前を確定した場合「以外」に継続するというものです。 そうであれば、その式全体を否定するだけです。 つまり、 (confirmation=='y')||(confirmation=='Y') が元なので、 !((result=='y')||(result=='Y')) で否定になります。 まとめると、「演算子の優先順位を覚えておこう。」ということになります。
- chie65536(@chie65535)
- ベストアンサー率44% (8741/19839)
前回の回答の通り、ループ文を result=make_character(); while((result!='y')&&(result!='Y')){ result=make_character(); } と修正すれば期待した動作をしますが「繰り返したい処理を必ず1回は実行して、実行してから、繰り返すかどうか判断する」のであれば「後置反復文」にした方が良いでしょう。 つまり // result=make_character(); 不要 do { result=make_character(); } while((result!='y')&&(result!='Y')); //←最後の「;」を忘れずに と書く方がスマートで判りやすいでしょう。 こうすれば「必ず1回は実行して、結果がyやYじゃなけりゃ繰り返すんだな」って事がすぐに判ります。
- chie65536(@chie65535)
- ベストアンサー率44% (8741/19839)
>'y'または'Y'でない間(yが入力されるまで)としたくて!=をつかいました。 「'y'または'Y'でない間」を「(result!='y')||(result!='Y')」と書いたのが間違い。 resultに色々な値が入っている場合の結果をよ~く考えてみよう。 ・'N'など、'Y'でもなく、かつ、'y'でもない物が来た時 「(result!='y')」は真になり「(result!='Y')」も真になる。なので結果は真。 ・'y'が来た時 「(result!='y')」は偽になり「(result!='Y')」は真になる。なので結果は真。 ・'Y'が来た時 「(result!='y')」は真になり「(result!='Y')」は偽になる。なので結果は真。 つまり「何が来ても、常に真」ってこと。 「'Y'または'y'でない間」ってのは「【'Y'または'y'】でない間」だよね?(【】の括弧の位置に注意) だったら「【'Y'または'y'】の全体を否定」しなきゃ駄目だ。 「【'Y'または'y'】でない間」ってのは、言い換えれば「【'y'である、または、'Y'である】でない間」って事。 つまり「(!(result=='y')||(result=='Y'))」って事だ。 ブール代数では「【AまたはB】の否定」は「【Aの否定】かつ【Bの否定】」に置き換えられる(集合図を書いてみよう) 従って「【'y'である、または、'Y'である】でない間」は「'y'でもなく、かつ、'Y'でもない」に変形する事ができる。 なので「!=」を使って書きたいなら「(result!='y')&&(result!='Y')」って書こう。 それともう一つ。 >while((result!='y')||(result!='Y')){ >make_character(); >} このループに入ったら、誰もresultに値を代入しないけど。 ここのループは while((result!='y')&&(result!='Y')){ result = make_character(); } が正解。 以下の法則を覚えよう。 法則1 「!((A) || (B))」は「(!A) && (!B)」に置き換え可能。 法則2 「!((A) && (B))」は「(!A) || (!B)」に置き換え可能。
- asuncion
- ベストアンサー率33% (2127/6289)
「'y'でない」または「'Y'でない」…(1) というのが、質問者さんが書かれているコードです。 ところが、実際に行ないたいことは 「'y'または'Y'」でない…(2) のようです。 (1)と(2)とは異なることに気づいてください。
- S117
- ベストアンサー率40% (18/45)
Cのプログラムを理解する第一歩は式を読むことです。 ans = (result != 'y') || (result != 'Y') result='y'とする。 ans = ('y' != 'y') || ('y' != 'Y') ans = 0 || 1 ans = 1 result='Y'とする。 ans = ('Y' != 'y') || ('Y' != 'Y') ans = 1 || 0 ans = 1 よって、'Y'でも'y'でも1(真)を返す。 では、どうすべきか。 >'y'または'Y'でない間 まさにこれをそのまま式に書くだけです。 ('y'または'Y')でない (result == 'y' || result == 'Y')でない !(result == 'y' || result == 'Y') もちろん、ド・モルガンの法則で (result != 'y' && result != 'Y') に変形してもいいでしょう。 この辺が怪しい場合は、むしろ数学の勉強が必要かもしれません。
補足
while(!(result=='y')||(result=='Y')){ で、行うと一度目にyを入れた場合はウマくいきますが、 一度目にnを入れて二度目で、名前確定のyをいれても ループします。 while((result != 'y') && (result != 'Y')){ こちらも、上と同じで一度目にyで確定だと成功しますが、nを入れた場合は 二度目のyで確定した後もループしてしまいます。 while((result=='y')||(result=='Y')){ で行うと、最初にyを入れた場合もループしてしまいます。 何が悪いのかさっぱりです。 自作のmake_character()側が悪いのでしょうか? こういった場合、if文ではなく、switch文で行ったほうがいいのでしょうか?
- asuncion
- ベストアンサー率33% (2127/6289)
>while((result!='y')||(result!='Y')){ この条件は正しいでしょうか? 'y'でない、「または」'Y'でない、 という条件だと、永久にループし続けるのは 当然だと思います。
補足
'y'または'Y'でない間(yが入力されるまで)としたくて!=をつかいました。
- precog
- ベストアンサー率22% (966/4314)
>int main() >{ >char result='n'; //初期化 >show_title(); >result=make_character(); >while((result!='y')||(result!='Y')){ resultが'y'のとき、前の項はFALSE, 後の項はTRUEです。結果はなんですか? resultが'Y'のとき、前の項はTRUE、後ろの項はFALSE、結果はなんですか? >make_character(); resultが更新されてないので式の評価結果は変化しません。 >} >return 0; >}
補足
((result!='y')||(result!='Y'))の条件式を一つにしても。だめでした 何が悪いのか、理解できないです
- bkbkb
- ベストアンサー率33% (97/289)
whileの条件が (result!='y')||(result!='Y') ですからwhileの前の result=make_character(); のところで多分yが帰ってきているので、ずっとwhileが動くでしょうね。 (result=='y')||(result=='Y') でもこうすると、 whileの前のresult=make_character();のところでyが返ってくるでしょうから、whileの中には入らない事になりますね。 ってことは whileの前のresult=make_character();も要らないことになります。
補足
make_characterの中の処理がわるいのでしょうか? あと、 >whileの前のresult=make_character();も要らないことになります。 これを取ると、make_characterが実行されず終わっていしまいます。
お礼
ありがとうございます。 目からうろこです。 これからも精進していきます。