Спецкурс Программирование на Паскале

advertisement
Программирование на Паскале
Кемерово, 2005
2
Содержание
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
Основы алгоритмов. Блок-схемы. ........................................................................................4
Среда Turbo Pascal .................................................................................................................5
Структура программы ...........................................................................................................6
Основные типы данных ........................................................................................................7
Операторы ввода и вывода ...................................................................................................7
Оператор присваивания. Стандартные функции. ...............................................................8
Оператор условного и безусловного перехода. ................................................................10
Оператор выбора .................................................................................................................11
Операторы цикла .................................................................................................................12
Массивы............................................................................................................................14
Текстовый файл ...............................................................................................................16
Записи ...............................................................................................................................19
Процедуры и функции пользователя .............................................................................24
Модуль CRT .....................................................................................................................29
Модуль Graph ...................................................................................................................32
3
1. Основы алгоритмов. Блок-схемы.
Алгоритм – это последовательный набор команд, направленный на решение той или
иной задачи.
Алгоритм можно оформить в виде:
- в виде списка последовательных команд,
- алгоритмического языка,
- блок-схемы,
- программы на языке программирования.
Алгоритмы могут быть:
1) линейные
2) разветвляющиеся
3) циклические
4) составные
Блок
Назначение
Команда на Паскале
Начало действия
Begin
Начало
команд
Блок ввода
данных
Read( );
Readln( );
Блок действия
A:=5;
B:=A+6;
Блок выбора
решения
If A>0 then {да}…
else {нет}…
Блок для
формирования
цикла
For k:=1 to 10 do …
For k:=10 downto 1 do …
Ввод данных
Выполнение
действия
нет
условие
Параметры
цикла
да
Тело цикла
4
Блок
Вывод
результата
Назначение
Блок вывода
данных на печать,
в файл или на
экран
Команда на Паскале
Write ();
Writeln ();
Блок завершения
алгоритма
End.
Конец
2. Среда Turbo Pascal
Для выполнения программы на языке программирования Паскаль используют
следующие этапы:
- с помощью текстового редактора набирают код программы
- с помощью программы - компилятора создают выполняемый код программы
- с помощью программы – отладчика проводят пошаговую реализацию программы и
контроль данных.
Все это выполняется с помощью специальной программы – интегрированной среды
Turbo Pascal:
Интегрированная среда Turbo Pascal работает как многооконный редактор и как отладчик
программ.
Команда
Назначение
F10
Выход в меню
File, New
Создание нового окна для редактирования
File, Save
F2
Сохранение в файл
File, Open…
F3
Открыть файл в текущее окно
File, Save as…
Сохранить под именем файла
File, Change dir…
Изменить текущий каталог
File, Exit
Alt+X
Выход
Option, Directories…
Задание путей к файлам Turbo Pascal
Edit, Undo
Alt+BackSpace
Отмена предыдущего действия
Edit, Cut
Shift+Delete
Вырезать выделенный фрагмент
Edit, Copy
Ctrl+Insert
Скопировать выделенный фрагмент
Edit, Paste
Shift+Insert
Вставить выделенный фрагмент
Edit, Clear
Ctrl+Delete
Очистить выделенный фрагмент
Window, Close
Alt+F3
Закрыть активное окно
5
Команда
Window, Zoom
F5
Window, Size/Move
Ctrl+F5
Window, Next
Window, Previous
Window, List …
Help, Index
F6
Shift+F6
Alt+0
Shift+F1
Help, Topic search
Compile, Compile
Run, Run
Ctrl+F1
Alt+F9
Ctrl+F9
Run, Step over
Run, Trace into
F8
F7
Run, Go to cursor
F4
Run, Program reset
Debug, User screen
Ctrl+F2
Ctrl+Break
Alt+F5
Debug, Add watch…
Ctrl+F7
Breakpoints On/Off
Go to window
Ctrl+F8
Alt+№ окна
Назначение
Развернуть окно
Перейти в режим изменения размера и
местоположения текущего окна
Перейти к следующему окну
Перейти к предыдущему окну
Перейти к списку открытых окон
Вывод окна помощи в виде предметного
указателя
Вывод окна помощи по текущему слову
Компилировать
Выполнить или продолжить выполнение
программы
Выполнить один шаг программы
Выполнить один шаг программы с заходом
в процедуры и функции пользователя
Выполнить программу до местоположения
курсора
Остановить выполнение программы
Прервать выполнение программы
Перейти на экран пользователя для
просмотра результата выполнения
программы
Добавить в окно Watch контрольные
значения
Добавить/отключить точки останова
Перейти в окно под заданным №
3. Структура программы
Программа на Паскале строится по логике построения предложения. Каждое
действие заканчивается точкой с запятой, а сама программа – точкой.
В Паскале существует понятие идентификатора – уникальное имя, которое дается
определенному понятию для того, чтобы можно было к нему обратиться во время
выполнения программы. Это – имя программы, имена используемых модулей, имена
констант, переменных и типов, имена функций и процедур, определенных пользователем.
{блок описаний используемых идентификаторов}
Назовем программу …;
Program
name;
которая использует процедуры,
функции, константы, типы следующих
модулей (библиотек) …;
определим метки, используемые в
программе в операторе GOTO, …;
зададим константы …;
Uses
Crt;
Label
1;
Const
myname=’Rita’;
будем использовать свои имена для
описания типов переменных и
констант …;
в программе используем переменные
…, такие, что они имеют тип …;
Type
myint=Integer;
Var
A,b: myint;
6
будем использовать функцию …,
которая возвращает значение
указанного типа и выполняет
следующие действия …;
Procedure
используем свою процедуру …,
myProc(<список параметров>);
которая выполняет с введенными
{описание работы процедуры}
параметрами следующие действия …;
{основной блок выполнения программы}
Begin
а теперь начнем выполнять
{блок операторов}
следующие команды, записанные в
End.
виде известных операторов языка
Паскаль … до окончания алгоритма.
Function
myFunc(<список параметров>):<тип>;
{описание работы функции}
4. Основные типы данных
Тип
Integer
Real
Значение
Натуральные или целые числа
Вещественные числа с
десятичной запятой
String
Строка символов, заключенных
в апострофы
Char
Один символ, заключенный в
апострофы
Boolean Логическое значение TRUE
(истина) или FALSE (ложь)
Примеры
-2, 10, 0, 565
-2.5, 100.0005, 1.14587е+20 (1.14587*1020),
2.0047е-05 (2.0047*10-5)
’12,45’, ‘Мир, труд, май!’, ‘For English city.’,
‘1000000000000001’
‘F’, ‘Ф’, ’1’, ’0’, ’*’
True, False
5. Операторы ввода и вывода
Для работы с данными их нужно задать – ввести с клавиатуры.
READ(); {считываем данные в строке в переменные, указанные в скобках}
READLN(); {считываем данные в строке в переменные, указанные в скобках,
и переходим на следующую строку}
В скобках необходимо указать имена переменных, которым будут присвоены
введенные значения.
READ(N,M);
{ввести два целых числа через пробел (N, M объявлены как переменные целого типа)}
READLN(F);
READLN(S);
{ввести вещественное число через точку (F должно быть объявлено как переменная
вещественного типа), затем с новой строки ввести строку символов размером не более
255 (S должно быть объявлено как строковая переменная) }
ВНИМАНИЕ:
1) если ввести число и строку в одну строчку, то строка не будет считана.
2) если ввести сначала строку, а потом число оператором
READLN(S,F);
то число может быть так и не прочитано, так как в строку может войти и введенное
число. Тогда нужно ограничить число вводимых символов в строке (например, String[5]) и
вводить только такое количество символов, а затем вещественное число.
Для вывода результата используют оператор
WRITE(); {написать (вывести на печатающее устройство) данные в строку}
7
WRITELN(); {написать (вывести на печатающее устройство) данные в строку
и перейти на следующую строку}
В скобках через запятую перечисляют переменные и константы с указанием формата
(шаблона) для вывода:
WRITE(‘ N=’, N:4);
{вывести ‘ N=’, затем значение переменной N, такое, что оно разместилось бы в 4
позиции}
WRITELN(‘ F=’, 3.456:7:2);
{вывести ‘ F=’, затем число 3.456 так, чтобы оно разместилось бы в 7 позиций, из
которых 2 отведено под десятичные цифры}
WRITE(‘Введите s =’:20); READLN(S);
{вывести ‘ Введите s =’ так, чтобы оно разместилось в 20 позиций, затем ввести с
клавиатуры значение, которое будет присвоено переменной S}
6. Оператор присваивания. Стандартные функции.
Можно задать значения через оператор присваивания.
<Имя переменной> := <выражение или значение>;
{пусть заданная переменная получит (присвоит) такое значение, которое будет равно
заданному выражению}
Выражения в зависимости от типа переменной могут быть - логическими,
арифметическими или строковыми.
Выражение строится по определенным правилам с использованием применимых к
этому типу операций:
Выражения
5<3
5>3
5<>3
5=3
5<=3
5>=3
Not (5<>3)
(5>3)and(5>10)
(5<3)or(5>10)
5 xor 5 xor 3
5 in [1..5]
5+5
5-5
5*5
5/2
5 div 2
5 mod 2
‘Я‘+’ и ‘ +’мы’
Полученное
значения
Операции
Логические
False
<
True
>
True
<>
False
=
False
<=
True
>=
False
Not
True
And
True
Or
3
Xor
True
In
Арифметические
10
+
0
25
*
2.5
/
2
Div
1
Mod
Строковые
‘Я и мы’
+
8
Назначение
Меньше
Больше
Не равно
Равно
Меньше или равно
Больше или равно
Не (отрицание)
И (пересечение)
Или (объединение)
Исключающее или
Принадлежит множеству
Сложение
Вычитание
Умножение
Десятичное деление
Целочисленное деление
Остаток от деления
Конкатенация
(соединение)
Кроме перечисленных операций над переменными могут воздействовать
стандартные функции или функции, определенные пользователем.
Функция
Ord(‘Z’)
Chr(90)
Odd(6)
Параметры
Символ
Число
Целое число
Pred(34)
Целое число или символ
Succ(33)
Целое число или символ
Abs(-5)
Sqr(2)
Sqrt(4)
Sin(pi)
Cos(pi/2)
Arctan(0)
Int(3.45)
Frac(3.45)
Round(3.45)
Trunc(2.5)
Число
Число
Число
Число
Число
Число
Вещественное число
Вещественное число
Вещественное число
Вещественное число
Random(2)
Целое число N
Random
Без параметров
Concat(‘Я’, ’ и
’, ’мы’)
Length(‘мама’)
Pos(‘м’,’мама’)
Copy(’мама’,
1, 2)
Список строковых
переменных или значений
Строка
Подстрока и строка
Строка, номер позиции и
количество символов
Значение
Код символа (=90)
Символ, указанного кода (=’Z’)
Логическое значение истина,
если число нечетное, или ложь,
если число четное (=False)
Предыдущий символ или число
(=33)
Следующий символ или число
(=34)
Абсолютное значение числа (=5)
Квадрат числа (=4)
Корень квадратный из числа (=2)
Синус числа (=0)
Косинус числа (=0)
Арктангенс числа (=0)
Целая часть (=3)
Дробная часть (=0.45)
Целое число без округления (=3)
Целое число округленное до
ближайшего целого числа (=3)
Случайным образом полученное
целое число из диапазона [0..N-1]
(=0 или =1)
Вещественное число из
диапазона от 0 до 1
Строка, объединяющая эти
значения (=’Я и мы’)
Длина строки (=4)
Позиция подстроки в строке (=1)
Копирует из строки, начиная с
указанной позиции, заданное
число символов (=‘ма’)
Кроме функций определены следующие стандартные процедуры:
Процедура
Inc (I)
Параметры
Переменная целого типа и
шаг изменения
Dec (I,10)
Переменная целого типа и
шаг изменения
Insert (‘!’, S,
1)
Подстрока, строка, номер
позиции
Delete (S, 1, 2) Строка, номер позиции и
количество символов
9
Назначение
Та же переменная, увеличенное
на указанное число шагов или
на 1, если не указан шаг (i:=i+1)
Та же переменная, уменьшенное
на указанное число шагов или
на 1, если не указан шаг (i:=i-10)
Вставляет подстроку в строку,
начиная с указанной позиции
(S:=‘!’+S)
Удаляет из строки, начиная с
указанной позиции, заданное
Str (5.6, S)
Val (‘5.6’, K,
code)
Число и строковая
переменная
Строка, числовая константа
и код ошибки
число символов (если S:=’Ok!’,
то после delete S:=’!’)
Преобразует число в строку
(S:=’5.6’;)
Преобразует строку в число
(K:=5.6; code:=0;)
7. Оператор условного и безусловного перехода.
Рассмотрим операторы, реализующие разветвленный алгоритм (алгоритм с двумя
выборами пути решения, к которому переходим в зависимости от значения логического
выражения или ответа на вопрос).
Фрагмент блок-схемы
Оператор
Назначение
да
Условие,
вопрос
Если <условие>
истинно, то
выполняем
действия 1, иначе
(если условие
ложно) выполняем
действие 2
IF <УСЛОВИЕ>
THEN <ОПЕРАТОРЫ 1>;
<ОПЕРАТОРЫ 2>;
Если <условие>
истинно, то
выполняем
действия 1, и потом
( и если условие
ложно) выполняем
действие 2
2. Действия, если
ответили нет
1. Действия, если
ответили да
да
нет
IF <УСЛОВИЕ>
THEN <ОПЕРАТОРЫ 1>
ELSE <ОПЕРАТОРЫ 2>;
Условие,
вопрос
нет
1. Действия, если
ответили да
2. Действия, если
ответили нет и
после действия да
Задание №1. Необходимо найти значение функции y=1/x. При x=0 функция не имеет
значения. Тогда мы будем выдавать это сообщение. Построим блок-схему к задаче и
напишем программу на Паскале.
Построим алгоритм решения задачи:
1. Определим тип переменной х как вещественный.
2. Введем значение переменной х с клавиатуры.
3. Проверим условие на 0. Если оно истинно, то выводим сообщение,
иначе выводим значение функции.
4. В операторе вывода добавим формат для вещественных чисел.
Приведем блок-схему и по ней построим программу действий:
10
Описание переменных:
Var x:real;
Begin
начало
Write(‘Введите значение х=’); {комментарий}
Readln(x);
Ввод х
да
нет
Х=0 ?
Вывод
сообщения
Вывод
Y=1/X
IF (x=0)
Then {да}
Else {нет}
writeln(‘Y=’,
writeln(‘Функция не
1/X:9:4);
имеет значения!’)
End.
конец
8. Оператор выбора
Создадим меню команд: «Ввод данных», «Вывод результата», «Выход». По выбранному
пункту будем выводить соответствующие команды.
Описание метки:
Label
Menu; {задаем метку строки для перехода на нее}
Описание переменных:
Var
K:[0..2]; {указываем диапазон изменения данных}
x: real;
Begin
начало
Menu: {Выводим пункты меню}
Writeln(‘0. Выход’);
Выбор команды меню
Writeln(‘1. Ввод данных’);
Writeln(‘2. Вывод результатов’);
Write(‘Сделай выбор ->’);readln(k);
да
нет
K=0?
{Сделаем выбор по значению переменной k}
Case k of
да
нет
{если k=0}0: exit;
K=1
{если k=1}1: begin
Write(‘Введите значение х=’);
readln(x); end;
Ввод x
нет
K=2
{если k=2}2:
да
да
X=0?
Вывод
сообщения
нет
Вывод
y=1/x
конец
If x=0
Then writeln(
Else writeln(
‘Функция не имеет ‘Y=’,1/X:9:4);
значения!’)
End; {конец выбора}
Goto Menu; {переходим на строку,
помеченной как Menu}
End.
11
9. Операторы цикла
Рассмотрим операторы циклического алгоритма (алгоритм, который позволяет
выполнять одно и то же действие несколько раз, или до тех пор, пока не выполниться
условие останова):
Фрагмент блок-схемы
Оператор
Назначение
FOR <ПАРАМЕТР> :=
<НАЧАЛЬНОЕ ЗНАЧЕНИЕ>
TO/DOWNTO <КОНЕЧНОЕ
ЗНАЧЕНИЕ> DO <ОПЕРАТОРЫ
ЦИКЛА>;
Изменение
параметра
цикла
{Цикл с параметром}
Тело цикла
WHILE <УСЛОВИЕ> DO
<ОПЕРАТОРЫ ЦИКЛА>;
{Цикл с предусловием}
Условие
продолжения
цикла
Нет
Для каждого значения
переменной, равной
сначала начальному
значению, до
конечного значения с
шагом 1 (или -1 при
downto) проделать
действия в теле
цикла.
Пока условие
истинно, выполняем
действия в теле
цикла, иначе выходим
из цикла.
Тело цикла
REPEAT
<ОПЕРАТОРЫ ЦИКЛА>
UNTIL <УСЛОВИЕ>;
Тело цикла
{Цикл с постусловием}
Условие
окончания
цикла
Нет
12
Повторять действия в
теле цикла до тех
пор, пока условие не
будет выполнено.
Задание №1. Будем повторять вычисления функции y=1/x до тех пор, пока не введем х=0.
{цикл с пост-условием}
Описание переменных
начало
Ввод Х
Вывод 1/x
Да
Х=0
конец
Var
x:real;
Begin
Repeat
{повторяем}
Write(‘Введите значение х=’);readln(x);
If x=0
Else
Then
writeln
writeln
(‘Y=’,1/X:9:4);
(‘Функция не
имеет
значения!’)
Until x=0;{пока х не станет равен 0}
End.
{цикл с предусловием}
Описание переменных
начало
Var
x:real;
Begin
Write(‘Введите значение х=’);
readln(x);
Ввод Х
Нет
Х≠0?
While x<>0 do
повторяем}
{пока х не равен 0
Begin
Да
writeln(‘Y=’,1/X:9:4);
Write(‘Введите значение х=’);readln(x);
Вывод 1/x
Ввод Х
конец
End;
End.
13
Задание №2. Вычислим значение функции y=1/x с начальным значением х и с каждым
изменением его на заданный шаг step ровно заданное N количество раз .
{цикл с параметром}
Описание переменных
начало
Ввод a, step, N
I = 1, N; 1
X = A + (I -1)*STEP
Да
X = 0?
Нет
Вывод x, 1/x
конец
Var
X, step :real;
I, N :integer;
Begin
Write(‘Введите начальное значение
х=’);readln(а);
Write(‘Введите шаг изменения
х=’);readln(step);
Write(‘Введите количество
вычислений у=1/х’);readln(N);
For i:=1 to N do
{для переменной i, начиная с 1 до
N делаем}
Begin
X := a+(i-1)*step;
If x=0
Then writeln(‘Функция не имеет
значения!’)
Else
writeln(‘Y=’,1/X:9:4);
End;
End.
10.Массивы
Массив – это специальный тип для хранения данных в виде определенной структуры –
ряда (array) чисел, последовательности переменных с индексами, упорядоченной
последовательности символов. Таким образом, для массива характерно наличие
нумерованных элементов.
Например, последовательность чисел ряда a1, a2, …, a10 можно представить как вектор
целых чисел размерности 10 и объявить для этого 10 переменных
Var a1, a2, a3, a4, a5, a6, a7, a8, a9, a10: integer;
Но доступ к таким переменным придется организовывать в виде линейного алгоритма.
10 раз вводить, 10 раз изменять в операторе присваивании, 10 раз выводить, и т.д. А если
вектор возрастет до 20 чисел? Сколько раз придется добавлять таких операторов?
I. Одномерный массив
В этом случае, хотелось бы индексы (номера) отделить от самого названия и вынести
их в отдельную структуру. Это возможно сделать, записав тип массив следующим
образом:
Type
Vector=array[1..10] of integer;
Теперь, объявив переменную этого типа как
Var
а: vector;
мы сможем обратиться к каждому элементу непосредственно, указав лишь в квадратных
скобках номер этого элемента: a[1] – это 1-ый элемент, a[2] – это 2-ый элемент, и т.д.
Теперь можно обратиться к индексу как к отдельной константе, переменной и включить
оператор ввода каждого i-го элемента в цикл по параметру i, изменяющийся от 1 до 10.
Таким образом, для ввода 10 или 20 нумерованных чисел потребуется изменить только
14
конечный параметр в цикле по i и алгоритм будет работать без добавления лишних
операторов ввода:
{ввод сроки чисел}
{вывод чисел в строку}
for i:=1 to 10 do
for i:=1 to 10 do
read(a[i]);
write(‘ ‘,a[i]);
{ввод чисел по-элементно}
{вывод чисел в столбец}
for i:=1 to 10 do
for i:=1 to 10 do
readln(a[i]);
writeln(a[i]);
Задание №1. Занести в массив аргумент и значение функции. Найти наибольшее и
наименьшее значение функции.
Type
Vector=array [1..100] of real;
Var
step :real;
I, N :integer;
X,Y :vector;
Max, Min:integer;
Begin
Write(‘Введите начальное значение х=’);readln(а);
Write(‘Введите шаг изменения х=’);readln(step);
Write(‘Введите количество вычислений у=1/х’);readln(N);
For i:=1 to N do
{для переменной i, начиная с 1 до N делаем}
Begin
X[i] := a+(i-1)*step;
If x[i]=0
Then writeln(‘Функция не имеет значения!’)
Else begin
y[i]:=1/x[i];
writeln(‘Y=’,y[i]:9:4);
end;
End;
{находим номер максимального элемента}
max:=1;
For i:=2 to N do
If y[i]>y[max] then max:=I;
Writeln(‘наименьшее значение функции в точке x=’,
x[min]:6:2,’и равно’, y[min]:9:4);
{находим номер наименьшего элемента}
min:=1;
For i:=2 to N do
If y[i]<y[min] then min:=I;
Writeln(‘наибольшее значение функции в точке x=’,
x[max]:6:2,’и равно’, y[max]:9:4);
End.
II. Строка как одномерный массив символов
Массивом можно представить строку символов, к каждому элементу которого можно
обращаться по его номеру.
Задание №2. Вывести количество нулей в заданном числе.
Var Number:string;
15
Kol_zero:integer;
i:integer;
begin
writeln(‘введите целое число: ’);readln(number);
kol_zero:=0;
for i:=1 to length(number) do
If number[i]=’0’ then inc(kol_zero);
Writeln(‘количество нулей в числе равно ’,kol_zero);
End.
III. Двумерный массив (матрица)
Элементом массива может быть сам массив. Тогда получим двумерный массив или
матрицу чисел, у которого есть индекс строки и индекс столбца.
Задание №3. Задана матрица целых чисел размером
5х5. Определить сумму
отрицательных элементов матрицы и произведение положительных элементов матрицы..
Type
Vector=array[1..5] of integer; {для хранения строк}
Matrica=array[1..5]of vector; {для хранения массива строк}
Var
A:matrica;
S,P:integer;
I,j:integer;
begin
writeln(‘введите матрицу чисел: ’);
for i:=1 to 5 do begin
for j:=1 to 5 do
read(a[i][j]);{читаем i-ую строку матрицы}
readln;{переходим к следующей строке}
end;
{сумма отрицательных чисел}
S:=0;
For i:=1 to 5 do
For j:=1 to 5 do {перебираем все элементы}
If a[I,j]<0 then S:=S+a[I,j];
Writeln(‘сумма отрицательных чисел =’,S);
{произведение положительных чисел}
p:=1;
For i:=1 to 5 do
For j:=1 to 5 do {перебираем все элементы}
If a[I,j]>0 then p:=p*a[I,j];
Writeln(‘произведение положительных чисел =’,P);
End.
11.Текстовый файл
Если массивы или матрицы заданы больших размеров, то их лучше хранить в
отдельном файле и считывать элементы из них.
I. Текстовые и типизированные файлы.
Существует текстовые и типизированные файлы (эти файлы хранят не только данные,
но и структуру данных).
Для работы с такими данными служит специальные файловые типы:
Var
16
F: text;
G:file of integer;
Они обеспечивают связь непосредственно с самим местоположением данных. Поэтому
в начале необходимо это место определить, вызвав процедуру, которая обеспечивает
присвоение файловой переменной необходимых данных о местоположении указанного
файла
assign(<файловая переменная>,<имя файла>);
Теперь надо определить, что делать с этим файлом: читать данные, записывать или
добавлять в конец, изменять записи в файле, закрыть доступ к файлу. Для этого
определены следующие процедуры:
для чтения
- reset(f);
для записи/создания - rewrite(f);
для добавления
- append(f);
для закрытия
- close(f);
Причем в параметрах указывается уже не сам файл по имени, а его идентификатор файловая переменная. Теперь для ввода или вывода данных в операторе ввода/вывода
файловую переменную необходимо писать первым в списке, чтобы указать, откуда читать
или куда записывать данные.
При этом запись и чтение в текстовый файл и в типизированный файл
производится разными способами. Рассмотрим это на примере.
Задание №1. Создайте матрицу вещественных чисел размером 10х10, используя функцию
генерации случайных чисел. Сохраните матрицу в текстовый файл и в типизированный.
Посмотрите различия хранения данных через текстовый редактор и сравните размеры
файлов.
Type
Matrica=array[1..10, 1..10]of real;
Var
I,j:integer;
A:matrica;
F:text;
G:file of matrica;
Begin
Randomize;{задание начального отчета для счетчика случайных чисел}
For i:=1 to 10 do
For j:=1 to 10 do
A[I,j]:=random;{вещественные числа от 0 до 1}
{устанавливаем связь с текстовым файлом}
Assign(f,’matrica1.txt’);rewrite(f);
For i:=1 to 10 do begin
For j:=1 to 10 do
Write(f,a[I,j]:6:4,’ ‘);
{помещаем числа в одну строку}
Writeln(f);{переходим на новую строку}
End;
Close(f);
{устанавливаем связь с типизированным файлом}
Assign(g,’matrica2.txt’);rewrite(g);
Write(g,A); {помещаем всю матрицу сразу}
Close(g);
End.
17
II. Файловые переменные Input и Output.
Кроме этого, существуют две файловые переменные, отвечающие за направление
ввода и вывода.
Input - отвечает за ввод,
Output - отвечает за вывод.
По умолчанию, эти переменные работают со стандартным вводом с клавиатуры и
выводом на экран. Поэтому операторы ввода/вывода Read/Write работают с этими
файловыми переменные по умолчанию без явной их записи в списке ввода/вывода. Если
эти переменные переопределить на ввод/вывод с файла, то операторы Read/Write будут
работать с файлами без явной записи этих переменные в списке ввода/вывода.
Задание №2. Создайте матрицу целых чисел размером 3х3, используя функцию генерации
случайных чисел. Сохраните матрицу в текстовый файл. Обнулите значения матрицы и
вновь введите их с текстового файла. Сравните результаты вывода с результатами в
текстовом файле.
Const
dim=3; {задаем размер матрицы}
Type
Matrica=array[1..dim, 1..dim]of integer;
Var
I,j:integer;
A:matrica;
Begin
Randomize;{задание начального отчета для счетчика случайных чисел}
For i:=1 to dim do
For j:=1 to dim do
A[I,j]:=random(101);{целые числа от 0 до 100}
{устанавливаем связь с текстовым файлом для вывода}
Assign(output,’matrica.txt’);rewrite(output);
For i:=1 to dim do begin
For j:=1 to dim do
Write(a[I,j],’ ‘);
{помещаем числа в одну строку}
Writeln;{переходим на новую строку}
End;
Close(output);
Fillchar(A,sizeof(A),0);{обнуляем матрицу}
{устанавливаем связь с текстовым файлом для ввода данных}
Assign(input,’matrica.txt’);rewrite(input);
For i:=1 to dim do begin
For j:=1 to dim do
Read(A[I,j]);
Readln;
End;
Close(input);
{выводим матрицу на экран}
For i:=1 to dim do begin
18
For j:=1 to dim do
Write(a[I,j],’ ‘);
{помещаем числа в одну строку}
Writeln;{переходим на новую строку}
End;
Readln;{пауза до нажатия клавиши Enter}
End.
III. Ввод и вывод в текстовый файл в командной строке.
Если файл еще не готов, то можно его задать при выполнении программы из
командной строки:
C:\myfile.exe <input.txt >output.txt
Знак < определяет, откуда считывать данные, а знак > - куда выводить данных. При
этом программа будет работать и без ввода/вывода в файл в обычном режиме ввода с
клавиатуры и вывода на экран:
C:\myfile.exe
12.Записи
При рассмотрении матриц с разнородной информацией (строка, число, дата) лучше
всего использовать структуру данных «запись».
Запись - это структура данных, состоящих из фиксированного числа компонентов,
называемых полями записи. В отличие от массива, компоненты (поля) записи могут быть
различного типа. Чтобы можно было ссылаться на тот или иной компонент записи, поля
именуются.
Ключевым словом в описании записи является Record, после которого перечисляются
все поля с указанием их типов, после которых обязательно слово End.
Для обращения к полям записи используется разделитель «точка» между именем
переменной и именем поля или оператор With <имя переменной> do <имена полей
записи> в операторах.
Задание №1. Введите данные о своих друзьях: Фамилия И.О., Дату рождения, Домашний
адрес и телефон. По заданной дате установите, кого в этот день нужно поздравить с днем
рождения.
Const
Kol=12;
Type
Birthday=Record
Day:1..31;
Month:1..12;
Year:Word;
End;
Friend=Record
Fio:String[25];
Data:Birthday;
Adress:String[50];
Telephone:longint;
End;
Var
I:integer;
A:holiday;
B:array[1..Kol] of friend;
Begin
19
Write(‘Введите текущую дату(дд мм гггг):’);
Readln(a.day,a.month,a.year);
for i:=1 to Kol do
with b[i] do begin
readln(fio)
readln(data.day, data.month, data.year);
readln(address);
readln(Telephone);
end;
for i:=1 to Kol do
if (b[i].data.day=a.day) and (b[i].data.month=a.month)
then
writeln(‘Не забудь поздравить с днем рождения своего друга ’,
b[i].fio, ‘ по телефону ’, b[i].telephone,
‘. Ему исполнилось ’,a.year-b[i].data.year, ‘ лет!’);
End.
Поля записи строятся в памяти по порядку их перечисления. Каждая запись состоит из
такого количества байт, из которого состоит в сумме каждое поле этой записи. Эти записи
можно хранить в текстовом файле и считывать их оттуда.
С помощью записи строятся базы данных, динамические структуры данных: списки,
очереди, деревья.
Начало файла
Блок с
записью
Размер файла
(количество
блоков)
Условная
граница
0
1
2
3
4
5
Обычно записи хранятся в типизированных файлах, которые хранят элементы в виде
линейной последовательности блоков и предполагают к каждому элементу прямой
доступ. Каждый блок представляет собой одну запись или компоненту того типа, с
которым файл объявлен. Если файл содержит n блоков, то они нумеруются от 1 до n.
Кроме того, вводится понятие условной границы между блоками (элементами), при этом
условная граница с номером 0 расположена перед блоком с номером 1, граница с номером
1 расположена перед блоком с номером 2 и, наконец, условная граница с номером n
находится после блока с номером n.
Реализация прямого доступа осуществляется с помощью следующих функций и
процедур:
Применение
Назначение
L:=FileSize(f); Возвращает количество блоков в открытом файле f.
P:=FilePos(f); Возвращает текущую позицию в файле f. Позиция в файле - это номер
условной границы. Для только что открытого файла текущей позицией будет
граница с номером 0. Это значит, что можно записать или прочесть блок с
номером 1. После чтения или записи первого блока текущая позиция
переместится на границу с номером 1, и можно будет обращаться к блоку с
номером 2. После прочтения последней записи значение FilePos равно
значению FileSize.
20
Seek(f, N);
Truncate(f);
Обеспечивает назначение текущей позиции в файле (позиционирование). В
параметре N должен быть задан номер условной границы, предшествующей
блоку, к которому будет производиться последующее обращение.
Например, чтобы работать с блоком 4, необходимо задать значение N,
равное 3.
Процедура Seek работает с открытыми файлами.
Устанавливает в текущей позиции признак конца файла, при этом все
последующие блоки не доступны, т.е. считаются удаленными.
Задание №2. Создайте базу данных с полями: Фамилия, Имя, Отчество учащегося, класс,
оценки по предметам на экзаменах. Выведите средний балл каждого учащегося и каждого
класса.
Оформим запись следующим образом:
Type
Predmets=(Mathematika, Fizika, History, English, Russian);
Ball=1..5;
Study=record
Klass: string[4];
Family, Name, Father: string[15];
Ocenka: array[Predmets] of ball;
Average: real;
End;
Filerec=file of Study;
Рассмотрим следующие методы работы с базой данных:
1) Проверить, пуста ли база данных.
2) Добавить в базу данных несколько записей
3) Просмотреть их для проверки
4) Подсчитать и вывести средний балл каждого учащегося
5) Подсчитать и вывести средний балл каждого класса
Проверка на пустоту базы данных будем проверять по функции filesize. Но даже если база
данных не пуста, нам все равно понадобиться количество уже введенных записей.
Оформим работу через меню команд
1. Добавление записей
2. Просмотр записей
3. Очистить базу данных
4. Вывод среднего балла класса
5. Выход
Это меню обрабатывается с помощью оператора case of.
Приведем дальнейший текст программы:
Var
St: study;
F: filerec;
K, L, kol: integer;
Menu:1..5;
Answer, klass:string[4];
Flag: Boolean;
Av: real;
Begin
Assign (f,’study.dat’);
{$I+}Reset(f);{$I-} {если файл не создан}
If IOResult<>0 then begin
Rewrite(F);close(F);Reset(F); {то создадим пустой файл}
21
End;
L:=filesize(f);
If L=0 then Flag:=false else Flag:=true;
Repeat
{вывод меню команд}
Writeln(‘Выберите номер команды:’);
Writeln(‘1. Добавление записей’);
Writeln(‘2. Просмотр записей’);
Writeln(‘3. Очистить базу данных’);
Writeln(‘4. Вывод среднего балла класса’);
Writeln(‘5. Выход’);
Readln(menu);
Case menu of
1: begin
ClrScr;
Write(‘Введите данные об ученике:’);
With st do begin
Write(‘Класс -’);readln(klass);
Write(‘Фамилия -’);readln(family);
Write(‘Имя -’);readln(name);
Write(‘Отчество -’);readln(father);
Write(‘Введите данные об оценках:’);
Write(‘Математика -’);readln(ocenka[mathematika]);
Write(‘Физика -’);readln(ocenkafizika]);
Write(‘История -’);readln(ocenka[history]);
Write(‘Английский -’);readln(ocenka[English]);
Write(‘Русский язык -’);readln(ocenka[Russian]);
Average:=0;
For k:=mathematika to Russian do
average:=average+ocenka[k];
End;{with}
Write(f,st);
L:=filesize(f);
Flag:=true;
end;
2: begin
If flag then
For k:=1 to L do begin
Seek(f,k-1);read(f,st);
With st do begin
Write(‘Класс -’);writeln(klass);
Write(‘Фамилия -’);writeln(family);
Write(‘Имя -’);writeln(name);
Write(‘Отчество -’);writeln(father);
Write(‘Оценки по предметам:’);
Write(‘Математика-’);writeln(ocenka[mathematika]);
Write(‘Физика-’);writeln(ocenkafizika]);
Write(‘История -’);writeln(ocenka[history]);
Write(‘Английский -’);writeln(ocenka[English]);
Write(‘Русский язык -’);writeln(ocenka[Russian]);
Write(‘Средний балл -’);writeln(average);
22
End;{with}
End{for}
Else begin
writeln(‘Записей в базе данных нет!’);readln;
end;
End;
3: begin
Write(‘Вы действительно хотите удалить все записи в
базе данных? (Да/Нет)’);readln(answer);
If answer=’Да’ then begin
seek(f,0);truncate(f);L:=0; Flag:=false;
end;
end;
4: begin
If flag then begin
Write(‘Введите класс:’);readln(Klass);
Av:=0;Kol:=0;
For k:=1 to L do begin
Seek(f,k-1);read(f,st);
IF klass=st.klass then
With st do begin
Write(‘Фамилия -’);writeln(family);
Write(‘Имя -’);writeln(name);
Write(‘Отчество -’);writeln(father);
Write(‘Оценки по предметам:’);
Write(‘Математика-’);writeln(ocenka[mathematika]);
Write(‘Физика-’);writeln(ocenkafizika]);
Write(‘История -’);writeln(ocenka[history]);
Write(‘Английский -’);writeln(ocenka[English]);
Write(‘Русский язык -’);writeln(ocenka[Russian]);
Write(‘Средний балл -’);writeln(average);
Av:=av+average;
Inc(kol);
End;{with}
End{for}
Av:=av/kol;
Write(‘Средний балл по классу-’);writeln(av);
end
Else begin
writeln(‘Записей в базе данных нет!’);readln;
end;
end;
5: break;
End;
Until false;
Close(f);
End.
Если вы заметили, то в этой программе нет массива записей. Мы работаем только с
данными из файла, переходя от записи к записи последовательно с помощью процедуры
seek. Такой подход экономит статическую память, при этом размер файла может
достигать сколь угодно больших размеров.
Можно продолжить работу с базой данных:
23
- сортировать по среднему баллу, фамилии И.О. учеников и классу,
- редактировать данные по выбранному ученику,
- удалять только выбранных учеников или класс,
- выводить средний балл по предметам,
- сохранять отчеты в текстовый файл,
- и т.д.
Это предлагаем сделать самостоятельно.
Мы рассмотрели два подхода к формированию базы данных: через массив записей и через
типизированные файлы. В каждом конкретном случае можно выбрать либо тот, либо
другой подход.
13.Процедуры и функции пользователя
Определить простейшую процедуру довольно просто: практически любой составной
оператор (группа операторов, заключенных в операторные скобки, т.е. между
ключевыми словами Begin … End;), вынесенный из основного блока программы и
объявленный предложением
PROCEDURE ИмяПроцедуры;
становится процедурой, и вместо составного оператора в основном блоке может
подставлятся одно лишь ИмяПроцедуры;.
Согласно более общему определению, процедура может иметь параметры, метки
перехода внутри себя, свои локальные переменные и процедуры. Обязательными
элементами процедур и функций является заголовок и тело - составной оператор.
Общая структура функций совпадает со структурой процедур, за исключением
заголовка и оператора присваивания значения функции (в теле имя функции
представляется как идентификатор переменной того типа, который стоит в заголовке
функции после двоеточия). Он описывается так
FUNCTION ИмяФункции (список параметров): <Скалярный Тип Значения Функции>;
Синтаксис вызова процедур прост. Ее выполнение активизируется указанием ее
имени и списком переменных или значений, подставляемых на место параметров:
ИмяПроцедуры (Параметр1, Параметр2,…);
Все процедуры и функции должны быть распределены по порядку обращения к ним,
как будто нанизываем кольца на стержень. Для поиска нужной процедуры программа
переберет все процедуры, стоящие снизу вверх от места вызова (а не сверху вниз!), как
будто мы снимаем кольца со стержня по очереди. И затем будет выполнять все операции
после заголовка до end. После этого программа вернет управление обратно в точку вызова
и продолжит выполнение следующих после нее операторов.
Примеры заголовков процедур и функций:
PROCEDURE Swap (var a, b: integer);
PROCEDURE Stop;
FUNCTION Max (a, b: byte): byte;
FUNCTION Sum (a, b: real): real;
Примеры вызова процедур и функций:
Swap (a, b);
24
Stop;
a:= Max (c, d);
t:= b+ sum (5, a);
Объявление
процедуры A1
Объявление
процедуры A2
Вызов процедуры A1
Объявление
процедуры A3
Тело программы
Вызов процедуры А3;
Вызов процедуры А2;
Вызов процедуры А1;
Параметры. Локальные и глобальные данные
Параметры процедур и функций в заголовках называются формальными
параметрами и должны содержать после идентификаторов переменных после двоеточия
ставить ее тип. При обращении к функции или процедуре в списке параметров
подставляются конкретные значения того же типа и в том же порядке или
идентификаторы переменных того же типа и в том же порядке. В этом случае мы говорим
о фактических параметрах.
Как же передаются значения в процедуры и функции? Первый способ – по
значению, т.е. передается значение или значение фактической переменной самой
формальной переменной (как будто до вызова процедуры выполнился невидимый
оператор присваивания), у же в процедуре это значение используется через эту
переменную. Как будто сделали копию переменной в памяти компьютера. Так оно и есть
– на каждый вызов процедуры программа занимает дополнительно ровно столько места,
сколько нужно для размещения формальных переменных. Такие параметры называются
параметры-значения.
Второй способ – по ссылке, т.е. передается только адрес памяти, где размещается
фактическая переменная. Тогда формальная переменная и фактическая будут работать с
одним и тем же значением, и память не будет выделять под нее дополнительное место.
Если значение переменной в процедуре изменится, то изменится и в вызывающем
процедуру блоке программы. При этом первоначальное значение фактической
переменной потеряется. В таком случае нельзя ставить в списке формальных параметров
значение, а только его идентификатор. В списке формальных параметров перед
идентификатором ставится ключевое слово VAR. Такие параметры называются
параметры-переменные.
Пример использование параметров- значений и параметров- переменных :
PROGRAM Prim;
VAR
a : Integer;
25
PROCEDURE Less (x : Integer); {параметр- значение}
BEGIN
x:= x-1; {В процедуре значение параметра уменьшается на 1}
END;
BEGIN
a:=5; Writeln ( ‘a=’, a);
Less(a); Write (‘новое значение a=’, a);
END.
После выполнения этой программы компьютер выдает:
a= 5
новое значение a= 5
Это происходит потому, что единственный параметр процедуры Less есть параметрзначение. Изменим в приведенном выше примере заголовок процедуры:
PROCEDURE Less (Var x : Integer);
В этом случае после выполнения программы компьютер выдает:
a= 5
новое значение a= 4
Этот пример показывает, что, в отличии от параметров- значений, параметрыпеременные связываются с фактическими параметрами в момент вызова и остаются
связанными с ними пока выполняется процедура.
Глобальные константы, типы, переменные- это те, которые объявлены в программе
вне процедур и функций.
Локальными называют константы, переменные и типы, существующие только
внутри процедур и функций, и объявленные либо в списке параметров (только
переменные), либо в разделах CONST, TYPE,VAR внутри процедуры или функции.
Процедуры и функции могут, наряду со своими локальными данными, использовать
и модифицировать и глобальные. Для этого нужно лишь, чтобы описание процедуры
(функции) стояло в тексте программы ниже, чем описания соответствующих глобальных
типов, констант и переменных:
PROGRAM Main;
{глобальные переменные}
VAR
Xmain, Ymain : LongInt;
Res: Real;
PROCEDURE Proc1 (a, b : Word; VAR Result : Real);
VAR
Res : Real; {Локальная переменная, закрывающая глобальную}
BEGIN
Res := a*a + b*b; {локальные действия}
Result := Xmain+Ymain*Res; {работают глобальные значения}
Xmain:= Xmain+1; {модифицируется глобальное значение}
END;
{Другие глобальные объявления, уже недоступные из процедуры Proc1}
TYPE ...
CONST ...
26
VAR ...
BEGIN
{Основной блок, в котором может вызываться Proc1}
END.
При совпадении имен глобальной и локальной переменной (типов, констант) сильнее
оказывается локальное имя, и именно оно используется внутри подпрограммы.
Существует неписанное правило: если подпрограмма содержит в себе циклы FOR ,то
параметры циклов должны быть описаны как локальные переменные. Это предупредит
неразбериху при циклическом вызове процедур.
Приведем еще один пример использования параметров – переменных и параметров –
значений:
{программа вычисляет А в кубе, где А- матрица порядка n x n, n<=5 }
PROGRAM Kub;
TYPE
matrica= Array [ 1..5,1..5] of Integer;
VAR
n, i, j : Integer;
a, b, c : matrica;
PROCEDURE
Multiply (n: Integer; a, b : matrica; VAR c : matrica);
{данная процедура находит С=А*В – произведение двух матриц}
{параметры n, a, b являются параметрами – значениями, с – параметр - переменная}
VAR
i, j, k, s : Integer;
BEGIN
FOR i:=1 TO n DO
FOR j:=1 TO n DO
BEGIN
s:=0;
FOR k:=1 To n DO
s:=s + a[i ,k] * b[k,j];
c[i,j]:=s;
END; {конец цикла}
END; {конец процедуры Multiply}
{печать матрицы, используются параметры - значения }
PROCEDURE Prn (n: Integer; a: matrica);
VAR
i, j :Integer;
BEGIN
FOR i: =1 TO n DO BEGIN
FOR j:=1 TO n DO
WRITE (a[i, j] : 5);
WRITELN;
END;{конец цикла}
END; {конец процедуры}
BEGIN
WRITE (‘введи размерность матрицы А,<=5’); READLN(n);
WRITELN (‘матрица А’);
27
FOR i:=1 TO n DO {задаем элементы матрицы с помощью}
FOR j:=1 TO n DO {датчика случайных чисел}
a[i, j]:= random(10);
Prn (n, a); {печатаем матрицу А}
Multiply (n, a, a, b); {находим В=А*А}
Multiply (n, a, b, c); {находим С=А*В – куб матрицы А}
WRITELN (‘C=A*A*A);
Prn (n, c); {печатаем матрицу С}
END.
Большое значение имеет соблюдение правил соответствия типов при подстановке
параметров. Число и порядок следования параметров в вызове должен соответствовать
описанию процедуры или функции. Кроме того, в Турбо Паскале существует правило,
требующее, чтобы параметры, имеющие файловый (или сложный тип с файловыми
компонентами), были обязательно описаны как VAR- параметры.
Процедуры и функции могут быть вложенными друг в друга. Число уровней
вложенности может быть достаточно большим, но на практике не превышает второго
уровня. Вложенная процедура или функция относится к охватывающей ее программе так
же, как сама программа относится к основной программе. Вложенные процедуры и
функции могут вызываться только внутри охватывающей программы.
Область действия меток переходов всегда локальна, и нельзя планировать переходы
с помощью оператора Goto из вложенной процедуры в охватывающую или основной блок
программы, или из программы в процедуру.
Рекурсивные подпрограммы
Использование рекурсии – традиционное преимущество языка Паскаль.
Турбо Паскаль в полной мере позволяет строить рекурсивные алгоритмы. Под
рекурсией понимается вызов функции (процедуры) из тела этой же самой функции
(процедуры).
Рекурсивность часто используется в математике. Так, многие определения
математических формул рекурсивны. В качестве примера можно привести формулу
вычисления факториала:
n!=1, если n=0
n!= n*(n-1)! , если n>0
Видно, что для вычисления каждого последующего значения нужно знать
предыдущее. В Паскале рекурсия записывается так же, как и в формулах. Ниже приведен
пример реализации функций вычисления того же факториала:
FUNCTION Fact (n : Word) : LongInt;
BEGIN
If n=0
Then Fact :=1
Else Fact := n*Fact (n-1);
END;
Если в функцию передаются n>0 , то происходит следующее: запоминаются
известные значения членов выражения в ветви ELSE, а для вычисления неизвестных
вызываются те же функции, но с «предшествующими» аргументами. При этом вновь
запоминаются (но уже в другом месте памяти!) известные значения членов и происходят
вызовы. Так происходит до тех пор, пока выражение не станет полностью определенным
(в нашем примере – это присваивание в ветви THEN), после чего алгоритм начинает
раскручиваться в обратную сторону, изымая из памяти отложенные значения. Поскольку
при этом на каждом очередном шаге все члены выражений уже будут известны, через n
таких «обратных» шагов мы получим конечный результат.
28
Необходимым условием для работоспособности рекурсивных процедур является
наличие условия окончания рекурсивных вызовов (например, проверка значения
изменяющегося параметра). Действия, связанные с такой проверкой, уже не могут
содержать рекурсивных вызовов. Если это условие не будет выполняться, то глубина
рекурсии станет бесконечной, что неизбежно приведет к аварийному останову
программы.
Зачастую внесение рекурсивности в программы придает им изящность. Но всегда
оно же «заставляет» программы расходовать больше памяти. Дело в том, что каждый
«отложенный» вызов функции или процедуры – это свой набор значений всех локальных
переменных этой функции, размещенных в стеке. Если будет, например, 100 рекурсивных
вызовов функции, то в памяти должно разместиться 100 наборов локальных переменных
этой функции. Поэтому во многих случаях те же задачи более эффективно решаются
«итерационными» методами, не требующими «лишней» памяти при сопоставимой
скорости вычислений.
Задание №1. Используя процедурный подход, создайте систему управления базой данных,
включающей в себя ввод, редактирование, просмотр и статистическую обработку данных
записей, состоящих из следующих полей: день, месяц, год, температура воздуха,
давление, влажность, скорость и направление ветра, облачность, осадки. Вычислить
среднегодовые и среднемесячные данные по введенным числовым данным.
14.Модуль CRT
Модуль-это библиотека процедур, функций, типов, констант, собранных в один файл.
При работе с выводом текстовой информации на экран часто используют процедуры и
функции модуля CRT (электронно-лучевая трубка). В работе часто используют цветовые
параметры. Приведем константы для задания цвета:
Константа
Black
Blue
Green
Cyan
Red
Magenta
Brown
LightGrey
DarkGrey
LightBlue
LightGreen
LightCyan
LightRed
LightMagenta
Yellow
White
Значение
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Цвет
Черный
Синий
Зеленый
Бирюзовый
Красный
Сиреневый
Коричневый
Светло-серый
Темно-серый
Голубой
Светло-зеленый
Светло-бирюзовый
Светло-красный
Светло-сиреневый
Желтый
Белый
Приведем процедуры и функции модуля CRT:
Процедура
ClrEоl;
ClrScr;
Назначение
Очищает все символы, начиная от позиции курсора до
конца строки, без перемещения курсора
Очищает экран и помещает курсор в верхнем левом углу.
29
Процедура
Dеlау(<миллисекунды>)
DelLine;
GоtоХY(X, Y)
НightVideo;
InsLine;
=KeyРrеssеd;
NoSound;
Sound(<частота в Гц>);
TextВаckground(<цвет>);
TextColor(<цвет>):
TextМоdе(<режим>)
Window(X1,Y1, X2,Y2)
=Rеаdкеу;
=WherеХ;
=WherеY;
Назначение
Выполняет задержку на указанное число миллисекунд
Удаляет строку, на которой находится курсор и
перемещает все следующие строки на одну строку вверх.
Нижняя строка очищается.
Выполняет позиционирование курсора. Х – это
горизонтальная позиция, Y - вертикальная позиция.
Выбирает символы с подсветкой
Вставляет пустую строку в месте расположения курсора.
Возвращает значение Truе, если клавиша на клавиатуре
нажата и Falsе - в противном случае.
Выключает внутренний динамик
Включает внутренний динамик
Выбирает фоновый цвет.
Выбирает цвет самого символа.
Выбирает конкретный текстовый режим
Определяет на экране текстовое окно.
Считывает символ с клавиатуры
Возвращает координату Х для текущей позиции курсора,
относящуюся к текущему окну. Х представляет собой
горизонтальную позицию
Возвращает координату Y для текущей позиции курсора,
относящуюся к текущему окну. Y представляет собой
вертикальную позицию
Задание №1. Выведем светофор, используя мигание слов соответствующим цветомКРАСНЫЙ, ЖЕЛТЫЙ, ЗЕЛЕНЫЙ.
Uses CRT;
begin
repeat
clrscr;
textcolor(red+blink);
writeln(‘красный’);
textcolor(yellow);
writeln(‘желтый’);
textcolor(green);
writeln(‘зеленый’);
delay(1000);
clrscr;
textcolor(red);
writeln(‘красный’);
textcolor(yellow+blink);
writeln(‘желтый’);
textcolor(green);
writeln(‘зеленый’);
delay(1000);
clrscr;
textcolor(red);
writeln(‘красный’);
textcolor(yellow);
writeln(‘желтый’);
30
textcolor(green+blink);
writeln(‘зеленый’);
delay(1000);
until keypressed;
end.
Измените программу, используя цикл.
Задание №2. Введем пароль, отображаемый в виде звездочек. Если ввели верно, то
выведем сообщение, иначе заново будем его вводить.
Uses CRT;
Cont password=’Rita’;
Var
C:char;
p:string[10];
Begin
P:=’’;
While p<>password do begin
Clrscr;
P:=’’;
Write(‘введите пароль:’);
Repeat
C:=readkey;
If c<>#13 then begin
Write(‘*’);
P:=p+c;
End;
Until ord(c) =13;
{код клавиши Enter}
Readln;
End;
Write(‘пароль введен верно!’);readln;
End.
Задание №3. Выведите код нажатой клавиши до нажатия клавиши Esc.
Uses CRT;
Var
C:char;
Begin
Repeat
C:=readkey;
Writeln(c,’-‘,ord(c));
Until ord(c) =27{код клавиши Esc }
End.
Если нужен код управляющей клавиши, то используем вызов Readkey дважды, так как эти
клавиши хранят в первом слове 0, а только во втором слове второй код.
Uses CRT;
Var
C:char;
Begin
Repeat
C:=readkey;
If ord(c)=0 then c:=readkey;
Writeln(c,’-‘,ord(c));
31
Until ord(c) =27{код клавиши Esc }
End.
Эти коды используют для перемещения по пунктам меню, для перемещения текста и
других объектов относительно экрана.
Задание №4. Используя клавиши управления курсором, переместите набранный текст по
экрану.
Uses CRT;
Const s=’Rita’;
Var
C:char;
X,y:integer;
Begin
X:=1;y:=1;
Repeat
Clrscr;
C:=readkey;c
If ord ( c )=0 then c:=readkey;
Case ord( c ) of
78:inc(x);
79:dec(x);
80:inc(y);
81:dec(y);
End;
If ((x<80)and(x>0)) and((y<25)and(y>0)) then
Gotoxy(x,y,s) else beep;
Until ord(c) =27{код клавиши Esc }
End.
15.Модуль Graph
Для вывода графической информации используется графический режим вывода попиксельно, а не по-символьно. При этом используется библиотека процедур и функций
модуля GRAPH.
Для инициализации графического экрана нужно загрузить в память драйвера (файлы
.BGI) для обработки графической информации. Эти файлы расположены в папке BGI.
Этот путь к папке нужно указать в процедуре инициализации InitGraph.
Драйвера
CGA.BGI
EGAVGA.BGI
HERC.BGI
ATT.BGI
PC3270.BGI
IBM8514.BGI
Графический режим
драйвер для IBM CGA, MCGA
драйвер для IBM EGA, VGA
драйвер для монохромного Hercules
драйвер для ATT&T 6300 (400 строк)
драйвер для IBM 3270 PC
драйвер для IBM 8514
Каждый драйвер содержит код и данные, хранящиеся в отдельном файле. Во время
выполнения процедура InitGraph определяет графическое устройство, загружает и
инициализирует соответствующий графический драйвер, переводит систему в
графический режим и возвращает управление вызывающей программе. Процедура
CloseGraph выгружает драйвер из памяти и восстанавливает предыдущий видеорежим. Вы
можете переключиться между графическим и текстовым режимами, используя процедуры
32
RestoreCrtMode (восстановить текстовый режим) и SetGraphMode (восстановить
графический режим).
Graph поддерживает конфигурацию с двумя мониторами. Когда Graph
инициализируется вызовом InitGraph, соответствующий монитор будет выбран для
запрошенного графического драйвера и режима. Когда графическая программа
завершается, предыдущий видеорежим будет восстановлен. Если в конфигурации с двумя
мониторами будет вызван InitGraph c режимом авто-обнаружения, Graph выберет монитор
и графический адаптер, на котором будет поддерживаться графический вывод с более
высоким качеством.
Адаптеры AT&T400 и IBM8514 нельзя распознать автоматически. Для
использования этих драйверов Вам нужно отменить авто обнаружение и передать в
InitGraph код драйвера и правильный код графического режима.
Константа
Для переменной GraphDriver
Detect
CGA
MCGA
EGA
EGA64
EGAMono
IBM8514
HereMono
AT&T400
VGA
PC3270
CurrentDriver
Для переменной GraphMode
CGAC0
Значение
Описание
Запрашивает автообнаружение
0
1
2
3
4
5
6
7
8
9
10
-128
Передается в GetModeRange
320x200 палитра 0:LightGreen,
LighhtRed,Yellow;1 страница
320x200 палитра 1:LightCyan,
LightMegenta,White;1 страница
320ч200 палитра 2:Green,Red,Brown;
320x200 палитра 3:Cyan,Magenta,
LightGray;1 страница
640x200 1страница
0
CGAC1
1
CGAC2
CGAC3
2
3
CGAHi
4
MCGAC0
0
MCGAC1
1
MCGAC2
MCGAC3
2
3
MCGAMed
MCGAHi
EGALo
EGAHi
EGA64Lo
EGA64Hi
EGAMonoHi
4
5
0
1
0
1
3
320x200 палитра 0:LightGreen,
LightRed,Yellow;1страница
320x200 палитра 1:LightCyan,
LightMagenta,White;1 страница
320x200 палитра 2:Green,Red,Brown;
320x200 палитра 3:Cyan,Magenta,
LightGray;1 страница
640x200 1 страница
640х480 1 страница
640х200 16 цветов 4 страницы
640х350 16 цветов 2 страницы
640х200 16 цветов 1 страница
640х350 4 цвета 1 страница
640х350 64К: 1 страница
33
Константа
Значение
HereMonoHi
AT&T400C0
0
0
AT&T400C1
1
AT&T400C2
2
AT&T400C3
3
AT&T400Med
AT&T400Hi
VGALo
VGAMed
VGAHi
PC3270Hi
IBM8514Lo
IBM8514Hi
4
5
0
1
2
0
0
1
Описание
256К: 2 страницы
720х348 2 страницы
320х200 палитра 0: LightGreen,
LightRed, Yellow; 1 страница
320х200 палитра 1: LightCyan,
LightMagenta, White; 1 страница
320х200 палитра 2: Green, Red,
Brown; 1 страница
320х200 палитра 3: Cyan, Magenta,
LightGrey; 1 страница
640х200 1 страница
640х400 1 страница
640х200 16 цветов 4 страницы
640х350 16 цветов 2 страницы
640х480 16 цветов 1 страница
720х350 1 страница
640х480 256 цветов
1024х768 256 цветов
Простой пример программы, использующий графический вывод на монитор:
uses Graph;
var
GraphDriver,
GraphMode,
ErrorCode: Integer;
begin
GraphDriver:=Detectt; {режим автоопределения}
{инициализация графического режима}
InitGraph(GraphDriver, GraphMode, ‘C:\BP\BGI’);
ErrorCode:=GraphResult;
if ErroeCode<>grOk then {ошибка}
begin
Writeln(‘Graphics error:’,GraphErrorMsg(ErrorCode));
Writeln(‘Program aborted...’);
Halt(1);
end;
setcolor(red);
Rectangle(0,0,GetMaxX, GetMaxY);
Line(0,0,GetMaxX, GetMaxY);
Readln;
CloseGraph;
end.
После инициализации графического экрана используются команды и функции
модуля GRAPH для рисования простых геометрических фигур, вывода текста, установки
цветов, типа линий и заливки и другие.
Процедура
Назначение
Процедуры
Arc (x, y: integer; StartAngle, EndAngle,
Рисует дугу от начального угла к конечному,
Radius: Word);
Используя (X, Y) как центр
34
Процедура
Bar (x1, y1, x2, y2: integer);
Bar3D(x1, y1, x2, y2: integer; depth:word;
top: boolean);
Circle (x, y: Integer; Radius: Word);
ClearDevice;
ClearViewPort;
CloseGraph;
DetectGraph( var graphdriver, graphmode:
integer);
DrawPoly( NumPoints: word; var
PolyPoints);
Ellipse (X, Y: Integer; StartAngle,
EndAngle, Xradius, Yradius: Word);
FillElilpse (X, Y: Integer; Xradius, Yradius:
Word);
FillPoly( NumPoints: word; var
PolyPoints);
FloodFill(X,Y:integer; Border: word);
GetArcCoords
GetAspectRatioi
GetFillPattern
GetFillSettings
GetImage
GetLineSettings
GetModeRange
GetPallete
GetTextSettings
GraphDefaults
GetViewSettings
InitGraph
Line (x1, y1, x2, y2: Integer)
LineRel
LineTo (x, y: Integer)
Назначение
Рисует полосу, используя текущий стиль и цвет
Рисует трехмерную полосу, используя текущий
стиль и цвет
рисует окружность, используя (X, Y) как центр
Очищает экран и устанавливает текущий
указатель (CP) в начало
Очищает окно
Закрывает графическую систему
Проверяет аппаратуру и определяет какой
графический драйвер и в каком режиме
используется
рисует многоугольник текущим цветом и типом
линии
рисует эллиптическую дугу от начального угла
к конечному, используя (X, Y) как центр
рисует заполненный эллипс, используя (X, Y)
как центр и Xradius и Yradius как
горизонтальные и вертикальные оси
заполняет многоугольник, используя
сканирование
заполняет ограниченную область, используя
текущий шаблон и цвет заполнения
позволяет запросить координаты команды Arc
возвращает разрешение экрана, из которого
может быть вычислен относительный аспект
(Xasp, Yasp)
возвращает шаблон заполнения, установленный
последним вызовом SetFillPattern
позволяет запросить текущий шаблон и цвет,
установленные SetFillStyle и SetFillPattern
сохраняет битовый образ указанной части
экрана в буфере
возвращает текущий стиль, шаблон и толщину
линии, установленные SetLineStyle
возвращает минимальный и мак. граф. режимы
для данного драйвера
возвращает текущую палитру и ее размер
возвращает текущий шрифт, направление,
размер и выравнивание текста, установленные
SetTextStyle и SetTextJustufi
устанавливает текущий указатель (CP) в начало
и переустанавливает графическую систему
позволяет запросить текущие параметры окна и
отсечения
инициализирует графическую систему и
устанавливает устройство в граф. режим
рисует линию от (X1, Y1) к (X2, Y2)
рисует линию от текущего указателя (CP) к
точке, лежащей на заданном расстоянии
рисует линию от текущего указателя к (X, Y)
35
Процедура
MoveRel
MoveTo (x, y: Integer)
OutText (TextString: String)
OutTextXY (x, y: Integer; TextString:
String)
PieSlice
PutImage
PutPixel (x, y: Integer; Color: Word)
Rectangle (x1, y1, x2, y2: Integer)
RestoreCRTMode
Sector
SetActivePage
SetAllPalette
SetAspectRatio
SetBkColor
SetColor
SetFillPattern
SetFillStyle
SetGraphBufSize
SetGraphMode
SetPalette
SetRGBPalette
SetTextJustify
SetTextStyle
SetLineStyle
SetUserCharSize
SetViewPort
SetVisualPage
SetWriteMode
GetBkColor
GetColor
Назначение
передвигает текущий указатель (CP) на
заданное расстояние от его текущей позиции
передвигает текущий указатель (CP) в (X, Y)
выводит текст на экран от текущего указателя
выводит текст на экран
рисует и заполняет сектор, используя (X, Y) как
центр и рисуя от начального угла к конечному
выводит битовый образ на экран
рисует точку (пиксел) в (X, Y)
рисует прямоугольник , используя текущий цвет
и тип линии
Восстанавливает видеорежим, который был до
инициализации графики
рисует и заполняет сектор эллипса
Устанавливает активную страницу для граф.
Вывода
изменяет цвет палитры
изменяет значение относительного аспекта
Устанавливает цвет фона
Устанавливает основной цвет, которым будет
осуществляться рисование
выбирает шаблон заполнения, определенный
пользователем
Устанавливает шаблон заполнения и цвет
Позволяет изменить размер буфера для
функций заполнения
переводит систему в графический режим и
очищает экран
изменяет один цвет палитры, указанный через
ColorNum и Color
позволяет модифицировать палитру для IBM
8514 и VGA
устанавливает выравнивание текста,
используемое OutText и OutTextXY
устанавливает текущий шрифт, стиль и размер
текста
устанавливает текущие толщину и стиль линии
позволяет изменить ширину и высоту символа
для штрихового шрифта
устанавливает текущее окно для графического
вывода
устанавливает номер видимой графической
страницы
устанавливает режим вывода (копирование или
XOR ) для линий, рисуемых с DrawPoly, Line,
LineRel, LineTo, Rectangle
Функции
возвращает текущий фоновый цвет
возвращает текущий цвет
36
Процедура
GetDefaultPalette
GetDriverName
GetGraphMode
GetMaxColor
GetMaxMode
GetMaxX
GetMaxY
GetModeName
GetPaletteSize
GetPixel
GetX
GetY
GraphErrorMsg
GraphResult
ImageSize
InstallUserDriver
InstallUserFont
RegisterBGIDriver
RegisterBGIFont
TextHeight (TextString: String)
TextWidth (TextString: Srting)
Назначение
возвращает аппаратную палитру в записи
PaletteType
возвращает строку с именем текущего драйвера
возвращает текущий графический режим
возвращает максимальный цвет, который можно
задать в SetColor
возвращает номер максимального режима
текущего загруженного драйвера
возвращает максимальный X (разрешение по
горизонтали) для текущего графического
драйвера и режима
возвращает максимальный Y (разрешение по
вертикали) для текущего графического драйвера
и режима
возвращает строку с именем указанного
графического режима
возвращает размер таблицы палитры
возвращает цвет точки в (X, Y)
возвращает координату X текущей позиции
(CP)
возвращает координату Y текущей позиции
(CP)
возвращает строку сообщения об ошибке для
заданного кода ErrorCode
возвращает код ошибки для последней
графической операции
возвращает число байт, требуемое для
заполнения прямоугольной области экрана
устанавливает пользовательский драйвер
устройства в BGI таблицу драйверов устройств
устанавливает новый шрифт, который не
встроен в BGI систему
регистрирует драйвер BGI для графической
системы
регистрирует шрифт BGI для графической
системы
возвращает высоту строки в пикселях
возвращает ширину строки в пикселях
Цветовая палитра используется такая же, как и в модуле CRT. Приведем некоторые
константы, которые используются при установке типа линий и типа заливки:
Константа
Значение
Для значения поля LineStyle
SolidLn
0
DottedLn
1
CenterLn
2
DashedLn
3
UserBitLn
4
Для значения поля Thickness
Назначение
Сплошная линия
Точечная линия
Штрих пунктирная линия
Пунктирная линия
Тип линии, определяемый пользователем
37
NormWidth
1
ThickWidth
3
Для значения заливки Pattern
EmptyFill
0
SolidFill
1
LineFill
2
LtSlashFill
3
SlashFill
4
BkSlashFill
5
LtBkSlashFill
6
HatchFill
7
XhatchFill
8
InterleaveFill
9
Wide DotFill
10
CloseDotFill
11
UserFill
12
Толщина линии в один пиксел
Толщина линии в три пикселя
Заполняет цветом фона
Заполняет основным цветом
--- заполнение
/// заполнение
/// заполнение толстыми линиями
\\\ заполнение толстыми линиями
\\\ заполнение
Редкая штриховка
Плотная штриховка
Пересекающиеся линии
Редкие точки
Плотные точки
Определенный пользователем стиль
Задание №1. Построим разноцветную звезду.
Uses graph;
Var x0,y0,r,i:integer;
Fi:real;
X,y: array[0..4] of integer;
graphdriver, graphmode:integer;
Begin
{инициализация графического режима}
Graphdriver:=Detect;
Initgraph(graphdriver, graphmode, ‘C:\BP\BGI’);
X0:=200;Y0:=200;R:=100;Fi:= 2*pi/5;
For i:=0 to 4 do begin
X[i]:=round(x0+R*cos(i*Fi));
Y[i]:=round(y0-R*sin(i*Fi));
End;
Setcolor(red);
Line(x[0],y[0],x[2],y[2]);
Line(x[2],y[2],x[4],y[4]);
Line(x[4],y[4],x[1],y[1]);
Line(x[1],y[1],x[3],y[3]);
Line(x[3],y[3],x[0],y[0]);
Setfillstyle(1,red);
Floodfill(x0,y0,red);
Readln;
Closegraph;
End.
Раскрасьте самостоятельно все лучи звезды разными цветами.
Для построения звезды с заливкой одного цвета используйте процедуру FillPoly.
Uses graph;
Var x0,y0,r,i:integer;
Fi:real;
Z:array[0..5]of Point;
graphdriver, graphmode:integer;
Begin
{инициализация графического режима}
38
Graphdriver:=Detect;
Initgraph(graphdriver, graphmode, ‘C:\BP\BGI’);
X0:=200;Y0:=200;R:=100;Fi:= 2*pi/5;
For i:=0 to 5 do begin
Z.X[i]:=round(x0+R*cos(i*Fi));
Z.Y[i]:=round(y0-R*sin(i*Fi));
End;
Setcolor(red);
Setfillstyle(1,red);
FillPoly(Z,6,red);
Readln;
Closegraph;
End.
Задание №2. Постройте разноцветную радугу, используя процедуру Sector.
Задание №3. Построим график функции у=1/х на заданном отрезке.
Для этого нам нужна информация о соотношении графического экрана (x1, y1, x2, y2) с
реальной системой координат (a, ymax, b, ymin). Для этого нужно соотнести пиксельный
шаг шагу на заданном отрезке StepX:= (b-a)/(x2-x1). Тогда, перебирая попиксельно
каждую точку, будем вычислять значение функции в xx:=xx+stepx. Значение по оси Y
будет меняться в обратном направлении, поэтому пиксельное значение нужно привести в
соответствие к реальному yy:=1/xx так y:=round(y1+my*(ymax-yy)), где масштаб
изменения по оси у вычисляется по формуле my:=(y2-y1)/(ymax-ymin). Для этого
алгоритма нужно предварительно вычислить минимально и минимальное значение
функции y=1/x. Так как функция имеет разрыв в точке 0, то при вычислении функции
будем проверять это условие.
Uses graph;
Var x1,x2,y1,y2,x,y:integer;
A,b,xx,yy,stepx,my,ymin,ymax:real;
graphdriver, graphmode:integer;
Begin
Write(‘введите отрезок:’); readln(a,b);
{инициализация графического режима}
Graphdriver:=Detect;
Initgraph(graphdriver, graphmode, ‘C:\BP\BGI’);
X1:=10; x2:=getmaxx-10;
Y1:=10; y2:=getmaxy-10;
StepX:=(b-a)/(x2-x1);
{вычисляем ymax, ymin}
xx:=a;
ymin:=1/xx;ymax:=ymin;
for x:=x1 to x2 do begin
xx:=xx+stepx;
if xx<>0 then yy:=1/xx;
if yy>ymax then ymax:=yy;
if yy<ymin then ymin:=yy;
end;
{вычисляем масштаб по оси Y}
my:=(y2-y1)/(ymax-ymin);
Xx:=a;
For x:=x1 to x2 do
39
Begin
if xx<>0 then yy:=1/xx;
y:=round(y1+my*(ymax-yy));
xx:=xx+stepx;
PutPixel(x, y, red);
End;
Readln;
closeGraph;
End.
Самостоятельно оформите график дальше. Например: постройте оси координат, если они
есть. Иначе постройте их по краю области графика. Обозначьте оси координат. Сделайте
разметку осей Х и У по заданной шкале. Выведите сетку. Проставьте числовые значения
шкалы по осям Х и У, а также укажите граничные значения. Сделайте рамку области
вывода графика. Вставьте название функции вне области рисования графика.
Задание №4. Используя описание процедуры для построения разноцветной звезды,
выведите миллиарды разных звезд на небе.
Задание №5. Используя описание функций и процедуру для построения графика функции,
постройте графики температур в разных городах за прошедший месяц. Используйте базу
данных из типизированного файла.
Задание №6. Используя процедуру вывода элементов массива в файл, функцию
нахождения максимального и минимального значения элементов массива, постройте
квадрат, включающий все точки, заданные своими координатами случайным образом.
Затем еще один внутри первого по тому же правилу, исключая первые найденные и т.д.
Примените рекурсивный подход.
Мультипликация
При создании графических объектов с ними можно проводить эффекты движения
или мультипликации. Для этого можно применять следующие подходы:
1) использование перерисовки объекта цветом фона
2) сохранять фрагменты движущихся объектов в динамической памяти
3) использовать смену видеостраниц
Приведем последние два способа, первый из них попробуйте реализовать
самостоятельно. Для удобства процедуру инициализации напишем в отдельном файле
initgraf.pas, который будем присоединять через ключ компиляции {$I initgraf.pas}:
{содержимое файла initgraf.pas}
Var graphdriver, graphmode, ErrorCode:integer;
Procedure GrInit;
Begin
{инициализация графического режима}
Graphdriver:=Detect;
Initgraph(graphdriver, graphmode, ‘C:\BP\BGI’);
ErrorCode:=GraphResult;
if ErroeCode<>grOk then {ошибка}
begin
Writeln(‘Graphics error:’,GraphErrorMsg(ErrorCode));
Writeln(‘Program aborted...’);
Halt(1);
end;
End;
40
Управление видеостраницами
Память видеоадаптеров разделена на так называемые страницы, или видеостраницы.
По умолчанию в графическом режиме действия производятся с нулевой страницей,
поэтому фактически во всех предыдущих примерах было видно, как рисуется на экране
фигуры. Однако если направить вывод изображений ненулевую страницу (при условии,
что такая доступна в текущем режиме видеоадаптера), то на экране ничего не отобразится,
поскольку по умолчанию видимой является нулевая страница. Если же после этого дать
команду считать видимой «скрытую» страницу, то она появится на экране буквально
мгновенно (конкретно за один прямой проход луча в кинескопе). Проделать все это
позволяют две процедуры:
SetVisualPage (Page: Word)
которая устанавливает “видимой” на экране видеостраницу номер Page, и процедура
SetActivePage (Page: Word)
устанавливающая перенаправление всех графических операций на страницу номер Page.
Приведем пример использования этих процедур.
(*Пример только для адаптеров EGA и VGA !!!*)
USES Graph, CRT;
{$I initgraf.pas}
PROCEDURE Forms (kadr: Byte); {рисование кадров 0..3}
CONST Radius: Array [0..3] of Integer =(20, 40, 60, 80);
VAR
R, rr: Integer;
{радиус эллипсов в квадратах}
BEGIN
R = Radius [kadr];
{максимальный радиус)
RR = 0;
{радиус вложенного эллипса}
Repeat
Ellipse (GetMaxX div 2, GetMaxY div 2, 0, 360, R, rr);
Inc (rr, 5)
Until rr >=R;
END;
PROCEDURE AnimEGAVGA;
{процедура смены кадров}
CONST ms=60;
{задержка между кадрами, мс}
VAR i: = Byte;
{параметр циклов смены}
BEGIN
Repeat
{цикл до нажатия клавиши..}
For i:=0 to 3 do begin
{смена видеостраниц: прямо}
SetVisualPage (i);
Delay (ms);
End;
For i:= 3 downto 0 begin
{..и обратно}
SetVisualPage(i);
Delay (ms);
End;
Until KeyPressed;
{условие окончания показа}
END;
VAR {*ОСНОВНАЯ ЧАСТЬ ПРИМЕРА*}
I :Byte;
BEGIN
{параметр (номер кадра)}
41
GrInit;
SetGraphMode (EGALo);
For i: = 3 downto 0 do begin
SetVisualPage (Succ (i)
SetActivePage (i);
Forms (i);
End; {for}
AnimEGAVGA;
CloseGraph;
{инициализация графики}
{режим EGA, 640x200}
{цикл заполнения страниц:}
mod 4);{видим «пустоту»}
{и готовим кадр}
{рисунок кадра}
{начало «оживления кадров}
{закрытие режима графики}
END.
Здесь показано использование процедур SetActivePage и SetVisualPage для алгоритма
«кадровой» мультипликации. Особенность ее заключается в том, что все кадры (здесь их
четыре) сначала записываются на соответствующие страницы, а затем производится
последовательное переключение отображения страниц на дисплей процедурой
SetVisualPage.
Работа с фрагментами изображений
При работе с фрагментом всегда важно знать его объем в байтах. Функция
ImageSize (x1,y1,x2,y2:integer): Word; возвращает размер памяти в байтах, необходимой
для сохранения прямоугольной области экрана. Прямоугольник определяется
координатами левого верхнего (x1,y1) и правого нижнего (x2,y2) углов. Эта функция
обычно используется совместно с процедурой GetMem.
Записать
изображение
в
буфер
можно,
используя
процедуру
GetImage(x1,y1,x2,y2:integer;Var BitMap) в которой параметры x1,y1,x2,y2 имеют то же
значение что и в ImageSize, а вместо бестипового параметра BitMap должна подставляться
переменная-буфер, занимающая область памяти размера, необходимого для полного
сохранения изображения. Отметим, что максимальный размер сохраняемого изображения
не должна превышать 64К.
Процедура PutImage (x1,y1:Integer; Var BitMap; Mode:Word) восстанавливает
изображение из буфера BitMap в прямоугольник, левый верхний угол которого определен
координатами (x, y). Обратите внимание на то, что в отличие от процедуры GetImage
здесь нужна всего одна точка. Объясняется это тем, что в структуре BitMap первые два
слова содержат ширину и высоту в пикселах запомненного изображения. Наиболее
интересным в этой процедуре является возможность определять режим вывода
изображения: можно суммировать изображение на экране и изображение в буфере,
можно уничтожать изображение, содержащиеся в определенной области,
можно
инвертировать изображение, содержащееся в буфере. Эти операции задаются параметром
Mode, для которого в модуле Graph определены константы, уже названные при описании
процедуры SetWriteMode. Напишем их еще раз:
CONST
CopyPut=0;
{операция Mov (замещение)}
XORPut=1;
{операция XOR}
ORPut=2;
{операция OR}
ANDPut=3;
{операция AND}
NOTPut=4;
{операция NOT}
Например, если в режиме ORPut на малиновый цвет изображения вывести
бирюзовый из буфера, то результирующая картинка будет светло-серого цвета. Из этих
пяти режимов самым интересным является XOR, поскольку проведенные
последовательно две операции XOR с одинаковым вторым аргументом оставляют первый
из них без изменений. Это свойство операции XOR и используется в тех случаях, когда
42
необходимо изобразить некий подвижный объект на сложном фоне: два раза выведется
один и тот же фрагмент в одном и том же месте в режиме XOR, мы оставим фон
неизменным. Фактически, мы, таким образом, экономим память компьютера – не нужен
буфер для запоминания участка фона, находившегося под новой картинкой.
USES Graph, CRT;
{используется Graph и CRT}
{$I initgraf.pas}
{вставляем процедуру инициализации}
CONST R=10;
{радиус подвижного шарика}
VAR {переменные для оживления фрагмента}
X1, Y1, X2, Y2, Sx, Sy: integer;
maxx, maxy, sxmove, symove: integer;
{величина фрагмента}
Size: Word;
{размер фрагмента}
P: Pointer;
{указатель на буфер}
BEGIN
GrInit; {инициализация графики}
max: = GetMaxX; {максимальное поле экрана}
max: = GetMaxY;
X1: = maxx div 2 – R;{координаты области экрана,}
X1: =maxy div 2 – R; {в которой будет нарисован}
X2: =X1 + 2 * R; {шарик и которая будет со-}
Y2: =Y1 + 2 * R; {храненным фрагментом}
Sx: = X1; sxmove: = 3; {начальная точка движения и}
Sy: = Y1; symove: = - 1;{шаг перемещения шарика}
SetFillStyle ( SolidFill , Red );{выбор типа заливки}
PieSlice ( X1 + R, Y1 + R, 0, 360, R );
{рисование шарика}
Size: = ImageSize (X1, Y1, X2, Y2);
{фрагмент в байтах}
GetMem (P, Size);
{размещение буфера}
GetImage (X1, Y1, X2, Y2, P^);
{фрагмент заносится в буфер}
SetFillStyle (CloseDotFill, blue);
{тип заливки фона}
Bar (50, 50, maxx – 50, maxx –50);
{фоновая картинка}
Repeat
{наличие движения шарика}
PutImage (Sx, Sy, P^, XORPut); {ввод шарика}
Delay (12);
{пауза}
PutImage (Sx, Sy, P^, XORPut); {стирание шарика}
{ограничение на движение шарика в пределах поля фона }
If (Sx < 50) or (Ss >maxx – 50 –2 * R) then
sxmove: = - sxmove;
If (Sy < 50) or (Sy > maxy – 50 –2 * R) then
symove: = - symove;
Inc (Sx, sxmove);
{следующая точка появления}
Inc {Sy, symove);
{шарика на экране}
Until KeyPressed;
{…пока не нажата клавиша}
FreeMem (P, Size);
{освобождение памяти буфера}
CloseGraph;
{закрытие режима графики}
END.
В приведенном примере продемонстрирован алгоритм мультипликации,
применяющий “битовые” методы (используется пересылка битовых массивов
процедурами GetImage и PutImage).Скорость движения картинки сильно зависит от
разрешения экрана и количества цветов: наибольшая – в режиме CGA 640x200 2 цвета (1
бит на пиксел), наименьшая – в режиме VGA 320x200 256 цветов (8 бит на пиксел).
43
Возникают также некоторые сложности с синхронизацией перемещений и частоты
вертикальной развертки монитора.
Обращаем внимание на стандартную связку:
Size: =ImageSize (X1, Y1, X2, Y2); {фрагмент в байтах}
GetMem (P, Size);
{размещение буфера}
GetImage (X1, Y1, X2, Y2, P^);
{фрагмент помещается в буфер}
..
PutImage( X, Y, P^, xxxPut);
{вывод фрагмента( ов) }
FreeMem (P, Size);
{освобождение буфера}
организующую хранение динамического фрагмента через переменную P типа Pointer
(хранит адрес памяти – «кучи» при выполнении программы, т.е. является указателем на
нее). В вызовах PutImage / GetImage указатель P должен быть разыменован (т.е.
обращаться не к адресу, а к самой памяти или хранящемуся там значению). Таким
образом, здесь используется динамическая область памяти – «куча», выделяемая
программе при ее выполнении.
44
Download