2010-08-23 15 views
9

¿Hay alguna forma de copiar toda la matriz en otra matriz? Aparte de usar un for-loop.¿Hay forma de copiar toda la matriz en otra matriz? (Aparte de usar un bucle For)

¿Funciona el comando move o copy para esto? Lo intenté pero tenía un error: "Tipos incompatibles".

¿Debo seguir con el for-loop?

+0

Move usa un bucle for. Al menos lo hizo en Delphi 7. ¿Qué código causó el error? –

+0

No lo sabía. Mover y Copiar ambos causaron un error. (No los usé al mismo tiempo) – Dian

+4

Move no usa un ciclo for. Está escrito en asm, incluso en Delphi 7, y usa un rep movsd/movsb con Delphi 7, o instrucciones FPU mucho más rápidas en la versión más nueva de Delphi. –

Respuesta

15

para estar en el lado seguro, utiliza la función Copy en matrices dinámicas, ya que maneja los tipos administrados internamente. Las matrices deben ser del mismo tipo, es decir declarados en la misma expresión:

var 
    a, b: array of string; 

o mediante la definición de un tipo de matriz personalizada:

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

entonces usted puede hacer:

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 

Tendrás que usar un bucle en matrices estáticas y al mezclar tipos de matrices (no es que yo recomiende hacerlo).
Si realmente tiene que usar Move, recuerde verificar la longitud cero, ya que las construcciones A[0] pueden aumentar los errores de comprobación de rango (con la notable excepción de SizeOf(A[0]), que se maneja mediante compilación mágica y nunca se ejecuta realmente).
También nunca suponga que A = A[0] o SizeOf(A) = Length(A) * SizeOf(A[0]), ya que esto es cierto solo para matrices estáticas y le morderá mucho si más adelante trata de refactorizar una gran base de código para matrices dinámicas.

+5

Aunque es conveniente usar límites superiores e inferiores codificados como 0 y 'MaxInt', es incluso más conveniente omitir los límites por completo:' a: = Copiar (b) '. Eso copia toda la matriz. –

+0

@Viktor, puede compartir el truco 'Copiar (Fuente)' con nuestro checo * "MVP" *, ya que parece que acaba de descubrir la posibilidad de omitir el último parámetro (lástima que visite accidentalmente su blog). – TLama

0

hmm ... llamar a la API RtlMoveMemory .... Pero eso es un bucle for ... de hecho esperanza de OK.let ya está optimizada por instrucciones SIMD ... o ASM y llamar a las instrucciones SIMD mismo ..

-2

Mover o copiar no funcionarán, podría usar CopyMemory pero esto requiere que la matriz sea un bloque de memoria contiguo.

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

Y si la matriz contiene punteros a tipos gestionados (cadenas, otras matrices dinámicas, referencias de interfaz, ...), las recotaciones ** no ** se incrementarán. –

+1

Quiere decir "Mover no siempre funcionará". Simplemente copia un grupo de bytes de una posición en la memoria a otra. Eso puede mover una matriz muy bien, siempre que la matriz ocupe un bloque contiguo de memoria. –

+2

Move y CopyMemory son idénticos (en función; la única diferencia es que CopyMemory acepta punteros como argumentos, mientras que Move acepta variables (punteros desreferenciados)). –

4

Ver article on delphibasics.co.uk

puede copiar una matriz mediante el método de copia (pasa de 0 para el índice y Longitud (Fuente) como el recuento para copiar el contenido completo).

NO utilice Move or CopyMemory para matrices de tipos gestionados string/array/interface/etc. Si lo hace, omitirá la mecánica de recuento de ref de Delphi y dará como resultado pérdidas de memoria y datos dañados.

2

1- Si la matriz no contiene ninguna cadena o una tabla dinámica, puede utilizar movimiento, pero matrices dinámicas no deben ser manejados como matrices de tamaño fijo:

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- Si la matriz contiene cadenas o otra matriz contenido de referencia, hay que utilizar un bucle:

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

Para matrices dinámicas:

var A,B: array of Byte; 

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

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

end; 

En matrices dinámicas, los duplicados instrucción de asignación sólo la referencia a la matriz, mientras que SetLength hace el trabajo de copia física/duplicarla, dejando dos matrices dinámicas separadas e independientes.

Cuestiones relacionadas