Difference between revisions of "Dynamic array/ru"

From Free Pascal wiki
Jump to navigationJump to search
(Created page with " {{Dynamic array}} A dynamic array is an array whose dimensions are not known at compile-time. The dynamic array type is not the only type providin...")
 
 
(9 intermediate revisions by one other user not shown)
Line 2: Line 2:
 
{{Dynamic array}}
 
{{Dynamic array}}
  
A dynamic array is an [[Array|array]] whose dimensions are not known at [[Compile time|compile-time]].
+
Динамический массив - это [[Array/ru|массив]], размеры которого неизвестны во [[Compile time|время компиляции]].
The dynamic array type is not the only type providing variable-length arrays, but as of 2018 it is the only one [[FPC]] supports.
+
Динамический массив не является единственным типом, предоставляющим массивы переменной длины, но с 2018 года он является единственным, который  поддерживает [[FPC/ru|FPC]].
  
== usage ==
+
== Использование ==
=== concept ===
+
=== Концепция ===
A dynamic array's definition will only allocate space for a [[Pointer|pointer]].
+
Определение динамического массива будет выделять пространство только для [[Pointer/ru|указателя]].
During [[runtime]] various routines will ensure convenient usage, but most importantly the syntax how to access array's elements by placing indices in square brackets, is supported by the [[Compiler|compiler]] (implemented as automatic de-referencing the [[Pointer|pointer]]).
+
Во [[runtime|время выполнения]] различные подпрограммы будут обеспечивать удобное использование, но что более важно, синтаксис доступа к элементам массива путем помещения индексов в квадратные скобки поддерживается [[Compiler|компилятором]] (реализован как автоматическое разыменование [[Pointer/ru|указателя]]).
  
Dynamic arrays' indices are always non-negative integers starting at zero for the first element.
+
Индексы динамических массивов всегда являются неотрицательными целыми числами, начинающимися с нуля для первого элемента.
It is not possible to use an enumerative type, any other ordinal type as index, or to change the first element being specified by an index of <syntaxhighlight lang="pascal" enclose="none">1</syntaxhighlight>.
+
Невозможно использовать перечислительный тип, любой другой порядковый тип в качестве индекса или изменить первый элемент, заданный индексом <syntaxhighlight lang="pascal" inline>1</syntaxhighlight>.
  
=== definition ===
+
=== Определение ===
A one-dimensional dynamic array is defined like this:
+
Одномерный динамический массив определяется так:
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
array of char
 
array of char
 
</syntaxhighlight>
 
</syntaxhighlight>
Note, how no dimensions' size is specified.
+
Обратите внимание, что размерность [массива] не указан.
  
In order to define a multidimensional array, an array itself is specified as the base type.
+
Для определения многомерного массива в качестве базового типа указывается сам массив.
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
array of array of longInt
 
array of array of longInt
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== sizing ===
+
=== Задание размерности ===
The compiler [[Procedure|procedure]] {{Doc|package=RTL|unit=system|identifier=setlength|text=<syntaxhighlight lang="pascal" enclose="none">setLength</syntaxhighlight>}} will change a dynamic array's length, provided there is enough memory.
+
[[Procedure/ru|Процедура]] компилятора {{Doc|package=RTL|unit=system|identifier=setlength|text=<syntaxhighlight lang="pascal" inline>setLength</syntaxhighlight>}} изменит длину динамического массива при условии, что памяти достаточно.
 
<syntaxhighlight lang="pascal" line highlight="5">
 
<syntaxhighlight lang="pascal" line highlight="5">
 
program setLengthDemo(input, output, stdErr);
 
program setLengthDemo(input, output, stdErr);
Line 35: Line 35:
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
The procedure allocates memory for as many records of the base type as specified, plus some management data.
+
Процедура выделяет память для стольких записей базового типа, сколько указано, плюс некоторые данные для управления. Затем она {{Doc|package=RTL|unit=system|identifier=copyarray|text=''copies''}} (копирует) все элементы старого массива в новый. Новые поля, которых раньше не было, инициализируются по умолчанию с помощью встроенного механизма.
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" enclose="none">default</syntaxhighlight> intrinsic.
 
  
Multidimensional arrays can be resized with <syntaxhighlight lang="pascal" enclose="none">setLength</syntaxhighlight>, too.
+
Размер многомерных массивов также можно изменить с помощью <syntaxhighlight lang="pascal" inline>setLength</syntaxhighlight>.
 
