Sign in Join
Wiki copytemporary

Dynamic array/ru

English · Español · Français · Suomi · Русский · 日本語

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

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

Концепция

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

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

Определение

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

pascal
array of char

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

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

pascal
array of array of longInt

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

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

pascal
program setLengthDemo(input, output, stdErr);
var
    sieve: array of longWord;
begin
    setLength(sieve, 1337);
end.

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

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

pascal
program multidimensionalSetLengthDemo(input, output, stdErr);
var
    samples: array of array of smallInt;
begin
    setLength(samples, 12, 64);
end.

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

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

pascal
program binomialPotence(input, output, stdErr);
var
    pascalsTriangle: array of array of longWord;
    exponent: longInt;
    factor: longInt;
begin
    setLength(pascalsTriangle, 20);
    
    setLength(pascalsTriangle[0], 1);
    pascalsTriangle[0][0] := 1;
    
    setLength(pascalsTriangle[1], 2);
    pascalsTriangle[1][0] := 1;
    pascalsTriangle[1][1] := 1;
    
    // строим значения простым сложением
    for exponent := 2 to high(pascalsTriangle) do
    begin
        setLength(pascalsTriangle[exponent], exponent + 1);
        pascalsTriangle[exponent][0] := 1;
        pascalsTriangle[exponent][exponent] := 1;
        for factor := 1 to exponent - 1 do
        begin
            pascalsTriangle[exponent][factor] :=
                pascalsTriangle[exponent - 1][factor - 1] +
                pascalsTriangle[exponent - 1][factor];
        end;
    end;
    
    // ...

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

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

pascal
program dynamicArrayCreateDemo(input, output, stdErr);
type
    truths = array of boolean;
var
    l: truths;
begin
    l := truths.create(false, true, true, false, true, false, false);
end.

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

pascal
program nestedDynamicArrayCreateDemo(input, output, stdErr);
type
    truths = array of boolean;
    pattern = array of truths;
var
    p: pattern;
begin
    p := pattern.create(
            truths.create(false, false),
            truths.create(true, false),
            truths.create(true, false, false),
            truths.create(true, true, false)
        );
end.

Обращение

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

Если вы хотите дублировать данные, вы должны использовать system.copy.

pascal
program dynamicArrayCopyDemo(input, output, stdErr);

var
    foo, bar: array of char;

procedure printArrays;
begin
    writeLn('foo[0] = ', foo[0], '; bar[0] = ', bar[0]);
end;

begin
    setLength(foo, 1);
    foo[0] := 'X';
    // копируем _адрес_
    bar := foo;
    write('     начальное значение: ');
    printArrays;
    
    // изменяем содержимое _посредством_ _второго_ адреса 
    bar[0] := 'O';
    write('изменено посредством 2-го адр: ');
    printArrays;
    
    // копируем содержимое
    bar := copy(foo, 0, length(foo));
    bar[0] := 'X';
    write(' скопировано и изменено: ');
    printArrays;
end.

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

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

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

pascal
program dynamicArrayNilDemo(input, output, stdErr);
var
    foo, bar: array of char;
begin
    setLength(foo, 1);
    foo[0] := 'X';
    // копируем ссылку, увеличиваем счетчик ссылок 
    bar := foo;
    // foo становится nil, счетчик ссылок уменьшается 
    setLength(foo, 0);
    writeLn('length(foo) = ', length(foo),
        '; length(bar) = ', length(bar));
    
    // уменьшаем количество ссылок в очередной раз
    bar := nil;
    writeLn('length(foo) = ', length(foo),
        '; length(bar) = ', length(bar));
end.

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

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

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

Приложение

См. также


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.

Revision 1, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.