В программировании массив переменной длины (англ. variable-length array, VLA, variable-sized array, runtime-sized array) представляет собой массив, длина которого определяется во время выполнения (а не во время компиляции)[1]. В C массив переменной длины имеет управляемый переменной тип (англ. variably modified type), который зависит от какого-либо значения (см. Зависимый тип).

Основная цель массивов переменной длины — это упростить программирование численных алгоритмов.

Языки программирования, поддерживающие массивы переменной длины: Ada, Algol 68 (без возможности менять длину строк в двумерных массивах и т. д.), APL, C99 (хотя впоследствии массив переменной длины стал в C11 необязательной возможностью, поддержка которой не требуется[2][3]; на некоторых платформах это могло быть реализовано ранее с помощью функции alloca() или аналогичных ей) и C# (массивы, выделенные на стеке — эта возможность доступна только в небезопасном режиме), COBOL, Fortran 90, J и Object Pascal (язык, используемый в средах Borland Delphi и Lazarus, компилирующийся с помощью Free Pascal Compiler).

Память

править

Выделение памяти

править
  • GNU C Compiler выделяет память для массива переменной длины с автоматическим сроком хранения (англ. automatic storage duration) на стеке[англ.][4]. Это более быстрый и простой вариант по сравнению с выделением в куче, и он используется большинством компиляторов.
  • Массивы переменной длины также могут быть выделены в куче, внутри реализации используется указатель на этот блок.

Реализация

править

C99

править

Следующая функция на C99 выделяет массив переменной длины заданного размера, заполняет его значениями с плавающей запятой, а затем передаёт его другой функции для обработки. Поскольку массив объявлен как автоматическая переменная, его время жизни заканчивается, когда возвращается read_and_process().

float read_and_process(int n)
{
    float vals[n];

    for (int i = 0; i < n; ++i)
        vals[i] = read_val();

    return process(n, vals);
}

В C99 параметр длины должен предшествовать параметру массива переменной длины при вызовах функций[1]. В C11 определяется макрос __STDC_NO_VLA__, если массивы переменной длины не поддерживаются[5]. GCC имел массивы переменной длины в качестве расширения до C99, которое также распространяется на его диалект C++.

Линус Торвальдс в прошлом выражал своё недовольство использованием массивов переменной длины малых размеров, поскольку это порождает ассемблерный код более низкого качества[6]. Ядро Linux 4.20 фактически не содержит массивов переменной длины[7].

Хотя C11 явно не указывает ограничение по размеру для массивов переменной длины, некоторые интерпретации полагают, что они должны иметь тот же максимальный размер, что и все другие объекты, т.е. SIZE_MAX байт[8]. Однако такую интерпретацию следует понимать в более широком контексте ограничений среды и платформы, таких как типичный размер страницы с защитой стека 4 КиБ, что на много порядков меньше, чем SIZE_MAX.

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

float read_and_process(int n)
{
    float (*vals)[n] = malloc(sizeof(float[n]));

    for (int i = 0; i < n; ++i)
        (*vals)[i] = read_val();

    float ret = process(n, *vals);

    free(vals);

    return ret;
}

Ada

править

Ниже приведён тот же пример на языке Ada. Массивы содержат свою длину вместе с данными, поэтому нет необходимости передавать их длину функции Process.

type Vals_Type is array (Positive range <>) of Float;

function Read_And_Process (N : Integer) return Float is
   Vals : Vals_Type (1 .. N);
begin
   for I in 1 .. N loop
      Vals (I) := Read_Val;
   end loop;
   return Process (Vals);
end Read_And_Process;

Fortran 90

править

Эквивалентная функция на языке Fortran 90.

function read_and_process(n) result(o)
    integer,intent(in)::n
    real::o

    real,dimension(n)::vals
    integer::i

    do i = 1,n
       vals(i) = read_val()
    end do
    o = process(vals)
end function read_and_process

Используется возможность Fortran 90 для проверки интерфейсов процедур во время компиляции; с другой стороны, если функции используют интерфейс вызова, который был до Fortran 90, сначала должны быть объявлены (внешние) функции, а длина массива должна быть явно передана в качестве аргумента (как в C):

function read_and_process(n) result(o)
    integer,intent(in)::n
    real::o

    real,dimension(n)::vals
    real::read_val, process
    integer::i

    do i = 1,n
       vals(i) = read_val()
    end do
    o = process(vals,n)
end function read_and_process

Cobol

править

