Адрес указателя по некоторым причинам равен NULL - PullRequest
0 голосов
/ 04 октября 2018

это простая программа, которая отображает адрес указателя:

#include <stdio.h>

int main(void)
{
    int *a;
    int *b;

    printf ("address of a : %p, the address of b : %p\n", a, b);
    return (0);
}

, поэтому вывод выглядит примерно так:

address of a : 0x7fff537b1ad8, the address of b : 0x0

мой вопрос: почему переменная b имеет недопустимыйадресная память, но переменная a не

Ответы [ 4 ]

0 голосов
/ 04 октября 2018

ab] никогда не инициализировались , поэтому они могут иметь любое значение.Получаемые ими значения - это то, что происходит в соответствующих местах памяти кадра стека main до вызова main.То есть a и b являются переменными области действия , поэтому они находятся в фрейме стека функции.

В вашем случае b получил 0x0, а a получилненулевое значение, которое кажется действительным, но оно не .Он может указывать на в любом месте в физическом адресном пространстве программы.Мы не знаем, где это.Если мы читаем из него, это может быть за пределами назначенного / действительного / сопоставленного адресного пространства программы, и мы тоже получим ошибку по этому поводу.

Или, если мы напишем в местоположение, которое a указывает на то, что мы можем писать в любое местоположение.Таким образом, мы можем испортить данные программы в произвольном месте.Это может не генерировать исключение сразу, но последствия неизвестны.Мы могли бы перезаписывать значения в сегменте данных.

Это может привести к тому, что программа выдаст неверные результаты позже, потому что значение данного значения в сегменте данных равно , а не .статически назначенный.

Или, возможно, мы искажаем значение, содержащееся в другой переменной указателя в глобальном пространстве памяти, которое было назначено статически.Позже, разыменование того, что указатель может [, вероятно, ] вызвать ошибку segault

Может даже указывать на защищенную память, такую ​​как сегмент кода, который [снова]сгенерировать segfault.

0 голосов
/ 04 октября 2018

Вы на самом деле не печатаете адрес указателей.Вы печатаете значения этих указателей.И поскольку переменные неинициализированы, они имеют неопределенные значения.

Вам необходимо использовать оператор address-of, чтобы получить их адреса:

printf("address of a : %p, the address of b : %p\n", (void *)&a, (void *)&b);

Обратите внимание, что это один из немногихслучаи, когда требуется приведение к void *.

0 голосов
/ 04 октября 2018

Локальная переменная имеет автоматическую продолжительность хранения (выходит за пределы области видимости, вероятно, выделен стек).

Чтобы получить доступ к неинициализированной переменной с автоматической продолжительностью хранения (у которой не указан ее адрес), вызывается неопределенное поведение.Когда вы это делаете, может произойти все что угодно.

Кроме того, неинициализированные переменные с автоматическим хранением имеют неопределенные значения .Значение может содержать любое значение, включая мусор, ноль или действительный адрес.Нет необходимости возвращать одно и то же значение дважды, если вы дважды выполняете программу или дважды читаете переменную в программе.В некоторых экзотических системах доступ к переменной с неопределенным значением может привести к неопределенному поведению, если это значение является представлением прерывания.

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


В качестве примечания, адрес 0 - это не то же самое, что NULL и не обязательно представление нулевого указателя.NULL - это константа нулевого указателя , а не адрес, с целочисленным значением 0 или (void*)0.Когда NULL назначается указателю любого типа, он создает нулевой указатель.Пустой указатель может содержать любое внутреннее представление, такое как адрес 0 или какое-либо другое значение - оно не указано в C.

0 голосов
/ 04 октября 2018

Оба указатели указывают на недопустимую память.Тот факт, что указатель указывает на, казалось бы, допустимое место в памяти, не означает, что он действителен в контексте вашей программы.

Для уточнения, место в памяти, на которое указывает a, не выделено для вашей программы.Таким образом, с точки зрения вашего приложения, это недействительная память.Любая попытка чтения или записи приведет к неопределенному поведению.

Другими словами, нет абсолютно никакой гарантии, что b будет содержать значение NULL, оно также может иметь некоторые другие, казалось бы, правильные, ноневерный адрес памяти.Они недействительны, независимо от места в памяти, на которое они указывают.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...