Лекции.ИНФО


Вложение циклов в разветвления и наоборот



Реальная программа на Паскале представляет собой сложную мозаику из циклических и разветвляющихся частей, вложенных друг в друга. Мы уже видели в 5.7, как в оператор case был вложен оператор for. В свою очередь в оператор цикла могут быть вложены другие операторы, как в 7.3, и так до бесконечности.

Для тренировки определите, что напечатает следующий фрагмент:

for i:=1 to 5 do begin

a:=9;

if i*i = a then for k:=5 to 8 do Write(k)

else WriteLn(1997);

end {for}

Ответ:

Вложенные циклы

Поставим себе задачу - напечатать таблицу умножения. В следующем виде:

 

1*1= 1*2= 1*3= 1*4= 1*5= 1*6= 1*7= 1*8= 1*9=
2*1= 2*2= 2*3= 2*4= 2*5= 2*6= 2*7= 2*8= 2*9=
3*1= 3*2= 3*3= 3*4= 3*5= 3*6= 3*7= 3*8= 3*9=
4*1= 4*2= 4*3= 4*4= 4*5= 4*6= 4*7= 4*8= 4*9=
5*1= 5*2= 5*3= 5*4= 5*5= 5*6= 5*7= 5*8= 5*9=
6*1= 6*2= 6*3= 6*4= 6*5= 6*6= 6*7= 6*8= 6*9=
7*1= 7*2= 7*3= 7*4= 7*5= 7*6= 7*7= 7*8= 7*9=
8*1= 8*2= 8*3= 8*4= 8*5= 8*6= 8*7= 8*8= 8*9=
9*1= 9*2= 9*3= 9*4= 9*5= 9*6= 9*7= 9*8= 9*9=

 

Начнем с малого - пусть нужно напечатать

1*1=1

Вот фрагмент программы:

 

Фрагмент 1

a:=1;

b:=1;

proizv:=a*b;

Write(a, ’*’ ,b, ’=’ ,proizv)

Здесь в операторе Write 5 элементов:

* сомножитель a,

* символ знака умножения ’*’,

* сомножитель b,

* символ ’=’,

* значение произведения proizv

 

Усложним задачу. Попробуем заставить компьютер напечатать первую строку таблицы:

1*1= 1*2= 1*3= 1*4= 1*5= 1*6= 1*7= 1*8= 1*9=

Замечаем, что здесь нам нужно решить 9 элементарных задач на вычисление произведения, первую из которых решает фрагмент 1. Все они очень похожи и различаются лишь значением второго сомножителя. Таким образом, для решения каждой из 9 задач подошел бы наш фрагмент 1, если бы в нем в операторе b:=1 вместо единицы стояла нужная цифра. В данном случае идеально подходит оператор for:

 

Фрагмент 2

a:=1;

for b:=1 to 9 do begin

proizv:=a*b;

Write(a, ’*’ ,b, ’=’ ,proizv, ’ ’ )

end {for}

Для того, чтобы печать была аккуратной, оператор Write мы дополнили символом пробела ’ ’. Он нужен для того, чтобы отдельные столбцы таблицы не сливались.

Следующая ступень усложнения - последняя - напечатать не одну строку таблицы, а девять. Для этого фрагмент 2 должен быть выполнен 9 раз, каждый раз - с новым значением a. Чтобы этого достичь, “обнимем” фрагмент 2 оператором for точно так же, как мы это сделали с фрагментом 1.

 

Фрагмент 3

for a:=1 to 9 do

for b:=1 to 9 do begin

proizv:=a*b;

Write(a, ’*’ ,b, ’=’ ,proizv, ’ ’ )

end {for b}

end {for a}

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

VAR a,b,proizv: Integer; {1}

BEGIN {2}

for a:=1 to 9 do begin {3}

WriteLn; {4}

for b:=1 to 9 do begin {5}

proizv:=a*b; {6}

Write(a, ’*’ ,b, ’=’ ,proizv:3, ’ ’ ) {7}

end {for b} {8}

end {for a} {9}

END. {10}

WriteLn нужен для того, чтобы каждая новая строка таблицы начиналась с новой строки экрана.

Формат :3 означает, что на изображение произведения на экране отведено три позиции. Формат в нашем примере нужен для того, чтобы разные по количеству цифр произведения (например, 4 и 25) занимали на экране одинаковое по размеру место, а то не получится у нас аккуратных столбиков в таблице.

