Типы данных

Типы данныхПростые типы данныхСсылочные типы данных

Главная
Копилка

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

Указатель в Turbo Pascal - это переменная, которая содержит адрес объекта определённого базового типа.  При определении ссылочного  типа используется базовый тип,  перед которым ставится признак указателя, - символ '^'.

НАПРИМЕР:

Type

mas = array[1..20] of integer;   {базовый тип}

pm = ^mas;                               {тип-указатель на массив}

pin = ^integer;                           {тип-указатель на целое число}

Базовым типом  для  ссылочного  типа может быть любой тип,  в том числе и ещё необъявленный,  что является исключением для Turbo Pascal. То есть ссылочный тип может быть объявлен раньше, чем объявлен базовый тип.

НАПРИМЕР:

Type

pm = ^mas;

mas = array[1..20] of integer;

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

НАПРИМЕР:

Var

p1, p2: pin;

mm: ^mas;

После объявления переменной ссылочного типа (указателя), значение её неопределено.Значением ссылочной переменной может быть адрес переменной базового типа.  Для того,  чтобы определить значение  ссылочной переменной, необходимо  занести в неё (присвоить) адрес переменной базового типа.

 

НАЗАД

 

 

  Операция взятия указателя

Если в программе объявлена некоторая переменная, например:

Var

i: integer;

то при обращении к этой переменной по её имени мы получим содержимое этой переменной.  Если же, при обращении к  этой переменной,  перед её именем (идентификатором) поставить специальный символ '@', то мы получим не значение данной переменной, а её адрес. Такую запись в Turbo Pascal называют операцией взятия указателя, и используют для определения ссылочных переменных:

     p1 := @i;

В результате образуется следующая связь:

 

p1                                                  i

           

 

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

 

var

A: array[1..10] of integer;

 

то обращение @A[i] имеет смысл указателя на i-ое целое в  массиве A и также может участвовать в присваивании:

 

p1 := @A[i];

     

НАЗАД

 

 

    Указатель на указатель

Базовым типом для ссылочного типа может быть любой тип данных,  в том числе и ссылочный,  поэтому допустимо определение вида  "указатель на указатель".  Например,  для  объявленного ранее ссылочного типа pin возможно следующее определение:

var

pp1: ^pin;

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

pp1 := @p1;

Образовавшиеся после этого связи выглядят так:

 

pp1                                  p1                                       i      

  

 

НАЗАД

 

 

"Нулевой" указатель

Значением любой ссылочной переменной может быть не  только  адрес переменной базового типа,  но и специальная константа - "нулевой" указатель.  Нулевой  указатель  обозначается служебным словом nil и может быть присвоен любой  ссылочной  переменной.  При  выполнении  операции присваивания

p1 := nil;

значение p1 определено и равно nil, что значит что p1 не указывает ни на какую переменную базового типа.

 

НАЗАД

 

 

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

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

НАПРИМЕР:

ind := p1=p2;

if p1 <> nil then и т.д.

 

НАЗАД 

 

 

 Операция разыменование

Существует два способа доступа к переменным. 

Первый способ - обращение к  переменной по её имени (идентификатору),  называется прямым способом.

Второй  обращение к переменной по её адресу,  содержащемуся в указателе. Такой способ доступа называется косвенным.

Для обращения к переменной по её адресу, который находится в ссылочной переменной, используют операцию "разыменование".

Если к ссылочной переменной обратится по её имени,  то мы получим адрес переменной  базового типа.  Если же после имени указателя поставить символ '^', то мы получим доступ к той переменной на которую указывает данный указатель. Поэтому операторы

i := i + 1;        {прямой доступ к переменной i}

p1^ := p1^ + 1;    {косвенный доступ к переменной i}

полностью аналогичны и выполняют одно и то же действие.

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

В случае "указателя на указатель" возможно многократное разыменование, например:

pp1^^  {косвенное обращение к переменной i}

Разыменование ссылочной переменной,  значением  которой  является nil, является  недопустимым,  так как в этом случае не существует переменной, на которую ссылается указатель.

 

НАЗАД 

 

 

Статические и динамические переменные

