Для чего используются нулевые указатели

Я только начал использовать С++ и увидел, что это нулевое значение для указателей. Мне интересно, для чего это используется. Кажется, что было бы бессмысленно добавлять указатель, указывающий на ничто.


person ineedalife    schedule 14.03.2018    source источник
comment
Что говорится по этой теме в вашей книге по C++?   -  person Algirdas Preidžius    schedule 14.03.2018
comment
Это ошибка Тони Хоара на миллиард долларов. Справочная информация: en.wikipedia.org/wiki/Sentinel_value   -  person Hans Passant    schedule 14.03.2018
comment
Куда указывает указатель, прежде чем ему будет на что указывать?   -  person tadman    schedule 14.03.2018
comment
@tadman, за исключением того, что нулевой указатель ни на что не указывает. Он указывает на абсолютный адрес 0. Это обычно недоступно, поэтому вызывает ошибку.   -  person Charlie Martin    schedule 14.03.2018
comment
@CharlieMartin Это незначительная деталь реализации, хотя она верна на многих машинах.   -  person Deduplicator    schedule 14.03.2018
comment
@tadman указывает на то, с чего он был инициализирован, или на что-то случайное   -  person UKMonkey    schedule 14.03.2018
comment
@CharlieMartin Технически говоря, UB разыменовывает nullptr, а не вызывает ошибку.   -  person Algirdas Preidžius    schedule 14.03.2018
comment
@CharlieMartin Это зависит от вашей платформы, у некоторых нет защиты памяти, но вы правы в том, что это не ничего, но и не что-то, так как в nullptr это не присвоенное значение типа.   -  person tadman    schedule 14.03.2018
comment
@UKMonkey Я спрашивал риторически, так как часто люди инициализируют их с помощью nullptr до тех пор, пока не появится фактическое значение для присвоения.   -  person tadman    schedule 14.03.2018
comment
@tadman На этот случай есть std:: optional. (Но я придираюсь)   -  person UKMonkey    schedule 14.03.2018
comment
@UKMonkey Это один из подарков, которые C++17 принес на вечеринку, но люди десятилетиями обходились без него. Если у вас есть класс с указателем, вам нужно чем-то инициализировать это значение, и если у вас нет цели, nullptr лучше, чем ничего, так как позже вы можете проверить, присвоено ли оно или нет, вместо того, чтобы не знать.   -  person tadman    schedule 14.03.2018
comment
@tadman выжил? до сих пор выживает! Сколько существует кода С++, использующего С++ 17? 0,1% может? Вероятно, все еще на порядок или два меньше! ;)   -  person UKMonkey    schedule 14.03.2018
comment
@AlgirdasPreidžius С технической точки зрения, отнесение к nullptr четко определено.   -  person Passer By    schedule 14.03.2018
comment
@PasserBy Как так? Укажите номер раздела стандарта C++, где это указано.   -  person Algirdas Preidžius    schedule 14.03.2018
comment
@AlgirdasPreidžius У меня нет книги, я смотрел учебные пособия и читал некоторые pdf-файлы. У меня нет денег, чтобы пойти на курсы или что-то в этом роде.   -  person ineedalife    schedule 14.03.2018
comment
У меня нет книги, я смотрю учебники. Ты делаешь это неправильно. Прекратите смотреть учебники и получите книгу.   -  person n. 1.8e9-where's-my-share m.    schedule 14.03.2018
comment
@AlgirdasPreidžius stackoverflow.com/a/28483256/4832499   -  person Passer By    schedule 14.03.2018
comment
Поиск в Google точного названия вашего вопроса может дать некоторую информацию.   -  person Jabberwocky    schedule 14.03.2018
comment
@PasserBy Ха, мило. Спасибо за ссылку.   -  person HolyBlackCat    schedule 14.03.2018
comment
Кажется, было бы бессмысленно добавлять указатель, указывающий ни на что. Очень нравится.   -  person Lightness Races in Orbit    schedule 14.03.2018


Ответы (5)


