Подтвердить что ты не робот

Что ТОЧНО понимается под "де-ссылкой на указатель NULL"?

Я полный новичок в C, и во время моей университетской работы я встретил комментарии в коде, которые часто ссылаются на де-ссылку на указатель NULL. У меня есть фон в С#, я получаю, что это может быть похоже на "исключение NullReferenceException", которое вы получаете в .Net, но теперь у меня возникают серьезные сомнения.

Может кто-нибудь, пожалуйста, объясните мне в терминах мирян точно, что это такое и почему это плохо?

4b9b3361

Ответ 1

Указатель

A NULL указывает на память, которая не существует. Это может быть адрес 0x00000000 или любое другое значение, определенное реализацией (если оно никогда не может быть реальным адресом). Выражение разыменования означает попытку доступа к тому, на что указывает указатель. Оператор * является оператором разыменования:

int a, b, c; // some integers
int *pi;     // a pointer to an integer

a = 5;
pi = &a; // pi points to a
b = *pi; // b is now 5
pi = NULL;
c = *pi; // this is a NULL pointer dereference

Это то же самое, что и NullReferenceException в С#, за исключением того, что указатели в C могут указывать на любой объект данных, даже элементы внутри массива.

Ответ 2

Выделение означает только чтение значения памяти по заданному адресу. Поэтому, когда у вас есть указатель на что-то, для разыменования указателя означает чтение или запись данных, на которые указывает указатель.

В C унарный оператор * является оператором разыменования. Если x - указатель, то *x указывает на то, что указывает x. Унарный оператор & является адресом-оператором. Если x - это что-то, то &x - это адрес, в котором x хранится в памяти. Операторы * и & являются инверсиями друг друга: если x - это любые данные, а y - любой указатель, то эти уравнения всегда верны:

*(&x) == x
&(*y) == y

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

В большинстве реализаций вы получите "ошибку сегментации" или "нарушение прав доступа", если вы попытаетесь это сделать, что почти всегда приведет к тому, что ваша программа будет завершена операционной системой. Здесь один путь может быть разыменован пустым указателем:

int *x = NULL;  // x is a null pointer
int y = *x;     // CRASH: dereference x, trying to read it
*x = 0;         // CRASH: dereference x, trying to write it

И да, разыменование нулевого указателя в точности похоже на NullReferenceException в С# (или NullPointerException на Java), за исключением того, что стандарт langauge здесь немного полезнее. В С# разыменование нулевой ссылки имеет четко определенное поведение: оно всегда выбрасывает NullReferenceException. Нет никакой возможности, чтобы ваша программа продолжала работать молча или стирать ваш жесткий диск, как в C (если не было ошибок в языковой среде исполнения, но опять же это невероятно маловероятно).

Ответ 3

Это означает

myclass *p = NULL;
*p = ...;  // illegal: dereferencing NULL pointer
... = *p;  // illegal: dereferencing NULL pointer
p->meth(); // illegal: equivalent to (*p).meth(), which is dereferencing NULL pointer

myclass *p = /* some legal, non-NULL pointer */;
*p = ...;  // Ok
... = *p;  // Ok
p->meth(); // Ok, if myclass::meth() exists

в основном, почти все, что связано с (*p) или неявно с участием (*p), например. p->..., который является сокращением для (*p). ...; кроме объявления указателя.

Ответ 4

Из wiki

Нулевой указатель имеет зарезервированное значение, часто, но не обязательно значение 0, указывающее, что оно не относится к объекту..

Поскольку нулевой указатель не ссылается на значимый объект, попытка разыменования нулевого указателя обычно вызывает ошибку времени выполнения.

int val =1;
int *p = NULL;
*p = val; // Whooosh!!!! 

Ответ 5

Цитата из wikipedia:

Указатель ссылается на местоположение в памяти и получения значения на местоположение, на которое ссылается указатель как разыменование указателя.

Выделение происходит путем применения оператора unary * к указателю.

int x = 5;
int * p;      // pointer declaration
p = &x;       // pointer assignment
*p = 7;       // pointer dereferencing, example 1
int y = *p;   // pointer dereferencing, example 2

"Разыменование указателя NULL" означает выполнение *p, когда p равно NULL