Данный оператор new возвращает указатель на переменную типа double
, но тип double
отличается от типа char
, поэтому мы не должны (и не можем) присвоить указатель на переменную типа double
указателю на переменную типа char
.
17.4.1. Размещение в свободной памяти
new
выполняет
• Оператор new
возвращает указатель на выделенную память.
• Значением указателя является адрес на первый байт выделенной памяти.
• Указатель ссылается на объект указанного типа.
• Указатель
Оператор new
может выделять память как для отдельных элементов, так и для последовательности элементов. Рассмотрим пример.
int* pi = new int; // выделяем память для одной переменной int
int* qi = new int[4]; // выделяем память для четырех переменных int
// (массив)
double* pd = new double; // выделяем память для одной переменной
// double
double* qd = new double[n]; // выделяем память для n переменных
// double
Обратите внимание на то, что количество объектов может задаваться переменной. Это важно, поскольку позволяет нам выбирать, сколько массивов можно разместить в ходе выполнения программы. Если n
равно 2
, то произойдет следующее.
Указатели на объекты разных типов имеют разные типы. Рассмотрим пример.
pi = pd; // ошибка: нельзя присвоить указатель double* указателю int*
pd = pi; // ошибка: нельзя присвоить указатель int* указателю double*
Почему нельзя? В конце концов, мы же можем присвоить переменную типа int
переменной типа double
, и наоборот. Причина заключается в операторе []
. Для того чтобы найти элемент, он использует информацию о размере его типа. Например, элемент qi[2]
находится на расстоянии, равном двум размерам типа int
от элемента qi[0]
, а элемент qd[2]
находится на расстоянии, равном двум размерам типа double
от элемента qd[0]
. Если размер типа int
отличается от размера типа double
, как во многих компьютерах, то, разрешив указателю qi
ссылаться на память, выделенную для адресации указателем qd
, можем получить довольно странные результаты.
Это объяснение с практической точки зрения. С теоретической точки зрения ответ таков: присваивание друг другу указателей на разные типы сделало бы возможными
17.4.2. Доступ с помощью указателей
Кроме оператора разыменования *
, к указателю можно применять оператор индексирования []
. Рассмотрим пример.
double* p = new double[4]; // выделяем память для четырех переменных
// типа double в свободной памяти
double x = *p; // читаем (первый) объект, на который
// ссылается p
double y = p[2]; // читаем третий объект, на который
// ссылается p
Так же как и в классе vector
, оператор индексирования начинает отсчет от нуля. Это значит, что выражение p[2]
ссылается на третий элемент; p[0]
— это первый элемент, поэтому p[0]
означает то же самое, что и *p
. Операторы []
и *
можно также использовать для записи.
*p = 7.7; // записываем число в (первый) объект, на который
// ссылается p
p[2] = 9.9; // записываем число в третий объект, на который
// ссылается p
Указатель ссылается на объект, расположенный в памяти. p
.
double x = *p; // читаем объект, на который ссылается указатель p
*p = 8.9; // записываем объект, на который ссылается указатель p
Когда оператор []
применяется к указателю p
, он интерпретирует память как последовательность объектов (имеющих тип, указанный в объявлении указателя), на первый из который ссылается указатель p
.
double x = p[3]; // читаем четвертый объект, на который ссылается p