Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Статические и динамические переменные⇐ ПредыдущаяСтр 11 из 11
До настоящего времени мы вели разговор о типах данных, служащих для представления так называемых статических переменных. Статической называется переменная, которую описывают в программе и к которой обращаются по имени. Статической она называется потому, что существует (то есть для нее выделен определенный участок памяти) на протяжении всего времени выполнения программы, процедуры или функции, в которой она содержится. Все объекты, описанные в разделе переменной, являются статическими. То есть их можно проконтролировать при статическом анализе текста программы, без ее выполнения (F9). Во время компиляции программы каждой статической переменной ставится в соответствие адрес ячейки памяти. Этот адрес в дальнейшем не меняется. Далеко не каждую задачу можно решить, используя только статические переменные. Попытаемся решить следующую задачу: составить список клиентов, ожидающих обслуживание. Безусловно, заказчик требует от нас составить не просто статичный список на некоторый момент времени, а динамичную, изменяющуюся во времени структуру. Попробуем решить задачу описания очереди (а подобная структура называется очередью не только в быту, но и в информационных технологиях), используя известные нам структуры данных. Опишем клиента так: Type Person = record …….. …….. end{of record}; Эта запись – информация о клиенте, она может содержать любые необходимые сведения, например, фамилию, имя, отчество, возраст, марку автомобиля, характеристику неисправности, и т.д. и т. п. Пусть заказчик предполагает длину очереди до const N = …; тогда описание самой очереди будет иметь вид: Var L: array [1…N] of Person; A: Person; {описание рабочей, или оперативной переменной} I, J, K: byte; {или word, в зависимости от величены N индексы очереди} C: integer; {или chart критерий выбора процедуры} Программа должна обеспечивать выполнение опреций типа: · Поставит в очередь, · Обслужить, то есть изъять из очереди, · Показать список очереди. Обозначения: I – первый ожидающий обслуживания, J – последнее свободное место в очереди. Пишем программу: Begin I: =1; J:=1;{очередь пуста} B: = False; {признак пустоты очереди} Repeart Write (‘операция: 1 – добавить, 2 –изъять, 3 – показать, 0 – конец работы’); readln(c); case c of 1: dobavit; {добавить} 2: izyat; {изъять} 3: perat; {печать} 0: exit; {выход} end {of case} until c = 0 end. Теперь нужно написать три процедуры, что не составить трудности, и задача будет решена. Итак, задача решена и довольно красиво, но остаются вопросы: - что делать, если кто-то желает покинуть очередь изнутри, не дождавшись обслуживания, - как поставить «своего» клиента внутрь очереди, - что делать, если значение N наперед не известно? Ответы на эти вопросы чрезвычейно просты, если воспользоваться новым для нас видом переменных – динамическим. Это значит, что, поимо статических существующих переменных, переменная может динамически создаваться и уничтожаться в процессе выполнения программы такая перемнная назывется динамической. Динамические переменные размещаются в свободной области памяти. Динамические переменные не описываются явно и прямой доступ к ним по имени невозможен. Адреса ячеек памяти, где они будут созданы, непредсказуемы и поэтому анализу не подлежат. Ссылочные типы (указатели)
Для работы с динамическими объектами используется ссылочный тип (или тип указатель). При этом в программе все действия над динамическими объектами описываются с помощью обыкновенных статических переменных. Но тип этих переменных – указатель (ссылочный тип). Это Pointer. Тип Pointer – это фактически адрес хранения объекта. Указатель может иметь значение адреса статической или динамической переменной. Особое значение указателя -<NIL>- - указатель, который указывает «в пустоту», в ничто. Динамические переменные создаются и наоборот, уничтожаются с помощью зарезервирования процедур New и Dispose, а обращение к ним осуществляется через величины, относящиеся к типу указателей, которые представляют собой не что иное как адреса в памяти компьютера, где хранятся вновь созданные переменные. Значения адресов присваиваются уже существующим переменным – указателям, относящимся к особому типу, который так и называется – типом указателей. В описании указателя P вводится тип T, на данные которого будет указатель P: Type P=^T; Множество значений типа P – неопределенное множество так называющихся идентифицирующихся величин (каждая из которых указывает на переменную типа T), в которое добавлено особое значение – Nil, которое ни на что не указывает. Доступ к идентифицированным (динамическим) переменным осуществляется через указатели, значения которых соответствуют именам обычных переменных. Указатели служат средством для формирования сложных и одновременно гибких структур данных. Для объявления указателя используется значок ^, который помещается перед типом: Var P1: ^Integer; P2: ^Integer; Если, например, указатель (дадим ему имя Ptr) описан как Var Ptr : P; и ему было присвоено некоторое значение, то Ptr^ будет обозначать динамическую переменную. Содержательно любой ссылочный тип определяет множество значений, которые являются указателями на значения некоторого определенного типа. Для описания ссылочных типов используется символ «^» и индификатор типа, например: Type P=^integer; Это описание определяет множество указателей на целые значения. Еип, на значения, которого можно конструировать указатели, может быть любым (он в данном случае называется базовым для ссылочного типа). Имя в программе определение ссылочного типа, можно по общим правилам описать переменные этого типа. Ссылочные типы в описании переменных можно задавать как посредством идентификаторов, так и явно, например: Пример. Type P= ^ integer; Person = record Word = 2 байта Name, SecondName, SurName: string [20], 0…65000 Sex: (Male, Female); Speciality: word; {индекс специальности} End; {of record} Omen: ^ Person; В подобных случаях говорят, что, например, значение переменной OneMan ссылается (указывает) на некоторое значение типа Person. Описание ссылочного типа – единственное исключение из общего правила, согласно которому все идентификаторы должны быть описаны перед использованием. В данном случае допускаются описания вида: Type P= ^ Base; Даже если тип Base еще не был описан. Однако в таком случае тип Base должен быть описан далее в такой же части описания типов: Type P= ^ Base; Base = record X, Y: real End; {of record}. Реально значение ссылочных типов содержат адреса расположения в памяти конкретных значений базового типа. Для того, чтобы присвоить переменной ссылочного типа некоторое значение, можно воспользоваться операцией взятия указателя, которая строится из знака этой операции – символа @ (амперсант) и переменной любого типа. Пример Var i: integer; {описание переменной} P1: ^ integer; ……………. P1: = @i; {указатель на целое} В результате такого присваивания P1 получит в качества своего нового значения указатель на переменную i (или, попросту говоря, адрес переменной i), это можно наглядно представить в виде схемы: P1: = I (P1 = адрес I) J: = P1 (j= i)
P1
I
Операция взятия указателя допустила до любых переменных, в том числе для элементов массивов, полей записи и т. д. Пример Var A: array [1..10] of integer; Для этого примера конструкция @ A[i] имеет смысл «указателя на i-ое целое в массиве A» и может участвовать в присваивании: P1:= @ A[i]; Ссылочные типы могут образовывать от любых типов, поэтому допустимо определение вида «указатель на указатель». Пример type P= ^ integer; P1 = ^ integer; Var F: ^ P; I: integer; Здесь переменная F в качестве своих возможных значений имеет множество указателей, ссылающихся на указатели, которые, в свою очередь, ссылаются на целые значения. Рассмотрим присваивание: P1: = @ A [i]; F: = P1?
F
P1
|