1

所以伙计们...我已经阅读了很多内容,并且尝试过使用诸如 madExcept 之类的插件(我是新手),但到目前为止我还无法确定是什么导致了我的错误。

在看似随机的时间调用 SetLength() 时,我的代码出现 EAccessViolation 异常。我一直无法确定其背后的原因,我什至无法将其追踪到一行代码。我想请你帮我整理一下。

这个函数应该在一个数字数组中寻找重复的模式并计算它们。目前,它的逻辑还没有 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);

如果 Length = 0 或 Length = 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。

编辑:由于您的变量与全局函数“Length”具有相同的名称,因此我更新了示例代码以使用“命名空间”系统。

于 2012-05-28T17:47:19.363 回答