1

だからみんな...私はたくさん読んで、madExcept(私は初めてです)のようなアドオンを使用しようとしましたが、これまでのところ、エラーの原因を特定できませんでした。

一見ランダムなタイミングで SetLength() を呼び出すと、コードで EAccessViolation Exceptions が発生します。その背後にある理由を特定できず、コードの 1 行にまで追跡することさえできません。整理するのを手伝ってください。

この関数は、数値配列で繰り返されるパターンを探してカウントすることになっています。現在、そのロジックはまだ 100% 準備が整っていませんが、続行する前にこれらのバグを修正したいと考えています。

完了時にどのように機能するかの例:

配列 {1, 2, 3, 4, 1, 2, 3, 5} を指定すると、サブ配列 (1, 2, 3) を (4, 1, 2) のような他のすべての可能なサブ配列と比較する関数 ( 1, 2, 3) と (2, 3, 5) で、同じ場合を数えます。次に、関数は次の長さに進み、(1, 2, 3, 4) と (1, 2, 3, 5) を比較してもう一度開始します...

  • 配列の最大長は 45 です。
  • サブ配列の最小長は 3 です。
  • EAccessViolation エラーは通常、配列の長さが 12 ~ 13 で、通常は最初のループの最後の繰り返しで発生します。

繰り返しになりますが、アルゴリズム ロジック自体に欠陥があることはわかっていますが、最初にメモリ関連を修正したいと考えています。

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

function TfrmMain.Ready(Numbers: Array of SmallInt): SmallInt;
var
  i: Integer;
  Length, MinLength, MaxLength: SmallInt;
  Array1, Array2: Array of SmallInt;
  Array1Pos, Array1FirstPos, Array1LastPos: Integer;
  Array2Pos, Array2FirstPos, Array2LastPos: Integer;
begin
  Result := 0;

  MinLength := 3;
  MaxLength := Trunc( (High(Numbers) + 1 ) / 2 );

  for Length := MinLength to MaxLength do
  begin
    SetLength(Array1, 0);
    SetLength(Array2, 0);

    SetLength(Array1, Length);

    Array1FirstPos := 0;
    Array1LastPos  := High(Numbers) - High(Array1);

    for Array1Pos := Array1FirstPos to Array1LastPos do
    begin
      for i := Array1Pos to Length + Array1Pos do
        Array1[i - Array1Pos] := Numbers[i];

      if ( High(Array2) + 1 <> Length ) then
        SetLength(Array2, Length);

      Array2FirstPos := Array1Pos + Length;
      Array2LastPos  := High(Numbers);

      if ( ( Array1Pos >= Array2FirstPos ) and ( Array1Pos + Length <= Array2LastPos ) ) then
        for Array2Pos := Array2FirstPos to Array2LastPos do
        begin
          for i := Array2Pos to Length + Array2Pos do
            Array2[i - Array2Pos] := Numbers[i];

          if CompareArrays(Array1, Array2) then
            Result := Result + 1;
        end;
    end;
  end;

  SetLength(Array1, 0);
  SetLength(Array2, 0);
end;

function TfrmMain.CompareArrays(Array1, Array2: Array of SmallInt): Boolean;
var
  i: Integer;
begin
    Result := false;

  if ( High(Array1) <> High(Array2) ) then
    Exit;

  for i := 0 to High(Array1) do
    if ( Array1[i] <> Array2[i] ) then
        Exit;

    Result := true;
end;

解決しました!ありがとう、ジェファーソン・オリベイラ!

4

1 に答える 1

1

エラーが発生するかどうかは、渡す配列の内容に依存するため、呼び出し例またはメモの内容を示していただければ幸いです。

とにかく、コードを分析すると、いくつかのことがわかります。

以下の行で:

  if ( High(Array2) + 1 <> Length ) then
    SetLength(Array2, Length);

長さ = 0、または長さ = High(Array2) + 1 の場合、Array2 の長さは定義されません。

したがって、以下のコードが実行されると:

  if ( ( Array1Pos >= Array2FirstPos ) and ( Array1Pos + Length <= Array2LastPos ) ) then
    for Array2Pos := Array2FirstPos to Array2LastPos do
    begin
      for i := Array2Pos to Length + Array2Pos do
        Array2[i - Array2Pos] := Numbers[i];

Array2 の長さが定義されていない場合は、AccessViolation が発生する可能性があります。そのため (このコードを修正する目的のみ)、インデックスにアクセスする前に Array2 の長さをテストする必要があります。

for i := Array2Pos to Length + Array2Pos do
begin
    if ((i - Array2Pos) >= System.Length(Array2) - 1) then
        Array2[i - Array2Pos] := Numbers[i];
end;

しかし、ロジックに焦点を当て、いくつかのテスト値を整理することで、現在の AV を解決するコードを大幅に改善できることがわかると思います。

編集:変数の名前がグローバル関数「長さ」と同じであるため、サンプルコードを「名前空間」システムを使用するように更新しました。

于 2012-05-28T17:47:19.363 に答える