2010-08-23 75 views
9

有沒有辦法將整個數組複製到另一個數組?除了使用for循環。有沒有辦法將整個數組複製到另一個數組中? (除了使用For循環)

movecopy命令是否適用於此? 我確實嘗試過,但它有一個錯誤:「不兼容的類型」。

我應該堅持for循環嗎?

+0

Move使用for循環。至少它在Delphi 7中做過。什麼代碼導致了錯誤? – 2010-08-23 08:22:18

+0

我不知道。移動並複製兩者都會導致錯誤。 (雖然我沒有在同一時間使用它們) – Dian 2010-08-23 09:19:37

+4

移動不使用for循環。它是用asm編寫的,即使在Delphi 7中,也可以在Delphi 7中使用rep movsd/movsb,或者在更新的Delphi版本中使用更快的FPU指令。 – 2010-08-23 09:41:34

回答

15

爲了安全起見,在使用動態數組的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]),因爲這隻適用於靜態數組,它會咬死你真的很糟糕,如果你以後嘗試重構巨大的代碼庫動態數組。

+5

儘管使用像0和'MaxInt'這樣硬編碼的上下界很方便,但完全省略邊界更加方便:'a:= Copy(b)'。這複製整個陣列。 – 2013-10-02 02:55:12

+0

@Viktor,你可能會與我們的Czech *「MVP」*共享'Copy(Source)'技巧,因爲他似乎只是發現了遺漏最後一個參數的可能性(對我不小心訪問他們的博客感到羞恥)。 – TLama 2015-06-12 18:26:33

0

嗯......調用RtlMoveMemory API .... 但是,這是一個for循環確... OK.let的希望,它已經通過SIMD指令...... 或ASM並呼籲SIMD指令優化自己..

-2

移動或複製不起作用,您可以使用CopyMemory,但這需要數組是一個連續的內存塊。

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

如果數組包含指向託管類型(字符串,其他動態數組,接口引用等等)的指針,則refcounts不會**遞增。 – 2010-08-23 08:23:20

+1

你的意思是「移動將不會_always_工作」。它只是將一堆字節從內存中的一個位置複製到另一個位置。只要數組佔用連續的內存塊,就可以移動數組。 – 2010-08-23 08:23:59

+2

Move和CopyMemory是相同的(在函數中 - 唯一的區別是CopyMemory接受指針作爲參數,而Move接受變量(取消引用的指針))。 – 2010-08-23 11:21:22

4

參見article on delphibasics.co.uk

可以使用複製方法(傳遞0的索引和長度(源)作爲計數複製全部內容)複製的陣列。

不要使用Move或CopyMemory作爲字符串/數組/接口/ etc託管類型的數組。這樣做會繞過Delphi的ref-counting機制,並會導致內存泄漏和數據損壞。

2

1-如果陣列中不包含任何字符串或動態數組,你可以使用移動,但動態數組不被處理的類似固定大小的數組:如果陣列

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; 
5

對於動態數組:

var A,B: array of Byte; 

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

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

end; 

在動態陣列中,賦值語句重複僅參考陣列,而SetLength確實物理複製/複製它,留下兩個單獨的,獨立的動態陣列的工作。

相關問題