Страницы

Поиск по вопросам

среда, 29 января 2020 г.

Динамическое выделение памяти с++

#cpp


Вопрос заключается в необходимости оператора new. Он предназначается для динамического
выделения памяти, то есть во время выполнения программы, когда требуемый размер неизвестен.
Но следующий простой пример у меня скомпилировался и работал(хотя и показывал мусор).

#include 
using namespace std; 

int main(){
    int size;
    cin >> size;
    int A[size];

    for(int i = 0; i < size; i++) cout << A[i] << " ";

    return 0;
}


Так вот возник вопрос, что происходит в этом примере и правильный ли он вообще? Каким
образом выделяется память? В каких вообще случаях нужен оператор new, и без него было
бы не обойтись?

В чем разница между этим определением массива и таким(помимо мусора):

int *A = new int[size];

    


Ответы

Ответ 1



С точки зрения стандарта C++ данный фрагмент кода int size; cin >> size; int A[size]; является некорректным. Стандарт C++ не допускает массивы переменной длины. Размер массива должен быть константным значением, известным на этапе компиляции, если только это не объявление массива с внешним связыванием. Однако некоторые компиляторы вводят собственные расширения языка, которые порой противоречат стандарту. И, похоже, вы компилировали этот код компилятором, который имеет такое расширение. Данный массив имеет автоматическую продолжительность памяти, которая обычно ограничена, а потому не позволяет определять массивы больших размеров. Объявление массивов больших размеров в этой памяти может привести к тому, что другие объекты не смогут быть определены, и программа завершится аварийно. Разница между этими объявлениями int A[size]; int *A = new int[size]; состоит в том, что, как было уже указано, первое объявление является некорректным. В первом предложении объявляется массив, который имеет автоматическую продолжительность памяти, а в то время, как во втором случае объявляется указатель с автоматической длительностью памяти и безымянный массив с динамической продолжительностью памяти. Это означает, что переменная A, может прекратить свое существование, а массив будет продолжать свое существование. В первом случае за распределение памяти отвечает компилятор, и он ее освобождает автоматически, в то время как во втором случае за выделение памяти и ее освобождение отвечает непосредственно пользователь.

Ответ 2



Существует 3 вида памяти. 1 Стековая - она выделяется для переменных в области видимости функции. int setArray() { int A [5]; } в таком случае выделяется массив с 5 ячейками. 5 - это константа! запись такого типа неприемлема: int setArray() { int length = 5; int A [length]; } а вот так можно int setArray() { const int length = 5; int A [length]; } То есть память выделяется до этапа компиляции. 2 Статическая память выделяется еще до начала работы программы, на стадии компиляции и сборки. Статические переменные имеют фиксированный адрес, известный до запуска программы и не изменяющийся в процессе ее работы. Запись: static int A [5]; A будет доступна не только в области видимости функции 3 Куча (Динамическая память). Выделятся в процессе работы программы. То есть вы не знаете, какой у вас массив - 5 элементов или 10. В таком случае вам надо выделить динамическую память. int *A = new int[size]; После работы с массивом (объектом и т.д.) необходимо её очистить: delete [] A;

Ответ 3



Тут у вас создался динамический массив на стеке. Проблема в том, что стек в общем-то, невелик, и большой массив на нем создать нельзя. Ну и массив на стеке будет уничтожен при выходе из функции. Лучше всего в C++ в качестве динамического массива задействовать std::vector.

Ответ 4



Данный пример неправильный, так как в C++ можно указывать размер массива только константой. Например: const int size = 3; int A[size]; или int A[3]; Отличие создания массива вышеупомянутым способом от такого способа int *A = new int[size]; состоит в том, что во втором случае переменная size может быть не константой, то есть Вы её можете прочитать с клавиатуры. А далее вы можете работать с этим массивом как с обычным. То есть, чтобы получить какой-либо элемент, используйте следующую конструкцию: A[n]. Оператор new нужен для динамического выделения памяти. Для более глубоко понимания темы вашего вопроса я рекомендую почитать информацию на этом сайте: http://cppstudio.com/post/432/

Ответ 5



Предложение ввести в язык С++ массивы с размером времени выполнения (отдаленный аналог VLA в C99) существовало на промежуточных этапах разработки стандарта С++11 и легко находится в черновых вариантах документа. Однако в конечный вариант документа ничего из этого не вошло и тема массивов с размером времени выполнения в С++ была закрыта. Тем не менее многие компиляторы либо уже имели более-менее соответствующую черновику реализацию подобной функциональности, либо бросились ее реализовывать еще до выхода финальной версии С++11. Именно эти реализации данной функциональности и продолжают жить в некоторых компиляторах в качестве расширения языка. Не забывайте, что "пример скомпилировался" никоим образом не является подтверждением корректности кода с точки зрения языка С++. При использовании компиляторов группы GCC/Clang возьмите в привычку всегда пользоваться параметром -pedantic-errors, чтобы отчистить эти реализации от разношерстной студенческой самодеятельности. В каких вообще случаях нужен оператор new Оператор new нужен в первую очередь для неограниченного ручного контроля за временем жизни создаваемых вами вручную объектов. Объекты, созданные через new живут "вечно", т.е. пока вы их сами не уничтожите через delete или пока ваша программа не завершится. Их время жизни никак не привязано к границам локальных блоков. Также new нужен для выбора во время выполнения конкретного типа создаваемых объектов (как в случае полиморфных классов) и/или их количества (в частности, в случае массивов это - размер массива). Этого можно достичь только средствами динамического создания объектов. Многого из этого можно достичь и без new или других вариантов динамического выделения памяти, а лишь грамотно/остроумно организовывая локальные определения объектов, но в общем случае преодолеть ограничения времени жизни не удастся (да и нет в этом смысла). В чем разница между этим определением массива и таким(помимо мусора) (Не совсем понятно о каком "мусоре" вы говорите). Разница в первую очередь в том, что локальный массив будет автоматически уничтожен по завершению блока, содержащего его объявление. А созданный через new[] массив автоматически уничтожаться не будет вообще - он будет жить до тех пор, по не будет уничтожен через delete[].

Комментариев нет:

Отправить комментарий