В целом программа иллюстрирует идею вложенных циклов, когда один, внутренний, цикл вложен внутрь другого, внешнего. У нас тело внешнего цикла (строки 4 и 5) выполняется 9 раз, а тело внутреннего (строки 6, 7 и 8) - 81 раз, так как на каждое выполнение строки 5 оно выполняется 9 раз.

 

Задания 53-56:

53) Распечатать все возможные сочетания из двух цифр - первая цифра может быть любой от 3 до 8, вторая - любой от 0 до 7. Например, 36, 44, 80.

54) Распечатать все возможные сочетания из четырех цифр, каждая из которых может принимать значения 1,2,3. Например, 2123, 3312, 1111.

55) Подсчитать количество таких сочетаний.

56) Подсчитать количество неубывающих сочетаний, то есть таких, где каждая следующая цифра не меньше предыдущей - 1123, 1223, 2222 и т.п., но не 3322.

Поиск максимального из чисел

Задача программисту: Найти максимальноеиз вводимых в компьютер чисел.

Задача рыбаку: Принести домой самую большую из выловленных рыб.

Решение рыбака: Рыбак приготовил для самой большой рыбы пустое ведро. Первую пойманную рыбу рыбак не глядя бросает в это ведро. Каждую следующую рыбу он сравнивает с той, что в ведре. Если она больше, то он бросает ее в ведро, а ту, что была там раньше, выпускает в реку.

Решение программиста: Программист приготовил для самого большого числа ячейку и придумал ей название, скажем, max. Первое число программист не глядя вводит в эту ячейку. Каждое следующее число (назовем его chislo) он сравнивает с max. Если оно больше, то он присваивает переменной max значение этого числа.

Напишем программу для определения максимального из 10 вводимых чисел:

VAR i, chislo, max :Integer;

BEGIN

ReadLn(max); {первую рыбу - в ведро}

for i:=2 to 10 do begin {ловим остальных рыб:}

ReadLn(chislo); {поймали очередную рыбу}

if chislo>max then max:=chislo {и если она больше той, что в ведре, бросаем ее в ведро }

end {for};

WriteLn(max) {несем самую большую рыбу домой}

END.

 

Задание 57: Найти из N чисел минимальное. Каким по порядку было введено минимальное число? Указание: для номера минимального числа тоже нужно отвести специальную ячейку.

Задание 58: У вас есть данные о росте ваших одноклассников. Правда ли, что рост самого высокого отличается от роста самого низкого больше, чем на 40 см.?

 

Глава 8. Процедуры

Смысл и выгода процедур вам известны из 2.8. Напомню, что процедурынужны для того, чтобы программа была короче, и чтобы ее было легче прочесть. Ни одна профессиональная программа не обходится без процедур или без их старших братьев - объектов, рассмотрение которых выходит за рамки начального курса.

Я мог бы объяснить вам процедуры, не вводя новых операторов, однако мне кажется, что лучше всего их объяснять на музыкальном примере, поэтому я предварительно расскажу вам, как заставить компьютер звучать и исполнять мелодии.

Компьютер звучит

Если даже в вашем компьютере нет звуковой карты, все равно он может звучать. Посмотрим, что заставляет его сделать такая программа:

USES CRT;
BEGIN

Sound(300)

END.

Пояснения:

Если мы хотим, чтобы наш компьютер настроился на работу со звуком, мы должны первой строкой программы написать Uses CRT. Подробно о том, что это значит, я расскажу в 9.1, а сейчас не будем отвлекаться.

Единственный оператор программы Sound(300) приказывает компьютеру включить ровный однообразный звук частотой 300 колебаний в секунду (герц). Слово Sound звучит “‘саунд”, переводится “звук”. Для тех, кто не знает, поясню, что частота определяет высоту звука. Sound(300) - это звук средней высоты . Sound(6000) - это звук высокий, тонкий, как комариный писк. Sound(40) - звук низкий, толстый.

Итак, все действие нашей программы заключается в том, что включается звук. А что дальше? Когда он выключается? А никогда! Программа, выполнившись мгновенно, прекращает свою работу, и мы остаемся один на один со звуком. Через две-три минуты он начинает нам надоедать. Пытаясь его прекратить, мы выходим из среды Паскаля - не помогает. В общем, звук продолжается все то время, пока компьютер включен. В остальном он никак не мешает компьютеру правильно работать. Мы можем запустить другую программу - звук будет сопровождать нас. Самый простой способ избавиться от звука - перезапустить компьютер. Другой способ - выполнить программу, в которой есть оператор NoSound:

