Нульовий вказівник: відмінності між версіями

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку
[неперевірена версія][перевірена версія]
Вилучено вміст Додано вміст
GreenTree96 (обговорення | внесок)
Скасування редагування № 16147133 користувача GreenTree96 (обговорення)
Немає опису редагування
 
(Не показані 28 проміжних версій 13 користувачів)
Рядок 1: Рядок 1:
{{Otheruses|NULL}}
{{Otheruses|NULL}}
'''Нульовий (порожній) покажчик''' або нульовий вказівник — [[Вказівник|покажчик]], який нікуди не вказує. Використовується для того, щоб показати, що дана змінна-вказівник ні на що не посилається. У різних мовах програмування представлений різними [[константа]]ми, наприклад:
'''Нульовий (порожній) вказівник''' (рідше — покажчик) — [[вказівник]], який нікуди не вказує. Використовується для того, щоб показати, що дана змінна-вказівник ні на що не посилається. У різних мовах програмування представлений різними [[константа]]ми, наприклад:


* У [[Машинний код|машинних кодах]]: '''0'''
* У [[Машинний код|машинних кодах]]: '''0'''
* У мовах [[Pascal]], [[Clipper]], [[Modula 2]], [[Ruby]], [[Lua]] : '''nil'''
* У мовах [[Pascal]], [[Clipper]], [[Modula 2]], [[Ruby]], [[Lua]] : '''[[nil]]'''
* У [[C (мова програмування)|C]]-подібних мовах: '''NULL'''
* У [[C (мова програмування)|C]]-подібних мовах: [[NULL (C)|'''NULL''']]
* У мовах [[Java]] та [[C Sharp|C#]]: '''null'''
* У мовах [[Java]] та [[C Sharp|C#]]: '''null'''
* У мові [[Icon (мова програмування)|Icon]]: '''&null'''
* У мові [[Icon (мова програмування)|Icon]]: '''&null'''
Рядок 10: Рядок 10:
* У мові [[Visual Basic]]: '''Nothing'''
* У мові [[Visual Basic]]: '''Nothing'''


[[Тоні Гоар]], який винайшов нульовий вказівник у 1965 році, вважає це помилкою, яка імовірно коштувала мільярди доларів, оскільки спроба розіменування нульового вказівника зазвичай приводить до збою й припинення роботи програми
[[Тоні Гоар]], який винайшов нульовий вказівник у 1965 році, вважає це помилкою, яка імовірно коштувала мільярди доларів, оскільки спроба розіменування нульового вказівника зазвичай приводить до збою й припинення роботи програми<ref>{{Cite web |url=http://qconlondon.com/london-2009/presentation/Null+References:+The+Billion+Dollar+Mistake |title=Tony Hoare. Null References: The Billion Dollar Mistake |accessdate=23 жовтня 2010 |archiveurl=https://web.archive.org/web/20090119110704/http://qconlondon.com/london-2009/presentation/Null+References%3A+The+Billion+Dollar+Mistake |archivedate=19 січня 2009 |deadurl=yes }}</ref>.
<ref>[http://qconlondon.com/london-2009/presentation/Null+References:+The+Billion+Dollar+Mistake Tony Hoare. Null References: The Billion Dollar Mistake]</ref>.


== Особливості використання в різних мовах ==
== Особливості використання в різних мовах ==

[[ANSI C]] гарантує, що значення ''NULL'' еквівалентне 0, тому записи
=== C та C++ ===
<code|C>
{{Main|NULL (C)|C (мова програмування)|C++|Помилка сегментації}}

Макрос <code>NULL</code> визначено у файлі <code>&lt;stddef.h&gt;</code>.

[[ANSI C]] гарантує, що значення ''NULL'' еквівалентне 0, тому записи
<syntaxhighlight lang=C>
int *a, *b;
int *a, *b;
a = NULL;
a = NULL;
b = 0;
b = 0;
</syntaxhighlight>
</code>
еквівалентні&nbsp;— вказівники a та b отримають однакове значення.
еквівалентні&nbsp;— вказівники a та b отримають однакове значення.


На відміну від C в Паскалі, який є дуже суворим щодо типів, ''Nil'' в жодному випадку не еквівалентний числу 0.
На відміну від C в Паскалі, який є дуже суворим щодо типів, ''Nil'' в жодному випадку не еквівалентний числу 0.
<!--
<!--
В будь-якому випадку вказівник, який має значення NULL не можна розіменовувати. Наприклад, якщо після приведеного вище коду виконати присвоєння
У будь-якому випадку вказівник, який має значення NULL не можна розіменовувати. Наприклад, якщо після приведеного вище коду виконати присвоєння
<code|C>
<code|C>
*a = 1;
*a = 1;
</code>,
</code>,
то результатом буде [[core dump]]&nbsp;— програма вилетить. -->
то результатом буде [[core dump]]&nbsp;— програма вилетить. -->

=== Java ===
{{Main|Java}}

Мова програмування [[Java]] використовує <code>null</code> для позначення порожнього посилання. Також мова визначає так званий тип даних null. При спробі використання <code>null</code> замість реального об'єкта [[Віртуальна машина Java|віртуальна машина]] створює [[Обробка винятків|виняткову подію]] типу <code>java.lang.NullPointerException</code>. Зокрема, ця подія виникає при:
* виклику динамічного [[Метод (програмування)|метода]] об'єкта <code>null</code>.
* доступі або зміні поля об'єкта <code>null</code>.
* обчисленні довжини об'єкта <code>null</code> наче він є масивом.
* доступі або зміні комірок об'єкта <code>null</code> наче він є масивом.
* створенні виняткової ситуації з об'єктом <code>null</code> замість об'єкта типу <code>Throwable</code>.

Додатки також можуть створювати виняткові ситуації типу <code>NullPointerException</code> за інших невірних використаннях об'єктів типу <code>null</code><ref>{{cite web
| url = https://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
| title = Class NullPointerException
| publisher = Oracle
| work = Java™ Platform Standard Ed. 8. API Specification
| date = 2016 }}</ref>.

З огляду на численні проблеми, спричинені неправильною обробкою об'єктів <code>null</code> та досвіду використання деяких інших мов програмування в бібліотеці стандартних класів Java SE 8 версії був доданий [[Контейнер (програмування)|контейнер]] <code>Optional&lt;T&gt;</code>. Об'єкти даного класу можуть містити значення типу <code>null</code>. Якщо контейнер містить непорожнє значення, тоді метод <code>isPresent()</code> поверне <code>true</code> а метод <code>get()</code> поверне це значення. Також цей контейнер пропонує низку додаткових методів, поведінка яких залежить від наявності непорожнього значення. Наприклад, метод <code>orElse()</code> повертає значення за замовченням при відсутності даних в контейнері, <code>ifPresent()</code> виконує блок коду за умови наявності даних в контейнері<ref>{{cite web
| url = https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
| title = Class Optional<T>
| publisher = Oracle
| work = Java™ Platform Standard Ed. 8. API Specification
| date = 2016 }}</ref>.

Наприклад, якщо комп'ютер не має звукової карти і метод <code>getSoundcard()</code> повертає <code>null</code>, то при виконанні наступного коду:
<syntaxhighlight lang="java">
String version = computer.getSoundcard().getUSB().getVersion();
</syntaxhighlight>
виникне виняткова ситуація типу <code>NullPointerException</code> при спробі викликати метод <code>getUSB()</code>. Проте, засобами контейнеру <code>Optional&lt;T&gt;</code> цей код може бути перетворений на безпечніший (після відповідного рефакторингу залучених типів даних):
<syntaxhighlight lang="java">
String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
</syntaxhighlight>
унаслідок виконання якого змінна <code>version</code> матиме значення «UNKNOWN» за відсутності звукової карти<ref>{{cite web
| url = http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
| title = Tired of Null Pointer Exceptions? Consider Using Java SE 8's Optional!
| author = Raoul-Gabriel Urma
| date = March 2014
| publisher = Oracle Technology Network }}</ref>.


== Примітки ==
== Примітки ==
{{reflist}}
{{reflist}}


== Див. також ==
{{мова програмування-доробити}}
* [[Вказівник]]
* [[Невизначена поведінка]]


== Посилання ==
* [http://cwe.mitre.org/data/definitions/476.html CWE-476]: NULL Pointer Dereference
* Quora: [https://www.quora.com/What-actually-happens-when-dereferencing-a-NULL-pointer What actually happens when dereferencing a NULL pointer?]


{{Типи даних}}
{{ВП-портали|Програмування}}
{{мова програмування-доробити}}
[[Категорія:Програмування]]
[[Категорія:Програмування]]
[[Категорія:Ніщо]]
[[Категорія:Типи даних]]
[[Категорія:Статті з прикладами коду мовою C]]
[[Категорія:Статті з прикладами коду мовою Java]]

Поточна версія на 12:56, 2 квітня 2022

Нульовий (порожній) вказівник (рідше — покажчик) — вказівник, який нікуди не вказує. Використовується для того, щоб показати, що дана змінна-вказівник ні на що не посилається. У різних мовах програмування представлений різними константами, наприклад:

Тоні Гоар, який винайшов нульовий вказівник у 1965 році, вважає це помилкою, яка імовірно коштувала мільярди доларів, оскільки спроба розіменування нульового вказівника зазвичай приводить до збою й припинення роботи програми[1].

Особливості використання в різних мовах

[ред. | ред. код]

C та C++

[ред. | ред. код]

Макрос NULL визначено у файлі <stddef.h>.

ANSI C гарантує, що значення NULL еквівалентне 0, тому записи

  int *a, *b; 
  a = NULL;
  b = 0;

еквівалентні — вказівники a та b отримають однакове значення.

На відміну від C в Паскалі, який є дуже суворим щодо типів, Nil в жодному випадку не еквівалентний числу 0.

Докладніше: Java

Мова програмування Java використовує null для позначення порожнього посилання. Також мова визначає так званий тип даних null. При спробі використання null замість реального об'єкта віртуальна машина створює виняткову подію типу java.lang.NullPointerException. Зокрема, ця подія виникає при:

  • виклику динамічного метода об'єкта null.
  • доступі або зміні поля об'єкта null.
  • обчисленні довжини об'єкта null наче він є масивом.
  • доступі або зміні комірок об'єкта null наче він є масивом.
  • створенні виняткової ситуації з об'єктом null замість об'єкта типу Throwable.

Додатки також можуть створювати виняткові ситуації типу NullPointerException за інших невірних використаннях об'єктів типу null[2].

З огляду на численні проблеми, спричинені неправильною обробкою об'єктів null та досвіду використання деяких інших мов програмування в бібліотеці стандартних класів Java SE 8 версії був доданий контейнер Optional<T>. Об'єкти даного класу можуть містити значення типу null. Якщо контейнер містить непорожнє значення, тоді метод isPresent() поверне true а метод get() поверне це значення. Також цей контейнер пропонує низку додаткових методів, поведінка яких залежить від наявності непорожнього значення. Наприклад, метод orElse() повертає значення за замовченням при відсутності даних в контейнері, ifPresent() виконує блок коду за умови наявності даних в контейнері[3].

Наприклад, якщо комп'ютер не має звукової карти і метод getSoundcard() повертає null, то при виконанні наступного коду:

String version = computer.getSoundcard().getUSB().getVersion();

виникне виняткова ситуація типу NullPointerException при спробі викликати метод getUSB(). Проте, засобами контейнеру Optional<T> цей код може бути перетворений на безпечніший (після відповідного рефакторингу залучених типів даних):

String version = computer.flatMap(Computer::getSoundcard)
                   .flatMap(Soundcard::getUSB)
                   .map(USB::getVersion)
                   .orElse("UNKNOWN");

унаслідок виконання якого змінна version матиме значення «UNKNOWN» за відсутності звукової карти[4].

Примітки

[ред. | ред. код]
  1. Tony Hoare. Null References: The Billion Dollar Mistake. Архів оригіналу за 19 січня 2009. Процитовано 23 жовтня 2010.
  2. Class NullPointerException. Java™ Platform Standard Ed. 8. API Specification. Oracle. 2016.
  3. Class Optional<T>. Java™ Platform Standard Ed. 8. API Specification. Oracle. 2016.
  4. Raoul-Gabriel Urma (March 2014). Tired of Null Pointer Exceptions? Consider Using Java SE 8's Optional!. Oracle Technology Network.

Див. також

[ред. | ред. код]

Посилання

[ред. | ред. код]