Массив статичен, но размер массива неизвестен до времени выполнения. Как это возможно? - PullRequest
9 голосов
/ 14 января 2012

Это беспокоило меня некоторое время. Это лежит в основе моего (отсутствия) понимания разницы между статическим и динамическим распределением памяти. Следующий массив является обычным статическим массивом, который должен означать, что память выделяется во время компиляции, правильно? Тем не менее, я настроил его так, чтобы пользователь вводил размер массива во время выполнения.

#include <iostream>
using namespace std;

int main() {
  cout << "how many elements should the array hold? ";
  int arraySize;
  cin >> arraySize;

  int arr[arraySize];

  for (int i = 0; i < arraySize; ++i)
    arr[i] = i * 2;

  return 0;
}

Обратите внимание, что в этой программе нет операторов new или delete. Он отлично работает в Xcode 4.2 (компилятор Clang по умолчанию), а также на сервере UNIX моей школы (GCC 4.4.5). Как компилятор узнает, сколько памяти выделить для arr, когда массив создается во время компиляции? Это просто случайность моего компилятора, опасный код, который может повредить другую память, или это законно?

Ответы [ 4 ]

8 голосов
/ 14 января 2012

Это нестандартное расширение ваших компиляторов C ++.Обратите внимание, что в C, в отличие от C ++, это официально поддерживается (то есть стандартно-обязательное поведение) начиная с C99.В C ++ это не поддерживается, потому что уже есть решение проблемы: используйте std::vector вместо массива.

Однако массив не равен , а не с использованием статического выделения памяти (нидинамическое распределение памяти), но автоматическое распределение памяти.Автоматические переменные автоматически освобождаются в конце функции (область памяти, в которой они размещены, называется стеком, потому что выделения и освобождения в ней имеют семантику стека).Чтобы массив использовал статическое выделение памяти, вы должны поместить static перед определением (обратите внимание, что переменные в глобальной области или области имен всегда используют статическое выделение памяти).Однако, если вы сделаете переменную статической, вы обнаружите, что компилятор больше не позволяет использовать непостоянный размер массива.

Обратите внимание, что std::vector вместо этого хранит свои данные с динамическим распределением памяти,По этой причине вы также можете использовать непостоянный размер даже для статических std::vector с.

4 голосов
/ 14 января 2012

Для массива (или любого объекта), объявленного внутри функции, память выделяется при входе в функцию (обычно в стеке) и освобождается при возврате функции. Тот факт, что в данном случае функция main, на это не влияет.

Это:

cin >> arraySize;
int arr[arraySize];

- это «массив переменной длины» (VLA). Дело в том, что C ++ не поддерживает VLA. C делает, начиная со стандарта ISO C 1999 года (C99), но это не та особенность, которую принял C ++.

Ваш компилятор поддерживает VLA в C ++ в качестве расширения. Их использование делает ваш код непереносимым.

(Одна из проблем с VLA заключается в том, что нет механизма обнаружения ошибки выделения; если arraySize слишком велико, поведение программы не определено).

Для gcc компиляция с -pedantic выдаст предупреждение:

warning: ISO C++ forbids variable length array ‘arr’
1 голос
/ 14 января 2012

Сгенерированный код выделяет байты arraySize в стеке во время выполнения.Как только функция возвращается, стек раскручивается, включая «возвращение» байтов, которые были выделены для массива.

Использование new и delete для выделения места в куче.Время жизни выделенной памяти в куче не зависит от области действия какой-либо функции или метода. Если вы выделите для нее место в функции и функция вернется, память все равно будет выделена и действительна.

0 голосов
/ 14 января 2012

Это Массив переменной длины (поддерживается только в C99, но не в C ++). Он выделяется в стеке во время выполнения.

...