Difference between revisions of "Dynamic array/es"
(Traducción inicial, en curso) |
|||
Line 35: | Line 35: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | El procedimiento reserva memoria para 1337 elementos del tipo especificado y para los datos | + | 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 |
− | | + | 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. |
− | |||
− | |||
− | + | 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: | |
− | |||
<syntaxhighlight lang="pascal" line highlight="5"> | <syntaxhighlight lang="pascal" line highlight="5"> | ||
program multidimensionalSetLengthDemo(input, output, stdErr); | program multidimensionalSetLengthDemo(input, output, stdErr); | ||
var | var | ||
− | + | ejemplos: array of array of smallInt; | |
begin | begin | ||
− | setLength( | + | setLength(ejemplos, 12, 64); |
end. | end. | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | + | 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>. | |
− | + | ||
− | + | 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: | ||
<syntaxhighlight lang="pascal" line highlight="7,9,12,19"> | <syntaxhighlight lang="pascal" line highlight="7,9,12,19"> | ||
− | program | + | program PotenciaBinomica(input, output, stdErr); |
var | var | ||
− | + | TrianguloDePascal: array of array of longWord; | |
− | + | exponente: longInt; | |
factor: longInt; | factor: longInt; | ||
begin | begin | ||
− | setLength( | + | setLength(TrianguloDePascal, 20); |
− | setLength( | + | setLength(TrianguloDePascal[0], 1); |
− | + | TrianguloDePascal[0][0] := 1; | |
− | setLength( | + | setLength(TrianguloDePascal[1], 2); |
− | + | TrianguloDePascal[1][0] := 1; | |
− | + | TrianguloDePascal[1][1] := 1; | |
− | // | + | // Contruimos los valores por simple adición |
− | for exponent := 2 to high( | + | for exponent := 2 to high(TrianguloDePascal) do |
begin | begin | ||
− | setLength( | + | setLength(TrianguloDePascal[exponente], exponent + 1); |
− | + | TrianguloDePascal[exponente][0] := 1; | |
− | + | TrianguloDePascal[exponente][exponente] := 1; | |
− | for factor := 1 to | + | for factor := 1 to exponente - 1 do |
begin | begin | ||
− | + | TrianguloDePascal[exponente][factor] := | |
− | + | TrianguloDePascal[exponente - 1][factor - 1] + | |
− | + | 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
- there is
system.tBoundArray
andobjPas.tBoundArray