Difference between revisions of "Dynamic array/es"

From Free Pascal wiki
Jump to navigationJump to search
m (error mecanográfico)
 
(3 intermediate revisions by the same user not shown)
Line 52: Line 52:
 
&nbsp;&nbsp;&nbsp;En este ejemplo, los indices válidos para la matriz <syntaxhighlight lang="pascal" inline>ejemplos</syntaxhighlight> serán, para la primera dimensión el rango <syntaxhighlight lang="pascal" inline>0..11</syntaxhighlight>, y para la segunda dimensión eñ rango <syntaxhighlight lang="pascal" inline>0..63</syntaxhighlight>.
 
&nbsp;&nbsp;&nbsp;En este ejemplo, los indices válidos para la matriz <syntaxhighlight lang="pascal" inline>ejemplos</syntaxhighlight> serán, para la primera dimensión el rango <syntaxhighlight lang="pascal" inline>0..11</syntaxhighlight>, y para la segunda dimensión eñ rango <syntaxhighlight lang="pascal" inline>0..63</syntaxhighlight>.
  
&nbsp;&nbsp;&nbsp;Un hecho bastante útil es que, debido a que las matrices dinámicas multidimensionales son siempre “matricess de matricess”, la limitación de que todas las dimensiones deben ser del mismo tamaño no se aplica a ellas. Las diferentes dimensiones se implementan como matrices y cada una puede tener su propio tamaño.  
+
&nbsp;&nbsp;&nbsp;Un hecho bastante útil es que, debido a que las matrices dinámicas multidimensionales son siempre “matrices de matrices”, la limitación de que todas las dimensiones deben ser del mismo tamaño no se aplica a ellas. Las diferentes dimensiones se implementan como matrices y cada una puede tener su propio tamaño.  
  
 
&nbsp;&nbsp;&nbsp;Por ejemplo:
 
&nbsp;&nbsp;&nbsp;Por ejemplo:
Line 120: Line 120:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== handling ===
+
=== Manejando ===
Keep in mind dynamic arrays are pointers.
+
&nbsp;&nbsp;&nbsp;Debemos tener en cuenta que las matrices dinámicas son punteros.
Assigning dynamic array variables to each other does not copy any payload, but just the address.
+
La asignación de variables de matriz dinámica entre sí no copia ninguna carga útil, los datos en sí, si no solo la dirección de la matriz.
This differs from static arrays’ behavior.
+
Esto difiere del comportamiento de las matrices estáticas.
 +
 
 +
&nbsp;&nbsp;&nbsp;Si queremos duplicar los datos, usaremos {{Doc|package=RTL|unit=system|identifier=copy|text=<syntaxhighlight lang="pascal" inline>system.copy</syntaxhighlight>}}.  
  
If you want to duplicate data you have to use {{Doc|package=RTL|unit=system|identifier=copy|text=<syntaxhighlight lang="pascal" inline>system.copy</syntaxhighlight>}}.
 
 
<syntaxhighlight lang="pascal" line highlight="25">
 
<syntaxhighlight lang="pascal" line highlight="25">
program dynamicArrayCopyDemo(input, output, stdErr);
+
program CopiaMatricesDinamicas(input, output, stdErr);
  
 
var
 
var
foo, bar: array of char;
+
algo, tasca: array of char;
  
procedure printArrays;
+
procedure ImprimeMatrices;
 
begin
 
begin
writeLn('foo[0] = ', foo[0], '; bar[0] = ', bar[0]);
+
writeLn('algo[0] = ', algo[0], '; tasca[0] = ', tasca[0]);
 
end;
 
end;
  
 
begin
 