Следующий фрагмент на языке COBOL объявляет массив записей переменной длины DEPT-PERSON, имеющий длину (количество элементов), заданную значением PEOPLE-CNT:

DATA DIVISION.
WORKING-STORAGE SECTION.
01  DEPT-PEOPLE.
    05  PEOPLE-CNT          PIC S9(4) BINARY.
    05  DEPT-PERSON         OCCURS 0 TO 20 TIMES DEPENDING ON PEOPLE-CNT.
        10  PERSON-NAME     PIC X(20).
        10  PERSON-WAGE     PIC S9(7)V99 PACKED-DECIMAL.

Массивы переменной длины в языке COBOL, в отличие от других языков, упомянутых здесь, безопасен, потому что COBOL требует указания максимального размера массива — в этом примере DEPT-PERSON не может содержать более 20 элементов, независимо от значения PEOPLE-CNT.

C#

править

Следующий фрагмент на языке C# объявляет массив целых чисел переменной длины. До версии C# 7.2 требовался указатель на массив в «небезопасном» контексте. Ключевое слово unsafe требует, чтобы сборка, содержащая этот код, была помечена как небезопасная.

unsafe void DeclareStackBasedArrayUnsafe(int size)
{
    int *pArray = stackalloc int[size];
    pArray[0] = 123;
}

C# версии 7.2 и более поздних версий позволяет выделять массив без ключевого слова unsafe с помощью функции Span[9].

void DeclareStackBasedArraySafe(int size)
{
    Span<int> stackArray = stackalloc int[size];
    stackArray[0] = 123;
}

Object Pascal

править

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

program CreateDynamicArrayOfNumbers(Size: Integer);
var
  NumberArray: array of LongWord;
begin
  SetLength(NumberArray, Size);
  NumberArray[0] := 2020;
end.

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

...
SetLength(NumberArray, 0);
...

Ссылки

править
  1. 1 2 Variable Length Arrays. Архивировано из оригинала 26 января 2018 года.
  2. Variable Length – Using the GNU Compiler Collection (GCC). Дата обращения: 16 августа 2022. Архивировано 27 августа 2022 года.
  3. ISO 9899:2011 Programming Languages – C 6.7.6.2 4.
  4. Code Gen Options - The GNU Fortran Compiler. Дата обращения: 16 августа 2022. Архивировано 28 мая 2022 года.
  5. § 6.10.8.3 of the C11 standard (n1570.pdf)
  6. LKML: Linus Torvalds: Re: VLA removal (was Re: [RFC 2/2] lustre: use VLA_SAFE). lkml.org. Дата обращения: 16 августа 2022. Архивировано 17 августа 2022 года.
  7. The Linux Kernel Is Now VLA-Free: A Win For Security, Less Overhead & Better For Clang - Phoronix (англ.). www.phoronix.com. Дата обращения: 16 августа 2022. Архивировано 23 июня 2022 года.
  8. §6.5.3.4 and §7.20.3 of the C11 standard (n1570.pdf)
  9. stackalloc operator (C# reference). Microsoft. Дата обращения: 16 августа 2022. Архивировано 26 августа 2022 года.

📚 Artikel Terkait di Wikipedia

BPEL

BPEL (англ. Business Process Execution Language) — язык на основе XML для формального описания бизнес-процессов и протоколов их взаимодействия между собой

ProcessWire

) (3 декабря 2012). The $page API variable (англ.). What's unique about ProcessWire (англ.). How to install ProcessWire CMS (англ.). processwire.com.

Микроволновая печь

промышленных печах частота излучения может изменяться (так называемые англ. variable frequency microwave, VFM). В отличие от классических печей (например, духовки

Annapurna Interactive

developer's next game is a cozy tea shop sim where you have some trauma to process, actually (англ.). PC Gamer (7 июня 2024). Дата обращения: 7 июня 2024

Си (язык программирования)

Дата обращения: 25 мая 2019. Архивировано 25 мая 2019 года. Traditional Process Address Space — Static Program (англ.). www.openbsd.org. Дата обращения:

Координатный спуск

1007/s10107-015-0892-3. — arXiv:1502.04759. Spall J. C. Cyclic Seesaw Process for Optimization and Identification // Journal of Optimization Theory and

PHP

контекста для их захвата: $variable = 'Hello World!'; // Использование оператора use function() use ($variable): string { return $variable; }; // Альтернативный

Secure Boot

отличных от Microsoft Windows. Аутентифицированные переменные (Authenticated Variable) — переменные, для изменения которых требуется аутентификация. Secure Boot