- •Начальные сведения
- •Алфавит
- •Лексемы, разделители и комментарии
- •Форма Бэкуса-Наура
- •Структура программы на Паскале
- •Типы данных
- •Базовые возможности Паскаля
- •Стандартные типы данных
- •Константы
- •Конструирование типов
- •Перечисления
- •Диапазоны (интервалы)
- •Массивы
- •Описание переменных и типов данных
- •Var a,b,c: Real; {описаны переменные вещественного типа}
- •I,j,k,l,m,n:Integer; {описаны переменные целого типа}
- •Оператор присваивания
- •Условные операторы
- •Оператор If
- •Оператор Case
- •Операторы цикла
- •Цикл While
- •Цикл Repeat-Until
- •Цикл For
- •Оператор безусловного перехода и метки
- •Пустой оператор
- •1: End; {конец тела цикла с помеченным пустым оператором}
- •Процедуры и функции
- •Описание
- •Список формальных параметров
- •Вызов процедур и функций
- •Локализация (области видимости) имен. Глобальные и локальные объявления.
- •Статическое и динамическое выделение памяти переменным
- •Рекурсия и опережающее описание
- •Стандартные функции
- •Стандартные процедуры
- •Стандартный ввод-вывод
- •Сложные типы данных и их использование
- •Квалификаторы
- •Конструкция записи, тип записи и переменная типа запись
- •Id:Person; {личные данные}
- •Id:Person; {личные данные}
- •Index: Ch; {Название/номер группы}
- •Использование записей в программе
- •Оператор With
- •Записи с вариантными полями
- •0:(I:Integer) {Два байта как одно поле Integer}
- •1:(Lo,hi:Char); {отдельно младш. И старш. Байты}
- •Var e: Integer; {в этой переменной будем менять байты}
- •Указатели и динамические структуры данных
- •Определение и описание
- •I:integer; {Информационное поле}
- •Var p,q:Point; {переменные-указатели на записи типа Rec}
- •Использование указателей и динамических переменных
- •Создание и уничтожение динамических переменных
- •Простейшие динамические структуры
- •Множества
- •Назначение и описание
- •Константы типа множество
- •Операции с множествами
- •Назначение и описание
- •Работа с файлами
- •Файлы типа Text
Var e: Integer; {в этой переменной будем менять байты}
C: Char; {это вспомогательная переменная}
H: ByteAccess; {это трюковая переменная}
. . . . . . . .
Begin
. . . . . . . .
E:=2; {Двоичн. знач. 0000 0000 0000 0010}
Writeln(E); {Будет выведено число 2}
With H do Begin {работаем с трюковой переменной}
I:=E;{заносим исходное значение в трюковую переменную}
C:=Lo;{заносим младший байт во вспомогат. переменную}
Lo:=Hi; {пишем старший байт в младший байт}
Hi:=C; {пишем младший байт в старший байт}
E:=I {возвращаем результат в исходную переменную}
End;
{Теперь в E двоичн. знач. 0000 0010 0000 0000}
Writeln(E); {Будет выведено число 512}
. . . . . . . .
Указатели и динамические структуры данных
Определение и описание
Указатель – это переменная, значением которой является адрес другой переменной. Указатель может хранить адрес переменной определенного типа, соответственно, указатели имеют тип указателя на определенный тип, который является базовым для него.
Синтаксис конструкции типа указателя:
<тип указателя>::="^"<имя указываемого типа>.
Пример:
Type Ipoint=^Integer;
Var M:Ipoint;
Этот пример не имеет практического смысла, так как к переменным типа Integer проще обращаться по имени, соответствующим образом описав их.
Основное назначение указателей – создание динамических структур данных. Такие структуры строятся из безымянных переменных типа записей. В этих записях, кроме информационных полей, присутствует одно или несколько полей, являющихся указателями на записи такого же или другого типа. Поскольку такие записи безымянные, доступ к ним по имени невозможен. Они не описываются в разделе Var, в программе описывается их тип. Они создаются и уничтожаются при работе программы по мере надобности.
Чтобы описать тип записи, содержащей поля-указатели, надо сначала описать соответствующий тип указателя. Но чтобы описать тип указателя на запись определенного типа, вначале нужно описать этот тип записи. Эта дилемма разрешена простым способом – сделано единственное отступление от принципа предварительного описания, принятого в Паскале.
Вначале описывается тип указателя на тип записи, используемый для построения динамических структур, а затем описывается тип соответствующей записи.
Пример:
Type Point=^Rec; {тип указателя на записи типа Rec}
Rec=Record {тип записи}
I:integer; {Информационное поле}
p:Point {поле-указатель}
end;
Var p,q:Point; {переменные-указатели на записи типа Rec}
{Переменные-записи не описываются}
Использование указателей и динамических переменных
В Паскале определена константа Nil, которая согласуется с указателями любого типа. Если указатель имеет значение Nil, он ни на что не указывает.
Указателю можно присваивать значение другого указателя того же типа, или константу Nil. Пример для описаний из предыдущего примера:
p:=q; q:=Nil;
Можно сравнивать значения указателей операциями отношения "=" и "<>". Если два указателя равны, значит, они указывают на одну и ту же безымянную переменную.
Можно обращаться к переменной, на которую указывает указатель, с помощью квалификатора "^", который добавляется после имени указателя, либо после квалификатора массива, выделяющего один указатель из массива указателей. Как следует из определения квалификатора, за квалификатором указателя может следовать квалификатор, выделяющий элемент указываемой переменной. Пример:
If p=q^.p then p^:=q^ else p^.i:=q^.i;
Рассмотрим теперь примеры выполнения операций над цепочками безымянных (динамических) переменных. Пусть в программе описаны типы Point и Rec, а также переменные-указатели p и q типа Point, как в примере из предыдущего пункта. Пусть также в процессе работы программы были созданы две динамических цепочки, каждая состоящая из двух записей типа Rec. На начало одной цепочки указывает указатель p, на начало другой – указатель q.
Р
ассмотрим
результат выполнения следующих операций,
для каждой из которых две указанные
цепочки являются исходными.
1) q=p;
Значение указателя p (а это адрес первой переменной в верхней цепочке) заносится в указатель q. В результате указатель q будет указывать на ту же цепочку, что и p.
Н
ижняя
цепочка остается несвязанной ни с одним
указателем. Доступ к ней утерян, а занятая
ей память не освобождена. Потерянная
цепочка становитсямусором
в
динамической памяти. Ситуаций, при
которых образуется мусор, следует
избегать. Как это сделать, рассмотрим
далее.
2) q^=p^;
Значение переменной, на которую указывает указатель p (а это первая переменная-запись в верхней цепочке), заносится в переменную, на которую указывает указатель q. Оба поля, информационное и указательное, в первой переменной нижней цепочки становятся равными соответствующим полям первой переменной верхней цепочки.
З
десь
опять образуется мусор в виде одной
потерянной динамической переменной.
3) q^.i=p^.i;
Значение информационного поля переменной, на которую указывает указатель p, заносится в информационное поле переменной, на которую указывает указатель q.
З
начения
поля-указателя в нижней цепочке не
меняется, безымянные переменные не
теряются.
4) q^.p=p^.p;
З
начение
поля-указателя переменной, на которую
указывает указательp,
заносится
в поле-указатель переменной, на которую
указывает указатель q.
Читателям предлагается самостоятельно определить результат выполнения следующей операции:
5) q^.p=p;
