Sign in Join
Wiki copytemporary

Dynamic array/ru: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Dynamic array/ru

OldNewLine
1+Динамический массив - это [[Array/ru|массив]], размеры которого неизвестны во [[Compile time|время компиляции]]. Динамический массив не является единственным типом, предоставляющим массивы переменной длины, но с 2018 года он является единственным, который поддерживает [[FPC/ru|FPC]].
2+
3+## Использование
4+
5+### Концепция
6+
7+Определение динамического массива будет выделять пространство только для [[Pointer/ru|указателя]]. Во [[runtime|время выполнения]] различные подпрограммы будут обеспечивать удобное использование, но что более важно, синтаксис доступа к элементам массива путем помещения индексов в квадратные скобки поддерживается [[Compiler|компилятором]] (реализован как автоматическое разыменование [[Pointer/ru|указателя]]).
8+
9+Индексы динамических массивов всегда являются неотрицательными целыми числами, начинающимися с нуля для первого элемента. Невозможно использовать перечислительный тип, любой другой порядковый тип в качестве индекса или изменить первый элемент, заданный индексом `1`.
10+
11+### Определение
12+
13+Одномерный динамический массив определяется так:
14+
15+``` pascal
16+array of char
17+```
18+
19+Обратите внимание, что размерность \[массива\] не указан.
20+
21+Для определения многомерного массива в качестве базового типа указывается сам массив.
22+
23+``` pascal
24+array of array of longInt
25+```
26+
27+### Задание размерности
28+
29+[[Procedure/ru|Процедура]] компилятора [`setLength`](https://www.freepascal.org/docs-html/rtl/system/setlength.html) изменит длину динамического массива при условии, что памяти достаточно.
30+
31+``` pascal
32+program setLengthDemo(input, output, stdErr);
33+var
34+ sieve: array of longWord;
35+begin
36+ setLength(sieve, 1337);
37+end.
38+```
39+
40+Процедура выделяет память для стольких записей базового типа, сколько указано, плюс некоторые данные для управления. Затем она [*copies*](https://www.freepascal.org/docs-html/rtl/system/copyarray.html) (копирует) все элементы старого массива в новый. Новые поля, которых раньше не было, инициализируются по умолчанию с помощью встроенного механизма.
41+
42+Размер многомерных массивов также можно изменить с помощью `setLength`.
43+
44+``` pascal
45+program multidimensionalSetLengthDemo(input, output, stdErr);
46+var
47+ samples: array of array of smallInt;
48+begin
49+ setLength(samples, 12, 64);
50+end.
51+```
52+
53+Допустимые индексы для первого измерения выборки находятся в диапазоне `0..11`, в то время как действительные индексы для его второго измерения находятся в диапазоне `0..63`.
54+
55+Один весьма полезный факт заключается в том, что ограничение в неизменности всех размеров \[статического массива\] не распространяется на динамические массивы.
56+
57+``` pascal
58+program binomialPotence(input, output, stdErr);
59+var
60+ pascalsTriangle: array of array of longWord;
61+ exponent: longInt;
62+ factor: longInt;
63+begin
64+ setLength(pascalsTriangle, 20);
65+
66+ setLength(pascalsTriangle[0], 1);
67+ pascalsTriangle[0][0] := 1;
68+
69+ setLength(pascalsTriangle[1], 2);
70+ pascalsTriangle[1][0] := 1;
71+ pascalsTriangle[1][1] := 1;
72+
73+ // строим значения простым сложением
74+ for exponent := 2 to high(pascalsTriangle) do
75+ begin
76+ setLength(pascalsTriangle[exponent], exponent + 1);
77+ pascalsTriangle[exponent][0] := 1;
78+ pascalsTriangle[exponent][exponent] := 1;
79+ for factor := 1 to exponent - 1 do
80+ begin
81+ pascalsTriangle[exponent][factor] :=
82+ pascalsTriangle[exponent - 1][factor - 1] +
83+ pascalsTriangle[exponent - 1][factor];
84+ end;
85+ end;
86+
87+ // ...
88+```
89+
90+### Инициализация
91+
92+Начиная с FPC 3.0.0 типы динамических массивов, которые не являются анонимными, автоматически снабжаются «конструктором», как это возможно уже знакомо по объектно-ориентированному программированию. Это позволяет объединить вызовы `setLength` и серию присвоения значений в одном операторе:
93+
94+``` pascal
95+program dynamicArrayCreateDemo(input, output, stdErr);
96+type
97+ truths = array of boolean;
98+var
99+ l: truths;
100+begin
101+ l := truths.create(false, true, true, false, true, false, false);
102+end.
103+```
104+
105+Конечно, вы также можете вкладывать массивы:
106+
107+``` pascal
108+program nestedDynamicArrayCreateDemo(input, output, stdErr);
109+type
110+ truths = array of boolean;
111+ pattern = array of truths;
112+var
113+ p: pattern;
114+begin
115+ p := pattern.create(
116+ truths.create(false, false),
117+ truths.create(true, false),
118+ truths.create(true, false, false),
119+ truths.create(true, true, false)
120+ );
121+end.
122+```
123+
124+### Обращение
125+
126+Имейте в виду, что динамические массивы являются указателями. Присвоение переменных динамического массива друг другу копирует не какую-либо полезную нагрузку, а только адрес. Это отличается от поведения статических массивов.
127+
128+Если вы хотите дублировать данные, вы должны использовать [`system.copy`](https://www.freepascal.org/docs-html/rtl/system/copy.html).
129+
130+``` pascal
131+program dynamicArrayCopyDemo(input, output, stdErr);
132+
133+var
134+ foo, bar: array of char;
135+
136+procedure printArrays;
137+begin
138+ writeLn('foo[0] = ', foo[0], '; bar[0] = ', bar[0]);
139+end;
140+
141+begin
142+ setLength(foo, 1);
143+ foo[0] := 'X';
144+ // копируем _адрес_
145+ bar := foo;
146+ write(' начальное значение: ');
147+ printArrays;
148+
149+ // изменяем содержимое _посредством_ _второго_ адреса
150+ bar[0] := 'O';
151+ write('изменено посредством 2-го адр: ');
152+ printArrays;
153+
154+ // копируем содержимое
155+ bar := copy(foo, 0, length(foo));
156+ bar[0] := 'X';
157+ write(' скопировано и изменено: ');
158+ printArrays;
159+end.
160+```
161+
162+Только с помощью `copy` оба массива могут быть изменены независимо.
163+
164+Как указано выше, `setLength` копирует данные. Выделенная строка в примере выше (семантически) эквивалентна `setLength(bar, length(bar))`.
165+
166+Динамические массивы считаются ссылками. Вызов `setLength(myDynamicArrayVariable, 0)` фактически делает `myDynamicArrayVariable:=` [[Nil|nil]] и уменьшает количество ссылок. Только когда счетчик ссылок достигает нуля, блок памяти освобождается.
167+
168+``` pascal
169+program dynamicArrayNilDemo(input, output, stdErr);
170+var
171+ foo, bar: array of char;
172+begin
173+ setLength(foo, 1);
174+ foo[0] := 'X';
175+ // копируем ссылку, увеличиваем счетчик ссылок
176+ bar := foo;
177+ // foo становится nil, счетчик ссылок уменьшается
178+ setLength(foo, 0);
179+ writeLn('length(foo) = ', length(foo),
180+ '; length(bar) = ', length(bar));
181+
182+ // уменьшаем количество ссылок в очередной раз
183+ bar := nil;
184+ writeLn('length(foo) = ', length(foo),
185+ '; length(bar) = ', length(bar));
186+end.
187+```
188+
189+Тем не менее, динамические массивы финализируются автоматически. Нет необходимости вручную устанавливать `setLength(…, 0)` для всех ваших ссылок, когда программа заканчивается или когда выходит из области видимости в целом.
190+
191+Без `{$rangeChecks on}` возможен выход за пределы массива. Это означает, что при итерации по динамическим массивам невозможно работать без [`low`](https://www.freepascal.org/docs-html/rtl/system/low.html) и [`high`](https://www.freepascal.org/docs-html/rtl/system/high.html) значений, чтобы определить допустимые индексы (первый является необязательным, поскольку динамические массивы всегда начинаются с нуля). В качестве альтернативы можно использовать [[for-in loop/ru|циклы]] `for… in`, если индекс не требуется.
192+
193+Помните, что [[SizeOf/ru|sizeOf]] динамического массива соответствует размеру указателя.
194+
195+## Приложение
196+
197+- есть [`system.tBoundArray`](https://www.freepascal.org/docs-html/rtl/system/tboundarray.html) и [`objPas.tBoundArray`](https://www.freepascal.org/docs-html/rtl/objpas/tboundarray.html)
198+
199+## См. также
200+
201+- [[String/ru|string]]
202+- пример: [[Example: Multidimensional dynamic array|multidimensional dynamic array]]
203+- [Free Pascal Reference guide: “Dynamic arrays”](https://www.freepascal.org/docs-html/ref/refsu14.html#x38-510003.3.1)
204+
205+---
206+*From the Free Pascal wiki, page "Dynamic array/ru", as it stood on 2022-08-06 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history