Difference between revisions of "Dynamic array/es"

From Lazarus wiki
Jump to navigationJump to search
(Traducción inicial, en curso)
 
Line 35: Line 35:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
&nbsp;&nbsp;&nbsp;El procedimiento reserva memoria para 1337 elementos del tipo especificado y para los datos necsarios para manejarlos. Los elementos preexistentes de la matriz se conservan, y los nuevos elementos se inicializan con el valor predeterminado del tipo
+
&nbsp;&nbsp;&nbsp;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 <syntaxhighlight lang="delphi" inline>predeterminado</syntaxhighlight> (<syntaxhighlight lang="delphi" inline>default</syntaxhighlight>) del tipo de los elementos de la matriz
  
&nbsp;&nbsp;&nbsp; Si
+
&nbsp;&nbsp;&nbsp;Es importante remarcar que, dado que todos los elementos se copian con <syntaxhighlight lang="pascal" inline>setLength</syntaxhighlight>, puede ser extremadamente ineficiente con matrices grandes o dentro de bucles internos.
It then {{Doc|package=RTL|unit=system|identifier=copyarray|text=''copies''}} all elements of the old incarnation to the new one.
 
New fields that did not exist before are initialized with the <syntaxhighlight lang="delphi" inline>default</syntaxhighlight> intrinsic.
 
  
It is important to remember that, since all elements are copied during <syntaxhighlight lang="pascal" inline>setLength</syntaxhighlight>, it can become extremely inefficient to use it with large arrays, or inside inner loops.
+
&nbsp;&nbsp;&nbsp;A las matrices multidimensionales también se les asignan sus dimensiones, y pueden ser redimensionadas, con <syntaxhighlight lang="pascal" inline>setLength</syntaxhighlight>, especificando las dimensiones necesarias de esta forma:
  
Multidimensional arrays can be resized with <syntaxhighlight lang="pascal" inline>setLength</syntaxhighlight>, too, by specifying multiple sizes in the call, like this:
 
 
<syntaxhighlight lang="pascal" line highlight="5">
 
<syntaxhighlight lang="pascal" line highlight="5">
 
program multidimensionalSetLengthDemo(input, output, stdErr);
 
program multidimensionalSetLengthDemo(input, output, stdErr);
 
var
 
var
samples: array of array of smallInt;
+
ejemplos: array of array of smallInt;
 
begin
 
begin
setLength(samples, 12, 64);
+
setLength(ejemplos, 12, 64);
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
In this example, valid indices for <syntaxhighlight lang="pascal" inline>samples</syntaxhighlight>’ first dimension are in the range <syntaxhighlight lang="pascal" inline>0..11</syntaxhighlight>, while valid indices for its second dimension are within <syntaxhighlight lang="pascal" inline>0..63</syntaxhighlight>.
 
  
One quite useful fact is that, because multidimensional dynamic arrays are always “arrays of arrays”, the limitation that all dimensions must be of the same size does not apply to them.
+
&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>.
Different dimensions are implemented as arrays, and can each have their own size.
+
 
For instance,
+
&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;Por ejemplo:
 
<syntaxhighlight lang="pascal" line highlight="7,9,12,19">
 
<syntaxhighlight lang="pascal" line highlight="7,9,12,19">
program binomialPotence(input, output, stdErr);
+
program PotenciaBinomica(input, output, stdErr);
 
var
 
var
pascalsTriangle: array of array of longWord;
+
TrianguloDePascal: array of array of longWord;
exponent: longInt;
+
exponente: longInt;
 
factor: longInt;
 
factor: longInt;
 
begin
 
begin
setLength(pascalsTriangle, 20);
+
setLength(TrianguloDePascal, 20);
 
 
setLength(pascalsTriangle[0], 1);
+
setLength(TrianguloDePascal[0], 1);
pascalsTriangle[0][0] := 1;
+
TrianguloDePascal[0][0] := 1;
 
 
setLength(pascalsTriangle[1], 2);
+
setLength(TrianguloDePascal[1], 2);
pascalsTriangle[1][0] := 1;
+
TrianguloDePascal[1][0] := 1;
pascalsTriangle[1][1] := 1;
+
TrianguloDePascal[1][1] := 1;
 
 
// construct values by simple addition
+
// Contruimos los valores por simple adición
for exponent := 2 to high(pascalsTriangle) do
+
for exponent := 2 to high(TrianguloDePascal) do
 
