TPixelQueueItem = record
    PrevPoint: TImagePoint;
    NextPoint: TImagePoint;
  end;  TPixelQueue = array of array of TPixelQueueItem;
var
  PixelQueue: TPixelQueue;
begin
    SetLength(PixelQueue,ImageHeight,ImageWidth);
    FillChar(PixelQueue,ImageWidth * ImageHeight * SizeOf(TPixelQueueItem),0);{这句不行!}
end;如果循环清零,效率太慢:
for I := 0 to High(PixelQueue) do
    FillChar(PixelQueue[I],ImageWidth * SizeOf(TPixelQueueItem),0);

解决方案 »

  1.   

    好象两个方法都不行呀
    动态数组很怪,FillChar和Move似乎都不支持帮你顶,也许会有高手知道
      

  2.   

    报内存访问错,我想是和动态数组的机制有关,会不会是因为动态数组的前面几个字节用来引用计数的?FillChar将一片内存区清零,这样的话实际上就把后面的动态数组的头破坏了,从而造成访问空指针错误。
      

  3.   

    var
      PixelQueue: TPixelQueue;
    begin
        SetLength(PixelQueue,100,100);
        ....   SetLength(PixelQueue,0,0);
    end;
      

  4.   

    呵呵 aiirii(ari-爱的眼睛) 的方法不错
      

  5.   

    奇怪,以为很简单的事,测试了下,是报错
    用 zeroMemory也是
      

  6.   

    呵呵
    SetLength(PixelQueue,0,0);
    这个 不是等则于
    赋值NIl吗。应该不可以的啦,实在是对于里面的机制不了解呀。
      

  7.   

    谢谢!
    我主要是想在使用这个二维数组前,把内容清零,查看帮助
    SetLength(PixelQueue,100,100);并不自动把内存清零。
    SetLength(PixelQueue,0,0);相当于把数组释放了,我还没有使用哩,不能用它!
      

  8.   

    sorry, 那个SetLength(PixelQueue,0,0); 是我以为你要释放PixelQueue
      

  9.   

    FillChar(PixelQueue,ImageWidth * ImageHeight * SizeOf(TPixelQueueItem),0)
    只是把指向数组的指针数组清0了。当然会出现你那个问题。
      

  10.   

    指针数组是n个内存块,这个操作的时间应该也是O(n)量级的,我翻了一下delphi算法与数据结构,上面描述了Tlist类的清空(p32),明确说明必须遍历每个item去释放 而且
    var a:array of array of integer;
        p:pinteger;
    begin
        setlength(a,10,10);
        a[3,3]:=3;
        p:=@a[3,3];
        setlength(a,0,0);
        showmessage(inttostr(p^));
    end;显示他的内存仍然还是存储它原先的直
      

  11.   

    这个ok.
    program Project1;
    {$APPTYPE CONSOLE}
    uses windows;
    type
    TPixelQueueItem = record
        PrevPoint: TPoint;
        NextPoint: TPoint;
      end;  TPixelQueue = array of array of TPixelQueueItem;
    var
      PixelQueue: TPixelQueue;
      i,j:Integer;
    begin
        SetLength(PixelQueue,100,100);
        FillChar(PixelQueue[0,0],100* 100 * SizeOf(TPixelQueueItem),0);{这句不行!}
        for i:=0 to 99 do
        begin
             writeln('');
             for j:=0 to 99 do
             begin
                  write(PixelQueue[i,j].PrevPoint.X);
             end;
        end;end.
      

  12.   

    说明,FillChar(PixelQueue,ImageWidth * ImageHeight * SizeOf(TPixelQueueItem),0);不行的原因PixelQueue并不代表该数组的首址。
      

  13.   

    我明白了,PixelQueue代表该数组的首址。然而,FillChar的第一个参数是个要填充区域第一个元素的引用,如果使用PixelQueue,则导致把存放数组名变量的地方给填了0,肯定出错。
      

  14.   

    to男巫:begin
        SetLength(PixelQueue,100,100);
        FillChar(PixelQueue[0,0],100* 100 * SizeOf(TPixelQueueItem),0);{这句不行!}
        for i:=0 to 99 do
        begin
             writeln('');
             for j:=0 to 99 do
             begin
                  write(PixelQueue[i,j].PrevPoint.X);
             end;
        
    不行的那句是因为越界了
      

  15.   

    to jinjazz(三个小时上下班) 不好意思,我的那句行,只不过忘了檫去{这句不行!}了。
      

  16.   

    //意思是说如下程序通过
    program Project1;
    {$APPTYPE CONSOLE}
    uses windows;
    type
    TPixelQueueItem = record
        PrevPoint: TPoint;
        NextPoint: TPoint;
      end;
      TPixelQueue = array of array of TPixelQueueItem;
    var
      PixelQueue: TPixelQueue;
      i,j:Integer;
    begin
        SetLength(PixelQueue,100,100);
        FillChar(PixelQueue[0,0],100* 100 * SizeOf(TPixelQueueItem),0);{这句行!}
        for i:=0 to 99 do
        begin
             writeln('');
             for j:=0 to 99 do
             begin
                  write(PixelQueue[i,j].PrevPoint.X);
             end;
        end;
    end.
      

  17.   

    上面方法不行, FillChar(PixelQueue[0,0],100* 100 * SizeOf(TPixelQueueItem),1),用一代替零就可以看到结果不对了。
      

  18.   

    2男巫:一定不行,你不用控制台的时候会发现会抛异常,但是在后面加一个showmessage('')他会把异常抛在showmessage('')后面,而不是马上抛出把你的程序改改:
        SetLength(PixelQueue,100,100);
        FillChar(PixelQueue[0,0],100* 100 * SizeOf(TPixelQueueItem),0);{这句行!}
        for i:=0 to 99 do
        begin
             writeln('');
             for j:=0 to 99 do
             begin
                  write(PixelQueue[i,j].PrevPoint.X);
             end;
        end;
            PixelQueue[55,55].PrevPoint.x:=1;
            write(PixelQueue[i,j].PrevPoint.X);
            readln;  end;
    不要直接运行,用cmd  到命令提示符下运行,比如:e:\project1.exe  会发现runtime error
      

  19.   

    我知道你是什么意思了,不过你要记住,使用的是FillChar,是逐字节的填充,用1,输出的是
    $01010101的十进制结果。
      

  20.   

    如果用你的方法必须保证 第二个参数不能大于100*size,其实也就是给指针数组的第一个指针指向的数组清零举个例子:比如一个老师带一个班,他要通知一件事情,不管班上有10个人还是100个人,他只要进一次教室的门就可以了
    而如果他带了n个班,不管他的n个半在教学楼里是否挨在一起,他都得每次都进入教室,宣布事情除非他有本事把学校已经排好的班按他自己的方法重新排...
      

  21.   

    男巫你的方法我试了,但是你那样做之后,数组就不能工作了,你也试试我该过的,或者把你的方在普通的application中试一下
      

  22.   

    setlength 可以对二维数组使用吗,我倒是在开发人员指南中见过这样用,不过我在delphi中没对二维数组用过,不是不用而是不知道是哪个单元声明这个函数的
      

  23.   

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, Grids;type
      TForm1 = class(TForm)
        Button1: TButton;
        StringGrid1: TStringGrid;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
     TPixelQueueItem = packed record
        PrevPoint: TPoint;
        NextPoint: TPoint;
      end;
      TPixelQueue = array of array of TPixelQueueItem;var
      Form1: TForm1;
      PixelQueue: TPixelQueue;implementation{$R *.DFM}procedure TForm1.FormCreate(Sender: TObject);
    begin
    //    SetLength(PixelQueue,100,100);
        GetMem(PixelQUeue,100*100 * SizeOf(TPixelQueueItem));
        ShowMessage(IntToStr(PixelQueue[0,0].PrevPoint.X));
        FillChar(PixelQueue,99* 99 * SizeOf(TPixelQueueItem),0);{这句行!}
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
        i,j:Integer;
    begin
         StringGrid1.RowCount:=100;
         StringGrid1.ColCount:=100;
         for i:=1 to 99 do
         for j:=1 to 99 do
         StringGrid1.Cells[i,j]:=IntToStr(PixelQueue[i,j].PrevPoint.X);end;end.
    //Sorry,可能Delphi中的动态数组有特殊的机制。
      

  24.   

    //动态数组里包含了下标的信息~~
      SetLength(PixelQueue, 10);
      SetLength(PixelQueue[0], 0);
      SetLength(PixelQueue[1], 1);
      SetLength(PixelQueue[2], 2);
      SetLength(PixelQueue[3], 3);
      SetLength(PixelQueue[4], 4);
      SetLength(PixelQueue[5], 5);
      SetLength(PixelQueue[6], 6);
      SetLength(PixelQueue[7], 7);
      SetLength(PixelQueue[8], 8);
      SetLength(PixelQueue[9], 9);
    //就是说有可能出现不是矩形的二维数组(二级下标信息因此也必须保存)~~
    //即使是从0位置开始清空也会把二级下标信息给清掉~~
    //这样就要选一个折中的办法,循环+FillChar()~~type
      TImagePoint = TPoint;
      TPixelQueueItem = record
        PrevPoint: TImagePoint;
        NextPoint: TImagePoint;
      end;
      TPixelQueue = array of array of TPixelQueueItem;
    var
      PixelQueue: TPixelQueue;
      ImageHeight, ImageWidth: Integer;
      I: Integer;
    begin
      ImageHeight := 10;
      ImageWidth := 10;
      SetLength(PixelQueue, ImageHeight, ImageWidth);
      for I := Low(PixelQueue) to High(PixelQueue) do
        if Length(PixelQueue) > 0 then
          FillChar(PixelQueue[I][Low(PixelQueue[I])],
            Length(PixelQueue[I]) * SizeOf(TPixelQueueItem), $FF);
    end;
      

  25.   

    //天呐,大家看看这个结果
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, Grids;type
      TForm1 = class(TForm)
        Button1: TButton;
        StringGrid1: TStringGrid;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
     TPixelQueueItem = packed record
        PrevPoint: TPoint;
        NextPoint: TPoint;
      end;
      TPixelQueue = array of array of TPixelQueueItem;var
      Form1: TForm1;
      PixelQueue: TPixelQueue;implementation{$R *.DFM}procedure TForm1.FormCreate(Sender: TObject);
    begin
        SetLength(PixelQueue,100,100);
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
        i,j:Integer;
    begin
         StringGrid1.RowCount:=100;
         StringGrid1.ColCount:=100;
         for i:=0 to 99 do
         for j:=0 to 99 do
         StringGrid1.Cells[i,j]:=IntToStr(PixelQueue[i,j].PrevPoint.X);end;end.
      

  26.   

    因为是内存自管理, 所以每一维数组的起始值前面有些东西, 所以不能一次置0,只能一维一维地清:SetLength(PixelQueue,3,3);
      for i := 0 to 2 do
      begin
        for j := 0 to 2 do
        begin
         PixelQueue[i][j].PrevPoint.X := 111;
         PixelQueue[i][j].PrevPoint.Y := 222;     PixelQueue[i][j].NextPoint.X := 333;
         PixelQueue[i][j].NextPoint.Y := 444;
        end;  end;  for i := 0 to 2 do
      begin
        FillChar(PixelQueue[i][0], 3*sizeof(TPixelQueueItem), 0);
      end;
      

  27.   

    {$APPTYPE CONSOLE}
    uses Windows;begin
      PInteger(nil)^ := 100;
    end.//就算有异常,控制台程序也不会出对话框啊,就算try-except也没用~~
      

  28.   

    详细结构定义:
      TImagePoint = record
        X,Y: Word;
      end;  TImageRect = record
        Left,Top,Right,Bottom: Word;
      end;  TPixelQueueItem = record
        PrevPoint: TImagePoint;
        NextPoint: TImagePoint;
      end;  TPixelQueue = array of array of TPixelQueueItem;
    看看SetLength是否自动清零:
    For a long-string or dynamic-array variable, SetLength reallocates the string or array referenced by S to the given length. Existing characters in the string or elements in the array are preserved, but the content of newly allocated space is undefined. The one exception is when increasing the length of a dynamic array in which the elements are types that must be initialized (strings, Variants, Variant arrays, or records that contain such types). When S is a dynamic array of types that must be initialized, newly allocated space is set to 0 or nil.帮助里说的明白,只有Strings, Variants, Variant arrays, or records that contain such types才自动清零。
    我的结构体是由word构成的,所以SetLength不会自动清零,如果是初始为0,很可能是内存块中的随机值,不敢用啊!!
      

  29.   

    When S is a dynamic array of types that must be initialized, newly allocated space is set to 0 or nil.应该是0吧,他说只要是动态数组就一定初始化...
      

  30.   

    TPixelQueueItem = record
        PrevPoint: integer;
        NextPoint: integer;
      end;  TPixelQueue = array of array of TPixelQueueItem;var
      PixelQueue: TPixelQueue;
      i,j:integer;
    begin
      SetLength(PixelQueue,3000,3000);
      for i := 0 to 2999 do
      begin
        for j := 0 to 2999 do
        begin
         PixelQueue[i][j].PrevPoint := 111;
         PixelQueue[i][j].PrevPoint := 222;     PixelQueue[i][j].NextPoint := 333;
         PixelQueue[i][j].NextPoint := 444;
        end;  end;
      PixelQueue := nil;
      SetLength(PixelQueue,3000,3000);
      for i := 0 to 2999 do
      begin
        for j := 0 to 2999 do
        begin
         PixelQueue[i][j].PrevPoint := 111;
         PixelQueue[i][j].PrevPoint := 222;     PixelQueue[i][j].NextPoint := 333;
         PixelQueue[i][j].NextPoint := 444;
        end;  end; end;经测试,没有出现内存泄漏, 并且能正常清零,赋值!
      

  31.   

    to Borlandor(五角大民) ; 你的类型是record好不好,不是word,所以你第二次SetLenth时就初始化了数组, 也就是初始化为和以前一样了, 但你看下面的代码,改成integer类型, 你第二次SetLenth时,里面的值照常存在(哪怕你增加二维数组的长度,前面的数据依然存在, 这和帮助相符的, 但最好的用法是用赋值给nil,清空,然后再用就和刚声明时一样了)TPixelQueue = array of array of integer;procedure TForm1.Button1Click(Sender: TObject);
    var
      PixelQueue: TPixelQueue;
      i,j:integer;
    begin
      SetLength(PixelQueue,3000,3000);
      for i := 0 to 2999 do
      begin
        for j := 0 to 2999 do
        begin
         PixelQueue[i][j] := 111;
        end;  end;
      //PixelQueue := nil;(为了测试将这句暂时注一下,实际中一定加上)
      SetLength(PixelQueue,3000,3000);
      for i := 0 to 2999 do
      begin
        for j := 0 to 2999 do
        begin
         PixelQueue[i][j] := 222;    end;  end; end;
      

  32.   

    When S is a dynamic array of types that must be initialized, newly allocated space is set to 0 or nil.
    The one exception is when increasing the length of a dynamic array in which the elements are types that must be initialized (strings, Variants, Variant arrays, or records that contain such types). 从上下文看,SetLength仅仅对(strings, Variants, Variant arrays, or records that contain such types)清零。
      

  33.   

    总之
    1. 如果SetLenth中的S作为动态数组其中的元素是strings, Variants, Variant arrays, or records that contain such types)那么,执行SetLenth后,增加的空间内容清0。其它的情况,比如说S就是一个String类型的变量,那么SetLenth后,其空间内的值是不定的。2.给动态数组清0,  只需将动态数组变量的赋nil,然后再次SetLenth即可!
      

  34.   

    TO Borlandor(五角大民):  老大, 拍个板呀!
      

  35.   

    动态数组是生存期自管理的,所以在用完它们以后没有必要释放,因为在离开作用域时它们会被放。然而,可能在离开作用域前,就需要删除动态数组(例如它用了很多内存)。要这么做,仅需要
    把nil赋值给动态数组:
    SA:=nil; //释放S A