Глава 2. Знакомство с языком Турбо Паскаля
- 2.1 Ваша первая программа
- 2.2 Типы данных
- 2.3 Преобразования типов и действия над ними
- 2.4 Операторы языка
- 2.5 Массивы
- 2.6 Процедуры и функции
- 2.7 Примеры программ
Примеры программ
Мы познакомились с основными возможностями языка Турбо Паскаль. Как видите, ядро языка очень компактно и отличается простотой - именно в этом состоит главная заслуга автора Паскаля Н.Вирта: язык, придуманный им, прост и естественен, он легко осваивается, на нем не трудно писать самые разнообразные программы. Конечно, рассмотрены далеко не все свойства Турбо Паскаля, ведь его главная отличительная черта - это богатство типов данных. Однако уже рассмотренного вполне достаточно для написания многих полезных программ.
Приводимые ниже программы относительно сложны, поэтому они реализуются поэтапно, по методу нисходящего программирования. Мне кажется, что тем читателям, кто не имеет большого опыта в программировании или кто захочет подробнее ознакомиться с нисходящим программированием, изучение этой главы принесет определенную пользу. Если Вам будет скучно разбираться в «кухне» программирования, но Вас заинтересуют описываемые здесь программы и Вы захотите их повторить, то в прил.5 Вы найдете полный текст соответствующей программы; однако в каждой из них используются некоторые дополнительные возможности языка Турбо Паскаль, которые не рассматривались ранее и которые обсуждаются в пропущенных Вами фрагментах книги.
При оформлении программ я стремился использовать хороший стиль написания программ, т.е. такую их форму, которая дает наиболее полное представление о структуре программы в целом и ее отдельных частей. Не существует какого-либо стандарта, определяющего хороший стиль программы. Обычно это интуитивное понятие включает способ расположения операторов и описаний по строкам (не рекомендуется размещать более одного оператора на каждой строке), а также выделение отступами тела составных и условных операторов. Последнее особенно важно в программах Турбо Паскаля: сплошь и рядом в них встречаются операторные скобки begin... end, причем часто вложенные друг в друга; использование отступа служит дополнительным средством проверки правильности их расстановки - не случайно в редакторе среды предусмотрена соответствующая опция. Принятый мною стиль оформления программ не претендует на эталон, просто мне кажется, что таким образом оформленные программы читаются лучше. Если Вы всерьез намерены программировать на Турбо Паскале, имеет смысл составить собственное представление о хорошем стиле и далее неукоснительно придерживаться его - очень скоро некоторые дополнительные издержки на подготовку программ с лихвой окупятся их «читабельностью», а это поможет Вам вспомнить все детали реализации программы, которая была написана несколько месяцев тому назад.
2.7.1. Вычисление дня недели
Случалось ли Вам мучительно вспоминать, какой именно день недели приходился на то или иное число год или два назад, или вычислять, на какой день недели в этом году приходится Ваш день рождения? Если да, то Вас, думаю, заинтересует простая программа, позволяющая по заданной дате мгновенно вычислить соответствующий день недели. В ее основе лежит такая формула:
день недели = остаток от деления X на 7,
где X = abs(trunc(2.6*m-0.2)+d+y/4+y+c/4-2*c);
m - номер месяца (см. ниже);
d - число (день месяца);
с - номер столетия (см. ниже);
у - номер года в столетии.
При использовании этой формулы следует учесть два обстоятельства. Во-первых, формула верна для григорианского календаря нового стиля (от 1582 до 4903 года). Во-вторых, год и месяц следует предварительно преобразовать так, как если бы начало года приходилось на 1 марта. Иными словами, март в этой формуле имеет порядковый номер 1, апрель 2, ..., январь 11 и февраль 12, причем январь и февраль следует отнести к предыдущему году. Например, для 1 февраля 1991 года номер месяца должен быть равен 12, а год 1990, в то время как для 31 декабря 1991 года номер месяца - 10, а год - 1991. Результат вычисления дается в виде целого числа в диапазоне от 0 до 6, причем 0 соответствует воскресенью.
Приступим к разработке программы. Прежде всего, предположим, что программа уже создана и Вы осуществляете ее прогон. Какая форма взаимодействия с программой кажется Вам наиболее подходящей? Вряд ли Вас удовлетворит однократное ее исполнение (ввод некоторой даты и вывод на экран соответствующего дня недели). Скорее всего Вы захотите повторить работу программы для нескольких дат, например, поинтересоваться, в какой день недели Вы родились, затем, на какой день недели приходится в этом году Ваш день рождения, дни рождения близких, друзей; может быть, определить, в какой день родились известные Вам исторические деятели, и т.д. Таким образом, в программе следует предусмотреть многократное выполнение действий <ввод даты> - <вычисление дня недели>, причем число циклов вычисления заранее не известно. Сразу же возникает новый вопрос: как сообщить программе, что Вы завершаете работу с ней? Для этого можно условиться, что ввод некоторой заранее обусловленной или недопустимой даты должен интерпретироваться программой, как указание на прекращение работы. С учетом сказанного, напишем такой начальный вариант программы:
var
IsCorrectDate: Boolean; {Признак правильной даты}
d,m,y : Integer; {Вводимая дата - день, месяц и год}
begin
repeat
{Ввести в переменные d, л? и у очередную дату и проверить ее. Если дата правильная, установить IsCorrectDate=True, иначе IsCorrectDate=False}
if IsCorrectDate then
{Вычислить и выдать на экран день недели};
until not IsCorrectDate
end.
Если Вы попытаетесь запустить эту программу на счет, то ее поведение будет зависеть от начального значения переменной IsCorrectDate. Это значение случайно, так как компилятор Турбо Паскаля не проводит начальной инициализации переменных. Скорее всего, тот байт оперативной памяти, в котором она разместится, окажется нулевым, что в Турбо Паскале расценивается как логическое значение FALSE, поэтому с большой вероятностью ничего не произойдет, и программа сразу же завершит свою работу (условие not IsCorrectDate будет выполнено). Если начальное значение IsCorrectDate окажется не нулевым, то цикл REPEAT. . .UNTIL будет выполняться до тех пор, пока Вы не выключите компьютер или не нажмете клавиши Ctrl-Break.
Будем считать, что необходимые действия осуществляются в двух процедурах с именами InputDate (ввод даты) и WriteDay (вычисление и печать дня недели). В процедуру InputDate не нужно ничего передавать из программы, так как в ней самой осуществляются ввод и контроль даты. Поэтому заголовок процедуры может иметь такой вид:
Procedure InputDate(var d,m,y: Integer; var correctly:
Boolean);
Процедура WriteDay, напротив, только получает из программы нужные ей данные и ничего не возвращает в программу, поэтому в ее заголовке параметры описываются без слова VAR:
Procedure WriteDay(d,m,у : Integer);
С учетом этого программу можно уточнить следующим образом:
var
IsCorrectDate: Boolean; {Признак правильной даты}
d,m,y : Integer; {Вводимая дата - день, месяц и год}
{...............................}
Procedure InputDate(var d,m,y : Integer;
var correctly : Boolean);
{Вводит в переменные d, m и у очередную дату и проверяет ее. Если дата правильная, устанавливает correctly=true, иначе correctly=false }
begin {InputDate}
correctly := false
end; {InputDate}
{...............................}
Procedure WriteDay(d,m,у: Integer);
{Вычисляет день недели и выводит его на экран}
begin {WriteDay}
end; {WriteDay}
{..............................}
begin
repeat
InputDate(d,m,y,IsCorrectDate);
if IsCorrectDate then
WriteDay(d,m,y)
until not IsCorrectDate
end.
Теперь можно разработать процедуру INPUTDATE. Ввод даты не вызывает трудностей - стандартные процедуры WRITE и READLN отлично приспособлены для этой цели. Для проверки правильности даты нужно проверить принадлежность месяца диапазону 1...12 и года - диапазону 1582...4903. Кроме того, число не должно выходить из диапазона 1...31. Если Вы не очень настаиваете на более точной проверке числа в зависимости от месяца и года (для февраля), то программная реализация процедуры будет следующей:
Procedure InputDate(var d,m,y : Integer;
var correctly : Boolean);
{Вводит в переменные d, m и у очередную дату и проверяет ее. Если дата правильная, устанавливает correctly=true, иначе correctly=false }
begin {InputDate}
Write('Введите дату в формате ДД ММ ГГ: ');
ReadLn(d,m,y);
correctly := (d>=l)and (d<=31) and (m>=l)
and (m<=12) and (y>=1582) and (y<=4903)
end; {InputDate}
При выполнении этой процедуры ввод, например, трех нулей приведет к присвоению переменной CORRECTLY значения FALSE, что вызовет завершение работы программы.
Теперь разберемся с процедурой WRITEDAY. Получив в параметрах обращения день, месяц и год, она должна:
- преобразовать месяц и год так, как описано выше (год должен начинаться 1 марта);
- вычислить день недели;
- выдать на экран результат.
Первое и второе действия очень просты и легко программируются. Что касается выдачи на экран, то можно потребовать от программы, чтобы эта выдача была не просто числом от 0 до 6, а одной из строк «воскресенье», «понедельник», ..., «суббота». Для этого потребуются дополнительные усилия: нужно сначала создать массив строковых констант с именем, например, DAYS_OF_WEEK (дни_недели), а затем выбрать из этого массива и выдать на экран нужную строку. Создать массив текстовых констант можно с помощью объявления типизированной константы (см. гл. 7):
const
Days_of_week: array [0..6] of String [11] =
('воскресенье','понедельник','вторник', 'среда','четверг','пятница','суббота');
В этом объявлении идентификатор Days_of_week описывается в разделе констант, однако справа от него указан тип данных (массив строк), как если бы описывалась переменная, а уже только после типа стоит знак равенства и заключенный в круглые скобки список элементов массива. В результате получим следующую процедуру:
Procedure WriteDay(d,m,y : Integer);
const
Days_of_week: array [0..6] of String [11] =
('воскресенье','понедельник','вторник', ' среда', ' четверг', ' пятница', ' суббота.') ;
var
с, w :Integer;
begin
if m <3 then
begin {Месяц январь или февраль}
m := m + 10;
у := у - 1
end
else
m : = m - 2; {Остальные месяцы}
с := у div 100; {Вычисляем столетие}
у := у mod 100; {Находим год в столетии}
w := abs(trunc(2.6*m-0.2)+d+y div 4+y+c div 4-2*c) mod 7;
WriteLn(Days_of_week[w] )
end;
Важно! Я не в коем разе не претендую на звание учителя по программированию! Я всего лишь хочу помочь вам немного углубить свои знания в данной теме, чтобы впоследствии вы не чувствовали себя "не в своей тарелке" на уроках информатики или в ВУЗе. Только для этого и для данной цели и был создан этот сайт. Все претензии будут проходить мимо, так как я никого не принуждаю учиться именно у меня на сайте.