Для установки нажмите кнопочку Установить расширение. И это всё.

Исходный код расширения WIKI 2 регулярно проверяется специалистами Mozilla Foundation, Google и Apple. Вы также можете это сделать в любой момент.

4,5
Келли Слэйтон
Мои поздравления с отличным проектом... что за великолепная идея!
Александр Григорьевский
Я использую WIKI 2 каждый день
и почти забыл как выглядит оригинальная Википедия.
Статистика
На русском, статей
Улучшено за 24 ч.
Добавлено за 24 ч.
Альтернативы
Недавние
Show all languages
Что мы делаем. Каждая страница проходит через несколько сотен совершенствующих техник. Совершенно та же Википедия. Только лучше.
.
Лео
Ньютон
Яркие
Мягкие

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

Из Википедии — свободной энциклопедии

В программировании массив переменной длины (англ. 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) на стеке[en][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 года.
Эта страница в последний раз была отредактирована 17 сентября 2023 в 21:50.
Как только страница обновилась в Википедии она обновляется в Вики 2.
Обычно почти сразу, изредка в течении часа.
Основа этой страницы находится в Википедии. Текст доступен по лицензии CC BY-SA 3.0 Unported License. Нетекстовые медиаданные доступны под собственными лицензиями. Wikipedia® — зарегистрированный товарный знак организации Wikimedia Foundation, Inc. WIKI 2 является независимой компанией и не аффилирована с Фондом Викимедиа (Wikimedia Foundation).