Турбо-Паскаль 7.0

Необходимые сведения о компьютере и программе. Командный и программный режимы программы "Турбо-Паскаль 7.0". Простые, линейные программы. Операторы ввода-вывода. Запись арифметических выражений. Стандартный модуль Graph, текстовый и графический режимы.

Рубрика Программирование, компьютеры и кибернетика
Вид учебное пособие
Язык русский
Дата добавления 13.10.2012
Размер файла 1,5 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Задание 95 (сложное): Сделайте игру: Пушка на экране стреляет в цель ядрами. С какого выстрела она поразит противника? Между пушкой и целью расположена небольшая гора. Перед началом игры случайно задается горизонтальная координата цели. Затем рисуется картинка.

Перед каждым выстрелом компьютер отображает на экране номер выстрела и запрашивает у человека стартовую скорость ядра v и угол наклона ствола пушки к земле. Затем летит ядро. Полет ядра подчиняется двум уравнениям: s=v*t*cos и h=v*t*sin - 9.81*t2/2 (см. предыдущее задание). Считается, что цель поражена, если ядро «отгрызло» от нее хоть маленький кусочек.

Я рассмотрел основные простые возможности модуля Graph. Некоторые другие средства модуля будут рассмотрены в Глава 15.

2.7 Создаем первую большую программу

В этой главе я вместе с вами напишу первую реальную программу. Достаточно большую для начинающих (строк на сто).

Прежде, чем приступить к большой программе, прочтите и изучите все, что вы еще не успели изучить в части IV, особенно “Отладку больших программ”.

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

2.7.1 Постановка задачи

Программу мы будем составлять для следующей задачи.

Задача: Создать мультфильм следующего содержания:

На экране возникает ночной пейзаж и секунды три ничего не происходит:

Затем звучит “космическая” музыка (секунд на 5).

Затем сверху слева появляется летающая тарелка (пусть это будет небольшой эллипс) и не спеша опускается на землю (до линии горизонта).

Затем снова раздается та же музыка.

Затем в окне ближайшего дома вспыхивает свет. Все.

2.7.2 Программирование по методу “сверху-вниз”

Повторю, что любая реальная (то есть достаточно большая и делающая «реальные» вещи) программа на Паскале содержит процедуры. Обычно более “основные” процедуры (P, I, N ) обращаются к менее “основным” (tochka, tire), те - к еще менее “основным” и т.д. Такая организация называется иерархией. Она подобна организации подчинения в армии - генералы приказывают полковникам, те - майорам и т.д.

Первая задача, стоящая перед программистом, - разбить программу на несколько частей, исходя из смысла задачи. В 8.2 это были части P, I, P, I, N, G. Обычно для правильного разбиения нужен опыт. В нашем случае разбиение напрашивается само собой исходя из последовательности действий мультфильма:

рисование пейзажа

пауза три секунды

музыка

движение тарелки

музыка

свет в окне

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

Итак, у нас будет три процедуры. Придумаем им имена:

пейзаж - Landscape

музыка - Music

тарелка - Flying_Saucer

Теперь относительно каждой из процедур нужно решить, следует ли ее разбивать на части, причем рассуждать нужно так же, как при разбиении на части всей программы:

Music. Для музыки можно было бы использовать процедуры-ноты, но я для простоты ограничусь набором операторов Sound и Delay. Не разбиваем.

Flying_Saucer. Движение тарелки по экрану ничем не отличается от движения окружности, которое программируется небольшим циклом. Здесь тоже не нужно разбиения на части.

Landscape. Вот здесь без разбиения не обойтись. Для этого посмотрим, из чего состоит пейзаж. Он состоит из земли и неба. Земля состоит из горизонта, зеленой краски травы, домов и деревьев. Небо состоит из синей краски неба, звезд и луны. Вы можете разделить пейзаж на две большие части - землю и небо, каждую из которых делить дальше. Это будет логично и четко. Я же для простоты забуду о земле и небе и буду считать пейзаж прямо состоящим из горизонта, травы, домов, деревьев, синевы, звезд и луны. Порядок рисования я выберу такой:

горизонт

синева

луна

звезды

дерево

дерево

дерево

дом

дом

трава

Ни одна из этих десяти частей не является достаточно большой, чтобы претендовать на ранг процедуры. Однако, дом и дерево встречаются не один раз, значит они и будут процедурами. Придумаем им имена:

дом - House

дерево - Tree

Я на примере показал, как нужно дробить любую задачу на все более мелкие части до тех пор, пока не станет ясно, как любую из этих мелких частей запрограммировать на Паскале. Это и называется программированием по методу “сверху вниз”. Можно программировать и по методу “снизу вверх”, когда программист сначала составляет список самых мелких частей, из которых состоит задача, а потом собирает из них более крупные части.

Поговорим о том, как запрограммировать на Паскале наши самые мелкие части:

горизонт - просто линия во весь экран

синева - заливаем верхнюю часть экрана до горизонта синей краской

луна - желтая окружность, залитая желтой краской

звезды - звездное небо мы уже делали. Здесь надо будет только позаботиться, чтобы звезды не появлялись ниже горизонта

дерево - залитые эллипс и прямоугольник

дом - аналогично дереву

трава - аналогично синеве

У вас может возникнуть следующий вопрос: Процедура Tree рисует некое дерево в определенном месте экрана. Как, использовав эту процедуру три раза, мы получим три дерева в разных местах экрана? Ответ: здесь нам на помощь придут переменные величины, о чем позже.

2.7.3 Сначала - работа над структурой программы

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

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

Сначала для простоты отладим “пустую” программу без разбивки пейзажа, и если она работает правильно, тогда составим “пустую” программу полностью. Вот программа без разбивки пейзажа:

USES Graph,CRT;

VAR Device, Mode :Integer;

PROCEDURE Landscape;

