<!DOCTYPE html>
- Основы программирования. Теория
- Синтаксис и семантика языков программирования. Алфавит языка Delphi Pascal. Cинтаксические диаграммы
- Представление данных в Delphi Pascal: константы и переменные
- Классификация скалярных типов данных, операции над ними
- Классификация типов данных языка
-
- Процедуры и функции порядковых типов данных
- Операции над скалярными типами данных.
- Математические функции
- Совместимость типов данных и операции преобразования типов
- Условный оператор – оператор условной передачи управления – if ... else
- Оператор выбора – case
- Операторы циклов Delphi Pascal
- Поисковый цикл. Неструктурная и структурная реализации поискового цикла.
- Массивы Delphi Pascal
- Строки Delphi Pascal
- Множества Delphi Pascal
- Записи Delphi Pascal
- Процедуры и функции. Определение, описание, особенности. Примеры.
- Структурные типы параметров: параметры-строки, параметры-массивы.
- Принципы разработки универсальных подпрограмм
- Модули Delphi Pascal
- Рекурсия
- Динамическая память
- Динамические структуры данных
- 21. Списковые структуры данных. Классификация и основные приемы работы с ними: создание элемента, добавление элемента к списку, удаление элемента из списка. Область применения списковых структур данных. Пример.
- Работа с файлами
- 22. Основы файловой системы: файл, каталог, дисковод, полное имя файла, внутреннее представление информации в файле. Файловая переменная. Операции открытия и закрытия файлов. Примеры.
- 23. Текстовые файлы. Внутреннее представление информации в файле. Операции над файлами. Пример.
- 24. Типизированные файлы: внутреннее представление информации в файле. Операции над файлами. Пример.
- 25. Нетипизированные файлы. Внутреннее представление информации в файле. Операции над файлами. Пример.
- Классификация типов данных языка
- Объектно-ориентированное программирование
- Технология событийного программирования. События Windows, сообщения и события Delphi. Основные события Delphi. Примеры.
- Ещё полезные вещи
Основы программирования. Теория
Язык: Delphi Pascal.
Синтаксис и семантика языков программирования. Алфавит языка Delphi Pascal. Cинтаксические диаграммы
Синтаксис - совокупность правил, определяющих допустимые конструкции (слова, предложения) языка, его форму.
Семантика – правила, определяющие смысл синтаксически корректных предложений.
Ясная или «интуитивно-понятная» семантика – семантика, позволяющая без большого труда определять смысл программы или «читать» ее.
Алфавит языка программирования Delphi Pascal включает:
- латинские буквы без различия строчных и прописных + символ
_(считается как буква); - арабские цифры:
0,1,2,3,4,5,6,7,8,9; - шестнадцатеричные цифры:
0..9,а..fилиA..F; - специальные символы:
+-*/=:=;и т. д.; - служебные слова:
do,while,begin,endи т. д.
Синтаксис – правила, определяющие допустимые конструкции языка, построенные из символов его алфавита.
Синтаксическая диаграмма — это направленный граф с одним входным ребром и одним выходным ребром и помеченными вершинами. Синтаксическая диаграмма задаёт язык. Цепочка пометок при вершинах на любом пути от входного ребра к выходному — это цепочка языка, задаваемого синтаксической диаграммой.

