質問するログイン新規登録
C

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

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

Q&A

解決済

3回答

1364閲覧

c言語 無限ループの解決方法お願いします!

kinsan0813

総合スコア1

C

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

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

0グッド

1クリップ

投稿2025/09/19 12:01

編集2025/09/20 12:29

0

1

実現したいこと

テストの点数の分布図を作成したいです。
例えば、6人の生徒の点数が30点・50点・55点・59点・75点・79点だったとすれば、

* * * * * *

0 10 20 30 40 50 60 70 80 90 100

このような分布図を作りたいです。

発生している問題・分からないこと

入力する生徒の数が11までは問題なく分布図を作れるのですが、12のときに分布図の上に改行文字が出力され、13を超えると空白を無限に出力する無限ループが起こってしまいます。

エラーメッセージ

error

1エラーメッセージはなしです。

該当のソースコード

c言語

1#include <stdio.h> 2 3int main(void) 4{ 5 int no; 6 7 printf("生徒の数は?:"); scanf("%d", &no); 8 9 int a[no]; // データ全体の数 10 int bunpu[11] = {0}; // 各点数のデータの数 0~9・10~19・…・90~99・100で分ける 11 12 for (int i = 0; i < no; i++) { // データの読込 13 do { 14 printf("%d人目の点数:", i + 1); scanf("%d", &a[i]); 15 if (a[i] < 0 || a[i] > 100) printf("\a正しく点数を入力してください。\n"); 16 } while (a[i] < 0 || a[i] > 100); 17 bunpu[a[i] / 10]++; // 各点数のデータの数を増やす 18 } 19 20 int max = bunpu[0]; 21 22 for (int i = 1; i < no; i++) { // 各点数のデータの数のなかで最大のものを求める 23 if (max < bunpu[i]) max = bunpu[i]; 24 } 25 26 int max2 = max; // for文の制御式に用いるmaxをmax2とする 27 28 for (int i = 1; i <= max2; i++) { // 分布図の行の繰り返し 29 for (int q = 0; q < 11; q++) { // 分布図の列の繰り返し *を打つための繰り返し 30 if (bunpu[q] >= max) printf(" * "); 31 else printf(" "); 32 } 33 putchar('\n'); 34 max--; 35 } 36 37 printf("---------------------------------\n"); // 分布図の目盛の部分 38 printf(" 0 10 20 30 40 50 60 70 80 90 100\n"); 39 40 return 0; 41} 42

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

for文が意図せず無限ループしてしまう理由はネット上で見つけられませんでした。

補足

特になし

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

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

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

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

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

melian

2025/09/19 13:17

配列 bunpu の容量は 11 ですが、 int bunpu[11] = {0}; // 各点数のデータの数 0~9・10~19・…・90~99・100で分ける 最大値を求めるループではインデックス(変数i)の上限を no-1 にしています。 for (int i = 1; i < no; i++) { // 各点数のデータの数のなかで最大のものを求める if (max < bunpu[i]) max = bunpu[i]; } 本来は、for (int i = 1; i < 11; i++) とすべきではないでしょうか。
kinsan0813

2025/09/19 15:21

コメントありがとうございます! melianさんの通りに修正したことで問題が解決し、生徒の数が12以上でも問題なく動作するようになりました! 本当にありがとうございます。 プログラムを書いてる途中で生徒の点数a[no]と点数の分布bunpu[11]が混乱してしまったようです。 これから気を付けます!
jimbe

2025/09/20 04:45

c と c# は別の言語ですので、 c# のタグは外されたほうが良いと思います。
kinsan0813

2025/09/20 12:30

了解です! それともう一つのコメントでも、プログラムをきれいに書くコツを教えていただいてありがとうございます! これからプログラムを書くときに心がけます!
jimbe

2025/09/20 14:36

編集ありがとうございます。
PopularTree

2025/09/23 00:49

9行目のコードですが、malloc関数か、calloc関数を使用するコードにした方がより良いコードになると思いました。 ご検討いただければと思います。
hiroki-o

2025/09/23 01:19 編集

個人的には同意ですが、C言語の規格としてはオプションで認められているので、多くの人は納得できないかと。 (VLAは、GCC/Clangはサポート、Visual Studioは未サポート)
rinjinto

2025/09/23 12:03

むしろ大多数はmalloc/callocを使う方だと思いますよ。 C99を使えない環境が多いし、互換性を考えたコーディングをしますし、静的解析でサポートしていないこともありますし。 少なくとも仕事で使ってる人はCでVLAは使わないと思います。
hiroki-o

2025/09/23 13:19

ですから、私はrinjintoさんの意見に同意です。 ただ、私もここで何回か同じ指摘をしていますが、毎回スルーされます。 ここはC言語のプロも多いはずなのに残念です。
rinjinto

2025/09/23 14:46

