先ほどに続きたびたびすいません。
やはり解決できてませんでした。
SetLengthをFor文の前でSetすると問題なくSetできます。
しかしFor文のあとにSetLengthを行うと0しかSetできません。
なぜこうなってしまうのかわかりません。
ただこのFor文によって得た値をSetしたいのでどうしてもFor文の後におきたいです。
なにが原因でこうなってしまうのでしょうか?
普通そんなことは起こらないので、実際のコードを見せてもらわないと原因なんてわかりません。
どこか配列の範囲外の領域に書き込んでメモリ破壊しているとかじゃないの?
>0しかSetできません
というのはどうやって確認したんでしょうか? 0以外だとエラーでも出るのですか?
CountNo :=100;
SetLength(T1,CountNo);
SetLength(T2,CountNo);
SetLength(T3,CountNo);
←ここに入れた場合は問題ありません。
for i:= 0 to CountNo do
begin
T1[i] := Test[i].T1;
T2[i] := Test[i].T2;
T3[i] := Test[i].T3;
end;
AllCount := T1Max * T2Max;
SetLength(T4,AllCount ); ←ここにいれるとだめです。
このAllCountを0にした場合はエラーになりませんでした。
AllCountを使わずに1や2などの数値にしてもだめでした。
エラーになってしまうというのは、コンパイルは通るのですが、実行すると
しばらくだんまり状態になってAccess Violation Errになります。
よろしくお願いします。
えーと、動的配列は0から始まるので、
例えば SetLength(T1, 3) としたら使える要素は3つ。
すなわち T1[0], T1[1], T1[2] です。T1[3] は使えません。
実際に使える要素は 0 から CountNo-1 までなんです。
一方、Delphiのfor文は
for i:= 0 to 3 do
と書いたら、0, 1, 2, 3 の4回ループします。
つまり、範囲外の T1[3] に書き込んでしまうということになります。
for i:= 0 to CountNo do
は
for i:= 0 to CountNo-1 do
では?
わかりにくい表現ですいません。
書き直します。
Var
T1 : Array of Integer;
T2 : Array of Integer;
T3 : Array of Integer;
T4 : Array of Integer;
begin
CountNo :=100;
SetLength(T1,CountNo);
SetLength(T2,CountNo);
SetLength(T3,CountNo);
SetLength(T4,○○);←ここに入れた場合は問題ありません。
※○○はなんでもよい
for i:= 0 to CountNo-1 do
begin
T1[i] := Hoge[i];
T2[i] := Hoge2[i];
T3[i] := Hoge3[i];
end;
AllCount := T1Max * T2Max; //T1のMax値とT2のMax値をかけてT4の配列数
SetLength(T4,AllCount ); ←ここにいれるとだめです。
T4のSetLengthを上記のように場所を変えるとだめになります。
問題はそこだけです。
さきほどFor文の中はわかりづらい表現でした。
申し訳ありません。
procedure TForm1.Button1Click(Sender: TObject);
var
Hoge1, Hoge2, Hoge3: array of Integer;
T1, T2, T3, T4: array of Integer;
CountNo, AllCount, I, T1Max, T2Max: Integer;
t4Log: TStringList;
begin
// initialize
SetLength(Hoge1,100);
SetLength(Hoge2,100);
SetLength(Hoge3,100);
for I:=0 to 100-1 do
begin
Hoge1[I] := I+1;
Hoge2[I] := I+2;
Hoge3[I] := I+3;
end;
//
// main process
T1Max := 0;
T2Max := 0;
CountNo := 100;
SetLength(T1,CountNo);
SetLength(T2,CountNo);
SetLength(T3,CountNo);
//SetLength(T4,CountNo);
for I:=0 to CountNo-1 do
begin
T1[I] := Hoge1[I]; if T1[I]>T1Max then T1Max := T1[I];
T2[I] := Hoge2[I]; if T2[I]>T2Max then T2Max := T2[I];
T3[I] := Hoge3[I];
end;
//
// final process
AllCount := T1Max*T2Max; ShowMessage( 'AllCount='+IntToStr(AllCount) );
SetLength(T4,AllCount);
for I:=0 to AllCount-1 do
T4[I] := I;
//
// debug out
t4Log := TStringList.Create;
try
for I:=Low(T4) to High(T4) do
t4Log.Add(IntToStr(I)+':'+IntToStr(T4[I]));
t4Log.SaveToFile('t4Log.log');
finally
t4Log.Free;
end;
end;
こんなテストをしてみましたが、エラーが出ませんね。
For文の後でSetLength(T4, 100)のように、変数AllCountでなく
具体的数値を入れて実行してもT4[0]以外の入力は不可ですか?
AllCountの値をブレークポイント設定あるいはShowMessageで確認してみたらいかがですか?
ついでにコンパイルオプションで範囲チェックを有効にして試してみて。
みなさありがとうございます。
通りすがりさん
テストありがとうございます。
なんで私のはでてしまうのかわかりません。
ただ配列にDouble型でかなりの文字数を入れているのでメモリが足りないのかな?と思っていますが、対処方もわかりませんし、確信はありません。
ふむさん
具体的な数値を入れてもだめです。
具体的な数値は0であれば問題ありませんが。
AllCountの値は15000くらいです。
tttさん
チェックいれてやってみました。これをするとどのような変化があるのでしょうか?
私なりに動的配列を静的にしました。
これをすると問題なくいきますが、なぜかその後のFor文(その配列を使用したほかの処理)でまた同じようにしばらくだんまってソフトがおちてしまいます。
Access violation errがでます。
この対処方を知りたいですが、このままでは進まないのでほかの方法も現在検討しています。
tttさん
今範囲チェックを有効にしたら、1たりないものに入れてたりと範囲チェックのエラーが出て、それをつぶしていったら出来ました!!
ただチェックを有効にしないといままでそこでは止まらなかったですね。
普通は止まると思うのですが。
> ただチェックを有効にしないといままでそこでは止まらなかったですね。
> 普通は止まると思うのですが
チェックを有効にすると、配列の範囲をはみ出していないかDelphiがいちいちチェックしてくれます。(その分オーバーヘッドがかかります)
無効にした場合、範囲をはみ出さないよう自己責任で管理しなくてはいけません。
配列の範囲をはみ出して書き込もうとした場合
*運が良ければ* そこが保護されたメモリ領域で、すぐにエラーが出ます。
*運が悪かったら* たまたまそこにあったメモリの内容(他の変数など)を書き換えてしまいますが、
OSから見れば「書き込み可能なメモリに書き込んだ」だけなので何事もなく先に進みます。
後に進んで、上書きされた変数の値を使ったりするうちに
だんだん矛盾が積み重なって、やがて異状が発覚します。
エラーの原因と実際の発生箇所が離れているので、こういうバグは潰すのがそうとう厄介です。
範囲のはみ出しには注意しましょう。
tttさん
tttさんが言うようにあとで変なところでエラーになったのはそのせいだったのですね。
今回のエラーはすべて範囲のはみ出しのせいだったということがわかります。
これからはちゃんとチェックをいれていてエラーをその都度出すようにしておきます。
解決とともにとても勉強になりました。
ありがとうございます
ツイート | ![]() |