Для типизированных указателей



ЛАБОРАТОРНАЯ РАБОТА

РАБОТА С ДИНАМИЧЕСКИМИ ПЕРЕМЕННЫМИ

И УКАЗАТЕЛЯМИ В ИНТЕГРИРОВАННОЙ СРЕДЕ

ТУРБО ПАСКАЛЬ

ЦЕЛЬ РАБОТЫ

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

ТЕОРЕТИЧЕСКАЯ ЧАСТЬ

Переменные обычно создаются при запуске программы (занимая при этом соответствующий объем памяти) и существуют вплоть до конца работы программы – это так называе­мые статические переменные. Легко прийти к выводу, что это не самый рациональный способ использо­вания памяти. Познакомимся с возможной аль­тернативой – динамическими переменными, которые создаются непо­средственно перед началом их использования и ликвидируются (освобождая при этом занимаемую память) сразу, как только это ис­пользование завершено.

Типичная проблема

Предположим, нам необходимо создать программу, обрабатываю­щую массив из 15 тысяч элементов, который содержит целочисленные значения типа LongInt. Как может выглядеть соответствующая про­грамма, демонстрирует пример 1.

Пример 1

Program array1;

Const number=15000;

Type

a=array [0..number] of longint;

var

ch:a ;

i:word ;

Begin

Writeln ;

For i:=1 to 15000 do

If (i mod 1000=0) or (i =number) then

Begin

ch[I]:=I;

Write(I;10, ch[I]:6)

End ;

End .

В этой программе объявлен массив, содержащий 15 тысяч значений типа Longint. В теле программы организован цикл (с помощью операто­ра FOR...TO...DO), в котором каждому элементу массива присваивается значение его индекса. Кроме того, значения элементов массива, а также значения параметра цикла (совпадающие между собой), кратные 1000, выводится на экран для контроля. Для того чтобы сразу же видеть результаты работы программы, в конце имеется оператор ReadLn. Благодаря этому результаты можно наблюдать на экране до тех пор, пока вы не введете что-нибудь и не нажмете клавишу <Enter>.

В принципе, в этой программе нет ничего нового для нас. Однако до­пустим, что возникла необходимость иметь дело с массивом, содержа­щим не 15, а 20 тысяч элементов. В представленной выше программе изменим значение константы Number с 15 000 на 20 000 и запустим про­грамму на выполнение, чтобы посмотреть, что получится.

При попытке запуска (напомним, что это осуществляется комбина­цией клавиш <Ctrl+F9> или выбором пункта Run в одноименном меню) на экране появляется сообщение:

Error 22: Structure too large.

Это значит: "Ошибка 22: Структура чересчур объемиста".

Если теперь в меню Help выбрать пункт Error messages, а затем в поя­вившемся окне дважды щелкнуть на номере этой ошибки (22), появится еще одно окно с соответствующей информацией. Информации в этом окне не так уж и много. Сообщается только, что максимальная размер­ность для структурированных типов составляет 65 520 байт. Что же это значит?

Вспомним, что элементы нашего массива содержат целочисленные значения, принадлежащие типу Longint (один из целочисленных типов), для каждого из которых требуется четыре байта памяти. Кроме того, массив (его первый вариант) включает 15 тысяч элементов, что в целом составляет 60 000 байт. Затем мы попытались перейти к массиву с 20 000 элементами. Нетрудно вычислить, что для такого массива, каж­дый элемент которого занимает в памяти четыре байта, в целом потре­буется 80 тысяч байт. А теперь вспомним, что информация об ошибке 22 гласит: максимальная размерность для структурированных типов составляет 65 520 байт. Это все объясняет. Если в первом случае допус­тимый предел превзойден не был (60 тысяч – это меньше чем 65 520), то второй вариант нашего массива (20 тысяч элементов) оказался недопустимо объемным.

Ну и что же дальше? Что если имеет место настоятельная необходи­мость работать с большими массивами? Неужели Turbo Pascal для этого не подходит? Оказывается, язык программирования Turbo Pascal по­зволяет справиться и с этой проблемой. Познакомимся с та­кими понятиями, принятыми в Turbo Pascal, как динамическая память и указатель.

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

До сих пор мы имели дело с так называемыми статическими данными и статическими переменны­ми. Такие переменные объявляются в начале программы (в разделе опи­саний) и существуют до завершения ее работы. Соответственно, па­мять для содержания этих переменных выделяется при запуске про­граммы и остается занятой все время, пока программа работает.

Очевидно, что это не самый рациональный способ использования памяти компьютера. Например, некоторая переменная может исполь­зоваться только однажды в единственном операторе обширной про­граммы, однако память, выделенная под эту переменную, остается за­нята все время, пока работает программа. А нельзя ли сделать так, что­бы память для такой переменной выделялась в момент, когда переменная начинает использоваться, и освобождалась сразу же по за­вершении ее использования? И чтобы эту память тут же можно было выделить для иных данных? Оказывается, это вполне реально и именно для этой цели в Turbo Pascal введено понятие динамической памяти. Динамическая память, известная также как куча, рассматривается в Turbo Pascal как массив байтов.

Кроме того, динамическая память (или куча), имеющая объем при­близительно 300 000 байт, позволяет обрабатывать более обширные структуры данных. В предыдущем разделе нам не удалось, используя Обычную (статическую) память, создать массив из 20 000 элементов типа LonInt. С помощью динамической памяти можно обработать гораздо больший массив, что мы и докажем в конце данной главы.

