Является ли (p == NULL) тем же, что и (*p == 0) в C++?

Мой код на C++ имеет следующее:

 if (p == NULL || *p == 0)

Интересно, это лишнее?

(p == NULL) — это то же самое, что (*p == 0)? Почему или почему нет?

Нет, это не то же самое.p == NULL проверяет адрес, хранящийся в указателе. *p == 0 разыменовывает указатель и проверяет, на что он указывает.

wohlstad 25.06.2024 12:48

Выражение *p в точности равно p[0]. Итак, *p == 0 проверяет, равен ли первый элемент p нулю.

Some programmer dude 25.06.2024 12:49

Никто не проверяет, является ли указатель нулевым, в то время как другой проверяет, является ли указанное значение нулевым или нет. Хорошая книга по C++

user12002570 25.06.2024 12:49

Также обратите внимание, что порядок имеет значение. Если p является нулевым указателем, его нельзя разыменовать (это приводит к неопределенному поведению). А логический оператор ИЛИ || использует сокращенную оценку , что означает, что если p == NULL истинно, то *p == 0 не будет оцениваться.

Some programmer dude 25.06.2024 12:52

С другой стороны, NULL — это макрос, который обычно расширяется до 0 и сохраняется для обратной совместимости с C. В C++ действительно следует использовать nullptr.

Some programmer dude 25.06.2024 12:53

Видите звездочку *? Если да, то почему вы думаете, что оба сравнения одинаковы.

i486 25.06.2024 12:58
p подскажет, где что находится; *p расскажет вам, что это за штука. Вы знаете разницу между тем, где вы находитесь, и тем, кто вы есть.
molbdnilo 25.06.2024 13:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
7
180
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Является ли (p == NULL) тем же, что и (*p == 0) в C++?

Нет, они не одинаковы.

Первый p == NULL проверяет, является ли указатель p нулевым или нет.

Последний *p==0 проверяет, является ли значение, на которое указывает указатель p, нулевым или нет. Это потому, что *p эквивалентно p[0], что дает нам указанное значение.


Обратите внимание, что в современном C++ следует использовать nullptr вместо NULL.

Эти 2 не одинаковы.

  • Выражение p == NULL проверяет адрес, хранящийся в самом указателе. Это правда, если адрес NULL.

  • Выражение *p == 0 разыменовывает указатель и проверяет, на что он указывает (обратите внимание, что *p эквивалентно p[0]). Это правда, если указатель указывает на значение 0.

Размещенный вами код вполне типичен, когда вы хотите проверить, указывает ли указатель на 0 или любое другое значение. Это связано с тем, что вам необходимо проверить, что указатель содержит действительный (не нулевой) адрес (если вы не уверены в этом), прежде чем проверять, на что он указывает. Разыменование нулевого указателя вызывает UB (Неопределённое поведение).

Примечание:
NULL — это наследие C. Фактически, это макрос, определенный как 0. В C++ указатель лучше сравнивать с nullptr.

@RemyLebeau спасибо за исправления опечаток и т. д. Однако «iff» не было опечаткой — я имел в виду если-и-только-если. Но, возможно, использование обычного «если» не сбивает с толку.

wohlstad 25.06.2024 17:07
Ответ принят как подходящий

p == whatever сравнивает значение p с чем угодно.

*p == whatever разыменовывает p и сравнивает указатель с whatever.


Если p является нулевым указателем, его разыменование не определено.

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


Они одинаковы? Нет.

Почему? Потому что значение указателя не является значением указателя.


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

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

Если p является указателем, его можно сравнить с NULL или nullptr, что обычно означает, что указатель инициализирован, но еще не установлен для указания на какие-либо данные.

*p — это разыменование, то есть доступ к содержимому указанного адреса. Это можно сделать только с указателями, указывающими на действительные данные: разыменование нулевого указателя вызывает неопределенное поведение.

Следовательно, если мы хотим проверить, является ли какое-либо содержимое данных, доступ к которому осуществляется через указатель, 0, но мы не уверены, указывает ли указатель на какое-либо значимое место, нам придется проверить, является ли это нулевым указателем, прежде чем обращаться к нему.

Самый простой и понятный способ сделать это:

if (p != NULL)
{
  if (*p == 0)
  {
    // do stuff
  }
}

Однако это также можно переписать как 100% эквивалентное логическое выражение if (p == NULL || *p == 0).

Это происходит из-за так называемой «короткой оценки» операторов && и ||. В отличие от большинства операторов в C++, эти два имеют четко определенный порядок вычислений слева направо, поэтому p==NULL гарантированно будет вычисляться раньше *p == 0.

Кроме того, также гарантируется, что если результат оператора можно получить после вычисления только левого, то правый не будет оцениваться. То есть в случае 0 && x или 1 || x нам не нужно заботиться о том, что может оценивать правильный операнд, поскольку независимо от значения правильного операнда результат в конечном итоге будет иметь значение false или true соответственно.

Таким образом, в случае вычисления p == NULL до true нам не нужно вычислять *p == 0, чтобы знать, что результатом || будет true. Это делает эти логические выражения похожими на операторы if. Мы будем точно знать, что p не является нулевым указателем, когда *p == 0 будет выполнено.

Другие вопросы по теме