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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Clang

Clangは、プログラミング言語 C、C++、Objective-C、Objective-C++ 向けのコンパイラである。

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

Q&A

解決済

6回答

1075閲覧

C言語のcodingについて。このコードは読みやすいですか?

tyaaaaaaaaaaras

総合スコア134

C

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Clang

Clangは、プログラミング言語 C、C++、Objective-C、Objective-C++ 向けのコンパイラである。

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

0グッド

1クリップ

投稿2021/03/28 12:43

C言語のプログラムを作りました。
コードが読みやすいものなのかが自分ではわからないので質問します。
自分ではわかりやすいようにインデントなどをしっかりしたつもりですが、更に読みやすくするためにアドバイスがあればお願いします。
あとは、プログラムのいけないところ(書き方を変えたほうがいい部分)も指摘してほしいです。

これは小さなタイピングゲームです。

C

1#include<stdio.h> 2#include<stdlib.h> 3#include<time.h> 4#include<string.h> 5#include<unistd.h> 6 7int bangou; 8 9int main(void){ 10 11 #define moji answer = kotae; 12 13 int i; // counter of for statement 14 char kotae[30]; 15 char *answer; 16 int plan; 17 int score; 18 char *word1 = "hello"; 19 char *word2 = "world"; 20 char *word3 = "impossible"; 21 char *word4 = "knowledge"; 22 char *word5 = "capital"; 23 char *word6 = "overcome"; 24 char *word7 = "analysis"; 25 char *word8 = "station"; 26 char *word9 = "linux"; 27 char *word10 = "misunderstanding"; 28 29 srand((unsigned)time(NULL)); //usage : rand()%number + 1; 30 for ( ; ; ){ 31 plan = 5; // reset plan number 32 printf("Select plan below\n"); 33 printf("\n - Plan 1 : Start typing game!!!\n - Plan 2 : Quit program :(\n"); 34 printf("\n Input your plan : "); 35 scanf("%d",&plan); 36 if(plan == 1){ 37 score = 0; 38 printf("(((((------> 5 <------)))))\r"); 39 usleep(1 * 1000000); 40 printf("(((((------> 4 <------)))))\r"); 41 usleep(1 * 1000000); 42 printf("(((((------> 3 <------)))))\r"); 43 usleep(1 * 1000000); 44 printf("(((((------> 2 <------)))))\r"); 45 usleep(1 * 1000000); 46 printf("(((((------> 1 <------)))))\r"); 47 usleep(1 * 1000000); 48 printf("\n\n"); 49 for(i = 1; i < 11; i++){ // 10 times loop 50 answer = "l"; // reset answer 51 bangou = rand()%10 + 1; // get number for select random word 52 switch (bangou) { 53 case 1: 54 printf(" %s = ",word1); 55 scanf("%s",kotae); 56 moji; 57 printf("\n"); 58 if (strcmp(answer, word1) == 0){ 59 printf("Correct! XD\n\n"); 60 score += 10; 61 }else{ 62 printf("Incorrect... :(\n\n"); 63 } 64 usleep(1 * 1000000); 65 break; 66 case 2: 67 printf(" %s = ",word2); 68 scanf("%s",kotae); 69 moji; 70 printf("\n"); 71 if (strcmp(answer, word2) == 0) { 72 printf("Correct! XD\n\n"); 73 score += 10; 74 }else{ 75 printf("Incorrect... :(\n\n"); 76 } 77 usleep(1 * 1000000); 78 break; 79 case 3: 80 printf(" %s = ",word3); 81 scanf("%s",kotae); 82 moji; 83 printf("\n"); 84 if (strcmp(answer, word3) == 0) { 85 printf("Correct! XD\n\n"); 86 score += 10; 87 }else{ 88 printf("Incorrect... :(\n\n"); 89 } 90 usleep(1 * 1000000); 91 break; 92 case 4: 93 printf(" %s = ",word4); 94 scanf("%s",kotae); 95 moji; 96 printf("\n"); 97 if (strcmp(answer, word4) == 0) { 98 printf("Correct! XD\n\n"); 99 score += 10; 100 }else{ 101 printf("Incorrect... :(\n\n"); 102 } 103 usleep(1 * 1000000); 104 break; 105 case 5: 106 printf(" %s = ",word5); 107 scanf("%s",kotae); 108 moji; 109 printf("\n"); 110 if (strcmp(answer, word5) == 0) { 111 printf("Correct! XD\n\n"); 112 score += 10; 113 }else{ 114 printf("Incorrect... :(\n\n"); 115 } 116 usleep(1 * 1000000); 117 break; 118 case 6: 119 printf(" %s = ",word6); 120 scanf("%s",kotae); 121 moji; 122 printf("\n"); 123 if (strcmp(answer, word6) == 0) { 124 printf("Correct! XD\n\n"); 125 score += 10; 126 }else{ 127 printf("Incorrect... :(\n\n"); 128 } 129 usleep(1 * 1000000); 130 break; 131 case 7: 132 printf(" %s = ",word7); 133 scanf("%s",kotae); 134 moji; 135 printf("\n"); 136 if (strcmp(answer, word7) == 0) { 137 printf("Correct! XD\n\n"); 138 score += 10; 139 }else{ 140 printf("Incorrect... :(\n\n"); 141 } 142 usleep(1 * 1000000); 143 break; 144 case 8: 145 printf(" %s = ",word8); 146 scanf("%s",kotae); 147 moji; 148 printf("\n"); 149 if (strcmp(answer, word8) == 0) { 150 printf("Correct! XD\n\n"); 151 score += 10; 152 }else{ 153 printf("Incorrect... :(\n\n"); 154 } 155 usleep(1 * 1000000); 156 break; 157 case 9: 158 printf(" %s = ",word9); 159 scanf("%s",kotae); 160 moji; 161 printf("\n"); 162 if (strcmp(answer, word9) == 0) { 163 printf("Correct! XD\n\n"); 164 score += 10; 165 }else{ 166 printf("Incorrect... :(\n\n"); 167 } 168 usleep(1 * 1000000); 169 break; 170 case 10: 171 printf(" %s = ",word10); 172 scanf("%s",kotae); 173 moji; 174 printf("\n"); 175 if (strcmp(answer, word10) == 0) { 176 printf("Correct! XD\n\n"); 177 score += 10; 178 }else{ 179 printf("Incorrect... :(\n\n"); 180 } 181 usleep(1 * 1000000); 182 break; 183 default: 184 break; 185 } 186 } 187 }else{ 188 break; 189 } 190 printf("Max score is 100. Your score is %d. \n\n", score); // display result 191 } 192 return 0; 193}

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

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

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

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

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