begin
setLength(foo, 1);
+
setLength(algo, 1);
foo[0] := 'X';
+
algo[0] := 'X';
// copies _reference_
+
// copia  la referencia
bar := foo;
+
tasca := algo;
write('    initial values: ');
+
write('    valores iniciales: ');
printArrays;
+
ImprimeMatrices;
 
 
// change content _via_ _second_ reference
+
// cambiar datos con segunda referencia
bar[0] := 'O';
+
tasca[0] := 'O';
write('changed via 2nd ref: ');
+
write('cambio con 2ª ref: ');
printArrays;
+
ImprimeMatrices;
 
 
// copy content
+
// copiar contenido
bar := copy(foo, 0, length(foo));
+
tasca := copy(algo, 0, length(algo));
bar[0] := 'X';
+
tasca[0] := 'X';
write(' copied and changed: ');
+
write(' copiado y cambiado: ');
printArrays;
+
ImprimeMatrices;
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
Only by using <syntaxhighlight lang="pascal" inline>copy</syntaxhighlight> both arrays can be modified independently.
+
&nbsp;&nbsp;&nbsp;Únicamente usando <syntaxhighlight lang="pascal" inline>copy</syntaxhighlight> ambas matrices se pueden modificar de forma independiente.
  
As stated above, <syntaxhighlight lang="pascal" inline>setLength</syntaxhighlight> ''copies'' data.
+
&nbsp;&nbsp;&nbsp;Como se indicó anteriormente, <syntaxhighlight lang="pascal" inline>setLength</syntaxhighlight> ''copia'' datos.
This procedure can be used to make data unique again, despite the fact only the references, the pointers (so just addresses) have been copied (<syntaxhighlight lang="pascal" inline>bar := foo</syntaxhighlight>).
+
Este procedimiento se puede usar para hacer que los datos sean únicos, a pesar de que solo se han copiado las referencias, los punteros (así que solo las direcciones) (<syntaxhighlight lang="pascal" inline>tasca := algo</syntaxhighlight>).
The highlighted line in the example above could be replaced by <syntaxhighlight lang="pascal" inline>setLength(bar, length(bar))</syntaxhighlight>, though the <syntaxhighlight lang="pascal" inline>copy</syntaxhighlight> function is preferred as it is more explanatory.
+
La línea resaltada en el ejemplo anterior podría reemplazarse por <syntaxhighlight lang="pascal" inline>setLength(tasca, length(tasca))</syntaxhighlight>, aunque la función <syntaxhighlight lang="pascal" inline>copy</syntaxhighlight> es preferible ya que es más explícita y clara.  
  
Dynamic arrays are reference counted.
+
&nbsp;&nbsp;&nbsp;Las matrices dinámicas se cuentan por referencia.
Calling <syntaxhighlight lang="pascal" inline>setLength(myDynamicArrayVariable, 0)</syntaxhighlight> virtually does [[Nil|<syntaxhighlight lang="pascal" inline>myDynamicArrayVariable := nil</syntaxhighlight>]] and decreases the reference count.
+
Llamar a <syntaxhighlight lang="pascal" inline>setLength(miVaribleMatrizDinamica, 0)</syntaxhighlight> en la práctica es equivalente a [[Nil|<syntaxhighlight lang="pascal" inline>miVaribleMatrizDinamica := nil</syntaxhighlight>]] y disminuye el recuento de referencias.
Only when the reference count hits zero, the memory block is released.
+
Al llegar el recuento de referencias a cero, se libera el bloque de memoria que ocupa la matriz.  
 
<syntaxhighlight lang="pascal" line highlight="9,10,15">
 
<syntaxhighlight lang="pascal" line highlight="9,10,15">
program dynamicArrayNilDemo(input, output, stdErr);
+
program VaribleMatrizDinamicaNilDemo(input, output, stdErr);
 
var
 
var
foo, bar: array of char;
+
algo, tasca: array of char;
 
begin
 
begin
setLength(foo, 1);
+
setLength(algo, 1);
foo[0] := 'X';
+
algo[0] := 'X';
// copy _reference_, increase reference count
+
// copia refencia, se incrementa la cuenta
bar := foo;
+
tasca := algo;
// foo becomes nil, reference count is decreased
+
// a algo toma el valor "nil", el recuento de referencias disminuye
setLength(foo, 0);
+
setLength(algo, 0);
writeLn('length(foo) = ', length(foo),
+
writeLn('length(algo) = ', length(algo),
'; length(bar) = ', length(bar));
+
'; length(tasca) = ', length(tasca));
 
 
// decrease reference count another time
+
// el recuento vuelve a decrecer
bar := nil;
+
tasca := nil;
writeLn('length(foo) = ', length(foo),
+
writeLn('length(algo) = ', length(algo),
'; length(bar) = ', length(bar));
+
'; length(tasca) = ', length(tasca));
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
Nonetheless, dynamic arrays are finalized automatically.
 
