Только начал изучать программирование на С++, и возник такой вопрос: что происходит, когда программа пытается обратиться к несуществующего элементу массива? Как видно на скрине, компилятор выделяет в памяти области для 4-х элементов и пока они неинициализированы, то заполнены какими-то непонятными значениями. Но что за число вообще выводится в консоль, когда я обращаюсь к элементу, которого не существует? Что в этот момент делает программа? Откуда она вообще взяла это число? Если программа обращается вообще к непонятному участку памяти, то почему именно к нему?
-
Это просто данные, которые были в памяти, и которые C++ преобразовал к типу int. Это могли быть остатки любой программы, или данных, которые помещались в оперативную память некоторое количество времени назад. – Jul 19 '18 at 12:25
-
3Крайне рекомендуется приводить исходники и прочее в виде текстов, а не жуткими скринами... – Harry Jul 19 '18 at 12:33
2 Answers
Когда вы объявляете массив int arr[4] - вы говорите, что нужно выделить память для четырех int, идущих в памяти подряд. Память грубо можно рассматривать как длинную улицу с пронумерованными домами, и компилятор выделяет для вашего массива 4 дома. При обращении arr[5] вы по сути стучитесь в дверь шестого дома. Который вам не выделили. И в котором может быть что угодно - заброшенные развалины, злой пес, привидения... Словом - обращаться туда, куда вам не разрешали - это undefined behaviour, неопределенное поведение. Программа может аварийно завершиться (наилучшее, что может произойти), а может просто продолжать работать и выдавать неверные результаты...
Кстати, когда вы попросили выделить эти 4 дома без инициализации - в них остались от прежних жильцов сплошные привидения :) - т.е. старые значения, которые просто когда-то были записаны в эти ячейки памяти. Пока вы не запишете в них новые - вы в принципе не можете сказать, что там находится. (Есть исключение - если это глобальный массив, но пока вы только начинаете учиться, об этом рано говорить.)
- 221,325
-
Кстати, ТС'у могло и не повезти, если бы он вышел за пределы допустимой памяти таким смещением. – Jul 19 '18 at 12:33
-
@Anamnian А что вы называете невезением? По-моему, ему как раз и не повезло - программа не упала... (впрочем, падение при такой ошибке, увы, редкость...) – Harry Jul 19 '18 at 12:34
-
Тут смотря с какой стороны смотреть- когда ты разработчик, задача чтобы программа не упала, когда тестер- чтобы упала. На деве нужны обработчики которые кричат на каждую ошибку, на проде желательно чтобы данные не потерялись (ну это как правило). Если вы пишите кардиорегулятор и возникла ошибка- лучше аварийно завершить работу и перезапустить программу. – Jul 19 '18 at 13:06
-
Спасибо большое за ваш ответ! На счет вашей аналогии с 6-ым домом, а вот про него хотелось бы узнать конкретней например почему программа не вылетает и не говорит что я обращаюсь к элементу которого нет и в таком случае куда именно программа пойдет искать этот 6-й дом в памяти )) и почему именно туда она и пойдет, а не в какое то еще место?)) – Никита Антонов Jul 19 '18 at 14:38
-
И если вас не затруднить поделиться какими-нибудь статьями или материалами, чтобы я в целом начал разбираться как работает память, откуда появляются эти привидения и прочее )) – Никита Антонов Jul 19 '18 at 14:41
-
Потому что это улица, а вы просите 6-й дом. И если доступ к памяти не запрещен (там не сидит злая собака) - а в стеке он не запрещен... - то вы вполне можете в него зайти и посмотреть, кто там живет. Другое дело, что этот дом может принадлежать какой-то другой переменной, так что, занеся туда что-то, вы можете испортить то важное, что там уже лежало... А книги - посмотрите большой список здесь. – Harry Jul 19 '18 at 15:35
-
-
А вот можно еще более углубленный вопрос задать ?)) Правильно ли я понимаю, что адрес массива - это адрес начального(нулевого) элемента массива (обозначим его за n), по сколько в массиве хранятся значения одного типа данных, то когда мы обращаемся к любому элементу массива его адрес рассчитывается по следующей формуле n+k·i, где k - количество байт занимаемого 1-им элементом, так вот поэтому когда я обращаюсь к элементу которого просто не существует компилятор расчитает как ни в чем не бывало адрес памяти и обратится к нему поэтому мы и получаем случайные числа в результате ? – Никита Антонов Jul 20 '18 at 10:13
-
Именно. Поэтому, кстати, для любого массива
type arr[]значение*(arr+i)будет значениеi-го элемента, а не элемента со смещениемiбайт от начала массива. Кстати, заодно можно обращаться к элементу массива не только как кarray[i], но и как кi[array]:) – Harry Jul 20 '18 at 10:21 -
Ого, здорово ! Спасибо еще раз, что помогли разобраться)). Я не знаю как в c++, но в js например в массиве можно хранить, что угодно, хоть строки, хоть числа, там видимо другой алгоритм для поиска элемента в памяти. – Никита Антонов Jul 20 '18 at 10:28
Эти "непонятные значения" - то что принято называть мусором(когда программа удаляет переменные, она, на самом деле их не удаляет, а просто помечает как неиспользуемые). И в том случае когда вы обращаетесь к несуществующему элементу массива выводится тоже мусор. Как это происходит? Для этого нужно понимать что такое смещение и иметь понятие что такое память. Дело в том, что когда вы инкременируете указатель, он не проверяет вышел ли он за пределы массива (он это и не может проверить самостоятельно), поэтому он просто смещается на заданное расстояние от начала массива и выводит то, что хранится в последовательности байт на которую он указывает, как будто это реальное значение.
- 8,057
-
Спасибо большое за углубленный ответ, не могли бы вы скинуть статей или литературы чтобы подробней почитать о смещении или о памяти в целом, чтобы иметь представление как это работает. Кстати очень интересная информация о том что переменные не удаляются из памяти )) – Никита Антонов Jul 19 '18 at 14:36
-
@НикитаАнтонов это есть в любом нормальном учебнике по Си/С++. Если не знаете с какого начать - выберите Прата, он хорошо и понятно пишет. – Andrej Levkovitch Jul 19 '18 at 14:40
-