begin
 
begin
setLength(pascalsTriangle[exponent], exponent + 1);
+
setLength(TrianguloDePascal[exponente], exponent + 1);
pascalsTriangle[exponent][0] := 1;
+
TrianguloDePascal[exponente][0] := 1;
pascalsTriangle[exponent][exponent] := 1;
+
TrianguloDePascal[exponente][exponente] := 1;
for factor := 1 to exponent - 1 do
+
for factor := 1 to exponente - 1 do
 
begin
 
begin
pascalsTriangle[exponent][factor] :=
+
TrianguloDePascal[exponente][factor] :=
pascalsTriangle[exponent - 1][factor - 1] +
+
TrianguloDePascal[exponente - 1][factor - 1] +
pascalsTriangle[exponent - 1][factor];
+
TrianguloDePascal[exponente - 1][factor];
 
end;
 
end;
 
end;
 
end;

Revision as of 14:31, 9 March 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 “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.

   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

Since FPC 3.0.0 dynamic array types that are not anonymous are automatically equipped with a “constructor” as it might be familiar from object-oriented programming. This lets you unite setLength calls and a series of assignments in one statement:

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

Of course you can nest arrays as well:

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

handling

Keep in mind dynamic arrays are pointers. Assigning dynamic array variables to each other does not copy any payload, but just the address. This differs from static arrays’ behavior.

If you want to duplicate data you have to use system.copy.

 1program dynamicArrayCopyDemo(input, output, stdErr);
 2
 3var
 4	foo, bar: array of char;
 5
 6procedure printArrays;
 7begin
 8	writeLn('foo[0] = ', foo[0], '; bar[0] = ', bar[0]);
 9end;
10
11begin
12	setLength(foo, 1);
13	foo[0] := 'X';
14	// copies _reference_
15	bar := foo;
16	write('     initial values: ');
17	printArrays;
18	
19	// change content _via_ _second_ reference
20	bar[0] := 'O';
21	write('changed via 2nd ref: ');
22	printArrays;
23	
24	// copy content
25	bar := copy(foo, 0, length(foo));
26	bar[0] := 'X';
27	write(' copied and changed: ');
28	printArrays;
29end.

Only by using copy both arrays can be modified independently.

As stated above, setLength copies data. This procedure can be used to make data unique again, despite the fact only the references, the pointers (so just addresses) have been copied (bar := foo). The highlighted line in the example above could be replaced by setLength(bar, length(bar)), though the copy function is preferred as it is more explanatory.

Dynamic arrays are reference counted. Calling setLength(myDynamicArrayVariable, 0) virtually does myDynamicArrayVariable := nil and decreases the reference count. Only when the reference count hits zero, the memory block is released.

 1program dynamicArrayNilDemo(input, output, stdErr);
 2var
 3	foo, bar: array of char;
 4begin
 5	setLength(foo, 1);
 6	foo[0] := 'X';
 7	// copy _reference_, increase reference count
 8	bar := foo;
 9	// foo becomes nil, reference count is decreased
10	setLength(foo, 0);
11	writeLn('length(foo) = ', length(foo),
12		'; length(bar) = ', length(bar));
13	
14	// decrease reference count another time
15	bar := nil;
16	writeLn('length(foo) = ', length(foo),
17		'; length(bar) = ', length(bar));
18end.

Nonetheless, dynamic arrays are finalized automatically. It is not necessary to manually setLength(, 0) on all your references when the program comes to end, or when leaving a scope in general.

Without {$rangeChecks on} it is possible to reach beyond an array’s limits. That means when iterating over dynamic arrays, it is impossible to work without low and high to determine valid indices (the former being optional, since dynamic arrays always start at zero). Alternatively, for in loops can be used, if no index is required.

Remember, sizeOf of a dynamic array evaluates to the size of a pointer.

application

see also