如何在 integer/real 的二维动态数组上使用 move?

How to use move on 2-Dimension Dynamic Arrays of integer/real?

在我的 Delphi Rio 应用程序中,我使用了很多二维动态数组。为了加快一些操作,我想使用移动命令而不是复制。我可以让它适用于 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缺少多维数组类型,如果需要极致性能,那么最好实现多维数组类型。