【问题标题】:Keep getting AV when closing my application after imputing some data to dynamic multidimensional array在将一些数据输入动态多维数组后关闭我的应用程序时继续获取 AV
【发布时间】:2014-08-31 13:04:12
【问题描述】:

我在我的一个项目中遇到了一些奇怪的问题。最奇怪的是,这只发生在这个项目中,我不能在另一个项目中重新创建它。

幸运的是,这是一个小项目(旨在为 SO 上的一个问题提供答案 - 仍未完成)所以我设法弄清楚它必须做一些事情来破坏我放置在我的 TImage 组件在设计时形成并在设计时为其设置 BMP 图像。

我得到的 AV 是: Project Project1.exe 引发异常类 $C0000005,并带有消息“在 0x00407430 处访问违规:读取地址 0xfffffffc”。

最后三个调用堆栈是:
Vcl.Graphics.TBitmapCanvas.Destroy
Vcl.Graphics.TCanvasDestroy
System.TObject.Free

此外,Delphi 将我置于 TObbject.Free 方法中的 System.pas 单元中的“Destroy”行。

procedure TObject.Free;
begin
  if Self <> nil then
{$IFDEF AUTOREFCOUNT}
    __ObjRelease;
{$ELSE}
    Destroy;
{$ENDIF}
end;

此时 Self 的值仅显示为 ()。

但是为什么只有当我将一些数据存储到我的多维数组中时才会发生这种 AV。
我可以在运行时创建和设置多维数组的大小,一切都很好。但是,一旦我更改了这个多维数组中某些项目的数据,我就会在关闭我的应用程序时得到 AV。

这是我的完整源代码:

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TSubImage = record
    LeftBound: Integer;
    RightBound: Integer;
    TopBound: Integer;
    BottomBound: Integer;
  end;

  TForm2 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;
  SubImages: Array of TSubImage;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var X,Y,I: Integer;
    RegionMask: Array of Array of Integer;
begin
  SetLength(RegionMask,Image1.Width+1,Image1.Height+1);
  for Y := 0 to Image1.Height do
  begin
    for X := 0 to Image1.Width do
    begin
      if Image1.Canvas.Pixels[X,Y] <> clFuchsia then
      begin
        //Check left pixel
        if X > 0 then
        begin
          if RegionMask[X-1,Y] <> 0 then
          begin
            RegionMask[X,Y] := RegionMask[X-1,Y];
            //Check to se if pixel X position is leftwards to subimages left bound
            if Subimages[RegionMask[X,Y]].LeftBound > X then
              //Move subimage left bound to match pixel X position
              Subimages[RegionMask[X,Y]].LeftBound := X;
            //Check to se if pixel X position is rightwards to subimages right bound
            if Subimages[RegionMask[X,Y]].RightBound < X then
              //Move subimage right bound to match pixel X position
              Subimages[RegionMask[X,Y]].RightBound := X;
            //Check to se if pixel Y position is upwards to subimages top bound
            if Subimages[RegionMask[X,Y]].TopBound > Y then
              //Move subimage top bound to match pixel Y position
              Subimages[RegionMask[X,Y]].TopBound := Y;
            //Check to se if pixel Y position is downwards to subimages bottom bound
            if Subimages[RegionMask[X,Y]].BottomBound < Y then
              //Move subimage bottom bound to match pixel Y position
              Subimages[RegionMask[X,Y]].BottomBound := Y;
          end;
        end;
        //Check top pixel
        if Y > 0 then
        begin
          if RegionMask[X,Y-1] <> 0 then
          begin
            RegionMask[X,Y] := RegionMask[X,Y-1];
            //Check to se if pixel X position is leftwards to subimages left bound
            if Subimages[RegionMask[X,Y]].LeftBound > X then
              //Move subimage left bound to match pixel X position
              Subimages[RegionMask[X,Y]].LeftBound := X;
            //Check to se if pixel X position is rightwards to subimages right bound
            if Subimages[RegionMask[X,Y]].RightBound < X then
              //Move subimage right bound to match pixel X position
              Subimages[RegionMask[X,Y]].RightBound := X;
            //Check to se if pixel Y position is upwards to subimages top bound
            if Subimages[RegionMask[X,Y]].TopBound > Y then
              //Move subimage top bound to match pixel Y position
              Subimages[RegionMask[X,Y]].TopBound := Y;
            //Check to se if pixel Y position is downwards to subimages bottom bound
            if Subimages[RegionMask[X,Y]].BottomBound < Y then
              //Move subimage bottom bound to match pixel Y position
              Subimages[RegionMask[X,Y]].BottomBound := Y;
          end;
        end;
        //Create new region
        if RegionMask[X,Y] = 0 then
        begin
          SetLength(SubImages,Length(SubImages)+1);

          //If I comment out this line no exception is raised on closing the from
          RegionMask[X,Y] := Length(SubImages);

          //Set subimage initial bounds which are coordinates of one pixel
          //since we created new region for this pixel
          SubImages[RegionMask[X,Y]].LeftBound := X;
          SubImages[RegionMask[X,Y]].RightBound := X;
          SubImages[RegionMask[X,Y]].TopBound := Y;
          SubImages[RegionMask[X,Y]].BottomBound := Y;
        end;
      end;
    end;
  end;
  Form2.Caption := IntToStr(Length(SubImages)-1);
  for I := 0 to Length(Subimages)-1 do
  begin
    ListBox1.Items.Add(IntToStr(SubImages[I].LeftBound)+','+
                       IntToStr(SubImages[I].RightBound)+','+
                       IntToStr(SubImages[I].TopBound)+','+
                       IntToStr(SubImages[I].BottomBound));
  end;
  SetLength(RegionMask,0,0);
  RegionMask := nil;