そういうことですか。頭痛いですねえ。 何度も指摘して理解してもらうしかないんですかね。
thkana

2025/09/24 00:03

gccが幅を利かせる昨今「C99を使えない環境が多い」は本当にそうだろうか、と思いますけれど、現行規格ではVLAはオプションに落ちているので採用には慎重であるべき、というのは言えますね。 回答中に「AIに聞けば教えてくれるっしょ」と書きましたけど、件の場所とともにclaudeにもchatGptにもVLAはちょっと...というツッコミは入れられました。本題ではないので省きましたけれど。 こないだ社内レビューで新人がCortexM0用のものにVLA使ってて、みんな引っかかりはして「他の環境に移植もしなさそうな部分だし、う~ん、どうしようかな」ってな感じでしたね(結局通した)。自分では使わないからこその反応でしょう。
guest

回答3

0

for文が意図せず無限ループしてしまう理由はネット上で見つけられませんでした。

どうしてそこで「ネット上」を探すのかちょっと疑問に思ったり。探した結果に「プログラムが間違っているから」というのはなかったのかしら。

答えが分かった段階でこんな話しても面白くないかもしれないけれど、いわゆるprintfデバッグで容易に原因を突き止められたのでは、と思います。

forループが無限ループになると思ったのなら、ループに関係する変数(特に継続条件に関わるもの)を確認しましょう。

