質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

3回答

697閲覧

if文が実行されない

shimi43

総合スコア7

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/07/29 12:35

編集2019/07/29 12:47

前提・実現したいこと

人狼を作成しています。
その際の二日目の夜について挙動が予測とは違うものになってしまいました。
ゲーム的には2日目の朝の処刑の時点で終了していますが、そこはあまり気にしないでください。

発生している問題・エラーメッセージ

205~285行目のif文が実行されないので直したいです。 その前のほとんど同じ分を使ったif文は作動しました。 また、if文が終了した後にはprintf("人狼陣営の勝利です!")という文章は出力され、プログラムは終了しました。

該当のソースコード

c言語

1#include<stdio.h> 2#include<stdlib.h> 3#include<time.h> 4 5void Jinrou4(); 6void shuffle(); 7 8int main() 9{ 10 srand((unsigned) time(NULL)); /*時間によって同じ値が出ないようにする */ 11 int n; 12 int role; 13 Jinrou4(); 14} 15 16void Jinrou4(int argc, char **argv) 17{ 18 int utagai,uranai; 19 int player; 20 int player1=0,player2=0,player3=0,player4=0; 21 int kill=0; 22 printf("役職を決めます。"); 23 int values[] = { 1, 2, 3, 4 }; 24 int size = sizeof(values) / sizeof(int); 25 shuffle(values, size); 26 27 for ( int player = 0; player <= 3; player++) 28 { 29 30 printf("あなたはplayer%dです。\n",player+1); 31 printf("Enterを押してください。"); 32 while (getchar()!='\n') 33 { 34 printf(" "); 35 } 36 37 if (values[player]==1) 38 { 39 printf("あなたは人狼です\n"); 40 printf("特徴:夜に一人指定してコ〇すことができます。"); 41 42 }else if(values[player]==2) 43 { 44 printf("あなたは市民です\n"); 45 printf("特徴:なし"); 46 47 }else if(values[player]==3) 48 { 49 printf("あなたは市民です\n"); 50 printf("特徴:なし"); 51 52 }else if(values[player]==4) 53 { 54 printf("あなたは占い師です\n"); 55 printf("特徴:夜に一人指名して人狼か否かを確認できます。"); 56 57 } 58 printf("確認したらENTERを押してください"); 59 if(getchar()=='\n'){ 60 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); 61 } 62 63 } 64 65 for (int count = 0; count<20; count++) 66 { 67 printf("\n\n"); 68 } 69 printf("それではゲームを開始します\n初夜の殺害はできません\n"); 70 printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 一日目 夜 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 71 72 printf("それではplayer1から操作を行います。\n"); 73 for ( player = 0; player <= 3; player++) 74 { 75 printf("player%dに渡してください。",player+1); 76 printf("あなたがplayer%dならENTERを押してください。\n",player+1); 77 while (getchar()!='\n') 78 { 79 printf(" "); 80 } 81 if (values[player]==1) 82 { 83 printf("あなたは人狼です\n"); 84 printf("怪しいと思うplayerの番号を入力してください\n"); 85 scanf("%d-1",&utagai); 86 if (utagai==0) 87 { 88 player1++; 89 }else if (utagai==1) 90 { 91 player2++; 92 }else if (utagai==2) 93 { 94 player3++; 95 }else if (utagai==3) 96 { 97 player4++; 98 } 99 }else if(values[player]==2) 100 { 101 printf("あなたは市民です\n"); 102 printf("怪しいと思うplayerの番号を入力してください\n"); 103 scanf("%d",&utagai); 104 if (utagai==1) 105 { 106 player1++; 107 }else if (utagai==2) 108 { 109 player2++; 110 }else if (utagai==3) 111 { 112 player3++; 113 }else if (utagai==4) 114 { 115 player4++; 116 } 117 }else if(values[player]==3) 118 { 119 printf("あなたは市民です\n"); 120 printf("怪しいと思うplayerの番号を入力してください"); 121 scanf("%d",&utagai); 122 if (utagai==1) 123 { 124 player1++; 125 }else if (utagai==2) 126 { 127 player2++; 128 }else if (utagai==3) 129 { 130 player3++; 131 }else if (utagai==4) 132 { 133 player4++; 134 } 135 }else if(values[player]==4) 136 { 137 printf("あなたは占い師です\n"); 138 printf("占うplayerの番号を入力してください。\n"); 139 scanf("%d",&uranai); 140 if (values[uranai-1]==1) 141 { 142 printf("player%dは人狼です\n",uranai); 143 printf("特徴:夜に一人指定してコ〇すことができます。\n"); 144 145 }else if(values[uranai-1]==2) 146 { 147 printf("player%dは市民です\n",uranai); 148 printf("特徴:なし\n"); 149 150 }else if(values[uranai-1]==3) 151 { 152 printf("player%dは市民です\n",uranai); 153 printf("特徴:なし\n"); 154 155 }if(getchar()=='\n'){ 156 printf(" "); 157 } 158 } 159 printf("確認したらENTERを押してください\n"); 160 if(getchar()=='\n'){ 161 printf(" \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); 162 } 163 164 } 165 166 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); 167 printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 二日目 朝 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 168 printf("夜が明け朝になりました\n"); 169 if (player1<2&&player2<2&&player3<2&&player4<2) 170 { 171 printf("怪しまれている人物はいません。\n"); 172 }else if (player1>=2) 173 { 174 printf("怪しまれているのはplayer1です。\n"); 175 }else if (player2>=2) 176 { 177 printf("怪しまれているのはplayer2です。\n"); 178 }else if (player3>=2) 179 { 180 printf("怪しまれているのはplayer3です。\n"); 181 } 182 printf("それでは話しあって本日処刑する人を決めてください\n話し合いが終わったらENTERを押してください\n"); 183 while (getchar()!='\n') 184 { 185 printf(" "); 186 } 187 printf("処刑するplayerの番号を入力してください。\n"); 188 scanf("%d",&player); 189 if (values[player-1]==1) 190 { 191 printf("市民陣営の勝利です!\nおめでとうございます!\n"); 192 return ; 193 }else 194 { 195 printf("player%dが処刑されました…\n",player); 196 values[player-1]=0; 197 } 198 199 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); 200 printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 二日目 夜 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 201 printf("恐ろしい夜がやってきました\n"); 202 printf("夜の行動を行います\n"); 203 204 printf("それではplayer1から操作を行います。\n"); 205 for ( player = 0; player <= 3; player++) 206 { 207 printf("player%dに渡してください。",player+1); 208 printf("あなたがplayer%dならENTERを押してください。\n",player+1); 209 while (getchar()!='\n') 210 { 211 printf(" "); 212 } 213 214 if (values[player]==0) /*ここから下のif文が実行されません*/ 215 { 216 printf("役職:1->人狼 2,3->市民 4->占い師\n\nplayer1の役職は%d\nplayer2の役職は%d\nplayer3の役職は%d\nplayer4の役職は%d\nでした。\n",values[0],values[1],values[2],values[3]); 217 }else if (values[player]==1) 218 { 219 printf("あなたは人狼です\n"); 220 printf("殺害するplayerの番号を入力してください\n"); 221 scanf("%d",&kill); 222 printf("殺害するのはplayer%dです。\nENTERを押してください。",kill); 223 if(getchar()=='\n'){ 224 printf(" "); 225 } 226 }else if(values[player]==2) 227 { 228 printf("あなたは市民です\n"); 229 printf("怪しいと思うplayerの番号を入力してください\n"); 230 scanf("%d",&utagai); 231 if (utagai==1) 232 { 233 player1++; 234 }else if (utagai==2) 235 { 236 player2++; 237 }else if (utagai==3) 238 { 239 player3++; 240 }else if (utagai==4) 241 { 242 player4++; 243 } 244 }else if(values[player]==3) 245 { 246 printf("あなたは市民です\n"); 247 printf("怪しいと思うplayerの番号を入力してください"); 248 scanf("%d",&utagai); 249 if (utagai==1) 250 { 251 player1++; 252 }else if (utagai==2) 253 { 254 player2++; 255 }else if (utagai==3) 256 { 257 player3++; 258 }else if (utagai==4) 259 { 260 player4++; 261 } 262 }else if(values[player]==4) 263 { 264 printf("あなたは占い師です\n"); 265 printf("占うplayerの番号を入力してください。\n"); 266 scanf("%d",&uranai); 267 if (values[uranai-1]==1) 268 { 269 printf("player%dは人狼です\n",uranai); 270 printf("特徴:夜に一人指定してコ〇すことができます。\n"); 271 272 }else if(values[uranai-1]==2) 273 { 274 printf("player%dは市民です\n",uranai); 275 printf("特徴:なし\n"); 276 277 }else if(values[uranai-1]==3) 278 { 279 printf("player%dは市民です\n",uranai); 280 printf("特徴:なし\n"); 281 282 }else if(getchar()=='\n'){ 283 printf(" "); 284 } /*ここまでのif文です*/ 285 } 286 printf("確認したらENTERを押してください\n"); 287 if(getchar()=='\n'){ 288 printf(" \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); 289 } 290 291 } 292 293 printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 三日目 朝 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 294 printf("昨晩の犠牲者はplayer%dです。\n",kill); 295 printf("人狼陣営の勝利です!\nおめでとうございます!\n"); 296 return ; 297} 298 299void shuffle(int array[], int size) 300{ 301 int i = size; 302 while (i > 1) { 303 int j = rand() % i; 304 i--; 305 int t = array[i]; 306 array[i] = array[j]; 307 array[j] = t; 308 } 309} 310 311

