В чем разница между VLA и динамическим выделением памяти через malloc?

Мне было любопытно вот это:

В чем разница между:

const int MAX_BUF = 1000;
char* Buffer = malloc(MAX_BUF);

и:

char Buffer[MAX_BUF];

person Alexis Zecharies    schedule 03.07.2015    source источник
comment
Является ли второй пример действительно VLA, учитывая, что MAX_BUF это const?   -  person juanchopanza    schedule 03.07.2015
comment
@juanchopanza Сэр, если я не ошибаюсь, в C++ переменная const является константой, но в C переменная const на самом деле имеет const квалификацию, а не фактическую константу. Итак, второй - VLA, поправьте меня, если я ошибаюсь.   -  person Sourav Ghosh    schedule 03.07.2015
comment
@SouravGhosh Хорошо, спасибо. Это был искренний вопрос. Я не так много знаю С.   -  person juanchopanza    schedule 03.07.2015
comment
@juanchopanza Мои C++ навыки ужасны, в этом случае я почти невидим. Просто случайно знаю несколько случаев, например этот. :-)   -  person Sourav Ghosh    schedule 03.07.2015
comment
какой код требует меньше времени для выполнения?   -  person Miraz    schedule 04.11.2020


Ответы (4)


  • Случай 1: В

     char Buffer[MAX_BUF];
    

    Buffer – это массив размера MAX_BUF. Метод распределения называется VLA.

  • Случай 2: В

    const int MAX_BUF = 1000;
    char* Buffer = malloc(MAX_BUF);
    

    Buffer – это указатель, которому выделяется память размером MAX_BUF, что равно 1000.

и массив не совпадает с указателем, и C-FAQ имеет очень хорошую коллекцию с подробным описанием причин.

Основное различие с точки зрения удобства использования и поведения:

  1. (1) обычно находится в стеке, Примечание, а (2) всегда в куче.
  2. (1) имеет фиксированный размер после выделения, (2) может быть изменен.
  3. (1) выделяется при вызове объемлющей функции и имеет область действия блока OTOH, (2) память выделяется динамически во время выполнения, а возвращаемая память имеет время жизни, которое простирается от выделения до освобождения.
  4. (1) программисту не нужно управлять выделенной памятью, а в (2) вся память malloc()d должна быть free()d. [Предоставлено: Джорджи]

Примечание. Вики

Например, компилятор C GNU выделяет память для VLA в стеке.

person Sourav Ghosh    schedule 03.07.2015
comment
В сторону: пока (2) всегда находится в куче. --> не всегда. Понятие кучи, стека и деталей распределения определяется реализацией. Остальные 3 балла хорошие. - person chux - Reinstate Monica; 09.10.2020

char* Buffer = malloc(MAX_BUF);

создает указатель char Buffer, динамически выделяет MAX_BUF байт памяти через malloc и заставляет Buffer указывать на начало выделенного пространства. Эта память выделяется в куче.

char Buffer[MAX_BUF];

создает массив Buffer размера MAX_BUF, который может содержать максимум MAX_BUF символов. Обратите внимание, что вы создаете массив переменной длины (функция, представленная в C99), поскольку MAX_BUF является переменной. Этот массив может быть создан в стеке.

person Spikatrix    schedule 03.07.2015
comment
Обратите внимание, что технически массив представляет собой VLA (массив переменной длины), потому что MAX_BUF не является константой времени компиляции. - person Jonathan Leffler; 03.07.2015
comment
Спасибо. Я пропустил это. - person Spikatrix; 03.07.2015

Я добавлю немного информации с точки зрения управления памятью, в дополнение к тому, что сказали другие.

1) Основное отличие здесь:

const int MAX_BUF = 1000;
char* Buffer = malloc(MAX_BUF);

Вам нужно управлять выделенной памятью вручную, например, освободить Buffer, когда вы закончите ее использовать. Если вы забудете free его (или освободите дважды), это может привести к проблемам.

2) Со вторым случаем:

char Buffer[MAX_BUF];

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

Некоторые моменты.

  • Поскольку второй выделяется в стеке, первый подход также используется, когда необходимо создать большой массив, поскольку в куче обычно доступно больше памяти.
  • Кроме того, если вы создаете массив, используя второй подход, например, в методе, время жизни объекта будет этим методом - вы не сможете использовать этот массив вне этого метода. В то время как с динамическим размещением это не так.
person Giorgi Moniava    schedule 03.07.2015
comment
Ницца. Требовался free() угол, который пропустили ни я, ни @coolguy. :-) - person Sourav Ghosh; 03.07.2015
comment
Я добавил это с атрибутами. :-) - person Sourav Ghosh; 03.07.2015
comment
@SouravGhosh: понятно, мило. - person Giorgi Moniava; 03.07.2015

Наиболее заметным отличием является масштаб. Массив VLA будет действителен только внутри области, в которой он объявлен, в то время как динамический массив будет доступен везде в программе, пока вы не вызовете free().

На практике VLA могут быть быстрее, чем динамическая память, если компилятор использует выделение стека для VLA. Однако стандарт C не указывает, где выделяется VLA.

(Теоретически компилятор может выделить VLA в куче, но тогда компилятор также будет отвечать за очистку. Я не думаю, что такие решения существуют. Каждый компилятор, который я использовал, всегда объявлял VLA в стеке. )

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

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


Сравнение/резюме:

  • VLA следует использовать при наличии небольших объемов локальных данных, поскольку они имеют быстрое время выделения и автоматическую очистку.
  • Динамические массивы следует использовать при наличии больших объемов данных, чтобы предотвратить переполнение стека.
  • Динамические массивы следует использовать, когда данные должны сохраняться после выполнения функции и быть доступными в другом месте программы.
  • Динамические массивы следует использовать, когда у вас есть исключительные и/или иррациональные требования к переносимости.
person Lundin    schedule 01.12.2016
comment
А еще Линус Торвальд ненавидит VLA ;) - person Matthieu; 15.07.2019