ЗАНЯТИЕ 8
Лекция
Для того, чтобы писать серьезные сложные программы с малыми затратами сил и времени, избегая множества ошибок, мало знать операторы какого-либо языка программирования. Необходимо овладеть навыками структурного программирования (навыками разработки и написания программ). Применение их на практике позволит Вам:
· просто и легко писать программы;
· получать понятные и легкочитаемые программы;
· быстро находить ошибки в программе;
· быстро изменять и совершенствовать программу.
Одна из главных идей структурного программирования — это, так называемое, программирование сверху вниз. То есть поставленная задача разбивается на несколько более простых подзадач. Далее каждая из подзадач также разбивается на части. Этот процесс продолжается до тех пор, пока в итоге Вы не получите несколько элементарных и простых подзадач, которые нужно решить.
Отдельные подзадачи в языке Паскаль называются процедурами.
С процедурами мы с вами уже работали, когда изучали Лого. Там процедура обозначалась, как новая команда для черепашки, состоящая из системы команд исполнителя.
Для того, чтобы понять, как процедуры используются и описываются в паскале, разберем задачу рисования елки. Причем начинать решение задачи будем с составления алгоритма решения (т. е. как-бы пишем задачу с «конца») на русском языке. Какие основные действия нам надо совершить для решения данной задачи? Запишем их:
1. Ввести данные для рисования елочки — начальные координаты X и Y, длину большого основания OSN1, длину самого маленького основания OSN2, высоту одного треугольничка H.
2. Инициализировать графику.
3. Нарисовать елочку.
4. Задержать картинку на экране.
5. Закрыть графику.
Эти пять пунктов и состовляют алгоритм решения задачи. т. е. мы разбили большую задачу на маленькие подзадачи. Теперь переведем этот алгоритм на язые программирования Паскаль. Переводить будем следующим образом, если один пункт решения можно заменить одним оператором языка Паскаль, то заменяем, иначе (т. е. если один пункт решения можно заменить только несколькими операторами) заменяем этот пункт новой командой — процедурой, которую потом надо будет описать в блоке объявления. В результате перевода получим следующее решение задачи на языке паскаль.
BEGIN { ******* MAIN PROGRAM ******* }
VVOD(x,y,osn1,osn2,h); {Ввести данные x,y,osn1,osn2,h}
INITGRAPH;{Инициализировать графику}
ELKA(x,y,osn1,osn2,h); {Нарисовать елку в зависимости от x,y,osn1,osn2,h}
READKEY; {Задержать картинку на экране}
CLOSEGRAPH; {Закрыть графику}
END.
Из приведенного решения сразу видны необходимые для решения задачи переменные. Опишем их в блоке объявления.
VAR x,y,osn1,osn2,h: INTEGER;
В теле программы мы видим названия действий, которые необходимо выполнить для решения задачи. Эти действия, как было сказано выше, называются в Паскале процедурами, величины в круглых скобках называются параметрами процедур.
Когда Паскаль встречает название действия, которое не является его собственной инструкцией, он рассматривает это как вызов процедуры и передает управление в процедуру с указанным именем (в нашем случае vvod и elka являются именами процедур). После выполнения всех действий в процедуре управление возвращается в основную программу на инструкцию, следующую после вызова процедуры.
Формат вызова процедуры:
<имя процедуры> ( <список фактических параметров> );
Процедуры должны быть описаны в разделе объявлений до основной программы, то есть прежде чем вызвать процедуру, ее необходимо описать.
Формат описания процедуры:
procedure <имя процедуры> ( <список формальных параметров> );
<блок объявлений>
begin
<действия>
end;
Первая строка при описании процедуры называется заголовком процедуры и содержит в себе служебное слово procedure, имя процедуры, которое является правильным идентификатором, и в круглых скобках список формальных параметров с указанием их типа. Формальные параметры разного типа отделяются друг от друга точкой с запятой. (Параметры называются формальные, т. к. мы описываем «формулу», по которой работает процедура).
При вызове процедуры — параметры фактические, т. е. те с которыми мы фактически работаем.
Необходимо помнить правило соответсвия фактических и формальных параметров: Их количество, порядок следования и типы совпадают.
После заголовка может быть блок объявления и обязательно блок описания действий. т. е. процедура имеет такую же структура, как и программа на языке Паскаль (процедура — небольшая программа внутри основной программы).
Если в процедуре необходимо использовать переменные, которые не являются параметрами, то их надо описать в блоке объявлений этой процедуры.
При вызове процедуры под эти переменные будут выделены ячейки памяти. По ходу выполнения процедуры в эти ячейки заносятся соответствующие данные. Однако после выполнения процедуры при возвращении в основную программу переменные исчезают и данные теряются.
Таким образом, переменные, описанные в процедуре, действуют только внутри данной процедуры и совершенно не доступны из основной программы. Такие переменные называются локальными.
Переменные, описанные в основной программе, являются глобальными и доступны как в основной программе, так и в процедурах. Однако, если в основной программе и в процедуре описаны переменные с одинаковыми именами, то при входе в процедуру глобальные переменные “забываются” и действуют локальные, а по возвращении в основную программу локальные переменные теряются, а глобальные “вспоминаются”.
Но вернемся к нашей программе. Если запустить ее на выполнение, то компьютер приготовит ячейки в оперативной памяти для переменных x, y, osn1, osn2, h типа INTEGER. Потом перейдет к блоку описания действий и сразу наткнется на неизвестную ему команду VVOD. Для того, чтобы компьютер знал, что надо делать в данном случае, эту команду — процедуру — надо описать (объявить) в блоке объявлений (клавиши <Alt>+<F4>). Выглядеть это будет так:
PROCEDURE VVOD (VAR kx,ky,dl1,dl2,h1:INTEGER);
BEGIN
WRITELN('Введите X,Y, длину 1 и 2, высоту');
READLN(kx,ky,dl1,dl2,h1);
END;
Посмотрим, что произойдет при вызове процедуры VVOD. Для этого заглянем в окно Watch (клавиша <F5>) отладчика среды Микропаскаль. До вызова процедуры, когда мы опишем переменные, используемые в нашей программе, окно состояния переменных будет выглядеть как представлено на рисунке1. При передаче управления в процедуру VVOD окно Watch изменит свой вид (рис. 2).
Рис.1 Рис.2
Переменным x, y, osn1, osn2, h присваиваются новые имена kx,ky,dl1,dl2,h1. Значения, введенные с клавиатуры, заносится в ячейки kx,ky,dl1,dl2,h1. При возвращении в основную программу имена x, y, osn1, osn2, h восстанавливаются, а значения, которые лежали в соответствующих ячейках, так и остаются там лежать.
Таким образом, в процедуре VVOD в качестве фактического параметра мы передаем переменную. Поэтому такие параметры называются параметрами-переменными. В заголовке описания процедуры перед параметрами-переменными пишется слово VAR.
Параметр-переменная показывает, откуда значение взять и куда ПОЛОЖИТЬ. Говорят, что процедура возвращает значение параметра-переменной в программу.
После ввода исходных данных и инициализации графики управление передается процедуре, рисующей елку. Напишем эту процедуру. Сначала опишем алгоритм решения данной задачи.
1. Зададим длину основания текущего треугольника (нижнего) dl равной первой введено длине основания dl1.
2. В текущую координату y1 положим начальное значение координаты ky.
3. Пока текущая длина основания больше или равна меньшей длине основания делаем следующее:
4. Перемещаем курсор в точку с координатами kx, y1 – это середина основая текущего треугольника.
5. Рисуем линию влево длиной в половину основания.
6. Рисуем линию вверх к вершине треугольника (высота h1).
7. Рисуем линию от вершины к правому углу треугольника.
8. Рисуем линию до середины основания (треугольник закончен).
9. Переопределяем координату y1 (вверх на высоту треугольника h1).
10. Переопределяем длину основания треугольника. (уменьшаем на какое-то значение, например 10. Можно шаг изменения длины основания задать в начальных данных)
11. Задаем стиль закраски для ствола елки.
12. Рисуем ствол елки с помощью процедуры BAR.
Как видно из алгоритма решения задачи — нам кроме параметров (kx,ky,dl1,dl2,h1) понадобятся еще две дополнительные локальные переменные dl1 и y1.
Наша процедура будет выглядеть так:
PROCEDURE ELKA (kx, ky, dl1, dl2, h1:INTEGER);
VAR dl,y1: INTEGER;
BEGIN
dl:= dl1;
y1:= ky;
WHILE dl>=dl2 DO
BEGIN
MOVETO(kx,y1);
LINETO(kx-dl div 2,y1,2);
LINETO(kx,y1-h1,2);
LINETO(kx+dl div 2,y1,2);
LINETO(kx,y1,2);
y1:= y1-h1;
dl:= dl-10;
END;
SETFILLSTYLE(0,8);
BAR(kx-5,ky,kx+5,ky+10);
END;
Посмотрим в окне отладчика на работу этой процедуры.
Мы видим, что у нас появились ячейки для локальных переменных Dl и Y1. Кроме того, появились ячейки kx, ky, dl1, dl2, h1, в которые скопировались значения из соответствующих им параметров x,y,osn1,osn2,h, указанных при вызове процедуры.
После выполнения процедуры при возвращении в основную программу ячейки kx, ky, dl1, dl2, h1 исчезают. Содержимое ячеек x,y,osn1,osn2,h остается без изменений.
Таким образом, в процедуру ELKA в качестве фактических параметров мы передаем значения. Такие параметры называются параметрами-значениями. Перед параметром-значением в списке формальных параметров ничего не стоит. В программу из процедуры ничего не возвращается. В случае параметров-значений на месте фактических параметров может быть константа, переменная или выражение.
Все, все процедуры описаны, задача решена.
Программа в собранном виде будет выглядеть следующим образом:
PROGRAM elka_1;
VAR x,y,osn1,osn2,h: INTEGER;
PROCEDURE VVOD (VAR kx,ky,dl1,dl2,h1:INTEGER);
BEGIN
WRITELN('Введите X,Y, длину 1 и 2, высоту');
READLN(kx,ky,dl1,dl2,h1);
END;
PROCEDURE ELKA (kx,ky,dl1,dl2,h1:INTEGER);
VAR dl,y1: INTEGER;
BEGIN
dl:= dl1;
y1:= ky;
WHILE dl>=dl2 DO
BEGIN
MOVETO(kx,y1);
LINETO(kx-dl div 2,y1,2);
LINETO(kx,y1-h1,2);
LINETO(kx+dl div 2,y1,2);
LINETO(kx,y1,2);
y1:= y1-h1;
dl:= dl-10;
END;
SETFILLSTYLE(0,8);
BAR(kx-5,ky,kx+5,ky+10);
END;
BEGIN { ******* MAIN PROGRAM ******* }
VVOD(x,y,osn1,osn2,h);
INITGRAPH;
ELKA(x,y,osn1,osn2,h);
READKEY;
CLOSEGRAPH;
END.