It is not necessary to manually <syntaxhighlight lang="pascal" inline>setLength(…, 0)</syntaxhighlight> on all your references when the program comes to end, or when leaving a scope in general.
 
  
Without <syntaxhighlight lang="pascal" inline>{$rangeChecks on}</syntaxhighlight> it is possible to reach beyond an array’s limits.
+
&nbsp;&nbsp;&nbsp;Las matrices dinámicas se finalizan automáticamente.
That means when iterating over dynamic arrays, it is impossible to work without {{Doc|package=RTL|unit=system|identifier=low|text=<syntaxhighlight lang="pascal" inline>low</syntaxhighlight>}} and {{Doc|package=RTL|unit=system|identifier=high|text=<syntaxhighlight lang="pascal" inline>high</syntaxhighlight>}} to determine valid indices (the former being optional, since dynamic arrays always start at zero).
+
No es necesario hacer explícitamente <syntaxhighlight lang="pascal" inline>setLength(..., 0)</syntaxhighlight> en todas las referencias cuando el programa llega a su fin, o cuando sale de un alcance en general.
Alternatively, [[for-in loop|<syntaxhighlight lang="pascal" inline>for … in</syntaxhighlight> loops]] can be used, if no index is required.
+
 
 +
&nbsp;&nbsp;&nbsp;Sin <syntaxhighlight lang="pascal" inline>{$rangeChecks on}</syntaxhighlight> es posible llegar más allá de los límites de una matriz.
 +
Eso significa que al iterar sobre matrices dinámicas, es imposible trabajar sin {{Doc|package=RTL|unit=system|identifier=low|text=<syntaxhighlight lang="pascal" inline>low</syntaxhighlight>}} y {{Doc|package=RTL|unit=system|identifier=high|text=<syntaxhighlight lang="pascal" inline>high</syntaxhighlight>}} para determinar índices válidos (el primero es opcional, ya que las matrices dinámicas siempre comienzan en cero ).
 +
Alternativamente, se pueden usar [[for-in loop|<syntaxhighlight lang="pascal" inline>for … in</syntaxhighlight> loops]], si no se necesita el índice.
  
