Выбрать главу

                // выводит 42

Обращение к значению указателя возвращает объект, на который указывает указатель. Присвоив значение результату оператора обращения к значению, можно присвоить его самому объекту.

*p = 0;     // * возвращает объект; присвоение нового значения

            // ival через указатель p

cout << *p; // выводит 0

При присвоении значения *p оно присваивается объекту, на который указывает указатель p.

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

Ключевая концепция. У некоторых символов есть несколько значений

Некоторые символы, такие как & и *, используются и как оператор в выражении, и как часть объявления. Контекст, в котором используется символ, определяет то, что он означает.

int i = 42;

int &r = i;   // & следует за типом в части объявления; r - ссылка

int *p;       // * следует за типом в части объявления; p - указатель

p = &i;       // & используется в выражении как оператор

              // обращения к адресу

*p = i;       // * используется в выражении как оператор

              // обращения к значению

int &r2 = *p; // & в части объявления; * - оператор обращения к значению

В объявлениях символы & и * используются для формирования составных типов. В выражениях эти же символы используются для обозначения оператора. Поскольку тот же символ используется в совершенно ином смысле, возможно, стоит игнорировать внешнее сходство и считать их как будто различными символами.

Нулевые указатели

Нулевой указатель (null pointer) не указывает ни на какой объект. Код может проверить, не является ли указатель нулевым, прежде чем пытаться использовать его. Есть несколько способов получить нулевой указатель.

int *p1 = nullptr; // эквивалентно int *p1 = 0;

int *p2 = 0;       // непосредственно инициализирует p2 литеральной

                   // константой 0, необходимо #include cstdlib

int *p3 = NULL;    // эквивалентно int *p3 = 0;

Проще всего инициализировать указатель, используя литерал nullptr, который был введен новым стандартом. Литерал nullptr имеет специальный тип, который может быть преобразован (см. раздел 2.1.2) в любой другой ссылочный тип. В качестве альтернативы можно инициализировать указатель литералом 0, как это сделано в определении указателя p2.

Программисты со стажем иногда используют переменную препроцессора (preprocessor variable) NULL, которую заголовок cstdlib определяет как 0.

Немного подробней препроцессор рассматривается в разделе 2.6.3, а пока достаточно знать, что препроцессор (preprocessor) — это программа, которая выполняется перед компилятором. Переменные препроцессора используются препроцессором, они не являются частью пространства имен std, поэтому их указывают непосредственно, без префикса std::.

При использовании переменной препроцессора последний автоматически заменяет такую переменную ее значением. Следовательно, инициализация указателя переменной NULL эквивалентна его инициализации значением 0. Сейчас программы С++ вообще должны избегать применения переменной NULL и использовать вместо нее литерал nullptr.

Нельзя присваивать переменную типа int указателю, даже если ее значением является 0.

int zero = 0;

pi = zero; // ошибка: нельзя присвоить переменную типа int указателю

Совет. Инициализируйте все указатели

Неинициализированные указатели — обычный источник ошибок времени выполнения.

Подобно любой другой неинициализированной переменной, последствия использования неинициализированного указателя непредсказуемы. Использование неинициализированного указателя почти всегда приводит к аварийному отказу во время выполнения. Однако поиск причин таких отказов может оказаться на удивление трудным.