Что такое указатель void и что такое указатель null?

Я задавал несколько вопросов на собеседовании и наткнулся на один о пустых и нулевых указателях, который утверждает:

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

Это меня полностью запутало! Кажется, что void и null могут использоваться как взаимозаменяемые в соответствии с этим вопросом, и я не считаю, что это правильно. Я предположил, что void является возвращаемым типом, а null - значением. Но я всего лишь новичок в программировании и не уверен, что прав.

Пожалуйста, выскажите свое мнение о том, что такое нулевой указатель и что такое пустой указатель. Я не ищу разницы между недействительным и недействительным.


person Shouvik    schedule 02.12.2010    source источник
comment
Это плохой ответ на плохой вопрос и не имеет отношения к CSS. Не обращайте на это внимания и двигайтесь дальше.   -  person CB Bailey    schedule 02.12.2010
comment
Lol на самом деле CSS - это компания: P   -  person Shouvik    schedule 02.12.2010
comment
Это компания, которая дает худший ответ на глупый вопрос интервьюера, который я когда-либо видел.   -  person Nicol Bolas    schedule 16.12.2011


Ответы (9)


Эти два понятия ортогональны:

  1. Пустой указатель (void *) - это необработанный указатель на некоторую ячейку памяти.
  2. Нулевой указатель - это специальный указатель, который по определению ни на что не указывает. Это может быть указатель на любой тип, void или иное.

Указатель void может быть нулевым или нет:

void *void_ptr1 = nullptr;
void *void_ptr2 = malloc(42);
void *void_ptr3 = new Foo;               // void * can point to almost anything
void *void_ptr4 = (char*)void_ptr3 + 1;  // even somewhere inside an object

Непустой указатель также может быть нулевым или нет:

Foo *f = nullptr;
Foo *g = new Foo;
person Marcelo Cantos    schedule 02.12.2010
comment
не могли бы вы привести пример? Вы говорите как указатель на функцию void или что-то в этом роде? Я новичок, так что пойму лучше, если бы вы могли немного уточнить :) - person Shouvik; 02.12.2010
comment
Тип void * просто означает указатель на память; Я не знаю, какие там данные. Любой нормальный указатель (int *, char *, MyStruct *) неявно может быть приведен к void *; это архетипический кусочек памяти. - person Chowlett; 02.12.2010
comment
@Chowlett: Да, я был немного неосторожен в своем описании. Изменен. - person Marcelo Cantos; 02.12.2010

Просто забудьте об этом ответе. Цитата из вашей ссылки:

«указатель без возвращаемого типа называется нулевым указателем».

Это ооочень просто НЕПРАВИЛЬНО. возвращаемый тип указателя? В САМОМ ДЕЛЕ? Это плохой источник ...

void* является универсальным указателем тип, потому что любой тип указателя (кроме указателя на const и / или volatile) может быть неявно преобразован в void*. Другими словами, вы можете присвоить любой указатель переменной типа void*. Нулевой указатель - это указатель значение 0

person Armen Tsirunyan    schedule 02.12.2010
comment
Спасибо, я так много угадала ... Придерживаюсь этого сейчас просто за вопросы ... :) - person Shouvik; 02.12.2010
comment
На самом деле нулевой указатель может не иметь значения «0», хотя я никогда не видел для него другого значения. На некоторых странных платформах 0 может быть допустимым значением указателя. - person Gianni; 02.12.2010
comment
@Gianni да, вы правы, и я рад, что эта информация может соответствовать моему ответу в форме вашего комментария - person Armen Tsirunyan; 02.12.2010
comment
это не объясняет разницу, которую ищет OP - person Chubsdad; 02.12.2010
comment
@ Джанни: да, и знаю. Хотя базовое представление (байты) нулевого указателя зависит от реализации, 0 представляет нулевой указатель на языке C ++. Компилятор должен сгенерировать соответствующий код, когда 0 следует рассматривать как указатель и создать правильное базовое представление в зависимости от реализации. - person Matthieu M.; 02.12.2010
comment
@Matthieu Верно. Но дело было в значении «0». Это неоднозначно. Мне вообще-то не нравится эта часть стандарта C ++. С этого момента следует отказаться от использования nullptr. Но мы здесь только прищуриваем. Дело в том, что void - это тип, NULL - это значение. - person Gianni; 02.12.2010
comment
@Gianni: Я тоже предпочитаю nullptr, но в обозримом будущем я придерживаюсь gcc3.4 :) Я все равно проголосовал за Армена за его ответ. - person Matthieu M.; 02.12.2010

Тип void в целом означает, что информация о типе не указана.

Вы всегда должны помнить, что указатель передает две части информации: тип указанных данных (int, double, ...), который указывает, как их интерпретировать, и адрес данных, на которые он указывает, который указывает где можно получить фактическое значение указанных данных.

Информация о типе находится в типе указателя (double *, int *, ...), а адрес данных - это фактическое значение, содержащееся в указателе. Переменная.

Итак, указатель void (void *) - это указатель, который не указывает никакой информации о типе. Он сообщает вам, где находятся данные, но не говорит, как их интерпретировать. Вы знаете, что по этому адресу что-то есть, но вы не знаете, int, double или группа летающих коров. Чтобы действительно использовать такие данные, вы должны получить информацию о типе каким-либо другим способом (например, с помощью какого-либо другого магического параметра), привести этот указатель к обычному типу указателя и затем использовать его как обычно.

void * часто используется в C для поддержки общего программирования; см., например, функцию библиотеки qsort C .

Вместо этого указатель NULL - это указатель, который ни на что не указывает. В этом случае информация о типе указателя в целом присутствует, но отсутствует адрес указанных данных. Конечно, возможно иметь void *, то есть NULL.