試したこと

似た内容の初夜の行動で使ったif文が実行されたのでそれをコピペしてみましたが、実行されませんでした。

補足情報(FW/ツールのバージョンなど)

vscodeで書き、コマンドプロンプトで実行しています。
当方知識がないので他におかしな点があったら指摘していただいて構いません。
2回目の質問ですので至らない点はご容赦ください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/07/29 12:38

> 205~285行目のif文 というのはどこのことでしょうか
mather

2019/07/29 12:39

「ここから下のすべてのif文が実行されません」とありますが、プログラムが終了するかどうかも記載してください(おそらく終了しないのだと思いますが…)
shimi43

2019/07/29 12:42

ソースコードのコメントでここから下のif文が実行されませんと書いてあるところから下のすべてのif文のことです。 ご親切にありがとうございますm(_ _)m
jimbe

2019/07/29 12:45

巨大な1つの関数によって, 全体が見辛く(見えなく)なっているようです. 動作しないことを修正することは勿論必要ですが, 処理の区切れ毎等に関数化することで全体を整理・見易くすることで原因の究明と修正をやり易くすることも必要です.
shimi43

2019/07/29 12:50

皆さん返信ありがとうございます。 y_waiwaiさん、mathwrさんの指摘通り情報の追加は行いました。(つもりです) jimbeさんのご指摘についても検討させていただきます。 ありがとうございます。
mather

