有没有办法将整个数组复制到另一个数组? (除了使用For循环)

时间:2010-08-23 07:20:13

标签: delphi

有没有办法将整个数组复制到另一个数组?除了使用for-loop之外。

movecopy命令是否适用于此? 我确实尝试了,但它有一个错误:“不兼容的类型”。

我应该坚持使用for循环吗?

7 个答案:

答案 0 :(得分:20)

为了安全起见,请在动态数组上使用Copy函数,因为它在内部处理托管类型。数组必须是相同的类型,即在相同的表达式中声明:

var  
    a, b: array of string;

或通过定义自定义数组类型:

type   
    TStringArray = array of string;  
var 
    a: TStringArray;  
//...and somewhere else
var  
    b: TStringArray;  

然后你可以这样做:

a := Copy(b, Low(b), Length(b));  //really clean, but unnecessary 
//...or   
a := Copy(b, 0, MaxInt);  //dynamic arrays always have zero low bound 
                          //and Copy copies only "up to" Count items  

你必须在静态数组上使用循环以及混合数组类型时(不是我建议这样做)。
如果你真的必须使用Move,请记住检查零长度,因为A[0]构造可以引发范围检查错误,(由SizeOf(A[0])引人注目的例外,它由编译器处理魔法,永远不会执行) 此外从不假设A = A[0]SizeOf(A) = Length(A) * SizeOf(A[0]),因为这仅适用于静态数组,如果您稍后尝试将巨大的代码库重构为动态数组,它将会非常糟糕。

答案 1 :(得分:6)

对于动态数组:

var A,B: array of Byte;

begin
  SetLength(A, <size>);
  //initialize A

  B:= A; 
  SetLength(B,Length(A));

end;

在动态数组中,赋值语句仅复制对数组的引用,而SetLength执行物理复制/复制它的工作,留下两个独立的独立动态数组。

答案 2 :(得分:4)

请参阅article on delphibasics.co.uk

您可以使用复制方法复制数组(传入0表示索引,传递长度(源)作为计数以复制完整内容)。

不要将Move或CopyMemory用于字符串/数组/接口/ etc托管类型的数组。这样做会绕过Delphi的引用计数机制,并导致内存泄漏和数据损坏。

答案 3 :(得分:2)

1-如果您的数组不包含任何字符串或动态数组,则可以使用move,但动态数组不会像固定大小的数组那样处理:

var A,B: array[0..10] of integer;
    DA, DB: array of double;
    i: integer;
begin
  for i := low(A) to high(A) do
    A[i] := i;
  move(A[0],B[0],length(A)*sizeof(A[0]));  // first version, compiler does the stuff
  move(A[0],B[0],sizeof(A)); // it works
  move(A[0],B[0],40); // if you know what you're doing, since sizeof(A)=40
  SetLength(DA,10); // DA[0]..DA[9]
  for i := 0 to high(DA) do // or for i := 0 to 9 if you know what you're doing
    DA[i] := 
  SetLength(DB,length(DA)); 
  if length(DA)<=length(DB) then // if your dynamic array may be void, use this before to avoid GPF
    move(DA[0],DB[0],length(DA)*sizeof(DA[0]));
  if pointer(DA)<>nil then // this will just check that DA[] is not void
    move(pointer(DA)^,pointer(DB)^,length(DA)*sizeof(double)); // similar to previous
end;

2-如果您的数组包含字符串或其他引用内容数组,则必须使用循环:

var A,B: array[0..10] of string;
    i: integer;
begin
  for i := 0 to high(A) do
    A[i] := IntToStr(i);
  for i := 0 to high(A) do
    B[i] := A[i]; // this doesn't copy the string content, just add a reference count to every A[], and copy a pointer: it's very fast indeed
end;

答案 4 :(得分:0)

您可以使用使用泛型函数将数组复制到动态 TArray 变量的记录类型,我已经开始使用:

 TGen = record // Unused record to allow generic functions.
 public
      ...
       class function arrayCopy<T>(const a: array of T): TArray<T>; static;
 end;



class function TGen.arrayCopy<T>(const a: array of T): TArray<T>;
var i: integer;
begin
  SetLength(result, length(a));
  for i := Low(a) to High(a) do
    result[i] := a[i];
end;

给定一个表单变量

dtls: TArray<TGridSetupDetails>;

以及从枚举类型上的数组分配的参数

const adtls: array of TGridSetupDetails

您可以初始化表单变量:

  dtls := TGen.arrayCopy<TGridSetupDetails>(adtls);

答案 5 :(得分:-2)

嗯...调用RtlMoveMemory API .... 但这确实是一个for循环...... OK.let希望它已经被SIMD指令优化了...... 或ASM并自己拨打SIMD说明......

答案 6 :(得分:-3)

移动或复制不起作用,你可以使用CopyMemory,但这要求数组是一个有名的内存块。

SetLength(DestArray, Length(MyArray));
CopyMemory(@DestArray[0], @MyArray[0], Length(MyArray) * SizeOf(ArrayElement));