动态记录数组无法展开

Dynamic Array of Records fails to expand

我创建了一个动态记录数组,使用此 actionexecute 方法对其进行了扩展:

procedure TForm1.AddTeamActionExecute(Sender: TObject);
Var
  c : integer;
begin
  c := length(PrjRecArray);
  PrjRecArray[c].tmpLoadPrjRec (true, 'Team', 'Big Building', '123 Main Street' ,'',
    'Somewhere', 'Ohio','43210', '555-1234', 'Bob', 'Big Cheese', '555-0123', 'bob@gmail.com');

  PrjSg.Cells[0,PrjSg.RowCount-1] := (PrjRecArray[c].Team);
  PrjSg.Cells[1,PrjSg.rowcount-1] := (PrjRecArray[c].Name);
  PrjSg.Cells[2,PrjSg.rowcount-1] := (PrjRecArray[c].addr1);
  PrjSg.Cells[3,PrjSg.rowcount-1] := (PrjRecArray[c].addr2);
  PrjSg.Cells[4,PrjSg.rowcount-1] := (PrjRecArray[c].city);
  PrjSg.Cells[5,PrjSg.rowcount-1] := (PrjRecArray[c].state);
  PrjSg.Cells[6,PrjSg.rowcount-1] := (PrjRecArray[c].zip);
  PrjSg.Cells[7,PrjSg.rowcount-1] := (PrjRecArray[c].phone);
  PrjSg.Cells[8,PrjSg.rowcount-1] := (PrjRecArray[c].contact);
  PrjSg.Cells[9,PrjSg.rowcount-1] := (PrjRecArray[c].title);
  PrjSg.Cells[10,PrjSg.rowcount-1] := (PrjRecArray[c].conPhone);
  PrjSg.Cells[11,PrjSg.rowcount-1] := (PrjRecArray[c].email);
  PrjSg.RowCount := PrjSg.RowCount + 1;
  Revised(true);
  showmessage ('PrSG Rows = ' + inttostr (PrjSg.RowCount));
  c := c + 1;
  SetLength (PrjRecArray, c);
  showmessage ('PrjRecArray Rows = ' + inttostr (length(PrjRecArray)));

end;

该数组在单元 (PrjRecArray : Array of TPrjRec;) 中声明为 PrjRecArray,并且未以其他方式初始化。 PrjSg是一个包含在表单中的tstringgrid,用于显示记录。

当我使用 AddTeamActionExecute 添加更多记录时,stringgrid 的大小继续正确增加。然而,虽然 PrjRecordArray 正确扩展为四个记录,但程序显然在设置长度行的第五次迭代中失败。执行挂起,从不显示第二个显示消息框。

我是否遗漏了一些正确使用动态数组的步骤?

您访问了数组的末尾。而不是

c := length(PrjRecArray);

c := length(PrjRecArray) - 1;

c := high(PrjRecArray);

请记住,动态数组是从零开始的。

如果您在编译器选项中启用了范围检查,那么您将遇到任何越界数组访问的运行时错误,这对调试有很大帮助。

SetLength 的调用也需要更正。例如

SetLength (PrjRecArray, length(PrjRecArray) + 1);

而不是动态数组,使用 TList<T> 可能会导致更简单的代码读写。您可以让 TList<T> 处理调整其内部动态数组大小的细节。

我唯一的其他评论是我想知道数组实际填充的位置。你延长了长度,但我显然没有看到你在哪里赋值。

Length 给出数组的当前长度。但是动态数组从索引 0 开始,并且它们结束于 —— 在本例中 —— High(PrjRecArray)。您应该访问 PrjRecArray[c - 1],而不是 PrjRecArray[c]

或者,使用

c := High(PrjRecArray);

然后你可以使用

PrjSg.Cells[0, PrjSg.RowCount - 1] := PrjRecArray[c].Team;
// etc...

在你的代码中,如果你已经有了 c 中的长度,然后再次将长度设置为相同的 c,你确实没有 expanding,您将其设置为与已有长度相同的长度。使用

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

或者,在您的代码中(假设 c 是长度):

SetLength(PrjRecArray, c + 1); // previous length + 1

FWIW,如果您经常这样做,您可能需要考虑以更大的块增加大小(例如 SetLength(PrjRecArray, c + c shr 1); - 或 SetLength(PrjRecArray, c + c div 2);,它们是相同的) ,并跟踪数组中实际使用的元素。这避免了堆碎片化,这可能会使您很容易 运行 内存不足。

在我的 blog article 关于扩展数组的内容中有更多相关内容。