Открытые массивы в Pascal

Обновлено: 26.04.2026

От обычных массивов объявление переменных открытых массивов отличается тем, что не указываются границы индексов. Остается только тип элементов. Например:

var
    a: array of real;
    b: array of integer;

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

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

Посмотрим, что будет возвращать функция sizeof, если ей передавать обычные и открытые массивы:

var
    A: array[1..10] of integer;
    B: array[1..5] of real;
    P: array of integer;
    Q: array of real;
begin
    writeln('Под A выделено ', sizeof(a),' байт');
    writeln('Под B выделено ', sizeof(b),' байт');
    writeln('Под P выделено ', sizeof(p),' байт');
    writeln('Под Q выделено ', sizeof(q),' байт');
end.
Под A выделено 20 байт
Под B выделено 40 байт
Под P выделено 8 байт
Под Q выделено 8 байт

Массив A занимает 20 байтов, потому что состоит из 10-ти целых чисел, под каждое из которых отводится 2 байта. Массив B занимает 40 байтов, так как состоит из 5-ти элементов, и каждый занимает 8 байт. Переменные P и Q являются указателями, они хранят адрес первого элемента массива. Поскольку адрес не зависит от типа массива, под обе переменные выделяется одинаковое количество памяти.

Зачем же тогда указывать тип открытых массивов, если под любой указатель все-равно выделяется 8 байтов? Дело в том, что когда память будет захватываться в процессе работы программы, то есть динамически, надо знать, сколько ее нужно взять под каждый элемент массива. Так если это массив целых и нужно место под 10 элементов, то будет выделено 20 байтов. Если же массив вещественный, то под 10 элементов понадобится 80 байтов.

Чтобы в процессе выполнения программы (когда начинает исполняться раздел действий) выделить память под открытый массив, в Pascal используется процедура setLength. Она принимает два параметра — имя открытого массива и устанавливаемое количество элементов в нем. В результате работы setLength в памяти выделяется столько байт, сколько необходимо для хранения n-го количества элементов определенного типа.

var
    int: array of integer;
    n, i: byte;
    sum: integer;
begin
    write('Введите длину массива: ');
    readln(n);

    setLength(int, n);

    write('Введите ', n, ' целых: ');
    for i:=0 to n-1 do
        read(int[i]);

    write('Сумма: ');
    sum := 0;
    for i:=0 to n-1 do
        sum := sum + int[i];
    writeln(sum);
end.
Введите длину массива: 4
Введите 4 целых: 12 -5 3 8
Сумма: 18

Особенностью открытых массивов является то, что их индексы всегда начинаются с нуля (а не с единицы, которая чаще всего используется для обычных массивов). Поэтому в примере выше первым значением переменой i был 0, а последним — на 1 меньше, чем количество элементов. Ведь если элементов n, и индексация начинается с нуля, то индекс последнего будет n-1.

Функция high принимает в качестве параметра имя массива и возвращает индексный номер последнего элемента. Так если выделяется память под десять элементов открытого массива, то индекс последнего будет 9 (т.к. индексация начинается с 0), что и вернет функция high.

setLength(int, 100);
i := high(int);
writeln(i);  // 99

Чтобы узнать длину массива, используется уже знакомая нам функция length. Для примера выше она вернет значение 100.

Напишите код, который вычисляет объем памяти, которая была динамически выделена под данные открытого массива.

Для изменения размера открытого массива используют ту же процедуру setLength, передавая в нее новое значение для количества элементов. Если оно будет равно 0, то ранее выделенная под массив память будет помечена как свободная. Также можно присвоить переменной открытого массива ключевое слово nil (встроенная константа), которое обозначает пустой указатель и указывает на "нулевой" адрес в памяти.

setLength(int, 10);
writeln(high(int));  // 9
setLength(int, 0);
writeln(high(int), ' ', length(int));  // -1 0
setLength(int, 5);
writeln(high(int));  // 4
int := nil;
writeln(high(int), ' ', length(int));  // -1 0

В Паскале открытые массивы часто используются в контексте передачи в подпрограмму массивов переменных размеров. Это позволяет с помощью одной и той же подпрограммы обрабатывать массивы произвольной длины. Без использования открытых массивов пришлось бы для каждого массива иной длины писать собственную подпрограмму.

В примере ниже показано, что хотя формальным параметром процедур является открытый массив, в Pascal реализована возможность передавать туда в том числе обычные массивы. При этом в теле таких подпрограмм не должно быть вызовов setLength. Также следует иметь в виду, что в теле подпрограммы обычный массив становится открытым и его индексация начинается с нуля.

var
    a: array of integer;
    b: array[1..15] of integer;
    i: byte;

procedure fillA(var arr: array of integer; m1, m2: integer);
begin
    for i:=0 to high(arr) do
        arr[i] := random(m2-m1) + m1;
end;
procedure writeA(var arr: array of integer);
begin
    for i:=0 to high(arr) do
        write(arr[i], ' ');
    writeln;
end;

begin
    randomize;

    setLength(a, 10);
    fillA(a, 0, 20);
    writeA(a);

    fillA(b, -5, 6);
    writeA(b);
end.

Пример выполнения программы:

12 8 10 5 5 0 10 7 10 6 
4 4 3 -3 1 -4 0 2 -5 2 -4 2 2 1 3 

Задания для дополнительной или самостоятельной работы:

Напишите функцию, которая возвращает открытый массив.