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

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

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

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

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Q&A

解決済

3回答

5855閲覧

乱数を用いたwhileの無限ループ問題

RHs

総合スコア5

C

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

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

0グッド

0クリップ

投稿2020/01/23 15:20

前提・実現したいこと

c言語で以下の問題が解きたいです。

whileの無限ループを作り、その中で、1から10までの乱数を発生させて、表示しなさい。 その際、値が10になったら、ループを抜け、”終了します”と表示してプログラムを終えるようにしなさい。

理想の出力結果は

5 3 2 1 9 10 終了します

です。

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

10になったら処理が終了するようにはできたのですが、なぜかそこに至るまでに大量に数字が出力されてしまいます。

例えば

5 5 5 5 5 : : 3 3 3 3 3 3 3 3 3 3 3 3 3 10 終了します

のようになってしまいます

該当のソースコード

C

1#include <stdio.h> 2#include <time.h> 3#include <stdlib.h> 4 5int main(void){ 6 int n; 7 8 while(1){ 9 srand((unsigned)time(NULL)); 10 n = rand() % 10+1; 11 printf("%d\n", n); 12 13 else(n==10){ 14 printf("終了します\n"); 15 break; 16 } 17 18 19 20 } 21 return 0; 22}

利用が初めてなのでおかしな使い方をしていたらすみません。よろしくお願いします。

試したこと

rand関数の書き方はあっていそうなのでそれ以下の部分かwhile文の位置が問題なのでしょうか?

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

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

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

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

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

guest

回答3

0

ベストアンサー

srandは一回だけ使うようにします。while文より前に出してあげて下さい。


randに依って得られる値は、順に計算可能な疑似乱数です。
スタート地点が同じであれば、その後得られる数列も全く同じになります。

srandはそのスタート地点を設定する為の関数です。引数はシードと呼ばれます。

time(NULL)はそのときの時刻を返します。
ループ一周は大抵time(NULL)の最小単位より短く、何度も同じシードを与えていることになります。

投稿2020/01/23 15:45

編集2020/01/23 15:51
LouiS0616

総合スコア35660

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

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

0

コメントにしようかとも思ったのですが、量がそこそこになりそうなので回答で。

ループの仕様の問題ではありません。srandとrandの意味/使い方を理解していないことが問題です。

完璧な(前後の値と全く無縁な)乱数というのは事実上無理なので、コンピュータ上では直前の値から計算によって乱数っぽい値(疑似乱数)を算出しています。一般的には「線形合同法」が使われることが多いです。興味があれば調べてみてください。
そして、「直前の値」になにか(プログラマが管理する)数を与えるのがsrand()関数です。これを乱数の「種」とよくいいますが。(プログラムの検証などでは、同じ乱数列をなんども試してみたい、というケースはよくあるので乱数並びを再現できることも必要です)

また、time()関数は、現在の時刻を秒単位で返す関数です。

さて。

C

1 while(1){ 2 srand((unsigned)time(NULL)); 3 n = rand() % 10+1; 4 printf("%d\n", n); 5 }

時刻が1579820801だったとしましょう。
また、rand()関数が直前の乱数に123を掛けて45を足したものを次の(疑似)乱数として返すものだったとしてみましょう。

このプログラムは、現在の時刻1579820801を得て、それを「種」に設定します。
rand関数で、1579820801に123を掛けて45を足すと、unsigned intの範囲では1044430248になります。10で割ったあまりは8で、それに1を足して9がnに入り、それが表示されます。
この操作は「一瞬」ですね。なのでループの繰り返しでは次回も時刻は1579820801が得られるでしょう。そうすると、これを「種」に設定して123を掛けて45を足して10で割った余りに1を足して9。これも一瞬なのでまた次の時刻は1579320801。
一瞬とはいえいくらかの時間はかかりますから、9がだ~っと表示された後、時刻が1579820802になる時が来ます。123を掛けて45を足すとunsigned intの範囲では1044430371‬。10で割ったあまりに1を足すと2。しかしこれも一瞬なのでまた2がだ~っと表示されることになります。
この繰り返しが、あなたのプログラムに起こった現象です。

srand()がループの外に出ていれば

C

1 srand((unsigned)time(NULL)); 2 while(1){ 3 n = rand() % 10+1; 4 printf("%d\n", n); 5 }

時刻1579820801を得て、
rand()は1044430248を返します。9を表示したあと、
その次のrand()では1044430248に123を掛けて45を足してunsigned intの範囲にした3910868965‬を返します。すると表示されるのは6。
その次のrand()では3910868965‬に123を掛けて45を足してunsigned intの範囲にした545588が得られて9を表示
...
という動作になるので、これは期待したものでしょう。


別件ですが。
既に経験されているとは思いますが、プログラムでは一文字の間違いでもエラーになって実行出来なかったり、実行できても期待しない結果が得られることがあります。その意味で、質問で提示するプログラムは、厳密にあなたが使ったのと同じものでないと、あなたの疑問の解決に何の役にも立たない場合が考えられるのはおわかりですね? (もちろん、問題になっている点以外を削ぎ落としてもいいですけれど、何が問題かわからなければ削ぎ落としも出来ないはずです)

そのプログラム、明らかに間違っています。一箇所が間違っているなら、他も間違っているんじゃないか、というのは十分考えられるでしょう。と、回答しようと思った私はなにを拠り所に問題点を考えればいいのでしょうか...

解決したいのなら、質問をしっかりとしてください。

投稿2020/01/23 23:32

thkana

総合スコア7639

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

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

0

srandを外に出したらすぐ直りました!ループ外に置いていたら値が固定されてしまうのでは?と勝手に勘違いしてました。ループの仕様を勉強しなおしたいと思います
ありがとうございました!

投稿2020/01/23 16:04

RHs

総合スコア5

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問