|
|
Волгоградский
государственный технический университет |
ПОВТОРЕНИЕ ЯЗЫКА Pascal
Файл - упорядоченный набор информации на внешнем (обычно дисковом носителе).
Порядок обработки информации машиной с целью получения программы следующий:
1) ввод нового и/или корректировка существующего файла с исходным текстом программы (файлы *.pas или *.inc);
2) компиляция файлов с исходными текстами (*.tpu);
3) редактирование связей программы (линковка), получение выполняемого файла программы (*.exe);
4) запуск программы на выполнение средствами операционной системы.
Понятие идентификатора
Идентификатор – имя, определенное пользователем.
Идентификаторы - это последовательность букв, цифр и ряда дополнительных символов (например, подчеркивания), но начинающаяся обязательно с буквы.
Большие и малые буквы в идентификаторе не различаются.
Минимальная длина идентификатора - одна буква. Максимальная длина - не ограничена, но два идентификатора будут различными, если различаются только первые 63 символа. Остальные символы опускаются компилятора.
Рекомендуется придавать идентификаторам мнемоничность - понятность обозначений.
Примеры идентификаторов:
X, y, i, j - немнемоничные идентификаторы;
Time, TIME, time - один и тот же идентификатор;
StartTime_minutes - этот идентификатор уже мнемоничен;
Понятие оператора. Описательные и выполняемые операторы языка
Оператор - предложение языка. Оператор заканчивается символом ";".
Описательные операторы не описывают действия программы.
Они необходимы для правильного понимания компилятором данных и частей программ.
Выполняемые операторы описывают действия согласно алгоритму. В операторах могу использоваться зарезервированные слова, запятые и другие знаки, идентификаторы.
Операторы можно записывать как в одной строке, так и в нескольких строках. Для придания красоты записи оператора можно использовать символы пробелов - "пусто". Пробелы и переносы нельзя вставлять в середину зарезервированных слов и идентификаторов. Пустые строки игнорируются компилятором. Их можно использовать для придания выразительности текстов программы.
Пример:
var
a,b, x, y: integer;
if a > b
then
y := 3 + x
else
y := 5 - x;
Комментарии
Комментарии игнорируются компилятором, но необходимы программистам для написания понятных текстов программ
Любой текст, даже длиной в несколько строк, заключенный между парой скобок {Текст} или (*Текст*) является комментарием.
Обычно используют комментарии { }. Комментарий (* *) обычно используется для временного исключения операторов и других комментариев текста программы путем превращения их в комментарий.
Пример:
(* !!!
{Вычисление определенного
интеграла}
x := a; {это комментарий справа от оператора}
*)
program my_program;
{ Комментарий назначения программы }
uses { Подключение библиотек программ }
Crt, Dos;
label { Метки для GoTo, но они не технологичны }
Metka1, M100;
const { Константы (неизменяемые значения) }
MaxData = 1024; { Константа типа "целый" }
Pi = 3.14159; { Константа типа "вещественный" }
NumChars = Ord('Z') - Ord('A') + 1; { Число букв в
латинском алфавите }
Message = 'Hello world...'; { Строка символов }
type { Tипы переменных }
TMy_Rec = record
Imia : string;
Familia : string;
Age : integer;
end;
TMy_Spisok = array [1 .. 100] of TMy_Rec;
var { Переменные }
i, j: integer; { Эти целочисленные переменные не имеют
дробной части }
X,
Y: real; { Координаты объекта (вещественные числа) }
Spisok: TMy_Spisok; { Список руппы студентов }
{ Здесь могут находиться описания функций и процедур }
procedure My_Inc(var i: integer); { Описание правил вычисления
процедуры }
{ Эта процедура увеличивает значение целочисленной переменной на 1 }
begin
i := i + 1;
end;
function DoubleSin(Z: Real) : Real;
{ Описание правил вычисления функции }
{ Эта функция вычисляет удвоенное значение синуса аргумента Z }
begin
DoubleSin := 2.0 * Sin(Z);
end;
begin { Тело программы содержит выполняемые операторы }
{ Отсюда начинается выполнение программы }
ClrScr; { Очистка экрана с использованием библиотечной процедуры }
i := 5;
My_Inc(i); { Теперь переменная i равна 6 }
Y := 5.0 * DoubleSin(0.25 * Pi + 0.1);
WriteLn('i= ', i, 'Y= ', y); {Вывод на экран значений i, y при
Помощи библиотечной процедуры }
end.
Имеет следующую форму записи:
y := x;
y - переменная,
x - выражение.
Типы x и y должны совпадать или допускать преобразование по умолчанию типа x в тип y.
Выражение - это один операнд или несколько операндов, соединенные знаками операций.
Операндами могут быть:
- константы;
- переменные, а также элементы структурированных переменных;
- функции;
- выражения, заключенные в круглые скобки ().
Типы операндов в выражении должны совпадать или допускать преобразование типов по умолчанию (в этом случае производится преобразование в высший тип).
Выражения рассчитываются в порядке слева на право с учетом старшинства операций. Наивысший приоритет имеет расчет функций, далее следует расчет выражения, заключенных в круглые скобки ().
Знак операции Старшинство
@ not Первое (высшее)
* / div mod Второе
and shl shr
+ - or xor Третье
= <> < > Четвертое (низшее)
<= >= in
1. Порядковые типы
Типы "целый" (Integer)
Типы "логический (Boolean)
Тип "символьный" (Char)
Типы "нумерованный" (Enumerated)
Типы "интервальный" (Subrange)
2. Вещественные типы (с плавающей точкой)
3. Строковые типы представляют строку символов (массив символов) переменной длины, но не более чем 255 символов (значение 0 элемента соответствует количеству символов в строке).
4. Структурированные типы позволяют в одной переменной хранить более одного значения.
Типы "массив" (Array)
Типы "запись" (Record)
Типы "объект" (Object)
Типы "определяемый" (Set)
Типы "файл" (File)
4. Типы "Указатели" (Pointer) определяют переменную, содержащую адреса других переменных.
5. Процедурные типы позволяют передавать в подпрограммы адреса подключаемых процедур и функций.
6. Типы "Объектный" (Object) используется в объектно-ориентированном и визуальном программировании.
Форматы определяются в битах и байтах 1byte = 8bit
Тип Диапазон Формат
Shortint -128..127 Со знаком 8-bit
Integer -32768..32767 Со знаком 16-bit
Longint -2147483648..2147483647 Со знаком 32-bit
Byte 0..255 Без знака 8-bit
Word 0..65535 Без знака 16-bit
Знаки операций арифметического выражения типа целый:
+ - сложение
- - вычитание
* - умножение
div - деление с отбрасыванием дробной части
mod - вычисление остатка от деления
Примеры:
5 * 3 {результат 15}
7 div 3 {результат 2}
7 mod 3 {результат 1}
y := 3 + 5*abs(x + 2);
Знаки унарных операторов + (игнорируется) и - (изменение знака)
Пример унарной операции:
x := -9;
y := -x; {результат y = 9.}
Функции:
Succ(7) результат 8
Pred(7) результат 6
Процедуры:
x := 7;
Inc(x) результат x = 8
x := 7;
Dec(x) результат x = 7
Abs(x) результат равен x при x >= 0, иначе -x.
Тип Диапазон Формат
Boolean False, True 8-bit
WordBool False, True 16 bit
LongBool False, True 32 bit
ByteBool False, True 8-bit
Знаки операций логического выражения с операндами типа "логический":
Оператор Операция
not отрицание (НЕ)
and логическое И
or логическое ИЛИ
not - унарный оператор.
not(True) результат False
not(False) результат True
X and Y. Если как X, так и Y равны True, то результат True, иначе результат False
X or Y. Если как X, так и Y равны False, то результат False, иначе результат True
Два арифметических выражения, соединенные знаками операций отношения дают результат типа "логический (Boolean).
Знаки операций отношения:
< <= = >= > <>
меньше меньше или равно равно больше или равно больше не равно
Пример:
x := 7;
not(x >= 3) результат True
L and not(B or (x >= 3))
Функции:
Ord(False) результат 0
Ord(True) результат 1
Succ(False) результат True
Pred(True) результат False
False < True
Переменные типы Char используются для сохранения одиночного символа ASCII.
Константа - символ записывается между символами '' - апострофы, например:
'A', '3', или '*'
Константа - символ ' кодируется двумя символами '', например:
''''
Функция Ord преобразует символ в порядковый номер символа кодовой таблицы ASCII (тип "целый").
Функция Chr осуществляет обратное по отношению к Ord преобразование.
Примеры:
Chr(70) - результат 'F'
Ord('G') - результат 71
type
TMonth = (January, February, March, April, May, June);
Согласно данному описанию, January как бы является цифрой типа TMonth, но над значениями нельзя проводить арифметические операции. Можно использовать операции отношения, например:
var
x, y: TMonth;
L : Boolean;
begin
x := March;
y := June;
L := x < Y; {Результат - L = True}
end.
Функции для работы с типами "нумерованный":
Ord(January) = 0
Ord(February) = 1
Ord(March) = 2
и т.д.
Pred(May) результат April
Suc(June) результат June
type
TMinutes = 0..59;
var
M : TMinutes;
begin
M := 59; {Нет ошибки}
M := 60; {Ошибка!!! Нарушен интервал}
end.
type
TEnglishUpperChars = 'A'..'Z';
Данные типы в памяти машины представляются в форме чисел с плавающей запятой (знак числа, знак порядка, порядок, мантисса).
Тип Диапазон Десятичных цифр Формат (байт)
real 2.9e-39..1.7e38 11-12 6
single 1.5e-45..3.4e38 7-8 4
double 5.0e-324..1.7e308 15-16 8
extended 3.4e-4932..1.1e4932 19-20 0
comp -9.2e18..9.2e18 19-20 8
В графе диапазон чисел приведены примеры записи констант.
Дополнительные примеры записи констант приведены ниже:
-5.66 2.99999 0.0 (0 - константа типа "целый!")
Примечание: Тип comp на самом деле является 64-bit "целым" (integer).
Он не имеет порядка и резко теряет точность вблизи границ.
Знаки операций арифметического выражения типа вещественный:
+ - сложение
- - вычитание
* - умножение
/ - деление
При расчете выражений тип целый автоматически преобразуется в вещественный тип.
Примеры:
5.0 * 3.0 результат около 15.0 (от 14.99999999 до 15.00000001)
5*3.0 результат около 15.0 вещественного типа.
Из-за неточного представления результата значения чисел сравниваются на равенство с использованием следующей конструкции:
Abs(X - 15.0) <= 0.00000001 (Вместо X = 15.0)
Знаки унарных операторов + (игнорируется) и - (изменение знака)
Пример унарной операции:
x := -9.0;
y := -x результат y = 9.0.
Функции:
Trunc(x) преобразует вещественное значение x в тип "целый" Longint с отбрасыванием дробной части
Round(x) преобразует вещественное значение x в тип "целый" Longint с округлением до ближайшего целого значения значение целой части вещественного значения x
Frac(x) получает вещественное значение дробной части вещественного значения x
Примеры:
Функция Результат
Trunc(7.69) 7
Round(7.69) 8
Int(7.69) 7.0
Frac(7.69) 0.69
Функции вещественной арифметики (аргумент тригонометрических функций определяется в радианах):
Abs(x) результат равен x при x >= 0.0, иначе -x
Sin(x)
Cos(x)
ArcTan(x) - arctg x
Exp(x)
Ln(x)
На этом простые типы закончились, далее начинаются структурированные типы.
Строковые типы представляют строку символов (массив символов) переменной длины, но не более чем 255 символов (значение 0 элемента соответствует количеству символов в строке )
Замечание:
По умолчанию строковый тип имеет длину в 255 символов.
Строковые константы записываются в одинарных кавычках ''. Например:
'Turbo'
'That''s all' Значение константы равно: That's all
Две идущих подряд кавычки используются для записи одиночной кавычки.
Эти бинарные операции могут использоваться с переменными строкового типа:
+ = <> < > <= >=
Операция + складывает строки.
Операции = <> сравнивают на полное совпадение, как длины, так и порядок символов в строках.
Операции < > <= >= сравнивают лишь длины строк.
Функция Length
function Length(S: String): Integer;
Возвращает текущее количество символов в строке.
Функция Pos находит подстроку в строке
function Pos(Substr: String; S: String): Byte;
Находит подстроку Substr в строке S и возвращает в качестве результата целое значение номера позиции первого включения подстроки в строку. Если в строке нет подстроки, то возвращает 0.
Функция Copy копирования подстроки
function Copy(S: String; Index: Integer; Count: Integer): String;
Результирующая строка содержит Count символов, начиная с символа Index исходной строки S.
Процедура Delete удаления подстроки в строке
procedure Delete(var S: String; Index: Integer; Count:Integer);
Результирующая строка S содержит символы исходной строки S с вычеркнутой подстрокой. Удаляет Count символов, начиная с позиции Index.
Процедура Insert вставляет подстроку в строку
procedure Insert(Source: String; var S: String; Index: Integer);
Процедура вставляет подстроку Source в исходную строку S, начиная с Index позиции. Возвращает результат в строке S.
Пример:
Program Test;
const
LineLen = 79;
S1 = 'Петров';
type
T_Name = String[25];
Line = String[LineLen]; {Длина строки до 79 символов}
var
Familia: String[25]; {Длина строки до 25 символов}
Imia: T_Name; {Длина и этой строки до 25 символов}
Student: String; {По умолчанию тип string описывает
строку максимальной длины (255)
символов.}
B: boolean;
i: integer;
begin
Imia := 'Иван';
Familia := 'Иванов';
i := Pos('но', Familia); {Результат: 4}
Student := Imia + ' ' + Familia; {Результат: Иван Иванов}
i := Length(Student); {Результат: 11}
B := Student > Imia; {Результат: True}
B := Familia = S1; {Результат: False}
B := Familia >= S1; {Результат: True}
Student := ''; {Результат: пустая строка
Из 0 символов}
Student := ' '; {Результат: строка из одного Символа}
end.
Элементы типа массив имеют одно и то же имя и тип, но различаются индексами (номерами). Тип элементов произволен, но тип индекса должен быть порядковым типом.
Пример:
type
TIntList = array[1..100] of Integer;
TCharData = array['A'..'Z'] of Byte;
TMatrix = array[0..9, 0..9] of real;
var
IntList: TIntList;
CharData: TCharData;
Matrix: TMatrix;
Strings: array[1..5] of String[10];
begin
IntList[5] := 896;
CharData[C] := 7;
Matrix[4,3] := 0.0;
Strings[4] := 'Сидоров';
end.
Пример иерархического описания массива:
const
MaxLenOfSpisok = 100;
type
TMy_Rec = record
Imia : string;
Familia : string;
Age : integer;
end;
TMy_Spisok = array [1 .. MaxLenOfSpisok] of My_Rec;
var
Spisok: TMy_Spisok; {Список руппы студентов}
CurrentStudent: TMy_Rec; {Один студент}
NumCurStudent: Integer; {Номер конкретного студента}
begin
NumCurStudent := 6; {Шестой студент}
CurrentStudent := Spisok[NumCurStudent]; {Атрибуты
шестого студента}
end.
В записи объединяются несколько полей из переменных, которые могут быть произвольных типов.
Пример:
type
TMy_Rec = record
Imia : string;
Familia : string;
Age : integer;
end;
TMy_Spisok = array [1 .. MaxLenOfSpisok] of TMy_Rec;
var
Spisok: TMy_Spisok; {Список руппы студентов}
CurrentStudent: TMy_Rec; {Один студент}
NumCurStudent: Integer; {Номер конкретного студента}
begin
NumCurStudent := 6; {Шестой студент}
CurrentStudent.Imia := 'Иван';
CurrentStudent.Familia := 'Иванов';
CurrentStudent.Age := 1979;
Spisok[NumCurStudent] := CurrentStudent;
Spisok[NumCurStudent].Age := 1978; {У Иванова изменили
год рождения}
{Второй (краткий) способ доступа к полям записи}
NumCurStudent := 7; {Седьмой студент}
with Sisok[NumCurStudent] do
{Внутри with сокращается ссылка на поля}
begin
Imia := 'Петр';
Familia := 'Петров';
Age := 1980;
end;
end.
Внимание! Применительно к описаниям типов переменных case используется для обозначения эквивалентности памяти переменных.
type
Date = record
D, M, Y: Integer;
end;
Facts = record
Name: string[10];
case Kind: Integer of
Num: (N: real);
Dat: (D: Date);
Str: (S: string);
end;
В приведенным примере имеется только два поля.
Name - обычное поле записи типа Facts.
Num, Dat, Str - эти поля располагаются в одной и той же памяти. При записи в поле Dat меняются значения полей Num, Str.
Тип переменной Kind является формальным и не учитывается!
Замечание:
Множество образуется перечисляемым типом. Количество значений в множестве может изменяться при выполнении программы, но не должно превышать 256. Каждое значение в множестве должно принадлежать диапазону от 0 до 255.
Пример:
Program hhh;
{ Set types }
type
Day = (Sun, Mon, Tue, Wed, Thu, Fri, Sat);
Days = set of Day;
CharSet = set of Char;
var
Q: CharSet;
WorkDays, {Рабочие дни}
FreeDays, {Выходные дни}
MyDays: Days;
L: Boolean;
begin
Q := ['0'..'9', 'A'..'Z', 'a'..'z', 'а'..'я', '_'];
WorkDays := [Mon..Fri];
FreeDays := [Sun, Sat];
L := Sat in WorkDays; {L = False in – принадлежность
множеству}
L := Wed in WorkDays; {L = True}
MyDays := WorkDays + FreeDays; {Объединение. Результат [Sun..Sat]}
MyDays := WorkDays - FreeDays; {Разность. Результат [Mon..Fri]}
MyDays := WorkDays * FreeDays; {Пересечение.Результат []}
end.
Следующие типы будут изучены позднее:
- структурированные типы "файл" (File)
структурированные типы "объект" (Object)
простой тип “указатель” (Pointer)
Подпрограммы - особо оформленные отдельные части алгоритма программы, допускающие накопление готовых алгоритмов для использования во все новых программах. Подпрограммы - строительный материал больших программ. Подпрограммы - средство борьбы со сложностью программ.
Модуль - фундаментальное понятие и функциональный элемент технологии структурного программирования.
Чтобы подпрограмма стала модулем, ее надо оформить особым образом.
Модулю должны быть приданы следующие свойства:
1) выполнять строго однозначную функцию (от слова функционирование), например "расчет зарплаты", но не "расчет зарплаты и/или расчет значения синуса";
2) иметь один вход;
3) иметь один выход;
4) вызывать при необходимости другие модули;
5) обеспечивать раздельную от текста других модулей компиляцию, при которой "забываются" все обозначения внутренних идентификаторов (кроме имени самого модуля и имен вызываемых модулей), что облегчает коллективное написание больших программ при отсутствии необходимости согласования внутренних имен;
6) длина текста модуля должны быть обозрима (Рекомендуемая длина модуля 25 или 60 строк, но модуль может включать только один выполняемый оператор или иметь длину до 200 строк).
Следствие: модуль не использует значений глобальных переменных или их использует очень ограниченно.
Сложные программы состоят из единственного модуля основной программы и подпрограмм. Сначала модуль основной программы согласно алгоритму вызывает подпрограммы, далее подпрограммы вызывают все новые подпрограммы.
Пример основной программы:
program My_Main; {Заголовок основной программы}
{Комментарий назначения программы}
{Здесь могут находиться описания глобальных меток,
констант и переменных для глобально описанных
подпрограмм и тела основной программы}
{Здесь могут находиться описания глобальных процедур,
которые могут вызываться описанными ниже по тексту
подпрограммами и в теле основной программы}
begin
{Тело основной программы}
{Выполнение программы начинается с исполнения первого
выполняемого оператора тела основной программы}
end.
Среди подпрограмм различают процедуры и функции.
Процедуры и функции различаются способом вызова при выполнении.
Пример оформления процедуры:
procedure My_Proc; {заголовок процедуры}
{Комментарий назначения процедуры}
{Здесь могут находиться локализованные текстом процедуры
описания меток, констант и переменных для тела процедуры.
Данные описания являются глобальными для описанных в тексте
процедуры подпрограмм}
{Здесь могут находиться описания подпрограмм, которые могут вызываться описанными ниже по тексту подпрограммами и в теле процедуры}
begin
{Тело процедуры}
{Выполнение процедуры начинается с исполнения первого
выполняемого оператора тела процедуры}
end; {My_Proc}
Процедуры вызываются при выполнении особым отдельным оператором.
Пример:
My_Proc;
При выполнении этого оператора будут выполнены все действия
согласно процедуре My_Proc
Пример оформления функции:
function My_Func: Integer; {заголовок функции}
{Комментарий назначения функции}
{Здесь могут находиться локализованные текстом функции
описания меток, констант и переменных для тела функции.
Данные описания являются глобальными для описанных в тексте
функции подпрограмм}
{Здесь могут находиться описания подпрограмм, которые могут вызываться описанными ниже по тексту подпрограммами и в теле функции}
begin
{Тело функции}
{Выполнение функции начинается с исполнения первого
выполняемого оператора тела функции}
My_Func := ...; {Обязательное присвоение для функции значения вычисленного результата. Тип результата определен в заголовке функции.}
end; {My_Func}
Функции вызываются в процессе выполнения расчета выражений.
Пример:
y := 5.0*sin(x)+2.0;
Здесь вызывается функция вычисления значения синуса аргумента x. Функции и процедуры могут не иметь аргументов. Процедура может не возвращать результатов. Функция должна возвращать хотя бы единственный результат - значение функции. Не рекомендуется, но возможен, возврат результатов у функции через механизм формальных и фактических параметров.
При необходимости в заголовках процедур или функций в круглых скобках указывается список формальных параметров.
Например:
procedure Integral(a, b, e: Real; var z: Real);
{Расчет значения определенного интеграла}
Описания формальных параметров ничем не отличаются по форме от описания переменных программы. Описатель var записывается перед описанием выходных параметров. Рекомендуется записывать сначала все входные параметры и далее все выходные параметры.
Описатель var в списке формальных параметров означает, что значения будут передаваться по ссылке (то есть посредством значения указателя). Поэтому используемые значения могут быть как входными, так и выходными. Внутри функций и процедур использование значений, переданных по ссылке, ничем не отличается от обычного использования переменных.
Описанные в заголовке формальные параметры, выполняют роль локализированных в пределах текста процедуры или функции переменных - носителей значений входных и выходных данных.
В списке формальных параметров нельзя описывать структурированные переменные.
Например, ошибочным будет описание:
function Determinant(A: array [1..4, 1..4]) of Real): Real;
Ниже приведен пример правильного описания:
type
TDetMatrix: array [1..4, 1..4] of Real;
function Determinant
(A: TDetMatrix) of Real {Исходная квадратная матрица}
): Real; {Значение определителя}
{Функция вычисляет значение определителя квадратной матрицы
размером 4*4}
Фактические параметры указываются в вызывающих операторах.
Между списками фактических и формальных параметров должно быть установлено соответствие по типам и по порядку следования в них данных. Причем, обозначения идентификаторов данных могут не совпадать.
Формальным параметрам с входными данными (аргументам) могут соответствовать константы, переменные, выражения, идентификаторы функций.
Формальным параметрам с выходными данными (результатам) могут соответствовать только переменные.
Например:
следующему списку формальных параметров
(i, j: Integer; y: Real; S: String; var y: real; var m: integer)
может соответствовать следующий список фактических параметров
type
k, l: Integer;
y: array[1..9] of Real;
(3, 2*k+1, 5.0, 'Положение регулятора', y[5], l)
Как видно, элементы списка фактических параметров всегда отделяются запятыми.
Большинство изложенных далее процедур находится в библиотеке Crt.
Процедура Window определяет окно вывода информации на экране дисплея:
procedure Window(X1, Y1, X2, Y2: Byte);
Замечания:
X1 и Y1 являются координатами верхнего левого угла окна. X2 и Y2 являются координатами нижнего правого угла окна. Координата X соответствует горизонтали, а Y - вертикали.
Самому верхнему левому углу экрана соответствуют координаты (1, 1). Окно минимальных размеров соответствует одному символу. Если значения координат неверны, то процедура Window не формирует никакого окна.
По умолчанию перед выполнением программы устанавливается окно во весь экран. Например, (1, 1, 80, 25) в текстовом режиме экрана 25 строк.
Сформированное процедурой Window окно для большинства процедур библиотеки Crt образует виртуальное окно со свойством экрана дисплея, но меньших дисплея размера. После выполнения Window координата (1, 1) соответствует левому верхнему углу окна.
После выполнения процедуры Window курсор автоматически перемещается в точку координатами (1, 1), которая соответствует левому верхнему углу окна.
Процедура ClrScr очищает активное окно дисплея, используя текущий цвет фона и символов для всего окна, автоматически перемещает курсор в точку координатами (1, 1):
procedure ClrScr;
Процедура TextBackground задает текущий цвет Color поля вывода текста:
procedure TextBackground(Color: Byte);
Замечание:
Color может принимать значения 0..7
Процедура TextColor задает текущий цвет Color символов выводимого текста:
procedure TextColor(Color: Byte);
Замечание:
Color может принимать значения 0..15
В Crt определены константы цветов:
Темные цвета (Символов и фона):
Black 0
Blue 1
Green 2
Cyan 3
Red 4
Magenta 5
Brown 6
LightGray 7
Светлые цвета (Символы):
DarkGray 8
LightBlue 9
LightGreen 10
LightCyan 11
LightRed 12
LightMagenta 13
Yellow 14
White 15
Процедуры HighVideo, LowVideo, NormVideo соответственно устанавливаю высокую, низкую и нормальную интенсивность яркости выводимых символов.
Процедура ClrEol очищает поле экрана от позиции с курсором до конца строки. Действует подобно ClrScr, но не изменяет положения курсора.
Процедура GotoXY перемещает курсор дисплея в точку окна с заданными координатами:
procedure GotoXY(X, Y: Integer);
Функции WhereX, WhereY соответственно возвращают целое значение координат X и Y положения курсора на экране.
Обычно вывод информации в окно экрана дисплея осуществляется процедурами:
WriteLn(список фактических параметров);
Write(список фактических параметров);
Обе процедуры начинают вывод информации с места позиции окна дисплея, которое отмечено курсором. В процессе вывода информации курсор устанавливается за последним выведенным символом. При выходе за границу окна экрана автоматически происходит перенос вывода на новую строку. В конце выполнения процедуры WriteLn дополнительно производится переход курсора к началу новой строки.
WriteLn; {Вызов без параметров дает пропуск строки}
Процедуры ReadLn и Read соответственно аналогичны
процедурам WriteLn и Write. Однако они используются для чтения информации вводимой с клавиатуры.
Пример использования процедур:
program ReadWrite;
uses
Crt; var
s : String;
begin
ClrScr; {Очистка экрана дисплея}
Write ('Введите строку текста: ');
ReadLn (s);
WriteLn('Вы вводили строку: ',s);
WriteLn('Нажмите <Enter> для завершения программы');
Readln; {Ожидание ввода любой строки}
ClrScr; {Очистка экрана дисплея}
end.
Процедуры ReadLn, Read, WriteLn, Write на самом деле являются операторами и только имеют форму процедур. Благодаря этому, их можно использовать с переменным количеством параметров.
Процедуры WriteLn, Write допускают форматный вывод информации. Для этого за выводимым фактическим параметром через двоеточие указывается длина поля вывода в количестве выводимых символов. Для вещественных переменных дополнительно может быть указано количество выводимых символов в дробной части числа. Если форматы выводимых величин не указаны, то вывод осуществляется с предельной точностью.
Например:
Следующий оператор WriteLn выведет на экран строку:
var
k: integer;
x: real;
b: boolean;
begin
k := 78;
x := 0;
b := True;
WriteLn('k=', k:3, ' x=', x:6.4, ' b=', b:2); end.
Результат:
k= 78 x= 0.0000 b= T
Процедура (оператор) Str преобразует значение переменной X в строку символов S:
procedure Str(X [: Ширина [: Символов в дробной части ]];
var S: string);
Процедура Val преобразует строку символов S с последовательностью символов в виде полного численного значения в значение численной переменной V:
procedure Val(S; var V; var Code: Integer);
После выполнения процедуры Val в целой переменной Code находится значение кода ошибки. Значение Code = 0 соответствует безошибочному завершению.
Функция ReaKey читает одиночный символ, введенный с клавиатуры:
function ReadKey: Char;
Замечание:
Введенный символ не отображается на экране.
Функция KeyPressed возвращает значение True, если была нажата клавиша на клавиатуре. При этом нажатый символ не теряется и его код далее может быть прочитан функцией ReadKey:
function KeyPressed: Boolean;
Структура АЛЬТЕРНАТИВА имеет четыре конструкции.
Конструкция для одной альтернативы:
if L then
begin
{Действие при L=True}
end;
Конструкция для двух альтернатив:
if L
then
begin
{Действие при L=True}
end
else
begin
{Действие при L=False}
end;
Первый вариант конструкции для нескольких альтернатив (ВЫБОРА):
if L1 then
begin
{Действие при L1=True}
. . .
end;
if L2 then
begin
{Действие при L2=True}
. . .
end;
if L3 then
begin
{Действие при L3=True}
. . .
end;
. . .
Второй вариант конструкции для нескольких альтернатив (ВЫБОРА):
Switch := 0;
L1 := . . .;
L2 := . . .;
L3 := . . .;
. . .
if L1 then Swich := 1;
if L2 then Swich := 2;
if L3 then Swich := 3;
. . .
case Switch of
1:begin
{Действие при L1=True}
. . .
end;
2:begin
{Действие при L2=True}
. . .
end;
3:begin
{Действие при L3=True}
. . .
end;
else
begin
{Вывод сообщения об
ошибочном кодировании
модуля}
end;
end; {End of Case}
Последняя конструкция соответствует очень сложной логике условий. В простейших случаях допускается упрощенная кодировка:
if a > b then x:=y+3 else x:=y+6;
ВЫБОР из более чем двух АЛЬТЕРНАТИВ нельзя кодировать при помощи вложения других структур простейших АЛЬТЕРНАТИВ из-за большой вероятности ошибок.
Не универсальный ЦИКЛ-ДО имеет две конструкции и используется для задания заданного числа повторений.
Конструкция по возрастанию:
for i:=3 to 5 do
begin
{тело цикла i=3,4,5}
end;
Конструкция по убыванию:
for i:=5 downto 3 do
begin
{тело цикла i=5,4,3}
end;
Здесь i - переменная цикла. Обычно эти циклы не требуют после кодирования дополнительного тестирования.
Универсальные циклы имеют конструкции ЦИКЛ-ДО и ЦИКЛ-ПОКА.
Универсальный ЦИКЛ-ПОКА:
{Подготовка}
while L do
begin
{Тело цикла}
end;
Универсальный ЦИКЛ-ДО:
{Подготовка}
repeat
{Тело цикла}
until L;
Здесь L логическое выражение при значении True является условием продолжения выполнения ЦИКЛ-ПОКА или условием окончания выполнения ЦИКЛ-ДО. Подготовка и тело цикла являются СЛЕДОВАНИЯМИ. Тело цикла выполняется столько раз, сколько и весь цикл. Признаком ЦИКЛ-ПОКА является возможность не выполнения тела цикла ни разу. При равноценности, из двух конструкций ЦИКЛ-ДО и ЦИКЛ-ПОКА выбирают ту, запись которой короче.
ВНИМАНИЕ: При программировании на языке C структура УНИВЕРСАЛЬНЫЙ ЦИКЛ-ДО должна включать операцию «!» (НЕ):
/* подготовка цикла */
do
{
/* Тело цикла */
. . .
}
while (!(L));
При пошаговом уточнении программы задача разбивается на подзадачи до тех пор, пока их решение не будет выражено в нескольких строках языка программирования. При этом основное внимание уделяется либо первичной декомпозиции программных единиц и мало внимания уделяется вторичной декомпозиции структур данных (структурное программирование). Либо процесс декомпозиции выполняется с точностью до наоборот, когда основное внимание уделяется данным и мало внимания уделяется функциям программных единиц (метод абстракции данных Дейкстры). Ранее большинство технологий пытались в какой-то мере сблизить эти два крайних подхода.
Объектно-ориентированное программирование (ООП) - это способ программирования, обеспечивающий модульность программ за счет разделения памяти на области, содержащие данные и процедуры. Области могут использоваться в качестве образцов, с которых по требованию могут делаться копии.
Объекты (капсулы или классы) - это наименее зависимые по данным части программы. Объекты моделируют свойства и поведение компонентов мира, в котором мы живем. Они являются конечной абстракцией данных. Объектный тип является записью (структурой), состоящей из фиксированного числа компонентов. Каждый компонент является либо полем, содержащим данные строго определенного типа, либо методом, выполняющим операции над объектом. По аналогии с описанием переменных, описание поля указывает тип данного этого поля и идентификатор, именующий поле: по аналогии с описанием процедуры или функции, описание метода указывает заголовок процедуры, функции, конструктора или деструктора. Другими словами, объект представляет собой данные и код в одном месте. Данные специфицируются и детализируются вместе с действиями, применяемыми для их обработки.
Наиболее существенно различие, проводимое в программировании между данными процедурами. Оно в определенной степени отражает различие между аппаратурой процессора и схемами памяти. На такой архитектуре машины основана модель программы, в которой данные запоминаются в памяти, а инструкции процессоров манипулируют этими данными. В этой модели данные выполняют пассивную роль, а оперирующие над ними инструкции являются активными элементами.
ООП - это шаг на пути к другой модели программирования с активными данными. Один из основных способов взаимодействия объектов в ООП, придающий данным активный характер, - это передача сообщений. В посылаемых объекту сообщениях указывается, что мы хотим, чтобы он выполнил. Так, например, если мы хотим вывести на экран строку, то мы посылаем строке сообщение, чтобы она изобразила себя. В этом случае строка - это уже не пассивный кусок текста, это активная единица, знающая, как правильно производить над собой различные действия.
Посылка сообщений требует, как минимум, указания имени адресата. В качестве аргументов могут использоваться имена переменных, известных исключительно принимающему объекту, или имена глобальных переменных. Объекту можно посылать такие сообщения, как: записать в себя знак; вывести на экран; уничтожить себя и т.д.
Сообщения могут быть приняты или отвергнуты. Объект принимает те сообщения, которые опознает, а остальные игнорирует. Поскольку этому протоколу следуют все объекты, внешний по отношению к объекту код не может непредсказуемым или нежелательным способом влиять на функционирование этого объекта.
Хотя передача сообщений придает поведению объектов характер активных данных, изнутри объекта по-прежнему существует четкое разделение пассивных данных и активных процедур.
В определении ООП сказано, что область кода объекта может использоваться в качестве образца для изготовления копий. Это означает, например, что как только определен объект "окно", так сразу можно создать столько таких окон, на сколько хватит памяти. При этом не понадобится создавать дополнительный код, позволяющий убедиться в отсутствии взаимодействия. Утверждая возможность копирования, здесь имеется в виду только способ поведения объектов. Внешне все выглядит так, как если бы существовало несколько подобных копий. Пожалуйста, отметьте, что из сказанного не следует способ реализации.
Три основных свойства характеризуют язык объектно-ориентированного программирования:
ИНКАПСУЛЯЦИЯ - это совмещение в одной записи языка программирования структур данных с процедурами и функциями, которые манипулируют полями данных этой записи, для получения нового типа данных - объекта. Инкапсуляция - это защита по интерфейсу доступа к полям и методам. Доступ разрешен лишь к открытым методам и полям. Полная совокупность методов и тонкости их реализаций являются скрытыми. Объекты связывают в единое целое свои свойства и поведение. Отношения частей к целому и к другим частям более ясны, когда все связано вместе, в одной оболочке.
НАСЛЕДОВАНИЕ - это определение объекта или класса и затем использование его для построения иерархии производных объектов или классов, причем каждый производный объект ("потомок") наследует доступ к коду и данным всех своих "прародителей". При этом, возможно, переопределение или добавление, как новых данных, так и методов. Наследование является транзитивным, то есть если Q3 наследует от Q2, а Q2 наследует от Q1, то Q3 наследует от Q1. Область (домен) объектного типа состоит из него самого и из всех его наследников.
ПОЛИМОРФИЗМ - это придание действию одного имени, которое совместно используется объектами всей иерархии, причем каждый объект или класс иерархии имеет возможность по-своему реализовать это действие своим собственным, подходящим для него, кодом.
Определение интерфейса объекта на Borland Pascal напоминает определение интерфейсной части модулей Borland Pascal и структур данных record.
Все поля данных и методы должны быть описаны до описания первого правила выполнения метода. Как и в случае с описаниями функций и процедур в разделе interface модуля, описания правил внутри объекта сообщают, ЧТО делает правило, но не КАК оно это делает.
type { Описание интерфейса объекта работы с пикселем }
Point = object { Предок или родительский тип }
public (* Открытые поля данных и методы *)
{Поле} X, Y : integer;
{Поле} color : word;
{Поле} Visiable : boolean;
{Метод} procedure Create(a, b : integer; c : byte);
{Метод} procedure SetMyColor(c : word);
{Метод} function GetMyColor : word;
{Метод} procedure SwitchOn;
{Метод} procedure SwitchOff;
{Метод} procedure Move(dX, dY : integer);
{Метод} function GetX : integer;
{Метод} function GetY : integer;
private (* Скрытые поля данных и методы *)
{Здесь могут находиться описания скрытых полей
данных и методов}
end;
"КАК" определяется ВНЕ описания объекта, в отдельном определении процедуры или функции, реализующих метод. Когда правила метода или собственно метод полностью определяются вне объекта, перед именем правила метода должно стоять имя типа объекта, который владеет этим правилом, за которым ставится точка.
procedure Point.Create(a, b : integer; c : byte);
begin
X := a;
Y := b;
Visiable := False;
Color := c;
end;
procedure Point.SetMyColor(c : word);
begin
Color := c;
end;
{ Описания реализаций других методов Point }
Статическое наследование реализуется на этапе компиляции и состав методов не может быть изменен при выполнении.
Процедура Move внешне похожа для двух объектов: Point - точки, Circle - окружности.
procedure Move(dX, dY : integer);
begin
SwitchOff; X := X + dX; Y := Y + dY; SwitchOn;
end;
Однако это разные методы для разных фигур. Если бы объект Circle просто бы унаследовал бы метод Move от Point, то при выполнении
FirstCircle.Move(80, 40);
окружность не была бы перемещена, а перемещена лишь его точка центра методом, унаследованным от Point. Экземпляр типа-потомка жестко связан с методами Point.SwitchOFF и Point.SwitchOn и жестко выполнит именно их. Связь методов статична и заложена при компиляции. Разрыв этой связи возможен введением виртуальных методов.
При наследовании одним объектом другого, поля данных всегда безусловно наследуются. Переопределены могут быть только методы. В новом типе типе-потомке новый одноименный метод может иметь другие параметры.
Присваивать переменным типа предок можно только значения потомков, а не наоборот. При этом копируются только поля, общие для двух типов.
unit
Graphica;
interface
uses
Crt, Graph;
{ Инкапсуляция: поля и методы описаны в одном типе }
{Описатель private используется для скрытия информации}
type { Объект работы с пикселем }
Point = object { Предок или родительский тип}
(* Описание полей данных и методов Point *)
end;
type { Вычерчивание окружности }
Circle = object(Point) { Первый наследник род. типа }
{ Поля данных и методы здесь также
инкапсулированы}
{ Поля X, Y, color, Visiable унаследованы от
объекта Point }
Radius :integer { Новое собственное поле }
procedure Create(a, b, r : integer; c : byte);
{ SetMyColor, GetMyColor унаследованы от Point }
procedure SwitchOn; { Новый собственный метод }
procedure SwitchOff; { Новый собственный метод }
procedure Move(dX, dY : integer);{ Нов.собст.метод}
function GetR : integer; { Новый собствен. метод }
{ GetX, GetY унаследованы от Point }
end;
{implementation}
procedure Point.Create(a, b : integer; c : byte);
begin
X := a; Y := b; Visiable := False; Color := c;
end;
procedure Point.SetMyColor(c : word);
begin Color := c; end;
function Point.GetMyColor : word;
begin
GetMyColor := Color;
end;
procedure Point.Move(dX, dY : integer);
begin
SwitchOff; X := X + dX; Y := Y + dY; SwitchOn;
end;
{Описание реализации других функций и процедур Point}
procedure Circle.Move(dX, dY : integer);
begin
SwitchOff; X := X + dX; Y := Y + dY; SwitchOn;
end;
function Circle.GetR : integer;
begin GetR := Radius; end;
{Описание реализации других функций и процедур Circle}
end.
{ Основная программа }
Program Test1;
uses Crt, Graphica;
var
gd,gm : integer; { Переменные графической системы }
ch : char; { Рабочая переменная }
FirstPoint, SecondPoint : Point; { Переменные для
экземпляров объектов }
FirstCircle : Circle;
begin
gd := Graph.detect;
Graph.InitGraph(gd, gm, 'C:\TP7\BGI ');
FirstCircle.Create(FirstPoint.GetX,
FirstPoint.GetY, 80, 40, Cyan);
FirstCircle.SwitchOn;
ch := ReadKey;
FirstCircle.Move(-50, -50);
ch := ReadKey;
FirstCircle.SwitchOff;
ch := ReadKey;
end.
Статическое наследование реализуется на этапе компиляции и методы не могут быть переопределены при выполнении.
Свойство, когда один и тот же объект работает по-разному, называется полиморфизмом. По-разному могут работать виртуальные методы.
По умолчанию, методы являются статическими, однако они могут, за исключением конструкторов, быть виртуальными (посредством включения директивы virtual в описание метода). Компилятор разрешает ссылки на вызовы статических методов во время процесса компиляции, тогда как вызовы виртуальных методов разрешаются во время выполнения. Это иногда называют поздним связыванием.
Если объектный тип объявляет или наследует какой-либо виртуальный метод, то переменные этого типа должны быть инициализированы посредством вызова конструктора перед вызовом любого виртуального метода. Таким образом, объектный тип, который описывает или наследует виртуальный метод, должен также описывать или наследовать, по крайней мере, один метод-конструктор.
Объектный тип может переопределять любой из методов, которые он наследует от своих родителей. Если описание метода в потомке указывает тот же идентификатор метода, что и описание метода в родителе, то описание в потомке переопределяет описание в родителе. Область действия переопределяющего метода расширяется до сферы действия потомка, в котором этот метод был введен, и будет оставаться таковой, пока идентификатор метода не будет переопределен снова.
Переопределение статического метода не зависит от изменения заголовка метода. В противоположность этому, переопределение виртуального метода должно сохранять порядок, типы и имена параметров, а также типы результатов функций, если таковые имеются. Более того, переопределение опять же должно включать директиву virtual.
Если объектный тип содержит виртуальный метод, то он должен содержать особый метод - конструктор и может содержать особый метод - деструктор. Эти методы могут быть определены как в самом объекте, так и унаследованы от объекта - предка. При описании конструктора и деструктора слово procedure метода заменяется на слово constructor или destructor. В большинстве разработок имена конструкторов и деструкторов соответственно вводятся как Init и Done.
Метод-конструктор должен быть применен к экземпляру объекта до первого вызова виртуального метода. Конструктор не может быть виртуальным, так как механизм диспетчеризации виртуального метода зависит от конструктора, который первым совершил инициализацию объекта. На практике в качестве конструктора определяют метод, который выделяет динамическую память под динамические поля данных объекта и/или устанавливает некоторые начальные значения данных объекта. Каждый отдельный экземпляр объекта размещается в динамической памяти и должен быть инициализирован отдельным вызовом конструктора.
Действия завершения возлагаются на особые методы - деструкторы. В одном объектовом типе может быть несколько деструкторов. Деструкторы гарантируют правильное удаление памяти, как самих объектов, так и дополнительной динамической памяти под данные объекта.
unit DinGraph;
interface
uses
Crt, Graph;
type { Объект работы с пикселем }
Point = object { Предок или родительский тип }
X, Y : integer;
color : word;
Visiable : boolean;
constructor Create(a, b : integer; c : byte);
procedure SetMyColor(c : word); virtual;
function GetMyColor : word; virtual;
procedure SwitchOn; virtual;
procedure SwitchOff; virtual;
procedure Move(dX, dY : integer);virtual;
function GetX : integer; virtual;
function GetY : integer; virtual;
destructor Done;
end;
type { Вычерчивание окружности }
Circle = object(Point) { Первый наследник род. типа }
Radius : integer; { Новое собственное поле }
constructor Create(a, b, r : integer; c : byte);
procedure SwitchOn; virtual;
procedure SwitchOff; virtual; { Move наследуется с
автоматическим переопределением !!!}
function GetR : integer; virtual;
end;
implementation
constructor Point.Create(a, b : integer; c : byte);
begin
{ Здесь мы могли бы выделить динамическую память }
X := a; Y := b; Visiable := False; Color := c;
end;
procedure Point.SetMyColor(c : word);
begin Color := c; end;
function Point.GetMyColor : word;
begin GetMyColor := Color; end;
procedure Point.SwitchOn;
begin
Visiable := True; Graph.PutPixel(X, Y, GetMyColor);
end;
procedure Point.SwitchOff;
begin
Visiable := False; PutPixel(X, Y, Black);
end;
procedure Point.Move(dX, dY : integer);
begin
SwitchOff; X := X + dX; Y := Y + dY; SwitchOn;
end;
function Point.GetX : integer;
begin GetX := X; end;
function Point.GetY : integer;
begin GetY := Y; end;
destructor Point.Done;
begin
{ Здесь мы могли бы освободить динамическую память }
end;
constructor Circle.Create(a,b,r : integer; c : byte);
begin
Visiable := False; Radius: = R; Point.Create(a,b,c);
end;
procedure Circle.SwitchOn;
begin
Visiable := True;
Graph.SetColor(GetMyColor);
Graph.Circle(X, Y, Radius);
end;
procedure Circle.SwitchOff;
begin
Visiable := False;
Graph.SetColor(Black);
Graph.Circle(X, Y, Radius);
end;
function Circle.GetR : integer;
begin GetR := Radius; end;
end.
Program test2;
uses
Crt, DinGraph;
var
gd,gm : integer; { Переменные графической системы }
ch : char; { Рабочая переменная }
FirstPointPtr, SecondPointPtr : ^Point; {перемен-
ные для экземпляров объекта}
FirstCirclePtr : ^Circle;
begin
gd := Graph.detect;
Graph.InitGraph(gd, gm, 'C:\TP7\BGI ');
{ "Новый" вызов конструктора }
New(FirstPointPtr, Create(100, 200, Red));
FirstPointPtr^.SwitchOn;
{ "Старый" вызов конструктора }
New(SecondPointPtr);
SecondPointPtr^. Create(300, 300, Green);
SecondPointPtr^.SwitchOn;
ch := ReadKey;
FirstPointPtr^.Move(100, 50);
ch := ReadKey;
SecondPointPtr^.SwitchOff;
ch := ReadKey;
New(FirstCirclePtr, Create(FirstPointPtr^.GetX,
FirstPointPtr^.GetY, 80, 40, Cyan));
FirstCirclePtr^.SwitchOn;
ch := ReadKey;
FirstCirclePtr^.Move(-50, -50);
ch := ReadKey;
FirstCirclePtr^.SwitchOff;
ch := ReadKey;
{ Освобождение памяти экземпляра объекта с
вызовом деструктора Done }
Dispose(FirstCerclePtr, Done);
Dispose(FirstPointPtr, Done);
{ Освобождение памяти экземпляра объекта без
вызова деструктора Done "старым" способом }
Dispose(SecondPointPtr);
end.
Borland Pascal поддерживает дополнительные методы с поздним связыванием, которые называются динамическими методами. Динамические методы отличаются от виртуальных методов только характером их диспетчеризации на этапе выполнения. Во всех других отношениях динамические методы считаются эквивалентным виртуальным.
Описание динамического метода эквивалентно описанию виртуального метода, но описание динамического метода должно включать в себя индекс динамического метода, который указывается непосредственно за ключевым словом virtual. Индекс динамического метода должен быть целочисленной константой в диапазоне от 1 до 65535 и должен быть уникальным среди индексов других динамических методов, содержащихся в объектном типе или его предках. Например:
procedure FileOpen(var Msg: TMessage); virtual 100;
Переопределение динамического метода должно соответствовать порядку, типа и именам параметров и точно соответствовать типу результата функции порождающего метода. Переопределение также должно включать в себя директиву virtual, за которой следует тот же индекс динамического метода, который был задан в объектном типе предка.
Довольно частым является случай, когда метод, переопределяющий метод из объекта - предка, должен по своей логике обращаться к методу переопределенного предка.
Следующий пример схематически иллюстрирует распространенную практику использования метода HandleEvent (обработчик событий) из объекта TApplication пакета Turbo Vision.
type
TMyProgram = object(TApplication)
. . .
procedure HandleEvent(var Event : TEvent); virtual;
. . .
end;
procedure TMyProgram.HandleEvent(var Event : TEvent);
begin
. . .
TApplication.HandleEvent(Event);
. . .
end;
В Turbo Pascal v. 7.0 вместо строки
TApplication.HandleEvent(Event);
можно записывать строку
inherited HandleEvent(Event);
Новое ключевое слово inherited означает унаследованный и используется для активизации уточненных методов.
[Назад] [Содержание]