Почему неинициализированные указатели вызывают нарушения доступа к памяти, близкие к 0?
Говорят, что часто (но не всегда), когда вы получаете AV в области памяти, близкой к нулю (например, $89), у вас есть неинициализированный указатель.
Но я видел это также в книгах Delphi... Хм... или они все были написаны одним и тем же автором (-ами)???
Обновить:
Цитата из "Руководства разработчика C++ Builder 6" Боба Сварта и всех, стр. 71:
Когда адрес памяти ZZZZZZZZ близок к нулю, причиной часто является неинициализированный указатель, к которому был получен доступ.
Почему это так? Почему неинициализированные указатели содержат низкие числа? Почему не большие числа, такие как $FFFFFFF или простые случайные числа? Это городской миф?
3 ответа
Это путает "неинициализированные указатели" с нулевыми ссылками или нулевыми указателями. Доступ к полям объекта или индексам в указателе будет представлен как смещение относительно базового указателя. Если эта ссылка равна нулю, то смещения, как правило, будут адресами либо около нуля (для положительных смещений), либо с адресами, близкими к максимальному значению собственного размера указателя (для отрицательных смещений).
Нарушения доступа по адресам с этими характерными малыми (или большими) значениями являются хорошим признаком того, что у вас есть нулевая ссылка или, в частности, нулевой указатель, а не просто неинициализированный указатель. Неинициализированная ссылка может иметь нулевое значение, но также может иметь любое другое значение в зависимости от того, как оно выделено.
Почему неинициализированные указатели содержат низкие числа?
Они не Они могут содержать любое значение.
Почему бы не большие числа, такие как $ FFFFFFF?
Они могут прекрасно содержать такие значения, как $ FFFFFFF.
или простые случайные числа?
Неинициализированные переменные, как правило, не являются действительно случайными. Как правило, они содержат все, что произошло, было записано в эту ячейку памяти при последнем использовании. Например, часто неинициализированные локальные переменные содержат одно и то же значение каждый раз, когда вызывается функция, потому что история использования стека оказывается повторяемой.
Также стоит отметить, что слово "случайный" часто используется неправильно. Люди часто говорят "случайный", когда они на самом деле имеют в виду "случайное распределение" с равномерным распределением. Я полагаю, это то, что вы имели в виду, когда использовали термин "случайный".
Ваше утверждение о AV, близком к нулю, верно для разыменования нулевого указателя. Это ноль или близко к нулю, потому что вы либо разыменовываете нулевой указатель:
int* p{};
const auto v = *p; // <-- AV at memory location = 0
или получить доступ к элементу массива:
char* p{};
const auto v = p[100]; // <--AV at memory location = 100
или поле структуры:
struct Data
{
int field1;
int field2;
};
Data* p{};
const auto v = p->field2; // AV at memory location = 4