Jump to content

Массив переменной длины

В компьютерном программировании массив переменной длины ( VLA ), также называемый переменным размером или размером во время выполнения , представляет собой структуру данных массива , длина которой определяется во время выполнения , а не во время компиляции . [1] В языке C говорят, что VLA имеет изменяемый тип данных , который зависит от значения (см. Зависимый тип ).

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

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

Расширяемые массивы (также называемые динамическими массивами ), как правило, более полезны, чем VLA, поскольку динамические массивы могут делать все, что могут делать VLA, а также поддерживают рост массива во время выполнения. По этой причине многие языки программирования ( JavaScript , Java , Python , R и т. д.) поддерживают только растущие массивы. Даже в языках, поддерживающих массивы переменной длины, часто рекомендуется избегать использования массивов переменной длины (на основе стека) и вместо этого использовать ( на основе кучи ). динамические массивы [4]

Распределение

[ редактировать ]

Выполнение

[ редактировать ]

Следующая функция 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] В С11 __STDC_NO_VLA__ макрос определяется, если VLA не поддерживается. [6] Стандарт C23 снова делает типы VLA обязательными. Необязательно создавать только объекты VLA с автоматическим сроком хранения. [7] GCC имел VLA в качестве расширения до C99, которое также распространяется на его диалект C++.

Линус Торвальдс в прошлом выражал свое недовольство использованием VLA для массивов с заранее определенными маленькими размерами, поскольку он генерирует ассемблерный код более низкого качества. [8] Ядро Linux 4.20 фактически не содержит VLA. [9]

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

Объект VLA можно использовать с динамическим хранилищем, используя указатель на массив.

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;

Фортран 90

[ редактировать ]

Эквивалентная Фортрана 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 объявляет массив записей переменной длины. 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 . VLA, в отличие от других упомянутых здесь языков, безопасен, поскольку COBOL требует указания максимального размера массива В этом примере DEPT-PERSON не может иметь более 20 предметов, независимо от значения PEOPLE-CNT.

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

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

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

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

Объектный Паскаль

[ редактировать ]

Динамические массивы Object Pascal размещаются в куче. [12]

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

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

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

...
SetLength(NumberArray, 0);
...
  1. ^ Перейти обратно: а б «Массивы переменной длины» . Архивировано из оригинала 26 января 2018 г.
  2. ^ «Переменная длина – использование коллекции компиляторов GNU (GCC)» .
  3. ^ ISO 9899:2011 Языки программирования – C 6.7.6.2 4.
  4. ^ Раймонд, Эрик С. (2000). «Практика выпуска программного обеспечения Raymond: 6. Хорошая практика разработки» . Проект документации Linux .
  5. ^ «Параметры генерации кода — компилятор GNU Fortran» .
  6. ^ § 6.10.8.3 стандарта C11 (n1570.pdf)
  7. ^ § 6.10.9.3 стандарта C23 (n3054.pdf)
  8. ^ Торвальдс, Линус (7 марта 2018 г.). «LKML: Линус Торвальдс: Re: удаление VLA (было Re: [RFC 2/2] блеск: используйте VLA_SAFE)» . Ядро Linux (список рассылки).
  9. ^ «Ядро Linux теперь не содержит VLA: победа в плане безопасности, меньше накладных расходов и лучшее для Clang — Phoronix» . www.phoronix.com .
  10. ^ §6.5.3.4 и §7.20.3 стандарта C11 (n1570.pdf)
  11. ^ «Оператор stackalloc (ссылка на C#)» . Майкрософт.
  12. ^ Майкл Ван Каннейт. «Справочное руководство по Free Pascal: Динамические массивы» .
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: d082379ac8056de5d050ab49e54aef75__1721232600
URL1:https://arc.ask3.ru/arc/aa/d0/75/d082379ac8056de5d050ab49e54aef75.html
Заголовок, (Title) документа по адресу, URL1:
Variable-length array - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)