USES CRT;
BEGIN

NoSound

END.

Оператор NoSound(звучит “ноу ‘саунд”, переводится “нет звука”), выключает звук. Совет: Работая с любой звуковой программой, откройте еще одно окно и введите туда эту программу с NoSound. Не пожалеете!

Теперь рассмотрим такую программу:

USES CRT;
BEGIN

Sound (300); Delay (2000); NoSound

END.

Здесь мы видим новый для нас оператор Delay (2000). Он читается “ди’лэй”, переводится “отсрочка” или “пауза”. Его действие в том, что он приостанавливает работу программы на 2000 миллисекунд или, что то же самое, на 2 секунды. Delay (1000) приостанавливает работу программы на 1 секунду, Delay (500) - на полсекунды и т.д. (Должен сказать, что на самом деле продолжительность паузы сильно зависит от быстродействия компьютера).

Итак, оператор Sound (300) включает звук. Сразу после этого оператор Delay (2000) приостанавливает работу программы на 2 сек. Но звук этот оператор не может выключить, компьютер продолжает звучать. Через 2 сек программа снова оживает и выполняется оператор NoSound. Звук выключается. Таким образом, результатом выполнения этих трех операторов будет звук частотой 300 гц продолжительностью 2 сек.

Рассмотрим работу программы:

USES CRT;
BEGIN

Sound(900);Delay(1000);Sound(200);Delay(3000);NoSound

END.

Начинается она со звука частотой 900 гц и продолжительностью 1 с, а затем оператор Sound(200) включает вместо звука в 900 гц звук частотой 200 гц, который длится 3 с.

В операторах Sound и Delay вместо чисел можно записывать целочисленные переменные величины и выражения. Вот программа, производящая серию постепенно повышающихся звуков:

USES CRT;

VAR hz: Integer;

BEGIN

hz:=60;

while hz<800 do begin

Sound(hz);

Delay(1000);

hz:=hz+40

end;

NoSound

END.

Если вас интересуют музыкальные ноты, то вот вам операторы Sound, задающие все ноты третьей октавы:

Нота до Sound(523)
Нота до диез Sound(554)
Нота ре Sound(587)
Нота ре диез Sound(622)
Нота ми Sound(659)
Нота фа Sound(698)
Нота фа диез Sound(740)
Нота соль Sound(784)
Нота соль диез Sound(831)
Нота ля Sound(880)
Нота ля диез Sound(932)
Нота си Sound(988)

 

Задания 59-63:

59) Уменьшив как следует числа в операторах Delay(1000) и hz:=hz+40 можно добиться впечатления одного непрерывного постепенно повышающегося звука (сирена). Попробуйте сделать это.

60) Если вам это удалось, попробуйте смоделировать сирену милицейской машины: звук вверх - звук вниз - звук вверх - звук вниз - … и так несколько раз.

61) Быстро чередуя короткие звуки двух разных частот и короткие паузы, можно добиться разных звуковых эффектов и шумов, например звука телефонного звонка или моторчика авиамодели.

62) Сделайте “датчик чувствительности уха к высоким частотам”. Извстно, что человеческое ухо не может слышать звуки, частота которых превышает 10000-20000 гц. У разных людей порог чувствительности разный. Напишите программу, которая выдает звуки все более высокой частоты и печатает на экране значения этой частоты, так что человек успевает увидеть, при какой частоте он перестает слышать звук. Вы сможете определить, у кого порог чувствительности выше – у вас или у вашего друга. Удобно внутри цикла использовать команду ReadLn.

63) Если у вас есть некоторое музыкальное образование, вы можете попробовать заставить компьютер исполнить простенькую мелодию из нескольких нот.

Простейшие процедуры

Задача:Все вы слышали про азбуку Морзе, широко использовавшуюся раньше для радиосвязи с кораблями и не только с ними. Включив радиоприемник и покрутив ручку настройки, можно было услышать частую тоненькую дробь однотонных сигналов разной длительности: точки (очень короткие сигналы) и тире (сигналы подлиннее). Каждая буква алфавита кодируется в азбуке Морзе последовательностью точек и тире.