2019/07/29 12:51

加えてインデントがごちゃごちゃに混ざっているのでミスリーティングが多いです。 コードフォーマッターなどを使って修正したほうがミスに気づきやすいですよ。
shimi43

2019/07/29 12:53

了解しました。
jimbe

2019/07/30 17:21

いまさらですが, ご提示のコードはコンパイル出来ませんので「if文が実行されない」の原因はコードを見る限りでは見つかりません. if文が実行されなかった時のコードに修正して頂けますか.
guest

回答3

0

205~285行目のif文が実行されないので直したい

matherさんの回答の通り、いわゆる printf()デバッグを、質問者自身がやってみるべきだと思います。

C

1 }else if(getchar()=='\n'){ 2 printf(" "); 3 } /*ここまでのif文です*/

ここにelse節が無いので、matherさんのようにしてみるのが先決でしょう。
printf()デバッグは

  • プログラムがどこを通るのか
  • その時の変数値はいくつか

を確認するものです。デバッガを使うまでもなく、工夫次第で簡単に動作状況を調べられます。

他におかしな点があったら指摘していただいて構いません

・player1〜player4という4つの変数を、配列にしたほうがよい

これらは疑いをかけられた回数、各人の疑惑値を表すようです。
何番目の登場人物かを表す player という単純変数もあり、名前がかぶらないように、変数名を変えて、例えばこうしたらどうでしょうか。

C

1 int suspicion[4] = { 0, 0, 0, 0 }; // 各人の疑惑値

配列にすることで、次のような箇所は、

C

1 printf("あなたは人狼です\n"); 2 printf("怪しいと思うplayerの番号を入力してください\n"); 3 scanf("%d-1",&utagai); 4 if (utagai==0) 5 { 6 player1++; 7 }else if (utagai==1) 8 { 9 player2++; 10 ....

if 〜 else if 〜が不要になり、わずか一行で済みます。

C

1 printf("あなたは人狼です\n"); 2 printf("怪しいと思うplayerの番号を入力してください\n"); 3 scanf("%d", &utagai); 4 suspicion[utagai]++; // 疑われた人の疑惑値を +1 する

名前がかぶらないようにするのは、エディタ等で、特定の変数を探す・変数名を一括変換する、といった作業をがしやすくするためです。

変数名や関数名は、何のためにあるのか、何をするものか、という意味が伝わりやすい名前にするよう、心がけてください(私にとっても難しいですけどね)。
ここで配列にした場合、その値が何を意味するか(例:疑惑値)、配列の添え字(インデックス)は何を意味するか(例:プレーヤーを特定する)を整理してください。配列の添え字は、Cでは0から始まります。ユーザに0〜3を入力させるか、1〜4を入力させるか、も大事です。
データ設計が大事なことを忘れないように。

・values[player]の値は2でも3でも市民です。

C

1 }else if(values[player]==2) 2 { 3 printf("あなたは市民です\n"); 4 printf("特徴:なし"); 5 }else if(values[player]==3) 6 { 7 printf("あなたは市民です\n"); 8 printf("特徴:なし");

まずこうしましょう。

C

1 } else if (values[player] == 2 || values[player] == 3) { 2 printf("あなたは市民です\n"); 3 printf("特徴:なし"); 4 } else ....