guest

回答6

0

ご質問のプログラムは短いので、努力すれば読んでコメントすることも可能でしょうが、
少し長いプログラムになったら、
・何を目的とするか
・何を考慮したか(メモリ消費量、処理時間、わかり易さ、同一システムの他プログラムとの整合性など)
・入力と出力
このような事項が不明だとコメント出来ない場合が多いでしょう。
「何故、このように書いてあるのか?」が分からないので。

私見では、「分かりやすいプログラム」とは
普通のプログラマが普通に発想するように書かれてているもの
と思います。

ほぼ同じ処理を10個のcase で書かれると、
「何か意味があるのではないか?」
と考えざるを得ません。
で、10個のcaseの中身をじっくり読んでいくと、「定数が違うだけ? じゃ、何故10個も書いたの?
わからん?」
と悩むことになります。
「ひょっとして、10個の内、どこかに違う処理をしてる所があるのではないか?」
とか、
「それぞれのcaseで処理を変えなきゃダメなのを間違って同じにしてるのでは?」
と疑ってプログラムを読むのは非常に苦労します。
結果が「なんだ、おんなじじゃん!」分かったときの疲労感は半端ないです。

まず、普通の書き方ができるようになって下さい。

投稿2021/03/29 02:12

nob.

総合スコア711

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

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

dodox86

2021/03/29 02:24 編集

> 私見では、「分かりやすいプログラム」とは > 普通のプログラマが普通に発想するように書かれてているもの > と思います。 > ほぼ同じ処理を10個のcase で書かれると、 > 「何か意味があるのではないか?」 > と考えざるを得ません。 高評価させていただきました。私もこのコードを読んで真っ先に思いました。これが製品のコードで、それを書いた本人が不在であるとき、私であればこれらの部分を目視ではなく、10個のファイルに分割してファイル比較を行い、確認すると思います。(勘弁してほしい) 共通の関数になっていれば、それすなわち「引数部分が可変で、処理は共通なのだな。」とのプログラマーの意思表示になりますね。
K_3578

2021/03/29 02:43

高評価理由:同上
fana

2021/03/29 03:22

同上
tyaaaaaaaaaaras

2021/03/30 12:41

皆さんありがとうございます。 これからはそれを意識していきます
guest

0

長いコードは(大抵)間違っています(あるいは今後間違います).

投稿2021/03/29 01:41

編集2021/03/29 01:42
episteme

総合スコア16614

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

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

guest

0

考えてから書いてますか?
考えながら書いてますか?
考えずにその場の勢いで書いてますか?

下2つなら即改めてください。

投稿2021/03/29 00:29

m.ts10806

総合スコア80850

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

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

K_3578

2021/03/29 00:53

せめてどう改めればいいかは書いてあげた方が良いのでは・・・と思いましたけど 過去質問、回答見るに言っても聞かなそうなのでこのままで良いですかね・・・。
dodox86

2021/03/29 01:05 編集

