Почему нельзя использовать указатель без объявления переменной?

Хочу понять, почему при объявлении указателя необходимо обязательно объявлять переменную? Почему нельзя просто объявить указатель, разименовать его и записать в него значение (почему не работает без var?, хотя и ошибки не пишет):
int var;
    int *pvar;

//    pvar = &var;
    scanf("%d", pvar);
    printf("%d %p", *pvar, pvar);
    getchar();
  • Вопрос задан
  • 668 просмотров
Пригласить эксперта
Ответы на вопрос 3
TrueBers
@TrueBers
Гуглю за еду
А потому что, учите ассемблер, вот почему.
Разработчика на C/C++ не бывает без базовых знаний ассемблера.
Можно взглянуть сюда и понять очень многое.

На 6-й строке ассемблерного кода у вас происходит выделение стекового фрейма. Это та область памяти, где будут храниться ваши локальные переменные, которые вы объявляете в текущей функции, т. е. в нашем случае это int var; int *pvar;. Несмотря на то, что сумма размеров этих переменных на стеке sizeof(int) + sizeof(int*) = 12 для x86_64, выделяется 16 байт согласно пункту 3.2.2 SystemV ABI AMD64, который говорит, что стековый фрейм должен быть выровнен по границе 16 байт. На другой архитектуре здесь может быть другое правило.

Стек растёт вниз по адресам, т. е. выделение памяти на нём — это просто вычитание (инструкция SUB) из адреса его вершины (регистр RSP) числа, равного тому количеству памяти, которое мы хотим выделить. К вам как бы «всплывает» кусок памяти «откуда-то снизу». Эта память скорее всего использовалась предыдущими вызовами функций и осталась не затёрта! Соответственно, вы должны инициализировать этот поюзаный кем-то кусок под себя.
Что-то типа аналогии со школы или универа, когда в аудитории есть такая раздвигающаяся доска из двух или трёх частей, видели наверное, когда выдвигаешь одну часть, а другая задвигается. Так вот, когда вы приходите на лекцию, выдвигаете доску, а там, внезапно, предыдущая группа не стёрла за собой свои творения, и вам придётся это стирать и писать вещи, относящиеся к вашему предмету. Естественно, если вы попытаетесь использовать для вашего предмета то, что осталось от предыдущей группы, получится бред в большинстве случаев.

Когда адрес вашего указателя где-то используется без инициализации (7-я строка асм кода), он возьмёт тот самый мусор, который к нам пришёл при выделении фрейма.
Получается лотерея: если этот мусор случайно оказывается действующим указателем на память, доступную для записи, ОС не выбрасывает исключение и пишет куда-то в непонятное место, ломая тем самым случайное место в вашей программе. Т. е. вы попадаете на тот случай, когда во фрейме попался до сих пор действующий указатель из мусора предыдущей функции, которая использовала этот кусок фрейма и не затёрла. А когда лотерея проиграна, и попали не на указатель, а на не пойми что, ОС бросает исключение. Поэтому ошибка не всегда проявляется.

Это всё частный случай реализации языка Си для конкретной архитектуры. Конечно, в терминах стандарта таких вещей не бывает вообще, а объявлено просто как неопределённое поведение, которого нужно избегать.
Ответ написан
@MiiNiPaa
разименовать его и записать в него значение
А куда значение будет записано? Куда указывает указатель, если его не направить на конкретную переменную?

Вы фактически перезаписываете случайную область памяти. Это может оказаться невыделенная память (краш), защищённая от записи (краш), мусор в памяти (хуже всего - кажется что работает), память используемая для каких-либо данных (Поменяли какую-то не имеющую отношения к этому переменную)...

Представьте себе, что вы взяли закипевший чайник и начали наливать кипяток куда-то на стол, не обращая внимания на то, что там окажется: чашка, блюдо, чья-то рука или склонившаяся голова... Приблизительно это вы и делаете.

И ещё: использовать неинициализированный указатель - UB. Это позволяет компилятору сделать с кодом что угодно, хоть удалить его весь.
Ответ написан
15432
@15432
Системный программист ^_^
Так создавайте указатель сразу с местом, куда записывать, компилятор такое умеет - массив называется.
int pvar[1];
Почти тот же самый указатель, только теперь на стеке было дополнительно выделено место, и он в него указывает. Только изменять место, куда указывает, нельзя.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы