- 締切済み
乱数の取得
キー操作をした時に複数の乱数を習得させようと思っています。 【キ─操作関数】 int num[3] = {11, 22, 33}; ←初期化のため数字は適当です。 srand((unsigned int)time(NULL)) for(int i=0; i<=3; i++) { num[i] = rand % 10; } 上記のプログラムを書いています。 num[0]、num[1]、num[2]にそれぞれ0~9の乱数が入ると思うのですが、 num[0]にしか乱数が入りません。 num[1]、num[2]には同じ数字(恐らくtimeで取得した数字?)が入っています。 何かお気づきの点がありましたらアドバイスお願い致します。
- みんなの回答 (9)
- 専門家の回答
みんなの回答
- SilverThaw
- ベストアンサー率32% (260/806)
No.2、6です。 >ループ条件ですが、 >for(int i=0; i<=3; i++)としたのは、今回は乱数を3つ必要でしたが後々4つ使用するためです。 >int num[3]ではnum[0]、num[1]、num[2]の3つしか使用してはいけないが、 >num[4]が発生したところで使用せずとも問題ないと思っていたのですが…これも認識が違っていますでしょうか? すでに回答が付いていますが、間違いです。 わかりやすい例えをしましょう。 --------- 机の上に空のコップが「3つ」あります。 一つのコップには「一回だけ」ジュースを注ぐこととし、計「4回」ジュースを注ぎました。 3回はコップにジュースを注ぐことができましたが、最後の一回は? コップが無いため、机と床を濡らしてしまいました。 --------- これが質問者さんの行っていることです。 実際、私の環境では、num[3] = rand()の実行で例外エラーが発生します。 どうしても、後で増やす必要があるのであれば、以下のような方法があります。(一部省略) --------- #define MAX 3 int num[MAX]; for(i=0; i<MAX; i++) --------- 配列の要素数とループの上限をあわせる為に同じ定数値を使うことです。 それによりループ回数と配列の要素の食い違いを防げます。 プログラムは「よくわからないけど、動いているからいいや」では駄目です。
- goosyu
- ベストアンサー率58% (36/62)
メモリ破壊を目視出来るようにコーディングしました。ただし配列(変数)のメモリへの割り付け方はコンパイラおよびリンカによって変化しますので,この例のようにnumとxが順にメモリ配置されるかは保証できません。 【検証コード】 #include <stdio.h> #include <stdlib.h> #include <time.h> void main() { static int num[3] = {11, 22, 33}; static int x[1]={44}; srand((unsigned int)time(NULL)); printf("0x%08X:x[0]=%d\n", (unsigned long)&x[0],x[0]); for(int i=0; i<=3; i++) { num[i] = rand() % 10; printf("0x%08X:num[%d]=%d\n", (unsigned long)&num[i], i, num[i]); } printf("0x%08X:x[0]=%d (x[0]がnum[4]で上書きされる。本当は44が返されるべき。)\n", (unsigned long)&x[0],x[0]); return; } 【実行結果】 0x00817044:x[0]=44 0x00817038:num[0]=8 0x0081703C:num[1]=3 0x00817040:num[2]=7 0x00817044:num[3]=1 0x00817044:x[0]=1 (x[0]がnum[4]で上書きされる。本当は44が返されるべき。) 【説明】 上記実行結果の「0x」で始まる16進数はメモリのアドレスで,x[0]とnum[3]が同じアドレスであることを確認して下さい。 (配列も変数も全てメモリ上に配置されていますので同じメモリアドレスを指しているのであれば値が共有されていることになります。) int num[3] 宣言はnumを3つ確保するだけなので使える範囲はnum[0]~num[2]までです。しかしC言語(C++)ではnum[3]に値を入れる事は禁止されていない為,num[3]に書き込むことが出来ます。この結果num[3]と同じメモリアドレスのx[0]が意図せずに壊されます。 このあとにx[0]を参照する処理があれば,値が破壊されている為,正常に処理を継続することが出来ません。 この例のように意図しないメモリを書き込み(メモリ破壊)があると,コードからのデバッグが難しくよくバグの原因となります。
- Wr5
- ベストアンサー率53% (2173/4061)
>for(int i=0; i<=3; i++)としたのは、今回は乱数を3つ必要でしたが後々4つ使用するためです。 >int num[3]ではnum[0]、num[1]、num[2]の3つしか使用してはいけないが、 >num[4]が発生したところで使用せずとも問題ないと思っていたのですが…これも認識が違っていますでしょうか? 使用しているつもりがなくても、代入している以上はどこかのメモリ領域を書き換えています。 「使わないから問題ナシ!!」の結果が、関数からのリターンアドレスを書き換えてて吹っ飛ぶのも問題ナシですか? バッファオーバーフロー系の不具合は、表面化する箇所がわかりにくい場合があるので注意が必要です。 # オープンソースなどでもときどき出てくるくらいよくあるミス…だったりしますけどね。
- SilverThaw
- ベストアンサー率32% (260/806)
No.2です。 >使用したいのはnum[0]、num[1]、num[2]なので… >int num[3]で配列を3つ用意する。という意味ではないのでしょうか? 記憶違いでしたらすみません。 これはあっています。しかし、No.2の内容を理解されていますか? 再度書きます。 ------------- 考え方はあっていますが、ループ条件が違います。 for(int i=0; i<=3; i++) は、iが「0から3以下」ならループが継続されます。 従ってiは、「0」「1」「2」「3」の4回ループされます。 int num[3]では、num[]の要素は、num[0]、num[1]、num[2]までしか使用してはいけません。 ------------- num[]は「3つ」しか用意していないのに、ループではnum[i]により「num[3]」、つまり「4つ目」になってしまう条件が発生することを、No.1氏も私も指摘しています。 ブレークポイントについては、「非効率」とありますが、確かにそれもひとつはありますが確認すべき項目を間違っているとしか思えません。
- titokani
- ベストアンサー率19% (341/1726)
>確認用にnum[0]などを書き、03の部分にブレイクポイントを打って確認しました。 一回目のbreakで、num[1]とnum[2]の確認もしているわけではないですよね?
補足
すみません…ブレイクポイントについての理解が足りていませんでした。 1回目のブレイクでnum[1]、num[2]も確認しておりました…。 解決致しましたありがとうございます。
- goosyu
- ベストアンサー率58% (36/62)
→#2の回答者さんの指摘以外,特に問題がありそうなところはありません。セミコロンが抜けている,randの括弧が足りない点を考えると,実際のソースと他に差分がないか確認した方がいいと思います。 差がほとんどありませんが,サンプル載せておきます。 #include <stdio.h> #include <stdlib.h> #include <time.h> void main() { int num[3] = {11, 22, 33}; srand((unsigned int)time(NULL)); for(int i=0; i<3; i++) { num[i] = rand() % 10; } printf("num[0]=%d,num[1]=%d,num[2]=%d\n", num[0], num[1], num[2]); }
お礼
サンプル有難うございます。 こちらを拝見し問題解決致しました。 取得した乱数を元に下の作業を振り分けたかったのですが、 num[1]、num[2]に乱数が入らなかったため作業分けが出来ていませんでした。 サンプルで確認しましたところ、num[i] = rand() % 10;の下に作業の振り分けを書いておりました…。 ループ1度目で振り分けされてしまうのでnum[1]、num[2]に乱数のループが入らなかったのではと思っています。 アドバイスありがとうございました。
- yamaj_biz
- ベストアンサー率71% (10/14)
まさか…とは思うのですが、 randっていう変数を作ってないですよね? 乱数の取得は関数なので「rand() % 10;」だと思います。
補足
↑の記述ミスです。 プログラムでは num[i] = rand() % 10; を使用しています。
- SilverThaw
- ベストアンサー率32% (260/806)
>>i[3]ってドコでしょう??? >配列は0から使用されるので"3回回す"で[0]、[1]、[2]にそれぞれ数字が入ると思っていたのですが違うのでしょうか? 考え方はあっていますが、ループ条件が違います。 for(int i=0; i<=3; i++) は、iが「0から3以下」ならループが継続されます。 従ってiは、「0」「1」「2」「3」の4回ループされます。 int num[3]では、num[]の要素は、num[0]、num[1]、num[2]までしか使用してはいけません。 >>どうやって確認しました? >VisualStudioでブレイクポイントをつけて確認しました。 どこにブレークポイントを張り、どの変数の内容を確認しましたか? rand()がある程度の分散値を出力するなら、値は変わっているはずですよ。
補足
使用したいのはnum[0]、num[1]、num[2]なので… int num[3]で配列を3つ用意する。という意味ではないのでしょうか? 記憶違いでしたらすみません。 01{ 02 num[i] = rand() % 10; 03 num[0]; 04 num[1]; 05 mum[2]; 06} 左端は行番号だと思って下さい。 確認用にnum[0]などを書き、03の部分にブレイクポイントを打って確認しました。 VisualStudioの扱いも不慣れなもので…非効率な事をしていましたらすみません。
- Wr5
- ベストアンサー率53% (2173/4061)
>num[i] = rand % 10; rand()ですよね? >for(int i=0; i<=3; i++) iが、0から「3」まで実行されます。 i[3]ってドコでしょう??? >num[0]にしか乱数が入りません。 >num[1]、num[2]には同じ数字(恐らくtimeで取得した数字?)が入っています。 どうやって確認しました?
補足
回答有難うございます。 rand()です。書き間違えました;; >i[3]ってドコでしょう??? 配列は0から使用されるので"3回回す"で[0]、[1]、[2]にそれぞれ数字が入ると思っていたのですが違うのでしょうか? >どうやって確認しました? VisualStudioでブレイクポイントをつけて確認しました。
補足
ブレイクポイントについては理解が足りておりませんでした。 お手数おかけして申し訳ありません。 プログラムについては解決致しました。 アドバイスありがとうございます。 ループ条件ですが、 for(int i=0; i<=3; i++)としたのは、今回は乱数を3つ必要でしたが後々4つ使用するためです。 int num[3]ではnum[0]、num[1]、num[2]の3つしか使用してはいけないが、 num[4]が発生したところで使用せずとも問題ないと思っていたのですが…これも認識が違っていますでしょうか? 何度も申し訳ありませんがご教授お願い致します。