> 過去質問、回答見るに言っても聞かなそうなのでこのままで良いですかね・・・。 コードレビュー相当の質問については過去に指摘済みのようですし。コードレビューだとしても、質問の仕方によっては有意義なやり取りになると思うのですが、さて、今回はどうでしょうと言うかんじでしょうか。 [C言語です。採点お願いします。] https://teratail.com/questions/308607
K_3578

2021/03/29 01:08

というか指摘されてもBAだけ付けて反応もしないのか・・・。 なんか数年前の質問に既に回答されてる内容を回答してマイナス大量に食らってるし何がしたいのか よく分かりませんねこの質問者・・・。
fana

2021/03/29 01:21

全く同じ処理を延々とcase 10まで書ききったわけで,そこにはきっと結構な「勢い」があっただろう,と想像. (ふつーの勢いだとせいぜいcase2か3あたりで失速して自身の行いに疑問を持つに至るだろうと思う)
m.ts10806

2021/03/29 01:23

「読むに耐えない」だけにしようか悩んだ結果みなさん回答したんじゃないかなと。 レビューするには観点がハッキリしないし、指摘してたらきりがない内容なので、好みを書くより「まずコードを書くスタンスを改めて」と。 次点で「想定通り動いてるならそれでいいんじゃない?」「自分が読みにくいと思ったならまずやれるところまでやってみたら?」 あたり。 レビュー依頼にしても丸投げなので、どこまで尽くしたのかくらいは書いてもらいたいですね。指摘しても書かなそうだから仕方なく回答してる人も中にはいるはず。
K_3578

2021/03/29 05:02 編集

※質問者の編集前のコメント【:(){ :|:& };:】 に対してコメントしています。 んで、Fork爆弾なんかコメントしてる暇が有ったら回答参考にして修正してみたらどうでしょうか。
m.ts10806

2021/03/29 10:57

通報案件ですねぇ。
tyaaaaaaaaaaras

2021/03/30 17:05

通報案件ですねぇ。 通報案件ですねぇ。
tyaaaaaaaaaaras

2021/03/30 17:06

通報案件ですねぇ。 通報案件ですねぇ。 通報案件ですねぇ。
tyaaaaaaaaaaras

2021/03/31 02:07

あなたらはただそう人を避難ばかりして優越感に浸っているだけですか? かわいそうに... いいですよ?どんどん通報してくださいw アカウントなんてBANされてもまた作るのみ。 Googleアカウントが無限に作れるようにテラテイルのアカウントだって無限に作れますw ここはただの質問サイト、インスタやツイッターのようにアカウントを大切にする必要はありませんねw
dodox86

2021/03/31 02:13

@質問者tyaaaaaaaaaarasさん > Googleアカウントが無限に作れるようにテラテイルのアカウントだって無限に作れますw > ここはただの質問サイト、インスタやツイッターのようにアカウントを大切にする必要はありませんねw 好奇心でお聞きしますが、これはrubato6809さんの回答のコメント欄[2021/03/31 11:03]のコメント: > 自分はいつも疑問を試したり調べないまま人に聞いてしまいます。最近特に意識して治そうとしているのですが、まだまだ思うように自分を制御?できないままいます。 と同じような理由による発言ですか?
K_3578

2021/03/31 02:17

>あなたらはただそう人を避難ばかりして優越感に浸っているだけですか? 優越感には浸ってませんがFork爆弾なんて言う物を久々に見て懐古に浸りました。
dodox86

2021/03/31 02:20

[2021/03/31 11:16]のコメントより: > ん?質問の意味がわかりません 自らが不利になるような暴言をなぜわざわざ投稿するのか、その理由はどこからくるのか、と言う質問です。他回答者さんのコメント欄であり、あくまで私の好奇心なので、必ずしもレスをいただかなくても結構です。
K_3578

2021/03/31 02:24

>Fork爆弾w 面白い発想です [2021/03/29 11:46]のコメントで編集前にそのようなコメントをされていたのは質問者氏ですが 覚えておられないのでしょうか。
tyaaaaaaaaaaras

2021/03/31 02:26

わからないものを求められることに苛立ちました。 わからないものを勉強しにきたのに 確かにプロからすれば苛立つほどクソなコードなのかもしれないけど、自分だってはじめはそうだったくせに、それに対してなぜ馬鹿にするような口調で回答するのか、
dodox86

2021/03/31 02:33 編集

[2021/03/31 11:26]のコメントより: > わからないものを求められることに苛立ちました。 なるほど、レスをいただき、どうもありがとうございます。反論の主旨に感情が勝ってしまったのですね。その点において理解しました。(一部誤字修正済み)
m.ts10806

2021/03/31 02:34

「プログラミング初心者だからルール守らなくていい」と書いてある公式の場所をご提示ください。
tyaaaaaaaaaaras

2021/03/31 02:42 編集