Что ж, значение нулевого указателя имеет замечательное свойство: несмотря на то, что оно является четко определенным и уникальным постоянным значением, точное значение зависит от машинной архитектуры и ABI (на большинстве современных все биты-ноль, не то, чтобы это имело значение) , он никогда не указывает на объект (или сразу за ним).

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

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

person Deduplicator    schedule 14.03.2018
comment
Этот ответ на самом деле неверен. См. ниже, согласно стандарту, нулевой указатель всегда имеет значение 0. - person Charlie Martin; 15.03.2018
comment
@CharlieMartin: Нет. В нем говорится, что литерал 0 (и некоторые связанные с ним вещи) преобразуется в значение null ponter в контексте указателя, а это нечто совершенно другое. Дьявол кроется в деталях. - person Deduplicator; 15.03.2018

Кажется, что было бы бессмысленно добавлять указатель, указывающий на ничто.

Нет это не так. Предположим, у вас есть функция, возвращающая необязательное динамически выделяемое значение. Когда вы хотите вернуть «ничего», вы возвращаете ноль. Вызывающий может проверить значение null и различать два разных случая: когда возвращаемое значение равно "ничего" и когда возвращаемое значение является допустимым пригодным для использования объектом.

person ks1322    schedule 14.03.2018

Как правило, это заполнитель. Если вы просто объявите указатель int *a;, нет гарантии, что находится в указателе, когда вы захотите получить к нему доступ. Поэтому, если ваш код может или не может установить указатель позже, нет никакого способа определить, является ли указатель действительным или просто указывает на мусорную память. Но если вы объявите его как NULL, например int *a = NULL;, вы сможете позже проверить, был ли установлен указатель, например if(a == NULL).

Большую часть времени во время инициализации мы присваиваем нулевое значение указателю, чтобы мы могли проверить, является ли он все еще нулевым или ему был назначен адрес или нет.

person Yserbius    schedule 14.03.2018
comment
В C++ это nullptr. - person tadman; 14.03.2018
comment
@tadman: Если вы ограничите это землей C ++ 11+, это достаточно верно, хотя и не совсем полная картина. Было бы лучше, если бы они просто укусили пулю и взяли null. - person Deduplicator; 14.03.2018
comment
@Deduplicator У всех нас есть надежды и мечты, которые в конечном итоге рушатся из-за C ++ TR. - person tadman; 14.03.2018

null значение в C и C++ равно 0. Но nullptr в C++ отличается от него, nullptr всегда является типом указателя в C++. Мы присваиваем нулевое значение переменной-указателю по разным причинам.

  1. Чтобы проверить, была ли выделена память для указателя или нет
  2. Чтобы нейтрализовать висячий указатель, чтобы он не создавал никаких побочных эффектов
  3. Чтобы проверить, является ли обратный адрес действительным адресом или нет и т. д.

Большую часть времени во время инициализации мы присваиваем нулевое значение указателю, чтобы мы могли проверить, является ли он все еще нулевым или ему был назначен адрес или нет.

person Abhijit Pritam Dutta    schedule 14.03.2018
comment
Но nullptr в C++ отличается от него. Это звучит неправильно. Можете ли вы уточнить? - person HolyBlackCat; 14.03.2018
comment
nullptr всегда является типом указателя в C++ На самом деле тип nullptr не является типом указателя. *nullptr неправильно сформирован. - person eerorika; 14.03.2018

По сути, указатели — это просто целые числа. Нулевой указатель — это указатель со значением 0. Он не указывает строго ни на что, он указывает на абсолютный адрес 0, который обычно недоступен для вашей программы; разыменование вызывает ошибку.

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

Обновление:

Кажется, многие люди сбиты с толку этим ответом, который, строго говоря, совершенно правильный. См. C11(ISO/IEC 9899:201x) §6.3.2.3 Указатели Раздел 3:

Целое константное выражение со значением 0 или такое выражение, приведенное к типу void *, называется константой нулевого указателя. Если константа нулевого указателя преобразуется в тип указателя, результирующий указатель, называемый нулевым указателем, гарантированно будет сравниваться с неравным указателю на любой объект или функцию.

