Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Информатика 1.docx
Скачиваний:
11
Добавлен:
26.09.2019
Размер:
364.88 Кб
Скачать

Указатели на различные типы.

В предыдущих примерах мы рассматривали только указатели на тип char. Однако указатели различаются между собой в зависимости от типа данных (основного или производного) на который он указывает. Этот тип определяет, на какие элементарные участки разбивается область памяти при работе с указателями, а также определяет как будут применяться к ним различные операции.

Например, рассмотрим 2 указателя, один на тип char (однобайтовый), другой – на тип long (четырёхбайтовый):

char * pChar;

long * pLong;

Размер элементарного участка памяти, адресуемого указателем зависит от типа на который он указывает. Таким образом, pChar будет указывать на однобайтовые участки, а pLong – на 4 байтовые.

Как это проявляется на практике ? Пусть мы имеем некоторую область памяти, начинающуюся с адреса 1000, в которой хранятся следующие числа:

Addr=1000 Addr=1004 Addr=1007

1

2

3

4

10

20

30

40

 pChar

 pLong

|–*pChar –|

|–––––––––––––– *pLong ––––––––––––––––|

Пусть первоначально оба указателя указывают на один и тот же адрес. Для присвоения необходимо явное преобразование типов, т.к. компилятор не может преобразовать константу 1000 в указатель автоматически.

pChar=(char*)1000;

pLong=(long*)1000;

Теперь воспользуемся операцией чтения памяти. Поскольку тип переменных и их значений, записываемых или читаемых из памяти с помощью оператора *, тождественнен типу, на который указывает указатель, то выражение *pChar вернёт нам значение типа char. Следовательно, *pChar вернёт значение 1.

Операция *pLong вернёт значение типа Long, т.е. четырёхбайтовое значение, записанное в обпамяти, начиная с адреса, записанного в указателе, т.е. с адреса 1000.

Напомню, что адрес ячейки памяти для подавляющего большинства платформ исчисляется в байтах, т.е. размер минимальной ячейки памяти, имеющей собственный адрес, равен 1 байту. Числа, занимающие в памяти более одного байта, хранятся в обратном порядке, т.е. сначала идёт самый младший байт, а последним идёт самый старший байт.

Таким образом, операция *pLong вернёт число, которое хранится по частям в ячейках с адресами 1000, 1001, 1002, 1003. Число это будет равно 04030201h (h – означает, что число записано в шестнадцатиричной форме), в десятичной форме это равно 67305985.

Как видим, даже если значения указателей равны, то, в зависимости от типа, на который они указывают, значения, получаемые с помощью операции * будут совершенно разными.

Значение типа, на который указывает указатель также влиет на смысл арифметических операций, применяемых к нему. В отличие от арифметических типов, операция прибавления или вычитания из указателя целого числа означает не просто изменение адреса, хранящегося в указателе на это целое число, а означает перемещение указателя на заданное количество адресуемых участков.

Продолжим пример, начатый выше. В результате выполнения операций:

pChar=pChar+1;

pLong=pLong+1;

мы получим следующую картину:

Addr=1000 Addr=1004 Addr=1007

1

2

3

4

10

20

30

40

 pChar

 pLong

|–*pChar –|

|–––––––––––––– *pLong ––––––––––––––––|

Как видим, значения адресов, хранящихся в указателях, перестали быть равными, хотя операции, на первый взгляд, были произведены полностью идентичные. Поскольку, размер элементарного участка, адресуемого указателем pChar равен 1 байту, то в результате операции +1 он перешёл к следующему участку, т.е. к следующему байту. Указатель pLong также перешёл к следующему участку, но поскольку длина типа long равна 4 байтам, то адрес, хранимый в pLong увеличился на 4 байта.

Таким образом, при совершении операции

Pointer=Pointer+i, где Pointer – указатель, а i – целое число,

физический адрес, хранимый в указателе изменится на i*TypeSize, где TypeSize – размер типа, на который указывает указатель Pointer.

Аналогично работают с указателями операции инкремента (++) и декремента (--).

Операции умножения и деления неприменимы к указателям.