┈┈┈┈▅┈┈▕▀┈┈┈┈┈ ┈┈┈▕┈┈┈╱╲▕▀┈┈ ┈┈┈╱╲┈┈▏▕╱╲┈ ┈┈┈▏▕╱╲▏▎▏▕╱╲┈▃ ┈╱╲▏▎▅▂▅▂▏▎▏▎▏▏ ▂▏▎▏▕╭┳┳╮▏┊▏▕╱╲ ▏▏┊▏▎┃┊┊┃▏▎▏▎▏▕ ▇▆▅▃▂┻┻┻┻▂▃▅▆▇▉
K_3578

2021/03/31 02:38

自分に対してのコメントではないでしょうが、 >わからないものを求められることに苛立ちました。 わからないものを勉強しにきたのに 確かにプロからすれば苛立つほどクソなコードなのかもしれないけど、自分だってはじめはそうだったくせに、それに対してなぜ馬鹿にするような口調で回答するのか、 わからないなりに真摯に向き合うべきでしたね。それは回答者に対してもですし、 このサイトに対してもです。別に最初から非難されていた訳ではないですよね。 その時に受けた指摘を冷静に受け止めて、活かしていれば少なくとも質問にマイナスが大量に 付くような事にはならなかったでしょう。 貴方が本気で勉強したいと思うならアカウント新規に作るなんて事はやめて今のアカウントで 汚名返上出来るように丁寧な質問を心掛ける事です。 理由は何にせよ、無意味なコメントを連投したりしている時点で今の貴方は「荒らし」でしかありません。
tyaaaaaaaaaaras

2021/03/31 02:41

なぜ僕をそこまで正そうとするのか、 僕なんて見捨てておけばいいのに
m.ts10806

2021/03/31 02:42

誰に対して返信してるかわかりませんが、「技術的には可能でもルールや法ではNGであること」はプログラミング限らず一般常識の範囲です。 自動車道路の逆走がいい例でしょう。煽り運転とか。 あなたがやってるのはそれらと同じです。 あなたはそこを突かれて暴れてるだけですね。バカ以前の問題です。
tyaaaaaaaaaaras

2021/03/31 02:43 編集

その馬鹿以前に対して真剣に陳述するあなたのコメントが面白いです。
m.ts10806

2021/03/31 02:44

技術は間違った使い方すると人に多大な迷惑かけますしね。見捨ててほしいならそもそもコミュニティ使わないでください。 厚意を踏みにじって遊んでるだけに見えます。
tyaaaaaaaaaaras

2021/03/31 02:46

厚意があるならなぜ馬鹿にした口調で回答するか あなたに限らず 1行だけ「◯◯が◯◯じゃない時点で話にならん」 これは解決策にはなっていない
K_3578

2021/03/31 02:47

>なぜ僕をそこまで正そうとするのか、 僕なんて見捨てておけばいいのに 個人的に自分を見つめ直す機会さえあればやり直せそうだなーと感覚的に思ったからですかね。 後はそういう気分だったからです。
tyaaaaaaaaaaras

2021/03/31 02:47

僕の何処かの質問でこのようなかいとうがついたはず
tyaaaaaaaaaaras

2021/03/31 02:49 編集

K_3578さん そうなんですね。ありがとうございます そんなふうにして頂いたのは初めてです
tyaaaaaaaaaaras

2021/03/31 02:49

てか、ここのコメント欄がかなりカオスなことになっているんでこの質問ごと消したいんですが...
tyaaaaaaaaaaras

2021/03/31 02:50 編集

質問を消すための条件を満たしていないみたい
K_3578

2021/03/31 02:57 編集

>この質問ごと消したいんですが... 回答が付いている質問は基本的に削除出来ません 回答者、並びにコメントされた方に通知が邪魔かと思われますので私は以降コメントしません。
tyaaaaaaaaaaras

2021/03/31 12:53

わかりました。では僕ももうコメントしません。最後に言っておきますが、 >貴方が本気で勉強したいと思うならアカウント新規に作るなんて事はやめて今のアカウントで 汚名返上出来るように丁寧な質問を心掛ける事です。 今アカウントを変えても僕のコードのクオリティじゃどうせまた同じようなことになるだけですからBANされるまではこのアカウントつかいますよ
dodox86

2021/03/31 13:18

@質問者 tyaaaaaaaaaarasさん > 今アカウントを変えても僕のコードのクオリティじゃどうせまた同じようなことになるだけですから そういうことではなく、本サイトを使う上ではガイドラインがあるのですから、推奨されない質問、つまりは「「問題・課題が含まれていない質問」と指摘されたことは止めましょう、と言うことなのです。非推奨イコール禁止ではない、と反論することはできますが、その姿勢が多くの人に受け入れられるか、という問題があります。そういった質問でも時に/興味深いことに多くの有意義な回答を集めることはありますが、批判も同時にあり得ることは覚悟しなければなりません。力足らぬ回答者の一人ですが、これが伝わって次への糧になれば幸いです。 ただ、「わからないものを求められることに苛立ちました。」と言う質問者tyaaaaaaaaaarasさんの正直であろう考えが分かったことは、少なくとも私にとっては有意義でした。どうもありがとうございます。私からも、コメントは以上です。
m.ts10806

