配列変数の参照でエラーが出たり出なかったりするのはなぜか?

解決


マックス  2011-08-09 23:08:12  No: 40835

お世話になっております。

XP,Delphi2007です。

「〜するには?」のような質問の仕方が思いつきませんでした。すみません。

FormにButton1,Button2を置いて、次のソースを書きました。

----------------------------------------------

  private
    { Private declarations }
    AData:array of array of string;//配列変数を宣言

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin

setlength(AData,10,10);

for I := 0 to 10 do
begin
  AData[0,i]:=inttostr(i);
end;

end;

procedure TForm1.Button2Click(Sender: TObject);
var
  I: Integer;
begin

setlength(AData,10,10);

for I := 0 to 10 do
begin
  AData[i,0]:=inttostr(i);
end;

end;

----------------------------------------------

このとき、配列の要素数は10×10(AData[0..9,0..9])なので、AData[0,10]を参照しても、AData[0,10]を参照しても、エラーが出るような気がしますが、Button1ではエラーにならず、Button2のときだけエラーが出ます。

なぜか理由が知りたいです。

または、Button1でもエラーが発生する方法(プロパティの設定、オプションの設定など)があれば、教えてください。

よろしくお願いします。


tor  2011-08-10 01:28:31  No: 40836

えーと、[0,10] がエラーにならなくて [10,0] はエラーということでいいんですよね?
エラーというのは、Delphiが出す範囲チェックエラー(ERangeError)?
それともメモリアクセス違反でしょうか?

コンパイラの設定で「実行時エラー」の「範囲チェック」を有効にしておけば、どちらのケースでもERangeErrorが生成されるはずです。
範囲チェックしておらず、メモリアクセス違反が出るときと出ないときがあるとしたら「たまたま」でしょう。
範囲外の領域にアクセスした時、そこが運よく触っても大丈夫な場所だったか、そうでなかったかという違いです。

一般論としては、2次元の配列というのは多くの場合、メモリ上では一次元の連続した領域になっています。
(0,0)-(0,1)-(0,2)-(0,3)-...-(0,9)-(1,0)-(1,1)-...-(9,7)-(9,8)-(9,9)
といった具合です。
仮に配列の要素がこのように配置されていた場合、(0,10)に対応するアドレスを計算すると一次元領域の11番目、つまり(1,0)と同じ場所になります。
たまたま有効なメモリアドレスなので、正常にアクセスできるわけです。
一方、(10,0)に対応するアドレスは101番目となり、有効なアドレスの範囲外になってしまいます。
実際、動的配列の場合に上の理屈が当てはまるかどうかはわかりませんが。(ちなみに私の環境ではどちらもメモリアクセス違反になりました)


マックス  2011-08-10 01:47:45  No: 40837

ありがとうございます。

エラーの内容は
「モジュール'Project1.exe'のアドレス004048F0でアドレス00000000に対する書き込み違反が起きました。」
というものです。

「一次元の連続した領域」と言われて、納得できました。

ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加