Какова цель выделения определенного объема памяти для массивов в C ++?
Я участвую в classе в Data Cructures на C ++ в этом семестре, и я наткнулся на то, что сегодня не совсем понимаю. Скажем, я должен был создать указатель на массив в куче:
int* arrayPtr = new int [4];
Я могу получить доступ к этому массиву с помощью синтаксиса указателя
int value = *(arrayPtr + index);
Но если бы я должен был добавить другое значение в позицию памяти сразу после окончания пространства, выделенного для массива, тогда я мог бы получить к нему доступ
- Объявление указателя на multidimensional array и выделение массива
- Когда следует использовать новое ключевое слово в C ++?
- Есть ли причина проверить указатель NULL перед удалением?
- Арифметика указателей в C
- Арифметика указателей
*(arrayPtr + 4) = 0; int nextPos = *(arrayPtr + 4); //the value of nextPos will be 0, or whatever value I previously filled that space with
Позиция в памяти * (arrayPtr + 4) проходит через конец пространства, выделенного для массива. Но, насколько я понимаю, вышеупомянутое все равно не вызовет никаких проблем. Таким образом, помимо того, что это требование C ++, почему даже объявляйте их конкретным размером?
- Безопасно ли удалять указатель на пустоту?
- Зачем использовать двойной указатель? или Зачем использовать указатели для указателей?
- Что мне нужно сделать, прежде чем удалять элементы в векторе указателей на динамически выделенные объекты?
- Почему std :: cout конвертирует изменчивые указатели в bool?
- Как распечатать адрес памяти в C
- Как использовать массивы на C ++?
- Передача двумерного массива с помощью указателя
- Как использовать глобальный var для файлов в пакете?
Когда вы проходите мимо выделенной памяти, вы фактически получаете доступ к памяти какого-либо другого объекта (или свободной памяти сейчас, но это может измениться позже). Таким образом, это вызовет проблемы. Особенно, если вы попытаетесь что-то написать.
Я могу получить доступ к этому массиву с помощью синтаксиса указателя
int value = * (arrayPtr + index);
Да, но не надо. Использовать arrayPtr[index]
Позиция в памяти * (arrayPtr + 4) проходит через конец пространства, выделенного для массива. Но, насколько я понимаю, вышеупомянутое все равно не вызовет никаких проблем.
Вы понимаете неправильно. О, очень неправильно. Вы вызываете неопределенное поведение, и неопределенное поведение не определено. Он может работать в течение недели, а затем перерыв на следующий день на следующей неделе, и вам останется интересно, почему. Если вы не знаете размер коллекции заранее, используйте что-то динамическое, как vector
а не массив.
Да, в C / C ++ вы можете получить доступ к памяти за пределами пространства, которое, как вы утверждают, было выделено. Иногда. Это то, что называется неопределенным поведением .
В принципе, вы сказали компилятору и системе управления памятью, что вам нужно пространство для хранения четырех целых чисел, а система управления памятью выделяет пространство для хранения четырех целых чисел. Он дал вам указатель на это пространство. Во внутреннем учете менеджера памяти эти байты delete[] arrayPtr;
теперь заняты, пока вы не delete[] arrayPtr;
,
Однако диспетчер памяти не выделил для вас следующий байт. У вас нет никакого способа узнать, в общем, что такое следующий байт или кому он принадлежит.
В простой примерной программе, такой как ваш пример, которая просто выделяет несколько байтов и не выделяет ничего другого, есть вероятность, что следующий байт принадлежит вашей программе и не занят. Если этот массив является единственной динамически распределенной памятью в вашей программе, то, вероятно , может быть безопасно работать в конце.
Но в более сложной программе с несколькими распределениями динамической памяти и освобождением памяти, особенно вблизи краев страниц памяти, у вас действительно нет хорошего способа узнать, что содержат любые байты вне запрашиваемой памяти. Поэтому, когда вы пишете байты за пределами памяти, которую вы просили в new
вы можете писать в основном что угодно.
Здесь происходит неопределенное поведение . Поскольку вы не знаете, что в этом пространстве вы написали, вы не знаете, что произойдет в результате. Вот несколько примеров того, что может случиться:
-
При написании на нее память не выделялась. В этом случае данные в порядке, и ничего плохого не происходит. Однако, если последующее распределение памяти использует это пространство, все, что вы пытались поместить там, будет потеряно.
-
Память была выделена, когда вы написали ей. В этом случае, поздравляю, вы просто перезаписали некоторые случайные байты из какой-либо другой структуры данных где-то еще в вашей программе. Представьте, что вы заменили переменную где-нибудь на одном из ваших объектов случайными данными и рассмотрите, что это будет означать для вашей программы. Может быть, список где-то еще имеет неправильный счет. Может быть, строка теперь имеет некоторые случайные значения для первых нескольких символов или теперь пуста, потому что вы заменили эти символы нулями.
-
Массив был выделен на краю страницы, поэтому следующие байты не принадлежат вашей программе. Адрес находится вне распределения вашей программы. В этом случае ОС обнаруживает доступ к случайной памяти, которая не принадлежит вам, и немедленно завершает работу вашей программы с помощью
SIGSEGV
.
В принципе, неопределенное поведение означает, что вы делаете что-то незаконное, но поскольку C / C ++ предназначен для быстрой работы, разработчики языка не содержат явной проверки, чтобы убедиться, что вы не нарушаете правила, например, другие языки (например, Java , C #). Они просто перечисляют поведение нарушения правил как неопределенные, а затем люди, которые делают компиляторы, могут иметь более простой и быстрый код, поскольку не выполняются проверки границ массива, и если вы нарушаете правила, это ваша собственная проблема.
Так да, это иногда работает, но никогда не полагаться на него.
Это не вызовет каких-либо проблем в чисто абстрактной настройке, где вы будете беспокоиться только о том, является ли логика алгоритма звуковой. В этом случае нет причин объявлять размер массива вообще. Однако ваш компьютер существует в физическом мире и имеет ограниченный объем памяти. Когда вы выделяете память, вы просите операционную систему разрешить использовать некоторую ограниченную память компьютера. Если вы выйдете за пределы этого, операционная система должна остановить вас, как правило, убивая ваш процесс / программу.
Да, вы должны записать его как arrayptr [index], потому что позиция в памяти * (arrayptr + 4) прошла через конец пространства, которое вы выделили для массива. Его недостаток в C ++, что размер массива не может быть расширен после выделения.