Все переменные, которые необходимо указывать в разделе объявления переменных и которые обозначаются идентификаторами,  Н. Вирт называл СТАТИЧЕСКИМИ переменными. Эти переменные используются тогда, когда память,  используемая программой,  предсказуема (известна) в момент её написания. Распределение памяти для статических переменных производится полностью автоматически и подчинено стековой дисциплине. Но существует ряд задач, для которых невозможно предсказать размер памяти в момент написания программы.  В этих задачах необходим другой подход: переменные нужно  формировать динамически,  не связывая их со структурой программы. Так как средств для явных описаний таких переменных нет, то обращаться к ним по их именам(идентификаторам) невозможно. Единственным способом обращения к таким переменным является использование  ссылочных имена  (указателей),  создаваемых при формировании динамических переменных.  Turbo Pascal даёт возможность как образовывать так и удалять  такие переменные в любой момент работы программы,  сообразуясь с потребностями решаемой задачи.

Переменные, созданием и уничтожением которых может явно управлять программист, называются ДИНАМИЧЕСКИМИ переменными.

 

НАЗАД

 

 

Организация (распределение) памяти

Во время выполнения программы оперативная память компьютера  разделяется на три части:

  •    область памяти в которой размещается код выполняемой программы;

  •    область  памяти  выделяемая для статических переменных - "статическая память". Место для каждой статической переменной выделяется автоматически и подчинено стековой дисциплине - последовательному заполнению выделенной области памяти. Поэтому статическую память иногда называют стековой памятью. Ее размер по умолчанию 16К.

  •    область памяти выделяемая для образования динамических переменных. Так  как размещение переменных в этой области носит случайный характер,  эту область часто называют heap (куча).  По умолчанию динамическая  память (куча) занимает весь доступный объём оперативной памяти компьютера.

НАЗАД

 

 

     Создание динамических переменных

Для создания динамических переменных используется процедура  New.

Параметром данной процедуры является переменная ссылочного типа,  например:

 New(p1);

При выполнении этого оператора:

1) в куче выделяется место для динамической переменной целого типа;

2) ссылочной переменной p1 присваивается указатель на только что организованную динамическую переменную.

В результате мы получаем динамическую переменную.  Как вы уже поняли, имени (идентификатора) у неё нет, поэтому прямое обращение к такой переменной просто невозможно.  Единственный способ,  это косвенное обращение путём разыменования ссылочной переменной p1, содержащей указатель на данную динамическую переменную:

p1^ := 28;

Процедура New может быть применена также в функциональной форме:

p1 := New(pin);

В этом случае параметром New должен быть ссылочный тип.

 

 НАЗАД

 

 

     Уничтожение динамических переменных

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

Dispose(p1);

После выполнения  данной  процедуры значение ссылочной переменной становится неопределённым.

 

 НАЗАД

 

 

     Управление динамической памятью

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

MaxAvail: longint;

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

MemAvail: longint;

Определяет общий размер свободных участков в куче.

ПРИМЕР

begin

Writeln(MemAvail, ' байт свободно');

Writeln('Наибольший свободный блок содержит ', MaxAvail, ' байт');

end.

SizeOf

Этой функции  в  качестве  параметра передаётся переменная или её тип; результатом является число байтов,  необходимых для хранения данной переменной или переменных данного типа.

if MaxAvail >=SizeOf(p1) then p1 := new(pin).

 

НАЗАД

 

 

     Примеры программ

Program ex35_1; Uses Crt

    Var

       px: ^char;

       i: byte;

Begin clrscr;

     new(px);

     for i:=0 to 255 do

         begin

           px^:=chr(i);

           write(i:3,'=',px^);

       end;

    dispose(px);

    repeat until keypressed;

End.

 

Program ex35_2; Uses Crt;

    Type vect=array[1..10] of integer;

    Var

        px: ^vect;

        i: byte;

Begin  clrscr;

     new(px);

     for i:=1 to 10 do

         begin

              write('Введите эл-т массива N ',i,' ');

               Readln(px^[i]);

          end;

     Writeln('Содержимое массива:');

     for i:=1 to 10 do write(px^[i]:3);

     dispose(px);

     repeat until keypressed;

End.

 

НАЗАД      

 
 

Типы данныхПростые типы данныхСсылочные типы данных 

 
Сайт управляется системой uCoz