Открыть главное меню

NULL в языках программирования Си и C++ — макрос, объявленный в заголовочном файле stddef.h (и других заголовочных файлах). Значением этого макроса является зависящая от реализации константа нулевого указателя (англ. null pointer constant).

Константа нулевого указателя — это целочисленное константное выражение со значением 0 или (только в Си) такое же выражение, но приведённое к типу void*. Константа нулевого указателя, приведённая к любому типу указателей, является нулевым указателем. Гарантируется, что нулевой указатель не равен указателю на любой объект (в широком смысле слова, любые данные) или функцию. Гарантируется, что любые два нулевых указателя равны между собой. Разыменовывание нулевого указателя является операцией с неопределённым поведением.

Иначе говоря, реализация предоставляет специальное значение — константу нулевого указателя, которую можно присвоить любому указателю и такой указатель при сравнении не будет равен любому «корректному» указателю. То есть, можно считать, что нулевой указатель не содержит корректного адреса в памяти.

ИспользованиеПравить

Нулевые указатели придуманы как удобный способ «отметить» указатели, которые заведомо не указывают на корректный адрес в памяти. Например, при объявлении указателя как автоматической переменной его значение не определено. Чтобы отметить, что этот указатель ещё не содержит корректный адрес в памяти, такому указателю присваивают константу нулевого указателя:

void f(void)
{
  int *x = NULL;
  /* ... */
}

Хорошим стилем программирования является присваивание указателю после освобождения памяти, на которую он ссылался, нулевого указателя. Кроме этого, применение обнуления указателей актуально для безопасности освобождения памяти: операция delete в C++ (free в Си) безопасна для нулевого указателя. Например:

TYPE *foo = new TYPE();
//использование foo
delete foo;// foo != NULL
//некоторый код программы
delete foo;//ОШИБКА! память уже недоступна

в то время как в таком варианте ошибки не будет

TYPE *foo = new TYPE();
//использование foo
delete foo;// foo != NULL
foo = NULL;// foo == NULL
//некоторый код программы
delete foo;//ошибки нет: delete проверяет значение foo

Разыменовывание нулевых указателейПравить

Разыменовывание нулевого указателя является операцией с неопределённым поведением. На реализацию не накладывается никаких ограничений: может произойти, например, обращение к памяти, не предназначенной для использования данной программой (то есть при чтении будет считан «мусор», а при записи — значение будет записано в область памяти, не принадлежащую программе). Например, в DOS запись по нулевому адресу затрёт как минимум нулевой вектор прерываний, так что следующий вызов int 0 приведёт, скорее всего, к зависанию системы. Однако чаще всего это приводит к ошибке времени выполнения (если в операционной системе реализована защита памяти и доступ в невыделенную процессу память блокируется). Например, в Windows 9x сообщение «Общая ошибка защиты» — «Программа выполнила недопустимую операцию и будет закрыта» (англ. general protection fault, GPF) выдаётся чаще всего в тех случаях, когда программа обращается в память по некорректному (в том числе неинициализированному или уже освобождённому) указателю. В Unix-подобных операционных системах в таких ситуациях процесс получает сигнал SIGSEGV и его обработчик выводит сообщение «Segmentation fault».

Нулевые указатели в C++Править

Если брать конкретную реализацию NULL по исходным файлам, то он может быть определен как (void*)0 или как 0. Использование NULL в проектах на языке C++ может приводить к ошибкам. Например

int (ClassName::*pf)() = NULL;

приведет к ошибке компиляции в случае, если NULL определен как (void*)0 (например опосредованно был включен заголовок, где стандартное для C++ определение NULL перекрывается). Поэтому в программах на C++ не рекомендуется использовать NULL. В стандарте C++11 для обозначения нулевого указателя добавлено новое ключевое слово nullptr[1][2].

См. такжеПравить

ПримечанияПравить

  1. JTC1/SC22/WG21 — The C++ Standards Committee. SC22/WG21/N2431 = J16/07-0301 «A name for the null pointer: nullptr» (англ.) (PDF). JTC1.22.32. The C++ Standards Committee (2 October 2007). Дата обращения 4 октября 2010. Архивировано 11 февраля 2012 года. (англ.)
  2. Scott Meyers, Summary of C++11 Feature Availability in gcc and MSVC, 16 August 2011

СсылкиПравить