<syntaxhighlight lang="pascal" line highlight="5">
 
<syntaxhighlight lang="pascal" line highlight="5">
 
program multidimensionalSetLengthDemo(input, output, stdErr);
 
program multidimensionalSetLengthDemo(input, output, stdErr);
Line 48: Line 46:
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
Valid indices for <syntaxhighlight lang="pascal" enclose="none">samples</syntaxhighlight>' first dimension are in <syntaxhighlight lang="pascal" enclose="none">0..11</syntaxhighlight>, while valid indices for its second dimension are within the range <syntaxhighlight lang="pascal" enclose="none">0..63</syntaxhighlight>.
+
Допустимые индексы для первого измерения выборки находятся в диапазоне <syntaxhighlight lang="pascal" inline>0..11</syntaxhighlight>, в то время как действительные индексы для его второго измерения находятся в диапазоне <syntaxhighlight lang="pascal" inline>0..63</syntaxhighlight>.
  
One quite useful fact is, the limitation all dimensions have to be of the same size does not apply to dynamic arrays.
+
Один весьма полезный факт заключается в том, что ограничение в неизменности всех размеров [статического массива] не распространяется на динамические массивы.
 
<syntaxhighlight lang="pascal" line highlight="7,9,12,19">
 
<syntaxhighlight lang="pascal" line highlight="7,9,12,19">
 
program binomialPotence(input, output, stdErr);
 
program binomialPotence(input, output, stdErr);
Line 67: Line 65:
 
pascalsTriangle[1][1] := 1;
 
pascalsTriangle[1][1] := 1;
 
 
// construct values by simple addition
+
// строим значения простым сложением
 
for exponent := 2 to high(pascalsTriangle) do
 
for exponent := 2 to high(pascalsTriangle) do
 
begin
 
begin
Line 84: Line 82:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== 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.
+
Начиная с FPC 3.0.0 типы динамических массивов, которые не являются анонимными, автоматически снабжаются «конструктором», как это возможно уже знакомо по объектно-ориентированному программированию.
This lets you unite <syntaxhighlight lang="pascal" enclose="none">setLength</syntaxhighlight> calls and a series of assignments in one statement:
+
Это позволяет объединить вызовы <tt>setLength</tt> и серию присвоения значений в одном операторе:
 
<syntaxhighlight lang="pascal" line highlight="7">
 
<syntaxhighlight lang="pascal" line highlight="7">
 
program dynamicArrayCreateDemo(input, output, stdErr);
 
program dynamicArrayCreateDemo(input, output, stdErr);
Line 97: Line 95:
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
Of course you can nest arrays as well:
+
Конечно, вы также можете вкладывать массивы:
 
<syntaxhighlight lang="pascal" line highlight="8-13">
 
<syntaxhighlight lang="pascal" line highlight="8-13">
 
program nestedDynamicArrayCreateDemo(input, output, stdErr);
 
