Массив переменной длины - Variable-length array
В компьютерном программировании , A переменной длины массива ( VLA ), называемый также переменного размера или выполнения размера , является массив , длина которого определяется во время выполнения (а не во время компиляции). В C говорят, что VLA имеет изменяемый тип, который зависит от значения (см. Зависимый тип ).
Основная цель VLA - упростить программирование численных алгоритмов.
Языки программирования, поддерживающие VLA, включают Ada , Algol 68 (для негибких строк), APL , C99 (хотя впоследствии они были переведены в C11 в условную функцию, реализация которой не требуется для поддержки; на некоторых платформах она могла быть реализована ранее с помощью alloca()
или аналогичные функции) и C # (как массивы с выделением стека в небезопасном режиме), COBOL , Fortran 90 , J и Object Pascal (язык, используемый в Borland Delphi и Lazarus , использующий FPC).
объем памяти
Распределение
- В GNU C Compiler выделяет память для Власа с автоматической продолжительностью хранения на стеке . Это более быстрый и простой вариант по сравнению с распределением в куче, и он используется большинством компиляторов.
- VLA также могут быть выделены в куче и доступны изнутри с помощью указателя на этот блок.
Реализация
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 параметр длины должен стоять перед параметром массива переменной длины в вызовах функций. В C11 __STDC_NO_VLA__
макрос определяется, если VLA не поддерживается. GCC имел VLA в качестве расширения до C99, которое также распространяется на его диалект C ++.
Линус Торвальдс в прошлом выражал свое недовольство использованием VLA для массивов с заранее определенными небольшими размерами, поскольку он генерирует код сборки более низкого качества. С ядром Linux 4.20 ядро Linux фактически не содержит VLA.
Хотя C11 явно не называет ограничение размера для VLA, некоторые чтения полагают, что он должен иметь такой же максимальный размер, как и все другие объекты, то есть байты SIZE_MAX. Однако это прочтение следует понимать в более широком контексте ограничений среды и платформы, таких как типичный размер страницы защиты стека 4 КиБ, что на много порядков меньше, чем SIZE_MAX.
Можно иметь VLA с динамическим хранилищем с помощью указателя на массив.
float read_and_process(int n)
{
float (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; ++i)
(*vals)[i] = read_val();
float ret = process(n, *vals);
free(vals);
return ret;
}
Ада
Ниже приведен тот же пример на Аде . Массивы 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
Эквивалентная функция 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 объявляет массив записей переменной длины 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 # объявляется массив целых чисел переменной длины. До версии C # 7.2 требовался указатель на массив, требующий «небезопасного» контекста. Ключевое слово unsafe требует, чтобы сборка, содержащая этот код, была помечена как небезопасная.
unsafe void DeclareStackBasedArrayUnsafe(int size)
{
int *pArray = stackalloc int[size];
pArray[0] = 123;
}
C # версии 7.2 и более поздних версий позволяет выделять массив без ключевого слова «unsafe» с помощью функции Span.
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);
...