如何在整数/实数的二维动态数组上使用move



在我的Delphi Rio应用程序中,我使用了很多二维动态数组。为了加快一些操作,我想使用move命令而不是copy。我可以让它适用于1D动态阵列,但对于2D或更高版本,我做不到。对于第二个维度,在发出move(A,B,size(后,数组B的元素指向数组A的元素的相同内存地址,即B引用A。事实上,我想单独使用A的B。请参阅我的代码:

program ProjArrayMove;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
Type
Arrayint   = Tarray<Integer>;
Arrayreal  = TArray<Real>;
MatrixInt  = Array of Arrayreal;
var
vectorA, vectorB : Arrayint;
matA, matB       : MatrixInt;
idx,idy          : integer;
begin
TRY
// =============== TESTING WITH 1D DYNAMIC ARRAYS OF SIMPLE TYPES ==================
Writeln('==============================================================');
Writeln('========= TESTING 1-DIMENSION DYNAMIC ARAYS ==================');
Writeln('===============================================================');
readln;
Writeln('------- Fills Vector A ----------------------------');
SetLength(vectorA,5);
for idx :=0 to 4 do
begin
vectorA[idx] := (idx+1) * 10;
Writeln('VectorA : [' + idx.tostring + ']  '  +
Format('Address : %p  [%d]' ,[PPointer(@VectorA), VectorA[idx] ]) );
end;
readln;
Writeln('--------------------------------------------------');
Writeln('------ Moves VectorA to VectorB ------------------');
SetLength(VectorB,Length(vectorA));
Move(VectorA[0],VectorB[0],SizeoF(VectorA[0]) * Length(VectorA));
for idx :=0 to 4 do
Writeln('VectorB : [' + idx.tostring + ']  '  +
Format('Address : %p  [%d]' ,[PPointer(@VectorB), VectorB[idx] ]) );
readln;
Writeln('---------------------------------------------------');
Writeln('------ Changes VectorB contents  ------------------');
for idx :=0 to 4 do
begin
vectorB[idx] := (idx+1) * 200;
Writeln('VectorB : [' + idx.tostring + ']  '  +
Format('Address : %p  [%d]' ,[PPointer(@VectorB), VectorB[idx] ]) );
end;
readln;
Writeln('--------------------------------------------------');
Writeln('------ Checking Vector A  ------------------------');
for idx :=0 to 4 do
Writeln('VectorA : [' + idx.tostring + ']  '  +
Format('Address : %p  [%d]' ,[PPointer(@VectorA), VectorA[idx] ]) );
Writeln;
Writeln('CONCLUSION : ===>>  MOVE command works fine for 1-Dimension Dynamic Arrays!');
readln;

//=========================== TESTING WITH MATRIX 2D DYNAMIC ARRAYS OF SIMPLE TYPES ==================
Writeln('===============================================================');
Writeln('========= TESTING 2-DIMENSIONS DYNAMIC ARAYS ==================');
Writeln('===============================================================');
readln;
Writeln('------ Fills MatrixA -----------------------------');
SetLength(matA,5,2);
for idx :=0 to 4 do
for idy := 0 to 1 do
begin
matA[idx][idy] := (idx +1) * (idy +1);
Writeln('Mat A : [' + idx.tostring + '][' + idy.tostring +']  '  +
Format('Address : %p  [%f]' ,[PPointer(@matA[idx][idy]), matA[idx][idy] ] ));
end;
readln;
Writeln('-------------------------------------------------');
Writeln('------ Move MatrixA to MatrixB ------------------');
SetLength(matB,length(matA));
//move(matA[0],MatB[0],Sizeof(matA[0]) * length(matA));
move(matA,MatB,Sizeof(matA[0]) * length(matA));
for idx :=0 to 4 do
begin
Setlength(MatB[idx],length(matA[idx]));
//Move(matA[idx][0],matB[idx][0],sizeof(matB[idx][0]) * length(matB[idx]) );
Move(matA[idx],matB[idx],sizeof(matB[idx][0]) * length(matB[idx]) );
for idy := 0 to 1 do
begin
Writeln('Mat B : [' + idx.tostring + '][' + idy.tostring +']  '  +
Format('Address : %p  [%f]' ,[PPointer(@matB[idx][idy]), matB[idx][idy] ] ));
end;
end;
readln;
Writeln('-------------------------------------------------');
Writeln('------ Change MatrixB content  ------------------');
readln;
for idx :=0 to 4 do
for idy := 0 to 1 do
begin
matB[idx][idy] := 100.5 * (idx+1) * (idy +1);
Writeln('Mat B : [' + idx.tostring + '][' + idy.tostring +']  '  +
Format('Address : %p  [%f]' ,[PPointer(@matB[idx][idy]), matB[idx][idy] ] ));
end;
Writeln('-------------------------------------------------');
Writeln('------ Checking Matrix A ------------------------');
readln;
for idx :=0 to 4 do
for idy := 0 to 1 do
Writeln('Mat A : [' + idx.tostring + '][' + idy.tostring +']  '  +
Format('Address : %p  [%f]' ,[PPointer(@matA[idx][idy]), matA[idx][idy] ] ));

Writeln;
Writeln('CONCLUSION : ===>>  MOVE command DOES NOT WORK on 2-Dimensions Dynamic Arrays!');
readln;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
readln;
end;
end;
end.

第二个维度的移动命令是否有错误或缺失?

谢谢!

您的问题从这里开始:

Move(matA, matB, Sizeof(matA[0]) * Length(matA));

您正在将一个动态数组传递给Move。动态数组被实现为指向数组的第一个元素的指针。因此,您正在覆盖指针。

也许你想做这样的事情:

Move(matA[0], matB[0], Sizeof(matA[0]) * Length(matA));

但你也不想那样做。这是在托管类型上使用Move,这与您在上一个问题中犯的错误完全相同。

事实上,如果你只是删除那一行代码,它应该可以工作。注意,我没有详细检查,所以可能还有其他缺陷。

你的代码真的非常复杂,很难看出发生了什么。至少你的一些问题是因为你的代码太模糊了。尝试停止在单个过程中放入大量代码。将代码拆分为较小的部分,然后在驱动程序例程中将这些较小的部分粘合在一起。

你想使用这样的功能:

function CloneMatrixInt(const matrix: array of ArrayInt): MatrixInt;
var
i: Integer;
begin
SetLength(Result, Length(matrix));
for i := 0 to High(Result) do
Result[i] := Copy(matrix[i]);
end;

请注意,这与您上一个问题的答案基本相同。为什么?

您需要停止将MatrixInt视为多维数组。事实并非如此。它只是一个数组。这是一个数组,其元素反过来也是数组。从技术上讲,它是一个锯齿状阵列。但你只需要把它看作一个一维数组。

因此,克隆它的功能如下所示:

  1. 分配目标数组
  2. 在目标阵列上循环,从源阵列克隆每个元素

这与您之前的问题完全相同。在那里,我们有一个记录数组,具有克隆该记录的功能。但是,因为我们已经将克隆外部数组和克隆数组元素这两项任务分开,所以生成的代码基本上是相同的。

现在假设您有一个MatrixInt数组。比方说

type
ArrayMatrixInt = array of MatrixInt;

好吧,像这样克隆:

function CloneArrayMatrixInt(const arrayMatrix: array of MatrixInt): ArrayMatrixInt;
var
i: Integer;
begin
SetLength(Result, Length(arrayMatrix));
for i := 0 to High(Result) do
Result[i] := CloneMatrixInt(matrix[i]);
end;

你猜怎么着,和以前一模一样的代码!

考虑到这个问题,以及你之前的问题,我可以建议你不要试图使用Move来解决所有问题吗。没有理由认为你遇到的任何问题都会通过使用Move来解决。

最后一点。锯齿形阵列的分配成本很高,因为它们需要多次分配。它们的操作效率也很低,因为它们不是连续存储的。Delphi缺少多维数组类型,如果需要最终的性能,那么最好实现多维数组类型。

最新更新