поскольку
если dptr = &numbers[x] = numbers + x
то dptr[i] = *(dptr + i) = = *(numbers + x + i) = numbers[x + i]
Указатель на один тип можно преобразовать в указатель на другой тип: такое преобразование не вызывает генерации каких-либо машинных команд, но заставляет компилятор изменить параметры адресной арифметики, а также операции выборки данного по указателю (собственно, разница в указателях на данные разных типов состоит только в размерах указуемых типов; а также в генерации команд `->' для выборки полей структур, если указатель - на структурный тип).
Целые (int или long) числа иногда можно преобразовывать в указатели. Этим пользуются при написании драйверов устройств для доступа к регистрам по физическим адресам, например:
unsigned short *KISA5 = (unsigned short *) 0172352;
Здесь возникают два тонких момента:
unsigned short SEGMENT, OFFSET; /*16 бит: [0..65535]*/ unsigned long ADDRESS = (SEGMENT << 4) + OFFSET; получается 20-и битный физический адрес ADDRESS
Более того, на машинах с диспетчером памяти, адрес, хранимый в указателе, является "виртуальным" (т.е. воображаемым, ненастоящим) и может не совпадать с физическим адресом, по которому данные хранятся в памяти компьютера. В памяти может одновременно находиться несколько программ, в каждой из них будет своя система адресации ("адресное пространство"), отсчитывающая виртуальные адреса с нуля от начала области памяти, выделенной данной программе. Преобразование виртуальных адресов в физические выполняется аппаратно.