2021/04/01 04:23

好意 と 厚意 間違ってるからこうなる。
tyaaaaaaaaaaras

2021/04/01 20:22

(oo) /-------/ O / | || /o)\ /H\ * ||----|| (o/ / \ ~~ ~~
guest

0

同じ処理をだらだらと何度も書いていることは既に指摘がありますね。

全部main関数にぶっこまない。適宜作業を関数に切り出しましょう。極論、mainは

int main(void){ アレして(); コレして(); どうする(); return 0; }

みたいな粒度が好きです。

#define moji answer = kotae;
このマクロはダメでしょう。mojiという名前からなにをしているのか全然想像できないし、単なる代入をマクロで書くものでもない。

しかも、answerにkotaeを代入してなにかいいことがあるかというと全然ないし。kotae, answerの登場シーンはここだけ

scanf("%s",kotae); moji; printf("\n"); if (strcmp(answer, word1) == 0){

これなら、

scanf("%s",kotae); printf("\n"); if (strcmp(kotae, word1) == 0){

で十分。
もしかして、配列が単独で記述されると配列の先頭要素へのポインタと解釈されることを知らなくて、strcmpに与えるためだけにchar*型のanswerに代入したのでしょうか?

for(i = 1; i < 11; i++){ // 10 times loop
とりあえず見た瞬間に「なんだこりゃ」と思いますね。「普通」は
for(i = 0; i < 10; i++){ // 10 times loop
と書くんじゃないかなぁ。慣習の問題として。

answer = "l"; // reset answer
"l"にはどういう意味が? (先述のようにanswer自体が不要じゃないかというのもあるけれど)

投稿2021/03/28 13:31

thkana

総合スコア7639

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

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

tyaaaaaaaaaaras

2021/03/29 10:04 編集

forループの中身は、”number(i) 問題”と画面に出るようにしようとしていました。 10問出題されますがその問題番号が自然数である必要がありましたが最終的にその機能をつけ忘れてしましました。 answerに”l”を代入したのは、2連続で同じ問題が選ばれた場合に2回めに何も入力せずにエンターキーを押したら前回の回答が適用されてしまうと思ったからです。この1文は必要ないのですか?
thkana

2021/03/29 11:05

10回繰り返す、は普通 for(int i=0;i<10;i++){} と書くでしょうし、1~10なら、 for(int i=1;i<=10;i++){} じゃないですかね。(i=1;i<11;i++)は見慣れないです。 > 最終的にその機能をつけ忘れてしましました。 それが検出されるだけの資料とともにレビューしなきゃ意味ないということです。 > 2回めに何も入力せずにエンターキーを押したら前回の回答が適用されてしまう 本当にそうなのですか? そうだったとしても、なぜ"l"なのですか? ""であればまだわかりますが。
tyaaaaaaaaaaras

2021/03/30 12:57

""でできるんですか? それは知りませんでした。
guest

0

wordなんたら、を配列にしてしまえば、延々とcase並べなくてもforループでまとめれそうだが。

printf(" %s = ",word[bangou]);

投稿2021/03/28 12:46

編集2021/03/28 12:48
y_waiwai

総合スコア87774

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

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

tyaaaaaaaaaaras

2021/03/29 09:58

ありがとうございます! そこに気づきませんでした...
guest

0

ベストアンサー

一番の難点は、y_waiwaiさんが指摘された通り、10個の文字列を配列にしなかったことです。これで各 case ラベルに、ほぼ同じコードを10回繰り返してしまい、長大な switch 文になってしまった。
文字列配列にすれば switch case は不要になります。もちろん、そうしたほうがわかりやすい。何よりも行数が大きく減るので見通しがスッキリします。
次のような書き方を覚えましょう。この場合 word はポインタの配列です。

char *word[] = { "hello", "world", "impossible", "knowledge", "capital", "overcome", "analysis", "station", "linux", "misunderstanding", };
#define moji answer = kotae;

このマクロに対する thkanaさんの指摘に加えて私は2つ言いたいことがあります。

  • ここにセミコロン「;」を書いてはいけない
  • マクロ名には大文字を使おう。moji ではなく MOJI に・・・

いや、これをマクロにする意味はありません。
「 answer = kotae; 」という単純な代入をマクロにしたら、かえって複雑になる・・・というだけでなく、thkana さんの指摘通り、そもそもポインタ変数 answer を設ける必要性が無いのだから。

私なら、一秒待ちをするところ、大きな数字(1000000)を隠したくなったので、次のようにするかも。

#define WAIT_SECONDS(n) usleep((n) * 1000000) // 1秒待ち

毎回「1 * 1000000」としたのは1秒を意識したと思う。使われているのは全て1秒だけだから引数は無くてもよいが、あえて引数付が良いと思う。

グローバル変数 int bangou; ???こんな変数を安易にグローバルにしてはいけません。

  • plan = 5; としておいて、scanf("%d", &plan); とする
  • answer = "1"; としておいて、answer = kotae; とする

どちらも最初に値を代入しておく必要が無いのに代入するのは全くのムダです。

今時のコンパイラならC99標準をサポートしているはずなので、たとえば
「for (int i = 0; i < 10; ++i) 」と書けませんか?
それと関係して、変数はできるだけ変数のスコープを意識したほうが良いです。その変数が必要なブロック内で変数定義する・使う場所の近くで変数定義する、使う場所の近くで値を代入する(score = 0; と score += 10; をできるだけ近づける等)といったことです。

for (;;) { // .... if(plan == 1){ // ゲームをする else break; // plan != 1 で無限ループ脱出 }

という構造・break 文の位置は見直すべきです。こうすれば良い。

for (;;) { // .... if (plan != 1) break; // 1でないので終了 // ゲームをする }

こうすると「ゲームをする」処理のインデントを一段浅くできます。インデントが浅いほうが読みやすいというのが一般原則です。

printf("(((((------> 5 <------)))))\r"); usleep(1 * 1000000); printf("(((((------> 4 <------)))))\r"); usleep(1 * 1000000); printf("(((((------> 3 <------)))))\r"); usleep(1 * 1000000);

これは所謂カウントダウン表示です。5, 4, 3, 2, 1 と減る、という規則性があるのだから、こう書けます。

for (int i = 5; i > 0; --i) { printf("(((((------> %d <------)))))\r", i); WAIT_SECONDS(1); // 1秒間隔で繰り返す }

・・・といった辺りで、関数に分割することはしてないし、マジックナンバを整理したいし、変数名などもう少しブラッシュアップしたいなど心残りがあるけど、書き直してみました。N_WORDS はタイプさせる文字列の数を増やしたい場合もあるかなという、よくある工夫です。

#include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #include <unistd.h> #define WAIT_SECONDS(n) usleep((n) * 1000000) #define N_WORDS (sizeof(word) / sizeof(word[0])) char *word[] = { "hello", "world", "impossible", "knowledge", "capital", "overcome", "analysis", "station", "linux", "misunderstanding", }; int main(void) { srand((unsigned)time(NULL)); // 乱数列を初期化 for (;;) { printf("Select plan below\n" // 実行画面と対応しやすくした "\n" "- Plan 1 : Start typing game!!!\n" "- Plan 2 : Quit program :(\n" "\n" " Input your plan : "); int plan; scanf("%d", &plan); if (plan != 1) break; // 1 でなければゲーム終了 // 画面にカウントダウン (5, 4, 3, 2 and 1) for (int i = 5; i > 0; --i) { printf("(((((------> %d <------)))))\r", i); WAIT_SECONDS(1); // 1秒間隔で繰り返し } printf("\n\n"); int score = 0; // 得点を0にし、ゲーム開始 for (int i = 0; i < 10; i++) { // 10回繰り返し int bangou = rand() % N_WORDS; // 乱数(0 .. N_WORDS - 1) printf(" %s = ", word[bangou]); // タイプさせる単語 char kotae[30]; scanf("%s", kotae); // 単語をタイプする printf("\n"); if (strcmp(kotae, word[bangou]) == 0) { printf("Correct! XD\n\n"); // 打ち間違い無し score += 10; // 10点加算 } else { printf("Incorrect... :(\n\n"); // 打ち間違いあり、加算無し } WAIT_SECONDS(1); // 1秒待つ } // 10回分の得点を表示 printf("Max score is 100. Your score is %d. \n\n", score); } return 0; }

次の課題は関数に分割することかな。ということで残念ながらツッコミどころ満載のコードでした。まだ先は長いですね。
Enjoy!


配列 word[] をグローバル変数にした件ですが、強い理由はありません。普通ならローカル変数にするものです。修正を始めた時に関数の外に配列を書いたのですが、見た感じおさまりがよかったのでそのままにしました。
もう少し言うと、元コードにあったグローバル変数 int bangou; はユーザが意識するようなデータではありません。「今、"hello" をタイプさせられているからには bangou は1になってるはずだ」なんて考えません、bangou の存在さえ意識しないでしょう。bangou は処理内部のための、隠れた存在です。
一方、 配列 word はユーザが否応なく目にするデータ("hello"などの文字列)を抱えているので、プログラムの外観=外部仕様に関わるデータと言えます。その分他の変数よりエライ、グローバルにするなら bangou より word が相応しい・・・みたいな気持ちです。

C

1#define N_WORDS (sizeof(word) / sizeof(word[0])) 2char *word[] = { 3 "hello", "world", "impossible", "knowledge", "capital",

このマクロは配列の要素数をコンパイラに計算させます。一要素分のところに型名を書くこともあります。
「#define N_WORDS (sizeof(word) / sizeof(char*))」みたいに。

元のプログラムでは文字列を10個用意しますが、ずっと10個とは限らない事があるものです。文字列を増やしたい(減らしたいこともあるか)時、配列の初期値として並べて書いてる文字列=初期値を書き足すだけで良い、またそうするために「char *word[10] = { ...」とも「char *word[N_WORDS] = { ...」とも書かず、要素数を空欄にするわけ。

N_WORDS = (配列全体のバイト数 ÷ 一要素分のサイズ) 。32bit機のポインタ変数は4byte長、64bit機のポインタ変数は8byte長です。64bit機で配列word全体が80byteだから、N_WORDS = 80 ÷ 8 = 10 ・・・でも問題は、word がポインタの配列であることとか、ポインタの姿を正確にイメージできていないとか、ポインタにまつわる文法だとか、その辺りがあやふやみたいですね、ありがちだけど。でもそれは別の質問にしてもらったほうがよいかなあ。

投稿2021/03/28 18:13

編集2021/04/05 23:54
rubato6809

総合スコア1380

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

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

tyaaaaaaaaaaras

2021/03/29 10:25

ありがとうございます! とてもわかりやすかったです! 一つ質問があります。charの配列をグローバル変数にしている理由が知りたいです。 main関数の中に書いたら正しく動作しないんですか?
rubato6809

2021/03/29 12:49

> main関数の中に書いたら正しく動作しないんですか? それは私に聞かなくても判断できるんじゃありませんか?
tyaaaaaaaaaaras

2021/03/30 17:05 編集

#define N_WORDS (sizeof(word) / sizeof(word[0])) このマクロを実行できるのためにmain関数の外にあるということですか?
rubato6809

2021/03/30 20:35

・charの配列をグローバル変数にした理由は何か? これはもっともな疑問です。よいツッコミだと思う。でも、そのあとがいただけない。 ・配列をmain関数の中に書いたら正しく動作しないのか? ・配列をmain関数の中に書いたらマクロが実行できないのか? 2つとも、質問者は自分で試したうえで質問したのですか?試すより先に思いついたことを聞いてみよう…というような質問文なのですよ。だとしたら学習者の態度として問題じゃないですか? 私からすりゃ、そんなのさっさと自分で書きなおして・コンパイルして・動かしてみりゃ、どうなるかわかるでしょ?あなたの手元にはCコンパイラがあるのだから・・・なんですが。
tyaaaaaaaaaaras

2021/03/31 02:13 編集

すいませんでした。 本当にあなたのおっしゃるとおりです。 自分はいつも疑問を試したり調べないまま人に聞いてしまいます。これがとても失礼なことだとわかっていて、最近特に意識して治そうとしているのですが、まだまだ思うように自分を制御?できないままいます。今後はより一層自分で調べたり試したりすることを意識していきます。 まずは自分で試してみます。
tyaaaaaaaaaaras

2021/04/01 03:02 編集

両方共に正しく動作しました。 なのでなおさらグローバル変数にした理由がわかりません。 ですがその前に、2個めのマクロの、”#define N_WORDS (sizeof(word) / sizeof(word[0]))” この1文が理解できません。プログラムを少し改良して "printf("%ld", sizeof(word));"の文を追加して実行してみたところ、”word”の大きさは”80”と出ました。これはなぜですか? ”#define N_WORDS (sizeof(word) / sizeof(word[0]))”この文章の右側のword[0]は”hello”なので大きさは5ですよね。なので80÷5でこのマクロの結果は16のはずです。 そして int bangouに乱数を格納させる際の ”int bangou = rand() % N_WORDS;” この1文、乱数を16で割った場合、1〜15が出るはずなのに用意してある単語数は全部で10個です。 どうしても理解ができないです。 このプログラムの2つ目のマクロについて説明してほしいです。お願いします。
rubato6809

2021/04/01 07:58 編集

そうです。word[] 配列をグローバル変数にしなければならない理由はありません、int bangou; がグローバルでなくてもよかったように。というか、普通はローカル変数にするものでしょう。これについては後で。 sizeof 演算子は、その変数・型がメモリ上で何バイトを占めるのか、バイト数を返します。sizeof(word) は、配列 word のメモリサイズ(=要素数10個分のバイトサイズ)が値です。配列 word は、要素数10で、全体が80バイトですから、一要素のサイズは8バイトなのです。64bitマシンですから8バイトなのは合点がいきます。 さて、 > 右側のword[0]は”hello”なので大きさは5ですよね そこに典型的な誤解・誤りがあります。試しに次の一行を追加してみてください。どんな値が表示されますか?あなたの考え方なら3つとも違う値が表示されそうだけど・・・まずそこからですね。 printf("%ld %ld %ld\n", sizeof(word[0]), sizeof(word[5]), sizeof(word[9]));
rubato6809

2021/04/01 22:21

子供じみたことをする暇があるなら、質問者自身のコードを元に char *word1 = "hello"; char *word3 = "impossible"; printf("%ld %ld\n", sizeof(*word1), sizeof(*word3)); printf("%ld %ld\n", sizeof(word1), sizeof(word3)); くらいは確かめてみても良いのではないか。
rubato6809

2021/04/01 22:27

sizeof と strlen() の違いも面白いかな。 printf("%ld %ld\n", sizeof("hello"), strlen("hello")); みたいな。
tyaaaaaaaaaaras

2021/04/03 03:37

違います。無視しているわけではないんです。 この2日間本当にとても忙しかったんです。コメントでお知らせできなかったことをごめんなさい。 もちろん試します。もちろんです。少しだけ待ってください。
tyaaaaaaaaaaras

2021/04/03 23:13 編集

明日試す時間が有るのでそれでまたコメントします
tyaaaaaaaaaaras

2021/04/04 13:40 編集

遅くなってしまいすみません。 >そこに典型的な誤解・誤りがあります。試しに次の一行を追加してみてください。 >printf("%ld %ld %ld\n", sizeof(word[0]), sizeof(word[5]), sizeof(word[9])); この行を追加してみました。結果はすべて 8 でした。 これは宣言して時点で8バイトが確保されていたということですか? -------------------------------------------------------- >子供じみたことをする暇があるなら、質問者自身のコードを元に >char *word1 = "hello"; >char *word3 = "impossible"; >printf("%ld %ld\n", sizeof(*word1), sizeof(*word3)); >printf("%ld %ld\n", sizeof(word1), sizeof(word3)); >くらいは確かめてみても良いのではないか。 結果はchar型ポインタが1バイト、普通のchar型が8バイトでした。 これはなぜなのかがわからず、下の2行を貼り付けて実行してみました。 printf("%d",(*word1) ); printf("\n%d", (*word3)); ↓実行↓ 104 1056 5 更に意味がわからなくなってしまいました。 これはword1とword3それぞれのchar型とchar型ポインタに入っている物が違うのですか? 教えてほしいです。お願いします。 -------------------------------------------------------- >sizeof と strlen() の違いも面白いかな。 >printf("%ld %ld\n", sizeof("hello"), strlen("hello")); みたいな。 sizeofでは6バイト、strlenでは5バイトでした。 sizeofはヌル文字を含められていて、strlenではヌル文字は含まれていないので1バイトの差があるのですね!
rubato6809

2021/04/04 22:57 編集

> これは宣言して時点で8バイトが確保されていたということですか? その通り。私の回答に「wordはポインタの配列です」と最初から書いてある。 ポインタのサイズは8。だって64bitマシンだから。 「宣言して時点」・・・間違い 「宣言した時点」・・・正しい > strlenではヌル文字は含まれていないので1バイトの差がある その通り。文字列には必ず終端文字('\0')があるから、「文字列のメモリ上のサイズ」と言ったらヌル文字を含んだバイト数になる。 > 更に意味がわからなくなってしまいました。 こういうことです。 104 = 0x68 = 'h' ・・・"hello" の先頭文字 h のアスキーコード値が 104 105 = 0x69 = 'i' ・・・"impossible" の先頭文字 i のアスキーコード値が 105 さらに、105 に続けてprintf("%ld %ld\n", sizeof("hello"), strlen("hello"));の表示「6 5」がくっついたから「1056 5」と表示されたに違いない。 > 結果はchar型ポインタが1バイト、普通のchar型が8バイト これには驚いた。見事に逆だから。 サイズが8と表示された方がchar型ポインタ変数です。 char *word1 = "hello"; は char * word1; word1 = "hello"; と、2つに分解できることを思い出そう。 word1 はポインタ変数である。その値は "hello" という文字列の先頭アドレス、すなわち h という文字があるメモリのアドレスである。 従って、printf() で表示しようとした「*word1」の値は 'h'、すなわち 104 であった。 もし word1 ポインタの値を確認したければ、たとえばこうしなさい。 printf("%p\n", word1);
tyaaaaaaaaaaras

2021/04/16 17:38 編集

>こういうことです。 >104 = 0x68 = 'h' ・・・"hello" の先頭文字 h のアスキーコード値が 104 >105 = 0x69 = 'i' ・・・"impossible" の先頭文字 i のアスキーコード値が 105 >さらに、105 に続けてprintf("%ld %ld\n", sizeof("hello"), strlen("hello"));の表示「6 5」がくっついたから「1056 5」と表示されたに違いない。 なるほどですね!凄すぎます…
tyaaaaaaaaaaras

2021/04/16 17:40

お忙しい中本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問