end;

end.

【问题讨论】:

  • for Y := 0 to Image1.Height 看起来很奇怪。当然for Y := 0 to Image1.Height-1。 X 循环也是如此。另外,为什么要使用 GUI 控件进行操作?当然,您需要的是位图。
  • 另外,我猜你正在运行范围检查?
  • 是的,这是我的代码中的一个错误,但它对我得到的 AV 没有任何影响。为什么我使用 GUI?这是我不关心速度而只关心结果的第一个实现。最后,我打算使用 TBtimap 和 ScanLine 而不是通过 Canvas.Pixel[X,Y] 方法访问单独的像素。但现在?我想知道为什么会发生这个错误,为什么只有当我将一些数据存储到我的动态多维数组中时,它与 TImage 没有任何关系,除了我最初将它的大小设置为图像尺寸。
  • 不,我之前没有启用范围检查(我认为它是默认启用的)。启用范围检查在我的代码中显示了许多错误。实际上,当我一直在引用子图像时,我总是偏离了一项。所以修复这些错误似乎解决了我的 AV 问题,但老实说我不知道​​如何。
  • 始终使用范围检查进行调试

标签: delphi multidimensional-array dynamic-arrays delphi-xe3


【解决方案1】:

您在这些行中有一次性错误。 考虑第一次将元素添加到 SubImages。 SubImages 的长度为 1,但数组中唯一的元素是 SubImages[0]。 您将 RegionMask[X,Y] 设置为 1,然后使用该值来索引数组。 因此,您正在尝试访问超出数组末尾的一项。

   SetLength(SubImages,Length(SubImages)+1);

      RegionMask[X,Y] := Length(SubImages);

      SubImages[RegionMask[X,Y]].LeftBound := X;

【讨论】:

  • 感谢您的回答。几分钟前,当大卫问我是否使用范围检查时,我才发现这一点。我没有用过它们。所以在启用它们后,我很快意识到我的错误。但我仍然不知道这会如何影响 TImage 组件的破坏。
  • 一旦您开始更改超出范围的内存,您可能会影响存储在内存中的任何内容的任何方面。你的数组在内存中的什么位置?除了它还有什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 2019-07-24
  • 1970-01-01
  • 2020-10-07
  • 2012-09-13
  • 2013-10-25
  • 1970-01-01
相关资源
最近更新 更多