none
配列でエラーが起きてしまいました RRS feed

  • 質問

  • こんにちは

    私は今、vb.net 2012でゲームを作っています。

    そこで配列を使って、インスタンスを管理しているのですが、その配列にfor文で値を代入しようとすると、「インデックスが配列の境界外です。」

    と、必ず出てしまいます。

    ですがデバックモードで確認してみると、配列はちゃんと存在していて、i(カウント用に宣言した変数です) もその範囲内でした。

    さらにおかしなことに、for文でいつエラーが出るかも一定しておらず、前止まったときはi=1だったのに、1時間後に試してみたら、i=3になっていたりします。

    なお、for文の中身だけ出して、配列のインデックスを数字にすると動くのですが、別のfor文を作り、入れなおしてみると動きませんでした。

    行き詰ってしまい、とても困っています。

    回答、よろしくお願いします!

    2015年4月2日 15:31

回答

  • 外池と申します。

    もしかすると外しているかもしれませんが、エラーの発生箇所、間違いなく、EnemySideKutikukan(i)X= の行でしょうか? そのひとつ前の banmen(enemyX, enemyY)=21 の行ではないですか? これご確認下さい。

    というのも、Ikebettiさんが仰るとおりで、EnemySideKutikukan(i)X=については、配列境界越えの原因が見当たりません。むしろ、banmen( )の行、というか、さらにその前の、enemyXとenemyYに与える乱数の最大値には極めて強い疑いを感じます。

    例外が検出される際の i の値がマチマチであるとの症状に合致することが、最大の理由。Rnd()*10にMath.Roundを適用すると0~10の11種類の値が得られます。これはIkebettiさんの意図どおりですか? 実は「9」までが意図なら、「10」という値が出てbanmenの境界を「たまに」超えているのでは?

    以下は、蛇足。確率分布は最大値の10だけ0.05、0~9はそれぞれ0.095です。


    • 編集済み 外池 2015年4月3日 23:49
    • 回答としてマーク Ikebetti 2015年4月4日 15:21
    2015年4月3日 23:18