Вот таблица кодирования русских и латинских букв (латинские буквы показаны строчными, а русские - заглавными):

Аa .- Бb -… Вw .-- Гg --. Дd -.. Еe . Жv …- Зz --..
Иi .. Йj .--- Кk -.- Лl .-.. Мm -- Нn -. Оo --- Пp .--.
Рr .-. Сs Тt - Уu ..- Фf ..-. Хh …. Цc -.-. Ч ---.
Ш ---- Щq --.- Ъ,Ьx -..- Ыy -.-- Э ..-.. Ю ..-- Я .-.-    

 

Закодируем азбукой Морзе текст PIPING и заставим компьютер воспроизвести соответствующий набор звуков. Пусть продолжительность точки - 100 миллисекунд, тире - 200, пауза молчания после точки или тире - 80, пауза после буквы - 300. Частота звуков не играет роли, выберем наугад 900 гц.

 

Вот как будет выглядеть фрагмент, воспроизводящий точку:

Sound(900);Delay(100); NoSound; Delay(80)

А вот фрагмент, воспроизводящий тире:

Sound(900);Delay(200); NoSound; Delay(80)

 

Вот вся программа:

Программа 1

USES CRT;
BEGIN

{буква P:}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Sound(900); Delay(200); NoSound; Delay(80); {тире}

Sound(900); Delay(200); NoSound; Delay(80); {тире}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Delay(300); {пауза}

{буква I:}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Delay(300); {пауза}

{буква P:}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Sound(900); Delay(200); NoSound; Delay(80); {тире}

Sound(900); Delay(200); NoSound; Delay(80); {тире}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Delay(300); {пауза}

{буква I:}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Delay(300); {пауза}

{буква N:}

Sound(900); Delay(200); NoSound; Delay(80); {тире}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Delay(300); {пауза}

{буква G:}

Sound(900); Delay(200); NoSound; Delay(80); {тире}

Sound(900); Delay(200); NoSound; Delay(80); {тире}

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Delay(300); {пауза}

END.

Недостатки программы:

· Довольно большой объем, что обидно, так как в программе много одинаковых фрагментов.

· Если бы не комментарии, было бы совершенно непонятно, о чем эта программа.

 

А теперь я напишу ту же программу, но с использованием процедур:

Программа 2

USES CRT;

 

PROCEDURE tochka;

BEGIN Sound(900); Delay(100); NoSound; Delay(80) END;

 

PROCEDURE tire;

BEGIN Sound(900); Delay(200); NoSound; Delay(80) END;

 

BEGIN

{буква P:}tochka; tire; tire; tochka; Delay(300);

{буква I:} tochka; tochka; Delay(300);

{буква P:}tochka; tire; tire; tochka; Delay(300);

{буква I:} tochka; tochka; Delay(300);

{буква N:}tire; tochka; Delay(300);

{буква G:}tire; tire; tochka; Delay(300);

END.

Программа 2 гораздо короче и даже без комментариев понятнее программы 1. Поясним, как мы получили ее из предыдущей.

Сначала мы обнаружили в программе 1 часто повторяющиеся фрагменты. Их было два:

Sound(900); Delay(100); NoSound; Delay(80); {точка}

Sound(900); Delay(200); NoSound; Delay(80); {тире}

Затем мы придумали имена каждому фрагменту: tochka и tire. После этого можно было писать программу 2. Каждый фрагмент мы записали один раз в начале программы выше главного BEGIN, оформив его в виде так называемого описания процедуры:

PROCEDURE tochka;

BEGIN Sound(900); Delay(100); NoSound; Delay(80) END;

PROCEDURE tire;

BEGIN Sound(900); Delay(200); NoSound; Delay(80) END;

В результате программа “узнала”, что такое tochka и tire. С этого момента имена процедурtochka и tire можно употреблять, как обыкновенные операторы, ниже главного BEGIN. Паскаль выполняет программу, начиная с главного BEGIN, и когда он натыкается на имя процедуры, он подставляет вместо него соответствующий фрагмент, взятый из описания процедуры. Это событие называется вызовомпроцедурыилиобращениемк процедуре.

Синтаксис описания простейшей процедуры таков:

PROCEDURE имя ; BEGIN оператор ; оператор ; ... END

Слово PROCEDUREчитается “про’сидже”, переводится “процедура”. Имя процедуры создается по тем же правилам, что и имя переменной. Все, что идет после имени, будем называть телом процедуры.