for (int i = 1; i <= max2; i++) { // 分布図の行の繰り返し
の次の行に、
printf("i:%d max2:%d", i, max2);
を入れてみます。「無限」状態ではmax2が変な値になっていることが容易に見えたでしょう。(無限ではなく、iがmax2に至るまで待てれば、ループは止まったのでしょう)

max2は、
int max2 = max; // for文の制御式に用いるmaxをmax2とする
で値が決まっていますから、どうやらmaxが変な値になっているっぽいですね。

ではmaxはどうやって決まっていますか?

int max = bunpu[0]; for (int i = 1; i < no; i++) { // 各点数のデータの数のなかで最大のものを求める if (max < bunpu[i]) max = bunpu[i]; }

おかしいのはmaxだということなので、maxの値を追跡します。ループ中、最後がいいかな
printf("i:%d max:%d", i, max);
を入れてみましょう。
なお、この後の表示とかは(画面が流れてしまうので)止めてしまってもかまわないでしょう。for文が終わったところでreturnしてしまえばとりあえずいいですね。

この段階で、iがbunpuの要素数を超えて、maxが不定の大きな数になったりすることに気がつくと思います。
なんで?ループの継続条件にi < noと書かれている(あなたが書いた)からですね。

某知恵袋あたりでこんなこと書くと「ゴタクはいいから間違っている場所だけ教えろ」と怒られたりしそうですが。
あるいは、そのソースコードをまるっとAIに投げれば「ここがおかしい」と指摘してくれます。
でも、この程度のミスは自分で見つけられるようにしておいた方がいいですね。

Cで値が吹っ飛ぶとかそういう場合、配列の添え字か、ポインタの計算の間違いであることは非常に多いです。いきなりfor文が無限ループになる話をネットで探す前に、その辺を確認してみましょう。

投稿2025/09/19 23:30

thkana

総合スコア7753

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

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

kinsan0813

2025/09/20 12:27

エラーの解決方法まで丁寧に教えていただいてありがとうございます。 これからは、いろいろな方法を試して、自身の力だけでもエラーを解決できるように勉強します!
guest

0

プログラムを勉強中と思われますので、ご提示されているコードについてこうしたらどうかというのを勝手に書いてみます。(個人の嗜好・志向が多少なりとも反映されています。)

  • 変数名は英単語にしましょう
    プログラムの文は基本英単語で構成されるため、変数名等も英単語を基本とするのが慣習です。

  • 配列 a は配列である必要はありません
    配列 a は i 番目の要素が入力の受けと分布データ配列の指定に使われるだけです。
    複数のデータの入力には配列を使うことが多いですが、それは複数の入力を後からまた使うのが前提ですので、"ループ1回内で使って終わり" のような入力なら、ただの変数で受けて十分です。

  • 同じ式を複数個所に書かないほうが良いです
    入力した値が正常値/異常値かを判断する式が2か所(ifとwhile)にあります。
    このようにすると正常値/異常値の式が変わった場合に両方を修正しないといけなくなり間違えの元になりますので、1つに纏まるように書くようにすると良いと思います。
    "異常値ならメッセージ表示"と"異常値ならループ継続"の2つになっている所を、無限ループ内で"正常値ならループを抜ける" "ループを抜けなかったらメッセージ表示"とすることで条件判断は1つになります。

  • 最大値を求めるだけのループは(必ずしも)必要ありません
    全ての値を入力しデータを集めてから改めてループして最大値を求めていますが、件ではデータの更新は一箇所だけですので、データを集めながら最大値を求めることも出来ます。
    プログラムの規模が大きくなると分かり易い様に処理を分けるようになりますが、この規模では単独の処理とするよりデータ収集の一環として纏めてしまったほうが良さそうに思います。

  • (文字通り)逆転の発想で max2 を不要にできます。
    max2 は、ループ終了条件が変わらないようにするためだけに使われています。
    が、ループの向きを 0→max で無く max→0 にすれば、max2 は(ついでにループカウンタも)不要になります。

  • 同じ部分を少し違えて表示するのなら、 3項演算子 というのが使えます
    " * "" " を条件で切り替えて表示するなら、真ん中の '*'/' ' の部分だけを 条件?'*':' ' という で表すことが出来ます。式なので printf 内に埋め込めます。

  • コメントに頼らないようにしましょう
    コメントの書き方や在り方については様々ありますが、個人的にはコメントに頼るとプログラム自体の理解が進み難いと思います。
    例えるなら、英語の映画で日本語字幕を追っていては英語学習の役には立ち難いような感じでしょうか。

ということで、以下のようにしてみました。コメントはほぼそのまま+追加です。

c

1#include <stdio.h> 2 3int main(void) { 4 int num; 5 printf("生徒の数は?:"); 6 scanf("%d", &num); 7 8 int datas[11] = {0}; // 各点数のデータの数 0~9・10~19・…・90~99・100で分ける 9 int max = 0; //datas 内の最大値 10 11 for(int i=0; i<num; ++i) { // データの読込 12 int a; 13 while(1) { //無限ループ 14 printf("%d人目の点数:", i+1); 15 scanf("%d", &a); 16 if(0 <= a && a <= 100) break; //正常範囲ならループを抜ける 17 printf("\a正しく点数を入力してください。\n"); //ココにくるということは正常範囲外なのでエラー表示 18 } 19 int v = ++datas[a/10]; // 各点数のデータの数を増やし、その値を v に代入する 20 if(max < v) max = v; // 各点数のデータの数のなかで最大のものを求める 21 } 22 23 for( ; max>0; --max) { // 分布図の行の繰り返し 24 for(int j=0; j<11; ++j) { // 分布図の列の繰り返し *を打つための繰り返し 25 printf(" %c ", datas[j]>=max?'*':' '); 26 } 27 putchar('\n'); 28 } 29 printf("---------------------------------\n"); // 分布図の目盛の部分 30 printf(" 0 10 20 30 40 50 60 70 80 90 100\n"); 31 32 return 0; 33}
* * * * * * --------------------------------- 0 10 20 30 40 50 60 70 80 90 100

投稿2025/09/20 04:44

jimbe

総合スコア13404

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

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

melian

2025/09/20 05:05

う〜ん、なぜ datas なのでしょう? 質問者である kinsan0813 さんがこの回答をきちんと読んで気付くかどうかを確認しようとしているのでしょうか…?
jimbe

2025/09/20 14:40

dist だと送り先みたいだし disp だと表示みたいだしで案外悩みまして(^^;
hiroki-o

2025/09/20 15:41

dataは複数形でもdataだという指摘では...
jimbe

2025/09/20 16:37

あー…恥ずかしい間違いです、 melian さん hiroki-o さんありがとうございました。分かってなかったのは私です。 配列だから複数形でと s だけ残してあれやこれや置換して結局こんなことに…。 反省のために残しておきます。
fana

2025/09/25 03:23

(すごくどうでもいい話ですが) "datas" に抱く親近感!みたいな. 何か別の複数形がある言葉を探して命名する(今回のやつなら "bins" とか?)ということがすんなりいけばよいのですが, なんか「データ」みたいな言葉しか浮かばないときって(わりとよく?)あります. そしたら「複数であること」を明示することをあきらめて "data" とするのか,それとも「でもこれは英語じゃないかね.変数名だからね」として "datas" とするのか…
guest

0

ベストアンサー

サッと見て下記のところは動作が怪しいと思いました。

for (int i = 1; i < no; i++) { // 各点数のデータの数のなかで最大のものを求める if (max < bunpu[i]) max = bunpu[i]; }

bunpuは0~10の要素を持つ配列ですが、人数であるnoまでループを回してbunpuの要素を参照しています。
人数が12のとき iの最大値は11となりますが、bunpuは[11]の要素を持っていないため配列外の領域を参照してしまうのではないでしょうか。

投稿2025/09/19 13:25

sleepsheep

総合スコア319

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

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

kinsan0813

2025/09/19 15:23

ありがとうございます! 制御式のnoを11に変更することで問題なく実行できるようになりました! これからは配列を扱うときは配列外の領域を参照しないように気を付けます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.29%

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

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

質問する

関連した質問