Представление данных в Delphi Pascal: константы и переменные
Представление данных
- Данные.
- Константы.
- Литералы.
- Поименованные константы.
- Переменные.
- Константы.
В языке Delphi Pascal все данные подразделяются на константы и переменные:
Константы – данные, не изменяемые в процессе выполнения программы.
Константы, в свою очередь, подразделяются на литералы и поименованные константы.
Литералы – константы, указанные непосредственно в тексте программы.
Примеры литералов:
-25,2.5,0.1e6– числовые литералы;$2a– шестнадцатеричное число;true,false– логические константы;'d',#65 = 'A'– символьные константы;'abcd'– строковая константа;nil– адресная константа.
Поименованные константы – константы, обращение к которым выполняется по имени. Объявляются в разделе описаний: const <имя>[: <тип>] = <значение>;.
const
min: byte = 0;
max = 100;
center = (max - min) div 2;
Переменные – поименованные данные, которые могут изменяться в процессе выполнения программы. Объявляются также в разделе описаний: var <имя>[, <имя>]: <тип>;
var
a, b: Integer;
c: Real;
При установленной опции Extended syntax {$X+} (расширенный синтаксис) переменным при объявлении можно задавать начальные значения:
var
a: Integer = 56;
b: Real = 85.25;
Для наложения или же создания абсолютной переменной (которая находится по заданному или абсолютному адресу в памяти) используется служебное слово absolute:
var <имя>: <тип> absoulute <адрес>:<смещение>; или
var <имя>: <тип> absoulute <переменная>;.
//Наложение по абсолютному адресу:
var
a: Word absolute $0000:$00FF; // адрес_сегмента:смещение
c: Byte;
b: Real absolute c; // наложение на ранее определенную переменную;
// обычно используется, когда тип переменной, которая тут `c`, может быть разным.
// (см. нетипизированные параметры)
Тип – описатель данных, который определяет:
- диапазон изменения значения переменной, задавая размер ее внутреннего представления;
- множество операций, которые могут выполняться над этой переменной.
Для объявления новых типов данных используется конструкция: type <имя> = <тип>;:
type
Int = LongInt;
Date = 1..31; // объявление нового типа данных
var
d1: Date; // объявление переменной этого типа
Классификация скалярных типов данных, операции над ними
Классификация типов данных языка
- Тип
- Простой
- Порядковые
- Целые;
- Логические;
- Символ;
- Перечисление;
- Отрезок (Интервал);
- Вещественный
- Вещественные;
- Большое целое;
- Порядковые
- Структурный
- Массив;
- Строка;
- Запись;
- Множество;
- Файл;
- Указатель;
- Простой
-
Целочисленные знаковые типы
Идентификатор Длина, байт Диапазон значений ShortInt,Int81SmallInt,Int162Integer*2-4Зависит от платформы LongInt,Int324NativeInt4-8Зависит от типа процессора Int648 -
Целочисленные беззнаковые типы
Идентификатор Длина, байт Диапазон значений Byte,UInt81Word,UInt162LongWord,Cardinal,UInt32,**DWord4NativeUInt4-8Зависит от типа процессора **,QWordUInt648 -
Вещественные типы
Идентификатор Длина, байт Количество значащих цифр Диапазон значений Single47-8Real48611-12Real*6-8??? Зависит от платформы Double815-16Currency8(4 знака после запятой) Comp819-20Extended*815-16Extended*1019-20 -
Символьные типы
Идентификатор Длина, байт Диапазон значений AnsiChar1#0..#255Char*1-2Зависит от платформы WideChar,**UnicodeChar2#0..#65535 -
Логические типы
Идентификатор Длина, байт Диапазон значений Boolean1False..TrueByteBool1False..TrueWordBool2False..TrueLongBool4False..True -
Перечисления – значения переменных этого типа описываются явно (перечисляются).
type DayOfWeek = (Mon, Tue, Wed, Thu, Fri, Sat, Sun); var d: DayOfWeek; {...} d := Fri; -
Отрезок – значения переменных этого типа входят в определенный диапазон значений стандартного типа.
type Day = 1..31; // значения - числа от 1 до 31 var d: Day; {...} d := 5;
* Зависит от платформы. В Delphi Pascal:
type
Integer = LongInt; // FreePscal: SmallInt
Real = Double; // FreePascal: 6-byte
// Extended (10 bytes)
Char = WideChar; // since Delphi 2009, FreePascal: ANSIChar
** Идентификаторы отсутствуют в Delphi Pascal.
Источники: wiki.freepascal.org 1, wiki.freepascal.org 2, delphibasics.ru.
Процедуры и функции порядковых типов данных
- Функция
ord(x: ordinal): int– возвращает номер значения по порядку (не применима к 64-битным аргументам)ord('A') // 65 - Функция
pred(x: ordinal): int– возвращает предыдущее значение.
Процедураdec(var x: int)– уменьшает значение переменной на1.x := 5; pred(x); // 4 dec(x); // 4 - Функция
succ(x: ordinal): int– возвращает следующее значение.
Процедураinc(var x: int)– увеличивает значение переменной на1.x := 5; succ(x); // 6 inc(x); // 6 - Функция
high(x)– возвращает самое большое значение типа переменнойxили максимальный размер типа строки или массива переменнойx.
Функцияlow(x)– возвращает самое малое значение типа переменнойxили минимальный размер типа строки или массива переменнойx.var x: ShortInt; s: String[42]; m: array [5..35] of ShortInt; {...} writeLn(low(x), ', ', high(x)); // -128, 127 writeLn(low(s), ', ', high(s)); // 0, 42 writeLn(low(m), ', ', high(m)); // 5, 35
Операции над скалярными типами данных.
- Арифметические операции – применяют к вещественным и целым константам и переменным:
+ - * / {вещественное деление} div, mod {целочисленное деление и остаток от целочисленного} - Операции отношения – применяют к числам, символам, строкам для сравнения. Результат – логическое значение:
не равно равно <> = нестрогие строгие < <= > >= - Логические операции – применяют к логическим значениям. Результат логическое значение:
var a, b: Boolean; {...} a := true; b := false; a and b {false}; not a {false}; a xor b {true} a or b {true}; not b {true}; a xor a {false} - Побитовые (поразрядные) операции – выполняются поразрядно, применяют к целым. Результат целое число.
not,and,or,xor,shr(сдвиг вправо),shl(сдвиг влево).var a: Byte; {...} a := 5; not a {побитовая инверсия (НЕ) : 00000101 -> 11111010}; a shl 2 {побитовый сдвиг влево на 2: 00000101 -> 00010100};
Математические функции
(int – абстрактный целочисленный тип, float – абстрактный вещественный тип)
| Имя функции | Тип принимаемого значения | Тип возвращаемого значения | Описание |
|---|---|---|---|
abs(x) |
int или float |
так же, как аргумент | Модуль числа (абсолютное значение числа) |
sqr(x) |
int или float |
так же, как аргумент | Квадрат числа () |
sqrt(x) |
int или float |
float |
Квадратный корень числа () |
exp(x) |
int или float |
float |
Экспонента числа () |
ln(x) |
int или float |
float |
Натуральный логарифм числа |
sin(x) |
int или float |
float |
Синус числа |
cos(x) |
int или float |
float |
Косинус числа |
arctan(x) |
int или float |
float |
Арктангенс числа |
Работа с вещественными числами и генератором псевдослучайных чисел
| Функция | Описание |
|---|---|
int(x: float): int |
Целая часть числа x |
frac(x: float): int |
Дробная часть числа x |
randomize |
Инициализация генератора псевдослучайных чисел |
random: float |
Случайное число r в диапазоне: |
random(x: int): int |
Случайное целое число r в диапазоне: |
Совместимость типов данных и операции преобразования типов
Правила вычисления выражений. Приоритеты
-
Порядок выполнения операций определяется приоритетами и скобками:
Операции Приоритет (порядок выполнения) Унарные +,-,not,@,^1 *,/,div,mod,and,shr,shl2 +,-,or,xor3 Логические =,<>,<,>,<=,>=4 Примеры:
-
При выполнении арифметических операций над числами различных типов автоматически осуществляется неявное преобразование:
- целого и вещественного типов – к вещественному,
- с разными интервалами представлений – к типу с большим интервалом.
var a: Single; k: Integer; {...} a / k; // число k преобразуется к типу Single -
При сравнении вещественных чисел из-за их неточного представления проверку равенства и неравенства следует осуществлять с явным указанием допуска.
var x, y: Single; {...} x <> y ==> abs(x - y) > 1e-10 x = y ==> abs(x - y) < 1e-10
Оператор присваивания :=
Используется для изменения значений переменных.
Формат: <идентификатор_переменной> := <выражение>;
var
v: Integer;
a, b: Single;
{...}
a := v * b / 2.0;
Корректное выполнение оператора предполагает, что результат вычисления и переменная правой части одного типа или совместимы по типу.
По правилам совместимы:
- все целые типы между собой;
- все вещественные типы между собой;
- отрезок базового типа и базовый тип;
- два отрезка одного и того же базового типа;
- символ и строка.
Неявное преобразование типов
Если типы результата и переменной не совпадают, но совместимы, то при выполнении присваивания выполняется неявное автоматическое преобразование.
var
l: LongInt;
e, x: Extended;
i: Integer;
r: Single;
begin
{...}
r := i * e / (x + l); // тип результата выражения `i * e / (x + l)` - Extended,
// но так как тип переменной `r` - Single, то результат автоматически преобразуется в Single.
Если результат не умещается в разрядную сетку переменной, то автоматически генерируется ошибка «Переполнение разрядной сетки».
Исключение! Для получения ошибки переполнения при работе с целыми числами необходимо установить опции компилятора Overflow checking {$Q+} и Range checking {$R+}.
Здесь что-то странное. Немного протестировав, у меня получилось так:
-
При
Overflow checking {$Q+}: если в результате каких-либо арифметических действий или присвоении произойдёт переполнение целочисленного типа, то вызывается ошибка. -
При
Range checking {$R+}: если при присвоении произойдёт переполнение целочисленного типа, то вызывается ошибка.
Явное преобразование типов
Для несовместимых типов результата и переменной, в которую его необходимо занести, при выполнении присваивания необходимо явное преобразование типов, например, посредством специальных функций:
trunc(x: float): intилиint(x: float): int– преобразует вещественное число в целое, отбрасывая дробную часть.round(x: float): int– округляет вещественное число до целого по правилам арифметики.ord(c: ordinal): int– преобразует значение в его номер.chr(x: int): Char– преобразует номер символа в символ.
Условный оператор – оператор условной передачи управления – if ... else
Оператор условной передачи управления используется при обработке вариантов вычислений и реализует конструкцию ветвления.
Формат: if <логическое_выражение> then <оператор> [else <оператор>];
Оператором может быть как простой оператор, так и составной оператор (блок операторов в операторных скобках begin...end)
Оператор выбора – case
Оператор позволяет программировать несколько вариантов решения.
Формат:
case <выражение> of
<константа/диапазон>: <оператор>;
[<константа/диапазон>: <оператор>; ...]
[else <оператор>;]
end;
Пример:
case 1 + 2 * j of
3: z:=sin(x);
-1..1, 10: z:=cos(x);
else z:=0;
end;
Операторы циклов Delphi Pascal
Операторы организации циклов
- Циклы:
- Счётные (
for-loop). - Итерационные (
while-do,repeat-until). - Поисковые.
- Счётные (
Cчетный цикл – цикл, количество повторений которого известно или можно посчитать. Выход из такого цикла программируется по счетчику.
Итерационный цикл – цикл, количество повторений которого неизвестно или считается неизвестным при построении цикла. Выход из цикла программируется по выполнению или нарушению условия.
Поисковый цикл имеет два выхода: нашли и перебрали все и не нашли.
Счётный цикл for-loop
Блок-схема: 
Выполняется конкретное количество раз.
Формат:
for <переменная-счётчик> := <значение_от> to <значение_по> do <оператор>; (если от < по)
for <переменная-счётчик> := <значение_от> downto <значение_по> do <оператор>; (если от > по)
Пример:
var i: Integer;
{...}
for i := 1 to 10 do
begin
x := x + 1;
e := e / 10;
end;
Цикл-пока while-do
Блок-схема:

Выполняется, пока условие истинно.
Формат: while <логическое_выражение> do <оператор>;
Пример:
while abs(e) >= 1e-5 do
begin
x := x + 1;
e := e / 10;
end;
Цикл-до repeat-until
Блок-схема:

Выполняется, до тех пор, пока условие не станет истинно (то есть пока условие ложно).
Формат:
repeat
<оператор>;
[<оператор>; ...]
until <логическое выражение>;
Пример:
repeat
x := x + 1;
e := e / 10;
until abs(e) < 1e-5;
Поисковый цикл. Неструктурная и структурная реализации поискового цикла.
В лекциях конкретного мало было, поэтому попробую расписать самостоятельно …
Поисковый цикл – особый вид цикла, который имеет два случая выхода:
- нашли,
- перебрали все элементы, но не нашли.
Существуют структурная (приведённая к обычному итерационному циклу) и неструктурная реализации данного цикла.
- Задача для примера:
- определить сумму ряда с заданной точностью .
(Рекуррентная формула последовательности: ).
- определить сумму ряда с заданной точностью .
Неструктурная реализация поискового цикла
Примерный общий вид неструктурной реализации поискового цикла:
var
found: boolean;
{...}
found := false;
while true do
begin
{операторы, выполняемые до проверки}
if {проверка на то, нашли ли необходимое} then begin
found := true; // ставим флаг, что нашли
break; // прерываем цикл
end;
if {проверка на то, не перебрали ли всё} then
break;
{операторы, выполняемые после проверки}
end;
if found then
{нашли}
else
{не нашли}
-
Решение примера:
-
Блок-схема:

-
Код:
var x, eps, s, r: Double; begin readLn(x, eps); s := 0; r := 1; while true do begin s := s + r; if abs(r) <= eps then break; r := -r / x; end; writeLn(x, ' ', s); end.
-
Структурная реализация поискового цикла №1 (через while-do)
Примерный общий вид структурной реализации поискового цикла:
var
found: boolean;
{...}
{операторы, выполняемые до проверки}
found := {нашли ли необходимое};
while not (found) and not ({не перебрали ли всё}) do
begin
{операторы, выполняемые после проверки}
{операторы, выполняемые до проверки}
if {нашли ли необходимое} then
found := true; // ставим флаг, что нашли
end;
if found then
{нашли}
else
{не нашли}
-
Решение примера:
-
Блок-схема:

-
Код:
var x, eps, s, r: Double; begin readLn(x, eps); s := 0; r := 1; s := s + r; while abs(r) > eps do begin r := -r / x; s := s + r; end; writeLn(x, ' ', s); end.
-
Структурная реализация поискового цикла №2 (через repeat-until)
Примерный общий вид структурной реализации поискового цикла:
var
found: boolean;
{...}
found := false;
repeat
{операторы, выполняемые после проверки}
{операторы, выполняемые до проверки} // !!!
// тут отличается от первой структурной реализации:
// выполнится в первый раз в любой случае, в отличие от первой реализации!
if {нашли ли необходимое} then
found := true; // ставим флаг, что нашли
until (found) or ({всё перебрали});
if found then
{нашли}
else
{не нашли}
-
Решение примера:
-
Блок-схема:

-
Код:
var x, eps, s, r: Double; begin readLn(x, eps); s := 0; r := 1; repeat s := s + r; r := -r / x; until abs(r) <= eps; writeLn(x, ' ', s); end.
-
Я мог что-то неправильно понять из того, что является структурными и неструктурным поисковым циклом, поэтому советую проверить самому.
Массивы Delphi Pascal
Массив – это упорядоченная совокупность однотипных данных. Каждому элементу массива соответствует один или несколько индексов порядкового типа, определяющих положение элемента в массиве.
Формат: array [<типы индекса>] of <тип элемента> (типы индекса перечисляются через запятую, если их больше одного).
Количество типов индексов задает размерность массива.
Тип индекса – порядковый – определяет доступ к элементу.
Тип элемента – любой кроме файла, в том числе массивы, строки и т.п.
Массив в памяти не может занимать более 2 Гб (из-за технических ограничений).
Кажется, потому, что это связано с технической проблемой выделить для 32-битной системы один кусок памяти больше, чем для 32-битного указателя, то есть для одного сегмента, но половина предназначена для системы. Поэтому в языке Pascal установлено жёсткое ограничение на 2 ГБ памяти.
Примеры объявления массива:
type
mas = array[1..10] of Integer;
var
a: array[1..5] of Integer;
с: array[’A’..’C’, -5..-3] of Byte;
b: array[Byte] of Char;
Инициализация массива при объявлении:
var
a: array[1..5] of Real = (0, -3.6, 7.8, 3.789, 5.0);
b: array[Boolean, 1..5] of Real = ((0, -3.6, 7.8, 3.789, 5.0),
(6.1, 0, -4.56, 8.9, 3.0));
Операции над массивами
- Операция присваивания (только для массивов одного типа):
var a, b: array[Boolean] of Real; c: array[Boolean] of Real; {...} b := a; c := a; // ОШИБКА! Их типы считаются разными, так как объявлены раздельно, // несмотря на то, что по факту они идентичны! - Доступ к элементу массива (прямой и косвенный доступ):
var a: array[Char, Boolean] of Real; {...} a[’A’, true] := 5.1; {прямой доступ} {...} ch := ’B’; b := false; a[ch, b] := 3; {косвенный доступ: значения индексов находятся в переменных} - Ввод/вывод массивов осуществляется поэлементно:
Вывод матрицы:var a: array[1..5] of Real; {...} for i := 1 to 5 do read(a[i]); readLn; {обрабатывает последний Enter}var a: array[1..5, 1..7] of Real; {...} for i := 1 to 5 do begin for j := 1 to 7 do write(a[i][j]); // также можно a[i, j] {a[i][1], a[i][2], a[i][3], a[i][4], a[i][5], a[i][6], a[i][7]} writeLn; {переход на следующую строку} end;
Строки Delphi Pascal
Строка – последовательность символов (фактически, массив символов).
Формат (обычно): string или string[<размер>], где размер – максимальная длина строки.
Внутренний формат:

Здесь нужно сделать небольшое отступление насчёт длинных строк
С более новых версий языка Pascal существует несколько видов строк, поэтому тип string зависит от платформы.
В Delphi Pascal (с версии Delphi 2009):
| Тип | Максимальная длина | Размер | Размер символа | Описание |
|---|---|---|---|---|
ShortString |
255 | 256 байт | 1 байт | Является псевдонимом для string[255] (с фиксированной длиной) |
AnsiString |
* | 4 Б – 2 ГБ* | 1 байт | Длинные, динамические строки, но с однобайтовыми символами |
UnicodeString |
* | 4 Б – 2 ГБ* | 2 байта | Длинные, динамические строки с двухбайтовыми символами. В среде разработки RAD Studio string (без размера!) является псевдонимом для UnicodeString |
WideString |
* | 4 Б – 2 ГБ* | 2 байта | Кажется, какой-то старый костыль, который был до UnicodeString. Использовать не рекомендуется |
При использовании string[<размер>] используется тип ShortString, но с размером <размер>, то есть строка фиксированной длины, меньшей 256, и символом, размером в 1 байт.
При использовании string (без размера) используется по умолчанию UnicodeString.
* Ограничение в 2 ГБ по тем же причинам, что и с массивами.
Также включить или отключить (кажется, только для старых версий) переопределение string на длинные строки можно с помощью опций компилятора:
| Включить | Выключить |
|---|---|
{$H+} |
{$H-} |
{$LONGSTRINGS ON} |
{$LONGSTRINGS OFF} |
Источник: docwiki.embarcadero.com
Примеры описания строк:
var
s1, s2: string[40];
s3: string;
type
S40 = string[40];
ST = string;
var
s1, s2: S40;
s3: ST;
var
s: string[40] = 'String-constant';
s1: string = '';
Операции над строками
-
Присваивание строк:
s1 := 'ABCD'; s1 := s2; s1 := 'A'; s1 := ''; {пустая строка} -
Обращение к элементу:
s1[5] {прямое} s1[i] {косвенное} -
Конкатенация (сцепление) строк:
str := str + 'A'; str := 'A' + 'BC'; -
Операции отношения – выполняется попарным сравнением кодов символов, результат определяется по отношению кодов первых различных символов:
s1 := 'ABCD'; s2 := 'ABCA'; b := s1 > s2; // true, так как 4: 'D' > 'A' 'T' < 'Ta'; // true, так как размер первой строки меньше -
Ввод-вывод строк:
readLn(s1); // Строка вводится до Enter (переноса строки, пропуская сам перенос) // или максимальной длины writeLn(s1);
Стандартные процедуры и функции для работы со строками
-
Функция
length(str: string): word– возвращает длину строкиstr:n := length(s); -
Процедура
delete(var str: string; i, k: int)– удаляетkсимволов строкиstr, начиная сi-го символа:s := 'aabbbbccccc'; delete(s, 3, 4); // s = 'aaccccc'' -
Процедура
insert(sub: string; var str: string; i: int)– вставляет подстрокуsubв строкуstr, начиная с символа с номеромi:my_string := 'aaacc'; sub_str := 'bbbb'; insert(sub_str, my_string, 4); // 'aaabbbbcc' insert('Pas', my_string, 6); // 'aaabbPasbbcc' -
Процедура
str(x[:w[:d]], var str)– преобразует результат выраженияx, в строкуstr, содержащую запись этого числа в виде последовательности символов (как при выводе):x := -5.67; str(x:7:3, s); // s = ' -5.670' -
Процедура
val(str, var x, var status_code)– преобразует строкуstrс записью числа в виде последовательности символов во внутреннее представление целого или вещественного числа и помещает его в переменнуюx. В целочисленной переменнойstatus_codeпроцедура возвращает код ошибки:var s: string; a: real; code: integer; {...} repeat write('Input a: '); readLn(s); val(s, a, code); if code <> 0 then writeLn('Wrong input!'); until code = 0; -
Функция
copy(str: string; i, k: int): string– возвращает фрагмент строкиstr, длинойkсимволов, начиная сi-го символа:str := 'qqqEEEEEEuuuuu'; s := copy(str, 4, 6); // 'EEEEEE' -
Функция
pos(sub, str: string): int– возвращает номер позиции первого вхождения подстрокиsubв строкуstr. Если вхождение не найдено, то функция возвращает0:str := 'qqqEEррEEuuuuu'; i := pos('EE', str); // i = 4 j := pos('X', str); // j = 4 -
Функция
upCase(c: char): char– возвращает символ, соответствующий символу верхнего регистра дляc, если таковой имеется, либо сам символc, если для него не определен символ верхнего регистра.
Кажется, противоположной функции
downCaseилиlowerCaseнет.
Множества Delphi Pascal
Множество – неупорядоченная совокупность неповторяющихся элементов.
Формат: set of <базовый_тип>.
Тип элементов – порядковый, но количество элементов не должно превышать 256. (То есть нельзя использовать Word, Integer, UInt64 и т. д., так как они явно больше 256)
type
Digits = set of 1..100;
SetChar = set of Char;
Letter = set of 'a'..'z';
var
mychar: SetChar;
mydig: Digits;
simst: Letter;
// or
number: set of 1..31;
cif: set of 0..9;
codes: set of #0..#255;
Конструкторы и инициализация множеств
Конструкторы множеств – константы множественного типа:
[] -- пустое множество;
[2, 3, 5, 7, 11] -- множество чисел;
[’a’, ’d’, ’f’, ’h’] -- множество символов;
[1, k] -- множество чисел, переменная k должна содержать число;
[2..100] -- множество содержит целые числа из указанного интервала;
[k..2 * k] -- интервал можно задать выражениями;
[red, yellow, green]- множество перечисляемого типа.
Инициализация множеств при объявлении:
type
SetNum = set of Byte;
var
s: SetNum = [1..10];
Операции над множествами
-
Присваивание:
A := B; A := []; -
Объединение, пересечение и дополнение:
A + B() – объединение множествАиB– множество, состоящее из элементов, принадлежащих множествамАиB.A * B() – пересечение множествАиB– множество, состоящее из элементов, принадлежащих одновременно и множествуАи множествуB.A - B() – дополнение множестваАдоB– множество, состоящее из тех элементов множестваА, которые не принадлежат множествуB.
[1, 2] + [3, 4] = [1, 2, 3, 4]; [1..10] * [3, 8, 9 ,15, 23, 45] = [3, 8, 9]; [1..15] - [3, 8, 9, 15, 23, 45] = [1, 2, 4..7, 10..14] [red, blue, green, black] * [blue, magneta, yellow] = [blue] -
Операции отношения:
A = B() – проверка совпадения множеств А и B (если совпадают –true).A <> B() – проверка не совпадения множеств А и B (не совпадают –true).A <= B() – проверка нестрогого вхождения A в B (если входит –true).A > B() – проверка строгого вхождения B в A (если входит –true).
- Проверка вхождения элемента во множество:
x in A() – входит ли элементxв множествоA(если входит –true).[1, 2] + [3, 4] = [1, 2, 3, 4]; [1..10] * [3, 8, 9 ,15, 23, 45] = [3, 8, 9]; [1..15] - [3, 8, 9, 15, 23, 45] = [1, 2, 4..7, 10..14] [red, blue, green, black] * [blue, magneta, yellow] = [blue]
Ввод-вывод элементов множеств
Значения множественного типа нельзя вводить и выводить!
-
Ввод элементов множества:
var s: set of 1..100; n: Word; {...} s := []; read(n); while n <> 0 do begin s := s + [n]; read(n); end; readLn; {...} -
Вывод элементов множества:
var s: set of 1..100; {...} s := []; for item := 'a' to 'z' do if item in s then write(i: 3); writeLn;
Записи Delphi Pascal
Запись – это структура данных, образованная фиксированным числом разнотипных компонентов, называемых полями записи
Формат:
type
<имя> = record
<переменные>: <тип>; // фиксированная часть
{--//--}
[case [тэг:] [набор_типов] of // вариантная часть
<тип>: (
<переменные>: <тип>;
{--//--}
);
{--//--}
]
end;
Примеры:
var
rec1: record
day: 1..31;
month: 1..12;
year: Word;
end;
type
Data = record
day: 1..31;
month: 1..12;
year: Word;
end;
var
rec1: Data;
birthDay: Data = (day: 30; month: 6; year: 1973);
type
EntryType = (Book, Magazine);
Entry = record
autor, title: String;
year : 1..2000;
case tag: EntryType of
Book: (publisher, city: String);
Magazine: (
magName: String;
volume, issue: Integer
); // case не имеет своего end'а и пишется последним.
end;
var
e: Entry;
{...}
e.tag := Book; // вариант записи: Book
e.autor := 'Thomas Hobbes';
e.title := 'Leviathan';
e.year := 1651;
// Как бы предназначены для варианта Book записи Entry:
e.publisher := 'Andrew Crooke';
e.city := 'London';
Подробнее про вариативную часть: informatics.mccme.ru
Операции над записями
- Присваивание записей одного типа:
type Date = record day: 1..31; month: 1.12; year: Word; end; var a, b: Date; c: Date; d, e: record day: 1..31; month: 1.12; year: Word; end; {...} a := b; b := c; a := c; d := e; a := d; // ОШИБКА! Считаются разными типами! e := c; // ОШИБКА! Считаются разными типами! - Доступ к полям записи
a.day := 21; {точечная нотация}with a do {оператор доступа} day := 27; with b do begin {оператор доступа c блочным оператором} day := 22; month := 6; year := 1983; end; - Ввод и вывод записей осуществляется по полям.
Процедуры и функции. Определение, описание, особенности. Примеры.
Процедуры и функции – самостоятельные фрагменты программы, соответствующим образом оформленные и вызываемые по имени (программные блоки).
Общий вид программного блока: Заголовок блока -> Раздел описаний -> Раздел операторов
Различия между процедурой и функцией
Процедура
Заголовок начинается с служебного слова procedure.
После работы процедура не возвращает значений.
Общий вид:
procedure <идентификатор> [(<паратметры>)];
[var
<локальные переменные>;]
begin
<операторы>;
end;
Пример заголовка
procedure alpha(x: Integer);
Функция
Заголовок начинается с служебного слова function и заканчивается возвращаемым типом. После работы функции, она возвращает значение типа, который указан в заголовке как возвращаемый.
Общий вид:
function <идентификатор> [(<паратметры>)]: <возвращаемый тип>;
[var
<локальные переменные>;]
begin
<операторы>;
end;
Пример заголовка:
function func(x: Integer): Double;
Чтобы вернуть какое-то значение из функции, в процессе её выполнения необходимо присвоить системной переменной <идентификатор_функции> (или result, при включенном расширенном синтаксисе {$X+}) это необходимое значение.
Пример возврата значения:
{$X+}
function hypot(a, b: Double): Double;
var
c_sqr, c: Double;
begin
c_sqr := sqr(a) + sqr(b);
c := sqrt(c_sqr);
result := c; // или `hypot := sqrt(c_sqr);`
writeLn('Hypot is ', c);
end;
Локальные и глобальные переменные, законы «видимости» идентификаторов
| Классы переменных | Время жизни | Доступность |
|---|---|---|
| Глобальные – объявленные в основной программе | От запуска до завершения программы | Из любого места программы, включая подпрограммы* |
| Локальные – объявленные в подпрограмме | От вызова подпрограммы до возврата управления | Из подпрограммы и подпрограмм, вызываемых из нее* |
* – при отсутствии перекрытия имен
Способы передачи данных в подпрограмму на Delphi Pascal
Подпрограмма может получать данные из основной программы:
- неявно – с использованием свойства доступности глобальных переменных;
- явно – через параметры.
Очевидно, что явная передача значительно лучше, так как позволяет делать подпрограммы более универсальными и независимыми.
Формальные и фактические параметры подпрограмм Delphi Pascal
Параметры, описанные в заголовке – формальные.
При вызове подпрограммы необходимо определить фактические значения этих параметров – аргументы (константы и переменные).
Вот только кто вообще их так называет?
Обычно их называют параметрами и аргументами соответственно.
Формальные и фактические параметры должны соответствовать по количеству, типу и порядку:
function proc(a: Integer; b: Single): Byte;
{...}
n := proc(5, 2.1); // a = 5, b = 2.1
Типы параметров, const/var-переменные
-
Параметры-значения при описании подпрограммы не помечаются. По факту в эту переменную копируется значение переданного аргумента, поэтому изменение этой переменной в подпрограмме не отразится на внешней.
function beta(x: Integer; n: Byte): Integer; begin x := x - 5; beta := x * n; end; {...} a := 6; writeLn(beta(a, 3)); // 3 writeLn(a); // 6 -
Параметры-переменные при описании подпрограммы помечаются служебным словом
var.
По факту происходит передача переменной по адресу, то есть все изменения такой переменной в подпрограмме отразятся на внешней!function alpha(var x: Integer; n: Byte): Integer; begin x := x - 5; alpha := x * n; end; {...} a := 6; writeLn(alpha(a, 3)); // 3 writeLn(a); // 1Ограничение: в качестве фактических значений (аргументов) параметров-переменных нельзя использовать литералы!
alpha(6, 3) // Ошибка! -
Параметры-константы при описании подпрограммы помечаются служебным словом
const.
Как и с параметрами-переменными, по факту происходит передача переменной по адресу, но при попытке изменить значение переменной в подпрограмме, вызывается ошибка. То есть изменять значение в подпрограмме запрещено.function gamma(const x: Integer; n: Byte): Integer; begin x := x - 5; // ОШИБКА gamma:= x * n; end; {...} a := 6; writeLn(gamma(a, 3)); // ОШИБКА writeLn(a); // -
Ограничение: в качестве фактических значений (аргументов) параметров-переменных нельзя использовать литералы!
Структурные типы параметров: параметры-строки, параметры-массивы.
Структурные типы параметров должны быть предварительно объявлены.
type
IntArr = array[1..100] of Integer;
MyStr = string[25];
function sum(arr: IntArr; n: Integer): integer;
{...}
procedure test_string(str: MyStr);
{...}
var
my_arr: IntArr;
my_str: MyStr;
{...}
begin
{...}
writeLn('Sum(arr) = ', sum(my_arr, n));
test_string(my_str);
end.
Принципы разработки универсальных подпрограмм
Открытые массивы
Открытый массив – конструкция описания типа массива без указания типа индексов.
Используется только при объявлении формальных параметров.
array of Single;
array of Integer;
С помощью открытых массивов можно делать более универсальные подпрограммы.
Индексы открытого массива всегда начинаются с 0-го.
Размер можно:
- передать через дополнительный параметр;
- получить, используя функцию
high(<идентификатор_массива>).
Открытые строки
Для строк, передаваемых в подпрограмму как параметр-переменная, осуществляет контроль длины строки.
Чтобы избежать его необходимо использовать «открытые» строки (openstring).
Или можно использовать параметр{$P+}, который сам будет делать так, что параметрами будут открытые строки
Пример. Программа, формирующая строку из букв латинского алфавита.
unit Stroka;
interface
procedure add(var s: Openstring);
implementation
procedure add;
var
ch: Char;
begin
ch := s[length(s)];
s := s + chr(succ(Ord(Ch)));
end;
end.
program Ex4_6;
{$APPTYPE CONSOLE}
uses
SysUtils, Stroka in 'Stroka.pas';
var
s: String[26];
i: Integer;
begin
s := 'A';
for i := 2 to 26 do
add(s);
writeLn(s);
readLn;
end.
Протестировав такое, у меня без этих “открытых” строк проблем не возникло. Скорее всего, из-за того, что сейчас, в новых версиях, обычные строки всегда считаются “длинными” (
UnicodeString), поэтому и проблем сейчас с передачей строк нет:
Note: The$Pdirective is obsolete. Now the default string is long (UnicodeString). You should not have to use{$OPENSTRINGS}in any new applications you write.
Источник: docwiki.embarcadero.com
Нетипизированные параметры.
Нетипизированные параметры – параметры-переменные, тип которых при объявлении не указан.
Для приведения нетипизированного параметра к определенному типу можно использовать:
-
автоопределенное преобразование типов:
procedure proc(var a); {...} b := Integer(a) + 10; -
наложенное описание переменной определенного типа:
type TType = (TReal, TInteger); procedure proc(var a; t: TType); var r: Real absolute a; i: Integer absolute a; {...} if t = TReal then {используем переменную `r`} else {используем переменную `i`}По факту, тут
aявляется ссылкой на какой-то адрес в памяти, но нужный размер в памяти нам неизвестен. С помощью наложения мы делаем несколько видов переменных, накладывая на адрес переменнойaразные типы.
Параметры процедурного типа
Параметры процедурного типа используются для передачи в подпрограмму имен процедур и функций.
Для объявления процедурного типа используется заголовок подпрограммы, в котором отсутствует имя:
type
Proc = procedure (a, b, c: Real; var d: Real);
UnaryFunc = function(x: Double): Double;
Значениями переменных процедурных типов являются идентификаторы процедур и функций с соответствующими заголовками:
{...}
function fun1(x: Double): Double;
{...}
procedure test_function(f: UnaryFunc);
begin
if f(0) > 0 then // какая-то проверка функции
{...}
end;
var
f: UnaryFunc;
{...}
f := fun1;
test_function(f); // или test_function(fun1);
Модули Delphi Pascal
Модуль – это автономно компилируемая коллекция программных ресурсов, предназначенных для использования другими модулями и программами
Ресурсы – переменные, константы, описания типов и подпрограммы.
Все ресурсы, определенные в модуле делят на:
- внешние – предназначенные для использования другими программами и модулями.
- внутренние – предназначенные для использования внутри модуля.
Структура модуля:
unit <имя_модуля>; // Имя модуля должно совпадать с
// именем файла, в котором он описан.
interface
<интерфейсная_секция>
implementation
<секция_реализации>
[initialization
<секция_инициализации>
[finalization
<секция_завершения>]]
end.
Подключение модуля к программе
Подключение модуля к программе осуществляется по имени:
uses <имя_модуля1>, <имя_модуля2>, {...};
Объявление модулей в файле проекта
Только для проектов (Delphi, Lazarus). Для обычных программ формата
.pasне работает.
Если:
- к проекту подключается модуль, который находится в каталоге, не совпадающем с каталогом проекта и не указанном в путях компилятора;
- в путях компилятора имеется несколько модулей с одинаковыми именами,
то необходимо указать местонахождение модуля:
uses Strings in 'C:\Classes\Strings.pas'; {абсолютный путь}
// или
uses Strings in '..\Strings.pas'; {относительный путь}
Законы видимости идентификаторов. Доступ к «перекрытым» идентификаторам
Ресурсы модуля перекрываются ресурсами программы и ранее указанных модулей.
Для доступа к перекрытым ресурсам модуля используют точечную нотацию: <имя_модуля>.<имя_ресурса>
Пример:

unit A;
interface
var x: Real; // !!!
{...}
end.
program ex;
uses A;
var x: Integer; // !!!
begin
x := 10;
A.x := 0.45;
{...}
Рекурсия
Рекурсия – организация вычислений, при которой процедура или функция обращаются к самим себе.
Различают явную и косвенную рекурсии.
При явной – в теле подпрограммы существует вызов самой себя, при косвенной – вызов осуществляется в подпрограммах, вызываемых из рассматриваемой.
Косвенная рекурсия требует предопределения forward:
procedure B(j: Byte); forward;
procedure A(j: Byte);
begin
{...} B(i); {...}
end;
procedure B;
begin
{...} A(i); {...}
end;
Структура рекурсивной подпрограммы

«Операторы после вызова», выполняются после возврата управления из рекурсивно вызванной подпрограммы.
Фрейм активации
Каждое обращение к рекурсивной подпрограмме вызывает независимую активацию этой подпрограммы.
Совокупность данных, необходимых для одной активации рекурсивной подпрограммы, называется фреймом активации.
Фрейм активации включает
- локальные переменные подпрограммы;
- копии параметров-значений;
- адреса параметров-переменных и параметров-констант (4 байта);
- копию строки результата (для функций типа
string); - служебную информацию ( байт, точный размер этой области зависит от способа передачи параметров).
Пример.
Задача: переворот заданной строки.
-
/// pointer: 4 bytes; string[255]: 256 bytes function reverse1(const st: string): string; begin if length(st) = 0 then result := ‘‘ else result := reverse1(copy(st, 2, length(st) - 1)) + st[1]; end;Фрейм активации:
-
/// pointer: 4 bytes; longint: 4 bytes procedure reverse2(var ss: string; n: integer); var temp: char; begin if n <= length(ss) div 2 then begin temp := ss[n]; ss[n] := ss[length(ss) - n + 1]; ss[length(ss) - n + 1] := temp; reverse2(ss, n + 1); end; end;Фрейм активации:
Древовидная рекурсия. Перестановки


https://mermaid-js.github.io/mermaid-live-editor
Динамическая память
Минимальная адресуемая единица памяти – байт.
Физический адрес – номер байта оперативной памяти.
Адресация по схеме «база+смещение»: ,
где – адрес базы – адрес, относительно которого считают остальные адреса;
– смещение – расстояние от базового адреса до физического.
Указатель – тип данных, используемый для хранения смещений.
В памяти занимает 4 байта, адресует сегмент размером ГБ.
Базовый адрес = адрес сегмента.
Типизированные и нетипизированные указатели
Различают указатели:
- типизированные – адресующие данные конкретного типа;
- нетипизированные – не связанные с данными определенного типа.
Объявление типизированного указателя: ^<идентификатор_базового_типа>
Объявление нетипизированного указателя: Pointer
type
TPI = ^Integer;
var
pi: TPI;
pr: ^Real;
p: Pointer
type
PP = ^Person; // Можно объявлять указатель типа, который объявлен следом
Preson = record
name: String;
next: PP;
end;
var
r: ^Integer = nil;
Операции с указателями
-
Присваивание. Допускается присваивать указателю только значение того же или неопределенного типа.
var p1, p2: ^Integer; p3: ^Real; p: Pointer; {...} p1 := p2; p := p3; p1 := p; p1 := nil; p := nil; {нельзя: p3 := p2; p1 := p3;} -
Получение адреса: оператор
@. Результат операции – указатель типаpointer– может присвоен любому указателю.var i: Integer; pi: ^Integer; {...} pi := @i; -
Доступ к данным по указателю (операция разыменования). Полученное значение имеет тип, совпадающий с базовым типом данных указателя. Нетипизированные указатели разыменовывать нельзя.
j := pi^; pi^ := pi^ + 2; -
Операции отношения: проверка равенства
=и неравенства<>.sign := p1 = p2; if p1 <> nil then {...}
Функции для работы с указателями
-
Функция
addr(x): Pointer– возвращает адрес объектаx, в качестве которого может быть указано имя переменной, функции, процедуры. Фактически,addr(x)@x.ptr := addr(obj); // <-> ptr := @obj; -
Функция
assigned(const p): Boolean– проверяет, присвоено ли значение указателю. Фактически,assigned(p)p <> nil.ptr := addr(obj); // <-> ptr := @obj; -
Функция
ptr(address: Integer): Pointer– преобразует число в указатель.var a: Integer; p: Pointer; {...} p := ptr(a);
Динамическое распределение памяти
Управление выделением и освобождением памяти осуществляется посредством специальных процедур и функций:
-
Процедура
new(var p: ^<тип>)– выделяет память для размещения переменной, размер определяется типом указателя. -
Процедура
dispose(var p: ^<тип>)– освобождает выделенную память.var pi: ^Integer; {...} writeLn(assigned(pi)); // false new(pi); pi^ := 5; dispose(pi); writeLn(assigned(pi)); // true (так как pi <> nil) -
Процедура
getMem(var p: Pointer; size: Integer)– выделяет указанное количество памяти и помещает ее адрес в указатель. -
Процедура
freeMem(var p: Pointer[; size: Integer])– освобождает выделенную память. -
Процедура
sizeOf(x): Integer– возвращает размер объекта в байтах.var buffer: ^array[1..100] of Byte; {...} getMem(buffer, sizeOf(buffer)); buffer^[1] := 125; {...} freeMem(buffer, sizeOf(buffer));
Динамические структуры данных
Пример последовательных: вектор, матрица, строка, запись, очередь, стек, дек.
Пример древовидных: бинарные деревья.
Динамические линейные структуры
- Очередь – структура данных, реализующая: добавление – в конец, а удаление – из начала.
- Стек – структура данных, реализующая: добавление и удаление с одной стороны.
- Дек – структура данных, реализующая: добавление и удаление с двух сторон.
Списки
Список – способ организации данных, предполагающий использование указателей для определения следующего элемента.
Элемент списка состоит из двух частей: информационной и адресной.
Информационная часть содержит поля данных.
Адресная – включает от одного до n указателей, содержащих адреса следующих элементов. Количество связей, между соседними элементами списка определяет его связность: односвязные, двусвязные, n-связные.
Виды списков
21. Списковые структуры данных. Классификация и основные приемы работы с ними: создание элемента, добавление элемента к списку, удаление элемента из списка. Область применения списковых структур данных. Пример.
Работа с файлами
Файловая система
Файл – поименованная последовательность элементов данных (компонентов файла), хранящихся, как правило, во внешней памяти.
Как исключение данные файла могут не храниться, а вводиться с внешних устройств (ВУ), например клавиатуры или выводиться на ВУ.
Полное имя файла включает:
<Имя диска>:<Список имен каталогов>\<Имя файла>.<Расширение>
Имя файла в Windows составляют из строчных и прописных букв латинского и русского алфавитов, арабских цифр и некоторых специальных символов, например, символов подчеркивания _ или доллара $
Файлы Delphi Pascal
Файл языка Pascal – последовательность однотипных компонентов: файл записей, файл целых чисел, файл строк.
В зависимости от типа компонентов различают три типа файлов: типизированные, текстовые и нетипизированные.
Количество компонентов файла при объявлении файловой переменной не указывается.
Максимальный размер файла определяется свободным пространством на устройстве, например, диске.
Физически операции ввода-вывода с файлами выполняются с использованием буфера.
Для файлов принципиально возможен не только последовательный, но и произвольный доступ, при котором чтение информации осуществляется из указанного места.
Указатель файла
Доступ к компонентам файла осуществляется через указатель файла.
При выполнении операции чтения или записи указатель автоматически перемещается на следующий компонент.
После вывода последнего компонента файла система пишет специальную запись – маркер «Конец файла» (байт #26).
При обнаружении во время операции чтения маркера конца файла – операция завершается. Попытка читать маркер вызывает прерывание по ошибке чтения.
Описание файловых переменных
- Типизированные файлы:
file of <тип> - Текстовые файлы:
text - Нетипизированные файлы:
file
Использование файлов в качестве параметров подпрограмм
Файлы можно передавать в подпрограмму только через параметры-переменные.
type
FF = file of Integer;
procedure print(var f1: FF);
Работа с файлами
Работа с файлами включает:
- инициализацию файловой переменной – установление связи файловой переменной с файлом;
- открытие файла – подготовку файла для выполнения операций ввода-вывода;
- обработку компонентов файла – выполнение операций ввода-вывода элементов данных;
- закрытие файла.
Инициализация файловой переменной
Процедура assign или assignFile (var f; path: String) (предпочтительнее) – связывает файловую переменную f с файлом, имя которого указано в строке path.
Если файл находится в текущем каталоге, то достаточно задать имя файла и его расширение. В противном случае необходимо указать полное имя файла.
type
FI1 = file of Integer;
var
f1, f2: FI1;
{...}
assignFile(f1, ’F1.dat’); {файл в текущем каталоге, относительный путь}
assignFile(f2, ’d:\iva\a.dat’); {файл в другом каталоге, абсолютный путь}
Открытие файла
При открытии файла необходимо задать направление передачи данных: запись или чтение. Кроме того текстовый файл можно открыть для добавления компонентов.
-
Процедура
reSet(var f)– открывает файл для чтения данных.
Устанавливает указатель файла на первый компонент. Если файл не существует, выдается сообщение об ошибке. -
Процедура
reWrite(var f)– открывает файл для записи.
Если указанный файл существовал, то он уничтожается без выдачи предупреждения пользователю, иначе он создается и указатель устанавливается на начало. -
Процедура
append(var f: Text)– открывает текстовый файл для добавления данных.
Указатель файла устанавливается на конец файла.
Контроль операций ввода-вывода
Функция IOResult: Word – возвращает код завершения операции ввода-вывода: 0 – если операция прошла нормально, код ошибки, если нет. Функция применяется при отключенном контроле операций ввода-вывода {$I-}.
Пример. Проверка существования файла.
var
f: file of char;
begin
assignFile(f,’a.dat’); {инициализация ф. п.}
{$I-} {отключение контроля ошибок ввода-вывода}
reSet(f); {открытие файла для чтения}
{$I+} {включение контроля ошибок ввода-вывода}
if IOResult <> 0 then
writeLn('File was not found')
else
writeLn('File was found');
{...}
Обработка компонентов файла
Основные операции над компонентами – операции записи и чтения. На базе этих операций выполняют более сложные операции:
- создание файла – занесение в файл требуемых записей;
- модификация файла – изменение всех или нескольких записей, добавление и удаление записей;
- поиск нужной информации в файле.
Операции записи и чтения для каждого типа файла осуществляется по-своему.
Закрытие файла
Процедура close или closeFile(var f) - выполняет закрытие файла. При этом вновь созданный файл регистрируется в каталоге.
Процедура закрытия файла обеспечивает вывод оставшихся компонентов из буфера в файл.
Связь файловой переменной с файлом при закрытии сохраняется, поэтому при продолжении обработки повторно процедуру assignFile() можно не выполнять.
Стандартные процедуры и функции обслуживания файлов (библ. System)
-
Процедура
reName(var f; name: string)– выполняет переименование файлаf, гдеname– новое имя файла.
При совпадении нового имени файла с ранее существовавшим выдается сообщение об ошибке. -
Процедура
erase(var f)– выполняет удаление файла. Перед уничтожением файл должен быть закрыт. -
Функция
EOF(var f): Boolean– проверяет конец файла, возвращаетTRUE, если указатель стоит после последней записи иFALSE, если нет.
Другие функции обслуживания файлов см. Help.
Текстовые файлы
Текстовый файл – файл, компонентами которого являются символьные строки переменной длины, заканчивающиеся специальным маркером – маркером «Конец строки».
Текстовые файлы используют для хранения и обработки символов, строк, символьных массивов. Числовые и логические данные при записи в текстовые файлы должны преобразовываться в символьные строки.
Текстовый файл можно открыть для записи, чтения и добавления записей в конец. Файл, открытый для записи, не может использоваться для чтения и наоборот.
Стандартные текстовые файлы
Программе, работающей в консольном режиме, без объявления, инициализации файловой переменной и открытия доступны два стандартных текстовых файла, связанных с логическими устройствами ввода и вывода:
INPUT – файловая переменная для обозначения файла данных, вводимых с клавиатуры;
OUTPUT – файловая переменная для обозначения файла данных, выводимых на экран.
Процедуры и функции обработки текстовых файлов
-
Функция
EOLn([var f]): Boolean– возвращаетTRUE, если во входном текстовом файле достигнут маркер конца строки; при отсутствии файловой переменной проверяется файлINPUT, связанный с клавиатурой.- При работе с клавиатурой функция
EOLnвозвращаетTRUE, если последним считанным был символ#13. - При работе с диском функция
EOLnвозвращаетTRUE, если следующим считанным будет символ#13.
- При работе с клавиатурой функция
-
Процедура
read([var f: text;] v1, v2, {...} vn)– обеспечивает ввод символов, строк и чисел. При вводе чисел пробелы и символы табуляции игнорируются. Если файловая переменная не указана, то ввод осуществляется из файлаINPUT. -
Процедура
readLn([var f: text;] v1, v2, {...} vn)– осуществляет ввод символов, строк и чисел. После чтения последней переменной оставшаяся часть строки до маркера конца строки пропускается так, что следующее обращение кreadLnилиreadначинается с первого символа новой строки. -
Процедура
write([var f: text;] v1, v2, {...} vn)– осуществляет вывод одного или более выражений типаCHAR,STRING,BOOLEAN, а также целого или вещественного типов. При выводе числовых значений последние преобразуются в символьное представление. Если файловая переменная не указана, то вывод осуществляется в файлOUTPUT.
Любой параметр из списка вывода может иметь формат:
<Параметр> [: <Целое1> [: <Целое2> ]]. -
Процедура
writeLn([var f: text;] v1, v2, {...} vn)– осуществляет вывод в текстовый файл. Если файловая переменная не указана, то вывод осуществляется в файлOUTPUT.
Выводимая строка символов завершается маркером конца строки. Если список вывода не указан, то в файл передается только маркер конца строки. -
Процедура
seekEOLn([var f]): Boolean– пропускает пробелы и знаки табуляции до маркера конца строки или до первого значащего символа и возвращаетTRUE, при обнаружении маркера. Если файловая переменная не указана, то функция проверяет файлINPUT. -
Процедура
SeekEOF([var f]): Boolean– пропускает все пробелы, знаки табуляции и маркеры конца строки до маркера конца файла или до первого значащего символа и возвращаетTRUEпри обнаружении маркера. Если файловая переменная отсутствует, то функция проверяет файлINPUT.
Типизированные файлы
Типизированный файл – файл, все компоненты которого одного типа, заданного при объявлении файловой переменной.
Компоненты хранятся на диске во внутреннем (двоичном) формате.
Типизированный файл можно открыть для записи и чтения. Файл, открытый для записи, может использоваться для чтения. В файл, открытый для чтения, можно писать.
Поскольку размер компонентов одинаков, принципиально возможен не только последовательный, но и прямой доступ.
Процедуры и функции обработки типизированных файлов
-
Процедура
read(var f; c1, c2, {...} cn)– осуществляет чтение компонентов типизированного файла. Список ввода содержит одну или несколько переменных того же типа, что и компоненты файла. Если файл исчерпан, обращение к процедуре вызывает ошибку ввода-вывода. -
Процедура
write(var f; c1, c2, {...} cn)– осуществляет запись компонентов в типизированный файл. Список вывода содержит одно или более выражений того же типа, что и компоненты файла. -
Процедура
seek(var f; numcomp: LongInt)– осуществляет установку указателя файла на компонент с номеромnumcomp. -
Функция
fileSize(var f): LongInt– возвращает количество компонентов файла. Может использоваться для установки на конец файла совместно сseek():seek(f, fileSize(f)); -
Функция
filePos(var f): LongInt– возвращает порядковый номер компонента, который будет обрабатываться следующим -
Процедура
truncate(var f)– выполняет «усечение» файла.
Нетипизированные файлы
Нетипизированными называют файлы, объявленные без указания типа компонентов.
Операции чтения и записи с такими файлами осуществляются блоками, что позволяет организовать высокоскоростной обмен данными между диском и памятью. Отсутствие типа делает эти файлы совместимыми с любыми другими.
Нетипизированные файлы, как и типизированные, допускают организацию прямого доступа.
Нетипизированный файл можно открыть для записи и для чтения:
reSet(var f[; recsize: Word]);
reWrite(var f[; recsize: Word]);
где recsize – размер записи файла в байтах. Длину записи задают кратной 512 байт, например: 1024, 2048. Если длина записи не указана, она принимается равной 128.
Процедуры и функции обработки нетипизированных файлов
-
Процедура
blockRead(var f: file; var buf; count: Word[; var res: Word])– осуществляет чтение блока записей из файла в буферbuf.
Параметрresбудет содержать количество фактически обработанных записей. Если последняя запись – неполная, то значение параметраresее не учтет. -
Процедура
blockWrite(var f: file; var buf; count: Word[; var res: Word])– осуществляет запись блока из буфераbufв файл.
Дополнительные процедуры и функции для работы с файлами
-
function changeFileExt(const fileName, extension: String): String– изменяет существующее расширение файла на указанное. -
procedure chDir(const s: String); overload;
procedure chDir(p: PChar); overload;– изменяет текущий каталог (каталог по умолчанию). -
function createDir(const dir: String): Boolean– создает новый каталог. -
function deleteFile(const fileName: String): Boolean– удаляет указанный файл. -
function directoryExists(const directory: String): Boolean– проверяет существование каталога по указанному адресу. -
function diskFree(drive: Byte): Int64– возвращает объем в байтах свободного пространства на указанном диске:
0– устройства по умолчанию;1– дискА;2– дискВи т.д. Функция возвращает-1, если указанный диск не существует. -
function diskSize(drive: Byte): Int64– возвращает объем памяти указанного диска. -
function fileExists(const fileName: string): Boolean– проверяет существование файла по указанному адресу. -
function fileSearch(const name, dirList: String): String– ищет файл в указанных через точку с запятой каталогах, если не находит, то возвращает пустую строку. -
function findFirst(const path: string; attr: Integer; var f: TSearchRec): Integer– ищет в каталоге первый файл с указанной маской и атрибутами; -
function findNext(var F: TSearchRec): Integer– ищет следующие файлы. -
function getCurrentDir: String– возвращает имя текущего каталога. -
function forceDirectories(dir: String): Boolean– создает каталоги и подкаталоги. -
function removeDir(const dir: String): Boolean– удаляет указанный пустой каталог. -
function setCurrentDir(const dir: String): Boolean– устанавливает текущий каталог.
22. Основы файловой системы: файл, каталог, дисковод, полное имя файла, внутреннее представление информации в файле. Файловая переменная. Операции открытия и закрытия файлов. Примеры.
23. Текстовые файлы. Внутреннее представление информации в файле. Операции над файлами. Пример.
24. Типизированные файлы: внутреннее представление информации в файле. Операции над файлами. Пример.
25. Нетипизированные файлы. Внутреннее представление информации в файле. Операции над файлами. Пример.
Объектно-ориентированное программирование
История
«Стихийное» программирование
«Стихийное» программирование – до середины 60-х годов ХХ века – технология отсутствует – программирование – искусство создания программ – в конце периода появляется возможность создания подпрограмм – используется процедурная декомпозиция.
Структурный подход
Структурный подход к программированию - 60-70-е годы ХХ века – технология, представляющая собой набор рекомендаций и методов, базирующихся на большом опыте работы:
- нисходящая разработка;
- декомпозиция методом пошаговой детализации;
- структурное программирование;
- сквозной структурный контроль и т. д.
Модульный подход
Модульное программирование – выделение групп подпрограмм, использующих общие глобальные данные в модули – отдельно компилируемые части программы (многоуровневая декомпозиция).
Объектный подход к программированию
C середины 80-х до наших дней.
Объектно-ориентированное программирование – технология создания сложного программного обеспечения, основанная на представлении програм-мы в виде системы объек-тов, каждый из которых яв-ляется экземпляром опре-деленного типа (класса), а классы образуют иерар-хию с наследованием свойств.
Компонентный подход
Компонентный подход – с конца 90-х годов ХХ века (COM-технология, Corba, SOAP) – подключение объектов через универсальные интерфейсы – развитие сетевого программирования – появление CASE-технологий.
Диаграмма состояний интерфейса
пользователя
Структурная декомпозиция
Процедурная декомпозиция – процесс разбиения программы на подпрограммы.
Структурной называют декомпозицию, если:
- каждая подпрограмма имеет один вход и один выход;
- подпрограммы нижних уровней не вызывают подпрограмм верхних уровней;
- размер подпрограммы не превышает 40-50 операторов;
- в алгоритме использованы только структурные конструкции.
Объектная декомпозиция
Объектная декомпозиция – процесс представления предметной области задачи в виде отдельных функциональных элементов (объектов предметной области), обменивающихся в процессе выполнения программы входными воздействиями (сообщениями) .
Объект отвечает за выполнение некоторых действий, инициируемых сообщениями и зависящих от параметров объекта.
Объект предметной области
Объект предметной области характеризуется:
- именем;
- состоянием;
- поведением.
Состояние – совокупность значений характеристик объекта, существенных с т. з. решаемой задачи.
Поведение – совокупность реакций на сообщения.
Реализация объектов предметной области
Класс – это структурный тип данных, который включает описание полей данных, а также процедур и функций, работающих с этими полями данных.
Применительно к классам такие процедуры и функции получили название методов.
Объект-переменная – переменная типа «класс».
Методы построения классов
-
Наследование – механизм, позволяющий строить класс на базе более простого посредством добавления полей и определения новых методов.
При этом исходный класс, на базе которого выполняется построение, называют родительским или базовым, а строящейся класс – потомком или производным классом.
Если при наследовании какие-либо методы переопределяются, то такое наследование называется полиморфным.
-
Композиция – механизм, позволяющий включать несколько объектов других классов в конструируемый.
-
Наполнение – механизм, позволяющих включать указатели на объекты других классов в конструируемый.
Средства объектно-ориентированного программирования
C точки зрения синтаксиса класс – структурный тип данных, в котором помимо полей разрешается описывать прототипы (заголовки) процедур и функций, работающих с этими полями данных.
type
TRoom = object
length, width: Single;
function square: Single; {прототип функции}
end;
function TRoom.square;
begin
result := length * width;
End;
Любой метод неявно получает параметр self – ссылку (адрес) на поля объекта, и обращение к полям происходит через это имя.
function TRoom.square;
begin
result := self.length * self.width;
End;
При необходимости эту ссылку можно указывать явно:
@self – адрес области полей данных объекта.
Объявление объектов класса
var
a: TRoom; {объект А класса TRoom}
b: array[1..5] of TRoom; {массив объектов типа TRoom}
type pTRoom=^TRoom; {тип указателя на объекты класса TRoom}
var pC: pTRoom; {указатель на объекта класса TRoom}
Для динамического объекта необходимо выделить память:
new(pC);
, а после его использования – освободить память:
dispose(pC);
Обращение к полям и методам аналогично доступу к полям записей:
Примеры:
v := a.length;
s := a.square;
s := s + b[i].square;
pC^.length := 3;
Над объектами одного класса определена операция присваивания. Физически при этом происходит копирование полей одного объекта в другой методом «поле за полем»:
Инкапсуляция – ограничение доступа к полям и методам
| Модификатор доступа | Доступность |
|---|---|
public |
поля и методы, доступны из других модулей |
private |
поля и методы, доступны только в пределах модуля |
protected |
поля и методы, доступны только в классах потомках |
published |
поля и методы, видимы в инспекторе объектов |
По умолчанию для всех полей испаользуется модификатор public.
Ограничение только в пределах модуля!
Хотя, вроде, нет. Наоборот, только в пределах модуля можно пользоваться приватными полями.
unit Room;
interface
type TRoom = object
private // !!!
length, width: Single;
public
function square: Single;
procedure init(l, w: Single);
end;
implementation
function TRoom.square;
begin
result := length * width;
end;
procedure TRoom.init;
begin
length := l;
width := w;
end;
end.
program Ex_7_02;
{$APPTYPE CONSOLE}
uses SysUtils, Room in 'Room.pas';
var a: TRoom;
begin
a.init(3.5, 5.1);
writeLn('Room: length = ', a.length:6:2,
'; width = ', a.width:6:2);
writeLn('Square = ', a.square:8:2);
readLn;
end.
Наследование
Наследование - конструирование новых более сложных производных классов из уже имеющихся базовых посредством добавления полей и методов.
program Ex_07_03;
{$APPTYPE CONSOLE}
uses SysUtils, Room in 'Ex_08_02\Room.pas';
type
TVRoom = object(TRoom)
height: Single;
function V: single;
procedure newInit(l, w, h: single);
end;
procedure TVRoom.newInit;
begin
init(l, w);
height := h;
end;
function TVRoom.V;
begin
result := square * height;
end;
var
a: TVRoom;
begin
a.newInit(3.4, 5.1, 2.8);
writeLn('Square = ', a.square:6:2);
writeLn('V = ', a.V:6:2);
readLn;
end.
Присваивание объектов иерархии
Допустимо присваивать переменной типа базового класса значение переменной типа объекта производного класса.
var
a: TRoom;
b: TVRoom;
{...}
a := b; {допустимо}
b := a; {не допустимо!}
Присваивание указателей в иерархии
Допустимо указателю на объект базового класса присваивать адреса объекта производного класса.
Однако при этом возникает проблема «невидимых» полей.

var
pC: ^TRoom;
e: TVRoom;
{...}
pC := @e;
pC^.length := 3.1;
pC^.height := 2.7; {ошибка!}
type
pTVRoom = ^TVRoom;
var
pC: ^TRoom;
e: TVRoom;
{...}
pC := @e;
pTVRoom(pC)^.height := 2.7;
Композиция
Композиция – включение объектов одного класса в объекты другого. Реализуется механизмом поддержки объектных полей.
program Ex_7_04;
{$APPTYPE CONSOLE}
uses
SysUtils,
Room in 'Ex_08_02\Room.pas';
type
TFlat = object
n: byte;
rooms: array[1..15] of TRoom;
function flatSquare(): Single;
procedure init(an: Byte; const ar: array of TRoom);
end;
procedure TFlat.init;
var
i: Byte;
begin
n := an;
for i := 1 to n do
rooms[i].init(ar[i - 1].length, ar[i - 1].width);
end;
function TFlat.flatSquare;
var
s: Single;
i: Integer;
begin
s := 0;
for i := 1 to n do
s := s + rooms[i].square();
result := s;
end;
var
mas: array[1..3] of TRoom = ((length: 2.5; width: 3.75),
(length: 2.85; width: 4.1),
(length: 2.3; width: 2.8));
f: TFlat;
begin
f.init(3, mas);
writeLn('S flast = ', f.flatSquare());
readLn;
end.
Наполнение (агрегация)
Наполнение – способ конструирования классов, при котором объекты строящегося класса могут включать неопределенное количество: от 0 до сравнительно больших значений (на практике обычно до нескольких десятков), объектов других классов.
program Ex_7_05;
{$APPTYPE CONSOLE}
uses
SysUtils,
Room in 'Ex_08_02\Room.pas';
type
TBRoom = object(TRoom)
pB: ^TRoom;
function BSquare(): Single;
procedure initAll(l, w: single; lb: single = 0; wb: single = 0);
end;
procedure TBRoom.initAll;
begin
init(l, w);
if (lb = 0) or (wb = 0) then
pB := nil
else
begin
new(pB);
pB^.init(lb, wb);
end;
end;
function TBRoom.BSquare;
begin
if pB = nil then
result := square()
else
result := square() + pB^.square;
end;
var
b: TBRoom;
begin
b.initAll(3.4, 5.1, 1.8, 0.8);
writeLn('BSquare =', b.BSquare():8:2);
readLn;
end.
Простой полиморфизм
Простой полиморфизм – механизм переопределения методов при наследовании, при котором связь метода с объектом выполняется на этапе компиляции (раннее связывание).
program Ex_7_06;
{$APPTYPE CONSOLE}
uses
SysUtils,
Room in 'Ex_08_02\Room.pas';
type
TVRoom2 = object(TRoom)
height: Single;
function square(): Single;
procedure init(l, w, h: Single);
end;
procedure TVRoom2.init;
begin
inherited init(l, w); { TRoom.init(l,w);}
Height := h;
end;
function TVRoom2.square;
begin
result := 2 * (inherited square() + height * (length + width));
end;
var
a: TVRoom2;
begin
a.init(3.4, 5.1, 2.8);
writeLn('Square = ', a.square():6:2);
readLn;
end.
Обращение объекта производного класса к переопределенному методу базового класса в программе
При необходимости обращении к переопределенному методу базового класса явно меняют тип переменной – объекта класса, например так
var
a: TVRoom2;
b: TRoom;
{...}
b := a;
b.square();
Сложный полиморфизм. Конструкторы
Существует три ситуации, в которых определение типа объекта на этапе компиляции программы невозможно, и, следовательно, невозможно правильное подключение переопределенного метода.
3 случая обязательного использования сложного полиморфизма
1-й случай – если наследуемый метод для объекта производного класса вызывает метод, переопределенный в производном классе.
2-й случай – если объект производного класса через указатель базового класса обращается к методу, переопределенному производным классом.
3-й случай – если процедура вызывает переопределенный метод для объекта производного класса, переданного в процедуру через параметр-переменную, описанный как объект базового класса («процедура с полиморфным объектом»).
1-й случай
program Ex_7_07;
{$APPTYPE CONSOLE}
uses
SysUtils;
// ================ TRoomP ================
type
TRoomP = object
length, width: Single;
function square: Single;
procedure print();
procedure init(l, w: Single);
end;
function TRoomP.square;
begin
result := length * width;
end;
procedure TRoomP.print;
begin
writeln('Square = ', square():6:2);
end;
procedure TRoomP.init;
begin
length := l;
width := w;
end;
// ================ TVRoomP ================
type
TVRoomP = object(TRoomP)
height: Single;
function square: Single;
procedure init(l, w, h: Single);
end;
procedure TVRoomP.init;
begin
inherited init(l, w);
height := h;
end;
function TVRoomP.square;
begin
square := 2 * (inherited square() + height * (length + width));
end;
// ================ ================
var
a: TRoomP;
b: TVRoomP;
begin
a.init(3.5, 5.1);
a.print(); // `Square = 17.85` -- верно
b.init(3.5, 5.1, 2.7);
b.print(); // `Square = 17.85` -- неверно, должно быть: `82.14`
writeLn(b.square():6:2); // `82.14` -- верно
readln;
end.
Пояснение к ошибке

При позднем связывании нужный аспект полиморфного метода определяется на этапе выполнения программы по типу объекта, для которого вызывается метод.
Реализация сложного полиморфизма
Для организации сложного полиморфизма необходимо:
- переопределяемые методы описать служебным словом
virtual; - к методам класса с виртуальными полиморфными методами добавить специальный метод-процедуру – конструктор, в котором служебное слово
procedureзаменено служебным словомconstructor; - вызвать конструктор прежде, чем произойдет первое обращение к виртуальным полиморфным методам.
Подключение осуществляется с использованием таблицы виртуальных методов (ТВМ), которая создается при выполнении конструктора.

Различие раннего и позднего связывания
Раннее связывание – адрес метода определяется на этапе компиляции по объявленному типу переменной.

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

Исправленный пример
unit RoomP;
interface
type
TRoomP = object
length, sidth: Single;
function square(): Single; virtual; // !!!
procedure print();
constructor init(l, w: Single);
end;
type
TVRoomP = object(TRoomP)
height: Single;
function square: Single; virtual; // !!!
constructor init(l, w, h: Single);
end;
implementation
function TRoomP.square;
begin
result := length * width;
end;
procedure TRoomP.print;
begin
writeln('Square = ', square():6:2);
end;
constructor TRoomP.init;
begin
length := l;
width := w;
end;
constructor TVRoomP.init;
begin
inherited init(l, w);
height := h;
end;
function TVRoomP.square;
begin
square := 2 * (inherited square() + height * (length + width));
end;
end.
program Ex_7_07a;
{$APPTYPE CONSOLE}
uses
SysUtils,
RoomP in 'RoomP.pas';
var
a: TRoomP;
b: TVRoomP;
begin
a.init(3.5, 5.1);
a.print(); // `Square = 17.85`
b.init(3.5, 5.1, 2.7);
b.print(); // `Square = 82.14`
readln;
end.
2-й случай
program Ex_7_07b;
{$APPTYPE CONSOLE}
uses
SysUtils,
RoomP in 'Ex_07_07\RoomP.pas';
var
pA: ^TRoomP;
B: TVRoomP;
begin
B.init(3.5, 5.1, 2.7);
writeLn('Square =', B.Square:6:2); // `Square = 82.14`
pA := @B;
writeLn('Square =', pA^.Square:6:2); // `Square = 82.14`
readLn;
end.
3-й случай
program Ex_7_07c;
{$APPTYPE CONSOLE}
uses
SysUtils,
RoomP in 'Ex_08_07\RoomP.pas';
procedure print(var r: TRoomP);
begin
writeln('Square =', r.square:6:2);
end;
var
a: TRoomP;
b: TVRoomP;
begin
a.init(3.5, 5.1);
b.init(3.5, 5.1, 2.7);
print(a);
print(b);
readln;
end.
Функция определения типа полиморфного объекта
typeOf(<имя_класса_или_объекта>): pointer – возвращает адрес ТВМ класса или класса объекта. Если адрес ТВМ объекта и класса совпадают, то объект является переменной данного класса.
if typeOf(self) = typeOf(<имя_класса>) then
{Объект принадлежит класс}>
else
{Объект не принадлежит классу}
Свойства виртуальных методов класса
- позднее связывание требует построения ТВМ, а следовательно больше памяти;
- вызов виртуальных полиморфных методов происходит через ТВМ, а следовательно медленнее;
- список параметров одноименных виртуальных полиморфных методов должен совпадать, а статических полиморфных – не обязательно;
- статический полиморфный метод не может переопределить виртуальный полиморфный метод.
Динамические полиморфные объекты. Деструкторы
Создание полиморфных объектов:
Функция new(<тип_указателя>) – возвращает адрес размещенного и, возможно, сконструированного объекта. После необходим вызов конструктора.
Или new(<тип_указателя>, <конструктор>).
Деструктор – метод класса, который используется для корректного уничтожения полиморфного объекта, содержащего невидимое поле. Деструктор можно переопределять.
Уничтожение полиморфных объектов
Процедура dispose(<указатель>) – освобождает память, на которую указывает указатель. Перед вызовом процедуры необходим вызов деструктора, если он указан, и затем – выполняется освобождение памяти.
Или dispose(<указатель>, <деконструктор>).
program Ex_7_08;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
pTRoomD = ^TRoomD;
TRoomD = object
length, width: Single;
function square(): Single; virtual;
constructor init(l, w: Single);
destructor done;
end;
type
pTVRoomD = ^TVRoomD;
TVRoomD = object(TRoomD)
height: Single;
function square(): Single; virtual;
constructor init(l, w, h: Single);
end;
function TRoomD.square;
begin
result := length * width;
end;
constructor TRoomD.init;
begin
length := l;
width := w;
end;
destructor TRoomD.done;
begin
end;
constructor TVRoomD.init;
begin
inherited init(l, w);
height := h;
end;
function TVRoomD.square;
begin
result := 2 * (inherited square() + height * (length + width));
end;
var
pA: pTRoomD;
pB: pTVRoomD;
begin
{указатель базового типа, объект базового типа}
pA := new(pTRoomD);
pA^.init(3.5, 5.1);
writeLn('Square =', pA^.square():6:2); // `Square = 17.85`
pA^.done();
dispose(pA);
{указатель производного типа, объект производного типа}
pB := new(pTVRoomD);
pB^.init(3.5, 5.1, 2.7);
writeLn('Square =', pB^.square():6:2); // `Square = 82.14`
Dispose(pB, done);
{указатель базового типа, объект производного типа}
pA := new(pTVRoomD, init(3.5, 5.1, 2.7));
writeLn('Square =', pA^.square():6:2); // `Square = 82.14`
dispose(pA, done);
readLn;
end.
Динамические поля в объектах
program Ex_7_09;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
pTRoomD = ^TRoomD;
TRoomD = object
length, width: Single;
function square(): Single; virtual;
constructor init(l, w: Single);
destructor done; virtual;
end;
type
pTBRoomD = ^TBRoomD;
TBRoomD = object(TRoomD)
pB: pTRoomD;
function square: Single; virtual;
function BSquare: Single;
constructor init(l, w: Single; lb, wb: Single);
destructor done; virtual;
end;
function TRoomD.square;
begin
square := length * width;
end;
constructor TRoomD.init;
begin
length := l;
width := w;
end;
destructor TRoomD.done;
begin
end;
constructor TBRoomD.init;
begin
inherited init(l, w);
if (lb = 0) or (wb = 0) then
pB := nil
else
pB := new(pTRoomD, init(lb, wb));
end;
function TBRoomD.BSquare;
begin
if pB <> nil then
BSquare := pB^.square
else
BSquare := 0;
end;
function TBRoomD.square;
begin
square := inherited square() + BSquare();
end;
destructor TBRoomD.done;
begin
if pB <> nil then
Dispose(pB, done);
end;
var
A: TBRoomD;
pB1: pTBRoomD;
pB2: pTRoomD;
begin
{статический объект с динамическим полем}
A.init(3.2, 5.1, 2.5, 1);
writeLn(A.Square():6:2, A.BSquare():6:2); // ` 18.82 2.50`
A.done;
{динамический полиморфный объект с динамическим полем}
pB1 := new(pTBRoomD, init(3.2, 5.1, 2.5, 1));
writeLn(pB1^.square():6:2, pB1^.BSquare():6:2); // ` 18.82 2.50`
dispose(pB1, Done);
{динамический полиморфный объект с динамическим полем}
pB2 := new(pTBRoomD, init(3.2, 5.1, 2.5, 1));
writeLn(pB2^.square:6:2, pTBRoomD(pB2)^.BSquare():6:2); // ` 18.82 2.50`
dispose(pB2, done);
readLn;
end.
Технология событийного программирования. События Windows, сообщения и события Delphi. Основные события Delphi. Примеры.
Приложение (в отличие от программы) – набор подпрограмм, вызываемых при наступлении некоторого события, которым считается любое изменение в системе, касающееся данного приложения.
События Delphi и их обработчики
Обработчики сообщений Windows предусмотрены у объектов класса TForm и классов управляющих компонентов, таких как кнопки, редакторы и т. п.
Обработка выполняется следующим образом:
- В системе происходит событие, например, пользователь передвинул мышь или нажал на клавишу клавиатуры, в результате генерируется сообщение об этом событии – сообщение Windows.
- Сообщение Windows диспетчируется конкретному приложению.
- В приложении сообщение передается активному компоненту (окну или управляющему элементу).
- Метод обработки сообщения Windows компонента инициирует заранее предусмотренные события Delphi.
- Если в приложении предусмотрен соответствующий обработчик события Delphi, то он вызывается, если нет – то продолжается обработка сообщения Windows.
События Delphi
Обработчики сообщений Windows, встроенные в классы компонентов VCL, инициируют множество событий Delphi.
Например, обработчик события клавиатуры WM_CHAR класса TForm инициирует три события Delphi.

Обработчики событий Delphi
Для каждого обработчика событий предусмотрен заголовок и определённый список передаваемых ему параметров.
procedure <компонент>.<Имя_компонента><Имя_события_delphi>(Sender: TObject[, {...}]);
procedure TForm1.FormActivate(Sender:TObject);
ПараметрSender– отправитель (инициатор события).procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
Параметр Key – символ ANSI.procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
Параметры: Key – виртуальный код, Shift – управляющие клав.procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
Примеры событий Delphi, обрабатываемые объектами класса TForm
-
при изменении состояния формы:
OnCreate– в начальной стадии создания формы - используется при необходимости задания параметров (цвет или размер);OnActivate– при получении формой фокуса ввода (окно становится активным и ему адресуется весь ввод с клавиатуры);OnShow– когда форма (окно) становится видимой;OnPaint– при необходимости нарисовать или перерисовать форму;OnResize- при изменении размеров формы на экране;OnDeactivate– при потере формой фокуса ввода (окно становится неактивным);OnHide– при удалении формы с экрана (окно становится невидимым);OnCloseQuery– при попытке закрыть форму - обычно используется для создания запроса-подтверждения необходимости закрытия окна;OnClose– при закрытии формы;OnDestroy– при уничтожении формы;
-
от клавиатуры и мыши:
OnKeyPressed– при нажатии клавиш, которым соответствует код ANSI;OnKeyDown,OnKeyUp– при нажатии и отпускании любых клавиш;OnClick,OnDblClick– при обычном и двойном нажатии клавиш мыши;OnMouseMove– при перемещении мыши (многократно);OnMouseDown,OnMouseUp– при нажатии и отпускании клавиш мыши;
-
при перетаскивании объекта мышью:
OnDragDrop– в момент опускания объекта на форму;OnDragOver– в процессе перетаскивания объекта над формой (многократно);
-
другие:
OnHelp– при вызове подсказки;OnChange– при изменении содержимого компонент.
Ещё полезные вещи
Некоторые опции/директивы компилятора
Каждая из них может быть включена директивой {$@+} или {$<dir> On} и отключена директивой {$@-} или {$<dir> Off} , где @ – одна из допустимых букв, <dir> – полное имя директивы (см. таблицу)
| Краткая форма | Полная форма | По умолчанию* | Описание |
|---|---|---|---|
{$X} |
{$ExtendedSyntax} |
+ |
Если включено можно: использовать result в функциях для возврата значений; вызывать функции как процедуры (никуда не возвращая результат); Обрабатывать массив char'ов как строки |
{$I} |
{$IOChecks} |
+ |
Если включено: проверяет правильность завершения операций ввода-вывода, если ошибка – вызывает ошибку выполнения программы; иначе – функция IOResult(): Word возвращает код статуса последней операции ввода-вывода |
{$H} |
{$LongStrings} |
+ |
Если включено: тип string присваивается к AnsiString, иначе к ShortString. (Хотя, кажется, с Delphi 2009 string всегда считается UnicodeString) |
{$Q}** |
{$OverFlowChecks}** |
- |
Если включено: проверяет наличие переполнения при выполнении некоторых арифметических операций. При переполнении программа аварийно завершается |
{$R}** |
{$RangeChecks}** |
- |
Если включено: проверяет правильность вычисленных индексов массивов. При выходе за рамки программа аварийно завершается |
* – в Delphi Pascal 2009
** – являются отладочными директивами, поэтому с ними выполнение программы потребует больше времени и/или памяти
Источник: delphibasics.co.uk
Written with StackEdit