ここに限らず if 〜 else if 〜 else を switch 〜 case に置き換えられる箇所がたくさんあります。こんな風に

C

1 switch (values[player]) { 2 case 1: 3 printf("あなたは人狼です\n"); 4 printf("特徴:夜に一人指定してコ〇すことができます。"); 5 break; 6 case 2: 7 case 3: 8 printf("あなたは市民です\n"); 9 printf("特徴:なし"); 10 break; 11 case 4: 12 printf("あなたは占い師です\n"); 13 printf("特徴:夜に一人指名して人狼か否かを確認できます。"); 14 break; 15 }

中カッコ { } の数がぐっと減ってすっきりしますし、if 文の条件に何度も出てくる values[player] == ? がひとつだけになり、分岐の意図が明確になります。

・これら case ラベルの 1, 2, 3, 4 は、人狼、市民、占い師を意味する値です。単なる整数値ではないので、マジックナンバーのままにするのではなく、例えば

C

1#define EXECUTED 0 // 処刑された 2#define JINROU 1 // 人狼 3#define CITIZEN1 2 // 市民1 4#define CITIZEN2 3 // 市民2 5#define DIVINER 4 // 占い師 6 または 7enum { EXECUTED, JINROU, CITIZEN1, CITIZEN2, DIVINER };

のようにした方が良くて、上の case ラベルはこんな風に書けます。

C

1 case JINROU: 2 case CITIZEN1: 3 case CITIZEN2: 4 case DIVINER:

・ここで、CITIZEN1 と CITIZEN2 の区別が要るのかどうか。同じ値でも良いのでは?それは私には判断できませんが、区別が要らない可能性があります。その場合、配列名 values(値)は他にも使いたくなりそうなので roles(役)に変えた上で、こんな風にするでしょう。

C

1 enum { EXECUTED, JINROU, CITIZEN, DIVINER }; 2 int roles[4] = { JINROU, CITIZEN, CITIZEN, DIVINER };

・player変数を用いた2種類の for 文には違いがあります。

C

1 int player; // (A) 2 3 for ( player = 0; player <= 3; player++) // (B) 4 for ( int player = 0; player <= 3; player++) // (C)

(B) の for 文は (A)で定義した player 変数を使いますが、
(C) の player 変数は (A) の player 変数ではありません。お分かりですか?
「if 文が実行されない」問題には関係ないと思いますが、不注意にこういうことをすると、思わぬバグに遭う危険性があります。

・player4 >= 2 の場合、何も表示しませんが、良いのでしょうか?

C

1 if (player1<2&&player2<2&&player3<2&&player4<2) 2 { 3 printf("怪しまれている人物はいません。\n"); 4 }else if (player1>=2) 5 { 6 printf("怪しまれているのはplayer1です。\n"); 7 }else if (player2>=2) 8 { 9 printf("怪しまれているのはplayer2です。\n"); 10 }else if (player3>=2) 11 { 12 printf("怪しまれているのはplayer3です。\n"); 13 }

・jinrou4() 関数は空行を含めて 280 行もあります。このあと、3日め、4日目と、ただダラダラと書き足しますか?
普通、関数は数十行程度に収めたほうが良いと言われます。まとまった処理を関数化して、見通しを良くすることは今後絶対に必要です。少しずつ関数化することをお勧めします。例えば

  • 初期化、初日、2日目…と場面が変わる毎に、それぞれを関数化・一般化するとか
  • 画面を更新する処理を関数化するとか
  • エンターキーを入力する処理を関数化するとか
  • 疑われている人の情報を表示する部分を関数化するとか etc.

・エンターキー入力に関して、

C

1 while (getchar()!='\n') // (A)タイプ 2 { 3 printf(" "); 4 } 5 6 if(getchar()=='\n'){ // (B)タイプ 7 printf("\n\n..."); 8 }

(A)タイプと(B)タイプがコード中に混在しています。心配なのは、(B) だとエンターキーでなくても処理が先に進んでしまうことです。関数化する際はついでに、こういう箇所でどうすべきか整理すると良いです。

投稿2019/07/30 09:57

編集2019/07/30 10:07
rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

以下のように else を付けてデバッグしてみてはいかがでしょうか。

c

1} else { 2 printf("DEBUG: player = %d\n", player); 3 printf("DEBUG: values[player] = %d\n", values[player]); 4}

投稿2019/07/29 13:04

mather

総合スコア6753

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

やばいところを示しておきます

void Jinrou4();

void shuffle();

実際の関数のプロトタイプ宣言とはなってません。
引数の型を明示してください。
また、Jinrou4の実行の際に引数を無視してるのもやばいです。
修正しましょう

そのうえで、動作がおかしい所があればまた言ってきましょう

投稿2019/07/29 12:59

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問