program nestedDynamicArrayCreateDemo(input, output, stdErr);
Line 115: Line 113:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== 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 {{Doc|package=RTL|unit=system|identifier=copy|text=<syntaxhighlight lang="pascal" enclose="none">system.copy</syntaxhighlight>}}.
+
Если вы хотите дублировать данные, вы должны использовать {{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 dynamicArrayCopyDemo(input, output, stdErr);
Line 135: Line 133:
 
setLength(foo, 1);
 
setLength(foo, 1);
 
foo[0] := 'X';
 
foo[0] := 'X';
// copies _reference_
+
// копируем _адрес_
 
bar := foo;
 
bar := foo;
write('    initial values: ');
+
write('    начальное значение: ');
 
printArrays;
 
printArrays;
 
 
// change content _via_ _second_ reference
+
// изменяем содержимое _посредством_ _второго_ адреса
 
bar[0] := 'O';
 
bar[0] := 'O';
write('changed via 2nd ref: ');
+
write('изменено посредством 2-го адр: ');
 
printArrays;
 
printArrays;
 
 
// copy content
+
// копируем содержимое
 
bar := copy(foo, 0, length(foo));
 
bar := copy(foo, 0, length(foo));
 
bar[0] := 'X';
 
bar[0] := 'X';
write(' copied and changed: ');
+
write(' скопировано и изменено: ');
 
printArrays;
 
printArrays;
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
Only by using <syntaxhighlight lang="pascal" enclose="none">copy</syntaxhighlight> both arrays can be modified independently.
+
Только с помощью <tt>copy</tt> оба массива могут быть изменены независимо.
  
As stated above, <syntaxhighlight lang="pascal" enclose="none">setLength</syntaxhighlight> copies data.
+
Как указано выше, <tt>setLength</tt> копирует данные. Выделенная строка в примере выше (семантически) эквивалентна <syntaxhighlight lang="pascal" inline>setLength(bar, length(bar))</syntaxhighlight>.
The highlighted line in the example above is (semantically) equivalent to <syntaxhighlight lang="pascal" enclose="none">setLength(bar, length(bar))</syntaxhighlight>.
 
  
Dynamic arrays are reference counted.
+
Динамические массивы считаются ссылками. Вызов <syntaxhighlight lang="pascal" inline>setLength(myDynamicArrayVariable, 0)</syntaxhighlight> фактически делает <tt>myDynamicArrayVariable:=</tt> [[Nil|nil]] и уменьшает количество ссылок. Только когда счетчик ссылок достигает нуля, блок памяти освобождается.
Calling <syntaxhighlight lang="pascal" enclose="none">setLength(myDynamicArrayVariable, 0)</syntaxhighlight> virtually does [[Nil|<syntaxhighlight lang="pascal" enclose="none">myDynamicArrayVariable := nil</syntaxhighlight>]] and decreases the reference count.
 
Only when the reference count hits zero, the memory block is released.
 
 
<syntaxhighlight lang="pascal" line highlight="9,10,15">
 
<syntaxhighlight lang="pascal" line highlight="9,10,15">
 
program dynamicArrayNilDemo(input, output, stdErr);
 
program dynamicArrayNilDemo(input, output, stdErr);
Line 167: Line 162:
 
setLength(foo, 1);
 
setLength(foo, 1);
 
foo[0] := 'X';
 
foo[0] := 'X';
// copy _reference_, increase reference count
+
// копируем ссылку, увеличиваем счетчик ссылок
 
bar := foo;
 
bar := foo;
// foo becomes nil, reference count is decreased
+
// foo становится nil, счетчик ссылок уменьшается
 
setLength(foo, 0);
 
setLength(foo, 0);
 
writeLn('length(foo) = ', length(foo),
 
writeLn('length(foo) = ', length(foo),
 
'; length(bar) = ', length(bar));
 
'; length(bar) = ', length(bar));
 
 
// decrease reference count another time
+
// уменьшаем количество ссылок в очередной раз
 
bar := nil;
 
bar := nil;
 
writeLn('length(foo) = ', length(foo),
 
writeLn('length(foo) = ', length(foo),
Line 180: Line 175:
 
end.
 
end.
 
</syntaxhighlight>
 
</syntaxhighlight>
Nonetheless, dynamic arrays are finalized automatically.
+
Тем не менее, динамические массивы финализируются автоматически. Нет необходимости вручную устанавливать <syntaxhighlight lang="pascal" inline>setLength(…, 0)</syntaxhighlight> для всех ваших ссылок, когда программа заканчивается или когда выходит из области видимости в целом.
It is not necessary to manually <syntaxhighlight lang="pascal" enclose="none">setLength(…, 0)</syntaxhighlight> on all your references when the program comes to end, or when leaving a scope in general.
 
  
Without <syntaxhighlight lang="pascal" enclose="none">{$rangeChecks on}</syntaxhighlight> it is possible to reach beyond an array's limits.
+
Без  <syntaxhighlight lang="pascal" inline>{$rangeChecks on}</syntaxhighlight> возможен выход за пределы массива. Это означает, что при итерации по динамическим массивам невозможно работать без {{Doc|package=RTL|unit=system|identifier=low|text=<syntaxhighlight lang="pascal" inline>low</syntaxhighlight>}} и {{Doc|package=RTL|unit=system|identifier=high|text=<syntaxhighlight lang="pascal" inline>high</syntaxhighlight>}} значений, чтобы определить допустимые индексы (первый является необязательным, поскольку динамические массивы всегда начинаются с нуля). В качестве альтернативы можно использовать [[for-in_loop/ru|циклы]] <tt>for… in</tt>, если индекс не требуется.
That means when iterating over dynamic arrays, it is impossible to work without {{Doc|package=RTL|unit=system|identifier=low|text=<syntaxhighlight lang="pascal" enclose="none">low</syntaxhighlight>}} and {{Doc|package=RTL|unit=system|identifier=high|text=<syntaxhighlight lang="pascal" enclose="none">high</syntaxhighlight>}} to determine valid indices (the former being optional, since dynamic arrays always start at zero).
 
Alternatively, [[for-in loop|<syntaxhighlight lang="pascal" enclose="none">for … in</syntaxhighlight> loops]] can be used, if no index is required.
 
  
Remember, [[SizeOf#dynamic arrays and alike|<syntaxhighlight lang="pascal" enclose="none">sizeOf</syntaxhighlight>]] of a dynamic array evaluates to the size of a pointer.
+
Помните, что [[SizeOf/ru#.D0.94.D0.B8.D0.BD.D0.B0.D0.BC.D0.B8.D1.87.D0.B5.D1.81.D0.BA.D0.B8.D0.B5_.D0.BC.D0.B0.D1.81.D1.81.D0.B8.D0.B2.D1.8B_.D0.B8_.D1.82.D0.BE.D0.BC.D1.83_.D0.BF.D0.BE.D0.B4.D0.BE.D0.B1.D0.BD.D0.BE.D0.B5|<syntaxhighlight lang="pascal" inline>sizeOf</syntaxhighlight>]] динамического массива соответствует размеру указателя.
  
== application ==
+
== Приложение ==
* there is {{Doc|package=RTL|unit=system|identifier=tboundarray|text=<syntaxhighlight lang="pascal" enclose="none">system.tBoundArray</syntaxhighlight>}} and {{Doc|package=RTL|unit=objpas|identifier=tboundarray|text=<syntaxhighlight lang="pascal" enclose="none">objPas.tBoundArray</syntaxhighlight>}}
+
* есть {{Doc|package=RTL|unit=system|identifier=tboundarray|text=<syntaxhighlight lang="pascal" inline>system.tBoundArray</syntaxhighlight>}} и {{Doc|package=RTL|unit=objpas|identifier=tboundarray|text=<syntaxhighlight lang="pascal" inline>objPas.tBoundArray</syntaxhighlight>}}
  
== see also ==
+
== См. также ==
* [[String|<syntaxhighlight lang="pascal" enclose="none">string</syntaxhighlight>]]
+
* [[String/ru|<tt>string</tt>]]
* example: [[Example: Multidimensional dynamic array|multidimensional dynamic array]]
+
* пример: [[Example: Multidimensional dynamic array|multidimensional dynamic array]]
 
* [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 Free Pascal Reference guide: “Dynamic arrays”]

Latest revision as of 17:11, 6 August 2022

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

Динамический массив - это массив, размеры которого неизвестны во время компиляции. Динамический массив не является единственным типом, предоставляющим массивы переменной длины, но с 2018 года он является единственным, который поддерживает FPC.

Использование

Концепция

Определение динамического массива будет выделять пространство только для указателя. Во время выполнения различные подпрограммы будут обеспечивать удобное использование, но что более важно, синтаксис доступа к элементам массива путем помещения индексов в квадратные скобки поддерживается компилятором (реализован как автоматическое разыменование указателя).

Индексы динамических массивов всегда являются неотрицательными целыми числами, начинающимися с нуля для первого элемента. Невозможно использовать перечислительный тип, любой другой порядковый тип в качестве индекса или изменить первый элемент, заданный индексом 1.

Определение

Одномерный динамический массив определяется так:

array of char

Обратите внимание, что размерность [массива] не указан.

Для определения многомерного массива в качестве базового типа указывается сам массив.

array of array of longInt

Задание размерности

Процедура компилятора setLength изменит длину динамического массива при условии, что памяти достаточно.

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

Процедура выделяет память для стольких записей базового типа, сколько указано, плюс некоторые данные для управления. Затем она copies (копирует) все элементы старого массива в новый. Новые поля, которых раньше не было, инициализируются по умолчанию с помощью встроенного механизма.

Размер многомерных массивов также можно изменить с помощью setLength.

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

Допустимые индексы для первого измерения выборки находятся в диапазоне 0..11, в то время как действительные индексы для его второго измерения находятся в диапазоне 0..63.

Один весьма полезный факт заключается в том, что ограничение в неизменности всех размеров [статического массива] не распространяется на динамические массивы.

 1program binomialPotence(input, output, stdErr);
 2var
 3	pascalsTriangle: array of array of longWord;
 4	exponent: longInt;
 5	factor: longInt;
 6begin
 7	setLength(pascalsTriangle, 20);
 8	
 9	setLength(pascalsTriangle[0], 1);
10	pascalsTriangle[0][0] := 1;
11	
12	setLength(pascalsTriangle[1], 2);
13	pascalsTriangle[1][0] := 1;
14	pascalsTriangle[1][1] := 1;
15	
16	// строим значения простым сложением
17	for exponent := 2 to high(pascalsTriangle) do
18	begin
19		setLength(pascalsTriangle[exponent], exponent + 1);
20		pascalsTriangle[exponent][0] := 1;
21		pascalsTriangle[exponent][exponent] := 1;
22		for factor := 1 to exponent - 1 do
23		begin
24			pascalsTriangle[exponent][factor] :=
25				pascalsTriangle[exponent - 1][factor - 1] +
26				pascalsTriangle[exponent - 1][factor];
27		end;
28	end;
29	
30	// ...

Инициализация

Начиная с FPC 3.0.0 типы динамических массивов, которые не являются анонимными, автоматически снабжаются «конструктором», как это возможно уже знакомо по объектно-ориентированному программированию. Это позволяет объединить вызовы setLength и серию присвоения значений в одном операторе:

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.

Конечно, вы также можете вкладывать массивы:

 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.

Обращение

Имейте в виду, что динамические массивы являются указателями. Присвоение переменных динамического массива друг другу копирует не какую-либо полезную нагрузку, а только адрес. Это отличается от поведения статических массивов.

Если вы хотите дублировать данные, вы должны использовать 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	// копируем _адрес_
15	bar := foo;
16	write('     начальное значение: ');
17	printArrays;
18	
19	// изменяем содержимое _посредством_ _второго_ адреса 
20	bar[0] := 'O';
21	write('изменено посредством 2-го адр: ');
22	printArrays;
23	
24	// копируем содержимое
25	bar := copy(foo, 0, length(foo));
26	bar[0] := 'X';
27	write(' скопировано и изменено: ');
28	printArrays;
29end.

Только с помощью copy оба массива могут быть изменены независимо.

Как указано выше, setLength копирует данные. Выделенная строка в примере выше (семантически) эквивалентна setLength(bar, length(bar)).

Динамические массивы считаются ссылками. Вызов setLength(myDynamicArrayVariable, 0) фактически делает myDynamicArrayVariable:= nil и уменьшает количество ссылок. Только когда счетчик ссылок достигает нуля, блок памяти освобождается.

 1program dynamicArrayNilDemo(input, output, stdErr);
 2var
 3	foo, bar: array of char;
 4begin
 5	setLength(foo, 1);
 6	foo[0] := 'X';
 7	// копируем ссылку, увеличиваем счетчик ссылок 
 8	bar := foo;
 9	// foo становится nil, счетчик ссылок уменьшается 
10	setLength(foo, 0);
11	writeLn('length(foo) = ', length(foo),
12		'; length(bar) = ', length(bar));
13	
14	// уменьшаем количество ссылок в очередной раз
15	bar := nil;
16	writeLn('length(foo) = ', length(foo),
17		'; length(bar) = ', length(bar));
18end.

Тем не менее, динамические массивы финализируются автоматически. Нет необходимости вручную устанавливать setLength(, 0) для всех ваших ссылок, когда программа заканчивается или когда выходит из области видимости в целом.

Без {$rangeChecks on} возможен выход за пределы массива. Это означает, что при итерации по динамическим массивам невозможно работать без low и high значений, чтобы определить допустимые индексы (первый является необязательным, поскольку динамические массивы всегда начинаются с нуля). В качестве альтернативы можно использовать циклы for… in, если индекс не требуется.

Помните, что sizeOf динамического массива соответствует размеру указателя.

Приложение

См. также