Remember, [[SizeOf#dynamic arrays and alike|<syntaxhighlight lang="pascal" inline>sizeOf</syntaxhighlight>]] of a dynamic array evaluates to the size of a pointer.
+
&nbsp;&nbsp;&nbsp;Recordemos que, [[SizeOf#matrices dinámicas y similares|<syntaxhighlight lang="pascal" inline>sizeOf</syntaxhighlight>]] de una matriz dinámica se evalúa como el tamaño de un puntero.
  
== application ==
+
== Definición ==
* there is {{Doc|package=RTL|unit=system|identifier=tboundarray|text=<syntaxhighlight lang="pascal" inline>system.tBoundArray</syntaxhighlight>}} and {{Doc|package=RTL|unit=objpas|identifier=tboundarray|text=<syntaxhighlight lang="pascal" inline>objPas.tBoundArray</syntaxhighlight>}}
+
* Está en {{Doc|package=RTL|unit=system|identifier=tboundarray|text=<syntaxhighlight lang="pascal" inline>system.tBoundArray</syntaxhighlight>}} y {{Doc|package=RTL|unit=objpas|identifier=tboundarray|text=<syntaxhighlight lang="pascal" inline>objPas.tBoundArray</syntaxhighlight>}}
  
== see also ==
+
== Ver además ==
* [[String|<syntaxhighlight lang="pascal" inline>string</syntaxhighlight>]]
+
* [[String|<syntaxhighlight lang="pascal" inline>string</syntaxhighlight> cadena de texto]]
* example: [[Example: Multidimensional dynamic array|multidimensional dynamic array]]
+
* Ejemplo: [[Example: Multidimensional dynamic array|Matriz dinámica multidimensional]]
* [https://www.freepascal.org/docs-html/ref/refsu14.html#x38-510003.3.1 Free Pascal Reference guide: “Dynamic arrays”]
+
* [https://www.freepascal.org/docs-html/ref/refsu14.html#x38-510003.3.1 Guía de referencia de Free Pascal: “Matrices dinámicas”]
  
 
[[Category: Code]]
 
[[Category: Code]]

Latest revision as of 19:28, 11 May 2022

English (en) español (es) suomi (fi) français (fr) 日本語 (ja) русский (ru)

   Una matriz dinámica es una matriz cuyas dimensiones no son conocidas hasta que se usan, es decir no se saben en el momento de compilar el programa. EL tipo matriz dinámica no es el único tipo que puede proveer matrices de longitud variable, pero hasta hoy es el único que admite el compilador FPC.

Utilización

Concepto

   La definción de la matriz dinámica únicamene reserva el espacio en memoria para un puntero.

   Durante la ejecución diversas rutinas asegurarán un uso adecuado pero, y lo que es más importante, la sintaxis de acceso a los elementos de una matriz colocando índices entre corchetes es compatible con el compilador, implementado como desreferenciación automática del puntero.

   Los índices de las matrices dinámicas son siempre números enteros no negativos que comienzan en cero para el primer elemento. No es posible utilizar un tipo enumerado o cualquier otro tipo ordinal como índice. El primer elemento siempre es de índice 0 ; esto no se puede cambiar.

Definición

   Una matriz dinámica de una dimensión se define así:

 array of <type>;

   No se especifican el tamaño de dimensiones, esta es la diferencia con la definición de una matriz corriente.

   Para definir una matriz multidimensional, se especifica una matriz como el tipo base, creando así una "matriz de matrices":

 array of array of <type>;

Dimensiones

   El procedimiento del compiladorsetLength se usa para cambiar las dimensiones de una matriz dinámica, siempre que haya suficiente memoria.

1program DimesionarDemo(input, output, stdErr);
2var
3	cedazo: array of longWord;
4begin
5	setLength(cedazo, 1337);
6end.

   El procedimiento reserva memoria para 1337 elementos del tipo especificado y para los datos necesarios para manejarlos. Los elementos preexistentes de la matriz se conservan, y los nuevos elementos se inicializan con el valor predeterminado (default) del tipo de los elementos de la matriz

   Es importante remarcar que, dado que todos los elementos se copian con setLength, puede ser extremadamente ineficiente con matrices grandes o dentro de bucles internos.

   A las matrices multidimensionales también se les asignan sus dimensiones, y pueden ser redimensionadas, con setLength, especificando las dimensiones necesarias de esta forma:

1program multidimensionalSetLengthDemo(input, output, stdErr);
2var
3	ejemplos: array of array of smallInt;
4begin
5	setLength(ejemplos, 12, 64);
6end.

   En este ejemplo, los indices válidos para la matriz ejemplos serán, para la primera dimensión el rango 0..11, y para la segunda dimensión eñ rango 0..63.

   Un hecho bastante útil es que, debido a que las matrices dinámicas multidimensionales son siempre “matrices de matrices”, la limitación de que todas las dimensiones deben ser del mismo tamaño no se aplica a ellas. Las diferentes dimensiones se implementan como matrices y cada una puede tener su propio tamaño.

   Por ejemplo:

 1program PotenciaBinomica(input, output, stdErr);
 2var
 3	TrianguloDePascal: array of array of longWord;
 4	exponente: longInt;
 5	factor: longInt;
 6begin
 7	setLength(TrianguloDePascal, 20);
 8	
 9	setLength(TrianguloDePascal[0], 1);
10	TrianguloDePascal[0][0] := 1;
11	
12	setLength(TrianguloDePascal[1], 2);
13	TrianguloDePascal[1][0] := 1;
14	TrianguloDePascal[1][1] := 1;
15	
16	// Contruimos los valores por simple adición
17	for exponent := 2 to high(TrianguloDePascal) do
18	begin
19		setLength(TrianguloDePascal[exponente], exponent + 1);
20		TrianguloDePascal[exponente][0] := 1;
21		TrianguloDePascal[exponente][exponente] := 1;
22		for factor := 1 to exponente - 1 do
23		begin
24			TrianguloDePascal[exponente][factor] :=
25				TrianguloDePascal[exponente - 1][factor - 1] +
26				TrianguloDePascal[exponente - 1][factor];
27		end;
28	end;
29	
30	// ...

initializing

   Desde FPC 3.0.0 los tipos de matrices dinámicas que no son anónimos son dotadas automáticamente de un "constructor", como es habitual en la programación orientada a objetos. Esto permite una llamada implícita a setLength con una serie de asignaciones en una única sentencia:

1program CrearMatrizDinamicaDemo(input, output, stdErr);
2type
3	verdades = array of boolean;
4var
5	l: verdades;
6begin
7	l := verdades.create(false, true, true, false, true, false, false);
8end.

   Esto es aplicable a las matrices de matrices, obviamente:

 1program CrearMatricesDinamicasAnidadasDemo(input, output, stdErr);
 2type
 3	verdades = array of boolean;
 4	patron = array of verdades;
 5var
 6	p: patron;
 7begin
 8	p := patron.create(
 9			verdades.create(false, false),
10			verdades.create(true, false),
11			verdades.create(true, false, false),
12			verdades.create(true, true, false)
13		);
14end.

Manejando

   Debemos tener en cuenta que las matrices dinámicas son punteros. La asignación de variables de matriz dinámica entre sí no copia ninguna carga útil, los datos en sí, si no solo la dirección de la matriz. Esto difiere del comportamiento de las matrices estáticas.

   Si queremos duplicar los datos, usaremos system.copy.

 1program CopiaMatricesDinamicas(input, output, stdErr);
 2
 3var
 4	algo, tasca: array of char;
 5
 6procedure ImprimeMatrices;
 7begin
 8	writeLn('algo[0] = ', algo[0], '; tasca[0] = ', tasca[0]);
 9end;
10
11begin
12	setLength(algo, 1);
13	algo[0] := 'X';
14	// copia  la referencia
15	tasca := algo;
16	write('     valores iniciales: ');
17	ImprimeMatrices;
18	
19	// cambiar datos con segunda referencia
20	tasca[0] := 'O';
21	write('cambio con 2ª ref: ');
22	ImprimeMatrices;
23	
24	// copiar contenido
25	tasca := copy(algo, 0, length(algo));
26	tasca[0] := 'X';
27	write(' copiado y cambiado: ');
28	ImprimeMatrices;
29end.

   Únicamente usando copy ambas matrices se pueden modificar de forma independiente.

   Como se indicó anteriormente, setLength copia datos. Este procedimiento se puede usar para hacer que los datos sean únicos, a pesar de que solo se han copiado las referencias, los punteros (así que solo las direcciones) (tasca := algo). La línea resaltada en el ejemplo anterior podría reemplazarse por setLength(tasca, length(tasca)), aunque la función copy es preferible ya que es más explícita y clara.

   Las matrices dinámicas se cuentan por referencia. Llamar a setLength(miVaribleMatrizDinamica, 0) en la práctica es equivalente a miVaribleMatrizDinamica := nil y disminuye el recuento de referencias. Al llegar el recuento de referencias a cero, se libera el bloque de memoria que ocupa la matriz.

 1program VaribleMatrizDinamicaNilDemo(input, output, stdErr);
 2var
 3	algo, tasca: array of char;
 4begin
 5	setLength(algo, 1);
 6	algo[0] := 'X';
 7	// copia refencia, se incrementa la cuenta
 8	tasca := algo;
 9	//  a algo toma el valor "nil", el recuento de referencias disminuye
10	setLength(algo, 0);
11	writeLn('length(algo) = ', length(algo),
12		'; length(tasca) = ', length(tasca));
13	
14	// el recuento vuelve a decrecer
15	tasca := nil;
16	writeLn('length(algo) = ', length(algo),
17		'; length(tasca) = ', length(tasca));
18end.

   Las matrices dinámicas se finalizan automáticamente. No es necesario hacer explícitamente setLength(..., 0) en todas las referencias cuando el programa llega a su fin, o cuando sale de un alcance en general.

   Sin {$rangeChecks on} es posible llegar más allá de los límites de una matriz. Eso significa que al iterar sobre matrices dinámicas, es imposible trabajar sin low y high para determinar índices válidos (el primero es opcional, ya que las matrices dinámicas siempre comienzan en cero ). Alternativamente, se pueden usar for in loops, si no se necesita el índice.

   Recordemos que, sizeOf de una matriz dinámica se evalúa como el tamaño de un puntero.

Definición

Ver además