BEGIN WriteLn(`Работает процедура Пейзаж') END;

PROCEDURE Music;

BEGIN WriteLn(`Работает процедура Музыка') END;

PROCEDURE Flying_Saucer;

BEGIN WriteLn(`Работает процедура Летающая тарелка') END;

BEGIN

Device:=0;

InitGraph(Device, Mode, '<путь к гр.др.>');

DirectVideo:=false;

Landscape; { рисование пейзажа }

WriteLn(`Работает пауза 3 секунды'); { пауза три секунды }

Music; { музыка }

Flying_Saucer; { движение тарелки }

Music; { музыка }

WriteLn(`Работает свет в окне'); { свет в окне }

ReadLn;

CloseGraph

END.

Пояснение. В нашей программе мы используем и модуль Graph и модуль CRT, так как нам понадобятся и графика и музыка. В этом случае оператор WriteLn просто так не работает. Чтобы он все-таки заработал, необходимо предварительно выполнить оператор DirectVideo:=false. Смысл его рассматривать не будем.

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

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

Работает процедура Пейзаж

Работает пауза 3 секунды

Работает процедура Музыка

Работает процедура Летающая тарелка

Работает процедура Музыка

Работает свет в окне

Теперь составим “пустую” программу полностью, с разбивкой пейзажа.

USES Graph,CRT;

VAR Device, Mode :Integer;

PROCEDURE Tree;

BEGIN WriteLn(`Работает процедура Дерево') END;

PROCEDURE House;

BEGIN WriteLn(`Работает процедура Дом') END;

PROCEDURE Landscape;

BEGIN

WriteLn(`Работает процедура Пейзаж');

WriteLn(`Работает Горизонт процедуры Пейзаж'); { горизонт }

WriteLn(`Работает Синева процедуры Пейзаж'); { синева }

WriteLn(`Работает Луна процедуры Пейзаж'); { луна }

WriteLn(`Работают Звезды процедуры Пейзаж'); { звезды }

Tree; { дерево }

Tree; { дерево }

Tree; { дерево }

House; { дом }

House; { дом }

WriteLn(`Работает Трава процедуры Пейзаж'); { трава }

END;

PROCEDURE Music;

BEGIN WriteLn(`Работает процедура Музыка') END;

PROCEDURE Flying_Saucer;

BEGIN WriteLn(`Работает процедура Летающая тарелка') END;

BEGIN

Device:=0;

InitGraph(Device, Mode, '<путь к гр.др.>');

DirectVideo:=false;

Landscape; { рисование пейзажа }

WriteLn(`Работает пауза 3 секунды'); { пауза три секунды }

Music; { музыка }

Flying_Saucer; { движение тарелки }

Music; { музыка }

WriteLn(`Работает свет в окне'); { свет в окне }

ReadLn;

CloseGraph

END.

Пояснения: То новое, что появилось по сравнению с укороченным вариантом программы, я выделил жирным шрифтом. Обратите внимание, что раздел операторов совершенно не изменился. Изменилось только содержание процедуры Landscape и выше нее появились описания новых процедур, каждая из которых о себе рапортует. (Они описаны именно выше, согласно требованию из 8.2.) Порядок записи операторов внутри процедуры Landscape строго соответствует порядку рисования, который я выбрал ранее.

Если наша “пустая” программа верна, то результатом ее работы будет такая последовательность сообщений (новые сообщения я выделил жирным шрифтом):

Работает процедура Пейзаж

Работает Горизонт процедуры Пейзаж

Работает Синева процедуры Пейзаж

Работает Луна процедуры Пейзаж

Работают Звезды процедуры Пейзаж

Работает процедура Дерево

Работает процедура Дерево

Работает процедура Дерево

Работает процедура Дом

Работает процедура Дом

Работает Трава процедуры Пейзаж

Работает пауза 3 секунды

Работает процедура Музыка

Работает процедура Летающая тарелка

Работает процедура Музыка

Работает свет в окне

Скелет нашей программы готов. Теперь можно наращивать его мышцами операторов. Однако, сначала нужно в программе правильно использовать переменные величины.

2.7.4 Зачем переменные вместо чисел

В 4.11 я учил вас использовать в программе не числа, а переменные величины. Однако, впоследствие при написании простеньких программ сам же этому принципу не следовал, чтобы не отвлекать ваше внимание на запоминание имен переменных. Теперь пришла пора показать, почему же все-таки полезно вместо чисел употреблять переменные.

Вот программа для задания 3 из 9.7 выше для бесконечного движения окружности влево-вправо. В ней этот принцип пока не соблюдается.

USES Graph;

VAR x, Device, Mode :Integer;

BEGIN

Device:=0;

InitGraph(Device, Mode, '<путь к графическим драйверам>');

ReadLn;

repeat {Внешний цикл для бесконечности отскоков}

{ Движение направо:}

x:=40; {Начинаем перемещение из левой части экрана}

repeat {Вложенный цикл для движения направо}

SetColor(White);

Circle(x,100,10); {Рисуем белую окружность}

SetColor(Black);

Circle(x,100,10); {Рисуем черную окружность}

x:=x+2 {Перемещаемся немного направо}

until x>600; {пока не упремся в правый край экрана}

{ Движение налево:}

x:=600; {Начинаем перемещение из правой части экрана }

repeat {Вложенный цикл для движения налево}

SetColor(White);

Circle(x,100,10); {Рисуем белую окружность}

SetColor(Black);

Circle(x,100,10); {Рисуем черную окружность}

x:=x-2 {Перемещаемся немного налево}

until x<40 {пока не упремся в левый край экрана}

until 8>9 {Невыполнимое условие, чтобы цикл выполнялся бесконечно}

END.

Предположим, мы хотим, чтобы шарик летал в три раза быстрее. Для этого нам достаточно в двух местах программы вместо 2 написать 6. Вот то-то и неудобно, что в двух, а не в одном. Слишком много труда. В нашей программе это, конечно, пустяк, а вот в больших и сложных программах одна и та же величина может встречаться десятки раз, и чтобы ее изменить, придется вносить десятки исправлений.

Теперь напишем вариант той же программы, но с использованием переменных величин:

USES Graph;

VAR x, Device, Mode, lev, prav, shag : Integer;

BEGIN

Device:=0;

InitGraph(Device, Mode, '<путь к графическим драйверам>');

ReadLn;

lev:=40; prav:=600; shag:=2;

repeat

x:=lev;

repeat

SetColor(White);

Circle(x,100,10);

SetColor(Black);

Circle(x,100,10);

x:=x+shag

until x>prav;

x:=prav;

repeat

SetColor(White);

Circle(x,100,10);

SetColor(Black);

Circle(x,100,10);

x:=x-shag

until x<lev

until 8>9

END.

Теперь для того, чтобы изменить скорость шарика, достаточно заменить 2 на 6 только в одном месте.

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

2.7.5 Записываем программу целиком

Пока у вас на экране - правильно работающий «скелет» программы. Наша задача - постепенно наполнить этот скелет мышцами.

Ниже вы можете посмотреть готовую программу мультфильма. А сейчас я поясню порядок ее написания, отладки и отдельные трудные места.

При работе на компьютере ни в коем случае не вводите сразу всю программу из сотни строк, чтобы потом, запустив ее, не схватиться за голову! Почему? Потому что профессиональный программист в среднем допускает одну описку или ошибку в 10 строках. Значит, в вашей программе будет порядка 10 опечаток или ошибок. Все 10 сразу вы не найдете и за сутки. Потому что сразу 10 ошибок искать в 100 раз труднее, чем 10 раз по одной. Хорошо, если вам одновременно врет только один человек. А если вам в уши одновременно врут 10 человек, и все по-разному?

Поэтому, следуя не спеша за материалом этого параграфа, действуйте в таком порядке.

Прочтите часть материала, посвященную горизонту (она чуть ниже). Введите в программу строки, необходимые для рисования горизонта: Прежде всего в раздел VAR нужно добавить описание y_goriz. Затем введите строку y_goriz:=240. Затем строку Line (0, y_goriz, 640, y_goriz). Запустите программу. Если горизонт на месте и все в порядке, сверьтесь с текстом программы в учебнике и сотрите репортаж горизонта о своей работе.

Все. С горизонтом разделались. Что дальше должно рисоваться на экране? Синева. Введите пару строк про синеву. Запустите программу. Все в порядке, сверьтесь с текстом. Сотрите репортаж синевы.

И так далее. Вводите за один раз не больше одной-двух строк, после чего запускайте программу и смотрите, как она работает.

Старайтесь не списывать с учебника, а придумывайте программу сами, с учебником только сверяясь.

А теперь приступим к объяснениям в самой программе.

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

Пусть горизонт делит экран пополам. Тогда подойдет оператор Line(0,240,640,240). Посмотрим, какие числа здесь целесообразно заменить переменными величинами. Числа 0 и 640 нам менять не понадобится, а вот высоту горизонта мы вполне можем захотеть изменить. Придумаем переменную величину y_goriz и поставим ее вместо числа 240. У нас вместо одного оператора получится пара:

y_goriz:=240;

Line (0, y_goriz, 640, y_goriz)

Оператор y_goriz:=240 я помещу в начало раздела операторов, так как значение y_goriz понадобится и части Звезды и процедуре Летающая тарелка и мало ли кому еще может понадобиться.

Части Синева, Луна, Звезды понятны без пояснений. Попробуем теперь сделать процедуру Дерево. Начнем с того дерева, что в левом нижнем углу:

PROCEDURE Tree;

BEGIN

SetColor(White);

{Рисуем крону:}

Ellipse (100,400,0,360,15,30);

SetFillStyle(1,LightGreen);

FloodFill(100,400,White);

{Рисуем ствол:}

Rectangle (97,430,103,460);

SetFillStyle(1,Brown);

FloodFill(100,440,White);

END;

Сделаем переменными все величины, от которых зависит местоположение дерева, а величины, от которых зависят форма и размеры, для простоты трогать не будем. Будем считать “координатами дерева” координаты центра эллипса, образующего крону. Придумаем им имена x_tree и y_tree и от них будем отсчитывать все остальные координаты дерева. Тогда процедура будет выглядеть так:

PROCEDURE Tree;

BEGIN

SetColor(White);

{Рисуем крону:}

Ellipse ( x_tree, y_tree, 0, 360,15,30);

SetFillStyle(1,LightGreen);

FloodFill(x_tree, y_tree, White);

{Рисуем ствол:}

Rectangle (x_tree - 3, y_tree + 30, x_tree + 3, y_tree + 60);

SetFillStyle(1,Brown);

FloodFill (x_tree, y_tree + 40, White);

END;

Теперь для того, чтобы дерево было нарисовано в нужном месте, нужно перед выполнением процедуры Tree присвоить координатам дерева нужные значения: x_tree := 100, y_tree:= 400. В программе процедура выполняется три раза, причем каждый раз перед ее выполнением координатам дерева присваиваются разные значения.

Аналогично составляем процедуру Дом. Сначала напишем ее без переменных:

PROCEDURE House;

BEGIN

SetColor(White);

{Рисуем стену:}

Rectangle (300,400,340,440);

SetFillStyle(1,LightBlue);

FloodFill (301,401,White);

{Рисуем окно:}

Rectangle (315,410,325,420);

SetFillStyle(1,DarkGray);

FloodFill (320,415, White);

{Рисуем крышу:}

Line(295,400,345,400);

Line(295,400,320,370);

Line(345,400,320,370);

SetFillStyle(1,Red);

FloodFill (320,399, White);

END;

Выберем левый верхний угол стены точкой начала отсчета. Ее координаты x_house:=300; y_house:=400. Окончательный вид процедуры House вы можете видеть в программе.

Вот полный текст программы:

USES Graph,CRT;

VAR Device, Mode, i : Integer;

y_goriz, x_tree, y_tree, x_house, y_house,

x_tar, y_tar, shirina_tar, visota_tar : Integer;

PROCEDURE Tree;

BEGIN

SetColor(White);

{Рисуем крону:}

Ellipse ( x_tree, y_tree, 0, 360, 15, 30);

SetFillStyle(1,LightGreen);

FloodFill(x_tree, y_tree, White);

{Рисуем ствол:}

Rectangle (x_tree - 3, y_tree + 30, x_tree + 3, y_tree + 60);

SetFillStyle(1,Brown);

FloodFill (x_tree, y_tree + 40, White);

END;

PROCEDURE House;

BEGIN

SetColor(White);

{Рисуем стену:}

Rectangle (x_house, y_house, x_house+40, y_house+40);

SetFillStyle(1,LightBlue);

FloodFill (x_house+1, y_house+1, White);

{Рисуем окно:}

Rectangle (x_house+15, y_house+10, x_house+25, y_house+20);

SetFillStyle(1,DarkGray);

FloodFill (x_house+20, y_house+15, White);

{Рисуем крышу:}

Line(x_house-5, y_house, x_house+45, y_house);

Line(x_house-5, y_house, x_house+20, y_house-30);

Line(x_house+45, y_house, x_house+20, y_house-30);

SetFillStyle(1,Red);

FloodFill (x_house+20, y_house-1, White);

END;

PROCEDURE Landscape;

BEGIN

{ горизонт: }

Line(0, y_goriz, 640, y_goriz);

{ синева: }

SetFillStyle(1,Blue);

FloodFill(10,10,White);

{ луна: }

SetColor(Yellow);

Circle(500,100,30);

SetFillStyle(1,Yellow);

FloodFill(500,100,Yellow);

{ звезды: }

for i:=1 to 100 do PutPixel (Random(640),Random(y_goriz),Random(16));

{Три дерева: }

x_tree:=100; y_tree:=400; Tree;

x_tree:=300; y_tree:=300; Tree;

x_tree:=550; y_tree:=380; Tree;

{Два дома: }

x_house:=300; y_house:=400; House;

x_house:=470; y_house:=300; House;

{ трава: }

SetFillStyle(1,Green);

FloodFill(10,470,White);

END;

PROCEDURE Music;

BEGIN

Sound(200);Delay(1000);

Sound(500);Delay(1000);

Sound(300);Delay(1000);

NoSound

END;

PROCEDURE Flying_Saucer;

BEGIN

{Задаем начальные координаты летающей тарелки и ее размеры.

Их не обязательно задавать в начале раздела операторов, так как они

больше никакой процедуре не нужны}

x_tar:=100; y_tar:=40; shirina_tar:=30; visota_tar:=15;

repeat {Цикл движения тарелки }

SetColor(White);

Ellipse (x_tar, y_tar, 0, 360, shirina_tar, visota_tar);

Delay(20); {Чтобы замедлить движение }

SetColor(Blue);

Ellipse (x_tar, y_tar, 0, 360, shirina_tar, visota_tar);

y_tar:=y_tar+1

until y_tar > y_goriz;

{Прорисовываем последний раз тарелку на горизонте: }

SetColor(White);

Ellipse (x_tar, y_tar, 0, 360, shirina_tar, visota_tar);

END;

BEGIN

Device:=0;

InitGraph(Device, Mode, '<путь к граф.драйверам>');

y_goriz:=240;

Landscape; { рисуем пейзаж }

Delay(3000); { пауза три секунды }

Music; { музыка }

Flying_Saucer; { движение тарелки }

Music; { музыка }

SetFillStyle(1,Yellow); { свет в окне }

FloodFill (x_house+20, y_house+15, White); { свет в окне }

ReadLn;

CloseGraph

END.

2.7.6 Порядок описания переменных, процедур и других конструкций Паскаля

Если вы помните (4.6), перед тем, как выполниться, программа на Паскале компилируется на машинный язык. При компиляции она просматривается сверху вниз, при этом Паскаль строго следит, чтобы ни одна переменная, процедура или другая конструкция не была в тексте программы применена выше, чем описана. Что имеется в виду?

У нас переменные описаны в разделе VAR. А под применением переменной будем пока понимать ее упоминание в разделе операторов основной программы или среди операторов в описаниях процедур, то есть там, где эта переменная должна “работать” в процессе выполнения программы.

Посмотрим на нашу программу. Мы мудро поместили раздел VAR на самый верх программы. А если бы мы поместили его, скажем, между описаниями процедур Music и Flying_Saucer, то например, переменная i была бы применена в тексте (в операторе for расположенной выше процедуры Landscape) выше, чем описана, на что Паскаль среагировал бы сообщением об ошибке. То же касается и переменной y_goriz, которая бы в этом случае была применена два раза ниже описания (в операторах repeat и y_goriz:=240), но один раз - выше (в операторе Line(0, y_goriz, 640, y_goriz) ). Не путайте - в данном конкретном случае важен не порядок исполнения операторов в процессе выполнения программы, о котором мы заранее часто и сказать ничего не можем, а примитивный порядок записи описаний и операторов в тексте программы.

Те же рассуждения применимы и к процедурам и другим конструкциям. Так, описание процедуры Tree ни в коем случае нельзя было помещать ниже описания процедуры Landscape, так как в процедуре Landscape процедура Tree применяется, причем три раза.

В некоторых случаях, однако, возникает необходимость, чтобы не только процедура, скажем, P1 обращалась к процедуре P2, но и процедура P2 обращалась к процедуре P1. Очевидно, программа должна была БЫ строиться по такой схеме:

Procedure P2; описание процедуры P2

BEGIN….

P1 ..... применение процедуры P1

END;

Procedure P1; описание процедуры P1

BEGIN .....

P2 ..... применение процедуры P2

END;

begin .....

P1 ..... применение процедуры P1

end.

Но эта схема противоречит упомянутому принципу, так как применение процедуры P1 предшествует ее описанию. В Паскале существует способ справиться с этой ситуацией. Достаточно полный заголовок процедуры P1 скопировать в любое место выше описания процедуры P2, снабдив его так называемой директивой FORWARD. Программа примет такой вид:

Procedure P1; forward; опережающее описание процедуры P1

Procedure P2; описание процедуры P2

BEGIN….

P1 ..... применение процедуры P1

END;

Procedure P1; описание процедуры P1

BEGIN .....

P2 ..... применение процедуры P2

END;

begin .....

P1 ..... применение процедуры P1

end.

2.7.7 Управление компьютером с клавиатуры. Функции ReadKey и KeyPressed

Попробуйте запустить программу, которая долго делает свое дело, не обращая на вас внимания. Например, такую:

BEGIN repeat WriteLn(`А нам все равно!') until 2>3 END.

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

Только когда вы, удерживая нажатой клавише Ctrl, щелкнете по клавише Break, программа прервет свою работу.

Пока программы работают, они не реагируют на клавиатуру, если вы об этом специально не позаботились. А чтобы позаботиться, вы должны включить в них специальные функции ReadKey и KeyPressed из модуля CRT. О смысле функций вообще мы поговорим в 13.2, а сейчас разберем на примерах эти две.

Дополним нашу упрямую программу парой строк:

USES CRT;

BEGIN

repeat

if KeyPressed then WriteLn(`Хозяин нажал клавишу!')

else WriteLn(`А нам все равно!')

until 2>3

END.

Выражение “if KeyPressed then” можно перевести как “если нажата клавиша, то”. Наткнувшись на это выражение, Паскаль проверяет, была ли нажата клавиша на клавиатуре. Когда вы запустите эту программу, она будет бесконечно печатать А нам все равно! Но как только вы щелкнете по какой-нибудь клавише, программа станет бесконечно печатать Хозяин нажал клавишу!

Если функция KeyPressed просто реагирует на то, была ли нажата какая-нибудь клавиша, то функция ReadKey сообщает, какая именно клавиша была нажата.

Вот программа, которая бесконечно печатает текст А нам все равно! и одновременно непрерывно ждет нажатия на клавиши, и как только клавиша нажата, однократно докладывает, была ли нажата клавиша “w” или другая клавиша, после чего продолжает печатать А нам все равно! Если мы захотим, чтобы программа закончила работу, мы должны нажать на клавишу “q”.

USES CRT;

VAR klavisha : Char;

BEGIN

repeat

Delay (1000); {иначе программа печатает слишком быстро}

WriteLn(`А нам все равно!');

if KeyPressed then begin

klavisha:= ReadKey;

if klavisha='w' then WriteLn(`Нажата клавиша w')

else WriteLn(`Нажата другая клавиша')

end {if}

until klavisha='q'

END.

Программа доберется до строки klavisha:= ReadKey только в случае, если будет нажата какая-нибудь клавиша. Функция ReadKey определяет, какой символ был на нажатой клавише, и присваивает его значение переменной, которую мы придумали - klavisha. С этого момента вы можете как хотите анализировать эту переменную и в зависимости от ее значения управлять работой компьютера.

Наша программа будет бесконечно печатать А нам все равно!, а при каждом нажатии на клавишу будет однократно сообщать Нажата клавиша w или Нажата другая клавиша. Почему однократно, а не бесконечно? Грубо это можно объяснить тем, что после выполнения функции ReadKey Паскаль “забывает”, что на клавиатуре была нажата клавиша.

Вы спросите, а зачем здесь вообще нужна строка if KeyPressed then? Дело в том, что если перед выполнением функции ReadKey клавишу на клавиатуре не нажать, то функция ReadKey останавливает программу и заставляет ее ждать нажатия на клавишу, а после нажатия программа продолжает работу. Если вам в вашей программе паузы не нужны, то вам придется использовать KeyPressed.

Функция ReadKey напоминает процедуру ReadLn. Однако у нее есть интересное отличие: при вводе символов по процедуре ReadLn они появляются на экране, а при вводе символа по функции ReadKey - нет. Благодаря этому свойству, с помощью ReadKey можно организовать “секретный ввод” информации в компьютер - человек, стоящий у вас за спиной и видящий экран монитора, но не видящий ваших пальцев, никогда не догадается, на какие клавиши вы нажимаете.

Подробнее о механизме действия ReadKey и KeyPressed см. в следующем параграфе.

Задача “Пароль на программу”.

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

Пусть ваш пароль - typ. Тогда для решения задачи вам достаточно вставить в начало вашей программы следующий фрагмент:

WriteLn(`Введите, пожалуйста, пароль');

Simvol1:= ReadKey;

Simvol2:= ReadKey;

Simvol3:= ReadKey;

if NOT ((Simvol1='t') AND (Simvol2='y') AND (Simvol3='p')) then Halt;

{Продолжение программы}

Вы скажете: Кто угодно перед запуском моей программы посмотрит в ее текст и сразу же увидит пароль. Совершенно верно. Чтобы текст программы не был виден, преобразуйте ее в исполнимый файл с расширением exe (см. часть IV).

Задание 96 “Светофор”: Нарисуйте светофор: прямоугольник и три окружности. При нажатии нужной клавиши светофор должен загораться нужным светом.

Задание 97 “Зенитка”: Вверху справа налево медленно движется вражеский самолет (эллипс). В подходящий момент вы нажатием любой клавиши запускаете снизу вверх зенитный снаряд (другой эллипс).

2.7.8 Буфер клавиатуры

При первом прочтении этот параграф можно пропустить.

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

Чтобы исправить ситуацию, нужно дать компьютеру возможность в случае занятости не игнорировать нажатия на клавиши, а запоминать их, чтобы обработать, как только освободится. Для этого и служит буфер клавиатуры - место в оперативной памяти, в котором и запоминаются эти нажатия. Вы можете, пока компьютер занят, нажать на клавиши до 16 раз - и буфер клавиатуры запомнит все 16 клавиш в том порядке, в котором они нажимались. Вот как можно изобразить процесс ввода в компьютер текста «Привет недоверчивым!», когда процессор занят:

На клавиши пока не нажимали:

Нажали на клавишу П:

Нажали еще на одну клавишу - р:

Нажали еще на несколько клавиш:

Нажали на клавиши в 15-й и 16-й раз:

Нажали на клавишу в 17-й раз - раздается предупреждающий писк компьютера, буква в в буфер не записывается:

Пока мы буфер клавиатуры только заполняли. А кто его опорожнит? Процессор. Процессор, выполняющий программу на Паскале, берет что-то из буфера клавиатуры только в тот момент, когда выполняет процедуру ReadLn, функцию ReadKey и еще кое-что. В остальное время он для буфера клавиатуры занят. Посмотрим, как он берет информацию из буфера, выполняя ReadKey.

Пусть перед выполнением ReadKey в буфере была такая информация:

При выполнении ReadKey первая из введенных в буфер букв - П - отправляется на обработку:

Еще одно выполнение ReadKey:

Помните, что если вы нажали на какую-нибудь клавишу и не отпускаете ее, то это равносильно частому-частому нажатию на эту клавишу. Если процессор в это время не занят выполнением процедуры ReadLn или большого количества функций ReadKey, то некому выуживать информацию из буфера клавиатуры, он мгновенно переполняется и вы слышите раздраженный писк.

На практике события, описанные всеми этими схемами, встречаются редко. Только неопытный пользователь будет жать на клавиши в тот момент, когда компьютер не готов воспринимать информацию. Обычно подавляющую часть времени буфер клавиатуры пуст, ни процессор, ни клавиатура с ним не работают. Раз в вечность человек в нужный момент нажимает на клавишу, в буфере появляется символ и тут же процессор при помощи ReadLn или ReadKey выуживает его оттуда и снова надолго буфер пуст.

Теперь я могу описать правила работы KeyPressed и ReadKey как надо:

Функция KeyPressed отвечает на вопрос, есть ли что-нибудь в буфере клавиатуры. В буфере клавиатуры она никаких изменений не производит.

Функция ReadKey забирает из буфера клавиатуры символ, который попал туда раньше других. Если буфер клавиатуры пуст, то ReadKey останавливает компьютер. Ожидание длится до тех пор, пока в буфере не появится символ (в результате нажатия на клавишу). ReadKey сразу же его оттуда забирает и компьютер продолжает работу.

Теперь вам должно быть понятно, зачем мы в одной из предыдущих циклических программ использовали KeyPressed. Без нее ReadKey просто остановила бы компьютер.

ReadLn при своей работе опустошает буфер клавиатуры.

И еще. Мы знаем, что любая информация в компьютере закодирована (см. 3.5). Поэтому, хоть для простоты я везде говорил, что в буфер попадает символ, правильней было бы сказать, что в буфер попадает код символа.

Как очистить буфер клавиатуры, не останавливая компьютер:

while KeyPressed do kl:=ReadKey

то есть «пока в буфере не пусто, таскай оттуда по символу».

Как ждать нажатия на произвольную клавишу:

repeat until KeyPressed

то есть «повторяй ничегонеделанье, пока не нажмут на клавишу».

Задание 98 “Управляемая точка”: Назначьте четыре клавиши. По нажатии одной из них точка по экрану перемещается на некоторый шаг вверх, другой - вниз, третьей - влево, четвертой - вправо.

В 12.11 вы узнаете, как управлять компьютером при помощи клавиш управления курсором и других.

Задание 99: Добавьте еще пару клавиш - одну для увеличения шага, другую - для уменьшения.

2.7.9 Гетерархия. Задание на игру “Торпедная атака”

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

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

Сейчас я напишу задание на создание программы для игры “Торпедная атака”. А затем предложу схему организации процедур этой программы. В учебных целях я выберу гетерархию, хотя в данном случае можно было бы обойтись и иерархией.

Задание 100: Наверху экрана слева направо плывет вражеский корабль. Внизу притаился ваш торпедный аппарат. В подходящий момент времени вы нажимаете клавишу - и торпеда плывет вверх. Если вы попали, то видна вспышка от взрыва, может быть, на мгновение виден и сам взрыв, раздается коротенькая радостная мелодия, на экране - коротенький поздравительный текст, счетчик подбитых кораблей на экране увеличивается на 1. Если не попали, то зрительные и звуковые эффекты - совсем другие. В любом случае увеличивается на 1 счетчик выпущенных торпед. Когда торпеды у вас кончатся (скажем, их было 10), игра заканчивается. Программа анализирует ваши успехи и в зависимости от них выдает на экран текст, скажем “Мазила!”, если вы не попали ни разу из 10, или “Профессионал!”, если вы попали 8 раз. Затем спрашивает, будете ли вы играть еще.

Схема программы (читайте ее не сверху вниз, а снизу вверх):

Uses CRT,Graph;

VAR все переменные опишем именно здесь, а не внутри процедур опережающие описания процедур

PROCEDURE ZAVERSHENIE_IGRI; Здесь анализируем, насколько успешно стрелял игрок, отмечаем мелодией, цветом и текстом его достижения, затем спрашиваем, будет ли игрок играть еще. Если да, то вызываем процедуру NACHALO, иначе закрываем графический режим и - Halt.

PROCEDURE NE_PORA_LI; Здесь увеличиваем счетчик торпед. Если он>10, то вызываем процедуру ZAVERSHENIE_IGRI, иначе процедуру RISUNOK.

PROCEDURE NEPOPAL; Здесь программируем все эффекты в случае промаха, после чего вызываем процедуру NE_PORA_LI.

PROCEDURE POPAL; Здесь программируем все эффекты в случае попадания, после чего вызываем процедуру NE_PORA_LI.

PROCEDURE ATAKA; Здесь плывут одновременно корабль и торпеда. Затем в зависимости от ситуации вызываются процедуры POPAL или NEPOPAL. Учтите также ситуацию, когда вы просто забыли выстрелить.

PROCEDURE KORABL; Здесь плывет корабль до выстрела, который вызывает процедуру ATAKA.

PROCEDURE RISUNOK; Здесь рисуем береговую линию, указываем на экране имя игрока, счетчики торпед и подбитых кораблей. Затем вызываем процедуру KORABL.

PROCEDURE NACHALO; Здесь устанавливаем в нуль счетчики торпед и подбитых кораблей, спрашиваем имя игрока и делаем все прочее, что нужно делать один раз за всю игру в самом ее начале. Затем прямо из процедуры NACHALO вызываем процедуру RISUNOK.

begin

инициализация графического режима;

DirectVideo:=false; {Чтобы работал WriteLn }

NACHALO {Вот такой короткий раздел операторов.}

end.

Помощь (читайте ее только в крайнем случае). Когда вы выстрелите, вы заметите, что корабль стал плыть медленнее. Это происходит потому, что теперь компьютер за каждый шаг корабля должен еще просчитать и изобразить на экране торпеду, а на это нужно время. Увеличьте шаг движения корабля после выстрела или уменьшите паузу Delay так, чтобы скорость осталась примерно той же.

Как компьютер определит, попал или не попал? Нужно в тот момент, когда торпеда доплывет до линии движения корабля, сравнить горизонтальные координаты корабля и торпеды, и если они достаточно близки, считать, что попал.

Улучшение. Если у всех кораблей будет одинаковая скорость, то попадать будет слишком просто, а значит и играть неинтересно. Сделайте скорость кораблей случайной. Конечно, не совсем уж (скажем, в условных единицах скорости диапазон от 0 до 10 - это слишком), а в пределах разумного (скажем, от 4 до 8 - это нормально). Причем не нужно менять скорость одного и того же корабля в процессе движения. Пусть она остается постоянной, а то все будет зависеть не от мастерства, а от везения. Различаются скорости только разных кораблей.

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

Еще одно задание 101: «Графический редактор». Создайте программу, которая бы, повинуясь нажатию разных клавиш клавиатуры, рисовала бы, расширяла, сжимала, перемещала по экрану, заливала разными цветами прямоугольники (а если вам понравилось, то и эллипсы и линии и прочее). В качестве «печки, от которой танцевать», можете взять решение задания 98.

Мы с вами закончили первый из двух циклов знакомства с Паскалем. Если вам удались «Торпедная атака» или «Графический редактор» и они у вас работают не хуже, чем указано в задании, то у вас должна появиться уверенность, что теперь, умело разбивая программы на небольшие процедуры, вы можете создавать программы любой сложности, а значит цель этого цикла достигнута. Я вас поздравляю - вам присваивается звание “Программист-любитель III ранга”!

Часть III. Программирование на Паскале - второй уровень

Если вам кажется, что вы уже все можете, то вы правы и неправы. Правы потому, что вы можете написать сколь угодно большую программу, разбив ее на разумное число процедур. Неправы потому, что ваша способность манипулировать данными в памяти компьютера еще очень ограничена. А без нее вам не поддадутся «умные» задачи. Например, не познакомившись с так называемыми массивами, вы не сможете запрограммировать игру в крестики-нолики или решить задачу о выходе из лабиринта; не освоив работу со строками, символами и файлами, вы не сможете решить задачу о мало-мальски серьезной секретной шифровке и расшифровке сообщений.

Эта часть посвящена тому, чтобы

Расширить ваши знания о возможностях Паскаля

Сделать ваши знания о Паскале строгими, иначе вы не сможете исправлять в программах грамматические ошибки, а значит программы у вас работать не будут.

Начнем с наведения порядка в наших знаниях о Паскале.

3.1 Алфавит и ключевые слова Паскаля

3.1.1 Алфавит

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

В Паскале тоже есть свой алфавит - четкий набор символов, которые вы имеете право употреблять в программе. Ни одного другого символа употреблять нельзя.

Вот алфавит Паскаля:

Латинские заглавные (прописные) буквы: A, B, C, D,......., Z.

Латинские малые (строчные) буквы: a, b, c, d,......., z.

Десять цифр: 0,1,2,3,4,5,6,7,8,9.

Символы подчеркивания “_” и пробела “ “.

Специальные символы: + - * / = < > ( ) [ ] { } . , : ; ' ^ @ $ #

В определенных местах программы можно употреблять и все остальные символы, в том числе и русские буквы. Поясню, о каких символах и о каких местах идет речь. Вы знаете (3.5), что для кодирования одного символа в компьютере используется один байт. Ввиду того, что байт состоит из 8 битов, им можно закодировать 256 символов. Все они приведены в так называемой таблице ASCII (в 12.11вам будет предложено распечатать эту таблицу). Большинство из них и имеется в виду. Употреблять их можно только в двух местах:

В символьных и строковых константах, например, Slovo:='Чаща'

Внутри комментариев, например, { Вот символы ASCII: % F ! \ Л }

3.1.2 Ключевые слова

Существует несколько десятков слов, некоторым из которых не рекомендуется, а большинству просто запрещено быть именами. Происходит это потому, что Паскаль использует их для более важных дел. Эти запрещенные слова, а заодно уж и нерекомендованные (хоть это и нестрого) мы будем называть ключевыми (их также называют зарезервированными или служебными). Вот ключевые слова языков Borland Pascal 7.0 для DOS и TurboPascal 7.0 (списки ключевых слов других версий Паскаля мало чем отличаются от приведенного):

absolute

AND

array

asm

assembler

begin

case

const

constructor

destructor

div

do

downto

else

end

export

exports

external

far

file

for

forward

function

goto

if

implementation

in

index

inherited

inline

interface

interrupt

label

library

mod

near

nil

not

object

of

or

packed

private

procedure

program

public

record

repeat

resident

set

shl

shr

string

then

to

type

unit

until

uses

var

virtual

while

with

xor

Таким образом, если вы ненароком придумаете своей переменной имя asm, Паскаль укажет вам на ошибку.

3.1.3 Использование пробела

Пробелы запрещены внутри имен и ключевых слов.

Пробелы обязательны между именами и ключевыми словами (если они находятся в одной строке).

В остальных случаях пробелы несущественны и могут ставиться произвольно.

Там, где допускается один пробел, допускается и сколько угодно.

Вместо нажатия на клавишу пробела можно нажимать на клавишу ввода.

3.2 Работа с разными типами данных Паскаля

3.2.1 Список типов

Каждая переменная величина в Паскале должна принадлежать какому-нибудь типу: Integer, Char, String и т.п. Вот список практически всех типов, многие из которых нам еще предстоит пройти. Здесь не учтены только так называемые процедурные типы, которые в этой книге освещаться не будут.

Простые типы

Числовые типы

Целочисленные типы

Byte

ShortInt

Word

Integer

LongInt

Вещественные типы

Real

Single (при наличии или эмуляции матем. сопроцессора)

Double (при наличии или эмуляции матем. сопроцессора)

Extended (при наличии или эмуляции матем. сопроцессора)

Comp (при наличии или эмуляции матем. сопроцессора)

Символьный тип

Char

Логический тип

Boolean

Перечислимый тип

Ограниченный тип (диапазон)

Сложные (структурированные) типы (строятся из простых):

Массивы array

Записи record

Множества set

Строки String

Файлы

Текстовые файлы

Text

Типизированные файлы

File of …

Бестиповые файлы

File

Объекты Object

Ссылки:

Ссылки

Адресный тип

Pointer

Комментарии к списку типов

Переменная простого типа в каждый момент времени имеет своим значением что-то одно: одно число или один символ и т.п.

Переменная сложного типа состоит из многих элементов, каждый из которых принадлежит простому или сложному типу. Элемент сложного типа в свою очередь раскладывается на другие элементы и так далее. Разложив все до конца, мы получим, что переменная сложного типа состоит из элементов простых типов.

Аналогия: Простой тип. Вы хотите купить продукты. Вы идете по улице и видите дверь с надписью «Лавка». Вы открываете дверь и видите, что там продаются, например, баранки.

Структурированный тип. Вы хотите купить продукты. Вы видите дверь с надписью «Супермаркет». Вы открываете дверь и видите, что там продается множество разных продуктов.

Ссылки. Вы хотите купить продукты. Вы видите дверь с надписью «Адресное бюро». Вы открываете дверь, но внутри никаких продуктов нет. Вместо них вам дают адрес лавки или супермаркета.

3.2.2 Числовые типы

Целочисленные типы позволяют переменной принимать значения целых чисел согласно следующей таблице:

Тип

Диапазон значений

Сколько байтов занимает одно значение

Byte

0..255

1

ShortInt

-128..127

1

Word

0..65535

2

Integer

-32768..32767

2

LongInt

-2147483648..2147483647

4

Зачем нужны Byte и ShortInt, если есть Integer? Они занимают меньше места в памяти. Если, например, ваша переменная по смыслу задачи обозначает минуты (то есть целое число в диапазоне от 0 до 60), то полный смысл придать ей тип Byte.

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

Тип

Примерный диапазон значений

Точность

(значащих цифр)

Сколько байтов занимает одно значение

Real

2.910-39 - 1.71038

11-12

6

Single

1.510-45 - 3.41038

7-8

4

Double

510-324 - 1.710308

15-16

8

Extended

3.410-4932 - 1.1104932

19-20

10

Comp Тип Comp, несмотря на то, что является вещественным, принимает значения только целых чисел.

примерно от -1019 до 1019

8

Типы Single, Double, Extended и Comp могут потребовать для своей работы некоторой настройки Паскаля.

Следует помнить, что дробные числа (например, 1/3) компьютер хранит примерно в таком виде: 0,3333333333333. Вы знаете, что такое представление дробных чисел приблизительно. Чтобы точно представить 1/3, компьютеру понадобилось бы бесконечное количество троек, но память компьютера ограничена. Ячейка под переменную типа Real позволяет хранить всего 11-12 таких троек. Эту приблизительность нужно иметь в виду, когда вы многократно выполняете арифметические действия над переменными вещественных типов. При определенном сочетании чисел и действий вы можете немедленно получить совершенно неправильный результат. Попробуйте, например, выполнить такую программу:

VAR a,b,y : Real;

BEGIN

a:=55555555555.1; b:=55555555555.0;

y:=a-b;

WriteLn (y :30:3)

END.

Вы обнаружите, что вместо результата 0.100 компьютер выдает результат 0.125.

3.2.3 Массивы

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

3.2.3.1 Переменные с индексами

В математике широко применяются так называемые индексированные переменные. На бумаге они записываются так:

x1 x2 b8 yi yi-6 zij zi+1j

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

X[1] X[2] B[8] Y[i] Y[i-6] Z[i,j] Z[i+1,j]

Зачем нужны индексированные переменные? Их удобно применять хотя бы при операциях над числовыми рядами. Числовой ряд - это просто несколько чисел, выстроенных по порядку одно за другим. Чисел в ряду может быть много и даже бесконечно много.

Возьмем, например, бесконечный ряд чисел Фибоначчи: 1 1 2 3 5 8 13 21 34..... Попробуйте догадаться, по какому закону образуются эти числа. Если вы сами не догадались, то я подскажу: каждое из чисел, начиная с третьего, является суммой двух предыдущих. А теперь попробуем записать это утверждение с помощью языка математики. Для этого обозначим каждое из чисел Фибоначчи индексированной переменной таким образом:

Первое число Фибоначчи обозначим так: f[1],

Второе число Фибоначчи обозначим так: f[2] и т.д.

Тогда можно записать, что f[1]=1 f[2]=1 f[3]=2 f[4]=3 f[5]=5 f[6]=8 ......

Очевидно, что f[3]=f[1]+f[2],

f[4]=f[2]+f[3],

f[5]=f[3]+f[4] и т.д.

Как математически одной формулой записать тот факт, что каждое из чисел является суммой двух предыдущих? Математики в индексном виде это записывают так:

f[i]=f[i-2]+f[i-1].

Для иллюстрации подставим вместо i любое число, например, 6. Тогда получится:

f[6]=f[6-2]+f[6-1] или

f[6]=f[4]+f[5].

Задание 102: Запишите в индексном виде, как получается из предыдущего числа ряда последующее:

14 18 22 26 .....

6 12 24 48 ....

3 5 9 17 33 65 ....

Вот еще примеры, когда математики предпочитают использовать индексы. Пусть мы на протяжении года каждый день раз в сутки измеряли температуру за окном Тогда вполне естественно обозначить через t[1] температуру первого дня года, t[2] - второго,....., t[365] - последнего. Пусть 35 спортсменов прыгали в высоту. Тогда через h[1] можно обозначить высоту, взятую первым прыгуном, h[2] - вторым и т.д.

3.2.3.2 Одномерные массивы

Одна из типичных задач программирования формулируется примерно так. Имеется большое количество данных, например, тех же температур или высот. С этими данными компьютер должен что-нибудь сделать, например, вычислить среднегодовую температуру, количество морозных дней, максимальную взятую высоту и т.п. Раньше мы вычисляли подобные вещи, и данные вводили в компьютер с клавиатуры одно за другим в одну и ту же ячейку памяти (см. 7.7). Однако, программистская практика показывает, что удобно, а часто и необходимо иметь данные в оперативной памяти сразу все, а не по очереди. Тогда для задачи про температуру нам понадобится 365 ячеек. Эти 365 ячеек мы и назовем массивом. Итак, массивом можно назвать ряд ячеек памяти, отведенных для хранения значений индексированной переменной. Вопрос о том, как большое количество значений оказывается в памяти, отложим на будущее (15.1).

Рассмотрим на простом примере, как Паскаль управляется с массивами. Предположим, в зоопарке живут три удава. Известна длина каждого удава в сантиметрах (500, 400 и 600). Какая длина получится у трех удавов, вытянутых в линию?

Обозначим длину первого удава - dlina[1], второго - dlina[2], третьего - dlina[3]. Прикажем Паскалю отвести под эту индексированную переменную массив:

VAR dlina : array [1..3] of Integer

Здесь array означает массив или ряд, 1 - первое значение индекса, 3 - последнее. Две точки обозначают диапазон от 1 до 3 (см. 5.7) В целом эту строку можно перевести так: Отвести в памяти под переменную dlina ряд ячеек типа Integer, пронумерованных от 1 до 3.

Вот программа полностью:

VAR dlina :array [1..3] of Integer;

summa :Integer;

BEGIN

dlina[1]:=500;

dlina[2]:=400;

dlina[3]:=600;

{В этот момент в трех ячейках памяти уже находятся числа


Подобные документы

  • Развертывание системы на жестком диске, диалоговая система программирования Турбо Паскаль, запуск программы и выполнение задания. Функциональные клавиши и их назначение. Текстовый редактор, средства создания и редактирования текстов программ, курсор.

    реферат [18,6 K], добавлен 01.04.2010

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

    лекция [55,7 K], добавлен 21.05.2009

  • Особенности использования графического режима в среде Турбо Паскаль. Типы драйверов. Инициализация графики. Построение изображения на экране. Графические примитивы и работа с текстом. Разработка и реализация программ в среде Турбо Паскаль "Графика".

    курсовая работа [1,2 M], добавлен 26.09.2014

  • Особенности программирования на языке Паскаль в среде Турбо Паскаль. Линейные алгоритмы, процедуры и функции. Структура данных: массивы, строки, записи. Модульное программирование, прямая и косвенная рекурсия. Бинарный поиск, организация списков.

    отчет по практике [913,8 K], добавлен 21.07.2012

  • Язык программирования Турбо Паскаль. Запись алгоритма на языке программирования и отладка программы. Правила записи арифметических выражений. Стандартное расширение имени файла, созданного системным редактором. Составной оператор и вложенные условия.

    курсовая работа [75,0 K], добавлен 21.03.2013

  • Использование графических возможностей Турбо Паскаля, подключение графического модуля Graph. Графические функции и процедуры. Общая структура графической программы. Построение фигур, определение цветов и стилей, работа с текстом, сообщения об ошибках.

    реферат [109,3 K], добавлен 28.04.2010

  • Правила описания множественных типов данных, приемов использования множеств и операций над множествами в Паскаль-программах. Разработка в Турбо Паскале программы вывода всех согласных букв, которые входят хотя бы в одно слово заданного предложения.

    контрольная работа [30,8 K], добавлен 25.12.2010

  • Освоение технологии структурного программирования и применения стандартных методов работы с одномерными массивами при разработке и создании программы на языке Турбо Паскаль. Разработка программы методом пошаговой детализации с помощью псевдокода.

    реферат [276,9 K], добавлен 27.02.2008

  • Разработка программы, создающей и управляющей базой данных, ее реализация на языке Turbo Pascal. Организация алгоритма программы. Вывод информации и возможность добавления информации в базу данных. Поиск информации в базе данных по заданному значению.

    курсовая работа [26,7 K], добавлен 19.06.2010

  • Расчет на устойчивость в системе программирования Турбо Паскаль. Определение критического напряжения стержня по формуле Ясинского, предельной гибкости в зависимости от материала. Программирование алгоритма расчета. Порядок ввода исходных данных.

    курсовая работа [1,0 M], добавлен 27.04.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.