2010-08-23 1 views
9

Gibt es eine Möglichkeit, das gesamte Array in ein anderes Array zu kopieren? Anders als eine For-Schleife zu verwenden.Gibt es eine Möglichkeit, das gesamte Array in ein anderes Array zu kopieren? (Anders als bei Verwendung einer For-Schleife)

Funktioniert der Befehl move oder copy dafür? Ich habe es versucht, aber es hatte einen Fehler: "Inkompatible Typen".

Sollte ich bei der For-Schleife bleiben?

+0

Move verwendet eine for-Schleife. Zumindest hat es in Delphi 7 getan. Welcher Code hat den Fehler verursacht? –

+0

Ich wusste das nicht. Verschieben und Kopieren beide verursachten einen Fehler. (Ich habe sie nicht zur gleichen Zeit verwendet) – Dian

+4

Move verwendet keine for-Schleife. Es ist in asm geschrieben, sogar in Delphi 7, und verwendet entweder eine rep movsd/movsb mit Delphi 7 oder viel schnellere FPU-Anweisungen in neueren Delphi-Version. –

Antwort

15

auf der sicheren Seite zu sein, verwenden Sie die Copy Funktion auf dynamische Arrays, wie es auch die verwalteten Typen intern behandelt. Die Arrays vom gleichen Typ sein, dh im selben Ausdruck erklärt:

var 
    a, b: array of string; 

oder durch einen benutzerdefinierten Array-Typen definieren:

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

dann können Sie tun:

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 

Sie müssen eine Schleife auf statischen Arrays und beim Mischen von Array-Typen verwenden (nicht, dass ich es empfehlen würde).
Wenn Sie wirklich verwenden müssen, denken Sie daran, auf Null-Länge zu überprüfen, wie die A[0] Konstrukte Bereich Überprüfung Fehler auslösen können, (mit der bemerkenswerten Ausnahme SizeOf(A[0]), die von Compiler Magie behandelt wird und nie tatsächlich ausgeführt wird). Auch nie angenommen, dass A = A[0] oder SizeOf(A) = Length(A) * SizeOf(A[0]), da dies nur für statische Arrays wahr ist und es wird Sie wirklich schlecht beißen, wenn Sie später versuchen, riesige Codebasis zu dynamischen Arrays umzuformen.

+5

Obwohl es bequem ist, hart codierte obere und untere Grenzen wie 0 und 'MaxInt' zu verwenden, ist es noch bequemer, die Grenzen ganz wegzulassen:' a: = Copy (b) '. Das kopiert das gesamte Array. –

+0

@Viktor, könnten Sie den 'Copy (Source)' Trick mit unserem tschechischen * "MVP" * teilen, da er gerade die Möglichkeit entdeckt hat, den letzten Parameter wegzulassen (Schande über mich, dass er versehentlich seinen Blog besucht). – TLama

0

hmm ... rufen RtlMoveMemory API .... Aber das ist eine for-Schleife in der Tat ... Hoffnung OK.let es von SIMD-Befehle bereits optimiert ist ... oder ASM und rufen Sie sich SIMD-Befehle .. .

-2

Verschieben oder Kopieren funktioniert nicht, Sie könnten CopyMemory verwenden, aber dafür ist das Array ein gemeinsamer Speicherblock.

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

Und wenn das Array Zeiger auf verwaltete Typen (Strings, andere dynamische Arrays, Schnittstellenreferenzen, ...) enthält, werden die refcounts ** nicht ** inkrementiert. –

+1

Sie meinen "Move wird nicht _always_ work". Es kopiert nur eine Reihe von Bytes von einer Position im Speicher zu einer anderen. Das kann ein Array gut bewegen, vorausgesetzt, das Array belegt einen zusammenhängenden Speicherblock. –

+2

Move und CopyMemory sind identisch (in der Funktion - der einzige Unterschied ist, dass CopyMemory Zeiger als Argumente akzeptiert, während Move Variablen akzeptiert (dereferenzierte Zeiger)). –

4

Siehe article on delphibasics.co.uk

Sie einen Array kopieren Copy-Methode (mit dem in 0 für den Index und Länge (Quelle) als Graf den gesamten Inhalt zu kopieren).

Verwenden Sie nicht Move oder CopyMemory für Arrays von string/array/interface/etc verwalteten Typen. Wenn Sie dies tun, umgehen Sie die ref-zählende Mechanik von Delphi und führen zu Speicherlecks und beschädigten Daten.

2

1- Wenn Ihr Array keine Zeichenfolge oder dynamische Array enthält, können Sie bewegen verwenden, aber dynamische Arrays sind nicht wie feste Größe Arrays gehandhabt werden:

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- Wenn Ihr Array enthält Strings oder anderen -Bezugsgehalt Array, müssen Sie eine Schleife verwenden:

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

Für dynamische Arrays:

var A,B: array of Byte; 

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

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

end; 

In dynamischen Arrays, die Zuordnungsanweisung Duplikate nur der Verweis auf das Array, während SetLength macht den Job von physisch Kopieren/Duplizieren es, so dass zwei getrennte, unabhängige dynamische Arrays.

Verwandte Themen