Задание 64: Составьте программу с процедурами, которая исполнит мелодию “Чижик-пыжик” (ми-до-ми-до-фа-ми-ре-соль-соль-ля-си-до-до-до).

 

А теперь попробуем еще больше упростить нашу программу. Замечаем, что и в программе 2 тоже имеются одинаковые фрагменты:

{буква P:} tochka; tire; tire; tochka; Delay(300);

{буква I:} tochka; tochka; Delay(300);

Для экономии места их тоже выгодно оформить в виде процедур:

PROCEDURE P;

BEGIN tochka; tire; tire; tochka; Delay(300) END;

PROCEDURE I;

BEGIN tochka; tochka; Delay(300) END;

Остальные буквы тоже выгодно оформить в виде процедур, но уже не для экономии места, а для удобочитаемости программы. Вот окончательный вариант программы:

Программа 3

USES CRT;

 

PROCEDURE tochka;

BEGIN Sound(900); Delay(100); NoSound; Delay(80) END;

 

PROCEDURE tire;

BEGIN Sound(900); Delay(200); NoSound; Delay(80) END;

 

PROCEDURE P;

BEGIN tochka; tire; tire; tochka; Delay(300) END;

 

PROCEDURE I;

BEGIN tochka; tochka; Delay(300) END;

 

PROCEDURE N;

BEGIN tire; tochka; Delay(300) END;

 

PROCEDURE G;

BEGIN tire; tire; tochka; Delay(300) END;

 

 

BEGIN

P;I;P;I;N;G

END.

Эта программа понятна и без комментариев. От предыдущей она отличается тем, что процедуры вызываются не только из тела программы, но и из тел других процедур. Действительно, посмотрим на самое начало выполнения программы. Первое, на что натыкается Паскаль ниже главного BEGIN, это P. Заглянув выше главного BEGIN, Паскаль обнаруживает, что P - это имя процедуры, и начинает ее выполнять (вызывает на выполнение). При этом, первое, на что он натыкается, это tochka. Заглянув выше, Паскаль обнаруживает, что tochka - это имя процедуры, и тоже начинает ее выполнять (вызывает на выполнение). Обратите внимание, что

вызываемая процедура должна быть описана выше вызывающей.

Такая уж особенность у Паскаля. О том, что делать, если это требование выполнить невозможно, написано в 10.6. Закончив выполнять процедуру tochka, Паскаль возвращается в процедуру P (возвращает управление процедуре P). Там он идет к следующему оператору. Это оказывается tire. И т.д.

Задание 65: Компьютер печатает текст Песня «Чижик-пыжик». 1 куплет. После этого исполняется мелодия чижика-пыжика (см. выше). Затем компьютер печатает текст 2 куплет и мелодия чижика-пыжика исполняется еще раз.

Процедуры и операторы

Разберемся немного с терминологией. Прежде всего уточним структуру программына Паскале. Любая программа на Паскале состоит из двух разделов:

 

{Раздел описаний}

BEGIN

{Раздел операторов}

END.

 

Раздел описаний может и отсутствовать, если же он присутствует, то может содержать разделы VAR, LABEL, USES, PROCEDURE и другие, нами еще не изученные.

Раздел операторов состоит из операторов, разделенных точками с запятой.

В самом начале части II я упомянул, что многие операторы на Паскале являются обращениями к процедурам. Для простоты мы договорились не различать поначалу обращения к процедурам и другие операторы. Сейчас нам пора этому научиться. Кроме процедур, написанных нами (таких как tochka, tire и др.), существуют еще так называемые стандартные процедурыПаскаля. Мы уже изучили следующие стандартные процедуры: Write, WriteLn, Read, ReadLn, Sound, Delay, NoSound. Они называются стандартными, потому что определены “внутри Паскаля”[7] и ими можно пользоваться, не описывая их, как мы описывали созданные нами “пользовательские” процедуры. Природа пользовательских и стандартных процедур едина, поэтому мы будем называть и те и другие просто процедурами. Операторами же мы будем продолжать называть операторы goto, if, case, for, while, repeat, оператор присваивания, составной оператор и еще незнакомые нам оператор with и пустой оператор.









Последнее изменение этой страницы: 2017-03-17; Просмотров: 11;


lektsia.info 2017 год. Все права принадлежат их авторам! Главная