Быстрый пример (предположим, что v объявлен как double v;):

                         Type information present
             +----------------------+----------------------+
             |          ✔           |          ✘           |
         +---+----------------------+----------------------+
    p  c |   |                      |                      |
 v  o  o | ✔ | double * ptr = &v;   | void * ptr = &v;     |
 a  i  n |   |                      |                      |
 l  n  t +---+----------------------+----------------------+
 i  t  e |   |                      |                      |
 d  e  n | ✘ | double * ptr = NULL; | void * ptr = NULL;   |
    d  t |   |                      |                      |
         +---+----------------------+----------------------+

Общая информация: NULL, по крайней мере, в текущем стандарте гарантированно равно 0.

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

person Matteo Italia    schedule 02.12.2010

Расскажите, пожалуйста: в чем разница:

  • между бензобаком и ситуацией отсутствия газа
  • между банкой для файлов cookie и без файлов cookie
  • между термином "деньги" и "пустые карманы"

Если вы их придумаете, вы сможете понять, что такое null vs void * dillema.

person Daniel Mošmondor    schedule 02.12.2010
comment
Я предполагаю, что путаница была подлинной, потому что вопрос ... SO должен был быть источником всего связанного с кодированием знаний, поэтому я подумал, что это будет уместный вопрос. извините, если вы считаете иначе ... - person Shouvik; 02.12.2010
comment
@Shouvik: Что ты имеешь в виду? Это как раз лучший ответ на ваш вопрос! В прямом смысле :) - person Armen Tsirunyan; 02.12.2010
comment
ммм, причина, как я уже упоминал, в том, что я не опытный программист и теперь меня интересует нечто большее, чем просто возможность собрать часть программы, но на самом деле понимать этот язык и его более тонкие аспекты. Но я вижу шутку в отсутствии сравнения между ними ... :) - person Shouvik; 02.12.2010
comment
lol, я понял ..: D Может быть, если вы поставите без бензобака, без банки для печенья и без пустых карманов, у меня будет схватил быстрее ... :) - person Shouvik; 02.12.2010

void не является типом. null не имеет значения.

person Nicolas Repiquet    schedule 02.12.2010
comment
Ага, я уже выразил эту разницу в вопросе .. Ищу разницу в указателе .. - person Shouvik; 02.12.2010
comment
void - это тип, а 0 или NULL - значение - person Armen Tsirunyan; 02.12.2010
comment
@armen: void - это тип, выражающий отсутствие типа. То же самое и с нулевым значением. - person Nicolas Repiquet; 02.12.2010

Вот некоторые отличия от арифметики указателей:

Это связано с тем, что void - это неполный тип.

void *vp;
vp++;     // error, incomplete type
vp += 2;  // same error

void *p = 0;
p++;      // still same error

int *p = 0;
p++;      // well-formed program, but UB ($5.6/5)
person Chubsdad    schedule 02.12.2010
comment
Так что в основном указатель void не годится, но это действительный фрагмент кода, да? - person Shouvik; 02.12.2010
comment
@Shouvik: Нет Нет. Иногда это очень хорошо, например, когда вы просто хотите передать его как непрозрачный дескриптор или что-то в этом роде и не раскрывать фактический тип, на который он указывает, или например если вы не хотите, чтобы вызываемая сущность выполняла какие-либо арифметические операции с указателями. Так что это зависит - person Chubsdad; 02.12.2010
comment
Ааа ладно .. Как в закрытии и прочем? - person Shouvik; 02.12.2010
comment
@Chubsdad: привет, почему твой последний экзамен с int ptr UB? можешь сказать? - person ; 13.07.2014

Связанная статья просто неверна. Его первое предложение:

указатель без возвращаемого типа называется нулевым указателем

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

Вы почти правы. «Указатель на void» - это тип (не «возвращаемый тип»). Значения любого типа могут возвращаться функциями и, таким образом, быть типом возвращаемого значения (функции).

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

Указатель на void также может быть нулевым;

void *nothing = 0;

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

person unwind    schedule 02.12.2010
comment
K спасибо за ваше подтверждение. bTW есть ли какое-либо конкретное использование указателя void? - person Shouvik; 02.12.2010
comment
@Shouvik Функция может принимать void* аргумент. Если вы знакомы с Java или C #, это примерно эквивалентно принятию Object. - person Pedro d'Aquino; 02.12.2010

void *ptr - это указатель, который можно использовать для указания любого типа данных. Это может быть int, float, double. Он не имеет возвращаемого типа, поскольку изначально указатель создается с типом указателя (имеющим шестнадцатеричное значение), и мы можем назначить этот указатель любому типу данных.

В то время как нулевой указатель - это указатель, адрес которого имеет значение NULL, указателю присваивается значение NULL, поэтому его нельзя использовать для доступа к другим данным, которые его адрес может содержать во время создания. Я считаю хорошей техникой программирования присвоить указателю NULL, если он в данный момент не используется.

person anurag tiwari    schedule 24.09.2016

нулевой указатель указывает на 0x000000 (что неверно для указателя доступа), в то время как указатель void является правильным указателем на неопределенный тип (void *). Однако указатель void может быть нулевым указателем, но тогда отсутствие ссылки на указатель приведет к ошибке.

person Vladimir Ivanov    schedule 02.12.2010
comment
Неправильно - это довольно расплывчатое прилагательное для указателей. NULL - допустимое значение для любого указателя, но нет объекта со значением указателя NULL. Кроме того, по вашей логике указатель void* не может иметь значение NULL, так как он будет как правильным, так и неправильным. Это явно неправда. - person MSalters; 02.12.2010