Шаг 68.
Общие сведения об указателях

    Этот шаг посвящен первоначальному знакомству с указателями.

    Все переменные хранят в себе какие-то значения. При описании переменной мы указываем ее тип, который определяет диапазон ее значений. Все переменные располагаются в памяти компьютера. Под размещение значений переменных отводится определенное количество байт. Однако существуют переменные, значениями которых являются адреса расположения в памяти других переменных. Такие переменные получили название указателей. Для чего нужны указатели? Ответ на этот вопрос мы дадим, когда будем изучать основы объектно-ориентированного программирования. А сейчас обратите внимание на рисунок 1, иллюстрирующий механизм использования указателей.


Рис.1. Использование указателей

    Как любая другая переменная указатель должен быть описан. Однако его описание должно отличаться от обычной переменной. Поэтому в описании указателя используется символ "^". Кроме того, при описании указателя также задается тип. Но зачем же указывать тип, если указатель в качестве своего значения имеет адрес расположения в памяти другой переменной? Дело в том, что доступ к этой переменной можно получить, используя указатель. Однако возникает вопрос: а какого типа значение хранится по этому адресу? Ведь, зная тип, компьютер обрабатывает это значение соответствующим образом. Поэтому тип при описании указателей крайне необходим.

    После это краткого вступления перейдем к рассмотрению синтаксических конструкций, используемых для описания указателей.

    Содержательно любой ссылочный тип определяет множество значений, которые являются указателями на значения некоторого определенного типа. Для описания ссылочных типов используется символ "^" и идентификатор типа, например:


     Type
        P= ^Integer;

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

    Имея в программе описание ссылочного типа, можно по общим правилам объявлять переменные этого типа. Ссылочные типы в описаниях переменных можно задавать как посредством идентификаторов, так и явно, например:


     Var
      P1, P2 : P; {Указатели на переменные целого типа.}
                  {Тип Р введен выше.}
      R: ^Real; {Указатель на переменную вещественного типа.}

Замечание. Обратите внимание на то, что переменные P1, P2, R еще не имеют значений.

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


     Type
        PtrType = ^BaseType;

даже если тип BaseType еще не был описан. Однако в таком случае BaseType должен быть описан далее в той же части описания типов, то есть в той же самой последовательности определений типов, что и тип PtrType:


     Type
        PtrType = ^BaseType;
        BaseType = Record
              		X, Y: Real;
                   End;                    .

    Реально переменные ссылочных типов содержат адреса расположения в памяти конкретных значений базового типа. Для того, чтобы присвоить переменной ссылочного типа некоторое значение, необходимо воспользоваться унарной операцией взятия указателя, которое строится из знака этой операции - символа @ (амперсанд) и одного операнда – переменной любого типа. Например, если имеется описание:


     Var
        i : Integer;

то применение этой операции к переменной i: @i – дает в качестве результата значение типа "указатель на целое"; поэтому оператор присваивания:


     P1 : = @i;

правомочен, так как в обеих его частях стоят конструкции одного и того же типа. В результате такого присваивания P1 получит в качестве своего нового значения указатель на переменную i (адрес переменной i).

    Операция взятия указателя допустима для любых переменных, в том числе для элементов массивов, полей записи и т.д. Например, если есть описание:


     Var
        A : Array [1...10] of Integer;

то конструкция: @A[i] имеет смысл указателя на i-й элемент массива А и также может участвовать в присваивании, например: P1:= @A[i];.

    Ссылочные типы можно образовывать от любых типов, поэтому допустимо определение вида указатель на указатель. Так, переменная PP1 из следующего описания:


     Var
       PP1 : ^P;

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

    Среди всех возможных указателей в языке выделяется один специальный указатель, который никуда не указывает. Это можно себе представить таким образом: в адресном пространстве оперативной памяти выделяется один адрес, в котором заведомо не может быть размещена никакая переменная. На это место в памяти и ссылается такой пустой или нулевой указатель, который обозначается служебным словом NIL. Указатель NIL считается константой, совместимой с любым ссылочным типом. Таким образом, это значение можно присваивать любому указательному типу.

    Над значениями ссылочных типов допускаются две операции сравнения на равенство и неравенство. Эти операции проверяют, ссылаются ли два указателя на одно и то же место в памяти. Обозначаются эти операции знаками = и <>.

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


Предыдущий шаг Содержание Следующий шаг