すべての返信

  • こんにちは。

    私が知る限りではこの例外は単純な実装ミスが疑わしいです。
    for文と値を代入する部分の周辺ロジックを提示できますか。
    また、for文の中でコレクションの数が変わる作りにはなっていませんよね?

    さらにおかしなことに、for文でいつエラーが出るかも一定しておらず、前止まったときはi=1だったのに、1時間後に試してみたら、i=3になっていたりします

    これはコードを見てみないと何とも言えませんが対象配列の長さが可変であれば不定でもおかしくないとは思います。

    値の代入だけで不都合が無ければ試しにFor Eachを使ってみてください。
    それで同様のエラーにならないのであれば、
    For i As Integer = 0 To XXXX ← ここがおかしいのがよくあるパターンでしょうか。


    2015年4月2日 16:01
    モデレータ
  • どのようなエラーなのかを把握されていないように思われますので、まず、発生したエラーを把握しましょう。

    >と、必ず出てしまいます。

    とのことですが、デバッグ実行すれば、エラーが発生した際に行が黄色に反転して止まっていると思います。
    そこに配列の記述があると思うのですが、その際にマウスカーソルをその配列に合わせると配列の長さ(Length)が表示されます。
    (ちなみに、その配列をクリックすると、その配列の中身が全て表示されます)
    もし長さが3であれば、インデックスは0, 1, 2ですから2までです。同様にインデックス i にマウスカーソルを合わせると現在の i の値が表示されます。もし、3以上であれば、このエラーメッセージを納得することができます。
    このようにしてエラーメッセージが指していることを把握して下さい。

    把握できたら、デバッグします。必ずエラーが出るようですから、ブレークポイントで止めながら少しずつ実行し、どのように配列に関する値やインデックスなどが変化していくかを確認していきましょう。もし、For文を100回も回す必要があれば、ある程度まではブレークポイントで止まらないように飛ばしましょう。条件付きブレークポイントを使えば簡単にできますので、調べてみて下さい。

    自分の思い通りに動作しないことはプログラム作成中に何度も出くわすことです。デバッグする技量を付けることはとても大切なことですし、この技量が無ければプログラムの開発は行き詰ってしまうこともあるでしょう。
    デバッグの基本は、自分の思い通りに動作しているかを1行ずつ追っていくことです。それを行ってみて下さい。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2015年4月3日 1:58
    モデレータ
  • デバッグをどのように進めたら良いのか分からないって事でしょうか?
    もしかして、エラーの出ている行とにらめっこしていませんか?

    私なら、まずはFor文の中に書かれているコードを全てコメントにします。そして少しずつコメントを外していきます。現象が発生知るようになったなら、その時にコメントではなくして部分のコードにヒントがあるはずです。ただしその部分に原因があるとは限りません。配列のインデックスはもとより、他の場所で配列そのものを壊している可能性も否定できないからです。

    若しくは徹底的にログを埋めていきます。エラーで止まる前後において、各変数の内容がどのように変化していったのか分かるようにログを出力します。


    甕星

    2015年4月3日 3:32
  • 回答ありがとうございます! いくつか、答えさせていただきます。

    trapemiya様の

    >そこに配列の記述があると思うのですが、その際にマウスカーソルをその配列に合わせると配列の長さ(Length)が表示されます。

    ということですが、それは既にやっていて、Length=6にしっかりなっているのに、i=1で止まっている

    と言った状況です。 とりあえず、コードを載せてみます

      Public EnemySideKutikukan(5) As Ship ’モジュールで宣言

         ’Sub EnemySet で

      For i As Integer = 0 To 5
                Randomize(Now.ToOADate())
                Dim enemyX As Integer = Math.Round(Rnd() * 10)
                Randomize(Now.ToOADate())
                Dim enemyY As Integer = Math.Round(Rnd() * 10)
                banmen(enemyX, enemyY) = 21
                EnemySideKutikukan(i).X = enemyX}ここでエラーが出ます
                EnemySideKutikukan(i).Y = enemyY
            Next

    ここ以外ではEnemySideKutikukan()はいじっていないのですが・・・

    2015年4月3日 13:46
  • 外池と申します。

    もしかすると外しているかもしれませんが、エラーの発生箇所、間違いなく、EnemySideKutikukan(i)X= の行でしょうか? そのひとつ前の banmen(enemyX, enemyY)=21 の行ではないですか? これご確認下さい。

    というのも、Ikebettiさんが仰るとおりで、EnemySideKutikukan(i)X=については、配列境界越えの原因が見当たりません。むしろ、banmen( )の行、というか、さらにその前の、enemyXとenemyYに与える乱数の最大値には極めて強い疑いを感じます。

    例外が検出される際の i の値がマチマチであるとの症状に合致することが、最大の理由。Rnd()*10にMath.Roundを適用すると0~10の11種類の値が得られます。これはIkebettiさんの意図どおりですか? 実は「9」までが意図なら、「10」という値が出てbanmenの境界を「たまに」超えているのでは?

    以下は、蛇足。確率分布は最大値の10だけ0.05、0~9はそれぞれ0.095です。


    • 編集済み 外池 2015年4月3日 23:49
    • 回答としてマーク Ikebetti 2015年4月4日 15:21
    2015年4月3日 23:18
  • 返信が遅くなってしまい、申し訳ありません。

    外池様のおっしゃった通りでした!

    banmenの定義が、(7,7)となっていました。

    黄色く反転していた行がその下だったので、そこを見ることを思いつきませんでした。

    バグが見つかったら、反転している行の周りの値も確認すべきなんですね。

    無事、解決できました!

    本当にありがとうございました!

    2015年4月4日 15:21
  • 外池です。解決できて良かったですが・・・、

    デバッグで表示された黄色の箇所が、例外発生の場所と違っていた件は、気を付けた方が良いでしょうね? 小生も似たようなズレを経験したことあったような記憶がありますが、その理由はもっとアヤフヤな記憶。

    もし、コード最適化のオプションをONにされているなら、デバッグ中はOFFにしておいた方が無難かもしれません。

    さらに蛇足・・・、とは言っても、乱数の使い方なので、かなり本質的ですが・・・、

    乱数を使うたびにRandomizeするのは適切ではないです。一番最初に一度だけRandomizeしておけばOKです。

    2015年4月5日 15:31