| 5. Указатели.
Массивы и строки.
5.1. Указатели и операции с адресами.
В языке Паскаль присутствуют
тип-указатели, каждый из которых состоит из
неограниченного множества указывающих на
однотипные элементы значений. В Паскале, над
указателями определены только операции проверки
на равенство и неравенство. Так же для всех типов
указателей языка Паскаль, присутствует пустой
указатель, который не указывает ни на один
элемент.
Все указатели языка Паскаль
описываются в разделе переменных. Синтаксис
такого описания можно представить так:
тип-указатель = “|”
идентификатор типа
В языке Паскаль существует
жесткое правило: идентификатор любого типа
сначала должен быть определён и лишь затем
использован. В большинстве программ,
использующих указатели, нельзя обойтись без
раздела описания типов, поскольку при
определении тип-указатель требуется
идентификатор типа.
Чтобы в Паскале связать
указатель P с типом T, записывают:
TYPE POINTER = @T;
T=…; или TYPE T=. . .
VAR P:POINTER; VAR P:@T;
Здесь P
является указателем на переменную типа T. Для обращения к самой переменной
типа T используют обозначение
P|.
Теперь рассмотрим
использование указателей на языке Си.
Указатели в Си, это переменные,
содержащие адреса других переменных. Указатель
– это адрес некоторого объекта, следовательно,
через него можно обращаться к этому объекту.
Унарная операция & даёт адрес переменной, поэтому
оператор y=&x;
присваивает адрес х переменной у.

Операцию & можно применять только к переменным
и элементам массива; конструкция вида &(x+7)
или &28 недопустимы.
Унарная операция * воспринимает свой операнд как адрес
некоторого объекта и использует этот адрес для
выборки содержимого, поэтому оператор z=*y; присваивает z
значение переменной, записанной по адресу y. Если y=&x; z=*y;, то z=x;
(смотри рисунок).

Объекты, состоящие из знака * и
адреса (например *а), необходимо объявлять.
Делается это так:
int *a, *b, *c;
char *d;
Объявление типа char *d; говорит о том, что значение,
записанное по адресу d, имеет
тип char.
Указатели могут встречаться и в
выражениях. Если у – указатель на целое
значение, т.е. имело место объявление int *y; то *у может появиться там же, где и
любая другая переменная, не являющаяся
указателем.
Значит, вполне допустимы
следующие выражения:

Первое из выражений заносит
число 7 в ячейку по адресу у, второе
увеличивает значение по адресу х в пять раз,
третье – добавляет единицу к содержимому ячейки
памяти с адресом z. В
последнем случае круглые скобки необходимы, т.к.
операции * и ++ имеют одинаковый приоритет и
выполняются справа налево.
Кроме этого, указатели можно
использовать как операнды в арифметических
операциях. Если у – указатель, то унарная
операция у++ увеличит его значение; теперь оно
является адресом следующего элемента. Указатели
и целые числа можно суммировать. Например,
конструкция y+n (у –
указатель, n – целое число)
задаёт адрес n-го объекта,
на который указывает у. Это справедливо для
любых объектов; транслятор будет масштабировать
приращение адреса в соответствии с типом,
определённым соответствующим объявлением.
Так же как и на Паскале, любой
адрес можно проверить на равенство (==) или неравенство (!=) со специальным значением NULL, которое записывается вместо нуля. В
языке Си, слово NULL, позволяет
определить указатель, который ничего не
адресует. |