Итак, что такое адрес? Это число n, где 0 ≤ nmax_address. И как представить такое число? Да ведь это целое число, как и говорит стандарт.

Стандарт C11 ясно дает понять, что по адресу 0 никогда не на что ссылаться, потому что в каком-то старом патологически непереносимом коде в BSD 4.2 вы часто видели такой код:

/* DON'T TRY THIS AT HOME */

int
main(){
    char target[100] ;
    char * tp = &target ;
    char * src = "This won't do what you think." ;
    void exit(int);

    while((*tp++ = *src++))
        ;

    exit(0);
}

Это все еще действует C:

$ gcc -o dumb dumb.c
dumb.c:6:12: warning: incompatible pointer types initializing 'char *' with an
      expression of type 'char (*)[100]' [-Wincompatible-pointer-types]
    char * tp = &target ;
           ^    ~~~~~~~
1 warning generated.
$ 

В 4.2BSD на VAX такая чепуха могла сойти с рук, потому что адрес 0 надежно содержал значение 0, поэтому присваивание оценивалось как 0, что, конечно же, ЛОЖЬ.

Теперь для демонстрации:

/* Very simple program dereferencing a NULL pointer. */

int
main() {
    int * a_pointer ;
    int a_value ;
    void exit(int);             /* To avoid any #includes */

    a_pointer = ((void*)0);
    a_value = *a_pointer ;

    exit(0);
}

Вот результаты:

$ gcc -o null null.c
$ ./null
Segmentation fault: 11
$ 
person Charlie Martin    schedule 14.03.2018
comment
Этот ответ делает много предположений о задействованной архитектуре. - person tadman; 14.03.2018
comment
Это действительно так (более или менее), но это не так со стандартной точки зрения. - person HolyBlackCat; 14.03.2018
comment
@HolyBlackCat Действительно так оно и работает Обычно.. Из-за UB-характера такого действия (разыменование nullptr) иногда можно вызвать метод, который не использует какие-либо переменные-члены, по указателю nullptr class. - person Algirdas Preidžius; 14.03.2018
comment
@н.м. однако первое предложение не является полностью неправильным. - person Jabberwocky; 14.03.2018
comment
@н.м. Бред какой то. Что, по-вашему, представляет собой указатель в C? Адрес, верно? Что такое адрес? Натуральное число n, где 0 ≤ n ≤ максимальный адрес. Что такое нулевой указатель? это адрес со значением 0. Я имею в виду, вы можете найти его: C11(ISO/IEC 9899:201x) §6.3.2.3 Указатели Раздел 3 - person Charlie Martin; 15.03.2018
comment
Некоторые архитектуры могут определять адрес как натуральное число, но язык C этого не делает. В нем говорится, что указатель может быть преобразован в целое число и из него, но это не делает его целым числом. Некоторые архитектуры могут определять нулевой указатель как адрес со значением 0, но язык C этого не делает. Не путайте константу нулевого указателя с представлением нулевого указателя, это две разные вещи. Нулевой указатель вполне может быть представлен значением 0xFFFFFFFF во время выполнения. Я видел такие платформы. - person n. 1.8e9-where's-my-share m.; 15.03.2018
comment
@n.m: Ты просто ведешь себя глупо. Представьте мне пример платформы, в которой машинные адреса не являются натуральными числами. Точно так же представьте мне платформу, на которой, ПРОТИВ СТАНДАРТА, нулевой указатель не представлен как значение 0. - person Charlie Martin; 16.03.2018
comment
(1) Вы когда-нибудь слышали о компьютерах на базе 8086? Раньше у них была сегментированная память. Адрес представляет собой пару целых чисел, сегмент и смещение. (2) Стандарт никогда не говорит, как должен быть представлен null. Вы можете найти цитату об обратном (константа нулевого указателя не имеет ничего общего с представлением нулевого значения во время выполнения). См. c-faq.com/null/machexamp.html. Все это забито до смерти здесь и в других местах. - person n. 1.8e9-where's-my-share m.; 16.03.2018
comment
@н.м. Конечно, сегмент+смещение не является натуральным числом. Спорим, - person Charlie Martin; 17.03.2018