Тип указателя определяется оператором в форме *d
, где d
— определяемое имя. Символ *
следует повторять для каждой переменной указателя.
int *ip1, *ip2; //
double dp, *dp2; //
//
Указатель содержит адрес другого объекта. Для получения адреса объекта используется &
.
int ival = 42;
int *p = &ival //
//
Второй оператор определяет p
как указатель на тип int
и инициализирует его адресом объекта ival
типа int
. Поскольку ссылки не объекты, у них нет адресов, а следовательно, невозможно определить указатель на ссылку.
За двумя исключениями, рассматриваемыми в разделах 2.4.2 и 15.2.3, типы указателя и объекта, на который он указывает, должны совпадать.
double dval;
double *pd = &dval //
double *pd2 = pd; //
int *pi = pd; //
pi = &dval //
//
Типы должны совпадать, поскольку тип указателя используется для выведения типа объекта, на который он указывает. Если бы указатель содержал адрес объекта другого типа, то выполнение операций с основным объектом потерпело бы неудачу.
Хранимое в указателе значение (т.е. адрес) может находиться в одном из четырех состояний.
1. Оно может указывать на объект.
2. Оно может указывать на область непосредственно за концом объекта
3. Это может быть нулевое значение, означающее, что данный указатель не связан ни с одним объектом.
4. Оно может быть недопустимо. Любое иное значение, кроме приведенного выше, является недопустимым.
Копирование или иная попытка доступа к значению по недопустимому указателю является серьезной ошибкой. Как и использование неинициализированной переменной, компилятор вряд ли обнаружит эту ошибку. Результат доступа к недопустимому указателю непредсказуем. Поэтому всегда следует знать, допустим ли данный указатель.
Хотя указатели в случаях 2 и 3 допустимы, действия с ними ограничены. Поскольку эти указатели не указывают ни на какой объект, их нельзя использовать для доступа к объекту. Если все же сделать попытку доступа к объекту по такому указателю, то результат будет непредсказуем.
Когда указатель указывает на объект, для доступа к этому объекту можно использовать *
.
int ival = 42;
int *p = &ival //
cout << *p; //
//
Обращение к значению указателя возвращает объект, на который указывает указатель. Присвоив значение результату оператора обращения к значению, можно присвоить его самому объекту.
*p = 0; //
//
cout << *p; //
При присвоении значения *p
оно присваивается объекту, на который указывает указатель p
.