Правда, при динамическом размещении к данным не удастся обра­щаться по именам, как к статическим данным, с которыми мы до сих пор имели дело. Кроме того, количество и тип динамически размещае­мых данных заранее неизвестны. Динамическая память выделяется для данных (и освобождается) в ходе работы программы. Для управления динамической памятью Turbo Pascal предоставляет гибкое средство, из­вестное как указатели.

Указатели

Мы уже знаем, что оперативная память компьютера – это множест­во ячеек, каждая из которых предназначена для хранения одного байта информации, и каждая имеет собственный адрес, по которому к этой ячейке можно обратиться. Указатель – это переменная, объ­явленная в разделе описаний программы, значение которой и пред­ставляет собой адрес одного байта памяти.

Указатели, используемые в Turbo Pascal, бывают типизированные и нетипизированные. Если нетипизированный указатель – это переменная, содержащая адрес данных произвольного типа, то типизирован­ный указатель содержит адрес данных, тип которых оговаривается при объявлении данного указателя.

Нетипизированные указатели объявляются следующим образом:

var

рр : pointer;

где POINTER – стандартный тип данных;

РР – переменная, содержащая адрес памяти, по которому могут храниться данные произвольного типа.

Что касается типизированных указателей, то их объявления в про­граммах на Turbo Pascal выглядят так:

var

рх : ^char;

ру : ^integer;

В этом примере описаны два типизированных указателя: РХ и PY. Значения этих переменных представляют собой адреса в оперативной памяти, по которым содержатся данные типа Char и Integer соответст­венно. Нетрудно заметить, что описание типизированного указателя отличается от описания статической переменной того же типа только тем, что в случае указателя перед типом присутствует символ "^".

Подытожим: когда требуется воспользоваться динамической памя­тью, в разделе описаний объявляется не сама переменная, а указатель (или ссылка) на нее. В этом случае указатель представляет собой обыч­ную переменную, а переменная, на которую он ссылается, – динамиче­скую. При этом если в выражении должен присутствовать указатель, используется идентификатор, объявленный в разделе описаний. Вот так: РХ. Однако, если в выражении должна фигурировать динамическая переменная, на которую ссылается указатель, идентификатор указателя дополняется символом "^". Такое действие называется разыменованием. Например, РХ^.

Еще пример:

type

DatePointer = ^Date;

Date=record

year : 1900..2100;

month : 1..12;

day : 1..31;

next : DatePointer

end;

var

pd : DatePointer;

Здесь объявлен тип DatePointer, представляющий собой указатель на тип Date, который описывает запись. Обратите внимание, что тип DatePointer описан до типа Date, на который он ссы­лается. В то же время одно из полей записи Date принадлежит типу DatePointer. В целом, в Turbo Pascal не допускается ссылаться на еще не описанные типы, однако в данном случае (достаточно частом, когда приходится иметь дело с указателями) как ни располагай описания, все равно ссылки на еще не описанный тип не избежать. Поэтому един­ственное исключение сделано для указателей: тип указателя на дина­мические данные может быть объявлен до описания самих данных.

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

var

рх , ру : ^char;

pz : ^integer;

В этом случае операция присваивания допустима для указателей РХ и РY:

px := py

Однако совершенно недопустимыми окажутся операторы:

рх : = pz;

или

pz :=ру;

В то же время нетипизированный указатель может присутствовать в операторе присваивания в паре с любым типизированным указателем. Например, в программе объявлены указатели:

var

рх : ^ char;

py : ^ integer;

pz : pointer;

Для этих переменных допустимы операторы присваивания:

рх := pz; ру := pz;

pz :=ру; pz := рх;

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

2.3.1. Состояния указателя.Для указателя, после того как он объявлен в разделе описания пере­менных, возможны три состояния. Указатель может содержать адрес некоторой переменной, "пустой" адрес NIL или иметь неопределенное состояние. Первый случай в объяснениях не нуждается. Во втором слу­чае, когда требуется, чтобы указатель никуда не указывал, ему присваи­вается специальное значение NIL. Что же касается неопределенного со­стояния, то оно имеет место сразу после начала работы программы (до того как указателю будет присвоен какой-нибудь адрес в памяти или значение NIL), либо после освобождения памяти, на которую данный указатель ссылается.

Если кого-то смущает "указатель, который никуда не указывает", то это можно представить как ссылку на область памяти, в которой ника­кая информация никогда не размещается. Значение NIL – это констан­та, которую можно присвоить любому указателю.

Может возникнуть вопрос, в чем разница между неопределенным со­стоянием указателя и случаем, когда его значение равно NIL? Поскольку NIL – значение конкретное, хотя и никуда не указывающее, можно ска­зать, что два указателя, содержащие NIL, имеют равные значения. В то же время значения двух указателей в неопределенном состоянии рав­ными признать нельзя.

2.3.2. Выделение и освобождение динамической памяти.Познакомимся с тем, как выделяется (или резервирует­ся) динамическая память для типизированных и нетипизированных указателей. Кроме того, узнаем как освободить память, кото­рая была выделена ранее.

Для типизированных указателей

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

var

рх , ру : ^char;

pz : ^integer;

begin

new(px);

new(py);

new(pz);

px ^ : ='A';

py ^ : ='7';

pz ^ : =667;

dispose(px);

dispose(py);

dispose(pz );

end .

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

Когда надобность в переменных РХ, PY и PZ отпадает, выделенная для них память освобождается с помощью процедуры Dispose. После этого освободившуюся память можно резервировать для других пере­менных, объявленных в программе и использующихся в оставшихся операторах.


Дата добавления: 2019-02-26; просмотров: 267; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!