/
Автор: Рубанцев В. Рубанцев Л.
Теги: алгоритмы информационные технологии языки программирования pascal язык программирования pascal
Год: 2023
Текст
Программирование на языке PascalABC.NET.
Начальный уровень. Часть 1
1
Бесплатное издание
Все права защищены. Никакая часть этой книги не может
быть воспроизведена в любой форме без письменного
разрешения правообладателей.
Автор книги не несёт ответственности за возможный
вред от использования информации, составляющей содержание книги и приложений.
Copyright 2023 Валерий Рубанцев
Лилия Рубанцева
2
От автора
При слове «паскаль» многие вспоминают убитый временем TurboPascal, который
до сих пор изучают в школе, отбивая у школьников всякий интерес к программированию. Есть ещё много других, тоже древних паскалей, но в этой книге мы будем использовать великолепный, мощный, современный паскаль, который называется PascalABC.NET. Название грузное, поскольку синтетическое. В нём есть и
паскаль, и ABC, и .NET. С паскалем понятно – новый паскаль наследует всё лучшее,
что было в паскале его создателя Никлауса Вирта. Буквы АВС указывают на назначение паскаля – это язык для обучения программированию. И наконец, последние буквы подчёркивают связь с платформой .NET. Основной язык этой платформы - Си-шарп, у которого PascalABC.NET взял многое и лучшее. Тут следует добавить, что новый паскаль немало интересного и полезного позаимствовал и у
Питона. В итоге PascalABC.NET превратился в идеальное средство обучения и в
чрезвычайно удобный инструмент для решения разнообразных задач.
Как и в любом другом деле, при изучении паскаля нужна систематическая тренировка, под которой можно понимать решение задач на основные элементы языка
программирования. Это могут быть и формальные упражнения, и занимательные
задачи. Принципиальной разницы между ними нет, за исключением того, что занимательные задачи имеют сюжет, а потому более интересны.
Решая задачи, вы укрепите умения и навыки в применении таких элементов языка
PascalABC.NET, как:
Числовые типы данных – integer, double/real
Логический тип boolean
Логические операции or, and и xor
Арифметические операции
Простейшие математические функции
Переменные и константы, внутриблочные переменные
Операторы объявления, определения и присваивания
Комбинированные операторы присваивания
Логические операторы и выражения
Логические выражения и условные логические операторы if, if – else
Операции ввода и вывода Read(ln), Write(ln).
3
Хотите получить удовольствие и пользу от программирования? – Тогда изучайте
PascalABC.NET!
Книга адресуется: школьникам, изучающим PascalABC.NET на уроках или самостоятельно, учителям информатики и математики, любителям программирования.
Большая часть иллюстраций для книги создана искусственным интеллектом. Всё
остальное сделал автор
Валерий Рубанцев
4
Условные обозначения, принятые в книге:
Дополнение
Указание
Замечание
Исходный код:
## uses Robot;
Task('c1');
// идём вправо 10 шагов:
for var i := 1 to 10 do
Right;
Задание для самостоятельного решения
Заголовок проекта:
Проект Константы
Исходные коды всех проектов находятся в папке _Projects
5
Оглавление
Программирование на языке PascalABC.NET. Начальный
уровень. Часть 1 .................................................... 1
От автора ............................................................... 3
Оглавление ............................................................. 6
Программы, алгоритмы, языки программирования ............... 10
Языки программирования ..................................................................................... 27
Программы и алгоритмы ...................................................................................... 40
Обобщение ................................................................................................................. 43
Знакомство с PascalABC.NET ........................................ 44
Загружаем и устанавливаем PascalABC.NET.................................................... 44
Запускаем PascalABC.NET ..................................................................................... 50
Интегрированная среда разработки PascalABC.NET ...................................... 55
Основные приёмы работы в Редакторе кода ................................................... 76
Обобщение ............................................................................................................... 100
Наша первая программа! ........................................... 101
Структура простой программы .......................................................................... 124
Интеллектуальная подсказка (Intellisense) ................................................... 127
Обобщение ................................................................................................................131
Грамматика паскаля ................................................ 132
Зарезервированные (ключевые) слова ........................................................... 132
Идентификаторы .................................................................................................... 133
Строковые литералы ............................................................................................. 135
Литералы других типов ....................................................................................... 137
Комментарии ........................................................................................................... 139
Выражения .................................................................................................................141
Проект Необычное сложение ............................................................................ 146
6
Именованные константы ...................................................................................... 148
Проект Константы .................................................................................................. 152
Переменные ............................................................................................................ 157
Проект Переменные ............................................................................................. 158
Инструкция присваивания ................................................................................... 160
Обобщение ............................................................................................................... 166
Числовые типы данных ............................................ 168
Таблица <Числовые типы> .................................................................................. 168
Проект Числовые типы ....................................................................................... 169
Целые типы ............................................................................................................. 170
Вещественные (действительные) типы .......................................................... 172
Арифметические операции ................................................................................ 174
Проект Арифметика паскаля ............................................................................. 176
Комбинированные операторы присваивания .................................................181
Таблица <Комбинированные операторы присваивания> ........................... 182
Проект Комбинированная арифметика ........................................................... 183
Преобразования числовых типов ..................................................................... 184
Таблица <Преобразования числовых типов> ................................................ 184
Обобщение ............................................................................................................... 187
Решение арифметических задач и вычисления по формулам . 189
Проект Тест по арифметике .............................................................................. 189
Проект Вычитаем ................................................................................................... 192
Проект Умножаем .................................................................................................. 193
Проект Градусник .................................................................................................. 194
Проект Картинная задача ..................................................................................... 197
Проект Громоздкое выражение ......................................................................... 199
Проект Вспомогательные переменные ......................................................... 200
Вычисления по формулам ................................................................................. 203
Проект Периметр квадрата ................................................................................ 204
Проект Длина окружности ................................................................................. 208
Проект Площадь круга ........................................................................................ 209
7
Проект Площадь прямоугольника ................................................................... 210
Задания для самостоятельного решения ....................................................... 212
Электронный задачник по программированию Programming
Taskbook 4 ........................................................... 214
Набор заданий Begin .............................................................................................. 214
Набор заданий Integer ........................................................................................ 280
Исполнительный Робот ............................................. 319
Исполнители ........................................................................................................... 321
Исполнитель Робот............................................................................................... 322
Дрессируем Робота ............................................................................................... 329
Набор заданий a Исполнитель Робот.............................................................. 337
Исполнитель Черт ёжник ............................................ 343
Набор заданий a Исполнитель Чертёжник .................................................... 344
Логический тип данных ............................................ 362
Логические переменные и операторы .......................................................... 362
Проект Построчно ................................................................................................ 362
Логический тип ..................................................................................................... 366
Проект Логический тип ...................................................................................... 367
Операторы и операции отношения (сравнения) ......................................... 368
Проект Операции отношения ........................................................................... 368
Условные логические операции...................................................................... 373
Проект Логические операции .......................................................................... 373
<Таблица истинности> ......................................................................................... 380
Приоритеты операций ........................................................................................ 380
Таблица <Приоритеты операций> .................................................................... 381
Обобщение .............................................................................................................. 383
Набор заданий Boolean ......................................................................................... 384
Управляющие структуры ........................................... 431
8
Блок-схемы алгоритмов ..................................................................................... 432
Блок инструкций.................................................................................................... 436
Условные операторы if и if-else ...................................................................... 438
Проект Условный оператор if .......................................................................... 446
Вложенные условные операторы .................................................................... 450
Вычисление логических выражений .............................................................. 455
Набор заданий If ................................................................................................... 457
Тернарный условный оператор ?: ................................................................... 489
Оператор множественного выбора case ......................................................... 491
Проект Оператор case ......................................................................................... 493
Набор заданий Case .............................................................................................. 496
Обобщение .............................................................................................................. 525
Литература .......................................................... 527
9
Программы, алгоритмы, языки
программирования
Отыщи всему начало
и ты многое поймёшь.
Козьма Прутков
Современный домашний (или персональный) компьютер оснащён множеством
полезных (и не очень) программ, ярлыки которых украшают Рабочий стол пользователя (Рис. 1).
Рис. 1. Рабочий стол с ярлыками
Здесь найдутся текстовые и графические редакторы, игры, калькулятор, браузеры
для просмотра Интернет-страниц, переводчики, словари и так далее – почти до
бесконечности.
Самая главная программа для наших ПК (то есть персональных компьютеров),
или PC (пи-си, если читать по-английски) – это операционная система Windows
(что в переводе с английского значит окна). В её честь все остальные программы
называют также приложениями для ОС (операционной системы) Windows.
10
Когда вы покупаете компьютер, то обычно получаете его в «готовом» виде, с установленной ОС и некоторыми совершенно необходимыми для работы на компьютере программами – антивирусником и каким-нибудь офисным пакетом. Немало
программ устанавливается на компьютер и с самой ОС. Например, калькулятор и
графический редактор Paint (Рис. 2).
Рис. 2. Джентльменский набор программ
Иногда приходится устанавливать ОС и самостоятельно. Для этого нужно включить компьютер и вставить диск с дистрибутивом ОС в дисковод, после чего
Windows устанавливается хотя и долго, но без вашей помощи.
Но что же управляет компьютером ещё до того, как на нём появилась ОС? Оказывается, на материнской плате компьютера (самая большая и самая важная «пластина», на которой размещается процессор, блоки памяти, разъёмы и многое другое) есть небольшая микросхема с «зашитой» в неё программой, которая срабатывает при включении компьютера, проверяет его работоспособность и запускает
11
ОС. Она называется BIOS (basic input/output system). На Рис. 3 вы найдёте микросхему с этой программой в левом нижнем углу материнской платы.
Итак, когда вы включаете компьютер, начинает работать программа BIOS, которая
контролирует все узлы компьютера. Если он исправен (а если нет, то динамик будет пищать, оповещая вас о поломках), то запустится ОС Windows, и компьютер
будет готов к работе.
Рис. 3. Материнская плата компьютера с микросхемой BIOS
12
Затем вы можете запустить любую программу, которая установлена на вашем
компьютере, дважды кликнув по её ярлыку на Рабочем столе (есть и другие способы, но этот - самый удобный). И сама ОС, и все программы хранятся на жёстких
дисках (винчестерах), CD- и DVD-дисках или на флешках. Но для работы они переносятся в память компьютера – это небольшие платы с микросхемами и множеством контактов (Рис. 4) в нижней части.
Они вставляются в панели с разъёмами и защёлками на материнской плате. Вы
легко найдёте их на Рис. 3⬆ внизу справа.
Рис. 4. Микросхемы памяти
А вы никогда не задумывались над тем, как выглядят программы в памяти компьютера? Примерно так же, как и на диске, поэтому мы легко доберёмся до кода
программы. Вы можете «исследовать» любую программу на вашем диске.
Обычно они имеют расширение exe.
Расширение файла сообщает и нам, и ОС о его назначении. Как мы выяснили, расширение файла exe говорит о том, что это исполняемый файл (программа, приложение). В файловом менеджере и в Проводнике Windows слева от названия файла
присутствует картинка (иконка), закреплённая за этим приложением (Рис. 6). По
этому признаку вы также можете найти исполняемые файлы.
13
Полное имя программы состоит из её названия и расширения, между которыми стоит точка. Для наших экспериментов я приготовил в папке Тест космонавта программу,
написанную на языке Delphi (Рис. 5)
Рис. 5. Имя файла состоит из названия и расширения
Как вы видите, полное имя программы - _tstcosm.exe (в
файловом менеджере или в Проводнике Windows точка не
ставится). В эпоху операционной системы MS-DOS на
название программы отводилось 8 символов, а на расширение – 3. Сейчас таких ограничений нет – вы можете давать
программе имя любой длины. Более того, в названии могут
присутствовать и другие точки, а не только та точка,
которая отделяет расширение программы от её названия.
В этом случае «главной» считается последняя точка, а все
остальные символы после неё - это расширение программы.
Рис. 6. Иконка файла находится слева от его названия
14
Исполняемый файл называют также исполнимым или выполняемым. Расширение exe - это сокращение от английского слова executable — исполнимый.
Этот же значок появляется на Панели задач и на ярлыке программы (Рис. 7).
Рис. 7. Значок приложения в Панели задач Windows и на ярлыке
Если вы дважды кликните мышкой по названию файла _tstcosm.exe, то ОС запустит его, и вы сможете пройти тест (Рис. 8).
Рис. 8. Запущенная программа
15
Никогда не запускайте неизвестные вам программы без их
предварительной проверки на вирусы! Подобное легкомысленное поведение может привести к порче всех программ и
данных на диске и даже к краху самой операционной системы.
В той же папке находится и файл cosmos.BMP. По расширению BMP (или bmp, регистр букв не учитывается) ОС опознаёт точечное (растровое) изображение. Если
вы дважды кликните по названию этого файла, то Windows запустит программу
для просмотра рисунков и сразу же загрузит в неё картинку (Рис. 9). В ней легко
узнать фон программы Тест космонавта. Таким образом, ОС умеет обращаться
с файлами, расширения которых ей известны.
Рис. 9. Картинка загружена в программу для просмотра изображений
16
Однако вернёмся к файлу _tstcosm.exe, который называется исполняемым, или
двоичным. Почему он исполняемый, мы уже разобрались, но вот почему он двоичный?
Давайте откроем файл в каком-либо просмотрщике, например, в программе Lister, которая входит в состав файлового менеджера Total Commander. Из всех режимов нам более всего подходит шестнадцатеричный (Рис. 10).
Рис. 10. Выбираем режим просмотра файла
И вот что мы увидим (Рис. 11).
Рис. 11. Тест космонавта в 16-ричном виде
17
Восьмизначные числа слева показывают номера байтов. После двоеточия следуют сами байты, а уже после них завершают каждую строку символы, которые
соответствуют этим числам (байтам).
Примерно так же устроена и запущенная программа в памяти компьютера. Мы
уже убедились, что Тест космонавта работает правильно, значит, компьютер понимает, что здесь написано. А вот мы вряд ли сможем разобраться в этой хитроумной цифири!
Исполняемые файлы современных программ устроены очень сложно. В них записаны машинные коды, которые исполняет главный процессор компьютера, различная информация (например, мы можем прочитать сообщение This program
must be run under Win32, которая означает, что эта программа может быть запущена только под управлением ОС Windows; понятно, что эта строчка предназначается людям, а не компьютеру), данные и ресурсы – значки, картинки, звуки, музыка. Распоряжается всем этим хозяйством само приложение, а для компьютера
важен именно машинный код, то есть команды, которые выполняет его центральный процессор (ЦП).
Он недаром называется «центральным» - это самая большая микросхема на материнской плате. Обычно ЦП имеет квадратную форму (Рис. 12), так что вы легко
найдёте его на Рис. 3⬆.
Рис. 12. Процессор для современных компьютеров: вид сверху и снизу
18
В нижней части он имеет огромное число ножек, которые вставляются в панель
на материнской плате. Он и выполняет почти всю программу, которая находится
в файле приложения.
Как вы уже знаете, она написана на машинном языке. Все команды обозначаются
в нём двоичными кодами. Такими были и программы для самых первых компьютеров. Естественно, машинный язык очень сложен и непонятен людям, поэтому
писать большие программы на нём совершенно невозможно. Для облегчения
своей жизни программисты придумали язык ассемблера. По сути, это тот же самый машинный язык, но в более понятной для человека форме.
Для разработки программ на языке ассемблера существуют специальные программы, которые также называются ассемблерами. Но нас сейчас больше интересуют дизассемблеры – программы, которые представляют машинный код на
языке ассемблера. Например, вы можете скачать и некоторое время бесплатно
пользоваться дизассемблером PE Explorer. Если вы загрузите исполняемый файл
и дизассемблируете его, то увидите вот такую картину (Рис. 13).
Рис. 13. Машинные коды и соответствующие им команды ассемблера
19
В каждой строке, слева записан адрес команды в памяти компьютера, затем - сама
команда в 16-ричном виде, затем - в некоторых строках находятся метки (например, L00403414:), которые указывают каким-либо командам адреса для перехода, и наконец, - название команды и необходимые ей данные (аргументы).
Вы можете заметить, что команды имеют разную длину (занимают в памяти от
одного до шести байтов). Например, первая команда, с кодом 53 – однобайтовая,
и на языке ассемблера записывается как push ebx. Она означает, что процессор
должен поместить на стек значение из регистра EBX. Команда pop (5A, 5E, 5B) выполняет обратную операцию, команда call (E8…) вызывает подпрограмму по указанному адресу, и так далее. Согласитесь, запомнить названия команд push, pop,
call гораздо проще и пользоваться ими куда удобнее, чем 16-ричными числами.
Особенно, если знать английский язык, на котором эти команды значат: поместить (на стек), извлечь (из стека) и вызвать (подпрограмму).
Программа на языке ассемблера записывается точно так же, как и «человеческие» команды в правой части Рис. 13⬆. Затем программа-ассемблер переводит
их в команды процессора (разные процессоры «говорят» на разных языках, а потому не понимают друг друга), то есть на машинный язык, понятный компьютеру.
Это последовательность 16-ричных чисел, которую мы видим в левой части Рис.
13⬆.
Конечно, процессор не понимает 16-ричных чисел, это
опять же только удобное для нас представление машинных
команд. Мы уже говорили, что исполняемый файл называется также двоичным. Вся память компьютера разбита
на множество (миллионы и миллиарды) отдельных ячеек,
называемых битами (bit). В информатике под битом понимают также минимальное количество информации. Бит
может принимать только два значения – установлен или
20
не установлен (включён-выключен, истина-ложь, есть сигнал-нет сигнала, и так далее). Очень удобно установленное
состояние бита обозначать единицей, а сброшенное – нулём.
Группа из 8 битов образует байт (byte). Два байта (16
бит) – слово (word), 4 байта (32 бита) – двойное слово
(double word) (Рис. 14).
Рис. 14. Представление информации в двоичном виде
Поскольку каждый бит в байте может принимать два состояния, то все 8 битов образуют 28 = 256 комбинаций.
Если состояние каждого бита показывать единицей и нулём,
то мы получим 256 двоичных чисел – от 0000 0000 до
1111 1111 (Рис. 15).
Рис. 15. Двоичные числа от 0 до 255
21
Первое соответствует десятичному числу 0, а последнее –
десятичному числу 255.
Легко заметить, что 4 бита могут давать 16 комбинаций
– от 0000 до 1111, или в десятичном виде – от 0 до 16.
Это значит, что все эти комбинации нулей и единиц можно
записать единственной цифрой в 16-ричной системе счисления.
Итак, в двоичной системе счисления всего две цифры – 0 и
1. В восьмеричной (она также широко используется в информатике) - восемь, в обычной, десятичной системе счисления – 10, а в шестнадцатеричной – 16. Первые 10 цифр
в ней совпадают с десятичными - 0, 1, 2, 3, 4, 5, 6, 7, 8,
9. Не хватает ещё 6 символов для обозначения следующих
цифр в 16-ричной системе. Чтобы не придумывать новых
символов, для их обозначения стали применять начальные
буквы латинского алфавита (безразлично – прописные или
строчные) – A (соответствует десятичному числу 10), B
(11), C (12), D (13), E (14), F (15).
Теперь мы легко запишем любое двоичное число в 16-ричном
виде. Для этого разбиваем его на группы по 4 бита и подставляем нужную 16-ричную цифру.
22
Десятичное число
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Двоичное число
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
16-ричное число
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
Так, двоичное число 0000 0000 превратится в 00,
0000 0001 – в 01,
0000 0011 – в 03,
0000 1111 – в 0F,
1110 0111 – в E7.
В распечатке программы на Рис. 13⬆ все числа записаны в
16-ричной форме, но, пользуясь этой таблицей, вы легко
представите их в двоичном виде:
53 0101 0011
56 0101 0110
51 0101 0001
8BD8 1000 1011 1101 1000
23
Дальше вы можете продолжить этот процесс и самостоятельно, но уже сейчас легко заметить, что двоичная запись
чисел длиннее, чем их представление в десятичной или 16ричной системах счисления. А это значит, что для их хранения в памяти компьютера (или на диске) потребуется
больше ячеек памяти. Тогда почему же для хранения и переработки информации в компьютерах используют столь
расточительную двоичную систему счисления? - А объясняется это очень просто – для надёжности. Действительно,
любой бит может быть только в двух состояниях, которые
очень просто различать. Как говорил мудрый Винни, мёд
либо есть, либо его нет. Компьютер без проблем установит, в каком состоянии находится каждый бит в памяти и
не ошибётся при считывании и записи информации в ячейки
памяти. Если бы мы записывали в память десятичные числа,
то каждая ячейка памяти могла бы находиться в 10 разных
состояниях, и распознать их без ошибок было бы уже весьма
трудно. А вот расплачиваться за надёжность приходится
большим числом ячеек памяти.
Цифру 0 и букву О легко перепутать, поэтому программисты часто перечёркивают ноль в записи 16-ричных чисел:
01, 02,…, 0E, 0F,…, F0,…
24
Кстати говоря, раньше для хранения информации (программ и данных) использовали перфокарты и перфоленты.
Они напоминают прокомпостированные билеты. В перфокартах пробиты некоторые цифры, а в перфолентах –
круглые дырочки (Рис. 16).
Рис. 16. Перфокарта (вверху) и перфолента (внизу)
25
По
наличию
или
отсутствию
дырочек
считывающее
устройство компьютера составляло двоичные числа, то
есть машинный код, который затем исполнялся компьютером.
На смену перфокартам и перфолентам пришли огромные
бобины с магнитной лентой, а затем дискеты, CD- и DVDдиски, винчестеры и флешки. Но при этом не изменился сам
принцип кодирования информации двоичными числами. Для
самого же компьютера важна именно последовательность
установленных и неустановленных битов, а не соответствующие им числа, которых он всё равно не понимает.
Таким образом, программа на языке ассемблера и на машинном языке - это одна
и та же программа, только по-разному записанная. Язык ассемблера очень сложен и неудобен при разработке больших программ, поэтому он используется
обычно только для написания небольших частей программы, если требуется,
чтобы код исполнялся максимально быстро. Всю остальную часть программы пишут на языках программирования высокого уровня (ассемблер – это язык программирования низкого уровня).
Довольно близок к ассемблеру язык С (си), который изучают в школе. Он позволяет программисту непосредственно работать с памятью компьютера, что даёт
возможность писать очень быстрые программы. Однако это часто приводит к
порче самой программы, особенно на этапе её разработки и отладки. Такой код
называется небезопасным. Более современные и надёжные языки программирования (мы будем сокращённо называть их ЯП) - Си-шарп (C#), Джава (Java) и паскаль. - дают безопасный код, поскольку предохраняют память компьютера от посягательств программиста. То же самое касается и языка бейсик (в лучших его вариантах). Из этого следует, что изучать программирование следует на безопасных
ЯП, и в первую очередь для этого годится паскаль.
26
Дальше мы будем называть PascalABC.NET просто паскалем, но вы должны помнить, что речь всегда идёт именно
об этой версии, а не о, например, Турбо Паскале.
Языки программирования
Обложка книги Жана Саммета
о языках программирования
В мире существуют сотни языков программирования, которые служат для разработки программ различного назначения – научных, инженерных, коммерческих,
игровых.
Недаром
обложку
книги
Жана
Саммета
Programming
Languages: History and Fundamentals, в которой, как следует
из названия, речь идёт об истории и основах языков программирования, украшает своеобразная вавилонская башня.
27
Небольшую часть этих ЯП вы можете видеть на Рис. 17.
Родственные связи между этими языками образуют настоящий клубок, который трудно распутать!
Рис. 17. Современные языки программирования
Некоторые языки предназначены специально для обучения. Прежде всего это
паскаль (Pascal), созданный в 1969 году Никлаусом Виртом, и бейсик (Basic), разработанный несколькими годами раньше профессорами Дартмутского колледжа
Томасом Куртом и Джоном Кемени.
28
Язык паскаль получил своё название в честь выдающегося французского математика и физика
Блеза Паскаля (1623 – 1662), а
название языка бейсик представляет собой сокращение его английского названия Beginner’s Allpurpose Symbolic Instruction Code
(универсальный код символических инструкций для начинающих) – BASIC. Несколько неуклюжее название языка объясняется желанием авторов придать ему глубокий смысл: поанглийски слово basic значит основной. Поскольку эти языки
программирования действительно являются основными для
многих
любителей
программирования,
то
их названия
стали нарицательными и пишутся с маленькой буквы.
Оба языка до сих пор широко применяются в программировании и имеют множество реализаций для всех операционных систем и процессоров.
Во многих отношениях язык паскаль лучше подходит для изучения программирования, чем бейсик. Его главное преимущество в том, что сложные программы
на этом языке состоят из классов, экземпляры которых (объекты) могут взаимодействовать друг с другом и с окружающей средой. Это значит, что паскаль объектно-ориентированный язык программирования, а бейсик и си - относятся
к процедурным.
Чтобы почувствовать между ними разницу, давайте посмотрим, какие бывают
языки программирования.
29
Всё множество ЯП можно разделить на 4 большие группы - процедурные, объектно-ориентированные, функциональные и логические.
Различные подходы к программированию называют парадигмами – процедурная парадигма, логическая парадигма,
функциональная парадигма и объектно-ориентированная
(объектная) парадигма.
В соответствии с парадигмами
называются и языки программирования. Однако необходимо
учитывать, что некоторые ЯП поддерживают одновременно несколько парадигм. Например, паскаль можно считать не только объектно-ориентированным, но и процедурным, и функциональным языком программирования. Такие ЯП называют мультипарадигменными.
Логическое и функциональное программирование противопоставляют императивному и называют декларативным.
Декларативные ЯП требуют не пошагового описания действий (алгоритма), а указания цели работы программы.
Декларативные ЯП можно считать языками более высокого
уровня, чем императивные. Язык паскаль в значительной
мере является декларативным.
На Рис.18 показано условное деление языков программирования согласно парадигмам.
30
Рис. 18. Языки программирования и парадигмы
Процедурные (императивные) ЯП
Процедурные ЯП возникли вслед за языком ассемблера. Действительно, ассемблер облегчал разработку программ, поскольку в нём использовались словесные команды вместо чисел, которые запомнить трудно, а перепутать легко. Затем ассемблер переводил исходный текст в машинные коды, то есть на язык процессора. Но процессоры в разных компьютерах «говорят» на разных языках и не
понимают другого машинного языка, кроме своего собственного. Это значит, что
программы, написанные для компьютеров с одним процессором, не будут работать на компьютерах с процессором другой марки.
Со временем сложность программ возрастала, так что писать их на языке ассемблера, где каждое действие сопровождалось десятками строк кода, стало просто невозможно. Вот тогда и появились процедурные ЯП – Фортран (Fortran), си
(C), Алгол (Algol), паскаль (Pascal). Программы, написанные на них, не привязаны
31
к определённому процессору, поэтому они универсальные - за перевод исходного кода отвечает программа-транслятор. Она переводит текст на машинный
язык нужного процессора, который, в принципе, может быть любым. Например,
программа на паскале записывается почти по-человечески:
begin
Writeln('Привет, мир!')
end.
В переводе на русский язык она была бы нам ещё понятнее:
начало
Напечатать('Привет, мир!')
конец.
Программы на процедурных языках состоят из команд (инструкций, директив, операторов), которые выполняются
процессором.
Ключевые слова всех языков программирования – это обычные английские слова. Если вы не знаете английского языка,
они вам будут непонятны. Однако в любом ЯП всего несколько десятков
таких слов, поэтому запомнить их не
составит никакого труда. Да и англо-русский словарь всегда должен быть под рукой.
Были попытки перевести ключевые слова на другие языки,
например, на русский и немецкий. Ничего хорошего из этого
не вышло (одна из причин: средняя длина слов (число букв) в
этих языках значительно больше, чем в английском). Более
32
того, английские слова ясно показывают нам, где - ключевые слова, а где – слова и строки на русском языке. Парадокс, но смешанный исходный текст, написанный на двух
языках, читается легче.
Язык программирования Рапира, разработанный в Советском Союзе в 80-е годы прошлого века, был построен на
русском языке. Самую первую программу на Рапире можно
записать так:
Проц Старт()
Вывод 'Здравствуй, мир!'
Кон Проц
Трансляторы бывают двух видов: интерпретаторы и компиляторы.
Интерпретатор последовательно, строчку за строчкой
просматривает исходный текст программы и передаёт
соответствующие команды процессору. Если оператор
языка программирования в какой-нибудь строке исходного
текста выполняется сто раз (а, может быть, и миллион!),
столько же раз интерпретатор будет переводить текст
в команды процессора. Нетрудно догадаться, что программа будет работать медленно. Чтобы ускорить процесс трансляции, иногда весь исходный текст сначала переводят в промежуточный код, который затем интерпретируется значительно быстрее.
33
Например, первые версии бейсика были оснащены интерпретаторами, поэтому скорость работы программ была невысокой. Другой недостаток интерпретатора состоит в
том, что для запуска любой программы необходим весь исходный код, а также сам бейсик-интерпретатор. То есть
сначала нужно запустить бейсик-интерпретатор, затем
загрузить в него исходный текст и только потом выполнить нужную программу. Конечно, это создавало проблемы
для программиста. И поделиться с кем-то своей программой было непросто, ведь другой пользователь также должен
был иметь на своем компьютере бейсик и уметь им пользоваться! Правда, у интерпретатора есть и небольшое
преимущество - написанная программа сразу же, без предварительной обработки начинает исполняться, что очень
важно при отладке.
Компиляторы работают по-другому: они сразу просматривают весь исходный текст и преобразуют его в машинный код, который процессор исполняет очень быстро. Но
вот на компиляцию программы уже нужно некоторое
время, поэтому при отладке придётся ждать, пока будет
скомпилирована вся программа, хотя была изменена, может быть, всего одна буква (современные компиляторы, конечно, «умнее», и не перекомпилируют всю программу целиком). В результате компиляции программист получает
исполняемый файл программы. Его можно запустить, как
34
и любой другой исполняемый файл. Но с приложениями,
написанными на паскале, не всё так просто! Если у вас есть
возможность повторить эту операцию на других компьютерах, то вы увидите, что она будет запускаться не всегда.
Это потому, что компилятор языка паскаль на самом деле
создаёт не двоичный (бинарный) файл, который непосредственно выполняется процессором, а код на промежуточном языке IL, как и все другие компиляторы для платформы
.NET. Например, C# или Visual Basic.
IL
-
это
сокращение
от
MSIL
(Microsoft
Common
Intermediate Language) и CIL (по-английски - Common
Intermediate Language).
Код на языке IL напоминает язык ассемблера, так что писать непосредственно на нём очень сложно. Но его хорошо
понимает виртуальная машина .NET, которая может работать с промежуточным кодом на компьютерах с любой
операционной системой – Windows, Linux или MacOS.
Легко сообразить, что эта программа напечатает на экране строку Привет, мир!
По традиции, принято в первой программе приветствовать весь мир. Традиция похвальная!
И нам совершенно безразлично, на каком компьютере будет работать эта программа – её текст везде одинаков (или почти одинаков). И мы даже не знаем,
какие именно машинные команды необходимы для того, чтобы написать на
экране нужный нам текст. А их потребуется немало!
35
Привет миру на языке IL выглядит совсем не страшно:
IL_0001:
IL_0006:
ldstr
call
"Привет, мир!"
System.Console.WriteLine
Сложная программа на процедурном языке состоит из большого числа команд.
Вот, например, программа на паскале, которая спрашивает имя пользователя, а
затем приветствует его и просит нажать какую-либо клавишу:
begin
Print('Как тебя зовут? - ');
var name := ReadString;
Println('Привет', name, '!');
Println('Нажми клавишу!');
Readln;
end.
Текст программы на паскале намного более понятен, чем на ассемблере, поскольку отсутствуют «мелкие подробности», связанные с машинными кодами.
Здесь мы говорим (приказываем) компьютеру: «сделай то-то и то-то», а не объясняем во всех подробностях его центральному процессору, какие данные и в
какие ячейки памяти он должен поместить и что потом с ними делать. Именно
поэтому машинные языки и язык ассемблера называют ЯП низкого уровня, а процедурные и все прочие ЯП, о которых мы ещё будем говорить, ЯП высокого
уровня.
Мы можем заметить, что в программе на паскале имеются команды Println
(напечатать строку) и ReadString (считать строку), которые вызывают подпрограммы для печати сообщений на экране и приёма текстовых данных (строк) от
пользователя.
Подпрограмма – это часть кода, которая выполняет какие-либо законченные,
определённые действия. Обычно это действия, которые повторяются многократно. В самом деле, зачем писать один и тот же код много раз. Достаточно
оформить его как подпрограмму и просто вызывать в нужном месте основной
программы. Подпрограммы часто используют и для лучшего обзора больших
программ. Тогда часть кода переносят в подпрограммы и вместо огромного
36
числа строк остаются только вызовы подпрограмм. Так и написать, и понять, и
отлаживать программу гораздо удобнее и проще. Подпрограммы называют
также процедурами и функциями. Именно процедуры и дали название этим языкам программирования. Программы на таких ЯП представляют собой набор команд (инструкций) и вызовов процедур (подпрограмм), которые оформляются в
виде отдельных частей программы. Отсюда и название этих ЯП – императивные, то есть командные, повелительные, или процедурные – в их основе лежат
процедуры.
Самые известные процедурные языки программирования:
Ada
Бейсик
Кобол
Модула-2
Паскаль
ПЛ/1
Рапира
PHP
Си
Фортран
Объектно-ориентированные ЯП
Объектно-ориентированные ЯП поддерживают объектно-ориентированную
(объектную) парадигму.
Впервые идея объектно-ориентированного программирования (ООП) была реализована в Симуле-67. Затем она была развита Аланом Кэйем и Дэном Ингаллсом в языке Smalltalk. Сейчас большинство ЯП реализует именно объектно-ориентированную парадигму.
Программы на объектно-ориентированных ЯП состоят из классов, описывающих
объекты (их также называют экземплярами классов), которые взаимодействуют
37
с другими объектами и могут реагировать на различные события. Каждый объект отличается от других объектов того же класса характеристиками (данными),
но все экземпляры одного класса имеют сходное поведение, которое определяется методами. Методы – это подпрограммы, которые обрабатывают данные.
Таким образом, объектно-ориентированное программирование развивает идеи
процедурного программирования - здесь вы найдёте и команды, и подпрограммы, - но главное достоинство ООП в том, что классы объединяют и данные,
и подпрограммы для работы с ними.
На паскале можно писать программы и в процедурном
стиле.
Список объектно-ориентированных языков программирования:
ActionScript
Ada
C#
C++
Delphi
Eiffel
Java
JavaScript
Objective-C
Object Pascal
Perl
PHP
PowerBuilder
Python
Ruby
Scala
Simula
Smalltalk
Visual Basic
38
Логические ЯП
Программы на логических ЯП не описывают пошаговый алгоритм, а представляют собой перечень фактов и правил, которые служат для логического вывода
из них.
Первым языком логического программирования был Planner (Плэнер). Его разработал Карл Хьюит в Лаборатории Искусственного Интеллекта Массачусетского
Технологического Института в 1969 г. Тремя годами позднее появился язык Пролог (Prolog), который до сих пор считается самым известным языком логического
программирования.
Функциональные ЯП
В основе функциональных ЯП лежит λ-исчисление. Работа программы, написанной на функциональном ЯП, сводится к вычислению функций.
Наиболее известные языки функционального программирования:
APL
Clojure
Common Lisp
Erlang
F#
Haskell
LISP
Miranda
Scala
Scheme
На паскале также можно использовать λ-функции, чтобы писать программы в
функциональном стиле.
39
Исторические связи между ЯП
Краткую историю языков программирования можно представить следующей
диаграммой (Рис. 19).
Рис. 19. Генеалогическое древо языков программирования
Год появления ЯП, а также его связи с другими ЯП могут
отличаться в разных источниках, но в целом рисунок даёт
правильное представление о хронологии и генеалогии языков
программирования.
Программы и алгоритмы
Программа – это просто иная форма записи алгоритма на каком-либо языке
программирования. То есть программа – это не любой код, пусть даже и
правильный, с точки зрения транслятора, а только тот, который решает
40
определённую задачу. И решает он её с помощью алгоритма, переведённого на
язык программирования. Таким образом, чтобы написать программу,
недостаточно знать грамматику, орфографию и пунктуацию языка
программирования.
В общем случае под алгоритмом понимают пошаговые инструкции, которые
однозначно определяют содержание и последовательность выполнения
действий для решения конкретной задачи.
Не следует думать, что алгоритмы нужны только в программировании. Люди и
сами ежедневно выполняют какие-либо алгоритмы. Например, при лепке и варке
пельменей вы пользуетесь рецептом, в котором написано: возьми то-то и то-то,
сделай так-то и так-то. Если алгоритм-рецепт хороший, а вы прилежный
исполнитель, то и пельмени выйдут на славу. Но обычно пельмени получаются
комом, поэтому рано или поздно приходится покупать компьютер и жениться.
Множество алгоритмов окружает нас и в школе, и в жизни как таковой: типовые
задачи по химии и физике, умножение и деление столбиком чисел (Рис. 20) и
многочленов (Рис. 21), правила решения квадратных уравнений и написания
сочинений, правила дорожного движения и этикета.
Рис. 20. Программа для умножения и деления столбиком на сайте live.mephist.ru/show/stolbik/
41
Рис. 21. Умножение и деления многочленов
Первые «настоящие» алгоритмы появились задолго до компьютеров, на которых
они сейчас используются. Например, зная язык паскаль, мы легко напишем подпрограмму (функцию), которая вычисляет НОД двух заданных чисел:
function Euklid(n1, n2 : longint): longint;
begin
while n2 <> n1 do
if n1 >= n2 then n1 -= n2
else n2 -= n1;
Result := n1;
end;
Этот алгоритм Евклида называется простым, он годится для маленьких чисел. А
для больших лучше использовать быстрый алгоритм Евклида:
function SpeedEuklid(n1, n2 : longint): longint;
begin
while n2 > 0 do
begin
var n := n1 mod n2;
n1 := n2;
n2 := n;
end;
Result := n1;
end;
Несколько позже появился ещё один замечательный алгоритм, доживший до
наших дней. Его придумал греческий математик Эратосфен. Он служит для
42
отсеивания простых чисел от составных. Его образно называют решетом
Эратосфена.
Таким образом, решение любой задачи состоит из двух основных частей:
1. Построение алгоритма.
2. Перевод его на язык программирования.
Обобщение
В мире существует огромное число языков программирования, которые
условно можно разделить на процедурные (императивные), объектно-ориентированные, логические и функциональные. Некоторые языки программирования можно одновременно отнести к нескольким группам. Их называют мультипарадигменными.
PascalABC.NET – современный, объектно-ориентированный, универсальный
язык программирования, на котором можно писать программы и в процедурном, и в объектном стиле. Лучший выбор для изучения программирования!
43
Знакомство с PascalABC.NET
Лёд тронулся,
господа присяжные заседатели!
Остап Бендер
В качестве языка программирования для этой книги выбран PascalABC.NET, специально созданный российскими разработчиками для обучения школьников и
студентов. Скоро вы и сами убедитесь, что выучить его основы можно за несколько уроков. Но несмотря на свою относительную простоту, PascalABC.NET
позволяет писать и полезные приложения по школьной программе, и занимательные игры с красивой графикой.
Загружаем и устанавливаем PascalABC.NET
Установочный файл системы программирования PascalABC.NET
вы можете скачать с официального сайта программы
pascalabc.net. На главной странице сайта найдите кнопку Скачать
и нажмите её (Рис. 1).
Рис. 1. Главная страница сайта pascalabc.net
44
Вы перейдёте на новую страницу со ссылками на скачивание (Рис. 2).
Рис. 2. Выбираем нужный файл
Здесь нажмите первую кнопку Скачать.
Установочный файл PascalABCNETSetup.exe появится в папке Downloads/Скачать.
Дважды щёлкните по нему мышкой, чтобы запустить установку среды разработки.
В диалоговом окне Установка PascalABC.NET… сбросьте ненужные галочки и
нажмите кнопку Далее > (Рис. 3).
Как обычно, по умолчанию паскаль будет установлен в системной папке, поэтому
снова нажмите кнопку Далее > (Рис. 4).
Вы можете выбрать любую папку для программы, но лучше
оставить папку по умолчанию, чтобы потом не искать её
на диске.
45
Рис. 3. Начинаем
Рис. 4. Без проблем
46
Запомните папку с программой, она вам ещё может пригодиться!
В последнем диалоговом окне просто нажмите кнопку Установить, если вы не хотите изменить место для Рабочей папки (Рис. 5).
Дальше вам будет предложено выбрать Рабочую папку для сохранения ваших
проектов на паскале. По умолчанию она находится в корневом каталоге системного диска С: (Рис. 5), что вполне разумно, если вы работаете на одном компьютере. Если же это не так, то при переходе на другую машину программы будут
недоступны. В этом случае лучше создать Рабочую папку на съёмном диске (или
даже флешке), чтобы использовать программы на любом компьютере.
Рис. 5. Рабочая папка
47
В случае изменения места для рабочей папки просто переустановите систему программирования и укажите новый
путь к Рабочей папке.
В Рабочую папку будут установлены примеры учебных программ в папке Samples.
Если вы хотите самостоятельно создать Рабочую папку, то нажмите кнопку с тремя
точками справа от текстового поля и в диалоговом окне Обзор папок укажите место для Рабочей папки (Рис. 6).
Рис. 6. Выбираем Рабочую папку
Нажмите кнопку Установить.
Процесс установки показывает зелёная полоска (Рис. 7).
48
Рис. 7. PascalABC.NET устанавливается на компьютер
Через несколько минут установка закончится, после чего вам нужно кликнуть по
кнопке Закрыть (Рис. 8).
Рис. 7. Установка паскаля закончена
49
Вы можете открыть установочную папку и запустить файл PascalABCNET.exe, дважды щёлкнув по его значку, но лучше для этого использовать ярлык программы
на Рабочем столе (Рис. 9).
Рис. 9. Ярлык программы
И вот настал торжественный момент: мы дважды кликаем по ярлыку и в первый
раз запускаем среду разработки программ на паскале...
Запускаем PascalABC.NET
Лиха беда - begin!
Программистская пословица
Загрузка программы в память компьютера происходит очень быстро, так что уже
через несколько секунд вы увидите её Главное окно (Рис. 1).
Рис. 1. Главное окно программы PascalABC.NET
50
Самая важное меню в любой новой программе – это, безусловно, Помощь. Раскрыв его, вы увидите список команд (Рис. 2).
Рис. 2. Меню Помощь
Пункт меню О программе (Рис. 3) сообщит вам её текущую версию, установленные компоненты, а также – дополнительно - имена разработчиков и адрес сайта,
который, впрочем, вы и без того хорошо знаете.
Рис. 3. Информация о программе
51
Пункт меню Справка (Рис. 4) откроет окно с разнообразной информацией как по
системе программирования, так и по языку паскаль. Так как эта информация совершенно необходима, то для её вызова достаточно нажать кнопку F1, как это и
принято в большинстве программ.
Рис. 4. Ценная информация
Пункт меню Коротко о главном просто повторяет действие пункта Справка.
Абсолютно незаменим при изучении языка пункт меню Примеры (Рис. 5).
В диалоговом окне Открытие вы найдёте папки с большим числом программ, иллюстрирующих возможности современной версии языка PascalABC.NET. Чтобы
загрузить программу в Редактор кода, выделите её название и нажмите кнопку
Открыть (Рис. 6).
52
Рис. 5. Берём пример
Рис. 6. Выбираем программу
53
И последний пункт меню Помощь – Изучаем PascalABC.NET – перенесёт вас в папку
Samples !Tutorial (Рис. 7) с короткими учебными программами. Они не раз пригодятся вам при изучении языка паскаль!
Рис. 7. Справочник по языку паскаль
И что особенно приятно: все надписи на русском языке!
Следите за выходом новых версий системы PascalABC.NET и своевременно обновляйтесь!
54
Интегрированная среда разработки
PascalABC.NET
Система программирования PascalABC.NET задумывалась и разрабатывается как
средство обучения школьников и студентов современному программированию.
Отсюда естественным образом вытекает простота интерфейса пользователя.
Здесь нет длинного меню, многочисленных окон и кнопок, поэтому освоиться в
среде разработки и начать программировать можно быстро и просто.
Тем не менее я считаю обязательным хотя бы коротко познакомиться с основными элементами среды разработки, чтобы в дальнейшем вы лучше понимали, о
чём идёт речь.
В старом номере журнала Крокодил был забавный анекдот,
в котором подвыпивший водитель ночью сел на заднее сиденье, после чего позвонил в полицию и сообщил, что из его
автомобиля украли руль, педали и приборную доску… Спустя некоторое время он понимает свой промах и пересаживается вперёд.
Так что совсем нелишне прежде чем браться за программирование, разобраться, где у ИСР руль, а где – педали…
PascalABC.NET – это не только язык программирования, но и система программирования, как её называют авторы. Обычно систему программирования принято
называть Интегрированная Среда Разработки программ (ИСР, по-английски, IDE Integrated Development Environment).
Она объединяет в себе:
Текстовый редактор
Отладчик
Компилятор
55
Сразу после запуска системы PascalABC.NET вы увидите
её Главное окно, с которого мы и начнём знакомство со
средой разработки.
Главное окно
Главное окно состоит из нескольких частей. Сверху
находится Заголовок – как и у большинства приложений. В нём можно прочитать название программы –
PascalABC.NET и номер версии (Рис. 1).
Рис. 1. Главное окно PascalABC.NET
Размеры Главного окна можно изменять точно так же, как и других окон, потянув
за одну из четырёх его границ или за точечный треугольник в правом нижнем углу.
Окно можно свернуть, развернуть и закрыть с помощью кнопок в правом верхнем
56
углу. Эти же операции доступны в контекстном меню, которое появляется на
экране, если нажать правую кнопку мышки на значке (иконке) программы
PascalABC.NET (Рис. 2).
Рис. 2. Контекстное меню программы PascalABC.NET
Окно Редактора кода
Большую часть Главного окна занимает окно Редактора кода, в котором вы можете набирать с клавиатуры и редактировать исходный текст программы. Он
представляет собой текстовый редактор с подсветкой синтаксиса (ключевых слов,
идентификаторов, литералов). В него можно загружать отдельные файлы и проекты. Поскольку у нас пока нет собственных файлов, то откройте папку Помощь
Изучаем PascalABC.NET Samples !Tutorial 01_First (Рис. 3) и щёлкните по
строчке HelloWorld. В Редакторе кода появится текст программы (Рис. 4).
Рис. 3. Выбираем программу на паскале
57
Рис. 4. Окно Редактора кода с загруженной программой
Обратите внимание, что выше окна Редактора кода на закладке появилось название загруженной программы – HelloWorld.pas.
Аналогично, то есть точно так же, вы можете открыть в Редакторе кода сколько
угодно других программ. Каждая из них имеет свою вкладку с названием файла
(Рис. 5).
Когда мышка находится ярлыке текущего документа, под
курсором появляется строка с полным путём к файлу на
диске.
Чтобы переключаться между программами, просто нажимайте на нужную
вкладку мышкой. Так вы сможете одновременно работать над несколькими программами или копировать код из одного проекта в другой. Очень удобно!
58
Рис. 5. Файлы и вкладки
Название текущего документа (файла, программы) выделено на ярлыке жирным
шрифтом. Вы всегда работаете с текущим документом: изменяете его, сохраняете
на диске и запускаете на выполнение.
Чтобы изменить порядок вкладок, ухватитесь мышкой за одну из них и перетащите
вправо или влево.
Левее и выше закладок находится кнопка со звёздочкой (Рис. 6).
Рис. 6. Кнопка для добавления нового файла
59
Если вы щёлкнете по ней, то в Редакторе кода будет создана пустая страница для
новой программы с названием по умолчанию – Program и порядковый номер
(Рис. 7).
Рис. 7. Новый файл
Чтобы закрыть вкладку (и всю её страницу), нажмите на ней правую кнопку мышки
и в контекстном меню щёлкните по строчке Закрыть (Рис. 8).
Рис. 8. Закрываем текущий файл
Следующая строчка меню – Закрыть все, кроме текущего – закрывает все открытые
файлы, кроме того, который вы видите в Редакторе кода.
60
Команда для закрытия текущей вкладки продублирована и кнопкой с крестиком
у правого края окна Редактора кода (Рис. 9).
Рис. 9. Кнопка для закрытия текущего файла
И последняя кнопка контекстного меню – Сделать активным – делает окно активным. Слева от его названия появляется жирная точка (Рис. 10).
Рис. 10. Активный файл
Активный файл открывается в окне Редактора кода. Его можно редактировать,
сохранять и запускать.
Чтобы запустить активный файл, нажмите кнопку с зелёной стрелкой (Рис. 11). Когда курсор находится на ней, возникает подсказка Выполнить.
Рис. 11. Запускаем программу
Вы всегда запускаете активную программу, то есть ту,
страница которой открыта в Редакторе кода! Текущая
программа при этом действии становится активной.
61
Панель инструментов
Все кнопки программы PascalABC.NET собраны на Панели инструментов (Рис. 12).
Рис. 12. Панель инструментов
На ней находятся кнопки быстрого доступа, дублирующие команды Главного
меню программы PascalABC.NET.
Если какая-либо кнопка недоступна в данный момент, то
её значок на Панели инструментов становится серым.
Как вы уже знаете, самая первая из них создаёт пустую заготовку для новой программы, а кнопка с зелёной стрелкой запускает активную (текущую) программу.
В следующей таблице перечислены все кнопки на Панели инструментов и кратко
прокомментированы их действия.
62
Синим жирным шрифтом указаны клавиатурные сокращения, соответствующие
этим кнопкам.
Клавиатурные сокращения
Во многих случаях клавиатурные сокращения упрощают и
ускоряют разработку программы, поэтому их нужно постепенно заучивать.
Клавиатурное сокращение может состоять из отдельной
клавиши, которую просто следует нажать, из двух или трёх клавиш. Они должны
63
быть нажаты одновременно. В таблице названия клавиш соединены знаком плюс.
Его, естественно, нажимать не нужно.
Некоторые команды открывают диалоговое окно, в котором необходимо ввести
дополнительную информацию.
64
65
Строка состояния
«Подвал» Главного окна занимает Строка состояния, в которую PascalABC.NET выводит различные сообщения. Например, на Рис. 13 вы видите строку Компиляция
прошла успешно. Она означает, что программа не имеет синтаксических ошибок
и состоит из 4 строк.
Рис. 13. Строка состояния
Раньше вы могли наблюдать в ней слово Готов.
Следующая информация в Строке состояния относится к позиции текстового
курсора в исходном коде. А завершает Строку состояния здоровье программы в
процентах. Если вы щёлкните по процентам, то откроется диалоговое окно, в котором вы можете узнать причину слабого здоровья своей программы (Рис. 14).
66
Рис. 14. Я болела
Как вы понимаете, сейчас речь идёт не о нашей программе,
а о примере HelloWorld.pas.
Нижняя Панель
Между окном Редактора кода и Строкой состояния
находится Нижняя панель (Рис. 15)
Рис. 15. Нижняя панель
Её ширина равна ширине Главного окна, а высота изменяется пропорционально
его высоте. Кроме того, высоту Панели можно изменить, потянув её мышкой за
верхнюю границу.
67
В нижней части Панели расположены вкладки окон, сменяющие друг друга при
нажатии на них. По умолчанию открыто Окно вывода, которое мы также будем
называть Консолью, или Консольным окном. Именно в Консоль выводятся все сообщения запущенной программы.
В окне Список ошибок вы сможете прочитать сообщения об ошибках, выявившихся при запуске программы.
Окно Сообщения компилятора пока не столь важно для нас, но из интереса вы
можете взглянуть и на него.
Переключаться между окнами можно и в меню Вид, но это менее удобно. Однако
команды этого меню пригодятся вам, если вы закрыли некоторые окна кнопкой
Close с крестиком, которая притаилась у правой границы нижней Панели.
Она закрывает открытую вкладку - Окно вывода (Рис. 16).
Рис. 16. Закрывашка
Затем вы можете закрыть вкладку Список ошибок (Рис. 17).
Рис. 17. Нижняя панель
И наконец, полностью закрыть Нижнюю панель.
68
Если размеры экрана небольшие, то Нижнюю панель можно временно удалить,
выполнив команду меню Вид Нижняя панель или нажав клавишу F5.
Восстановить Нижнюю панель и вкладки вы можете из меню Вид (Рис. 18).
Рис. 18. Управляем Панелью
Главное меню
Под заголовком Главного окна находится Главное меню
программы (Рис. 19).
Рис. 19. Главное меню
Оно содержит несколько меню со списком команд.
Чтобы раскрыть меню, щёлкните левой кнопкой мышки по его названию. Затем
вы можете, как обычно, выбрать любую доступную команду из списка (Рис. 20).
69
Рис. 20. Раскрытое меню File
70
Меню Файл
Команды меню Помощь вы уже досконально изучили раньше.
Сейчас мы изучим меню File, в котором вы найдёте несколько уже известных вам
команд, а с остальными меню вы познакомитесь по ходу чтения книги.
Команда Новый (клавиатурное сокращение Ctrl + N, кнопка
) создаёт новую текущую страницу в Редакторе кода для программы с именем по умолчанию Program#.pas.
Команда Новый проект открывает одноимённое диалоговое окно для выбора типа проекта.
Команда Открыть… (клавиатурное сокращение Ctrl + О, кнопка
) открывает одноимённое диалоговое окно для выбора и загрузки файла в Редактор кода. Выделите нужный файл с расширением .pas и нажмите кнопку
Открыть (Рис. 21). Или просто дважды щёлкните по названию файла.
Рис. 21. Открываем программу
71
Если за названием команды меню следуют 3 точки, значит,
будет открыто какое-либо диалоговое окно.
Команда Открыть проект… открывает то же самое диалоговое окно, но выбрать нужно сохранённый ранее проект, а не отдельный файл.
Команда Сохранить (клавиатурное сокращение Ctrl + S, кнопка
) сохраняет текущий (изменённый) файл на диске под текущим именем. При первом
сохранении действует, как команда Сохранить как…
Команда Сохранить как… сохраняет текущий файл на диске под заданным
именем и в указанной папке. В открывшемся диалоговом окне Сохранение (Рис.
22) перейдите в папку с программами, задайте имя файла и нажмите кнопку
Сохранить. Расширение .pas добавляется к имени файла автоматически.
Рис. 22. Сохраняем программу
72
Команда Сохранить все (кнопка
) сохраняет все открытые в Редакторе
кода файлы. Если они не были сохранены ранее, то откроется диалоговое окно
Сохранить как.
Команда Закрыть закрывает текущий файл. Если последние изменения не
были сохранены на диске, на экране появится диалоговое окно с предупреждением (Рис. 23).
Всегда сохраняйте программу перед закрытием!
Если в Редакторе кода открыт единственный файл, то его закрыть нельзя.
Рис. 23. Будьте бдительны!
Команда Закрыть все, кроме текущего закрывает все открытые в Редакторе
кода файлы, за исключением текущего.
Команда Печать…
(клавиатурное сокращение Ctrl + P) открывает
диалоговое окно для печати текущего документа на выбранном принтере (Рис.
24).
По мере работы над программами в меню Файл пополняется список Последние файлы. Обратите внимание на треугольник в конце этой строки меню:
. Он означает, что вы можете раскрыть список, выбрать нужный файл и загрузить его в Редактор кода, просто щёлкнув по его
названию.
73
Список Последние проекты
гично, но в нём сохраняются не файлы, а проекты.
И последняя команда меню Файл – Выход
PascalABC.NET.
действует анало– закрывает программу
Рис. 24. Печатаем текущий файл
Обобщение
Главное окно программы PascalABC.NET разбито на отдельные функциональные
части:
Заголовок
Главное меню
Панель инструментов
Окно Редактора кода
Панель с Консольным окном
74
Строка состояния
Поэтому ориентироваться в среде разработки очень просто. На Рис. 25 представлены все составные части Главного окна.
Большинство команд, управляющих работой программы PascalABC.NET, сосредоточено в Главном меню, а некоторые из них продублированы кнопками на Панели
инструментов.
Меню Файл содержит самые необходимые команды для начала работы с программой PascalABC.NET: создание нового файла или проекта, сохранение текущего файла или проекта на диске, закрытие текущего файла и другие.
Рис. 25. Составные части Главного окна
75
Основные приёмы работы в Редакторе кода
Исходный код (исходный текст) программы – это текст, который можно редактировать хотя бы в программе Блокнот, входящий в состав операционной системы
Windows.
Исходный код состоит из отдельных строк, в каждой из которых записано ключевое слово, оператор или комментарий. Пустые строки не содержат ни одного символа и служат для отделения логических частей программы друг от друга.
Конечно, в Блокноте слова не будут выделяться цветом, как Редакторе кода, но
в остальном текст в Блокноте ничем не отличается от исходного текста в Редакторе кода. Это значит, что вы можете копировать текст из Редактора кода в любой текстовый редактор и наоборот.
Основные операции
Все команды редактирования находятся в меню Правка (Рис. 1).
Рис. 1. Меню Правка
76
Если вы нажмёте правую кнопку мыши в окне Редактора кода, то появится Контекстное меню (Рис. 2), в котором также имеются основные команды редактирования текста.
Рис. 2. Контекстное меню Редактора кода
Они продублированы и кнопками на Панели инструментов (Рис. 3).
Рис. 3. Кнопки редактирования на Панели инструментов
Кнопки с недоступными командами окрашены в серый цвет.
Чтобы выделить весь текст текущего файла, одновременно нажмите клавиши Ctrl
+ A или выполните команду меню Правка > Выделить все (Рис. 4).
77
Рис. 4. Выделяем весь текст
Чтобы выделить фрагмент текста, установите курсор в начало первой строки фрагмента, нажмите левую кнопку мышки и ведите курсор в его последнюю строку.
Выделенный кусок текста окрасится в синий цвет (Рис. 5).
Рис. 5. Выделяем фрагмент текста
Выделить часть кода можно и клавишами со стрелками, но
это менее удобно.
Стереть выделенный текст можно клавишами Del или Backspace.
Чтобы стереть слово слева от курсора, нажмите клавиши Ctrl + Backspace.
Удалить выделенный текст в буфер обмена можно командой Вырезать меню
Правка или Контекстного меню, а также клавишами Ctrl + X (Рис. 6).
Рис. 6. Команда меню Вырезать
Скопировать выделенный текст в буфер обмена можно командой Копировать или
клавишами Ctrl + С (Рис. 7).
Рис. 7. Команда меню Копировать
78
Чтобы скопировать выделенную часть текста в другое место, нажмите на нём левую кнопку мышки и, удерживая клавишу Ctrl, переместите курсор в нужное место
текста, где отпустите кнопку мышки и клавишу. Либо вставьте текст, предварительно скопированный в буфер обмена, командой меню Вставить или клавишами
Ctrl + V (Рис. 8).
Рис. 8. Команда меню Вставить
Чтобы перенести выделенную часть текста с одного места кода в другое, выполните те же самые действия, что и при копировании, но клавишу Ctrl не нажимайте.
Либо вставьте текст, вырезанный в буфер обмена, командой Вставить.
Чтобы отменить удаление (или другую операцию редактирования), выполните команду меню Правка Отменить или нажмите клавиши Ctrl + Z (Рис. 9).
Рис. 9. Отменяем последнюю операцию редактирования
Вернуть отменённую операцию можно командой меню Правка Восстановить
или клавишами Ctrl + Shift + Z (Рис. 10).
Рис. 10. Возвращаем отмену
Поиск слов
Чтобы отыскать нужное слово в тексте, воспользуйтесь командой меню Правка
Найти… (клавиатурное сокращение Ctrl+F) (Рис. 11).
Рис. 11. Поиск слов из меню Правка
79
В появившемся диалоговом окне введите слово для поиска в текстовое поле Искать и нажмите кнопку Искать далее (Рис. 12).
Рис. 12. Диалоговое окно поиска слова
Если слово сначала выделить в исходном тексте, а затем
вызвать диалоговое окно, то оно сразу появится в текстовом поле.
Первое найденное слово от позиции курсора будет выделено синим фоном (Рис.
13).
Рис. 13. Слово найдено!
Нажимая кнопку Искать далее, или клавиши Ctrl + L, или строчку меню Найти далее, вы будете последовательно переходить к следующему найденному слову.
При этом диалоговое окно может быть закрыто.
80
По умолчанию регистр букв не учитывается, поэтому будут найдены, например,
слова writeln и Writeln. Если вы ищите только вполне определённое написание, то
установите галочку перед строкой Учитывать регистр. Тогда будут найдены только
те слова, которые записаны в тексте точно так же, как и в окне для поиска.
По умолчанию будут найдены вхождения заданного слова во все слова текста. Так
в результате поиска вы можете получить и лишние слова. Чтобы избавиться от
них, установите галочку Слово целиком.
Если вы умеете пользоваться регулярными выражениями, то поставьте галочку
Регулярные выражения.
По умолчанию поиск строк ведётся от позиции курсора вниз по тексту. Установите
флажок Искать вверх, и поиск пойдёт в обратном направлении – к началу текста.
Если вы занимались поиском неоднократно, то можете открыть список всех «поисковых» слов и выбрать из них нужное (Рис. 14).
Рис. 14. Список слов
Замена слов
Замена слов – также одна из наиболее частых операций редактирования - выполняется в диалоговом окне Замена (Рис. 15).
Выделите в исходном тексте слово (или несколько слов) и нажмите клавиши Ctrl
+ R, чтобы перейти в это диалоговое окно. В текстовом поле Искать вы увидите
слово для поиска (заменяемое), а в текстовое поле Заменить впечатайте новое
81
слово. Теперь нажимайте кнопку Заменить, чтобы последовательно заменять старое слово новым.
Рис. 15. Заменяем слова в исходном тексте
Замена производится от выделенного слова (или текстового
курсора) вниз, если флажок Искать вверх не установлен, или
вверх, если установлен.
Переходя от слова к слову, вы сможете легко контролировать процесс, ведь иногда можно по ошибке заменить совсем не то слово, которое вы хотели.
Если же вы твёрдо уверены в своём выборе, то нажмите кнопку Заменить все,
чтобы произвести замены во всём тексте разом (но только в заданном направлении).
Если операция замены привела к ошибкам, то отмените её, выполнив команду
меню Правка > Отменить или нажав клавиши Ctrl + Z.
Форматирование текста
В паскале блоки кода принято записывать с отступами от левого края (блок кода
– это инструкции внутри операторных скобок begin-end) (Рис. 16).
В приведённом фрагменте кода операторы Writeln образуют блок, который записан с отступом от левого края, чтобы выделить его по отношению к операторным
скобкам.
82
Рис. 16. Блок кода
Именно так принято записывать исходный текст на языке
паскаль, а теперь паскалевский способ применяется во всех
языках программирования. Язык программирования Python
вообще обходится отступами, без операторных скобок.
Всегда записывайте программу с отступами! При этом
ключевые слова, обозначающие начало и конец многострочных операторов, должны находиться на одинаковом расстоянии от начала строки – так вам будет гораздо проще
контролировать правильность записи исходного текста.
Чтобы увеличить отступ, выделите строки и нажмите клавишу табуляции. Текст
сместится вправо на расстояние табуляции (Рис. 17).
Отдельную строку можно переместить влево (уменьшить отступ) клавишей
Backspace.
Ещё удобнее отформатировать весь исходный текст, выполнив команду меню
Сервис (Рис. 18, слева) или Контекстного меню (Рис. 18, справа) Форматировать
код.
83
Рис. 17. Табуляция
Рис. 18. Форматируем код
Ещё проще нажать кнопку
на Панели инструментов.
Если в тексте имеются ошибки, то он не будет отформатирован, а компилятор предложит вам сначала исправить их.
Сворачивание блоков кода
Как ни старайся, а с длинным кодом всё равно работать неудобно. Есть несколько
способов, чтобы его «укоротить». Мы рассмотрим один из них.
84
Установив флажок Разрешить сворачивание кода в диалоговом окне Настройки
(Рис. 19), мы разобьём весь исходный код на отдельные регионы.
Рис. 19. Пора сворачивать
В начале каждого региона находится узелок с минусом, который означает, что регион развёрнут (Рис. 20).
Рис. 20. История с узелками
85
Чтобы свернуть регион, нажмите узелок мышкой. Тогда место минуса в узелке
займёт плюс, от региона останется только первая строка, в конце которой появится многоточие в рамке (Рис. 21).
Рис. 21. Узелок завяжется
Обычно сворачивают те части исходного кода, работа над которыми уже закончена, и они только занимают ценное место на экране. Но при необходимости
свёрнутый сегмент разворачивается щелчком по узелку с плюсом, и его можно
посмотреть или подредактировать.
Настройка ИСР
Прежде чем идти дальше, давайте настроим среду разработки так, чтобы в ней было удобно работать.
По умолчанию размер табуляции равен двум символам.
Это слишком мало, поэтому лучше увеличить табуляцию
до 3-4 символов.
Для настройки ИСР выполните команду меню Сервис Настройки… (Рис. 22).
Рис. 22. Приступаем к настройкам среды
Откроется диалоговое окно Настройки (Рис. 23).
В нём вы можете изменить язык интерфейса, но я предпочитаю надписи на русском языке.
Теперь перейдите на вкладку Редактор (Рис. 24).
86
Рис. 23. Диалоговое меню Настройки
Рис. 24. Настраиваем Редактор кода
87
По умолчанию исходный код печатается мелким шрифтом Courier. Я советую вам
заменить его шрифтом Consolas размером 12 или 14 пунктов. Так работать с текстом вам будет гораздо удобнее.
Все строки исходного текста пронумерованы (если установлен флажок Показывать номера строк), что облегчает навигацию по длинному документу (Рис. 25).
Рис. 25. Пронумерованные строки исходного текста
Строки в Редакторе кода нумеруются только для удобства
перемещения по длинному исходному тексту, в самой программе они не используются. Согласитесь, гораздо проще
найти нужную строку, если она имеет номер. Правда, номер строки может и измениться, если вы перед ней вставите одну или несколько строк, но тут уж ничего не попишешь!
Некоторые строки принято оставлять пустыми, чтобы
отделять друг от друга смысловые части программы.
88
Как только вы нажмёте клавишу ВВОД (или ENTER), к
тексту добавится ещё одна пустая строка, причем строки
нумеруются последовательно, начиная с единицы (Рис. 26).
Рис. 26. Все строки пронумерованы!
Увеличьте табуляцию и поставьте все остальные флажки (Рис. 27).
Рис. 27. Настройка Редактора кода закончена
89
На следующей вкладке – Опции компилятора – установите флажки так, как оказано на Рис. 28.
Рис. 28. Продолжаем благоустраивать ИСР
Теперь выполняемый файл программы с расширением .exe после запуска программы останется в папке в целости и сохранности, и вы сможете запустить его
на любом компьютере, на котором установлена платформа .NET. Однако работа
программы на диске отличается от работы этой же программы в среде разработки – после вывода сообщения Консольное окно тут же закроется, так что вряд
ли вы успеете его прочитать. Допишите ещё одну строку к исходному коду:
begin
Writeln('Hello World!');
Readln();
end.
Либо на вкладке Общие установите флажок Делать паузу после завершения консольной программы (Рис. 29).
90
Рис. 29. Ставим на паузу
Теперь окно закроется только после нажатия на какую-нибудь клавишу.
Если программа на открытой вкладке Редактора кода запускалась, то слева от её названия появится жирная точка:
И на последней вкладке – Intellisense (Интеллектуальная подсказка) – установите все флажки (Рис. 30).
Intellisense – это умная подсказка, которая облегчает набор исходного текста. О
ней мы в своё время ещё поговорим.
Нажмите кнопку ОК, чтобы закончить настройку среды.
91
Рис. 30. Подсказываем подсказке!
Навигация по коду
Если исходный код полностью помещается на экране, то работать с ним легко и
удобно. Однако такое счастье выпадает редко, потому что большинство программ
состоит из многих десятков, а то и сотен строк.
Для примера откройте в Редакторе кода игру BookWorm (Рис. 31).
Обратите внимание на тонкую серую вертикальную черту
справа. Она показывает, где заканчивается 80-ый символ
строки:
92
Это максимальная длина строки, которую ещё можно нормально прочитать. Именно столько символов помещалось
на старых дисплеях/мониторах.
Рис. 31. Длинный книжный червь
93
Как вы видите, все строки аккуратно пронумерованы, о чём мы уже позаботились.
Но текст слишком длинный и широкий - он гораздо больше, чем видимые размеры окна Редактора кода. Поэтому справа и снизу появились полосы прокрутки,
пользуясь которыми, вы можете перейти к нужному участку кода.
Перемещаться по тексту можно и с клавиатуры, но это
менее удобно.
Если текст ещё длиннее, а у вас хорошая память, и вы запомнили номер строки,
то можете сразу перейти на неё, выполнив команду меню Правка Перейти к
строке… (клавиатурное сокращение Ctrl+G) (Рис. 32).
Рис. 32. Переход на заданную строку
В очень простом диалоговом окне наберите нужный номер строки и нажмите
кнопку ОК (Рис. 33).
Рис. 33. Номер строки
94
Текстовый курсор займёт место в начале указанной строки (Рис. 34).
Рис. 34. Знай свой место
Обратите внимание, что в диалоговом окне Перейти к строке указан диапазон номеров (1-228), в который должен укладываться и номер строки для перехода. В
противном случае вы навсегда останетесь в этом диалоговом окне.
Циклически переходить к редактировавшимся ранее строкам очень удобно с помощью команд меню Вид Перейти назад (клавиатурное сокращение Ctrl + -) и
Вид > Перейти вперёд (клавиатурное сокращение Ctrl + Shift + -) (Рис. 35, слева).
Эти же команды продублированы и на Панели инструментов (Рис. 35, справа).
Рис. 35. Вперёд-назад
95
Закладки
Номера строк трудно удержать в голове, и они могут измениться
при работе над программой. На этот случай предусмотрены закладки. Они действуют почти так же, как и всем известные закладки для книг.
Для управления закладками меню Правка имеет 4 команды
(Рис. 36).
Рис. 36. Закладки
Чтобы поставить закладку, установите текстовый курсор в любое место нужной
строки и выполните команду меню Правка Закладки Поставить закладку (клавиатурное сокращение Shift + F2). Слева от номера строки появится значок, символизирующий закладку (Рис. 37).
Рис. 37. Закладка поставлена
Расставьте в исходном коде ещё несколько закладок.
Теперь вы можете циклически переходить на эти закладки при помощи команд
меню Правка Закладки Перейти к следующей (клавиатурное сокращение F2)
и Правка Закладки Перейти к предыдущей (клавиатурное сокращение Alt +
F2).
Чтобы удалить закладку, просто щёлкните по ней мышкой.
96
Удалить все закладки вам поможет команда меню Правка Закладки Удалить
все закладки.
Панель навигации по коду
Длинный исходный код, как правило, разбивают на отдельные части, которые
называются подпрограммами. Каждая подпрограмма имеет своё имя, по которому её легко найти в Панели навигации по коду.
Она появляется под ярлыками файлов (Рис. 38), если в меню Вид поставлена галочка перед строчкой Панель навигации по коду (Рис. 39).
Рис. 38. Панель навигации по коду
Рис. 39. Показываем Панель навигации по коду на экране
Панель навигации состоит из двух раскрывающихся списков. Слева – список глобальных имён, слева – локальных. Чтобы развернуть список, щёлкните по кнопке
с галочкой (Рис. 40).
97
Рис. 40. Списки глобальных и локальных имён
Выберите нужное имя и щёлкните по нему. Текстовый курсор перейдёт в указанное место кода.
Все объекты программы разбиты по категориям, в которых они располагаются в
алфавитном порядке.
Слева от идентификаторов (имён объектов программы) находятся значки, указывающие на принадлежность объекта к той или иной категории. Подпрограммы отмечены лиловым кубиком. Зелёные кубики относят объект к переменным, а белые прямоугольники – к константам.
Шаблоны кода
Для облегчения и ускорения набора текста в ИСР предусмотрена возможность вставки целых фрагментов текста (их называют шаблонами кода, по-английски - snippets). Для этого нужно набрать несколько начальных букв
и нажать клавиши Shift+ПРОБЕЛ.
Чтобы начать программу в новом документе, наберите prog и нажмите указанные
клавиши. Тут же появляется заготовка программы:
98
program Program1;
begin
end.
Имя программы совпадает с именем файла. Если вы предварительно запишете
пустой документ на диск, например, под именем test.pas, то программа получит
имя test.
Как вы знаете, имя программы указывать не обязательно (а теперь и не нужно!).
На этот случай имеется другой шаблон. Набираем буквы be, нажимаем клавиши
– и получаем «безымянную» заготовку программы:
begin
end.
Для приложений с графическим интерфейсом требуется модуль GraphWPF. Набираем буквы gr и после нажатия на клавиши Shift+ПРОБЕЛ шаблон для графической
программы готов:
uses GraphWPF;
begin
end.
Конечно, такие «операции» проводят только в самом начале разработки программы, но многие конструкции языка необходимо набирать много и часто. Особенно это относится к операторным скобкам. Но – достаточно напечатать только
букву b и нажать клавиши Shift+ПРОБЕЛ, чтобы они заняли своё место в исходном
тексте:
begin
99
end;
Очень часто приходится набирать слово integer, означающее в паскале целый тип.
Переменные этого типа встречаются в программах чаще всего, поэтому для него
также имеется шаблон кода, который срабатывает после ввода буквы i:
integer
Обобщение
Вся работа с исходным текстом программы выполняется в Редакторе кода, который представляет собой специализированный текстовый редактор. Он умеет
выделять ключевые слова и другие объекты программы. Многие функции Редактора кода известны вам по работе с другими текстовыми программами.
Например, выделение текста, его копирование, вырезание, вставка, поиск и замена строк ничем не отличаются от этих операций в других программах.
Более специфические команды Редактора кода, как, например, нумерация
строк также очень просты для понимания и использования.
Команды редактирования собраны в меню Правка, в Контекстном меню Редактора кода и на Панели инструментов. Но зачастую удобнее и быстрее выполнять соответствующие им клавиатурные сокращения, которые в Редакторе
кода совпадают с общепринятыми для команд редактирования.
100
Наша первая программа!
Я поэт, зовусь я Цветик!
От меня вам всем приветик!
Мультфильм про Незнайку
В компьютерной литературе принято начинать обучение
программированию с создания приложения, выводящего
на экран надпись Привет, Мир!. Мы не станем нарушать
эту славную традицию.
Запустите программу PascalABC.NET. В Редакторе кода откроется пустая страница программы с названием по умолчанию – Program1 (Рис. 1).
Рис. 1. Пока пусто
Такое имя ничего не говорит о назначении программы, поэтому его следует изменить, записав программу на диск. Но вначале мы должны определиться, что же
101
за программу мы хотим написать. Здесь как раз всё просто: назовём программу
Привет.
Поскольку мы ничего не изменили в тексте программы, то единственный способ
сохранить её – это выполнить команду меню Файл Сохранить как… (Рис. 2).
Рис. 2. Сохраняем программу из меню Файл
Все программы, даже учебные сразу сохраняйте на диске, в
папке с проектами.
Но можно поступить хитрее, и изменить текст программы, ничего в ней не напортив. Просто нажмите клавишу ПРОБЕЛ – и после названия файла на его вкладки
появится звёздочка, сигнализирующая о том, что файл изменён, но ещё не сохранён на диске (Рис. 3).
Теперь вы можете нажать любую из двух кнопок с дискетами
инструментов.
на Панели
Ещё правильнее не мудрить с пробелом, а сразу создать заготовку для будущей
программы, воспользовавшись шаблоном кода.
Наберите «слово» be, а затем нажмите клавиши Shift + ПРОБЕЛ (Рис. 4).
102
Рис. 3. Следите за звёздочками!
Рис. 4. Действуем по шаблону
103
Если на экране появится подсказка, то уберите её, нажав
клавишу ПРОБЕЛ или ВВОД.
Осталось изменить название программы и сохранить её на диске. Для этого
нажмите кнопку Сохранить (Рис. 5, слева) или выполните команду меню Файл
Сохранить как… (клавиатурное сокращение Ctrl+Shift+S) (Рис. 5, справа).
Рис. 5. Сохраняйся!
Перейдите в папку с проектами и создайте в ней папку Привет (Рис. 6).
Рис. 6. Храните программы в папках
104
Откройте папку двойным щелчком мышки или нажмите кнопку Открыть (Рис. 7).
Рис. 7. Сохранение – мать сбережения
Наберите имя файла и нажмите кнопку Сохранить (Рис. 8).
В папке с программой появится файл Привет.pas (Рис. 9).
Название файла на вкладке в Редакторе кода также изменится на Привет.pas,
а звёздочка исчезнет (Рис. 10).
Для коротких программ, состоящих из одного файла не
обязательно заводить отдельную папку. Сохраняйте их в
общей папке со всеми программами.
105
Рис. 8. Новое имя для первой программы
Рис. 9. Удачно записалось
Рис. 10. Закладка на память
106
По умолчанию файл будет сохранён в Рабочей папке, путь
к которой вы указали при установке системы программирования PascalABC.NET. Поэтому вы можете сохранять
учебные файлы в этой папке.
Такую программу можно даже запустить, нажав кнопку с зелёным треугольником
(или стрелкой, если вам так больше нравится) (Рис. 11). В Окне вывода, вы, естественно, ничего не увидите, но компилятор в Строке состояния сообщит, что
программа состоит из пяти строк, в которых нет ни одной ошибки.
Рис. 11. Безошибочная, но бесполезная программа
Если бы компьютер понимал человеческий язык, то есть русский, то мы могли бы
передать привет так:
begin
107
Привет, Мир!
end.
Запускаем программу – и в окне Список ошибок (запомните его, потому что вы
часто будете в него попадать!) читаем, что уже первая буква нашего послания непонятна компьютеру. Строка с ошибкой в исходном тексте выделяется красным
фоном, а курсор устанавливается в месте предполагаемой ошибки (Рис. 12).
Рис. 12. Компьютер нас не понимает!
Текст программы называют также исходным текстом,
исходным кодом или – жаргонно – исходником.
Ну конечно, привет миру – это прямая речь, которую следует взять в двойные кавычки. Однако в паскале в этом случае используют одинарные кавычки. Исправляем текст и снова запускаем программу (Рис. 13).
108
Рис. 13. Понял, но не так
В паскале любые символы, заключённые в одинарные кавычки, называются строкой (string).
Если в одинарные кавычки попал ровно 1 символ, то это не
строка, а именно символ (char)!
Одинарные кавычки только ограничивают строку, но в саму строку не входят.
Строка выделяется в тексте синим цветом.
Цвет отдельных слов определяется самой ИСР, поэтому не
ищите кнопок выбора цвета! А выделяются слова не
столько для красоты, сколько для удобства ориентирования
109
в исходном коде. Например, комментарии выводятся на
экран зелёным шрифтом. Названия подпрограмм (процедур
и функций), ключевые слова – чёрным, переменных – тоже
чёрным, а их значения – зелёным. О смысле этих элементов
любой программы мы ещё поговорим, но уже сейчас вы
должны обратить внимание на то, что сходные по назначению слова выделяются одним и тем же цветом.
Уже лучше! Сообщение выделено синим цветом, значит, компилятор понимает,
что это строка. Но всё равно он указывает нам на ошибку.
В нашей строке отсутствует точка с запятой, которой должны заканчиваться все
команды (инструкции) на языке паскаль.
Но запуск программы снова огорчает нас очередной ошибкой, хотя мы закончили
предложение правильно (Рис. 14).
Да, к сожалению, компьютеры пока не знают ни одного человеческого языка, а
понимают только машинный, который состоит из нулей и единиц. Но на таком
«тарабарском» языке невозможно написать даже самую простую программу,
поэтому люди и придумали языки программирования, чтобы с их помощью
объяснять компьютеру, что же он должен делать.
Языки, подобные паскалю, называются декларативными, то есть командными.
Чтобы программа что-нибудь выполнила, ей нужно дать приказ. Мы же только
написали сообщение, но не дали компьютеру никакого распоряжения. Давайте
немного покомандуем!
В отличие от сообщений, все команды записываются на английском языке. Порусски мы бы отдали такой приказ:
Напиши 'Привет, Мир!';
По-английски он должен был бы выглядеть так:
110
Write 'Привет, Мир!';
Рис. 14. Опыт – сын ошибок трудных…
Если читать слово Write по буквам, то получится Врите.
Но англичане избежали этой двусмысленности, читая слово
Write как Райт.
И всё равно при запуске программы получаем ошибку (Рис. 15).
Опять чего-то не хватает! Пора нам больше узнать о команде Write. Установите на
это слово текстовый курсор, под которым тут же появится подсказка (Рис. 16).
Команда Write выводит на экран (печатает, пишет) то, что заключено в круглых
скобках. А вот скобки-то мы и не поставили!
111
Рис. 15. И по-английски не понимает?
Рис. 16. Умело пользуйтесь подсказками!
Вообще говоря, правильна и такая команда:
Write;
Но она ничего не напечатает.
Берём сообщение в круглые скобки – и заработало! В Окне вывода вы можете
прочитать наше сообщение (Рис. 17).
112
В паскале можно не ставить круглые скобки после имени
подпрограммы, если они пустые.
Рис. 17. Вывели привет
Обратите внимание, что и скобки, и кавычки всегда парные: если есть открывающая скобка или кавычка, то должна быть и закрывающая! Только попробуйте забыть закрывающую скобку, и компилятор напомнит вам об этом упущении (Рис.
18).
Мы написали сейчас Консольное приложение. В среде PascalABC.NET в режиме
отладки (а кнопка Выполнить запускает программу в отладочном режиме) информация печатается в Окне вывода, которое находится в нижней части Главного
окна ИСР.
113
Рис. 18. Все скобки и кавычки должны иметь пару
Чтобы увидеть работу программы в настоящем Консольном окне, следует запустить программу в автономном режиме. Для этого нажмите клавиши Shift+F9 или
выполните команду меню Программа Выполнить без связи с оболочкой (клавиатурное сокращение Shift+F9) (Рис. 19).
Рис. 19. Вывод на консоль Windows
В этом случае будет создано Консольное окно приложения (Рис. 20), но отладочный режим теперь уже не действует.
114
Рис. 20. Наша программа в настоящем Консольном окне
Чтобы закрыть Консольное окно, нажмите любую клавишу, красную кнопку с крестиком в правом верхнем углу окна, кнопку Завершить на Панели инструментов,
выполните команду меню Программа Завершить (Рис. 21) или нажмите клавиши Ctrl +F2.
Рис. 21. Пора заканчивать
Вы, конечно, заметили, что после нашей строки с приветствием компилятор добавил строку Программа завершена… Дело в том, что команда Write печатает
строку, но вывод печати остаётся в той же строке. Если вы хотите, чтобы следующая строка была напечатана ниже, то используйте команду Writeln. Она делает то
же самое, что и команда Write, но переносит вывод информации в строку ниже.
Исправляем исходный код и запускаем программу:
begin
Writeln ('Привет, Мир!');
end.
Теперь мы получили на экране 2 строки (Рис. 22).
Рис. 22. Пора заканчивать
115
Для лучшего понимания текста между строками с информацией вставляют пустую
строку. Для этого нужно записать инструкцию Writeln;
Начните печатать с новой строки слово Write.
Обычно в каждой строке записывают только одну команду
– так исходный текст легче читается.
Уже после первой буквы w на экране появляется Интеллектуальная подсказка
со списком слов, начинающихся с этой буквы (Рис. 23).
Рис. 23. Подсказка всегда к месту
Если нужное слово не выделено, то продолжайте набирать слово. Обычно бысстро появляется нужное слово, которое выделяется синим фоном. Но вы можете
просто прокрутить список на нужное слово и нажать клавишу ВВОД или просто
щёлкнуть по строчке мышкой.
Интеллектуальную подсказку вы можете вызвать в любое время самостоятельно,
если нажмёте клавиши Ctrl + ПРОБЕЛ. А дальше вы можете прокрутить список и
выбрать нужное слово. Но так до него вам придётся долго добираться.
Интеллектуальная подсказка объясняет нам, что команда Writeln не только печатает данные в скобках, но и переходит на другую строку (Рис. 24).
116
Рис. 24. Подсказка – двигатель прогресса!
В программах на паскале имена объектов можно писать и ПРОПИСНЫМИ, и
строчными буквами, поэтому команды Write и Writeln вы можете писать и со
строчной буквы - write и writeln. С точки зрения паскаля, это одно и то же. Но на
паскале названия команд принято писать со строчной буквы, а платформа .NET
предпочитает ПРОПИСНЫЕ. Вы можете писать команды как угодно, но всё-таки
лучше – с Заглавной буквы.
Мы дополнили программу одной строкой:
begin
Writeln ('Привет, Мир!');
Writeln;
end.
И вывод информации на экран стал гораздо лучше (Рис. 25).
Рис. 25. Лучше – лучше, чем хорошо
В данном случае совсем необязательно снова набирать всю
строку. Просто скопируйте первую строчку и исправьте
её.
Кстати говоря, командами Write и Writeln можно одновременно передавать несколько строковых сообщений, отделив их друг от друга запятой (Рис. 26).
117
Рис. 26. Два сообщения в одной строке
Команды Write и Writeln печатают следующее сообщение без разделяющего пробела. Команды Print и Println действуют так же, но автоматически вставляют пробел между отдельными строками (Рис. 27):
begin
Writeln ('Привет, Мир!', 'Привет, Россия!');
Writeln;
Println('Привет, Мир!', 'Привет, Россия!');
Println;
end.
118
Рис. 27. С пробелом
Если вы используете для печати команды Write и Writeln,
то, чтобы отдельные строчки при этом не сливались, не
забывайте ставить в начале или в конце строк пробелы!
А теперь давайте разберёмся со странными словами Writeln и Println. Начало
слова мы Writeln знаем: write – напиши. А ln – это сокращение от слова line – линия, строка. Слово Print можно перевести как напечатай. О значении хвостика ln
в слове Println вы уже знаете. Когда оба эти слова записаны всмятку, то их смысл
становится трудноуловим. Лучше писать так: WriteLn. Это не совсем по-паскалевски, но вполне допустимо, а в языках платформы .NET так и следует писать составные идентификаторы.
119
Каким бы способом вы ни запускали программу или просто скомпилировали её
без запуска командой меню Программа Компилировать (клавиатурное сокращение Ctrl + F9) (Рис. 28), в папке с программой или в папке Output появится выполняемый файл программы Привет.exe (Рис. 29). В операционной системе
Windows такой файл (программа) называется приложением. Его легко отличить от
других файлов на диске по расширению exe (сокращение от английского слова
execute - выполнять, исполнять). Чтобы запустить приложение, достаточно дважды щёлкнуть по названию файла мышкой.
Рис. 28. Компилируем программу
Рис. 29. Выполняемый файл
Легко убедиться, что паскаль узнаёт свои файлы. Закройте среду разработки
PascalABC.NET и дважды кликните по названию файла с расширением .pas - паскаль снова запустится и самостоятельно загрузит исходный текст программы в Редактор кода. Если вы подведёте к закладке файла курсор мышки, то появится
подсказка, в которой будет указан полный путь к файлу, включая название Рабочей папки (Рис. 30).
Рис. 30. Путь к файлу проекта
120
Чтобы закрыть среду разработки, нажмите красную кнопку Закрыть с крестиком в
правом верхнем углу Главного окна программы или выполните команду меню
Файл Выход (Рис. 31).
Рис. 30. Путь к файлу проекта
Если остались несохранённые файлы, то среда разработки напомнит вам об этом
(Рис. 31).
Рис. 31. Помни, не забывай…
Если вы хотите сохранить изменения в программе, то нажмите кнопку Да. Если
хотите оставить предыдущий вариант программы, нажмите кнопку Нет. А кнопка
121
Отмена вернёт вас в среду разработки, где вы сможете продолжить работу над
программой.
Сохраняйся!
Программистская пословица
Поставьте ещё 2 восклицательных знака, чтобы усилить наш мировой привет. Обратите внимание, что после названия файла на вкладке в Редакторе кода появилась звёздочка, которая сигнализирует, что файл изменён (Рис. 32).
Рис. 32. Путеводная звезда
После каждого удачного запуска программы сохраняйте её
на диске, как описано выше.
Если нет других открытых файлов, то можно нажать и кнопку Сохранить все или
выполнить одноимённую команду меню Файл (Рис. 33).
Звёздочка после имени файла исчезнет (Рис. 34).
Чтобы открыть файл с программой, дважды щёлкните по её названию в файловом
менеджере. Или нажмите кнопку Открыть (клавиатурное сокращение Ctrl+O) с
изображением папки (Рис. 35).
Вы можете переложить свои обязанности по сохранению
программы на среду разработки, если поставите галочку
Сохранять файлы, если компиляция прошла успешно:
122
Рис. 33. Средства сохранения
Рис. 34. Погасшая звезда
Рис. 35. Кнопка для загрузки исходного файла
123
В появившемся одноимённом диалоговом окне (Рис. 36) перейдите в нужную
папку и щёлкните по названию файла программы, чтобы выделить его, после чего
нажмите кнопку Открыть (или сразу дважды щёлкните по названию).
Рис. 36. Диалоговое окно для выбора программы
Текст программы откроется в Редакторе кода.
В окне Редактора кода можно одновременно редактировать несколько документов. Вы можете любой из них сделать активным, просто щёлкнув по его вкладке.
Структура простой программы
Самая короткая и простая программа на паскале состоит из двух строк:
begin
. . .
end.
Иногда конструкцию begin и end называют операторными скобками.
124
В паскале роль операторных скобок исполняют ключевые
слова begin и end, которые совсем не похожи на скобки. Но
вот в языках C++, C# и других для этих целей используют
фигурные скобки:
{
}
Назначение этих слов легче запомнить, если знать, что с
английского слово begin переводится как начало, а end как
конец. Назначение точки в конце программы понятно без
объяснений.
Обратите внимание на точку после ключевого слова end! Она сигнализирует об
окончании текста программы. После этой точки ничего писать нельзя!
Комментарии, конечно, писать можно и после точки, но
исполняемый код – ни в коем случае…
Внутри операторных скобок вместо многоточия записываются команды (инструкции). Эти команды внутри операторных скобок называют блоком кода, или
блоком операторов. Все инструкции должны заканчиваться точкой с запятой (за
исключением последней).
Блок операторов, который заканчивается словом end с точкой, называют главной, или основной программой/блоком. Эти инструкции образуют тело программы.
Классический паскаль относится к декларативным языкам программирования,
поскольку все действия выполняются с помощью отдельных команд – таких, как
Write, WriteLn, Read, ReadLn.
Обычно программы на паскале состоят из многих десятков строк, которые невозможно целиком увидеть на экране. К тому же многие действия в программе
125
выполняются несколько раз, поэтому один и тот же код придётся повторять. По
этим и другим причинам длинный код разбивают на отдельные законченные части, которые называют процедурами. По этому признаку классический паскаль
относят к процедурным языкам.
Процедуры – это законченные части программы, то есть подпрограммы, которые
в паскале разделяют на собственно процедуры и функции. Они отличаются тем,
что функции возвращают вычисленное значение, а процедуры не возвращают.
Команды Write, WriteLn, Read, ReadLn – это процедуры. Они только выполняют
какие-либо действия, но никаких данных не возвращают.
На самом деле процедуры Read, ReadLn могут возвращать
значения, но делают они это иначе, чем «нормальные»
функции.
Чтобы узнать, что именно делает процедура или функция паскаля, достаточно
установить на её идентификаторе в исходном коде текстовый курсор (Рис. 37).
Рис. 37. Подсказка по процедуре ReadLn
Из этой справки не следует, что команда Readln – процедура, поэтому нажмите
на ней правую кнопку мышки, чтобы вызвать Контекстное меню Редактора
кода и нажмите строчку Перейти к определению (Рис. 38).
Рис. 38. Уточняем справку
126
В Редакторе кода откроется системный файл (его изменять нельзя, да и не получится) PABCSystem.pas, а курсор установится в начало строки с определением
процедуры Readln (Рис. 39).
Рис. 39. Всё верно!
Точно так же вы можете проверить, что команды Write и WriteLn – это тоже процедуры (Рис. 40).
Рис. 41. Процедуры!
Интеллектуальная подсказка (Intellisense)
Вы уже знаете, что при наборе строки появляется подсказка со списком допустимых объектов программы.
Действие подсказки определяется настройками на вкладке
Intellisense в диалоговом окне Настройки:
127
Например, мы начинаем набирать первую строку программы и, как только мы
нажмём клавишу р, сразу же увидим всплывающее окно подсказки (Рис. 42).
Рис. 42. «Интеллектуальная» подсказка
Так как ИСР не может знать заранее, какое слово мы хотим набрать, то она просто
переходит на первую строку, начинающуюся с буквы р. Но нам нужно ключевое
слово Print (или Println), которое находится ниже в алфавитном списке, поэтому
продолжаем набирать строку дальше (Рис. 43).
И ещё дальше (Рис. 44).
128
Рис. 43. Подсказка автоматически прокручивает список
Рис. 44. Подсказка нашла нужное слово
Вот теперь в окне подсказки оказалось нужное нам слово, и мы можем не продолжать набор, а просто нажать клавишу ВВОД. Слово целиком появится в окне
редактирования (Рис. 45), а подсказка исчезнет с экрана.
Рис. 45. Слово вставлено в строку программы
129
Заметьте: нам не пришлось до конца вводить слово, и напечатано оно без ошибок, которые мы могли бы сделать!
Можно ещё облегчить себе ввод слов, если просто напечатать первую букву, а когда появится подсказка, прокрутить её на нужное нам слово с помощью мышки или клавиш
со стрелочками ВВЕРХ-ВНИЗ. Когда появится нужное нам
слово, нажимаем клавишу ВВОД или дважды щёлкаем по
нему мышкой.
Подсказку можно вызвать в любое время, нажав клавиши
CTRL+ПРОБЕЛ.
Если в исходном коде программы имеются синтаксические
ошибки, то подсказка может и не появиться. В этом случае
нужно проверить текст.
Обратите также внимание на то, что справа от окна подсказки (Рис. 44⬆) появляется информация о текущем объекте (он выделен синим фоном). Когда вы хорошо
выучите все операторы паскаля, эта информация вам не потребуется, но на первых порах очень даже пригодится!
Здесь вы найдёте сведения, например, о командах печати. Вот так, прокручивая
мышкой подсказку, можно выучить весь паскаль. Это, конечно, шутка: по словарю
тарабарского языка говорить не научишься. С паскалем ничуть не проще.
Если вы захотите получить помощь по любому объекту программы, который имеется в исходном коде, подведите к нему курсор мышки и прочитайте короткую
справку. Так что весь справочник по паскалю у вас всегда под рукой!
130
Обобщение
При разработке новой программы регулярно нажимайте кнопку Сохранить!
В папке с программами обязательно заведите папку для архивных файлов.
Назовите ее _ARCHIV, или _АРХИВ, или как угодно иначе, но она должна быть
обязательно, если вы планируете достаточно долго работать над проектом. В
этой папке периодически сохраняйте файлы, которые изменяются при работе,
например, файлы паскаля с расширением .pas.
Чтобы файлы занимали меньше места на диске, пользуйтесь архиватором.
Сжатые файлы последовательно нумеруйте, чтобы всегда можно было вернуться к отлаженной версии программы, если вы наделаете ошибок при дальнейшей работе. Если проект ответственный, то сохраняйте его дополнительно
на другом диске: вдруг вы случайно сотрёте папку или диск выйдет из строя…
Простые программы на паскале пишут в процедурном стиле.
Простые программы на паскале состоят из подпрограмм, которые делятся на
процедуры и функции.
Простые программы на паскале состоят из операторных скобок begin – end,
между которыми записываются операторы, составляющие тело программы:
begin
. . .
end.
Последнее ключевое слово end в программе должно заканчиваться точкой.
Весь блок операторов внутри операторных скобок begin – end. называется
главной программой/блоком.
Процедуры Write, Writeln Print и Println выводят сообщения в Консольное окно,
а процедуры Read и Readln ждут ввода данных с клавиатуры.
131
Грамматика паскаля
Программа на паскале в окне Редактора кода – это
«обычный» текст, состоящий из слов, чисел и различных
знаков. И это естественно, ведь программист набирает
его на своей клавиатуре и не может напечатать никаких
других символов. Зато почти все они используются в программах:
Все строчные и прописные буквы как латинского, так и русского алфавита, а
также знак подчёркивания _ и пробел.
Все цифры.
Специальные символы # $ & ' ( ) * + , - . / : ; < = > @ [ ] ^ { }. Некоторые пары
этих символов: .. // := <= >= <> имеют собственное значение.
Зарезервированные (ключевые) слова
Кроме отдельных символов, в программах на паскале используются и целые слова, которые и составляют язык
программирования. Их называют ключевыми, или зарезервированными. Они имеют собственное значение, поэтому их нельзя использовать иначе.
abstract and array as begin case class const constructor default destructor div do downto else end event except external
file final finalization finally for foreach forward function
goto if implementation in inherited initialization interface
internal is label lock mod nil not of on operator or overload
override params private procedure program property protected
public raise record reintroduce repeat set shl shr sizeof template then to try type typeof unit until uses using var virtual where while with xor
132
Красным цветом выделены контекстные ключевые слова,
которые используются по-другому, чем остальные.
Если вам всё-таки хочется использовать ключевые слова
как идентификаторы, то ставьте перед ними префикс &:
&mod, &var, &set.
Ключевые слова выделяются в исходном тексте жирным шрифтом (а некоторые цветом), так что вы легко их «опознаете»:
// Перемена местами значений двух переменных с использованием третьей
var x,y: real;
begin
Write('Введите x,y: ');
Readln(x,y);
var v: real; // вспомогательная переменная
v := x;
x := y;
y := v;
Writeln('Новые значения x,y: ',x,' ',y);
end.
Идентификаторы
Если вы хотите обратиться к человеку, то должны знать
его имя (в особо ответственных случаях - имя, отчество и
фамилию). Так и в паскале – объекты программы не могут
обходиться без имени, или идентификатора.
Идентификатором может служить любая последовательность латинских букв и
цифр, начинающаяся с буквы, знака подчёркивания или символа &. Таким образом,
_i
Abcd
133
QWERTY
i_j
g56
o8j90
&int
это правильные имена для любых объектов программы. Но они годятся только в
качестве кодов к замкам, потому что не имеют никакого смысла, доступного человеческому разумению.
В паскале строчные и ПРОПИСНЫЕ буквы считаются одинаковыми, в отличие от
Си-шарпа. Поэтому идентификаторы
pascal
Pascal
PASCAL
PaScAl
обозначают один и тот же объект!
Идентификаторы должны отражать, в первую очередь, назначение объектов в
программе. Они могут состоять из нескольких слов, записанных слитно, но каждое слово должно начинаться с ПРОПИСНОЙ буквы, чтобы отделять слова друг
от друга. В качестве идентификаторов запрещено использовать ключевые
слова языка паскаль.
134
Строковые литералы
Вернёмся к нашей программе Привет:
begin
Writeln ('Привет, Мир!', 'Привет, Россия!');
Writeln;
Println('Привет, Мир!', 'Привет, Россия!');
Println;
end.
Любое строковое сообщение (строка) должно быть заключено в одинарные кавычки, но обратите внимание: сами кавычки в Окне вывода не печатаются (Рис.
1), они служат только для обозначения строк (string), или, как их ещё называют,
строковых литералов (string literals).
Рис. 1. Строковые литералы
Строковый литерал – это любая строка (последовательность) символов, взятая
в одинарные кавычки.
Термин литерал происходит от латинского слова литера,
litera – буква.
Литералы нельзя изменить в работающей программе (но в исходном коде это
вполне возможно), поэтому литералы называют также неименованными константами (о константах речь пойдёт дальше).
135
Итак, все строковые литералы – это символы, заключённые в одинарные кавычки.
Но литерал может состоять только из кавычек, вообще без символов – ''. Такая
строка называется пустой. При её печати в Окне вывода, естественно, ничего не
появится.
Двойные кавычки процедура Writeln напечатает без проблем (Рис. 2):
Writeln('Мы говорим: "Привет, Россия!" ');
Рис. 2. Двойные кавычки – обычный символ
А что делать, если нужно напечатать сами одинарные кавычки? – Для этого повторите кавычки дважды:
Writeln('Мы говорим: ''Привет, Россия!'' ');
В Окне вывода будут напечатаны и кавычки (Рис. 3).
Рис. 3. Сообщение с кавычками
136
Литералы других типов
Все строковые литералы состоят из отдельных символов – букв, цифр, математических знаков. Каждый символ в отдельности – это символьный литерал (character
literal). Символьные литералы так же, как и строки, записываются в одинарных кавычках, но они состоят из единственного символа:
// это символьный литерал:
'A'
Отдельная цифра в одинарных кавычках – это не однозначное число, а именно
символ:
// это символьный литерал:
'1'
Несколько цифр в одинарных кавычках – строковый литерал:
// это строковый литерал:
'12';
//это строковый литерал:
'2023'
Теперь вы легко догадаетесь, что целые числа, или целочисленные литералы
(integer literals) нужно записывать цифрами, но без кавычек:
// это числовой литерал:
1
// это числовой литерал:
2023
137
Кроме целых, в паскале имеются и вещественные (дробные) литералы (real
literals). Они отличаются от целых наличием десятичной точки в записи, которая
отделяет целую часть числа от дробной.
Будьте внимательны: обычно для этих целей используют
запятую, а не точку!
// это числовой литерал:
1.5
// это числовой литерал:
1.0
// это числовой литерал:
0.5
В паскале целые и вещественные числа – это разные типы
данных!
И наконец, в паскале имеются два особых, логических литерала – true (истина) и
false (ложь). Они обычно записываются в исходном коде строчными (маленькими) буквами, а печатаются с заглавной (Рис. 4):
WriteLn(true);
WriteLn(false);
Рис. 4. Логические литералы
138
По виду они похожи на слова, но без кавычек (вы можете взять их в кавычки, но
тогда они превратятся в строковые литералы!). Не путайте их со словами! Если все
остальные литералы мы можем придумывать сами, то логические литералы являются частью языка паскаль и потому называются также ключевыми словами.
К логическим литералам можно добавить ещё ключевое
слово-литерал nil.
Комментарии
Вы, конечно, заметили, что некоторые строчки присутствуют в исходном тексте,
но не печатаются в Окне вывода или в Консольном окне:
// это числовой литерал:
Такие строки называют комментариями. Комментарии нужны
для объяснения работы программы: себе - на память, другим программистам –
для облегчения понимания кода.
Чтобы закомментировать строку, нужно напечатать в её начале две косые черты
(их называют также слешами - от английского слова slash; это обычная дробная
черта /). Строка с таким комментарием (его называют однострочным), окрашивается в зелёный цвет и игнорируется компилятором.
Это значит, что вы можете писать в программе сколько угодно комментариев и
при этом ни один из них не попадёт в выполняемый файл программы – все комментарии компилятор пропускает.
Комментарии используются также при разработке и отладке программ, когда
нужно временно «устранить» часть кода. Если просто стереть несколько строк, то
потом их трудно возвратить на место – даже команда Отменить может вас подвести.
139
В этом случае следует закомментировать временно ненужные строки программы.
С одной строкой работы немного, но несколько десятков строк поштучно закомментировать, а потом раскомментировать будет уже довольно долго и утомительно.
Рассмотренный нами комментарий со слешами – однострочный и действует
только в той строке, в которой находится, – от слешей и до конца строки.
Чтобы закомментировать несколько соседних строк, используйте многострочный
комментарий. Он начинается открывающей фигурной скобкой {, а заканчивается
закрывающей фигурной скобкой }. Все строки между этими скобками становятся
закомментированными:
begin
{
// первая сторона прямоугольника:
var a := 0.0;
Write('Введите длину первой стороны прямоугольника: ');
Readln(a);
// вторая сторона прямоугольника:
var b := 0.0;
Write('Введите длину второй стороны прямоугольника: ');
readln(b);
var area := a * b;
WriteLine('Площадь
прямоугольника = ' + area);
// Read();
}
end.
Этим способом вы легко закомментируете, а затем и раскомментируете участок
кода любой длины.
Кстати говоря, «фигурный» комментарий более универсальный, чем «слешный»,
поскольку он действует только на текст, заключённый в фигурные скобки. Это значит, что такие комментарии можно вставлять в любое место строки. Например,
140
значение переменной b в программе должно равняться единице, но мы временно хотим присвоить ей другое значение – нулевое. Чтобы безошибочно восстановить потом прежний код, мы аккуратно берём старое значение в скобки и
подписываем новое:
var b := {1.0;} 0.0;
Теперь вернуться к первоначальному варианту не составит труда.
Однако в практике программирования однострочные комментарии используются
гораздо чаще многострочных. А поскольку это так, то во многих Редакторах кода
предусмотрена возможность разом закомментировать несколько строк.
Для этого перейдите на латинскую раскладку клавиатуры. Выделите нужные
строки и нажмите клавиши Ctrl + / (клавиатуры бывают разные, поэтому проверьте!). Чтобы раскомментировать ранее закомментированные строки, повторите эту операцию.
Точно так же вы можете закомментировать и одну строку, но её выделять не
нужно – достаточно установить текстовый курсор в любое место строки и выполнить клавиатурное сокращение.
Выражения
Печатать и придумывать литералы вы научились, но это
занятие не очень интересное: в Окне вывода вы видите
почти то же самое, что и в исходном коде (не считая
кавычек). Но из литералов и знаков операций можно
составлять выражения.
Давайте разбираться, как это делается в паскале! А начнём мы с определений:
Выражение (expression) – это запись (строка), состоящая из операторов, операндов и круглых скобок.
141
Оператор (operator), или знак операции – это символ (+ - * / < > = .), который
обозначает операцию.
Оператором может быть и пара символов (:= >= <= <>) и даже целое ключевое
(зарезервированные) слово языка паскаль (or, and, not и другие).
Операторы получают данные (операнды), производят над ними действия и
возвращают результат этих действий в программу.
Операции - это действия, которые применяются к объектам программы
(данным) - операндам (operand): к литералам, константам, переменным и
методам. Операнды называют также аргументами операций.
Мы можем представлять операнды как какие-либо данные: числа, строки или
символы. Например, из третьего определения следует, что литералы могут быть
операндами, или аргументами операций.
Самое простое выражение состоит из одного операнда, то есть даже отдельный
литерал - это уже выражение.
Более сложные выражения включают несколько литералов и называются константными выражениями, поскольку их значение компилятор может вычислить по
значениям входящих в него операндов (ведь они известны заранее).
Знаком операции (оператором), как следует из второго определения, может быть
известный вам знак плюс. В языке паскаль он используется с числами точно так
же, как и в арифметике, то есть обозначает операцию сложения, результатом которой является сумма чисел (то есть операндов, числовых литералов).
Проверим, как паскаль умеет считать!
При сложении двух нулей, мы должны получить нуль. На Рис. 5 вы этот нуль и
видите!
142
Рис. 5. По нулям!
Код программы должен быть таким:
begin
WriteLn(0 + 0);
end.
Зададим задачку сложнее (Рис. 6):
WriteLn(2 + 2);
Рис. 6. Детская задача
Опять верно!
Уже понятно, что такими примерами мы паскаль не напугаем, поэтому заставим
его решать очень «сложный» пример (Рис. 7):
WriteLn(2023 + 29417);
Рис. 7. Паскаль считать умеет!
Паскаль и с ним справляется без труда.
143
Между числами и знаками операций может быть любое
число пробелов, но допустимо печатать их и вплотную
друг к другу. Последний способ выражений сокращает запись,
но делает её трудно читаемой. Лучше между знаками операций и операндами ставить ровно 1 пробел.
При использовании зарезервированного слова в качестве
знака операции он должен быть отделён от операндов хотя
бы одним пробелом!
В первом определении говорится, что в выражениях можно использовать круглые
скобки.
В школьной математике наряду с круглыми () для тех же
целей употребляют квадратные [] и фигурные {} скобки.
Используют их и в паскале, но назначение их совсем другое.
Квадратные скобки нужны для обозначения элементов массива, а фигурные скобки в паскале применяются в многострочных комментариях.
Часто скобки используют не для изменения порядка вычислений, а для повышения «читабельности» длинных выражений (для группирования операндов).
Чтобы не отрываться от школьной жизни, мы решим примеры со скобками из разработки урока Житкевич Наталии Андреевны (Рис. 8):
WriteLn((457 + 705) + 2);
WriteLn((385 + 615) + 5);
144
Рис. 8. Скобки не помеха
Конечно, при сложении чисел скобки не нужны (если вы не хотите показать, как
именно группируются слагаемые для быстрого счёта, например), но паскаль правильно вычислил значения числовых выражений.
А вот строки ни на уроках арифметики, ни на уроках русского языка вам складывать наверняка не приходилось. А в паскале мы вполне можем найти «сумму» нескольких строковых литералов. Достаточно между ними расставить знак плюс.
Результат сложения строк (эту операцию называют также конкатенацией) – новая,
длинная строка, которая состоит из коротких строк (и отдельных символов), взятых в том же порядке, что и в выражении. Все кавычки и знаки операции сложения
из строк удаляются (Рис. 9):
WriteLn('Привет' + ',' + ' Россия!');
Рис. 9. Конкатенация строк
Если выражение в исходном коде слишком длинное, его можно разбить на несколько строк. Значение выражения при этом не изменяется:
WriteLn('Привет' +
145
',' +
' Россия!');
Символьные литералы также допускают операцию сложения. В результате получается строка, состоящая из этих символов (Рис. 10):
WriteLn('А' + 'Б');
Рис. 10. Сумма символов – строка
Операция сложения к логическим литералам не применяется.
Эти примеры показывают, что литералы разных типов ведут себя по-разному при
выполнении операций над ними.
Проект Необычное сложение
Вы научились находить сумму однотипных операндов: строк со строками, чисел с
числами и символов с символами, но зададимся вопросом: а можно ли, например, к строке прибавить число, и если можно, то какой результат мы получим?
Возьмём наш арифметический пример и добавим к нему поясняющую строку:
WriteLn(2023 + 29417 + ' - Сумма двух чисел');
146
Как вы видите на Рис. 11, паскаль позволяет складывать числа и строки, хотя они
разных типов!
Рис. 11. И так можно
Компилятор очень умный и самостоятельно превращает числа в строки, если они
записаны в процедурах печати.
Все числа имеют особый метод (функцию) ToString, который преобразует число в
строку. При желании вы можете применять его в своих программах:
WriteLn((2023+29429).ToString + ' - Сумма двух чисел');
Символы и строки также можно складывать без дополнительных преобразований
(Рис. 12):
WriteLn('А' + 'Б' + ' - Сумма двух символов');
Рис. 12. Сумма символов и строки
Делаем вывод: в процедурах печати можно складывать строки, символы и числа
в любых сочетаниях. При сложении строк с числами последние можно преобразовать в строку с помощью метода ToString.
В выражениях из строк и чисел важен порядок следования данных разного типа.
Как вы видели, если числовые выражения предшествуют строке, то они сначала
147
вычисляются, а затем преобразуются в строку. Если строка предшествует числовому выражению, то все числа в числовом выражении сразу превращаются в
строки, поэтому процедура WriteLn
WriteLn('Сумма двух чисел = ' + 2023 + 29417);
в этом случае напечатает сумму трёх строк (Рис. 13).
Рис. 13. Соблюдайте порядок!
Именованные константы
Константы в языке паскаль бывают двух видов –
именованные и неименованные, или явные. С
неименованными константами вы уже хорошо знакомы это литералы.
Именованные константы (их часто называют просто константами) сходны с
литералами – они также могут хранить данные разных типов: целочисленного,
вещественного, строкового, символьного и логического. Ни литералы, ни
именованные константы не могут изменить своего значения, которое они
получают при определении.
Главное отличие именованных констант от литералов отражено в их названии – к
ним можно обращаться по имени.
Своё имя константа получает при «крещении», которое в программировании
называется объявлением (declaration), или определением.
Возьмём неименованную константу (строковый литерал):
'Привет, Мир!'
148
Она имеет строковый тип, поскольку состоит из нескольких символов и заключена
в одинарные кавычки. Её значение – это строка внутри кавычек.
Дальше мы поговорим о типах данных более подробно, а сейчас вам достаточно
знать, что каждый тип данных обозначается ключевым словом языка паскаль:
Строковый – string (от string - строка)
Символьный – char (сокращение от character - символ)
Целочисленный – integer или System.Int32 (сокращение от integer - целый)
Вещественный – double (double – двойной (точности)), или real
(вещественный)
Логический – boolean (от фамилии английского математика Джорджа Буля –
George Boole)
Числовых типов в паскале значительно больше, чем здесь
упомянуто, но типы integer и double используются чаще
всего.
Именованные константы в языке паскаль объявляются в разделе описания
констант, перед главной программой. Этот раздел начинается с
зарезервированного слова const (сокращение от слова constant - постоянный).
Киноманы здесь могут вспомнить знаменитую сцену из замечательного фильма
Покровские ворота (Рис. 1).
Чтобы объявить (определить) константу, нужно записать её имя, затем поставить
знак равенства и, наконец, указать значение константы. Завершается объявление
точкой с запятой:
const
ИМЯ = значение;
149
Рис. 1. Мнемотехническая сцена
Константы, объявленные в разделе описания констант программы, называются
глобальными. Это значит, что ими можно пользоваться во всех процедурах и функциях программы.
Константы можно объявлять и в разделе описаний процедуры или функции –
перед телом подпрограммы, до операторных скобок begin-end. Такие константы
называются локальными и доступны только в самой подпрограмме. Запрещено
описывать константы внутри любого блока!
Значение константы, как мы уже выяснили, это литерал, константа или
константное выражение того же типа, что и сама константа. Оно определяет тип
именованной константы. Но вы можете самостоятельно указать тип (type)
константы после двоеточия:
const
ИМЯ : type = значение;
150
Идентификаторы
констант
часто
записывают
ПРОПИСНЫМИ буквами, чтобы выделить их в исходном
коде.
Теперь мы можем превратить литерал в именованную константу:
const
ПРИВЕТ: string = 'Привет, Мир!';
begin
end.
В этой записи мы найдём все атрибуты объявления констант:
Ключевое слово const
Тип константы - string
Её имя (идентификатор) – ПРИВЕТ
Знак присваивания =
Значение – строковый литерал 'Привет, Мир!'
Точку с запятой ;
Аналогично объявляются и константы других типов:
const
const
const
const
CH : char= 'Э';
NUM : integer = 12;
COST : double = 11.9;
FLAG : boolean = true;
Объявление константы - это уже не выражение, а инструкция объявления.
151
Так как разделов описания констант может быть сколько
угодно, то вы можете писать ключевое слово const в начале
каждого объявления.
Тип константы однозначно определяется типом литерала или константного
выражение, значение которого ей присваивается, поэтому тип константы
указывать необязательно (Рис. 2).
Рис. 2. Типичные константы
Проект Константы
При запуске программы Константы:
const
ПРИВЕТ = 'Привет, Мир!'
begin
end.
замечаний мы не получим, однако строка Привет, Мир! не появится в Окне
вывода.
Константы объявляются не просто так, а для их дальнейшего использования в
программе. Например, мы можем напечатать значение константы на экране (Рис.
1):
const
152
ПРИВЕТ = 'Привет, Мир!';
begin
Writeln(ПРИВЕТ);
end.
Рис. 1. Печатаем константу
Вместо идентификатора константы в выражениях или в
операторах всегда подставляется её значение! Поэтому команды печати
WriteLn(ПРИВЕТ);
и
WriteLn('Привет, Мир!');
для компилятора значат одно и то же.
Слово ПРИВЕТ, записанное без кавычек, это имя константы, а не строковый литерал!
Итак:
чтобы напечатать значение константы, вы должны сами об этом
позаботиться.
преимущество именованных констант перед явными состоит в том, что они
делают исходный код более понятным (особенно если константам дать
говорящие имена) и коротким (Рис. 2), а также облегчают модификацию
программы в случае необходимости.
const
ПРИВЕТ = 'Привет, Мир!';
153
begin
Writeln(ПРИВЕТ);
Writeln(ПРИВЕТ + ' ' + ПРИВЕТ);
end.
Рис. 2. Применение именованных констант
Пусть нам нужно написать программу, играющую в шашки. Доска имеет 8
вертикалей и 8 горизонталей. Если в исходном коде использовать числа, то эти
восьмёрки невозможно будет отличить от других восьмёрок, которые тоже могут
оказаться в коде. Да и вообще - число 8 никак не указывает на то, что это число
вертикалей на шахматной доске. Пусть нам удалось написать программу для игры
в обычные шашки. Но потом мы решили взяться за 100-клеточные шашки, а там
доска больше: 10 горизонталей и столько же вертикалей. Придётся
просматривать (и очень внимательно!) весь код и исправлять восьмёрки на
десятки.
Конечно, лучше сразу объявить две константы:
const MAX_ROW = 8; MAX_COL = 8;
В одной строке можно объявить через точку с запятой несколько констант.
Их же следует использовать и в тексте программы, тогда при переходе от русских
шашек к международным достаточно будет изменить только 2 числа в самом
начале программы, где их отыскать совсем нетрудно:
const MAX_ROW = 10; MAX_COL = 10;
154
Естественно, после этого программа не сможет играть в
международные шашки! Речь идёт только о размере доски,
а алгоритм игры изменится до неузнаваемости.
Продолжим наши эксперименты с константами и напечатаем константы разных
типов (Рис. 3):
const
const
const
const
CH = 'Э';
NUM = 12;
COST = 11.9;
FLAG = true;
const
ПРИВЕТ = 'Привет, Мир!';
begin
Writeln(ПРИВЕТ);
Writeln(ПРИВЕТ + ' ' + ПРИВЕТ);
Writeln(CH);
Writeln(NUM);
Writeln(COST);
Writeln(FLAG);
end.
Рис. 3. Константы разных типов
Как вы уже знаете, везде вместо идентификатора константы используется её значение, поэтому инструкции:
155
Writeln(NUM);
Writeln(12);
на промежуточном языке IL дадут одинаковый код! Таким образом, именованные
константы нужны программистам для удобства разработки программ, а компилятор легко обходится и без них.
Попробуем повторно объявить какие-либо константы – и компилятор напомнит
нам, что мы их уже объявили (Рис. 4).
Рис. 4. Нельзя повторно объявлять константу!
Константы под одним и тем же именем нельзя объявлять дважды.
Попробуем присвоить константе другое значение (или то же самое, но повторно).
Компилятор сообщает нам, что после идентификатора константы не может быть
знака присваивания (Рис. 5).
156
Рис. 5. Константе нельзя присвоить новое значение!
Константа всегда сохраняет то значение, которое она получила при объявлении.
Переменные
Гораздо чаще, чем именованные константы, в программах используются переменные (variables). Они также
имеют тип, идентификатор и значение, но, в отличие от
констант (и это закреплено в их названии), могут изменять своё значение в работающей программе.
Переменные в паскале могут быть глобальными, и тогда они объявляются в разделе описания переменных, обычно после глобальных констант. Раздел начинается с ключевого слова var, после которого следует список переменных с указанием их типа. Завершается каждое объявление точкой с запятой:
var
имя : type;
Однотипные переменные допускается записывать в одной строке через запятую:
157
var
имя1, имя2, имя3 : type;
Переменные можно объявлять и в разделе описания переменных процедуры или
функции – как и константы. Но, в отличие от констант, их разрешается объявлять
и непосредственно в том блоке, в котором они используются. Объявляются они
так же, но каждая строка объявлений должна начинаться с ключевого слова var.
Все переменные, описанные в подпрограмме, называются локальными. Если они
объявлены в разделе описаний, то доступны во всей подпрограмме. Если они
описаны в блоке, то доступны только в этом блоке.
Проект Переменные
Например, мы хотим завести переменную для хранения сообщений – объявляем
строковую переменную hallo:
var привет : string;
Идентификаторы переменных обычно записывают строчными буквами. Если они состоят из нескольких слов, то все
они, кроме первого, начинаются с Заглавной буквы.
Здесь мы указываем компилятору, что собираемся хранить в этой переменной
строку (тип string), а не число и не другие данные.
Обратите внимание: при объявлении переменной её значение можно не
указывать, компилятор паскаля самостоятельно присвоит ей значение по
умолчанию (для строковых переменных это пустая строка). Напечатать такую
строку можно, но на экране мы ничего не увидим. Все строки имеют свойство
Length, которое возвращает длину строки (число символов в ней) (Рис. 1).
158
Рис. 1. Длина строки
Добавляем в исходный код строку, которая печатает в Окне вывода длину строки.
Запускаем программу и убеждаемся, что строковая переменная при объявлении
получает знаение пустой строки (Рис. 2).
Рис. 2. По нулям
Физически переменная представляет собой область памяти компьютера, в
которой хранится её значение. Конечно, переменные не просто занимают место
в оперативной памяти компьютера - они хранят там какие-то данные, то есть свои
значения. Поэтому после объявления переменной ей следует присвоить
начальное значение. Это действие называется инициализацией переменной.
В Си-шарпе, например, все локальные переменные должны
быть проинициализированы самим программистом, поэтому лучше и в паскале поступать аналогично.
159
Инициализация переменной происходит в инструкции присваивания:
привет := 'Привет, Мир!';
Инструкция присваивания
Инструкция присваивания записывается так:
имя := выражение;
В языке программирования паскаль оператор присваивания состоит из двоеточия
и знака равенства. Так более понятно назначение этого оператора, однако в большинстве языков программирования оператор присваивания обозначается просто
знаком равенства, без двоеточия.
В результате выполнения этой инструкции значение переменной станет равным
значению выражения.
Выражением может быть другая переменная, литерал, константа, константное
выражение или выражение того же типа, что и сама переменная.
Действие инструкции присваивания заключается в том, что в зарезервированные
ячейки памяти записывается указанное (или вычисленное) значение переменной.
Все данные, которые там хранились раньше, стираются. Совершенно очевидно,
что в область памяти переменной могут быть записаны данные только того же
типа, что и тип переменной, и никакие другие, иначе компилятор не сможет ими
пользоваться!
Итак, после выполнения оператора присваивания переменная привет получила
значение правой части, то есть строку Привет, Мир!. Когда вы используете в программе идентификатор переменной, то компилятор подставляет вместо него те-
160
кущее значение переменной. Проверим это утверждение и напечатаем переменную в Окне вывода. На Рис. 1 вы видите значение переменной, то есть строку
Привет, Мир!.
Например:
Оператор присваивания
Результат присваивания значение переменной
var width : integer;
Width := 100;
100
var height : integer;
height := width + 20;
120
const OFFSET = 90;
var width : integer;
width := OFFSET + 100;
190
Инструкция присваивания
n := n + 2;
в которой и в левую, и в правую части входит одна и та
же переменная n, может вызвать недоумение, поскольку ни
при каких значениях n это «равенство» не может быть
верным! Здесь важно понять, как действует инструкция
присваивания:
- сначала вычисляется значение правой части инструкции
присваивания;
- затем это значение присваивается переменной в левой
части.
Например, если текущее значение переменной n равняется
трём, то значение правой части инструкции присваивания
161
равно 3 + 2 = 5. Оно присваивается переменной n в левой
части оператора присваивания, то есть её значение станет равным пяти.
Рис. 1. В программе используется текущее значение переменной
Пока переменная привет ведёт себя точно так же, как и константа. Но константа
всегда имеет то значение, которое она получила при объявлении, а значение
переменной можно изменять сколько угодно раз!
Давайте, передадим привет России. Для этого нам не нужно объявлять новую
переменную, мы просто присвоим переменной привет новое значение и
напечатаем его на экране (Рис. 2).
А теперь проверим бдительность компилятора и присвоим строковой
переменной привет числовое значение. Компилятор не может самостоятельно
преобразовать число в строку и выдаёт ошибку (Рис. 3).
162
Рис. 2. Переменной можно присвоить другое значение
Рис. 3. Не тот тип!
163
Как вы знаете. мы можем самостоятельно преобразовать число в строку с
помощью метода ToString, который имеется у всех типов данных:
привет := 2023.ToString;
Теперь значением переменной привет – это строка 2023 (не число!).
Инициализацию переменной часто проводят одновременно с её объявлением.
Эта операция называется определением переменной. В этом случае переменная
получает указанное значение, а не значение по умолчанию.
var привет2 := 'Привет, Мир!';
Всегда инициализируйте (локальную) переменную при её
объявлении!
Даже если вы пока не определились со значением переменной, присвойте ей
любое допустимое значение (например, пустую строку без символов - '' - для
строковых переменных или 0 (нуль) - для числовых):
var message := '';
var num := 0;
Определение переменной в общем виде можно записать так:
var имя : type := выражение;
Такая
«комбинированная»
инструкция
называется
ин-
струкцией инициализации.
164
Когда тип переменной совпадает с типом выражения, то её тип указывать не обязательно:
var имя := выражение;
Если тип переменной выводится из типа правой части инструкции присваивания, то такая переменная называется
неявно типизированной.
В Си-шарпе неявно типизированными могут быть только
локальные переменные, а в паскале и локальные, и глобальные.
Но тут нужно соблюдать осторожность, иначе переменная получит не тот тип, что
вы хотели. Например, переменная ch получит при инициализации символьный
тип. Это легко проверить, если установить текстовый курсор на её идентификаторе (Рис. 4).
Рис. 4. Неявно типизированная переменная символьного типа
А вы, возможно, хотели иметь переменную строкового типа. Но тогда вы должны
явно указать тип переменной (Рис. 5).
Рис. 5. Явно типизированная переменная строкового типа
Если в правой части оператора присваивания стоит целое число, то переменная
получит тип integer (Рис. 6).
Рис. 6. Целые числа имеют тип integer
165
Если вещественное - тип real (double) (Рис. 7).
Рис. 7. Вещественные числа имеют тип real/double
Если справа от оператора присваивания находится не литерал, а выражение, то
тип переменной определить сложнее, поэтому всегда контролируйте типы переменных!
Обобщение
Именованные константы и переменные имеют идентификатор, по которому к
ним можно обращаться в исходном коде. Идентификаторы констант принято
записывать ПРОПИСНЫМИ буквами, а переменных - строчными.
Идентификаторы должны отражать, в первую очередь, назначение объектов в
программе. Они могут состоять из нескольких слов, записанных слитно, но каждое слово должно начинаться с ПРОПИСНОЙ буквы, чтобы отделять слова друг
от друга. В качестве идентификаторов запрещено использовать ключевые
слова языка паскаль.
В программе вместо идентификаторов констант и переменных используются их
значения. Для констант – то значение, которое они получили при объявлении,
для переменных – их текущее значение.
Литералы – это неизменяемые (константные, фиксированные, постоянные) значения, которые могут быть:
Строковыми (несколько символов в одинарных кавычках: 'Строковый литерал')
Символьными (1 символ в одинарных кавычках: 'C')
Целочисленными (число без десятичной точки: 2023)
Вещественными (число с десятичной точкой: 2.023)
166
Логическими (true и false)
Выражения – это строки, состоящие из операндов (аргументов, данных), операторов (знаков операций) и круглых скобок.
Каждое выражение имеет тип (строковый, символьный, числовой, логический)
и значение этого типа, которое компилятор вычисляет, применяя к операндам
указанные операции (действия).
Порядок выполнения операций зависит от их приоритета (например, умножение и деление выполняются раньше сложения).
Порядок выполнений действий можно изменить с помощью круглых скобок.
Именованные константы и переменные перед их использованием должны
быть объявлены/определены.
Константы получают своё значение при объявлении и не могут изменить его.
Переменные получают своё начальное значение при инициализации – при
определении или в операторе присваивания после объявления. Затем они могут изменять его сколько угодно раз в операторе присваивания.
И константы, и переменные имеют тип, который они получают при объявлении/определении. Изменить свой тип они не могут. И константам, и переменным можно присвоить значение только их типа (или совместимого: например,
вещественным переменным допускается присваивать целые значения).
167
Числовые типы данных
Числовые типы данных используются практически во всех программах. В языке
паскаль, как и во многих других языках программирования, для различных целей
используют и разные числовые типы. Если числа небольшие, то для них
достаточно типа байт (byte), для чисел побольше уже нужен тип word, и так далее.
Но для большинства случаев достаточно четырёх числовых типов, которые
приведены в таблице.
Таблица <Числовые типы>
Тип
Диапазон значений
Объём памяти
integer
longint
-2147483648..2147483647
4 байта
Int64
-9223372036854775808..
9223372036854775807
8 байтов
single
±1.5*10-45 до ±3.4*1033
Точность – 7 разрядов
4 байта
double
real
±5*10-324 до ±1.7*10306
Точность –15-16 разрядов
8 байтов
Из целых типов чаще всего используют тип integer, а к типу int64 (длинное целое)
прибегают только тогда, когда имеют дело с очень большими числами.
В последней колонке таблицы указано число ячеек памяти (байтов), которые
необходимы для хранения чисел разных типов: чем большее значение должна
хранить переменная и/или чем оно должно быть точнее, тем больше потребуется
ячеек памяти. Но при выборе типов переменных вы должны учитывать не только
расход памяти для их хранения, но и скорость выполнения операций с ними.
Например, операции с целыми числами гораздо более быстрые, чем с
вещественными.
Во второй колонке вы видите, какие значения могут принимать переменные (или
константы) того или иного типа. Если задать переменным значения вне
168
указанного диапазона, то либо возникнет ошибка при выполнении программы,
либо результат вычислений будет неверным. Строго следите за значениями
переменных и правильно выбирайте их тип!
У каждого целого знакового типа (например, integer и int64) имеется беззнаковый
«двойник» (соответственно, longword = cardinal и uint64). Эти типы могут
принимать только неотрицательные значения, но зато у них максимальные
положительные значения в 2 раза больше, чем у знаковых.
Знаковые типы употребляются в программировании значительно чаще, чем беззнаковые, даже когда заведомо известно, что они должны принимать только неотрицательные значения. Беззнаковые типы предпочтительнее, когда
переменные могут принимать большие положительные
значения.
Глядя на вторую и третью колонку таблицы, вы легко сделаете вывод, что в
программе невозможно хранить очень большие целые числа – они займут в
памяти слишком много места. То же самое относится и к вещественным числам,
хотя они могут быть гораздо больше целых. При этом вещественные числа имеют
совсем немного значащих цифр. Из этого следует, что очень большие целые и/или
вещественные числа могут быть представлены в программах только
приблизительно.
Проект Числовые типы
Таблицу числовых типов не обязательно хранить в голове, всю нужную
информацию вы можете получить с помощью констант MinValue, MaxValue и
оператора sizeof (Рис. 1).
begin
WriteLn(' Диапазон значений типа integer: ' + integer.MinValue +
169
'..' + integer.MaxValue);
WriteLn(' Диапазон значений типа int64: ' + int64.MinValue + '..' +
int64.MaxValue);
WriteLn(' Диапазон значений типа single: ' + single.MinValue + '..'
+ single.MaxValue);
WriteLn(' Диапазон значений типа double: ' + double.MinValue + '..'
+ double.MaxValue);
WriteLn;
WriteLn(' Длина в байтах типа int: ' + sizeof(integer));
WriteLn(' Длина в байтах типа int64: ' + sizeof(int64));
WriteLn(' Длина в байтах типа single: ' + sizeof(single));
WriteLn(' Длина в байтах типа double: ' + sizeof(double));
end.
Рис. 1. Полная информация
В языке паскаль имеются также константы MaxInt, MaxInt64, MaxReal, MaxDouble
и MaxSingle.
Целые типы
Типы integer и int64 предназначены для хранения целых
чисел. Это самые «востребованные» типы данных! Можно
смело утверждать, что ни одна программа не обходится без
них.
170
Большое преимущество целых типов перед вещественными состоит не только в
том, что процессор быстрее их «переваривает», но прежде всего в том, что они
хранят точные значения, а вещественные – приближённые.
Тип integer вы уже изучили, поэтому обратимся к типу int64. Переменные этого
типа объявляются с использованием ключевого слова int64:
var lng: int64;
Объявление переменных типа int64 можно совмещать с их инициализацией. В
данном операторе объявление переменной типа int64 сочетается с её
инициализацией целочисленным литералом типа integer:
var lng: int64 := 100;
Никакого беспокойства такое смешение типов у компилятора не вызовет – он самостоятельно преобразует значение типа integer к типу int64.
В результате объявления и инициализации компилятор выделит переменной lng
для её хранения 8 байтов памяти и сохранит там число 100. Это значит, что теперь
для программы имя переменной lng и её значение - число 100 - это одно и то же.
Аналогично – и для других числовых переменных.
Если же значение литерала (не выражения!) в правой части оператора присваивания превышает возможности типа integer, то переменная автоматически получит тип int64:
var lng := 2147483648;
Итак, инструкции определения переменных ясно говорят компилятору, сколько
ячеек памяти он должен отвести для каждой переменной, какие данные в них записать, и что за данные в них находятся.
171
Тип данных также позволяет определить, какие операции
(действия) можно проводить с переменными. Так, числа
можно перемножать, а строки - нельзя. И к числам, и к
строкам можно применять операцию сложения, но выполняется она по-разному.
Вещественные (действительные) типы
Переменные типов single и double используются для хранения чисел с десятичной точкой, которая отделяет целую часть действительного числа от дробной.
В математике ставят запятую, так что будьте внимательнее!
Объявляются и инициализируются переменные типа single и double так же, как и
переменные целого типа:
// ВЕЩЕСТВЕННЫЕ ТИПЫ
begin
WriteLn(' Переменные типа double: ');
var d1: double := 0;
var d2: double := -1;
var d3: double := 1;
var d4: double := 3.14;
var d5: double := 3.14159265358979323846;
var d6: double := 0.5;
WriteLn(' d1 = ' + d1);
WriteLn(' d2 = ' + d2);
WriteLn(' d3 = ' + d3);
WriteLn(' d4 = ' + d4);
WriteLn(' d5 = ' + d5);
172
WriteLn(' d6 = ' + d6);
WriteLn;
WriteLn(' Переменные типа single: ');
var f1: single := 0;
var f2: single := -1;
var f3: single := 1;
var f4: single := 3.14;
var f5: single := 3.14159265358979323846;
var f6: single := 0.5;
WriteLn(' f1 = ' + f1);
WriteLn(' f2 = ' + f2);
WriteLn(' f3 = ' + f3);
WriteLn(' f4 = ' + f4);
WriteLn(' f5 = ' + f5);
WriteLn(' f6 = ' + f6);
end.
Все числа с десятичной точкой имеют тип double, поэтому тип переменных single
нужно указывать явно.
Запускаем программу – все числа напечатаны правильно (Рис. 1).
Рис. 1. Переменные типа double и single
173
Как и следует из таблицы, значение переменной f5 округлено до семи значащих
цифр.
У всех вещественных чисел количество правильных десятичных знаков уменьшается с ростом целой части числа, поэтому для «тонких» расчётов используйте тип double, а
не single.
Значения переменных вещественных типов всегда приблизительные!
Арифметические операции
С операцией сложения вы уже познакомились, но над числовыми литералами,
константами и переменными можно производить и другие арифметические действия:
Знак операции
Операция
+
Сложение
-
Вычитание
*
Умножение
**
Возведение в степень
/
Вещественное деление
div
Целочисленное деление
mod
Остаток от деления целых чисел
174
Операции сложения, вычитания, умножения и деления вы
хорошо знаете, но, наверное, заметили, что некоторые знаки
арифметических операций в программировании отличаются
от обычных. Так, знак умножения в виде крестика или точки
здесь заменён звёздочкой (её также называют астериском;
не путайте с героем мультиков Астериксом!), а двоеточие –
знак деления – дробной чертой (слешем). Это объясняется
тем, что знака умножения нет на клавиатуре, а двоеточие используется для других
целей.
Операция mod возвращает остаток от деления первого целого числа на второе.
Она называется также делением с остатком или делением по модулю.
Ключевое слово mod – это сокращение слова modulе.
Результат операции вещественного деления / всегда имеет тип double. Операнды
могут быть любого числового типа.
Результат целочисленного деления div - всегда целое число, округлённое до ближайшего целого: положительные числа при этом уменьшаются, отрицательные –
увеличиваются. Операнды должны быть целого типа.
Результат операции возведения в степень a ** b = ab всегда имеет тип double.
Эти арифметические операции относятся к бинарным, поскольку для их выполнения нужны два числа (операнда, аргумента), между которыми и ставят знак операции (Рис. 1).
Рис. 1. Арифметические операции
175
Проект Арифметика паскаля
Результат выполнения операции должен быть использован в программе, например, присвоен переменной. Наберите строчку:
2 + 3;
и при запуске программы вы получите сообщение об ошибке (Рис. 1).
Рис. 1. Арифметическое выражение это не инструкция
Если же результат присвоить константе или переменной или использовать в процедуре печати Writeln, то никаких нареканий со стороны компилятора уже не будет (Рис. 2):
const ПЯТЬ = 2 + 3;
begin
//2 + 3;
WriteLn(ПЯТЬ);
176
var пяток := 2 + 3;
WriteLn(пяток);
WriteLn(2 + 3);
end.
Рис. 2. Выражение должно быть использовано в инструкции
Знаки плюс и минус могут применяться и к отдельному
числу (одному операнду), в этом случае они называются
унарными. Знак минус служит для изменения знака выражения: 2 -2;
x -x. Унарный плюс только «украшает»
число, но никаких операций с ним не производит. Он оставлен в языке паскаль только для симметрии со знаком минус
и практически не употребляется.
Унарные операции выполняются раньше бинарных, кроме
операции возведения в степень (имеют более высокий приоритет).
Рассмотрим примеры. Пусть:
begin
var a := 6;
var b := 3;
var num: integer;
Тогда значение переменной num после выполнения арифметических операций:
num := a;
177
WriteLn(' a = ' + num);
num := b;
WriteLn(' b = ' + num);
WriteLn;
num := a + b;
WriteLn(' a + b = ' + num);
num := a - b;
WriteLn(' a - b = ' + num);
num := a * b;
WriteLn(' a * b = ' + num);
num := integer(a ** b);
WriteLn(' a ** b = ' + num);
num := integer(a / b);
WriteLn(' a / b = ' + num);
num := a div b;
WriteLn(' a div b = ' + num);
num := a mod b;
WriteLn(' a mod b = ' + num);
WriteLn;
num := -a;
WriteLn(' -a = ' + num);
num := +b;
WriteLn(' +b = ' + num);
end.
будет равно - (Рис. 3).
Здесь мы обошлись единственной переменной num, а констант
понадобилось бы 7 штук! Более того, выражение для значения
константы при её объявлении не может включать переменные,
поскольку они могут иметь разные значения – здесь допустимы
только константные выражения.
Рис. 3. Арифметические операции с участием переменных
178
С другой стороны, значения переменных a и b в программе
не изменяются, поэтому их можно заменить константами.
Подумайте, как нужно изменить код, чтобы не понадобились ни константы, ни переменные.
При вычислении выражений учитывается приоритет операций – точно так же, как
и в математике. Сначала слева направо выполняются операции возведения в степень, умножения, деления и деления по модулю, а затем сложения и вычитания:
Операция
**
+ - Унарные
* / div mod
+ - Бинарные
:=
Изменить порядок вычислений можно с помощью круглых скобок (не квадратных
и не фигурных!). В полном согласии с правилами арифметики, сначала выполняются операции в скобках, а затем все остальные (Рис. 4):
var n := 0.0;
n := (2 + 4 - 1) / 5 * 11;
WriteLn(' (2 + 4 - 1) / 5 * 11 = ' + n);
n := 3 * 4 + 5 - 6/2;
WriteLn(' 3 * 4 + 5 – 6/2 = ' + n);
Рис. 4. Скобки изменяют порядок вычисления выражений
179
Целочисленным переменным (и константам) нельзя присваивать вещественные
значения:
var num: integer := (3.1415 - 1.0) / 7.78 * (45 - 7); ОШИБКА!
Таким образом, если в выражение входит хотя бы одно вещественное число (с
десятичной точкой – тип double) или присутствует операция деления /, то результат выражения - вещественное число. Если вы хотите присвоить вещественное
значение целочисленной переменной, то вы должны самостоятельно (явно) преобразовать его к целому типу. Для этого необходимо всё выражение взять в
скобки и спереди приписать функцию Trunc, Floor, Round или Ceil:
var numi : integer := Trunc((3.1415 - 1.0) / 7.78 * (45 - 7));
На Рис. 5 вы видите округлённые значения вещественных выражений, которые
получаются отбрасыванием дробной части вещественных значений:
num := Trunc((3.1415 - 1.0) / 7.78 * (45 - 7));
WriteLn(' (3.1415 - 1.0) / 7.78 * (45 - 7) = ' + num);
num := Trunc(-2.67 * 3.14 + -3 / 2 - 7.01);
WriteLn(' -2.67 * 3.14 + -3/2 - 7.01 = ' + num);
Рис. 5. Приведение числовых типов
Чтобы привести вещественное значение к целому типу, вы можете использовать
оператор integer, который отбрасывает дробную часть вещественного числа:
num := integer(-2.67 * 3.14 + -3 / 2 - 7.01);
180
Если вы хотите получить вещественные значения («точные»), то должны взять переменную типа double. Но если вы попробуете изменить тип переменной num, то
компилятор выдаст сообщение об ошибке (Рис. 6).
Рис. 6. Тип переменной изменить нельзя
Нельзя повторно объявить переменную с тем же именем и нельзя изменить тип
переменной, который она получила при объявлении/определении!
Исправьте имя переменной и присвойте ей вещественные значения (Рис. 7):
var dnum: double;
dnum := (3.1415 - 1.0) / 7.78 * (45 - 7);
WriteLn(' (3.1415 - 1.0) / 7.78 * (45 - 7) = ' + dnum);
dnum := -2.67 * 3.14 + -3/2 - 7.01;
WriteLn(' -2.67 * 3.14 + -3/2 - 7.01 = ' + dnum);
Рис. 7. Переменная типа double
Комбинированные операторы присваивания
В программировании очень часто требуется изменить
значение какой-либо переменной. На этот случай в паскале имеются операторы присваивания, совмещённые с
181
арифметическими, которые позволяют изменить значение переменной на любую
величину:
var n := 0;
n += 2;
var m := 3;
n -= m;
Комбинированные операторы присваивания представляют собой сокращённую
запись арифметической операции и оператора присваивания.
Таблица <Комбинированные операторы присваивания>
Оператор
+=
Операция
n += 3;
Эквивалент
n := n + 3;
-=
*=
n -= 2;
n *= 3;
n := n - 2;
n := n * 3;
/=
n /= 2;
n := n / 2;
Итак, оператор присваивания := просто помещает вычисленное значение выражения (справа от него) в переменную (слева от него), а комбинированный:
сначала применяет соответствующий арифметический оператор;
затем присваивает значение переменной.
Поскольку эти операции проводятся над данными в одном и
том же месте памяти, то оба пункта выполняются одновременно, то есть очень быстро.
182
Операция /= не применяется к целым типам.
Комбинированных операторов для операторов div, mod и **
не существует.
Проект Комбинированная арифметика
В небольшой программе мы испытаем все арифметические комбинированные
операторы присваивания:
// Комбинированные операторы присваивания
begin
var n := 21;
WriteLn('n = ' + n);
n += 3;
WriteLn('n += 3 --> n = ' + n);
WriteLn;
n := 21;
WriteLn('n = ' + n);
n -= 3;
WriteLn('n -= 3 --> n = ' + n);
WriteLn;
n := 21;
WriteLn('n = ' + n);
n *= 3;
WriteLn('n *= 3 --> n = ' + n);
WriteLn;
var d := 21.0;
WriteLn('d = ' + d);
d /= 3;
183
WriteLn('d /= 3 --> d = ' + d);
WriteLn;
end.
Рис. 1 показывает результаты применения этих операторов к переменным n и d.
Рис. 1. Комбинированные операторы присваивания
Преобразования числовых типов
Без труда не вынешь рыбку из пруда!
Программистская пословица
Чтобы не запутаться в преобразованиях типов, пользуйтесь таблицей.
Таблица <Преобразования числовых типов>
integer int64
single
double
integer integer int64
single
double
int64
int64
int64
single
double
single
single
single
single
double
double double double double double
184
В бинарной операции участвуют 2 числовых операнда. Тип результата операции
определяется старшим типом этих операндов, если считать тип integer самым
младшим, а тип double – самым старшим. Это хорошо видно в таблице. Также
следует учитывать, что тип результата вещественного деления / всегда имеет тип
double.
Объявляем 4 переменные разных типов:
var
var
var
var
i: integer := 1;
i64: int64 := 2;
f: single := 3;
d: double := 4.0;
Тогда тип переменной v – integer, если в правой части оператора присваивания
находится единственная переменная этого типа:
var v := i;
Если в правую часть выражения добавить переменную типа int64, то тип всего
выражения и переменной v2 также станет int64:
var v2 := i + i64;
Добавим к выражению переменную типа single – и всё выражение примет тип single:
var v3 := i + i64 + f;
И наконец, переменная типа double превращает всё выражение в тип double:
var v4 := i + i64 + f + d;
185
Вещественные типы могут хранить значения, которые слишком велики для целых
типов, поэтому типам integer и int64 нельзя присваивать вещественные значения.
Это значит, что целочисленные литералы не должны содержать десятичной
точки, а если справа стоит вещественная переменная, то необходимо явное преобразование (приведение) (explicit) с помощью функций Trunc, Floor, Round или
Ceil или оператора integer. Это преобразование приводит к уменьшению точности, так как дробная часть числа теряется.
Значения типа integer можно присваивать переменным типа int64, single и double.
В этом случае неявные преобразования выполняются автоматически (implicit). Однако числа типа integer могут иметь больше значащих цифр, чем числа типа single,
поэтому преобразование может привести к уменьшению точности.
Значения типа int64 можно присваивать типам integer, single и double. Но если
число имеет больше значащих цифр, чем могут хранить эти типы, преобразование
приведёт к уменьшению точности. Переменные типа integer не могут хранить
большие значения, доступные типу int64, поэтому могут получить неверные значения (Рис. 1):
var vi64 := int64.MaxValue;
Writeln('vi64 = ' + vi64.ToString);
var vi := 0;
vi := vi64;
Writeln('vi = ' + vi);
Рис. 1. Ошибка вышла
Значение типа single можно присваивать переменным типа double.
Значение типа double можно присваивать переменным типа single. При этом преобразовании число округляется до ближайшего числа типа single. Если оно выходит за границы допустимого диапазона, то значение будет равно нулю или бесконечности.
186
Как вы видите, преобразование типов требует аккуратности и понимания выполняемых в программе действий. Обычно для проверки правильности работы программы используют тестовые примеры, результат которых известен заранее. Если
программа выдаёт результаты, отличные от тестовых, то надо искать ошибку.
Обобщение
Числовые типы используются во всех программах на языке паскаль. Чаще всего
это:
Обычные целые числа типа integer
Длинные целые числа типа int64
Вещественные числа нормальной точности типа single
Вещественные числа двойной точности типа double
Над числами можно проводить арифметические операции:
Возведения в степень
Сложения
Вычитания
Умножения
Деления
Целочисленного деления
Деления по модулю
При этом учитывается приоритет операций: сначала выполняются слева
направо фиолетовые и красные операции, затем – зелёные. Порядок вычислений может быть изменён с помощью круглых скобок.
В унарных операциях участвует один операнд, в бинарных - два.
Арифметические операторы могут быть совмещены с оператором присваивания, в результате чего получаются комбинированные операторы присваивания,
которые сначала выполняют арифметическую операцию, а затем присваивают
переменной её результат.
187
Переменным можно присваивать значение того же типа.
Если тип данных отличается от типа переменной, то он преобразуется к нужному типу.
Автоматическое преобразование типов называется неявным (implicit).
Явные преобразования (explicit), или приведения выполняются с помощью
функций Ceil, Floor, Round и Trunc, а также оператором приведения integer.
Тип выражения определяется операндом самого длинного типа.
188
Решение арифметических задач и вычисления
по формулам
Мы рассмотрели структуру простой программы на паскале. Это операторные
скобки begin – end. И инструкции внутри них:
begin
var vi := 12;
Writeln('vi = ' + vi);
end.
Поскольку вся программа заключена в операторные скобки, то в новых версиях
паскаля можно обойтись без них. Но тогда в начале программы необходимо напечатать 2 решётки ##, которые переведут систему программирования в командный
режим.
Проект Тест по арифметике
Арифметика – она и в Африке арифметика, поэтому мы решим несколько задач из
книги Get Ready! for Standardized Tests Math Grade 3 (Рис. 1).
Рис. 1. Обложка книги
189
Задачи, конечно, очень простые, но они вполне годятся для закрепления навыков
по вычислению выражений, которые встречаются практически в каждой программе.
Итак, задания первого теста:
322 + 409 + 786 + 250
16 + 27 + 87 +34
456 + 985
3626 + 7597
4.36 + 8.98
Как вы видите, все они на сложение. Числа во всех примерах, кроме последнего,
- целые. Следовательно, сумма также будет целым числом. Когда нет веских оснований, для целочисленного результата нужно выбирать тип integer. В последнем примере оба числа, а значит и их сумма имеют тип double.
Если вам нужно только узнать сумму чисел, то это можно сделать непосредственно в методе печати, но обычно результат вычислений используют в программе, поэтому мы присвоим его переменной, значение которой затем и напечатаем.
Поскольку никаких сложностей с определением типа результата мы не видим, то
можем использовать неявно типизированные переменные:
## // КОМАНДНЫЙ РЕЖИМ!
var
var
var
var
var
sum1
sum2
sum3
sum4
sum5
WriteLn('
WriteLn('
WriteLn('
WriteLn('
WriteLn('
:=
:=
:=
:=
:=
322 + 409 + 786 + 250;
16 + 27 + 87 + 34;
456 + 985;
3626 + 7597;
4.36 + 8.98;
322 + 409 + 786 + 250 = ' + sum1);
16 + 27 + 87 + 34 = ' + sum2);
456 + 985 = ' + sum3);
3626 + 7597 = ' + sum4);
4.36 + 8.98 = ' + sum5);
190
На Рис. 2 вы видите, что все задачи для третьего класса компьютер решил верно.
Рис. 2. Сплюсовали
Обращает на себя внимание отсутствие примера на сложение целых чисел с вещественными, поэтому мы переделаем ещё один пример из этой книги под свои
нужды:
3626 + 7.597
Понятно, что сумма получит тип double. Это легко проверить, если установить курсор на идентификаторе переменной (Рис. 3).
var sum6 := 3626 + 7.597;
WriteLn(' 3626 + 7.597 = ' + sum6);
Рис. 3. Узнаём тип данных
На этом первый тест можно считать законченным (Рис. 4).
Рис. 4. Оттестировались
191
Проект Вычитаем
Теперь давайте решим несколько примеров на вычитание, которые для людей
труднее, чем на сложение, а компьютеру – всё едино:
600 – 286
724 − 382
3957 - 9004
23.60 − 9.57
9004 – 3.957
В этих примерах нет ничего нового для нас по сравнению с предыдущей порцией
(Рис. 1):
##
var
var
var
var
var
sub1
sub2
sub3
sub4
sub5
WriteLn('
WriteLn('
WriteLn('
WriteLn('
WriteLn('
:=
:=
:=
:=
:=
600 - 286;
724 - 382;
3957 - 9004;
23.60 - 9.57;
9004 - 3.957;
600 – 286 = ' + sub1);
724 − 382 = ' + sub2);
3957 - 9004 = ' + sub3);
23.60 − 9.57 = ' + sub4);
9004 – 3.957 = ' + sub5);
Рис. 1. Положительное вычитание
192
Проект Умножаем
В книге я нашёл всего один пример на умножение, достойный нашего внимания,
поэтому остальные примеры мы «смастерим» из примеров на вычитание:
6 * 537
724 * 382
3957 * 9004
23.60 * 9.57
9004 * 3.957
И опять же достаточно переделать предыдущий проект (Рис. 1):
##
var
var
var
var
var
mul1
mul2
mul3
mul4
mul5
WriteLn('
WriteLn('
WriteLn('
WriteLn('
WriteLn('
:=
:=
:=
:=
:=
6 * 537;
724 * 382;
3957 * 9004;
23.60 * 9.57;
9004 * 3.957;
6 * 537 = ' + mul1);
724 * 382 = ' + mul2);
3957 * 9004 = ' + mul3);
23.60 * 9.57 = ' + mul4);
9004 * 3.957 = ' + mul5);
Рис. 1. Преумножаем знания
193
Проект Градусник
Самые интересные примеры, конечно, на деление, но в тестовой книге они лишком просты даже для компьютера, поэтому мы решим практически важную задачу:
Мы привыкли измерять температуру в градусах Цельсия, а американцы для
этого используют градусы Фаренгейта.
Если известна температура по Цельсию, то для пересчёта температуры в градусы Фаренгейта можно воспользоваться формулой:
F = C * 9 / 5 + 32
(1)
А вот формула для обратного пересчёта:
C = (F - 32) * 5 / 9 (2)
Температура может выражаться и целыми, и вещественными числами.
Предположим, что мы имеет конкретное значение температуры в градусах
Цельсия. Тогда для вычисления температуры по Фаренгейту мы воспользуемся формулой (1).
Температура может быть представлена и целым, и вещественным числом. К
тому же в формуле присутствует вещественное деление /, поэтому результат
вычислений – число типа double.
Задавать, конечно, лучше не произвольную температуру в градусах Цельсия, а
вполне определённую. Например, температуру замерзания и кипения воды, а
также нормальную температуру человеческого тела. Дополнительно мы узнаем,
при какой температуре градусы Цельсия и Фаренгейта сравняются:
##
var c := 0;
var f := c * 9 / 5 + 32;
194
Write(' Градусы Цельсия: ' + c);
WriteLn(' Градусы Фаренгейта: ' + f);
c := 100;
f := c * 9 / 5 + 32;
Write(' Градусы Цельсия: ' + c);
WriteLn(' Градусы Фаренгейта: ' + f);
var cd := -40.0;
f := cd * 9 / 5 + 32;
Write(' Градусы Цельсия: ' + cd);
WriteLn(' Градусы Фаренгейта: ' + f);
cd := 36.6;
f := cd * 9 / 5 + 32;
Write(' Градусы Цельсия: ' + cd);
WriteLn(' Градусы Фаренгейта: ' + f);
А вот и ответы (Рис. 1).
Рис. 1. Компьютерный градусник
Особенно забавно, что температура тела по Фаренгейту почти 100 градусов.
Градусы Фаренгейта в градусы Цельсия нам переводить ни к чему, но одну температуру в этих градусах должен знать каждый современный человек.
Как сейчас принято говорить, в культовом романе Рэя Бредбери 451 градус по Фаренгейту (Рис. 2), рассказывается о печальном будущем человечества, когда все
книги, заставляющие думать, будут сжигать. 451 градус по Фаренгейту – это как
раз температура воспламенения бумаги.
195
Рис. 2. Обложки книг Рэя Бредбери
Что касается будущего, то оно уже наступило (роман был впервые издан в 1953
году, так что ждать пришлось недолго). Правда, для этого книги сжигать не пришлось – тут классик жанра ошибся…
А нам только и остаётся, что перевести градусы Фаренгейта в градусы Цельсия
(Рис. 3):
// 451 градус по Фаренгейту
var Far := 451;
var cel := (Far - 32) * 5 / 9;
Write(' Градусы Фаренгейта : ' + far);
WriteLn(' Градусы Цельсия: ' + cel);
Рис. 3. Будет жарко!
196
Проект Картинная задача
На картине русского художника Николая Петровича Богданова-Бельского Устный
счёт. В народной школе С.А. Рачинского (1895) вы можете видеть интересное
арифметическое выражение (Рис. 1).
Рис. 1. Картина и арифметический пример
В журнале Наука и жизнь, № 7 за 2006 год, на страницах 50-51 обсуждаются способы устного решения этой задачи.
Числа, использованные в примере, называют последовательностями Рачинского.
Они состоят из идущих подряд квадратов чисел, которые можно разбить на 2
группы с равными суммами так, чтобы во второй группе было на 1 число меньше,
чем в первой:
197
Мы не будем отыскивать последовательности Рачинского, а всего лишь решим
картинную задачу. Впрочем, уже очевидно, что результат равен двойке.
Эта задача интересна для нас тем, что в ней присутствуют квадраты чисел. Обычно
возведение в квадрат заменяют умножением – так и вычисления идут быстрее, и
результат получается точнее:
##
var res := (10*10 + 11*11 + 12*12 + 13*13 + 14*14) / 365;
Write(' Ответ: ' + res);
В данном случае мы точно знаем, что результат должен быть целым числом, иначе
в уме задачу вряд ли можно было бы решить, поэтому вещественное деление
можно заменить целочисленным:
var resi := (10*10 + 11*11 + 12*12 + 13*13 + 14*14) div 365;
Write(' Ответ: ' + resi);
Тип результата res в первом случае – double, во втором – integer, хотя в Окне вывода в обоих случаях мы увидим – двойку (Рис. 2)!
Рис. 2. Опять двойка
В этой задаче есть небольшая «тонкость»: числитель – это сумма произведений,
поэтому всё выражение в числителе нужно взять в скобки.
Чтобы получить третью двойку в одном проекте, давайте заменим умножение
возведением чисел в квадрат:
var resd := (10**2 + 11**2 + 12**2 + 13**2 + 14**2) / 365;
Write(' Ответ: ' + resd);
Предоставляю вам возможность и право самостоятельно получить двойку!
198
Проект Громоздкое выражение
А сейчас мы решим задачу, абсолютно оторванную от жизни. Ни в какой реальной
программе вы не столкнётесь с таким выражением (Рис. 1).
Рис. 1. Короче!
Я нашёл его в книге Практикум программирования на Turbo
Pascal.
Тип результата здесь очевиден – это double. Но эта задача хороша тем, что показывает, как использовать при вычислении сложных выражений вспомогательные
переменные.
Никогда не вычисляйте длинные выражения в одну строку! Написать её без ошибок очень трудно, а найти ошибки – ещё труднее. Разбивайте выражение на составные части, находите промежуточные значения и сохраняйте их во вспомогательных переменных.
В предложенном примере числитель довольно прост, поэтому мы можем целиком вычислить его:
var a := (7 - 6.35) / 6.5 + 9.9;
Знаменатель разумно разбить на 2 части:
var b := 1.2 / 36 + 1.2 / 0.25 - (1 + 5 / 16);
var c := 7 + 1 / 24;
199
Теперь мы без труда решим задачу:
var res := a / (b / c);
Write(' Ответ: ' + res);
Судя по ответу (Рис. 2), числа для выражения взяты не с потолка, а тщательно подобраны:
##
var a := (7 - 6.35) / 6.5 + 9.9;
var b := 1.2 / 36 + 1.2 / 0.25 - (1 + 5 / 16);
var c := 7 + 1 / 24;
var res := a / (b / c);
Write(' Ответ: ' + res);
Рис. 2. Целое значение
Проект Вспомогательные переменные
Очень часто вспомогательную переменную используют при обмене значениями
двух переменных.
Пусть это будут переменные a = 1 и b = 2. После обмена их значения должны тать
такими: a = 2, b = 1.
Понятно, что если мы совершим обмен наивным способом:
a := b;
b := a;
200
то обе переменные получат значение переменной b, поскольку переменная а потеряет своё значение после первого присваивания. Это значит, что перед этим его
нужно сохранить во вспомогательной (или временной, temporal; отсюда обычное
имя для таких переменных - tmp):
##
var a := 1;
var b := 2;
WriteLn(' a = ' + a + ' b = ' + b);
// вспомогательная переменная:
var tmp := a;
// обмениваем значения переменных a и b:
a := b;
b := tmp;
WriteLn(' a = ' + a + ' b = ' + b);
Со вспомогательной переменной обмен выполнен верно (Рис. 1).
Рис. 1. Правильный обмен
Более сложная обменная задача: циклически обменять значения трёх переменных.
На первый взгляд может показаться, что здесь не обойтись без двух вспомогательных переменных, но на самом деле достаточно и одной:
##
var a := 1;
var b := 2;
var c := 3;
Println(' a =', a, 'b =', b, 'c =', c);
201
// вспомогательная переменная:
var tmpa := a;
// обмениваем значения переменных a, b и с:
a := c;
c := b;
b := tmpa;
Println(' a =', a, 'b =', b, 'c =', c);
Рис. 2 показывает, что и второй обмен на исполнен без обмана.
Рис. 2. Циклический обмен
Подумайте, годится ли этот способ для циклического обмена значениями произвольного числа переменных.
Ещё одна известная задача со вспомогательными переменными - возведение в
степень с наименьшим числом умножений.
Значение переменной a можно задать любым, потому что оно нас в этой задаче
не интересует.
Во вспомогательную переменную tmpa помещаем a2. После первого умножения
переменной tmpa на себя её значение станет равным a4, а после второго – а8:
##
var a := 11;
// вспомогательная переменная:
var tmpa := a * a;
// вычисляем 8-ю степень:
tmpa *= tmpa;
202
tmpa *= tmpa;
Println(' a =', a, 'a8 =', tmpa);
Итак, нам понадобилось всего 3 умножения, чтобы возвести а в восьмую степень
(Рис. 3).
Рис. 3. Возведение в степень
Если значение переменной сохранять не нужно, то можно обойтись и без вспомогательной переменной:
a *= a;
a *= a;
a *= a;
При наивном решении задачи потребовалось бы 7 умножений:
var tmpa := a*a*a*a*a*a*a*a;
Этот проект тренировочный, поэтому мы не использовали здесь операцию возведения в степень и кортежи!
Вычисления по формулам
Недостаток рассмотренных нами задач в том, что они решаются «однократно», а
пользователь не имеет возможности изменить условия задачи. Но пример с градусами Фаренгейта и Цельсия показывает, что было бы совсем неплохо вводить
данные в работающей программе и получать от неё результаты вычислений.
Такие действия называются вычислениями по формулам.
203
Проект Периметр квадрата
Так как у квадрата 4 стороны одинаковой длины, то, зная длину стороны, мы
найдём периметр квадрата, умножив её на 4.
Легко определить, что переменные для хранения длины сторон и периметра
квадрата должны быть одного типа. Можно поддаться искушению и назначить им
целый тип integer, но длина может выражаться и десятичными дробями. Поэтому
правильный тип данных для этой задачи – double.
Как программисты мы можем сразу присвоить переменной size (длина стороны)
нужное значение, запустить программу и прочитать ответ в Окне вывода. А пользователь программы должен задать длину квадрата в работающей программе,
когда эта переменная ему недоступна.
Вы уже встречались с процедурами Read и ReadLn, которые используются для
ввода значений в работающем приложении.
В данном случае годится любая из них, но обычно используют вторую. В отличие
он нас, пользователь может и не знать, что он должен сделать, поэтому мы
должны сообщить ему ожидаемые действия. Как всегда, применяем процедуру
Write (не WriteLine!), чтобы введённое пользователем значение было напечатано
в той же строке.
Процедура Readln изменяет значение переменной size так, что оно становится
равно числу, введённому пользователем с клавиатуры.
Затем мы находим периметр квадрата и печатаем его на экране:
##
// сторона квадрата:
var size := 0.0;
Write(' Введите длину стороны квадрата: ');
Readln(size);
var perimeter := size * 4;
WriteLn(' Периметр квадрата = ' + perimeter);
204
Дойдя до инструкции Readln(size);, запущенная программа приостановится, и под
Окном вывода появится текстовое поле Ввод данных:. В нём нужно набрать число
с клавиатуры – длину стороны и нажать либо кнопку Ввести, либо клавишу ВВОД
(Рис. 1).
Рис. 1. ВВОДим
Получив данные, программа продолжит работу, ненужное теперь текстовое поле
исчезнет с экрана, а в Окне вывода появится строка, сообщающая вычисленный
периметр квадрата (Рис. 2).
Рис. 2. Проверочный квадрат
Для проверки правильности работы программы сначала нужно вводить такие
значения, чтобы можно было в уме найти периметр и сравнить правильный
результат с компьютерным. Иначе вы можете получить неверный периметр.
Например, для стороны 10 периметр должен равняться 40, что мы и видим в Окне
вывода.
Так как мы предусмотрели ввод и вещественных чисел (с плавающей точкой), то
давайте узнаем, чему равен периметр квадрата, сторона которого (приближённо)
равна π (Рис. 3).
Рис. 3. Произвольный квадрат
205
Казалось бы, работа над программой закончена, но тут самое время вспомнить,
что пользователи бывают разные. Допустим, нашёлся пользователь, который так
же, как и мы, захотел узнать периметр квадрата со стороной pi (Рис. 4).
Рис. 4. Пи пи рознь
Конечно, так ничего он не узнает, а программа завершится с ошибкой (Рис. 5).
Рис. 5. Не формат!
Действительно, строка pi – это не вещественное число, которого ожидает
программа, а потому она не сможет присвоить такое значение переменной size.
К сожалению, обработать в программе любой ввод пользователя - непростая
задача, поэтому мы пока будем предполагать, что наш пользователь
внимательный и сознательный.
Итак, слегка прикрыв глаза на отдельные недостатки нашей программы, мы
можем принять её в эксплуатацию. Правда, она получилась одноразовая – ввёл
длину стороны, получил периметр, и программа закрылась. Чтобы она выполняла
свою работу многократно, мы должны заключить ввод данных и печать
результата в какой-либо цикл, но это дело будущего.
С тем же успехом вы можете запустить программу без связи с оболочкой, чтобы
она выполнялась в Консольном окне (Рис. 6).
Рис. 6. Консольное приложение
206
Если вы хотите поддерживать совместимость программ с Си-шарпом, то всегда
используйте вместо процедур Write и Writeln методы Console.Write и Console.WriteLine. Процедуры Read и Readln заменяйте методами Console.Read и Console.ReadLine.
Более универсальный код программы должен быть таким:
uses System;
begin
// сторона квадрата:
Console.Write(' Введите длину стороны квадрата: ');
var size := double.Parse(Console.ReadLine());
var perimeter := size * 4;
Console.WriteLine(' Периметр квадрата = ' + perimeter);
Console.Read();
end.
Метод Console.ReadLine возвращает строку, которую нужно преобразовать в
вещественное число методом Parse (он имеется и у других числовых типов).
Запускать такую программу нужно в Консольном режиме (Рис. 7)!
Рис. 7. Под Си-шарп
Паскаль обзавёлся более удобными функциями для ввода вещественных чисел с
клавиатуры – ReadReal и ReadlnReal (Рис. 8).
Рис. 8. В паскале всё удобнее
207
Чем они отличаются друг от друга, вы, конечно, догадались.
С функцией ReadlnReal наша программа стала более короткой и понятной:
##
// сторона квадрата:
var size := ReadlnReal(' Введите длину стороны квадрата: ');
var perimeter := size * 4;
WriteLn(' Периметр квадрата = ' + perimeter);
Проект Длина окружности
Раз уж мы упомянули добрым словом число π, то давайте упомянем его ещё раз
и вычислим длину окружности по её радиусу. Как вы помните, она равна:
2 * PI * r
В паскале имеется специальная константа PI, так что вам не обязательно
заучивать число π наизусть.
Код новой программы легко получить из «старой», заменив длину стороны
радиусом:
##
// радиус окружности:
var r := ReadlnReal(' Введите радиус окружности: ');
var c := 2 * PI * r;
WriteLn(' Длина окружности = ' + c);
Опять сначала испытываем программу на низких оборотах, чтобы проверить её
работоспособность. При радиусе, равном 5, длина окружности должна равняться
10π, что мы и читаем в Окне вывода (Рис. 1).
208
Рис. 22. Тестовый радиус
А дальше можете вводить любые - допустимые! - значения – программа вас не
подведёт (Рис. 2).
Рис. 2. Числовая дробь
Проект Площадь круга
Продолжим геометрические вычисления и научим программу находить площадь
круга, которая равна:
PI * r*r или PI * r**2
Переделка предыдущей программы заняла несколько секунд – и мы можем находить площадь круга по его радиусу:
##
// радиус окружности:
var r := ReadlnReal(' Введите радиус окружности: ');
var s := PI * r**2;
WriteLn(' Площадь круга = ' + s);
Проводим обязательную проверку программы. При радиусе в 10 единиц площадь
круга должна быть равна 100π. Это число мы и видим на экране (Рис. 1).
209
Рис. 1. Обязательная проверка
Программа работает верно, и вы можете использовать её по прямому назначению (Рис. 2).
Рис. 2. Круглая площадь
Проект Площадь прямоугольника
Прямоугольник отличается от квадрата только тем, что длина его сторон может
быть различна. Это значит, что пользователь должен ввести длину двух сторон, а
для этого программе потребуется ещё одна функция ReadlnReal.
Если мы обозначим буквой a первую сторону прямоугольника, а буквой b – вторую, то его площадь будет равна:
a * b
Программу для вычисления площади прямоугольника легко написать, слегка переработав программу для вычисления периметра квадрата:
##
// первая сторона прямоугольника:
var a := ReadlnReal(' Введите длину первой стороны прямоугольника: ');
// вторая сторона прямоугольника:
var b := ReadlnReal(' Введите длину второй стороны прямоугольника: ');
// площадь прямоугольника:
var s := a * b;
WriteLn(' Площадь прямоугольника = ' + s);
210
Тест наша программа проходит успешно (Рис. 1).
Рис. 1. Проверка сторон
Теперь вы сможете вычислить площадь любого прямоугольника (Рис. 2).
Рис. 2. Прямоугольная площадь
Функции ReadReal2 и ReadlnReal2 позволяют вводить 2 числа в одной строке, разделяя их пробелом. Это несколько сокращает исходный код, но не всегда благоприятно влияет на пользователя (Рис. 3):
##
// стороны прямоугольника:
var (a, b) := ReadlnReal2(' Введите длину сторон прямоугольника: ');
// площадь прямоугольника:
var s := a * b;
WriteLn(' Площадь прямоугольника = ' + s);
Рис. 3. Оба два
Обратите внимание, что переменные a и b нужно обязательно заключать в круглые скобки!
211
Задания для самостоятельного решения
Задача #837
Математическая шкатулка
Вычислите сумму наибольших однозначного, двузначного, трёхзначного и четырёхзначного чисел.
Ответ: 9 + 99 + 999 + 9999
Задача #3.1
Удивительный мир чисел, стр. 42
Число 32
Десятичная запись куба этого числа начинается самим числом, а запись его пятой степени оканчивается цифрами данного числа:
323 = 32768
325 = 33554432.
Проверьте эти равенства. Степени записывайте как произведения:
323 32 * 32 * 32
Задача #10
Математическая шкатулка
Найдите возможно быстрее, какое частное и какой остаток получатся при делении числа 1 ⦁ 2 ⦁ 3 ⦁ 4 ⦁ 5 ⦁ 6 + 1 на 5.
Ответ: Частное равно 2 ⦁ 3 ⦁ 4 ⦁ 6 = 144, остаток равен 1.
212
Задачи #45, 46, 47, 58
Математическая шкатулка
Сколько суток составляет миллион минут?
Сколько лет составляет миллион часов?
Сколько столетий составляет миллион дней? Прошёл ли с начала нашего летосчисления миллион дней?
Сколько столетий в миллиарде минут?
Задачи #70, 71, 72, 74, 75
Математическая шкатулка
Земля при своём движении вокруг Солнца проходит путь в 936 250 000 км в год.
Какое расстояние проходит Земля за 1 сутки? (Считайте год в среднем равным
365, 25 суток.)
Скорость света в вакууме ≈ 3,00 ⦁ 105 км/с. Какое расстояние проходит свет в
течение года?
Расстояние от Земли до звезды Проксима Центавра свет проходит за 4⅓ года.
Сколько километров до этой звезды?
В астрономии для выражения расстояний во вселенной используются единицы: парсек = 3,26 световых года и мегапарсек = 1 000 000 парсеков.
Выразите эти единицы в километрах.
Тончайшая паутиновая нить, если бы её протянуть по земному экватору, длина
которого ≈ 40 060 км, имела бы массу 660 г. Какую массу имела бы такая нить,
протянутая на расстояние в один мегапарсек?
213
Электронный задачник по программированию
Programming Taskbook 4
Вы познакомились с основами языка программирования PascalABC.NET. Прежде
чем идти дальше, вам следует хорошенько закрепить пройденный материал,
чтобы он не вызывал у вас в будущем ни малейших затруднений. Поэтому в этом
разделе мы порешаем задачи из электронного задачника по программированию
Programming Taskbook 4.
Здесь вы не только закрепите уже полученные знания, но и узнаете немалого нового!
Набор заданий Begin
Начнём мы с самого первого набора заданий Begin, название которого говорит
само за себя: они адресуются начинающим программировать на паскале и предназначены для изучения таких базовых понятий любых языков программирования, как:
Ввод и вывод данных
Вычисления по формулам
Типы данных
Вещественный тип
Процедуры и функции
Структура простой программы
Операторы и операции
Арифметические операции
Объявление и инициализация переменных
Автоопределение типа
Оператор присваивания
Электронный задачник по программированию разработан Михаилом Эдуардовичем Абрамяном и интегрирован в среду разработки PascalABC.NET. Это значит,
что задачи доступны без дополнительной установки модулей. Достаточно нажать
214
кнопку на Панели инструментов и выбрать нужный набор заданий. Очень
удобно!
Следует отметить, что Задачник не только содержит наборы заданий, но и контролирует их выполнение. В случае ошибки вы получите необходимую информацию для её нахождения и исправления. Таким образом, даже начинающие программисты могут самостоятельно отрабатывать навыки программирования на
языке паскаль!
Электронный задачник
Прежде всего, вы должны научиться получать задания для последующего их выполнения.
Самый простой и в то же время правильный путь в этом направлении – нажать
кнопку Создать шаблон программы на Панели инструментов (клавиатурное сокращение Ctrl+Shift+L) (Рис. 1).
Рис. 1. Шаблонная кнопка
Откроется диалоговое окно PT4 Load (Рис. 2).
Рис. 2. Окно открывается автоматически
215
Внизу вы можете прочитать, какие имеются группы заданий. Нам нужна группа
Begin.
Набираем в текстовом поле Задание буквы abe (в любом регистре) и получаем
внизу диалогового окна полное название группы (Рис. 3).
Рис. 3. Получили, что просили
Достаточно нажать клавишу ПРОБЕЛ, чтобы название группы было закончено автоматически. Также вы получите подсказку: в наборе 40 заданий (Рис. 4).
Рис. 4. Паскаль и 40 заданий
Конечно, начинать нужно с первого задания, поэтому печатаем цифру 1 (Рис. 5).
216
Рис. 5. Начинаем!
По умолчанию все ваши проекты-решения сохраняются в папке PascalABC.NET,
название которой напечатано в текстовом поле Каталог. Если вы хотите изменить
место хранения своих проектов, то нажмите кнопку с жёлтой папкой и укажите
новый путь (Рис. 6).
Рис. 6. Пути, которые мы выбираем
Все приготовления закончены. Нажимаем кнопку Загрузка или клавишу ВВОД
(Рис. 7).
В Редакторе кода появилась страница Begin1.pas с заготовкой кода для задания
Begin1 (Рис. 8).
Если у вас на то есть охота, то вы можете и самостоятельно набрать весь этот код
и сохранить его на диске под нужным именем.
217
Рис. 7. Загружаемся и погружаемся
Рис. 8. Пора начать
Чтобы не выбирать каждый раз папку для хранения файлов,
сохраните задание на диске, закройте среду разработки, перейдите в папку с файлом и дважды щёлкните по нему. Заготовка задания откроется в Редакторе кода, а при загрузке нового задания в текстовом поле Каталог будет автоматически напечатан путь к нужной папке.
Строчка
uses PT4;
218
подключает к проекту модуль PT4.pas, в котором находится электронный задачник Programming TaslBook 4.
В главном блоке программы записан вызов процедуры Task, которой мы передаём строку 'ABegin1' с названием задания.
Так как условие задачи пока неизвестно, то вы должны запустить программу,
нажав кнопку Выполнить на Панели инструментов или воспользоваться командами меню Программа Выполнить (Выполнить без связи с оболочкой) (Рис. 9).
Рис. 9. Выполняем
На экране появится окно с заданием и элементами управления (Рис. 10).
Рис. 10. Белым по чёрному
219
Всегда внимательно читайте верхнюю строку (на чёрном фоне), в которой находится условие задачи. В средней строке вы можете прочитать исходные данные,
а в нижней – правильный ответ. Исходные данные и ответ на задачу обновляются
при каждом запуске программы, поэтому их нельзя использовать в исходном
коде!
В заголовке окна напечатано название задачника, а также размещаются 2 кнопки.
Кнопка с крестиком закрывает окно задания. Кнопка с вопросительным знаком
открывает диалоговое окно Информация, в котором вы найдёте исчерпывающие
сведения по работе с задачником (Рис. 11).
Рис. 11. Информация для размышления
Под заголовком вы можете прочитать название текущего задания ABegin1, имя
«испытуемого», а также содержание первой группы заданий: ВВОД И ВЫВОД
ДАННЫХ, ОПЕРАТОР ПРИСВАИВАНИЯ.
Правее находятся кнопки:
220
Кнопка Результаты (клавиша F2) вызывает окно, показывающее, какие задания и насколько успешно вы уже решали (Рис. 12).
Рис. 12. Пока безуспешно
Кнопка Цвет (клавиша F3) инвертирует цвета фона и шрифта в строках с заданием (Рис. 13).
Рис. 13. Так-то лучше
Если вам больше по душе писать чёрным по белому, чем наоборот, то вы можете
остановиться на этом колористическом варианте. Повторное нажатие на кнопку
Цвет вернёт этим строчкам первоначальный мрачный цвет.
221
Кнопка Режим открывает задание в браузере по умолчанию (Рис. 14).
Рис. 14. Можно и так
И наконец, под этими кнопками выводятся текущая дата и время.
Обратите внимание, что задачник очень умный и понимает, что мы пока не решаем задачу, а только знакомимся с её условием. Об этом говорит сообщение в
синем текстовом поле: Ознакомительный запуск: не выполнена ни одна из операций ввода-вывода.
Запомните или запишите условие задания и закройте окно. Если память у вас слабая или лень переписывать задание в тетрадь, то окно можно и не закрывать. Тогда при необходимости вы всегда сможете по(д)смотреть условие задачи.
Итак, первое задание такое:
Дана сторона квадрата a. Найти его периметр P = 4·a.
Как вы видите, решать ничего не нужно, поскольку формула для вычисления периметра приведена в условии задания. Нам нужно только записать её на паскале.
Возвращаемся в Редактор кода и после вызова процедуры Task объявляем переменную a вещественного типа:
begin
Task('Begin1');
222
// сторона квадрата:
var a: double;
Именно этой буквой длина стороны квадрата обозначена в формуле. Чтобы не
ничего не перепутать, лучше не менять названия переменных.
Помните, что во всех заданиях переменные имеют вещественный тип real, или double.
Вы можете указывать тип переменных, как это принято в Си-шарпе (double) или
как это делается в классическом паскале (real):
var a: real;
На решение задачи это никак не влияет, но я советую вам пользоваться типом
double как более универсальным. Тогда при переносе решения на Си-шарп у вас
будет меньше работы по исправлению кода.
Объявлять переменную нужно именно в этом месте кода,
а не в разделе глобальных переменных программы!
Теперь мы должны получить значение для этой переменной, которое будет использоваться при решении задачи. Обычный способ ввода значений в языке паскаль – с помощью процедуры Read, которой следует передать имя переменной.
В нашем случае код должен быть таким:
begin
Task('ABegin1');
// сторона квадрата:
var a: double;
223
//var a: real;
// получаем значение переменной:
Read(a);
end.
После его выполнения переменная а получит от задачника некоторое случайное
значение. Какое именно – нам знать необязательно, так как оно просто используется для вычисления периметра по формуле:
P = 4·a
С точки зрения паскаля, в левой части выражения находится переменная того же
типа, что и тип правой части. Как вы уже знаете, все переменные в группе заданий
имеют вещественный тип.
Для идентификаторов переменных принято использовать строчные буквы, поэтому
переменная для хранения длины периметра должна называться p. И хотя в паскале регистр символов не учитывается, но лучше придерживаться этого правила.
Обратимся к правой части уравнения для вычисления периметра. Её значение
равно произведению значения переменной а на 4. Точку следует заменить звёздочкой - знаком умножения, принятом в программировании.
Четвёрка – это литерал целого типа, а переменная а имеет вещественный тип. В
результате выполнения операции умножения результат получит более «высокий»
тип, то есть вещественный тип переменной а.
Таким образом, тип правой части выражения – вещественный. Точно такой же тип
имеет и левая часть выражения, а это значит, что для переменной р не нужно явно
указывать её тип, так как компилятор установит его автоматически.
Пишем перед именем переменной ключевое слово var – и инструкция для вычисления периметра готова:
224
// периметр:
var p := 4 * a;
И поскольку нам нужна именно инструкция, а не выражение, то строчка должна
заканчиваться точкой с запятой.
Обратите также внимание на знак операции присваивания – это двоеточие и знак
равенства, а не просто знак равенства, как это принято в математике или во многих других языках программирования.
И последняя обязательная операция во всех заданиях – печать результата выполнения задачи на экране. В паскале за это отвечают процедуры Write и Writeln:
// печатаем результат на экране:
Writeln(p);
Нажимаем кнопку Выполнить – и получаем от программы сообщение, что с первым заданием мы успешно справились (Рис. 15).
Рис. 15. Ух!
Итак, полный код программы должен быть таким:
uses PT4;
225
begin
Task('ABegin1');
// сторона квадрата:
var a: double;
//var a: real;
// получаем значение переменной:
read(a);
// периметр:
var p := 4 * a;
// печатаем результат на экране:
Writeln(p);
end.
Во всех заданиях должны быть:
операторы ввода и вывода Read/Readln и Write/Writeln
операторы объявления переменных
арифметические/математические выражения
операторы присваивания
Запомните:
Все переменные должны иметь вещественный тип double.
Все инструкции должны заканчиваться точкой с запятой.
Все переменные должны объявляться в главном блоке программы непосредственно перед их использованием.
Если числовой литерал имеет дробную часть, то она отделяется от целой части точкой, а не запятой.
Знак операции присваивания состоит из двух символов – двоеточия и
знака равенства, которые пишутся слитно.
Идентификаторы переменных пишутся с маленькой буквы.
Левая часть оператора присваивания (переменная) должна иметь тот
же тип (или совместимый), что и правая часть. Если тип левой части
оператора присваивания совпадает с типом правой части, то его можно
не указывать.
226
Для объявления и определения переменных используется ключевое слово
var.
Тип переменной указывается после её идентификатора в операторе объявления через двоеточие.
Если в программе используется значение переменной, то она должна
быть инициализирована, то есть ей должно быть присвоено какое-либо
значение того же типа (или совместимого). По умолчанию все переменные вещественного типа получают значение 0.0, но лучше и правильнее
присваивать значения переменным самостоятельно.
Оператор присваивания действует так. Сначала вычисляется значение
правой части, а затем оно присваивается переменной в левой части.
В правой части оператора присваивания должна стоять переменная.
В выражениях всегда используется текущее значение переменной.
Задачник строго следит за выполнение этих правил и в случае нарушений выдаёт
соответствующие сообщения.
Давайте закомментируем оператор вывода:
// печатаем результат на экране:
//Writeln(p);
И запустим программу.
В окне программы появляется синяя строка, сообщающая нам, что мы не напечатали необходимые результаты (Рис. 16).
Если вы забудете объявить переменную, то получите замечание от компилятора
(Рис. 17).
Действительно, в процедуре Writeln указана переменная р, которая до этого не
объявлена. Компилятор её не знает!
Аналогично вы может делать и другие ошибки, чтобы посмотреть, как на них реагируют компилятор и задачник. Впрочем, если вы будете невнимательны, то
ошибки в программах будут возникать сами собой, без дополнительных усилий.
227
Сохраните исходный код программы на диске и готовьтесь к новым испытаниям!
Рис. 16. Узелок на память
Рис. 17. Память подвела
Дополнительные процедуры ввода и вывода
Кроме стандартных процедур ввода-вывода паскаля, электронный задачник
имеет и собственные, которые вы также можете использовать при решении задач
(но не в других программах!).
Так, для ввода вещественных значений гораздо естественнее использовать функции GetReal и GetDouble, которые возвращают значение вещественного типа:
228
var a := GetReal();
var a := GetDouble();
Так как в этом случае правая часть оператора присваивания заведомо имеет вещественный тип, то тип переменной а дополнительно указывать не нужно.
Аналогично действуют функции ReadReal и ReadlnReal:
var a := ReadReal();
var a := ReadlnReal();
При вызове функции без параметров круглые скобки можно
не писать, но с ними код программы более понятен. А в
языке Си-шарп скобки необходимо ставить в любом случае!
И последний способ ввода вещественных значений – объявить переменную и вызвать процедуру GetR:
var a: double;
GetR(a);
Для вывода (печати на экране) вещественных значений можно пользоваться процедурами Put и PutR:
Put(p);
PutR(p);
Дальше мы будем пользоваться стандартными процедурами ввода-вывода.
229
Задание Begin2
Получить заготовку для второго задания ещё проще, чем для первого!
Нажмите кнопку Создать шаблон программы и исправьте в диалоговом окне PT4
Load единицу на двойку (Рис. 1-2).
Рис. 1. Было
Рис. 2. Стало
Если вы сохраняете решения не в папке по умолчанию, то укажите её, как мы это
делали раньше, а затем нажмите кнопку Загрузка. В Редакторе кода откроется
заготовка:
uses PT4;
230
begin
Task('ABegin2');
end.
Так как прежде чем браться за выполнение задания, его нужно увидеть, то запустите программу и внимательно прочитайте задание (Рис. 3).
Рис. 3. Не отвлекайтесь
Другой способ ознакомиться с заданием – нажать кнопку
ментов (клавиатурное сокращение Crtl+Shift+D) (Рис. 4).
на Панели инстру-
Рис. 4. Кнопки – наше будущее
В открывшемся диалоговом окне PT4 Demo выберите из списка нужную группу
заданий, номер задания и нажмите кнопку Просмотр (Рис. 5).
Откроется диалоговое окно с условием задачи (Рис. 6).
Если вы хотите разом увидеть условия всех заданий и/или распечатать их, то
нажмите кнопку Показать группу заданий в виде html-страницы (клавиатурное сокращение F2) (Рис. 7).
231
Рис. 5. Посмотрим
Рис. 6. Условились
Рис. 7. Всё и сразу
В браузере откроется страница, и вы сможете прочитать условие любого задания
(Рис. 8).
Решение второй задачи практически повторяет решение первой, нужно только
переименовать переменные и правильно записать формулу для вычисления площади квадрата.
232
Рис. 8. Для любопытных
В математической формуле используется операция возведения в квадрат. В паскале для этого имеется функция Sqr, но в программировании обычно возведение
в квадрат заменяют умножением.
Код программы может быть таким:
uses PT4;
begin
233
Task('ABegin2');
// сторона квадрата:
var a := ReadReal;
// площадь:
var s := a * a;
// печатаем результат:
Writeln(s);
end.
Кроме собственно вычисления площади квадрата, в нём нет ничего нового для
вас. Лёгкая прогулка и приятная тренировка!
При решении простых задач вы можете пользоваться командным режимом. Для
этого в начале программы напечатайте две решётки, а затем все инструкции:
## uses PT4;
Task('ABegin2');
// сторона квадрата:
var a := ReadReal;
// площадь:
var s := a * a;
// печатаем результат:
Writeln(s);
Операторные скобки begin-end. Можно стереть.
Задание Begin3
Получите заготовку для третьего задания и ознакомьтесь с его условием:
234
Задача посложнее прежних! Теперь нам нужно получить 2 значения – длину сторон прямоугольника a и b. Вычислить и напечатать также нужно 2 значения – площадь прямоугольника s и его периметр р.
Функция ReadReal возвращает единственное значение, поэтому значения двух
переменных мы можем получить так:
## uses PT4;
Task('ABegin3');
var a := ReadReal;
var b := ReadReal;
А функция ReadReal2 возвращает два значения, поэтому мы сразу можем получить
значения для двух переменных:
var (a, b) := ReadReal2;
Вычисления и печать результатов выполняются точно так же, как и раньше:
// вычисляем площадь:
var s := a * b;
235
// печатаем значение:
Writeln(s);
// вычисляем периметр:
var p := 2 * (a + b);
// печатаем значение:
Writeln(p);
Вычислять площадь и периметр можно в любом порядке, но напечатать их значения нужно именно так, как указано в условии задачи, – сначала площадь, а затем
периметр, но не наоборот!
Замечание. Для проверки программы запустите её несколько раз. Ведь вполне вероятно, что при первом запуске результаты случайно совпадут с правильными,
хотя само решения будет ошибочным.
Задание Begin4
Четвёртое задание практически повторяет первое:
Ни обсуждать, ни комментировать здесь нечего:
## uses PT4;
236
Task('ABegin4');
// диаметр:
var d := ReadReal;
// длина окружности:
var l := 3.14 * d;
Writeln(l);
Задание Begin5
Переходим в пространство и решаем стереометрическую задачу:
При вычислении объёма и площади поверхности куба заменяйте возведение в
степень умножением. Других «хитростей» в этой задаче нет:
## uses PT4;
Task('ABegin5');
// длина ребра куба:
var a := ReadReal;
237
// объём:
var v:= a * a * a;
Writeln(v);
// площадь поверхности:
var s:= 6 * a * a;
Writeln(s);
Задание Begin6
Переходим к следующему заданию:
Самое сложное в этом задании – суметь выговорить прямоугольный параллелепипед. Смогли? – Тогда вычисления не доставят вам много хлопот!
Правда, нужно получить значения для трёх переменных, а формула для вычисления площади поверхности довольно замысловатая:
## uses PT4;
Task('ABegin6');
238
// длины рёбер ПП:
var (a, b, c) := ReadReal3;
// объём:
var v := a * b * c;
Writeln(v);
// площадь поверхности:
var s:= 2 * (a*b + b*c + a*c);
Writeln(s);
Задание Begin7
Опять простенькое задание на вычисления по готовым формулам:
Все комментарии – в исходном тексте программы:
## uses PT4;
Task('ABegin7');
239
// радиус:
var r := ReadReal;
// длина окружности:
var l := 2 * 3.14 * r;
Writeln(l);
// площадь круга:
var s := 3.14 * r * r;
Writeln(s);
В новых версиях паскаля появилась удобная операция возведения в степень, обозначаемая двумя звёздочками. С этим оператором запись формулы более понятная:
// площадь круга:
var s := 3.14 * r ** 2;
Задание Begin8
Здесь нам впервые встречается операция вещественного деления, которая обозначается в исходном коде косой дробной чертой:
240
Не путайте эту операцию с операцией целочисленного деления div!
Сам код программы не должен вызвать у вас никаких вопросов:
## uses PT4;
Task('ABegin8');
// числа:
var (a, b) := ReadReal2;
// среднее арифметическое:
var sa := (a + b) / 2;
Writeln(sa);
Задание Begin9
И опять новинка! Для вычисления среднего геометрического двух чисел необходимо извлечь квадратный корень из их произведения:
241
Для этого в паскале имеется функция Sqrt, которая возвращает вещественное значение – корень квадратный из значения выражения в скобках:
## uses PT4;
Task('ABegin9');
// числа:
var (a, b) := ReadReal2;
// среднее геометрическое:
var sg := Sqrt(a * b);
Writeln(sg);
Задание Begin10
В этом задании всего 2 числа, но они входят в четыре выражения:
Так как квадраты чисел a и b используются в вычислениях неоднократно, то их
необходимо вычислить один раз, а затем вместо умножения чисел подставлять
переменные a2 и b2:
242
## uses PT4;
Task('ABegin10');
// числа:
var (a, b) := ReadReal2;
// квадраты чисел:
var a2 := a * a;
var b2 := b * b;
// сумма квадратов:
var sum := a2 + b2;
Writeln(sum);
// разность квадратов:
var razn := a2 - b2;
Writeln(razn);
// произведение квадратов:
var proiz := a2 * b2;
Writeln(proiz);
// частное от деления квадратов:
var chastn := a2 / b2;
Writeln(chastn);
С этими заменами код становится более простым, понятным и надёжным. Всегда
заменяйте повторяющиеся вычисления переменными, хранящими их значения!
Задание Begin11
Задача, аналогичная предыдущей, только вместо квадратов чисел нужно брать их
абсолютные значения:
243
В паскале имеется функция Abs, которая возвращает абсолютное значение выражения в скобках. Для хранения абсолютных значений чисел a и b следует определить переменные aa и ba, которые затем использовать в вычислениях:
## uses PT4;
Task('ABegin11');
// числа:
var (a, b) := ReadReal2;
// модули чисел:
var aa := Abs(a);
var ba := Abs(b);
// сумма модулей:
var sum := aa + ba;
Writeln(sum);
//разность модулей:
var razn := aa - ba;
writeln(razn);
// произведение модулей:
var proiz := aa * ba;
Writeln(proiz);
244
// частное от деления модулей:
var chastn := aa / ba;
Writeln(chastn);
Задание Begin12
Типичная задача из школьной геометрии:
Так как в условии задачи уже даны готовые формулы, то нам не нужно даже вспоминать, чему равны пифагоровы штаны:
## uses PT4;
Task('ABegin12');
// катеты:
var (a, b) := ReadReal2;
// длина гипотенузы:
var c := Sqrt(a*a + b*b);
Writeln(c);
// периметр треугольника:
245
var p := a + b + c;
Writeln(p);
Задание Begin13
Условие задачи длинное, но легкоусвояемое:
А вся программа – это простой перевод условия задачи на язык программирования:
## uses PT4;
Task('ABegin13');
// радиусы кругов:
var (r1, r2) := ReadReal2;
// площадь первого круга:
var s1 := 3.14 * r1 * r1;
Writeln(s1);
// площадь второго круга:
246
var s2 := 3.14 * r2 * r2;
Writeln(s2);
// площадь кольца:
var s3 := s1 - s2;
Writeln(s3);
Задание Begin14
А эта задача с хитрецой:
Радиус окружности не даётся в готовом виде – его нужно найти из формулы для
длины окружности. Ну, это легко:
L = 2 π R
R = L / 2 / π
В знаменатель можно поставить и произведение 2π, но лучше использовать двукратное деление.
247
Весь прочий код элементарен:
## uses PT4;
Task('ABegin14');
// длина окружности:
var l := ReadReal;
// радиус:
var r := l / 2 / 3.14;
Writeln(r);
// площадь круга:
var s := 3.14 * r * r;
Writeln(s);
Задание Begin15
В этом задании нужно вычислить длину окружности, предварительно найдя из
предложенной формулы её диаметр:
Если S = πD2/4, то диаметр равен:
248
D = √S ∗ 4 / 3.14
Остальное, как говорится, дело компьютерной техники:
## uses PT4;
Task('ABegin15');
// площадь круга:
var s := ReadReal;
// диаметр:
var d := Sqrt(s * 4 / 3.14);
Writeln(d);
// длина окружности:
var l := 3.14 * d;
Writeln(l);
Задание Begin16
Очень простое задание:
Расстояние между двумя точками на числовой оси равно абсолютной величине
разности их координат:
249
## uses PT4;
Task('ABegin16');
// координаты точек:
var (x1, x2) := ReadReal2;
// расстояние:
var l := Abs(x1 - x2);
Writeln(l);
Задание Begin17
Развиваем плодотворную идею предыдущего задания:
Длину отрезка на числовой оси мы уже научились вычислять. Поэтому найти
длины двух отрезков, а затем их сумму проще простого:
## uses PT4;
Task('ABegin17');
// координаты точек:
250
var (a, b, c) := ReadReal3;
// длина отрезка AC:
var ac := Abs(a - c);
Writeln(ac);
// длина отрезка BC:
var bc := Abs(b - c);
Writeln(bc);
// сумма длин отрезков:
var sum := ac + bc;
Writeln(sum);
Задание Begin18
Опять нужно найти длины двух отрезков:
Чтобы не ошибиться в расположении точек на оси, «нарисуем» их:
А----С----В
Таким образом, мы должны вычислить длину отрезков АС и СВ, то есть абсолютную величину разности их координат:
251
## uses PT4;
Task('ABegin18');
// координаты точек:
var (a, b, c) := ReadReal3;
// длина отрезка AC:
var ac := Abs(a - c);
// длина отрезка BC:
var bc := Abs(b - c);
// произведение длин отрезков:
var proizv := ac * bc;
Writeln(proizv);
Задание Begin19
Площадь и периметр прямоугольника мы умеем вычислять, но для этого нужно
знать длину его сторон:
252
В данном случае мы можем считать длину одной стороны прямоугольника его
шириной w, а длину второй стороны – его высотой h.
Ширина прямоугольника равна абсолютной величине разности горизонтальных
координат его противоположных вершин, а высота – абсолютной величине разности вертикальных координат.
Если вы начертите прямоугольник и подпишете координаты его противоположных вершин, то эти утверждения станут очевидными.
После этих предварительных рассуждений задача практически решена:
## uses PT4;
Task('ABegin19');
// координаты вершин:
var (x1, y1, x2, y2) := ReadReal4;
// ширина прямоугольника:
var w := Abs(x1 - x2);
// высота прямоугольника:
var h := Abs(y1 - y2);
// периметр прямоугольника:
var p := 2 * (w + h);
Writeln(p);
// площадь прямоугольника:
var s := w * h;
Writeln(s);
Задание Begin20
Решение этой задачи сводится к переводу её условия на язык программирования
паскаль:
253
Действительно, координаты точек мы получаем от программы, а формула для вычисления расстояния между ними дана в готовом виде:
## uses PT4;
Task('ABegin20');
// координаты вершин:
var (x1, y1, x2, y2) := ReadReal4;
// разность координат по осям X и Y:
var dx := x1 - x2;
var dy := y1 - y2;
// расстояние между двумя точками:
var d := Sqrt(dx * dx + dy * dy);
Writeln(d);
Задание Begin21
Число точек на плоскости увеличивается:
254
Усложняет ли это нашу задачу? – Ничуть!
Чтобы сделать код более наглядным, мы предварительно находим разность координат заданных точек по обеим осям и сохраняем значения в переменных dx1,
dy1, dx2, dy2, dx3, dy3:
## uses PT4;
Task('ABegin21');
// координаты вершин:
var (x1, y1) := ReadReal2;
var (x2, y2) := ReadReal2;
var (x3, y3) := ReadReal2;
// разность координат по осям X и Y:
var dx1 := x1 - x2;
var dy1 := y1 - y2;
var dx2 := x1 - x3;
var dy2 := y1 - y3;
var dx3 := x3 - x2;
var dy3 := y3 - y2;
255
Расстояния между парами точек (это длины сторон треугольника) также следует
вычислить отдельно и сохранить в переменных a, b, c:
// расстояния между
var a := Sqrt(dx1 *
var b := Sqrt(dx2 *
var c := Sqrt(dx3 *
парами точек:
dx1 + dy1 * dy1);
dx2 + dy2 * dy2);
dx3 + dy3 * dy3);
При вычислении расстояний мы дважды используем вычисленные ранее переменные. Согласитесь, такой код гораздо понятнее, чем если бы мы записывали
вместо них разности координат в скобках.
Остальная часть кода просто повторяет условие задачи на языке паскаль:
// периметр треугольника:
var p := a + b + c;
Writeln(p);
// полупериметр треугольника:
var p2 := p / 2;
// площадь треугольника:
var s := Sqrt(p2 * (p2 - a) * (p2 - b) * (p2 - c));
Writeln(s);
256
Задание Begin22
Обмен значениями – типовая задача в программировании:
В паскале для этого имеется специальная процедура Swap:
Swap(a, b);
Вы вполне можете использовать её в своих программах, но это задание, конечно,
предполагает, что мы самостоятельно обменяем значения переменных.
Хитрость этой операции заключается в том, что в результате выполнения очевидного кода:
a := b;
b := a;
обмена значениями не произойдёт!
После выполнения первой инструкции присваивания переменная а получит значение переменной b. Поэтому вторая инструкция не изменит значения переменной b, поскольку переменная а уже получила то же самое значение b.
257
Таким образом, вместо обмена значениями обе переменные получат одинаковое
значение b.
В таких случаях всегда используется вспомогательная переменная tmp, в которой
необходимо сохранить значение одной из переменной. В нашем примере – переменной а. Тогда второй оператор присваивания должен быть таким:
b := tmp;
К этому времени переменная а получила значение переменной b, но в переменной tmp сохранилось её значение, и переменная b получит исходное значение
переменной а. Обмен состоялся!
## uses PT4;
Task('ABegin22');
// значения переменных:
var (a, b) := ReadReal2;
// вспомогательная переменная:
var tmp := a;
// меняем значения переменных:
a := b;
b := tmp;
// новые значения переменных:
Writeln(a, b);
В новых версиях паскаля обмен значениями выполняется с помощью кортежей:
// меняем значения переменных:
(a, b) := (b, a);
В этом случае вспомогательная переменная не нужна!
258
Задание Begin23
Это задание – усложнённый вариант предыдущего:
Нам предстоит циклически изменить значения переменных:
ABCA
Если мы будем действовать «очевидным» способом, то все переменные получат
значение переменной а:
b := a;
c := b;
a := c;
Как и при любом обмене, нам необходим посредник, то есть вспомогательная переменная tmp. В неё можно временно поместить значение какой-нибудь переменной, например, а.
Теперь мы можем безнаказанно изменить значение переменной а, то есть присвоить ей значение переменной с. Это легко понять, если посмотреть на цикл обмена значениями, который мы записали выше. Если мы запомнили значение первой переменной, то присваивать новые значения переменным нужно от конца к
началу этого цикла:
259
## uses PT4;
Task('ABegin23');
// значения переменнных:
var (a, b, c) := ReadReal3;
// вспомогательная переменная:
var tmp := a;
// меняем значения переменных:
a := c;
c := b;
b := tmp;
// новые значения переменных:
Writeln(a, b, c);
Кортежи снова облегчают нам задачу:
// меняем значения переменных:
(b, c, a) := (a, b, c);
260
Задание Begin24
Практически то же самое задание, что и предыдущее:
Чтобы нас запутать, порядок обмена значениями изменён:
AСВA
Но, пользуясь этой записью цикла, мы легко решим задачу:
## uses PT4;
Task('ABegin24');
// значения переменнных:
var (a, b, c) := ReadReal3;
// меняем значения переменных:
(c, b, a) := (a, c, b);
// новые значения переменных:
Writeln(a, b, c);
261
Задание Begin25
Возвращаемся к вычислениям по формулам:
Оператор возведения в степень делает программу очень простой:
## uses PT4;
Task('ABegin25');
// значение переменной:
var x := ReadReal;
// значение функции:
var y := 3 * x ** 6 - 6 * x ** 2 - 7;
Writeln(y);
262
Задание Begin26
Усложнённый вариант предыдущего задания:
Вы можете заменить разность в скобках новой переменной, но это необязательно:
## uses PT4;
Task('ABegin26');
// значение переменной:
var x := ReadReal;
// значение функции:
var y := 4 * (x - 3) ** 6 - 7 * (x - 3) ** 3 + 2;
Writeln(y);
263
Задание Begin27
Если вы поняли, как вычисляются целые степени, то эта задача – лёгкая тренировка для вас:
## uses PT4;
Task('ABegin27');
// число:
var a := ReadReal;
// a в квадрате:
var a2 := a ** 2;
Writeln(a2);
// a в четвёртой степени:
var a4 := a2 ** 2;
Writeln(a4);
// a в восьмой степени:
var a8 := a4 ** 2;
Writeln(a8);
264
Задание Begin28
Слегка усложнённый вариант предыдущего задания:
Его решение прямо указано в условии. Следуйте ему – и всё у вас получится!
## uses PT4;
Task('ABegin28');
// число:
var a := ReadReal;
// a в квадрате:
var a2 := a * a;
Writeln(a2);
// a в кубе:
var a3 := a2 * a;
Writeln(a3);
// a в пятой степени:
var a5 := a2 * a3;
Writeln(a5);
// a в десятой степени:
265
var a10 := a5 * a5;
Writeln(a10);
// a в пятнадцатой степени:
var a15 := a10 * a5;
Writeln(a15);
Задание Begin29
Простейшее задание на пропорцию:
Из условия нам известно, что 180° = π радианов. Тогда углу alpha в градусах соответствует угол rad в радианах:
180 – π
alpha – rad
Откуда:
rad = alpha / 180 * π
Записываем это уравнение на компьютерном языке:
266
## uses PT4;
Task('ABegin29');
// угол в градусах:
var alpha := ReadReal;
// угол в радианах:
var rad := alpha / 180.0 * 3.14;
Writeln(rad);
Так как в правой части оператора присваивания находятся вещественные значения, то правильнее делить не на 180 – целочисленный литерал, а на 180.0 – вещественный литерал.
Задание Begin30
Та же самая задача, что и предыдущая, только наоборот:
Теперь мы должны найти значение угла в градусах, зная его значение в радианах.
Формула для вычисления угла в градусах легко выводится из той пропорции, которую мы написали в предыдущем задании:
267
alpha = rad * 180 / 3.14
Про код и вовсе говорить нечего:
## uses PT4;
Task('ABegin30');
// угол в радианах:
var rad := ReadReal;
// угол в градусах:
var alpha := rad * 180.0 / 3.14;
Writeln(alpha);
Задание Begin31
Наипростейшее задание на вычисления по готовой формуле:
От нас требуется только внимание и аккуратность при переводе математической
формулы на язык паскаль:
268
## uses PT4;
Task('ABegin31');
// температура в градусах Фаренгейта:
var tf := ReadReal;
// температура в градусах Цельсия:
var tc := (tf - 32.0) * 5.0 / 9.0;
Writeln(tc);
Задание Begin32
Опять задание «наоборот»:
Формула та же самая, что и в предыдущем задании, но теперь нам нужно найти
из неё температуру в градусах Фаренгейта.
Начинаем преобразование:
TF – 32 = TC * 9 / 5
269
И далее:
TF = TC * 9 / 5 + 32
Вот и вся задача!
## uses PT4;
Task('ABegin32');
// температура в градусах Цельсия:
var tc := ReadReal;
// температура в градусах Фаренгейта:
var tf := tc * 9.0 / 5.0 + 32.0;
Writeln(tf);
Задание Begin33
Очередное задание на простую пропорцию:
270
Легко сообразить, что если Х кг конфет стоят А рублей, то 1 кг стоит A/X рублей.
Если же нужно найти стоимость не 1 кг, а Y, то это значение и нужно умножить на
Y.
То же самое на паскале:
## uses PT4;
Task('ABegin33');
// вес и стоимость:
var (x, a) := ReadReal2;
// 1 кг конфет стоит:
var a1 := a / x;
Writeln(a1);
// y кг конфет стоят:
var y := ReadReal;
var ay := a * y / x;
Writeln(ay);
271
Задание Begin34
Опять конфетная задача:
Но уже на 2 сорта конфет.
Так как стоимость 1 кг конфет мы уже научились вычислять, то тут и сказочке, то
есть задачке – конец:
## uses PT4;
Task('ABegin34');
// вес и стоимость шоколадных конфет:
var (x, a) := ReadReal2;
// 1 кг шоколадных конфет стоит:
var a1 := a / x;
Writeln(a1);
// вес и стоимость ирисок:
var (y, b) := ReadReal2;
272
// 1 кг ирисок стоит:
var b1 := b / y;
Writeln(b1);
// во ск. раз шок. конфеты дороже ирисок:
var r := a1 / b1;
Writeln(r);
Задание Begin35
Типичная задача из школьной математики:
Так как скорость и время движения нам известны, то путь легко вычислить по формуле, данной в условии задачи:
## uses PT4;
Task('ABegin35');
// скорости:
273
var (v, u) := ReadReal2;
// время:
var (t1, t2) := ReadReal2;
// путь лодки по озеру:
var s1 := v * t1;
// путь лодки по реке:
var s2 := (v - u) * t2;
Весь путь равен сумме путей, пройденных лодкой по озеру и по реке:
// общий путь лодки:
var s := s1 + s2;
Writeln(s);
Задание Begin36
Также школьная задача:
274
Всё решение уже подробно изложено в условии задачи, поэтому нам остаётся
только аккуратно переписать его:
## uses PT4;
Task('ABegin36');
// скорости:
var (v1, v2) := ReadReal2;
// начальное расстояние между автомобилями:
var s0 := ReadReal;
// время движения:
var t := ReadReal;
// расстояние между автомобилями через t часов:
var s := s0 + t * (v1 + v2);
Writeln(s);
275
Задание Begin37
На этот раз автомобили двигаются навстречу друг другу, что усложняет нашу и без
того простую задачу:
Впрочем, в условии задачи имеется подсказка, которой мы и воспользуемся:
## uses PT4;
Task('ABegin37');
// скорости:
var (v1, v2) := ReadReal2;
// начальное расстояние между автомобилями:
var s0 := ReadReal;
// время движения:
var t := ReadReal;
// расстояние между автомобилями через t часов:
var s := Abs(s0 - t * (v1 + v2));
Writeln(s);
276
Задание Begin38
Линейное уравнение – это уравнение с неизвестным(и) в первой степени:
Линейное уравнение в общем виде записывается так:
Ax + B = 0
Решить уравнение – значит найти х.
Для этого нужно преобразовать уравнение так, чтобы в левой части осталось
только неизвестное:
x = -B / A
Так как коэффициент А не равен нулю, то на него можно делить безбоязненно и
безнаказанно.
Переписываем выражение для х на паскаль – и задача решена:
## uses PT4;
Task('ABegin38');
// коэффициенты:
var (a, b) := ReadReal2;
277
// решение:
var x := -b / a;
Writeln(x);
Задание Begin39
От линейных уравнений переходим к квадратным:
К счастью, нам не нужно вспоминать, как решаются квадратные равнения, - вся
информация уже содержится в условии задачи.
В первую очередь, нам нужно вычислить дискриминант:
## uses PT4;
Task('ABegin39');
// коэффициенты:
var (a, b, c) := ReadReal3;
278
// дискриминант:
var d := b * b - 4 * a * c;
После чего мы легко находим оба корня квадратного уравнения:
// корни уравнения:
var x1 := (-b - Sqrt(d)) / 2 / a;
var x2 := (-b + Sqrt(d)) / 2 / a;
Writeln(x1, x2);
Задание Begin40
Последнее задание в этом наборе:
Решать задачи на систему линейных уравнений очень интересно, но в этом задании нам нужно только переписать информацию из условия задачи:
279
## uses PT4;
Task('ABegin40');
// коэффициенты уравнения 1:
var (a1, b1, c1) := ReadReal3;
// коэффициенты уравнения 2:
var (a2, b2, c2) := ReadReal3;
var d := a1 * b2 - a2 * b1;
// решение:
var x := (c1 * b2 - c2 * b1) / d;
var y := (a1 * c2 - a2 * c1) / d;
Writeln(x, y);
Набор заданий Integer
В предыдущем наборе заданий вы пользовались литералами и переменными
типа double. На этот раз почти во всех задачах особое внимание уделяется целому
типу integer и арифметическим операциям над целыми числами:
Целочисленное деление div
Деление по модулю (остаток от деления) mod
Нажмите кнопку Создать шаблон программы на Панели инструментов (клавиатурное сокращение Ctrl+Shift+L) (Рис. 1).
Рис. 1. По шаблону
280
Откроется диалоговое окно PT4 Load. Набираем в текстовом поле Задание буквы
In (в любом регистре) и получаем внизу диалогового окна полное название
группы (Рис. 2).
Рис. 2. Целочисленная группа
Достаточно нажать клавишу ПРОБЕЛ, чтобы название группы было закончено автоматически. Также вы получите подсказку: в наборе 30 заданий (Рис. 3).
Рис. 3. Трижды десять
Начинаем с первого задания, поэтому печатаем цифру 1 (Рис. 4).
281
Рис. 4. Начинаем с первого
Все приготовления закончены. Нажмите кнопку Загрузка или клавишу ВВОД (Рис. 5).
Рис. 5. Погрузка закончена
В Редакторе кода появилась страница Integer1.pas с заготовкой кода для задания
Integer1 (Рис. 6).
Рис. 6. Заготовительные работы
282
Итак, первое задание такое (Рис. 7).
Рис. 7. Читаем внимательно!
Во всех заданиях должны быть:
операторы ввода и вывода Read/Readln и Write/Writeln
операторы объявления переменных
арифметические/математические выражения с операциями целочисленного деления div и деления по модулю mod
операторы присваивания
Запомните:
Все переменные должны иметь целый тип integer.
Все операторы должны заканчиваться точкой с запятой.
Все переменные должны объявляться в главном блоке части программы
непосредственно перед их использованием.
Знак операции присваивания состоит из двух символов – двоеточия и
знака равенства, которые пишутся слитно.
Идентификаторы переменных пишутся с маленькой буквы.
Левая часть оператора присваивания (переменная) должна иметь тот
же тип (или совместимый), что и правая часть. Если тип левой части
оператора присваивания совпадает с типом правой части, то его можно
не указывать.
Для объявления переменных используется ключевое слово var.
283
Тип переменной указывается после её идентификатора в операторе объявления через двоеточие.
Если в программе используется значение переменной, то она должна
быть инициализирована, то есть ей должно быть присвоено какое-либо
значение того же типа (или совместимого). По умолчанию все переменные целого типа получают значение 0, но лучше и правильнее присваивать значения переменным самостоятельно.
Оператор присваивания действует так. Сначала вычисляется значение
правой части, а затем оно присваивается переменной в левой части.
В левой части оператора присваивания должна стоять переменная.
В выражениях всегда используется текущее значение переменной.
Для обозначения операции целочисленного деления в паскале используют ключевое слово div. При этом оба операнда должны иметь целый тип. Результат деления также имеет целый тип. Если делимое не делится нацело, то результат (частное) округляется до ближайшего целого:
если частное положительное, то оно округляется до ближайшего целого
числа, которое меньше частного. Иначе говоря, отбрасывается дробная
часть частного от деления.
если частное отрицательное, то результатом будет ближайшее целое число,
которое больше частного. То есть и в этом случае отбрасывается дробная
часть частного.
Вернёмся к задаче.
В 1 метре содержится 100 сантиметров (если вы забыли, то внимательно прочитайте условие задачи). Это значит, что число сантиметров нужно просто нацело
разделить на 100. В результате мы получим целое число метров, так как дробная
часть частного будет отброшена.
## uses PT4;
Task('Integer1');
// расстояние в см:
284
var l := ReadInteger;
// метраж:
var m := l div 100;
Writeln(m);
Для самопроверки и самоконтроля запускаем программу и убеждаемся, что задача решена верно (Рис. 8).
Рис. 8. Задача решена
Действительно, если разделить 3526 на 100, то получится 35,26. После отбрасывания дробной части останется 35, что и требовалось доказать.
Обращаю ваше внимание, что после отбрасывания дробной части получается не
вещественное число 35.0, а целое – 35.
285
Задание Integer2
Переходим ко второму заданию:
Практически такое же задание, что и первое, только для превращения килограмм
в тонны нужно делить на 1000:
## uses PT4;
Task('Integer2');
// масса в кг:
var m := ReadInteger;
// тоннаж:
var t := m div 1000;
Writeln(t);
286
Задание Integer3
Третье задание воплощает поговорку повторение – мать учения:
У программистов кило чего-то это не 1000, как у обычных людей (см. предыдущую
задачу), поэтому в килобайте 1024 байтов.
Для нас было бы проще делить на 1000, а компьютеру наоборот – на 1024:
## uses PT4;
Task('Integer3');
// размер в байтах:
var b := ReadInteger;
// размер в килобайтах:
var kb := b div 1024;
Writeln(kb);
Если вы когда-нибудь покупали жёсткие, полужёсткие и мягкие диски, то могли
убедиться, что изготовители и продавцы дружно считают, что кило это 1000, поэтому объём памяти дисков на самом деле всегда оказывается меньше, чем
утверждают эти деятели.
287
Задание Integer4
Условие четвёртого задания длинное и путанное:
А суть его такова: поделить число А нацело на число В.
Что мы и делаем с удовольствием:
## uses PT4;
Task('Integer4');
// числа:
var (a, b) := ReadInteger2;
// кратность:
var k := a div b;
Writeln(k);
288
Задание Integer5
Добавок к предыдущему заданию:
Эту задачу вполне можно решить, используя только операцию целочисленного
деления:
## uses PT4;
Task('Integer5');
// числа:
var (a, b) := ReadInteger2;
// кратность:
var k := a div b;
// занято на а:
var z := k * b;
// не занято на а:
var nz := a - z;
Writeln(nz);
289
Но в условии задачи ясно и недвусмысленно требуется использовать операцию
деления по модулю, которая обозначается ключевым словом mod. И здесь все переменные и литералы должны быть целого типа! Результат операции – целое
число - остаток от деления первого операнда на второй.
Как вы уже знаете, операцию деления по модулю можно заменить операцией целочисленного деления, используя равенство:
x mod y = x - (x div y) * y
С операцией деления по модулю исходный код программы становится совсем
простым:
## uses PT4;
Task('Integer5');
// числа:
var (a, b) := ReadInteger2;
// остаток:
var k := a mod b;
Writeln(k);
290
Задание Integer6
Cледующее задание:
Наконец-то мы получили задание, в котором можно было бы хоть немного подумать, но в условии задачи прямо указано, что число десятков нужно найти с помощью операции деления нацело, а единиц – с помощью операции деления по
модулю:
## uses PT4;
Task('Integer6');
// двузначное число:
var de := ReadInteger;
// число десятков:
var d := de div 10;
// число единиц:
var e := de mod 10;
Writeln(d, e);
291
Задание Integer7
Усложнённый вариант шестого задания:
Так как находить цифры двузначного числа вы уже умеете, то вычислить их сумму
и произведение не составит большого труда:
## uses PT4;
Task('Integer7');
// двузначное число:
var de := ReadInteger;
// число
var d :=
// число
var e :=
десятков:
de div 10;
единиц:
de mod 10;
// сумма цифр:
var sum := d + e;
// произведение цифр:
var mul := d * e;
Writeln(sum, mul);
292
Задание Integer8
Очередное усложнение:
Чтобы переставить цифры в числе, нужно сначала их найти. Вы это умеете.
При перестановке цифр десятки становятся единицами, а единицы – десятками.
Из этого следует, что «перестановленное» число равно:
10 * единицы + десятки
Вот и вся задача!
## uses PT4;
Task('Integer8');
// двузначное число:
var de := ReadInteger;
// число
var d :=
// число
var e :=
десятков:
de div 10;
единиц:
de mod 10;
// переставляем цифры:
var ed := e * 10 + d;
293
Writeln(ed);
Задание Integer9
Добрались до трёхзначных чисел:
Так как нам нужно найти число сотен в заданном числе, то и делить нужно на
сотню:
## uses PT4;
Task('Integer9');
// трёхзначное числр:
var sde := ReadInteger;
// число сотен:
var s := sde div 100;
Writeln(s);
294
Задание Integer10
На этот раз нам нужно найти число единиц и десятков в трёхзначном числе:
Извлекать число единиц из любого числа вы умеете. Для этого используется операция деления по модулю 10.
Чтобы получить число десятков, нужно… превратить их в единицы, а затем действовать так, как указано выше.
Нетрудно догадаться, что при делении трёхзначного числа на 10 от него останутся
две первые цифры. Это значит, что десятки переместятся на место единиц.
Для сокращения кода весь процесс извлечения десятков можно записать в одну
строку:
## uses PT4;
Task('Integer10');
// трёхзначное числр:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
295
// число десятков:
var d := sde div 10 mod 10;
Writeln(e, d);
Задание Integer11
К десяткам и единицам добавились сотни трёхзначного числа:
Все эти цифры вы уже умеете извлекать из числа:
## uses PT4;
Task('Integer11');
// трёхзначное число:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
296
var s := sde div 100;
// сумма цифр:
var sum := s + d + e;
// произведение цифр:
var mul := s * d * e;
Writeln(sum, mul);
Задание Integer12
Более сложная задача на перестановку цифр в числе:
Все цифры трёхзначного числа мы легко найдём.
При их перестановке единицы займут место сотен, сотни – место единиц, а десятки так десятками и останутся:
## uses PT4;
Task('Integer12');
// трёхзначное число:
var sde := ReadInteger;
297
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
// число-палиндромоид:
var pal := e * 100 + d * 10 + s;
Writeln(pal);
Задание Integer13
Почти такое же задание, что и предыдущее, но цифры переставляются на новый
лад:
Чтобы понять, какие места займут цифры в новом числе, внимательно посмотрите
на картинку выше.
Ага! Сотни становятся единицами, десятки – сотнями, единицы – десятками. Если
вы ничего не перепутали, то должен получиться вот такой код:
298
## uses PT4;
Task('Integer13');
// трёхзначное число:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
// новое число:
var num := d * 100 + e * 10 + s;
Writeln(num);
Задание Integer14
Опять задача на проверку бдительности:
299
Но если вы её не потеряли, а, наоборот, сберегли, то должны написать такой код:
## uses PT4;
Task('Integer14');
// трёхзначное число:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
// новое число:
var num := e * 100 + s * 10 + d;
Writeln(num);
Задание Integer15
Как говорится, найдите разницу:
300
Нашли? – Тогда я вас поздравляю: с новым кодом!
## uses PT4;
Task('Integer15');
// трёхзначное число:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
// новое число:
var num := d * 100 + s * 10 + e;
Writeln(num);
301
Задание Integer16
Опять перестановка цифр:
Исходный код в дополнительных комментариях не нуждается:
## uses PT4;
Task('Integer16');
// трёхзначное число:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
// новое число:
var num := s * 100 + e * 10 + d;
Writeln(num);
302
Задание Integer17
Наконец-то пошли большие числа:
Вы уже догадались, что из n-значного числа нужно получить 3-значное или я первый?
Чтобы выделить из любого числа 3 последние цифры, нужно найти остаток от деления этого числа на 1000:
## uses PT4;
Task('Integer17');
// число:
var num := ReadInteger;
// трёхзначное число:
var sde := num mod 1000;
// число сотен:
var s := sde div 100;
Writeln(s);
303
Задание Integer18
Числа растут, как грибы после дождя:
Следуя логике предыдущего задания, мы должны сначала получить 4-значное
число, а затем найти в нём число тысяч делением на 1000:
## uses PT4;
Task('Integer18');
// число:
var num := ReadInteger;
// четырёхзначное число:
var tsde := num mod 10000;
// число тысяч:
var t := tsde div 1000;
Writeln(t);
304
Задание Integer19
Возвращаемся к простым задачам на целочисленное деление:
Достаточно вспомнить, что в 1 минуте 60 секунд – и задача решена:
## uses PT4;
Task('Integer19');
// число секунд:
var n := ReadInteger;
// число минут:
var min := n div 60;
Writeln(min);
305
Задание Integer20
Продолжение часовых задач:
Мы уже вспомнили, что в 1 минуте 60 секунд. Вспоминаем дальше: в 1 часе – 60
минут. Можно найти число часов в одну строчку кода, но обычно программисты
это делают не спеша, с расстановкой:
## uses PT4;
Task('Integer20');
// число секунд:
var n := ReadInteger;
// число минут:
var min := n div 60;
// число часов:
var h := min div 60;
Writeln(h);
306
Задание Integer21
Напряжение растёт:
Прежде чем браться за решение этой задачи, следует в ней разобраться.
До начала последней минуты прошло целое число минут, а осталось меньше одной минуты. Из этого рассуждения следует, что сначала мы должны найти число
целых минут в n секундах:
## uses PT4;
Task('Integer21');
// число секунд:
var n := ReadInteger;
// число минут:
var min := n div 60;
Теперь мы можем узнать, сколько в них секунд:
// число секунд в min минут:
var sec := min * 60;
307
Если мы вычтем из общего числа секунд число секунд в полных минутах, то как
раз и получим число секунд, прошедших с начала последней минуты:
// остаток секунд:
var ost := n - sec;
Writeln(ost);
Задание Integer22
Усугубление предыдущей задачи:
На этот раз мы должны найти число полных часов в n секундах:
## uses PT4;
Task('Integer22');
// число секунд:
var n := ReadInteger;
// число минут:
var min := n div 60;
// число часов:
308
var h := min div 60;
Дальше действуем так, как и в предыдущей задаче, учитывая специфику задачи
текущей:
// число секунд в h часов:
var sec := h * 60 * 60;
// остаток секунд:
var ost := n - sec;
Writeln(ost);
Задание Integer23
Минуты сменяются секундами – вот и новая задача:
Находим число полных часов в n секундах:
## uses PT4;
Task('Integer23');
// число секунд:
309
var n := ReadInteger;
// число минут:
var min := n div 60;
// число часов:
var h := min div 60;
А дальше снова – повторение – мать учения:
// число минут в h часов:
var minh := h * 60;
// остаток минут:
var ost := min - minh;
Writeln(ost);
Задание Integer24
С повышением! От часов мы перешли к календарю:
310
Если не задаваться вопросом, почему дни пронумерованы таким странным образом, то задача решается в одно действие:
## uses PT4;
Task('Integer24');
// число:
var k := ReadInteger;
// номер дня недели:
var num := k mod 7;
Writeln(num);
Но это только потому, что первый день года был понедельником!
Задание Integer25
Однако не каждый год начинается так удачно:
Следующий год начался сразу с четверга, хотя в жизни так не бывает!
311
Если первый день года пришёлся на четверг, то для K = 1 остаток от деления числа
прошедших дней на 7 (число дней в неделе) должен равняться 4, поскольку это
был четверг (четвёртый день недели).
Из этой предварительной арифметики следует, что к числу К нужно добавить 3,
чтобы получить верный результат:
## uses PT4;
Task('Integer25');
// число:
var k := ReadInteger;
// номер дня недели:
var num := (k + 3) mod 7;
Writeln(num);
Все остальные дни автоматически пронумеруются правильно.
312
Задание Integer26
Путаница с календарём продолжается:
Во-первых, мы должны учесть, что дни теперь нумеруются с единицы, а остаток
от деления равен 0..6. Чтобы получить правильный день, всегда нужно добавлять
единицу к остатку от деления.
Так как первый день недели был вторником (день номер 2), то при К = 1 (с учётом
добавочной единицы) мы как раз получим двойку, поэтому дни недели вычисляются очень просто:
## uses PT4;
Task('Integer26');
// число:
var k := ReadInteger;
// номер дня недели:
var num := k mod 7 + 1;
Writeln(num);
313
Задание Integer27
Любите ли вы задачи с календарём так, как их люблю я?
Из предыдущей задачи вы знаете, что к остатку от деления нужно добавить единицу. Это первое.
На второе: если бы год начался со вторника, то к числу К ничего не нужно было
бы добавлять. Но опять случилась оказия, и год начался с субботы. Это значит, что
к числу К нужно добавить: среда – 1, четверг – 2, пятница – 3, суббота – 4. Логично?
– Аналогично!
## uses PT4;
Task('Integer27');
// число:
var k := ReadInteger;
// номер дня недели:
var num := (k + 4) mod 7 + 1;
Writeln(num);
314
Задание Integer28
Как вы помните, на Острове невезения не было календаря. А у нас каждый год –
новый календарь:
С добавочной единицей всё понятно. А вот, что делать с числом N? – Рассуждаем:
если N = 2, то к числу К нужно добавить 0. Это следует из задачи про вторник. Если
N = 6, то к числу К нужно добавить 4. А это следует уже из задачи про субботу.
Небольшое умственно-мышечное усилие – и вот его результат: из числа N необходимо вычесть 2, чтобы получить правильный день недели по новому календарю:
## uses PT4;
Task('Integer28');
// числа:
var (k, n) := ReadInteger2;
// номер дня недели:
var num := (k + n - 2) mod 7 + 1;
Writeln(num);
315
Задание Integer29
Резкий и неожиданный переход от календаря к прямоугольникам:
Так как квадраты должны целиком поместиться на предложенной им жилплощади, то мы легко найдём общее число квадратов, удобно расположившихся по
ширине и по высоте прямоугольника:
## uses PT4;
Task('Integer29');
// числа:
var (a, b, c) := ReadInteger3;
// число
var numw
// число
var numh
квадратов по ширине:
:= a div c;
квадратов по высоте:
:= b div c;
// общее число квадратов:
var num := numw * numh;
316
Если из площади прямоугольника вычесть площадь этих квадратов, то мы получим свободную площадь:
// площадь квадратов:
var s := num * c * c;
// остаток площади:
var ost := a * b - s;
Writeln(num, ost);
Задание Integer30
Резкий возвратный скачок к календарю:
Номер столетия легко найти делением по модулю 100. Но при этом мы должны
учитывать, что отсчёт времени начался не с нулевого года, а с первого, и столетие
также было не нулевое, а первое. В таких случаях, как вы уже знаете, к остатку от
деления нужно добавлять 1.
А так как первый год был именно первым, а не нулевым, то из номера года нужно
1 вычесть:
317
## uses PT4;
Task('Integer30');
// номер года:
var ng := ReadInteger;
// номер столетия:
var ns := (ng - 1) div 100 + 1;
Writeln(ns);
Если вы помните, была большая календарная неразбериха с новым тысячелетием. Гуманитарно образованные граждане считали, что новое тысячелетие
начнётся 1 января 2000 года. Математически образованные сограждане, пользуясь таблицей умножения и здравым смыслом, утверждали, что 2 тысячелетия –
это 2000 прошедших лет. Следовательно, новое, третье тысячелетие начнётся 1
января 2001 года. Так оно и началось!
318
Исполнительный Робот
Нельзя научиться программировать, усердно штудируя учебник. Тут нужна практика! Только перерешав сотню-другую (а лучше больше!) задач, вы твёрдо усвоите основы языка паскаль.
На начальном обучении очень важна наглядность. В предлагаемых дальше заданиях она достигается за счёт использования Исполнителя, который называется
Роботом. Это виртуальный автомат, умеющий выполнять определённый набор
команд для перемещения по полю и закрашивания клеток.
Все наборы заданий для Робота были созданы Станиславом Станиславовичем
Михалковичем, руководителем проекта PascalABC.NET, в 2002-2019 годах. Они
идеально подходят для изучения программирования по таким темам как:
переменные
внутриблочные переменные
оператор присваивания
комбинированные операторы присваивания
математические операции
логические операции or и and
логические выражения и условный оператор if-else
цикл с параметром for
цикл с условием while
вложенные циклы
процедуры без параметров
процедуры с параметрами
операторы exit и break
Так как управлять Роботом невозможно без предварительной разработки алгоритма, то выполнение заданий хорошо развивает и укрепляет:
логическое и алгоритмическое мышление
умение находить и исправлять ошибки в алгоритме
умение находить оптимальные решения
319
Имея правильный алгоритм, вы легко сможете перевести его на любой процедурный язык: паскаль, Си-шарп, Дельфи, Джаву или Питон. Поэтому решение задач
на паскале в будущем существенно облегчит вам изучение других, не «учебных»
языков программирования.
В книге имеется исчерпывающая информация по каждому набору заданий, а
также подробно разбирается решение всех задач (а их около полутора сотен!). Но
это не значит, что вы должны просто копировать готовые решения! Сначала попробуйте найти собственное решение. Оно не обязательно должно совпадать с
решением автора книги. И только при затруднениях вы можете «подглядывать» в
книгу. Решив задачу собственным способом, сравните его с предложенным. Может быть, ваше решение окажется лучше…
Задания хотя и занимательны по форме, но вполне серьёзны по содержанию, так
что вам нередко придётся хорошенько подумать, разрабатывая алгоритм. Однако
наглядное воплощение алгоритма в виде перемещения
Робота по полю сильно облегчит вам понимание сути заданий и отладку алгоритмов. Но
имейте в виду, что система
PascalABC.NET строго следит
за правильностью выполнения
заданий, поэтому не надейтесь решить задачу по принципу
Вовки-в-Тридевятомцарстве: А, ладно, и так сойдёт!
Дальше вы найдёте полезные
советы по решению заданий. Прежде чем приступать к работе, прочитайте их.
Другие приложения пригодятся вам при изучении команд Робота, а также при
составлении собственных заданий.
320
Исполнители
Исполнители – это объекты программы, которые умеют выполнять определённый
набор команд, который называют также системой команд исполнителя (СКИ).
Исполнители традиционно используются для обучения детей программированию. Первым исполнителем была знаменитая Черепашка в языке программирования Лого (Рис. 1).
Рис. 1. Знаменитая Черепашка-долгожительница
Теперь Черепашки имеются во многих языках программирования, например, в
паскале, Смолл Бейсике и Питоне. Черепашка умеет поворачиваться и ползти
вперёд на заданное расстояние, прочерчивания за собой прямую линию.
Со времени создания Черепашки появилось много новых исполнителей – Кузнечик, Чертёжник, Хамстер. А в этом номере журнала вы познакомитесь с Роботом, который поможет вам наглядно изучить основные конструкции языка паскаль.
321
Исполнитель Робот
У лукоморья дуб зелёный;
Златая цепь на дубе том:
И днём и ночью кот учёный
Всё ходит по цепи кругом;
Идёт направо - песнь заводит,
Налево - сказку говорит.
А.С. Пушкин, Руслан и Людмила
Исполнитель Робот имеет покладистый нрав и умеет выполнять
простые команды.
Его рабочее место – игровое поле представляет собой прямоугольник,
разбитый на квадратные клетки.
Сам Робот – это тоже квадрат, но, в
отличие от белых клеток поля, он
окрашен в жёлтый цвет и немного
меньше клеток по размеру.
В начале решения задачи он находится в стартовой позиции. Маленький квадратик в левом верхнем углу
одной из клеток поля отмечает его
финишную позицию. В ней Робот
должен закончить свой путь.
А его работа заключается в том, чтобы закрасить клетки поля, обозначенные
точками, которые находятся в их центре.
Игровое поле по периметру обнесено неприступной стеной, через которую Робот перешагнуть не может. Подобные стены могут разделять также клетки поля,
и тогда Робот не сможет перейти из одной клетки в другую, даже в соседнюю
(Рис. 1).
322
Рис. 1. Робот и окружающая среда
Робот может переходить из одной клетки в другую, соседнюю, выполняя следующие команды (Рис. 2):
Right – идти вправо
Left – идти влево
Down – идти вниз
Up – идти вверх
323
Рис. 2. Направления переходов
Давайте посмотрим, как выглядит исходная позиция задания а1 в запущенной
программе (Рис. 3).
Рис. 3. «Вот и первое заданье…»
324
Во второй строке (считаем сверху, с единицы) вы видите Робота в исходной позиции.
В первой, верхней строке располагаются 4 клетки с точками – их нужно закрасить.
Левая верхняя клетка помечена маленьким квадратиком – в неё должен прийти
Робот, когда закрасит все клетки.
Сейчас Робот может сделать ход вниз, влево или вправо. Но если он попытается
пойти вверх, то вы получите сообщение об аварии (Рис. 4), и выполнение задания
прекратится.
Рис. 4. ДТП
Итак, у Робота остаётся для начала только 3 хода на выбор: пойти налево,
направо или вниз. Любой из этих ходов допустим, но Робот должен не просто
бродить по полю, а стремиться как можно быстрее выполнить задание. Это значит, что нужно за минимальное число ходов добраться до первой клетки с точкой
и закрасить её. На Рис. 3⬆ хорошо видно, что для Робота первая клетка с точкой
– это самая правая из них. Робот не сможет добраться до других точек, минуя её.
325
Легко догадаться, что, прежде всего, Робот должен выполнить 4 шага вправо,
чтобы обогнуть стену (Рис. 5).
Рис. 5. Идём направо
Теперь он может беспрепятственно подняться на верхнюю горизонталь (Рис. 6).
Рис. 6. И вверх
326
И тут начинаются настоящие малярные работы!
Запомните: Робот может закрасить только ту клетку, в
которой он находится.
Значит, Робот должен сделать шаг влево, а затем уже закрасить клетку (Рис. 7).
Рис. 7. Первая закраска!
327
Эти действия он должен повторить трижды, чтобы закрасить и остальные клетки
(Рис. 8).
Рис. 8. Все клетки закрашены
Робот делает последний, решающий шаг влево, чтобы закончить задание (Рис. 9).
Рис. 9. Задание выполнено!
328
Дрессируем Робота
Итак, на бумаге мы справились с задачей. Действительно, Робот только выполнял наши команды, поэтому
слава и почёт должны достаться авторам, а не исполнителям. Но как заставить Робота, даже самого послушного выполнять наши команды в реальной программе? –
А их нужно записать в исходном коде, который Робот
умеет читать.
Но сначала мы должны получить задания для последующего их осмысливания и исполнения.
Самый простой и в то же время правильный путь в этом направлении – нажать
кнопку Создать шаблон программы на Панели инструментов или клавиши
Ctrl+Shitf+L. Вы это уже знаете.
В диалоговом окне Загрузка задания, в текстовом поле Задание набираем буквы
букв RB (в любом регистре), которые означают Robot, и получаем внизу диалогового окна буквы для наборов заданий. Нам нужен самый первый набор а, который
предназначен для предварительного знакомства с системой команд Робота. Добавляем в текстовое поле Задание букву а и опять получаем подсказку: в наборе
4 задания. Конечно, начинать нужно с первого задания, поэтому печатаем цифру
1 (Рис. 1).
Рис. 1. Можно начинать
329
Все приготовления закончены, и мы нажимаем кнопку Загрузка или клавишу
ВВОД. В Редакторе кода появилась страница RBa1.pas с заготовкой кода для задания а1 (Рис. 2).
Рис. 2. Заготовительно-приготовительные работы закончены
Строчка
uses Robot;
подключает к проекту модуль Robot.pas, без которого Робот не появится на
экране.
В главном блоке программы записан вызов процедуры Task, которой мы передаём строку 'a1' с названием задания.
Вы можете запустить программу, нажав кнопку Выполнить на Панели инструментов.
На экране появится окно с заданием, игровое поле и элементы управления (Рис.
3).
Всегда внимательно читайте верхнюю строку, в которой находится задание для
Робота.
В нижней части окна выводятся сообщения о текущем состоянии программы. Сейчас вы можете прочитать там, что Робот готов к выполнению команд.
Кнопка Выход (клавиша Esc) закрывает программу.
330
Кнопка Справка (клавиша F1) открывает одноимённое диалоговое окно, в котором перечислены все команды Робота, а также условия, которые может проверять Робот по ходу выполнения задания (Рис. 3).
Рис. 2. Конкретное задание
Команды перемещения Робота вам уже известны, а новая команда Paint закрашивает клетку, в которой Робот находится.
При отладке команд следует пользоваться пошаговым перемещением Робота,
чтобы внимательно наблюдать за каждым его действием. При обнаружении
ошибки, нужно исправить исходный код и снова запустить программу.
Чтобы выполнить 1 шаг, нажмите кнопку Шаг или клавишу ПРОБЕЛ (Рис. 4).
331
Рис. 3. Всегда держите под рукой!
Набравшись смелости, мы дерзко нажимаем на эту кнопку, но Робот не двигается с места, а мы получаем обидное сообщение, что Работа окончена, задание
не выполнено (Рис. 5).
332
Рис. 4. Пошагали?
Рис. 5. Топчемся на месте
333
Всё верно, ведь мы не дали Роботу ни одной команды!
Возвращаемся в Редактор кода и после вызова процедуры Task аккуратно выписываем команды, которые придумали раньше:
uses Robot;
begin
Task('a1');
// идём направо без закраски:
Right;
Right;
Right;
Right;
// поднимаемся вверх без закраски:
Up;
// идём налево с закраской:
Left; Paint;
Left; Paint;
Left; Paint;
Left; Paint;
// идём налево без закраски:
Left;
end.
Если вы внимательно читали книгу, то здесь для вас нет ничего нового, поэтому
запускайте программу и нажимайте кнопку Шаг. Робот послушно переходит из
одной клетки в другую, выполняя команды, пока, наконец, не окажется на базе.
Следующее нажатие на кнопку Шаг остановит программу, которая порадует вас
приятным сообщением, что Задание выполнено (Рис. 6).
Закройте программу, а затем снова запустите её. На этот раз нажмите кнопку Пуск.
Робот самостоятельно и быстро выкрасит все заданные клетки и окажется на
базе. Программа также сообщит вам, что Роботу потребовалось сделать 15 шагов
для выполнения задания. Если вы пересчитаете команды, то их окажется только
334
14. Лишняя команда появилась из-за того, что при запуске программы считается,
что Робот уже сделал 1 шаг, хотя он и не сдвинулся с места.
Рис. 6. С выполнением!
Скорость перемещения Робота можно изменять ползунком Скорость. Двигайте
его вправо, чтобы Робот шёл быстрее, влево – медленнее.
Сохраните исходный код программы на диске и готовьтесь к новым испытаниям!
## uses Robot;
Task('a1');
// идём направо без закраски:
Right;
Right;
335
Right;
Right;
// поднимаемся вверх без закраски:
Up;
// идём налево с закраской:
Left; Paint;
Left; Paint;
Left; Paint;
Left; Paint;
// идём налево без закраски:
Left;
336
Набор заданий a Исполнитель Робот
Первое задание мы уже решили. Осталось ещё 3 задания для знакомства с командами Робота.
Задание а2
Получите заготовку для второго задания.
Так как прежде чем браться за выполнение задания, его нужно увидеть, то запустите программу и внимательно посмотрите на картинку с заданием (Рис. 1).
Рис. 1. Требуется особое внимание
Если вы не можете сразу найти решение, то скопируйте игровое поле на листочек
в клеточку и нарисуйте путь Робота.
В данном случае понятно, что самый короткий путь для Робота такой:
337
обойти клетки с точками по часовой стрелке или
обойти клетки с точками против часовой стрелки
Что касается начальной клетки, то её можно закрасить сразу, а можно и в конце
выполнения задания, поскольку Робот всё равно в неё должен вернуться.
Я выбрал вариант движения по часовой стрелке без закраски начальной клетки,
тогда Робот сначала идёт вправо, закрашивает клетку, опять идёт вправо и закрашивает клетку.
И эти действия он повторяет по остальным направлениям – вниз, влево, вверх.
Вернувшись на базу, он закрашивает последнюю клетку – и задача решена!
Переписать команды в главную часть программы не составляет никакого труда:
## uses Robot;
Task('a2');
// идём направо:
Right; Paint;
Right; Paint;
// идём вниз:
Down; Paint;
Down; Paint;
// идём налево:
Left; Paint;
Left; Paint;
// идём вверх:
Up; Paint;
Up; Paint;
338
Задание а3
Получите заготовку для третьего задания, запустите программу и ознакомьтесь с
игровой ситуацией (Рис. 1).
Рис. 1. Третье задание
Тут, как говорится, без вариантов. Робот обязательно должен закрасить начальную клетку, потому что он в неё больше не вернётся. А дальше он двигается зигзагом: вниз – вправо – вверх – вправо, и так до базовой клетки. Каждую клетку
Робот должен закрасить. Задание очень простое (Рис. 2):
## uses Robot;
Task('a3');
// закрашиваем первую клетку:
Paint;
// идём вниз и закрашиваем вторую клетку:
Down; Paint;
339
// идём вправо:
Right; Paint;
// идём вверх:
Up; Paint;
// идём вправо:
Right; Paint;
// идём вниз:
Down; Paint;
// идём вправо:
Right; Paint;
// идём вверх:
Up; Paint;
Рис. 2. Осторожно: закрашено!
340
Задание а4
И вот мы дошли до последнего задания в первом наборе (Рис. 1).
Рис. 1. Четвёртое задание
Задача чуть сложнее предыдущей, но тоже решается в уме.
Идём вверх до упора, переходим вправо, опускаемся до дна, закрашиваем там
клетку, выбираемся наверх, и так далее (Рис. 2):
## uses Robot;
Task('a4');
// поднимаемся до верхней горизонтали:
Up;Up;
// идём вправо до второй колонки:
Right;
// опускаемся до дна и закрашиваем клетку:
Down;Down;Paint;
// поднимаемся до верхней горизонтали:
341
Up;Up;
// идём вправо до третьей колонки:
Right;
// опускаемся до дна и закрашиваем клетку:
Down;Down;Paint;
// поднимаемся до верхней горизонтали:
Up;Up;
// идём вправо до четвёртой колонки:
Right;
// опускаемся до дна и закрашиваем клетку:
Down;Down;Paint;
// задание выполнено // возвращаемся на базу:
Up;Up;
Left;Left;Left;
Down; Down;
Рис. 2. На дне
342
Исполнитель Чертёжник
По-английски чертёжник называется DrawMan, поэтому набираем в диалоговом
окне буквы DM (Рис. 1).
Рис. 1. Нам нужен Чертёжник
Как видите, для Чертёжника вы можете выполнить 5 групп заданий:
a – вводные задания
c – цикл с параметром
cc – вложенные циклы
p – процедуры без параметров
pp – процедуры с параметрами
Буквы латинские!
343
Набор заданий a Исполнитель Чертёжник
Нас интересуют только первые 3 группы заданий, которые расположены по мере
возрастания сложности. Наберите имя группы и номер задания. Нажмите кнопку
Загрузка (Рис. 1).
Рис. 1. Чертёжник загружен
Задание a1
Исправляем заготовку для первого задания:
## uses Drawman;
Task('a1');
Запускаем программу и читаем первое задание (Рис. 1).
Читаем подсказку:
Команда ToPoint(x, y) – перемещает Чертёжника в точку (x, y).
Значит, инструкция ToPoint(2, 3); переместит Чертёжника в нижнюю точку
(начало) отрезка.
344
Рис. 1. По косой
Команда OnVector(a, b) – перемещает Чертёжника на вектор (a, b). То есть на a
клеток по горизонтали и на b клеток по вертикали. a и b – это приращения текущих
координат Чертёжника.
Значит, инструкция OnVector(1, 2); переместит Чертёжника в точку с координатами (x + a, y + b). Это верхняя точка отрезка (конец).
Запускаем программу. Чертёжник правильно выполнил команды, но не задание
(Рис. 2).
По умолчанию перо Чертёжника поднято, поэтому он не оставляет за собой следов.
345
Рис. 2. И что не так?
Знакомимся с двумя новыми командами Чертёжника:
PenUp – поднимает перо Чертёжника
PenDown – опускает перо Чертёжника
Наши действия (алгоритм) решения задачи таков:
С помощью команды ToPoint устанавливаем Чертёжника в начале линии.
Перо поднято, поэтому он ничего не начертит.
Опускаем перо командой PenDown.
- С помощью команды OnVector гоним Чертёжника в конец линии. Перо
опущено, поэтому он начертит отрезок заданной прямой.
Первая программа готова:
346
## uses Drawman;
Task('a1');
ToPoint(2, 3);
PenDown;
OnVector(1, 2);
После выполнения задания Чертёжника обязательно следует вернуть в начало координат:
// заканчиваем задание:
PenUp;
ToPoint(0, 0);
Задание выполнено (Рис. 3).
Рис. 3. Прочертили
347
Задание a2
Во втором задании Чертёжник должен четырежды выполнить первое задание,
каждый раз возвращаясь на исходную позицию (Рис. 1).
Рис. 1. В разные стороны
Каждый раз нужно поднимать и опускать перо (Рис. 2).
## uses Drawman;
Task('a2');
// чертим первый отрезок:
ToPoint(5, 4);
PenDown;
OnVector(3, 1);
PenUp;
// чертим второй отрезок:
348
ToPoint(5, 4);
PenDown;
OnVector(-4, 2);
PenUp;
// чертим третий отрезок:
ToPoint(5, 4);
PenDown;
OnVector(-2, -2);
PenUp;
// чертим третий отрезок:
ToPoint(5, 4);
PenDown;
OnVector(2, -3);
// заканчиваем задание:
PenUp;
ToPoint(0, 0);
Рис. 2. Получилось
349
Попробуйте найти решение
с меньшим числом операций
поднимания и опускания пера!
Задание a3
В этом задании 3 линии, которые не имеют общих точек (Рис. 1).
Рис. 1. Трёхлинейка
Чертим каждую линию в отдельности:
350
## uses Drawman;
Task('a3');
// первая линия:
ToPoint(3, 2);
PenDown;
OnVector(0, 3);
PenUp;
// вторая линия:
ToPoint(4, 4);
PenDown;
OnVector(5, -1);
PenUp;
// третья линия:
ToPoint(2, 1);
PenDown;
OnVector(4, 0);
// заканчиваем задание:
PenUp;
ToPoint(0, 0);
Главное в этом задании - не
ошибиться с координатами
(Рис. 2).
351
Рис. 2. Строго по компасу
352
Задание a4
Каждый квадрат – это замкнутая ломаная линия: конец одной линии – это начало
следующей (Рис. 1).
Рис. 1. Три квадрата
Каждый квадрат чертим, начиная с верхнего левого угла по часовой стрелке. Для
этого переносим Чертёжника с поднятым пером в этот угол. Опускаем перо и
перемещаем Чертёжника по всем сторонам. Тогда все квадраты вычерчиваются
одинаково – нужно только следить за длиной сторон:
## uses Drawman;
Task('a4');
353
// первый квадрат:
ToPoint(1, 5);
PenDown;
OnVector(2, 0);
OnVector(0, -2);
OnVector(-2, 0);
OnVector(0, 2);
PenUp;
// второй квадрат:
ToPoint(5, 6);
PenDown;
OnVector(3, 0);
OnVector(0, -3);
OnVector(-3, 0);
OnVector(0, 3);
PenUp;
// третий квадрат:
ToPoint(3, 2);
PenDown;
OnVector(1, 0);
OnVector(0, -1);
OnVector(-1, 0);
OnVector(0, 1);
PenUp;
// заканчиваем задание:
PenUp;
ToPoint(0, 0);
Отквадратились мы великолепно
(Рис. 2)!
354
Рис. 2. Три квадрата в готовом виде
355
Задание a5
Прямоугольники хуже квадратов – у них стороны разные (Рис. 1).
Рис. 1. Плохие квадраты
Поскольку Чертёжник после вычерчивания прямоугольника возвращается в исходную точку, то легко догадаться, что если он идёт влево на а клеток, то затем он
пойдёт вправо на столько же клеток:
## uses Drawman;
Task('a5');
// первый пр-к:
ToPoint(1, 6);
PenDown;
356
OnVector(1, 0);
OnVector(0, -5);
OnVector(-1, 0);
OnVector(0, 5);
PenUp;
// второй пр-к:
ToPoint(3, 7);
PenDown;
OnVector(4, 0);
OnVector(0, -3);
OnVector(-4, 0);
OnVector(0, 3);
PenUp;
// третий пр-к:
ToPoint(4, 3);
PenDown;
OnVector(3, 0);
OnVector(0, -2);
OnVector(-3, 0);
OnVector(0, 2);
PenUp;
// заканчиваем задание:
PenUp;
ToPoint(0, 0);
Вышло изящно и великолепно
(Рис. 2).
357
Рис. 2. И эти туда же
358
Задание a6
Все цифры хороши, кроме четвёрки (Рис. 1).
Рис. 1. Четыре цифры
Но мы и четвёрку вычертили на пятёрку (Рис. 2):
## uses Drawman;
Task('a6');
// 1:
ToPoint(2, 3);
PenDown;
359
OnVector(1, 1);
OnVector(0, -2);
PenUp;
// 2:
ToPoint(4, 4);
PenDown;
OnVector(1, 0);
OnVector(0, -1);
OnVector(-1, -1);
OnVector(1, 0);
PenUp;
// 3:
ToPoint(6, 4);
PenDown;
OnVector(1, 0);
OnVector(-1, -1);
OnVector(1, 0);
OnVector(-1, -1);
PenUp;
// 4:
ToPoint(8, 4);
PenDown;
OnVector(0, -1);
OnVector(1, 0);
OnVector(0, -1);
PenUp;
ToPoint(9, 4);
PenDown;
OnVector(0, -1);
// заканчиваем задание:
PenUp;
ToPoint(0, 0);
360
Рис. 2. Всё отлично
361
Логический тип данных
Вы уже знаете, что, кроме чисел, символов и строк, в паскале есть и логический тип данных. Он имеет 2 значения –
логических литерала: true (истина) и false (ложь), поэтому
все логические переменные и выражения могут принимать
только эти два значения.
Логические переменные и операторы
Все наши программы выполнялись строго последовательно – от первой строки
исходного кода до последней. Это вполне возможно в коротких программах, но
гораздо чаще необходимо выполнять исходный код программы, реагируя на какие-либо события, происходящие в работающей программе. Например, пользователь нажмёт кнопку мышки или переменная x получит значение 10. Для этого
нужны логические операторы и выражения, которые активно используются управляющими структурами.
Проект Построчно
Для экспериментов нам понадобится достаточно длинный код, который вы можете скопировать, например, из файла Арифметика паскаля.pas.
Чтобы увидеть, в каком порядке выполняются строки программы, нажмите кнопку
Шаг с заходом в подпрограмму на Панели инструментов (Рис. 1).
Рис. 1. Отладочные кнопки
Программа перейдёт на первую выполняемую строку исходного кода. Она выделена жёлтым фоном и жёлтой стрелкой (Рис. 2).
362
Рис. 2. Строка программы, которая будет выполняться
Эта строка ещё не выполнена, поэтому снова нажмите ту же самую кнопку. Программа выполнит первую строку и перейдёт на вторую.
После инициализации переменная а получит значение 6, в чём легко убедиться,
установив курсор на её идентификаторе (Рис. 3).
Рис. 3. Значения локальных переменных
Ещё больше информации о локальных переменных можно получить в одноимённом окне. Здесь вы видите, что переменная а имеет тип integer и значение – 6. Все
363
остальные переменные проинициализированы компилятором и получили нулевые значения.
По мере продвижения по исходному коду в Окне вывода будет появляться информация о вычисленных значениях арифметических выражений (Рис. 4).
Рис. 4. Пошаговое выполнение программы
Если вы попадёте в файл PABCSystem.pas, то нажимайте кнопку Шаг без входа в
подпрограмму (Рис. 5).
Рис. 5. На выход
364
Поскольку в нашем коде подпрограмм нет, то дальше вы можете пользоваться
только этой кнопкой.
Вернувшись в окно Локальные переменные, вы можете просмотреть текущие значения локальных переменных (Рис. 6).
Рис. 6. Контролируем локальные переменные
Точно таким же способом вы можете проводить простейшую отладку исходного
кода.
Прекратить выполнение программы вы можете в любой момент, нажав кнопку
Завершить (Рис. 7).
Рис. 7. Пора пресечь
Построение программы, когда все её операторы выполняются друг за другом,
называется структурой следования. Все наши программы были именно такими.
365
Логический тип
Для объявления переменных логического типа используется ключевое слово
boolean:
var
var
var
var
f : boolean;
a, b, c : boolean;
d := false;
e := true;
Ключевое
слово
boolean
является
псевдонимом
типа
System.Boolean, поэтому вы можете объявлять логические
переменные, указывая тип .NET:
var g: System.Boolean;
Полное название типа Boolean происходит от фамилии английского математика и логика Джорджа Буля (Рис. 1), поэтому логический тип называют также булевым.
Рис. 1. Джордж Буль (George Boole, 1815-1864)
366
Проект Логический тип
Для исследования логического типа начните новый файл и определите 3 логические переменные:
##
// ЛОГИЧЕСКИЙ ТИП
var a := false;
var b := true;
var c := a;
PrintLn(' a =', a);
PrintLn(' b =', b);
PrintLn(' c =', c);
Распечатываем их значения на экране (Рис. 1).
Рис. 1. Логические переменные
Инициализируйте локальные переменные до их использования в программе!
Логические значения могут быть преобразованы в строки методом ToString, что
вы и видели в программе. Обратная операция выполняется с помощью функций
Parse и и TryParse (Рис. 2):
var s := 'true';
PrintLn(boolean.Parse(s));
Рис. 2. Работает!
367
Операторы и операции отношения (сравнения)
Операции отношения предназначены для сравнения двух операндов совместимых типов (например, целых и вещественных, символов и строк).
Результат всегда имеет логический тип и равен true, если указанное соотношение
выполняется, и false - в противном случае.
Проект Операции отношения
Начните новый проект, в котором мы рассмотрим логические выражения и действие логических операторов отношения.
= - оператор равенства
Результат сравнения равен true, если операнды равны, и false, если не равны.
Определите две целочисленные переменные x и y, а затем сравните их между
собой с помощью оператора равенства:
##
// ОПЕРАТОРЫ И ОПЕРАЦИИ ОТНОШЕНИЯ (СРАВНЕНИЯ)
// оператор равенства =
var x := 7;
var y := 13;
Println('
Println('
Println('
Println('
Println('
x
y
x
x
x
=', x);
=', y);
= y -->', (x = y));
= 3 -->', (x = 3));
= 2+5 -->', (x = 2 + 5));
Запустите программу – она полностью подтверждает наши ожидания (Рис. 1).
368
Рис. 1. Операция прошла успешно
Поскольку в этих операциях используются текущие значения переменных, то
операции сравнения можно записать более наглядно:
7 = 13
false
7 = 3
false
7 = 2 + 5 true
То есть значение логического выражения 7 = 13 равно false (ложь), а логического
выражения 7 = 2 + 5 – true (истина). Действительно, утверждение, что число 7
равно числу 13 - ложно, а утверждение, что число 7 равно сумме чисел 2 и 5 –
истинно.
< - оператор сравнения «меньше»
Результат сравнения равен true, если первый операнд меньше второго, и false,
если больше или равен (не меньше).
Добавьте новую порцию кода:
// оператор
Println(' x
Println(' x
Println(' x
сравнения «меньше» <
< y
-->', (x < y));
< 3
-->', (x < 3));
< 2+5 -->', (x < 2 + 5));
и прочитайте в Окне вывода результаты сравнения двух операндов (Рис. 2).
369
Рис. 2. Действие логического оператора меньше
Опять «исследуем» более наглядную запись:
7 < 13
true
7 < 3
false
7 < 2 + 5 false
Легко убедиться, что результаты сравнения верные.
<= - оператор сравнения «меньше или равно» (не больше)
Результат сравнения равен true, если первый операнд меньше второго или равен ему, и false, если больше (Рис. 3).
// оператор
Println(' x
Println(' x
Println(' x
сравнения «меньше или равно» (не больше) <=
<= y
-->', (x <= y));
<= 3
-->', (x <= 3));
<= 2+5 -->', (x <= 2 + 5));
7 <= 13
true
7 <= 3
false
7 <= 2 + 5 true
Рис. 3. Действие оператора меньше или равно
Обратите внимание, что результат сравнения верный, когда:
370
Первый операнд меньше второго
Первый операнд равен второму
Результат сравнений ложный, когда:
Первый операнд больше второго
> - оператор сравнения «больше»
Результат сравнения равен true, если первый операнд больше второго, и false,
если меньше или равен (не больше) (Рис. 4).
// оператор
Println(' x
Println(' x
Println(' x
сравнения «больше» >
> y
-->', (x > y));
> 3
-->', (x > 3));
> 2+5 -->', (x > 2 + 5));
Рис. 4. Действие оператора больше
7 > 13
false
7 > 3
true
7 > 2 + 5 false
=> - оператор сравнения «больше или равно» (не меньше)
371
Результат сравнения равен true, если первый операнд больше второго или равен ему, и false, если меньше (Рис. 5).
// оператор
Println(' x
Println(' x
Println(' x
сравнения «больше или равно» (не меньше) >=
>= y
--> ', (x >= y));
>= 3
--> ', (x >= 3));
>= 2+5 --> ', (x >= 2 + 5));
Рис. 5. Действие оператора больше или равно
7 >= 13
false
7 >= 3
true
7 >= 2 + 5 true
<> - оператор неравенства
Результат сравнения равен true, если операнды не равны, и false, если равны
(Рис. 6).
// оператор
Println(' x
Println(' x
Println(' x
неравенства <>
<> y
--> ', (x <> y));
<> 3
--> ', (x <> 3));
<> 2+5 --> ', (x <> 2 + 5));
В Си-шарпе и в других языках программирования используется знак операции != , который, очевидно, должен напоминать математический знак неравенства ≠.
7 >= 13
false
7 >= 3
true
7 >= 2 + 5 true
372
Рис. 6. Действие оператора неравенства
Условные логические операции
Условные логические операции применяются к логическому типу данных, и результат операции также имеет логический тип. Операция логического отрицания
унарная, остальные – бинарные. Для обозначения логических операций используют логические операторы AND, OR, XOR и NOT.
Проект Логические операции
В результате выполнения операции логического отрицания истинное выражение
становится ложным, и наоборот:
NOT - оператор логического отрицания НЕ
Результат операции равен true, если значение операнда равно false, и false,
если значение операнда равно true, то есть:
not false true
not true false
Эта логическая операция называется также инверсией.
Начните новый проект и добавьте код, который изменяет значение логических
выражений сравнения:
##
373
// УСЛОВНЫЕ ЛОГИЧЕСКИЕ ОПЕРАЦИИ
var x := 7;
var y := 13;
Println(' x =', x);
Println(' y =', y);
// оператор логического отрицания НЕ
Println(' (x = y) -->', (x = y));
Println(' (x = 3) -->', (x = 3));
Println(' (x = 2 + 5)
-->', (x = 2
Println(' not (x = y)
-->', (not(x
Println(' not (x = 3)
-->', (not(x
Println(' not (x = 2 + 5) -->', (not(x
+
=
=
=
5));
y)));
3)));
2 + 5)));
Рис. 7 показывает действие оператора not.
Рис. 7. Логическая операция отрицания
То же самое в цифрах:
not(7 = 13)
true
not(7 = 3)
true
not(7 = 2 + 5) false
Здесь вы видите, что ложные выражения превратились в истинные, а истинные –
в ложные.
374
Логическое выражение (не отдельную переменную) необходимо заключить в скобки!
AND - логический оператор И
Результат операции тогда и только тогда истинный, когда истинны одновременно оба операнда.
Эта логическая операция называется также конъюнкцией.
Дополните проект новым кодом:
// логический оператор И (AND)
var res := (x = 2 + 5) and (x < y);
Println(' (x = 2 + 5) and (x < y) -->', res);
res := (x <> y) and (x <= y);
Println(' (x <> y) and (x <= y)
-->', res);
res := (x = y) and (x = 7);
Println(' (x = y) and (x = 7)
-->', res);
Мы обычно говорим с «пропусками» слов, но при этом прекрасно понимаем, о чём идёт речь. Например: переменная x
равна y И меньше семи:
x=y И< 7
Говоря на языке паскаль, пропускать слова нельзя, поэтому
вы должны сказать так: переменная x равна y И переменная
x меньше семи:
(x = y) and (x < 7)
Каждое логическое выражение должно быть взято в скобки!
375
Запустите программу и убедитесь, что правило действует (Рис. 8).
Рис. 8. Логическая операция И
(x = 2 + 5) and (x < y) true
(x <> y) and (x <= y)
true
(x = y) and (x = 7)
false
В первом логическом выражении операция сравнения x = 2 + 5 вернёт true, так как
переменная x равна 7. Операция сравнения x < y также вернёт true, потому что
значение переменной x меньше значения переменной y. То есть после выполнения операций сравнения выражение примет вид:
true and true true
Поскольку оба операнда имеют значение true, то и значение всего логического
выражения равно true, значит, оно истинно.
Остальные три выражения разберите самостоятельно!
(7 = 2 + 5) and (7 < 13) true
(7 <> 13) and (7 <= 13) true
(7 = 13) and (7 = 7)
false
OR - логический оператор ИЛИ
Результат операции истинный, если хотя бы один операнд истинен.
376
Эта логическая операция называется также дизъюнкцией.
Для исследования этой логической операции достаточно в предыдущем коде заменить оператор and оператором or:
// логический оператор ИЛИ (OR)
var res := (x = 2 + 5) or (x < y);
Println(' (x = 2 + 5) or (x < y) -->', res);
res := (x <> y) or (x <= y);
Println(' (x <> y) or (x <= y)
-->', res);
res := (x = y) or (x = 7);
Println(' (x = y) or (x = 7)
-->', res);
Здесь изменилось значение только последнего логического выражения (Рис. 8).
(x = 2 + 5) or (x < y) true
(x <> y) or (x <= y)
true
(x = y) or (x = 7)
true
Рис. 8. Логическая операция ИЛИ
Значение выражения сравнения x = y равно false, ведь значение переменной x
равно 7, а значение переменной y равно 13. Значение выражения x = 7 равно true.
Итак, мы получили более простое логическое выражение:
false or true
377
Первый операнд ложный, но второй – истинный. Этого достаточно для того, чтобы
всё логическое выражение было истинным:
false or true true
Опять для наглядности заменим идентификаторы переменных их значениями:
(7 = 2 + 5) or (7 < 13) true
(7 <> 13) or (7 <= 13) true
(7 = 13) or (7 = 7)
true
XOR - логический оператор ИСКЛЮЧАЮЩЕЕ ИЛИ
Результат операции истинный, если операнды имеют разные значения, и ложный – если одинаковые.
Эта логическая операция называется также сложением по модулю 2.
Исправьте название операции в предыдущем коде, а также операторы сравнения
во втором логическом выражении:
// логический оператор ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR)
var res := (x = 2 + 5) xor (x < y);
Println(' (x = 2 + 5) xor (x < y) -->', res);
res := (x = y) xor (x >= y);
Println(' (x = y) xor (x > y)
-->', res);
res := (x = y) xor (x = 7);
Println(' (x = y) xor (x = 7)
-->', res);
Значения этих логических выражений вы
видите на Рис. 9.
Рис.
9.
Логическая
ИСКЛЮЧАЮЩЕЕ ИЛИ
операция
378
(x = 2 + 5) xor (x < y) false
(x = y) xor (x >= y)
false
(x = y) xor (x = 7)
true
Рассуждая, как и раньше, мы получим для первого логического выражения:
true xor true false
Поскольку оба операнда имеют одинаковые значения, то результат операции
ложный.
Второе логическое выражение приводится к более простой форме:
false xor false false
Здесь опять оба операнда имеют одинаковые значения, поэтому результат операции ложный.
В третьем логическом выражении операнды имеют разные значения: первый операнд ложный, второй истинный, поэтому всё логическое выражение истинное:
false xor true true
Заменяем идентификаторы переменных их значениями:
(7 = 2 + 5) xor (7 < 13) false
(7 = 13) xor (7 >= 13)
false
(7 = 13) xor (7 = 7)
true
379
<Таблица истинности>
Поскольку условные логические операции встречаются в программировании буквально на каждом шагу, то давайте сведём все результаты их выполнения в одну
таблицу:
Здесь логические операции выполняются так:
(Логическое выражение exp1) AND (Логическое выражение exp2)
(Логическое выражение exp1) OR (Логическое выражение exp2)
(Логическое выражение exp1) XOR (Логическое выражение exp2)
Приоритеты операций
Мы уже вспомнили приоритеты арифметических операций, но поскольку операций в паскале значительно больше, то давайте заполним таблицу, чтобы в дальнейшем вы могли легко находить в ней нужную информацию.
В программировании, как и в математике, все операции выполняются в полном
соответствии с их приоритетом (старшинством). Операции с более высоким приоритетом выполняются раньше операций, приоритет которых ниже. Если приоритет операций одинаков, то они выполняются последовательно слева направо.
380
Таблица <Приоритеты операций>
Операторы
()
**
+
NOT
*
/
div
mod
AND
+
OR
XOR
<
>
<=
>=
=
<>
:=
*=
/=
+=
-=
Действие
Выражения в круглых скобках
Возведение в степень
Унарные
операции
отрицания
и
идентификации
Операция логического отрицания
Арифметические операции умножения,
деления и деления по модулю
Операция логического И
Бинарные арифметические операции сложения и вычитания
Операция логического ИЛИ
Логического операция ИСКЛЮЧАЮЩЕЕ ИЛИ
Операции отношения
Операции равенства
Операции присваивания
Операторы в соседних строках одного цвета имеют равный
приоритет.
381
С помощью круглых скобок можно изменять порядок вычисления выражений.
Сначала выполняются операции в скобках. Если внутри скобок имеются вложенные скобки, то вычисления начинаются с самых глубоко вложенных скобочных
выражений.
Например, арифметическое выражение
10 * (21 / (3 + 4) - 5)
вычисляется так. Находим самые глубоко вложенные скобки, вычисляем выражение в них и подставляем результат в выражение:
10 * (21 / (3 + 4) - 5) 10 * (21 / 7 - 5)
Опять вычисляем выражение в скобках:
10 * (21 / 7 - 5) 10 * (-2)
И наконец, выполняем операцию умножения:
10 * (-2) -20
Вопрос: правильно ли записаны выражения 10 * (-2) и 10 * -2?
Добавляем к проекту пару строк:
Println(' 10 * (-2) =', 10 * (-2));
Println(' 10 * -2
=', 10 * -2);
и узнаём, что обе записи верные (Рис. 10).
Рис. 10. Скобки нужны не всегда
382
А ответ, почему это так, вы легко найдёте в Табл. Приоритеты операций. Действительно, приоритет оператора унарного минуса выше, чем оператора умножения,
поэтому при вычислении выражения сначала будет выполнена операция изменения знака, а затем умножения. Таким образом, скобки в выражении 10 * (-2) не
нужны. Однако следует заметить, что с ними выражение становится более понятным, а это гораздо важнее, чем сэкономить пару скобок!
Обобщение
Переменные, константы и выражения логического типа boolean могут принимать 2 значения: true (истина) и false (ложь).
Для сравнения операндов совместимых типов используют операции отношения (равенства), обозначаемые знаками:
= - оператор равенства
<> - оператор неравенства
< - оператор сравнения «меньше»
<= - оператор сравнения «меньше или равно» (не больше)
> - оператор сравнения «больше»
>= - оператор сравнения «больше или равно» (не меньше)
Результат операций отношения имеет логический тип.
К значениям логического типа применяют условные логические операции, обозначаемые ключевыми словами:
NOT - оператор логического отрицания НЕ
AND - логический оператор И
OR - логический оператор ИЛИ
XOR - логический оператор ИСКЛЮЧАЮЩЕЕ ИЛИ
Операция логического отрицания унарная, остальные – бинарные.
383
Все операции, в том числе и логические, выполняются в соответствии с их приоритетом.
Определить результат условной логической операции вам поможет Таблица
истинности.
Набор заданий Boolean
Продвигаемся в глубь паскаля и решаем третий набор заданий из электронного
задачника по программированию Programming Taskbook 4 - Boolean. В них особое
внимание уделяется логическому типу boolean и логическим операциям:
Логическое отрицание НЕ - not
Логическое И - and
Логическое ИЛИ - or
Логическое ИСКЛЮЧАЮЩЕЕ ИЛИ – xor
В этом наборе 40 заданий.
Задание Boolean1
Итак, первое задание такое:
В этой задаче высказывание – это логическое выражение, которое может иметь 2
значения:
384
true – истинное высказывание
false – ложное высказывание
Высказывание Число А является положительным можно записать на языке паскаль так: A > 0
На этом решение заканчивается:
## uses PT4;
Task('Boolean1');
// число:
var a := ReadInteger;
// высказывание:
var v := a > 0;
Writeln(v);
Не забывайте печатать ответ на экране!
Задание Boolean2
Переходим ко второму заданию:
Целое число называется нечётным, если оно не делится на 2 без остатка. На языке
паскаль это определение можно записать так:
385
Abs(a) mod 2 = 1
Это выражение можно упростить, если использовать функцию Odd, которая возвращает true, если значение параметра нечётное:
## uses PT4;
Task('Boolean2');
// число:
var a := ReadInteger;
// высказывание:
var v := Odd(a);
Writeln(v);
Задание Boolean3
Второе задание, но наоборот:
Если целое число – чётное, то оно делится на 2 без остатка:
Abs(a) mod 2 = 0
386
Здесь мы можем использовать ту же функцию Odd, но, чтобы заданное выражение было истинным, к результату нужно применить операцию логического отрицания not. Она изменяет значение логического выражения на противоположное,
то есть истинное становится ложным, а ложное – истинным:
not true false
not false true
Таким образом выражение not Odd(а) истинно, если число а чётное:
## uses PT4;
Task('Boolean3');
// число:
var a := ReadInteger;
// высказывание:
var v := not Odd(a);
Writeln(v);
Задание Boolean4
Высказывание уже дано в условии задания:
387
Нам нужно только заменить союз и знаком логической операции логическое И –
and. Помните, что отдельные логические выражения, входящие в состав сложного, следует заключать в круглые скобки!
## uses PT4;
Task('Boolean4');
// числа:
var (a, b) := ReadInteger2;
// высказывание:
var v := (a > 2) and (b <= 3);
Writeln(v);
Задание Boolean5
Здесь на смену логической операции И пришла другая логическая операция – ИЛИ
- or:
Никаких сложностей при решении этой задачи вы не встретите:
## uses PT4;
Task('Boolean5');
// числа:
388
var (a, b) := ReadInteger2;
// высказывание:
var v := (a >= 0) or (b < -2);
Writeln(v)
Задание Boolean6
В этом задании сложное высказывание записано так, как принято в математике:
В программировании сложное высказывание должно соединяться логическими
операторами AND или OR. Таким образом, сначала нужно разбить сложное высказывание на простые. В данном случае их два:
A<BиB<C
Так как они должны выполняться (быть истинными) одновременно (оба), то для
объединения простых высказываний нужно использовать операцию логического
И, то есть and:
## uses PT4;
Task('Boolean6');
// числа:
var (a, b, c) := ReadInteger3;
// высказывание:
389
var v := (a < b) and (b < c);
Writeln(v)
Задание Boolean7
Задача на числовую ось:
«Нарисуем» числовую ось и отметим на ней заданные числа:
А---В---С
С---В---А
Первая схема описывает ситуацию, когда А – самое маленькое из трёх чисел. Вторая – когда самое большое.
Если число В находится между А и С, то в первом случае должно выполняться
двойное неравенство:
А<В<С
Во втором случае неравенство должно быть таким:
С<В<А
Чтобы учесть оба случая, нужно соединить эти неравенства логической операцией
ИЛИ:
## uses PT4;
390
Task('Boolean7');
// числа:
var (a, b, c) := ReadInteger3;
// высказывание:
var v := ((a < b) and (b < c)) or ((a > b) and (b > c));
Writeln(v)
Задание Boolean8
Задание на сложное логическое выражение:
Нечётные числа вы уже умеете определять с помощью функции Odd, так что нам
осталось соединить 2 простых выражения в одно сложное.
Если каждое из чисел А и В нечётное, то они нечётные одновременно, то есть для
связки нужно использовать логическую операцию И:
## uses PT4;
Task('Boolean8');
// числа:
var (a, b) := ReadInteger2;
// высказывание:
var v := Odd(a) and Odd(b);
391
Writeln(v)
Задание Boolean9
Вариация на тему предыдущего задания:
Высказывание Хотя бы одно из чисел нечётное означает, что:
ИЛИ А нечётное
ИЛИ В нечётное
ИЛИ А и В нечётные
Так как не обязательно оба числа одновременно должны быть нечётными, то для
связки простых логических выражений нужно использовать логическую операцию
ИЛИ:
## uses PT4;
Task('Boolean9');
// числа:
var (a, b) := ReadInteger2;
// высказывание:
var v := Odd(a) or Odd(b);
Writeln(v)
392
Задание Boolean10
А вот это уже интересно:
Нечётность заданных чисел мы, как обычно, проверяем с помощью функции Odd,
поэтому простые высказывания будут точно такими же, как и в предыдущих заданиях. Вопрос в том, как из них получить сложное высказывание/выражение.
Здесь самое время вспомнить о последней логической операции в паскале:
XOR - логическая операция ИСКЛЮЧАЮЩЕЕ ИЛИ
Результат операции тогда и только тогда будет истинным, если один операнд
истинен, а второй ложен, во всех остальных случаях результат будет ложным.
Из её описания становится понятно, что если простые логические выражения –
это Odd(А) и Odd(В), то сложное логическое выражение должно быть истинным
только тогда, когда одно из них истинное, а второе – ложное. Следовательно, для
связки простых логических выражений нужно использовать операцию
ИСКЛЮЧАЮЩЕЕ ИЛИ:
## uses PT4;
Task('Boolean10');
// числа:
var (a, b) := ReadInteger2;
// высказывание:
393
var v := Odd(a) xor Odd(b);
Writeln(v)
Задание Boolean11
Ещё более коварная задача:
Простые высказывания:
Odd(А) и Odd(В)
Они одновременно должны быть либо ложными, либо истинными. Если же одно
из выражений истинное, а второе ложное, то и сложное выражение должно быть
ложным. Если мы применим к простым выражениям логическую операцию
ИСКЛЮЧАЮЩЕЕ ИЛИ, то получим то, что нам нужно, но наоборот. А «наоборот»
легко исправить с помощью оператора логического отрицания not.
Вот это настоящая логика!
## uses PT4;
Task('Boolean11');
// числа:
var (a, b) := ReadInteger2;
// высказывание:
var v := not (Odd(a) xor Odd(b));
394
Writeln(v);
Задание Boolean12
Более длинная задача, чем мы решали раньше, но очень легкая:
Все 3 простых высказывания одновременно должны быть верными, поэтому их
нужно соединить в сложное выражение с помощью операции ЛОГИЧЕСКОГО И:
## uses PT4;
Task('Boolean12');
// числа:
var (a, b, c) := ReadInteger3;
// высказывание:
var v := (a > 0) and (b > 0) and (c > 0);
Writeln(v)
Задание Boolean13
Почти такое же задание, что и предыдущее, но на логическую операцию
ЛОГИЧЕСКОЕ ИЛИ:
395
В предыдущем коде заменяем ключевое слово and ключевым словом or – и это всё:
## uses PT4;
Task('Boolean13');
// числа:
var (a, b, c) := ReadInteger3;
// высказывание:
var v := (a > 0) or (b > 0) or (c > 0);
Writeln(v)
Задание Boolean14
Совершенно интересная задача:
В данном случае сложное выражение получается не только сложным, но и длинным, поэтому мы пойдём другим путём.
396
Определяем переменную sum:
## uses PT4;
Task('Boolean14');
// числа:
var (a, b, c) := ReadInteger3;
var sum := 0;
И добавляем к её значению 1, если число положительное:
sum := a > 0 ? sum + 1 : sum;
sum := b > 0 ? sum + 1 : sum;
sum := c > 0 ? sum + 1 : sum;
Здесь для сокращения записи мы применили условный оператор ?:
Он действует так. Если логическое выражение истинно, то выполняется действие
после знака вопроса, то есть к значению переменной sum прибавляется 1:
sum := sum + 1
Если логическое выражение ложно, то выполняется действие после двоеточия:
sum := sum
То есть сумма не изменяется.
Теперь по окончательному значению переменной sum мы легко определим,
сколько было положительных чисел:
// высказывание:
var v := sum = 1;
Writeln(v)
397
Задание Boolean15
Найдите разницу:
А разница такая: теперь нам нужны 2 положительных числа:
## uses PT4;
Task('Boolean15');
// числа:
var (a, b, c) := ReadInteger3;
var sum := 0;
sum := a > 0 ? sum + 1 : sum;
sum := b > 0 ? sum + 1 : sum;
sum := c > 0 ? sum + 1 : sum;
// высказывание:
var v := sum = 2;
Writeln(v)
Задание Boolean16
Несложное задание на сложное логическое выражение:
398
Для начала найдём простые высказывания:
число чётное
число двузначное
Так как простые высказывания одновременно должны быть истинными, то они
должны соединяться в сложном выражении логической операцией ЛОГИЧЕСКОЕ
И.
Если мы обозначим число буквой а, то первое высказывание можно записать так:
not Odd(a)
Если число а чётное, то высказывание истинное.
Со вторым высказыванием сложнее. Мы легко определим, что число двузначное,
если оно состоит из двух цифр. Но как это сделает компьютер? – Так как компьютер охотнее считает, чем думает, то мы можем предложить ему такой вариант
определения двузначности заданного числа:
Если число больше 9 И меньше 100, то оно двузначное.
Эти условия должны выполняться одновременно, поэтому выражения (a > 9) и (a
< 100) нужно соединить операцией ЛОГИЧЕСКОГО И.
Осталось собрать все наши рассуждения вместе – и задача решена:
## uses PT4;
Task('Boolean16');
399
// число:
var a := ReadInteger;
// высказывание:
var v := not Odd(a) and (a > 9) and (a < 100);
Writeln(v);
С оператором in решается ещё проще, но требует больше знаний в программировании:
var v := not Odd(a) and (a in 11..99);
Или даже так:
var v := a in Range(10, 98, 2);
Задание Boolean17
Задача, которая легко решается после предыдущей:
Нечётность числа мы определяем с помощью функции Odd, а трёхзначность так:
Если число больше или равно 100 И меньше или равно 999, то оно трёхзначное.
## uses PT4;
400
Task('Boolean17');
// число:
var a := ReadInteger;
// высказывание:
var v := Odd(a) and (a >= 100) and (a <= 999);
Writeln(v)
Можно использовать и строгие неравенства:
(a > 99) and (a < 1000)
но они не так хороши, потому что в них присутствуют нетрёхзначные числа.
Решение с оператором in:
var v := Odd(a) and (a in 101..999);
var v := a in Range(101, 999, 2);
Задание Boolean18
Для этой задачи можно придумать очень длинное логическое выражение:
401
Поэтому мы опять пускаемся на хитрость и находим сумму совпадающих пар чисел. К счастью, из трёх чисел можно составить всего 3 пары, так что работы у нас
немного:
## uses PT4;
Task('Boolean18');
// числа:
var (a, b, c) := ReadInteger3;
var
sum
sum
sum
sum :=
:= a =
:= b =
:= c =
0;
b ? sum + 1 : sum;
c ? sum + 1 : sum;
a ? sum + 1 : sum;
// высказывание:
var v := sum > 0;
Writeln(v)
Если хотя бы одна пара чисел совпадает, то значение переменной sum будет
больше нуля.
Но в данном случае «классическое» решение короче и понятнее:
## uses PT4;
Task('Boolean18');
// числа:
var (a, b, c) := ReadInteger3;
// высказывание:
var v := (a = b) or (b = c) or (c = a);
Writeln(v)
402
Задание Boolean19
По сути, та же самая задача, что и предыдущая:
Взаимно противоположными называются числа, равные по абсолютной величине,
но имеющие разные знаки:
## uses PT4;
Task('Boolean19');
var (a, b, c) := ReadInteger3;
var
sum
sum
sum
sum :=
:= a =
:= b =
:= c =
0;
-b ? sum + 1 : sum;
-c ? sum + 1 : sum;
-a ? sum + 1 : sum;
// высказывание:
var v := sum > 0;
Writeln(v)
Так как сумма взаимно противоположных чисел равна нулю, то можно использовать и такое выражение:
sum := a + b = 0 ? sum + 1 : sum
403
Сумма двух взаимно противоположных чисел равна нулю. Если имеется хотя бы
одна пара взаимно противоположных чисел, то произведение трёх различных
сумм также равно нулю:
## uses PT4;
Task('Boolean19');
var (a, b, c) := ReadInteger3;
// высказывание:
var v := (a + b) * (b + c) * (c + a) = 0;
Writeln(v)
Задание Boolean20
Более серьёзная задача:
Так как число трёхзначное, то оно состоит из трёх цифр, которые нужно предварительно из него извлечь:
## uses PT4;
Task('Boolean20');
// трёхзначное число:
var sde := ReadInteger;
404
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
Остальные действия очень простые.
Если все цифры различны, то ни одна пара цифр не совпадает:
var
sum
sum
sum
sum :=
:= s =
:= s =
:= d =
0;
d ? sum + 1 : sum;
e ? sum + 1 : sum;
e ? sum + 1 : sum;
// высказывание:
var v := sum = 0;
Writeln(v);
«Классический» вариант решения более понятен и приятен:
## uses PT4;
Task('Boolean20');
// трёхзначное число:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
405
// высказывание:
var v := (s <> d) and (s <> e) and (d <> e);
Writeln(v);
Задание Boolean21
Более сложная задача с трёхзначными числами:
Предварительно выделяем из заданного числа его цифры:
## uses PT4;
Task('Boolean21');
// трёхзначное число:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
406
Если цифры образуют возрастающую последовательность, то каждая следующая
больше предыдущей. То есть число десятков больше числа сотен, а число единиц
больше числа десятков:
// высказывание:
var v := (s < d) and (d < e);
Writeln(v)
Задание Boolean22
Опять наши любимые трёхзначные числа:
Первую половину этой задачи мы уже решили.
Если же цифры образуют убывающую последовательность, то знак < в простых выражениях нужно заменить знаком >. Но это ещё не всё! Две половинки задачи
нужно соединить логической операцией ИЛИ:
## uses PT4;
Task('Boolean22');
// трёхзначное число:
var sde := ReadInteger;
// число единиц:
var e := sde mod 10;
407
// число десятков:
var d := sde div 10 mod 10;
// число сотен:
var s := sde div 100;
// высказывание:
var v := (s < d) and (d < e);
v := v or ((s > d) and (d > e));
Writeln(v)
Задание Boolean23
А в этом задании и вовсе четырёхзначное число!
Но процесс выделения цифр из числа вы уже хорошо изучили, поэтому переходим
к логическому выражению:
## uses PT4;
Task('Boolean23');
// четырёхзначное число:
var tsde := ReadInteger;
// число единиц:
var e := tsde mod 10;
// число десятков:
408
var d := tsde div 100 mod 10;
// число сотен:
var s := tsde div 10 mod 10;
// число тысяч:
var t := tsde div 1000;
Глядя на рисунок в начале задания, вы легко сообразите, что, если число одинаково читается в обе стороны, то число тысяч в нём равно числу единиц, а число
сотен равно числу десятков:
// высказывание:
var v := (t = e) and (s = d);
Writeln(v)
Задание Boolean24
Логико-математическая задача:
Чтобы её решить, необходимо вспомнить, когда квадратное уравнение имеет вещественные корни. Дискриминант вам в подмогу!
Итак, если дискриминант неотрицательный, то квадратное уравнение имеет
вещественные корни.
409
Вычисляем дискриминант и составляем простейшее логическое выражение:
## uses PT4;
Task('Boolean24');
// кожффициенты:
var (a, b, c) := ReadReal3;
// дискриминант:
var d := b * b - 4 * a * c;
// высказывание:
var v := d >= 0;
Writeln(v);
Задание Boolean25
Опять в логику вторгается математика:
Прежде всего, найдите на Рис. 1 вторую координатную четверть!
Если точка лежит на ней (включая оси координат), то должны одновременно выполняться условия:
x <= 0
y >= 0
410
Рис. 1. Координатные четвертушки
## uses PT4;
Task('Boolean25');
// координаты:
var (x, y) := ReadReal2;
//высказывание:
var v := (x <= 0) and (y >= 0);
Writeln(v);
Логика должна быть железной!
Задание Boolean26
Это задание исключительно на внимательность:
411
Чтобы решить её, достаточно внимательно посмотреть на рисунок координатных
четвертей из предыдущего задания:
## uses PT4;
Task('Boolean26');
// координаты:
var (x, y) := ReadReal2;
// высказывание:
var v := (x >= 0) and (y <= 0);
Writeln(v);
Задание Boolean27
Продолжаем четвертовать плоскость:
412
Нужны ли комментарии к этой задаче? – Вопрос риторический…
## uses PT4;
Task('Boolean27');
// координаты:
var (x, y) := ReadReal2;
// высказывание:
var v := x <= 0;
Writeln(v);
Задание Boolean28
А вот тут нужна сообразительность:
Заметим, что произведение координат любой точки в первой и третьей четвертях
неотрицательное – и вся задача:
## uses PT4;
Task('Boolean28');
// координаты:
var (x, y) := ReadReal2;
413
// высказывание:
var v := x * y >= 0;
Writeln(v);
Задание Boolean29
Задача из аналитической геометрии:
Чтобы решить задачу, нужно сначала вычертить прямоугольник и поставить в произвольном месте внутри него точку с координатами (x, y) (Рис. 1).
Теперь хорошо видно, что для такой точки одновременно должны выполняться
условия:
x > x1
x < x2
y < y1
y > y2
Составить из этих простых логических выражений одно сложное как раз несложно:
## uses PT4;
Task('Boolean29');
414
// координаты:
var (x, y) := ReadReal2;
var (x1, y1) := ReadReal2;
var (x2, y2) := ReadReal2;
// высказывание:
var v := (x > x1) and (x < x2) and (y < y1) and (y > y2);
Writeln(v);
Рис. 1. И точка
415
Задание Boolean30
Очередная задача из геометрии:
Так как длины всех сторон треугольника нам известны, то нужно только попарно
сравнить их между собой. Из трёх сторон можно составить 3 различные пары, но
достаточно сравнить 2 пары сторон, так как третья пара в случае успеха совпадёт
автоматически:
## uses PT4;
Task('Boolean30');
// числа:
var (a, b, c) := ReadInteger3;
// высказывание:
var v := (a = b) and (b = c);
Writeln(v);
Задание Boolean31
Равносторонний треугольник из предыдущего задания - это частный случай равнобедренного треугольника, поэтому на этот раз мы должны решить более общую задачу:
416
Итак, треугольник является равнобедренным, если совпадают длины любой пары
его сторон:
## uses PT4;
Task('Boolean31');
// длины сторон:
var (a, b, c) := ReadInteger3;
// высказывание:
var v := (a = b) or (a = c) or (b = c);
Writeln(v);
То есть иногда среди равнобедренных треугольников будут попадаться и равносторонние.
417
Задание Boolean32
Переходим к прямоугольным треугольникам, которые могут быть равнобедренными, но не равносторонними:
При решении этой задачи нам не обойтись без теоремы Пифагора про его знаменитые штаны.
Из неё следует, что в прямоугольном треугольнике квадрат гипотенузы равен
сумме квадратов катетов.
Так как мы не знаем, какая из сторон является в треугольнике гипотенузой, а отыскивать её – дополнительная задача, то мы просто последовательно «провозгласим» каждую из сторон гипотенузой, тогда двум оставшимся достанется роль катетов:
## uses PT4;
Task('Boolean32');
// длины сторон:
var (a, b, c) := ReadInteger3;
// квадраты
var a2 := a
var b2 := b
var c2 := c
длин:
* a;
* b;
* c;
// высказывание:
418
var v := (a2 = b2 + c2) or (b2 = a2 + c2) or (c2 = a2 + b2);
Writeln(v);
Задание Boolean33
Очередная треугольная задача:
Во-первых, длины всех сторон должны быть положительны. Так как далеко не все
целые числа положительны, то необходимо проверить числа a, b, c:
## uses PT4;
Task('Boolean33');
// длины сторон:
var (a, b, c) := ReadInteger3;
// высказывание:
var v := (a > 0) and (b > 0) and (c > 0);
Во-вторых, не всякие три числа могут выражать длину сторон треугольника. Это
возможно только в том случае, если сумма любых двух чисел больше третьего. Из
этого условия следует, что должны одновременно выполняться логические выражения:
a < b + c
b < a + c
419
c < a + b
Кроме того, если вы помните, непременно должно быть истинным и первое высказывание. Поэтому сложное высказывание должно быть таким:
v := v and ((a < b + c) and (b < a + c) and (c < a + b));
Writeln(v);
Задание Boolean34
Шахматная доска раскрашена в 2 цвета:
Если внимательно и вдумчиво посмотреть на доску, то можно заметить, что сумма
координат белых клеток всегда нечётная (Рис. 1).
## uses PT4;
Task('Boolean34');
// координаты клетки:
var (x, y) := ReadInteger2;
// высказывание:
var v := Odd(x + y);
Writeln(v);
420
Рис. 1. Круглые шахматы
Задание Boolean35
Продолжаем раскрашивать шахматную доску:
Из предыдущего задания следует, что клетки одинакового цвета имеют и одинаковую чётность суммы координат, то есть либо обе суммы чётные, либо обе
суммы нечётные:
421
## uses PT4;
Task('Boolean35');
// координаты клеток:
var (x1, y1, x2, y2) := ReadInteger4;
// высказывание:
var v := Odd(x1 + y1) = Odd(x2 + y2);
Writeln(v);
Задание Boolean36
Шахматная задача с ладейным уклоном:
Ладья – фигура тяжёлая и прямолинейная, то есть за 1 ход может переместиться
либо по горизонтали, либо по вертикали. Из этого вытекает, что заданные клетки
должны иметь или одинаковые горизонтальные, или одинаковые вертикальные
координаты (Рис. 1).
## uses PT4;
Task('Boolean36');
// координаты клеток:
422
var (x1, y1, x2, y2) := ReadInteger4;
// высказывание:
var v := (x1 = x2) or (y1 = y2);
Writeln(v);
Рис. 1. Прямолинейная ладья
423
Задание Boolean37
Королевская задача:
Шахматный король ходит только на соседнюю клетку (Рис. 1).
Рис. 1. Недалеко пошёл
424
Координаты соседних клеток отличаются на 0 или на 1. Если король ходит прямо,
то изменяется только 1 координата, а если криво – то обе.
Разность координат соседних клеток может быть как положительной, так и отрицательной, поэтому лучше использовать абсолютную величину разности:
## uses PT4;
Task('Boolean37');
// координаты клеток:
var (x1, y1, x2, y2) := ReadInteger4;
// высказывание:
var v := (Abs(x1 - x2) <= 1) and (Abs(y1 - y2) <= 1);
Writeln(v);
Задание Boolean38
В ход пошли слоны:
Слоны могут ходить только по диагонали, но на любое число клеток, если они при
этом не вываливаются с доски (Рис. 1).
425
Рис. 1. Ход слоном
Легко заметить, что при перемещении по диагонали абсолютная величина разности координат по обеим осям должна быть одинаковой:
## uses PT4;
Task('Boolean38');
// координаты клеток:
var (x1, y1, x2, y2) := ReadInteger4;
// высказывание:
var v := Abs(x1 - x2) = Abs(y1 - y2);
Writeln(v);
426
Задание Boolean39
Ферзь, как известно, самая мощная шахматная фигура:
Он может ходить, как ладья, - по горизонтали и по вертикали – или, как слон, – по
диагонали (Рис. 1).
Рис. 1. Мощная фигура
427
Из этого следует, что нужно соединить условия для хода ладьи и хода слона логической операцией ИЛИ:
## uses PT4;
Task('Boolean39');
// координаты клеток:
var (x1, y1, x2, y2) := ReadInteger4;
// высказывание:
var v := (Abs(x1 - x2) = Abs(y1 - y2)) or (x1 = x2) or (y1 = y2);
Writeln(v);
Задание Boolean40
Конь – самая коварная шахматная фигура:
Он может неожиданно появиться из-за угла и больно ударить копытом. Недаром
бытует выражение сделать ход конём, которое означает хитрый, неожиданный
ход.
Из песни Высоцкого Честь шахматной короны мы знаем, что кони ходят только
так:
428
Помню - всех главнее королева:
Ходит взад-вперёд и вправо-влево, Ну а кони вроде - буквой «Г».
У этой буквы одна сторона – 3 клетки, а вторая – 2. Так ходить, конечно, и коню
трудно, и нам вычислять координаты клеток нелегко (Рис. 1).
Рис. 1. И где ткие кони?
Так как шахматы предполагают размышления над каждым ходом, то давайте поразмышляем.
Координаты начальной и конечной клеток коня различаются на 2 и на 1. Это значит, что абсолютные величины разности координат всегда равны 2 и 1. Причём в
зависимости от направления хода, большая разность может быть у горизонтальных координат или у вертикальных. Однако произведение чисел 2 и 1 всегда
равно двум. Поэтому конская задача имеет очень простое решение:
429
## uses PT4;
Task('Boolean40');
// координаты клеток:
var (x1, y1, x2, y2) := ReadInteger4;
// высказывание:
var v := Abs(x1 - x2) * Abs(y1 - y2) = 2;
Writeln(v);
Если вы, конечно, умеете делать ход конём!
430
Управляющие структуры
Щёлкни кобылу в нос она махнёт хвостом.
Козьма Прутков
В 1965 г. итальянцы Бом и Джакопини доказали, что для записи любого алгоритма
(а, значит, и программы в целом) достаточно трёх управляющих структур:
следования
o
o
o
ветвления (выбора):
if
if-else
case
повторения (цикла):
for
while
repeat
foreach
Управляющая структура следования – самая простая, она предполагает
поочерёдное выполнение операторов, то есть в том порядке, в котором они
записаны в программе. Наши первые программы как раз и являются примерами
такого последовательного выполнения операторов.
Последовательность выполнения операторов в программе
называется потоком управления.
Без управляющих структур ветвления и повторения жизнь была бы скучна и
однообразна. То же самое и в программах: порядок выполнение инструкций
должен определяться действиями пользователя и другими факторами. На этот
случай в языке паскаль имеются операторы выбора (ветвления) – if, if-else и case.
431
Вообще говоря, хватило бы и одного оператора if, но тогда
многие программы выглядели бы «неуклюже».
Другие управляющие структуры - for, while, repeat, foreach – просто незаменимы,
когда нужно многократно повторить одни и те же действия.
Как и в случае с операторами выбора, для записи алгоритмов достаточно одного оператора цикла while, но во многих
случаях структура for более эффективна, а foreach – более
удобна.
Блок-схемы алгоритмов
Для наглядного представления алгоритмов часто
используются блок-схемы и структурные диаграммы.
В литературе на русском языке принято изображать
алгоритмы в виде блок-схем.
Всякая блок-схема (или просто схема) состоит, по
крайней мере, из трёх элементов:
Назначение
Элемент
Начало программы.
Поток управления.
Конец программы.
432
Самую простую программу, которая вообще ничего не делает, можно
представить такой схемой (Рис. 1).
Рис. 1. «Пустая» программа
Она соответствует программе, в которой нет выполняемого кода. В Окне вывода
при запуске такой программы ничего не будет напечатано, но при запуске без
связи с оболочкой создаётся Консольное окно (Рис. 2).
Рис. 2. Программа без выполняемого кода создаёт Консольное окно
На самом деле такие программы выполняют очень много
действий, которые необходимы для того, чтобы создать
окно приложения. Но поскольку эту рутинную (но непростую!) работу ИСР выполняет без нашего участия, то мы
будем считать, что все эти действия происходят в начале
программы, что мы и обозначаем знаком
.
Когда мы
закрываем программу, что соответствует знаку
на
блок-схеме, ОС уничтожает окно и освобождает память,
которую использовало приложение.
433
Так как нам не приходится задумываться об этих действиях
нашего приложения, то мы можем целиком сосредоточиться непосредственно на разработке алгоритма программы.
Любое действие в программе обозначается прямоугольником. При этом
различают действия пользователя (ввод данных с клавиатуры, нажатие кнопки
мышки) и действия приложения. Первые показывают обычным
прямоугольником, а вторые – прямоугольником со скруглёнными углами:
Элемент
Назначение
Действие пользователя
Действие программы
Простейшую программу, которая печатает на экране заданную строку и ждёт от
пользователя нажатия на клавишу можно изобразить так (Рис. 3).
Она включает два действия – печать сообщения и
ожидание нажатия на клавишу.
Любое действие может описываться в коде
одним или несколькими инструкциями (блоком
инструкций, составной инструкцией) (Рис. 4).
434
Рис. 3. Простейшая программа
Рис. 4. Программа c двумя процедурами WriteLn
435
Блок инструкций
Под блоком инструкций понимают несколько последовательно записанных инструкций, взятых в операторные скобки begin-end. Внутри одного блока инструкций могут быть и другие блоки, которые называются вложенными.
Например, вы можете создать блок инструкций в файле Логические операции,
выделив законченную часть кода (Рис. 1).
Рис. 1. Блок инструкций в операторных скобках
Естественно, в данном случае в этих операторных скобках нужды нет, хотя они
вполне допустимы. Принято блок инструкций внутри операторных скобок
сдвигать вправо на несколько позиций, чтобы выделить его. Для этого выделите
все операторы, входящие в блок, и нажмите клавишу табуляции.
Обратите внимание, что при щелчке на одной из скобок Редактор кода выделяет
серым фоном пару скобок, чтобы показать границы блока (Рис. 2).
436
Рис. 2. Каждому beginу свой еnd
Следует отметить такую особенность блока кода: переменные, объявленные
внутри блока, не видны за его границами. Они существуют только при
выполнении операторов блока (Рис. 3), а затем уничтожаются.
// внутриблочные переменные
begin
var i := 1;
var r := 2.0;
Println(' i =', i);
Println(' r =', r);
end;
Рис. 3. Внутриблочные переменные
Если вы попробуете напечатать значения этих
переменной после выхода из блока, то
компилятор сообщит вам, что он ничего не
знает о такой переменной (Рис. 4).
437
Рис. 4. Компилятор в недоумении
Но объявлять вне блока переменные с теми же именами, что и в блоке,
разрешено.
Условные операторы if и if-else
Если гора не идёт к Магомеду,
то Магомед идёт к горе.
Магомед
Трудно себе представить программу без условных операторов, разве что за
исключением самых простых.
Раньше вам уже встречались операторы – знаки операций.
Они по-английски так и называются operators.
438
Строки, заканчивающиеся точкой с запятой и описывающие
какие-либо законченные действия, в русском языке также
называют операторами, хотя их английское название statements, что можно перевести как предложение (вспомните, что предложение в русском языке – это законченная
мысль), утверждение или декларация. Оператор if, как и
многие другие, это не operator, а statement, то есть не знак
операции, а некое предложение, или конструкция, или инструкция, или управляющая структура.
Условный оператор if служит для того, чтобы
изменять порядок выполнения операторов в
программе в зависимости от некоторого
логического условия. Он имеет две формы –
сокращённую и полную.
Условный оператор if называют также оператором единственного выбора.
С условными операторами мы знакомимся уже в раннем
детстве. Например, строгий отец семейства может изложить свои требования в категоричной форме: Если принесёшь из школы, лишу наследства.
А вот мама скажет так: Если ты будешь себя хорошо вести, получишь большую сладкую конфету, иначе не пойдёшь
гулять во двор.
Более наглядно эти посулы можно изобразить так:
если принесёшь из школы двойку
439
останешься без карманных денег
если ты будешь себя хорошо вести
получишь большую сладкую конфету
иначе не пойдёшь гулять во двор
Сокращённая форма может быть с одной инструкцией:
if (условие) then
инструкция;
Или с блоком инструкций:
if (условие) then
begin
инструкция1;
инструкция2;
. . .
инструкцияN;
end;
Перед ключевым словом end точку с запятой ставить не
обязательно. В этом случае точка с запятой считается
пустым оператором, который ничего не делает.
Логическое условие не обязательно брать в круглые скобки.
В рассмотренном нами жизненном примере папина декларация состоит из
единственной инструкции останешься без карманных денег. А вот если он не
ограничится этим воздействием, но и запретит ребёнку выход в Интернет, то
получится блок операторов.
440
Полную форму оператора выбора («мамину»)
называют if-else, и она также может включать
единственную инструкцию в одной или в обеих
ветвях или блок инструкций.
Оператор if-else с единственной инструкцией
оператором в обеих ветвях:
if (условие) then
инструкция1
else
инструкция2
И с блоками инструкций:
if (условие) then
begin
инструкция1;
инструкция2;
. . .
инструкцияN;
end
else
begin
инструкцияN+1;
инструкцияN+2;
. . .
инструкцияN+M;
end;
После ключевого слова else условия быть не должно!
441
Оператор if - else называют также оператором двойного
выбора.
Каждый оператор блока (кроме последнего) в ветвях if и else
должен заканчиваться точкой с запятой. Но в конце строк
с ключевыми словами if-then и else, а также после операторных скобок блоков инструкций (кроме последнего end)
точку с запятой ставить не нужно!
Все инструкции в этих ветвях записываются со сдвигом
вправо на несколько позиций.
Операторные скобки ставят на одном уровне с ключевыми
словами if и else.
Если в ветвях if или else выполняется только одна инструкция, то операторные скобки ставить не обязательно.
Впрочем, вы можете и одну инструкцию заключать в
скобки – для большей наглядности кода. Более того, при отладке программы именно так и следует поступать – это
избавит вас от ошибок и необходимости ставить и убирать операторные скобки.
Инструкции в ветвях if и else образуют тело условных операторов if и if-else.
Если условие состоит из нескольких выражений, объединённых условными логическими операторами, то каждое из них
заключают в круглые скобки:
if ((a = 1) and (b = 1)) then . . .
if ((a = 1) or (b = 1)) then . . .
442
Внешние скобки ставить не обязательно, но с ними сложное
логическое выражение читается лучше.
Условие в этих записях – это логическое выражение, которое может быть заключено в круглые скобки.
Для записи логического выражения используют операторы отношения и сравнения =, <>, <, <=, >, >=, а также условные операторы not, and, or, xor.
Логическое выражение может быть либо истинным (условие выполняется, значение равно true), либо ложным (не выполняется, значение равно false).
Родительские условные операторы, согласно правилам, следует записать так:
если (принесёшь из школы двойку)
останешься без карманных денег;
УСЛОВИЕ
ДЕЙСТВИЕ
если (будешь себя хорошо вести)
УСЛОВИЕ
получишь большую сладкую конфету; ДЕЙСТВИЕ1
иначе
не пойдёшь гулять во двор;
ДЕЙСТВИЕ2
Действует условный оператор так:
Если (условие) истинное, то выполняется следующая за условием инструкция (или блок инструкций). Ветвь else пропускается (если она есть).
Если (условие) ложное, то следующая за условием инструкция (или блок инструкций) пропускается, а ветвь else выполняется (если она есть).
После выполнения условного оператора управление передаётся следующей за
ним инструкции.
443
Для наглядности изобразим условные операторы в виде блок-схемы. Нам понадобятся два новых графических элемента:
Назначение
Элемент
Узел
Ветвление
На Рис. 1 показана блок-схема оператора if, из которой хорошо видно, что если
условие истинно (значение логического выражения равно true), то выполняется
указанное действие в ветви if (один оператор или блок операторов). Если условие
ложно (значение логического выражения равно false), то действие не выполняется, а управление передаётся оператору, следующему за оператором if.
Рис. 1. Условный оператор if
Иногда эту схему вычерчивают несколько иначе (Рис. 2). Вы можете выбрать любой из этих вариантов.
Оператор if-else отличается от оператора if только тем, что имеет действие в
каждой из ветвей (Рис. 3).
444
Рис. 2. Другое схематическое представление условного оператора if
Рис. 3. Условный оператор if-else
445
Проект Условный оператор if
Часто необходимо показать на экране значение какой-либо переменной или
узнать, выполняется ли тело условного оператора. Тогда в нужном месте условного оператора достаточно поставить вызов процедуры WriteLn, чтобы получить
нужную информацию (Рис. 1):
##
// Условный оператор if
var n := 7;
var m := 0;
if (n = 7) then
begin
m := n;
WriteLn(' Выполняется ветвь if');
end
else
begin
m := n + 1;
WriteLn(' Выполняется ветвь else');
end
Рис. 1. Простейшая отладка
Если же вы запишете только инструкции присваивания, а затем добавите отладочные инструкции, например, так:
##
// Условный оператор if
var n := 7;
var m := 0;
if (n = 7) then
m := n
else
446
m := n + 1;
WriteLn(' Выполняется ветвь else'); //ОШИБКА!
то получите неверное сообщение о том, что выполняется ветвь else, хотя выполняется ветвь if (Рис. 2).
Рис. 2. Компилятор в недоумении
Будьте внимательны и всегда ставьте операторные скобки, чтобы выделить блок
инструкций!
Во многих языках программирования первую операторную скобку ставят в строке
с условным оператором, чтобы укоротить код. Вторую операторную скобку ставят
на одном уровне с условным оператором. Вы можете следовать этой программистской привычке:
##
// Условный оператор if
var n := 7;
var m := 0;
if (n = 7) then begin
m := n;
WriteLn(' Выполняется ветвь if');
end
else begin
m := n + 1;
WriteLn(' Выполняется ветвь else');
end
Пусть вы хотите найти большее (max) из двух чисел n1 и n2. Это легко сделать с
помощью условного оператора if-else.
Объявите и проинициализируйте переменные n1 и n2 (можно взять и выражения), а затем - в зависимости от результата операции отношения > - присвойте
большее значение переменной max:
447
##
// Условный оператор if
var max := 0;
var n1 := 12;
WriteLn(' Первое число: ' + n1);
var n2 := 3;
WriteLn(' Второе число: ' + n2);
if (n1 > n2) then
max := n1
else
max := n2;
WriteLn;
WriteLn(' Максимальное число = ' + max);
Распечатайте результат на экране (Рис. 3).
Рис. 3. Условный оператор if-else в действии
Как вы видите, условный оператор не ошибается.
Подумайте, изменится ли работа программы, если заменить строгое условие (n1 > n2) нестрогим (n1 >= n2)!
Если достаточно только убедиться, что два числа равны, то сделать это ещё
проще:
##
448
// Условный оператор if
var n1 := 2024;
WriteLn(' Первое число: ' + n1);
var n2 := 2023;
WriteLn(' Второе число: ' + n2);
if (n1 = n2) then
WriteLn(' Числа равны')
else
WriteLn(' Числа не равны');
Теперь программа сообщает, равны ли два числа в паре (Рис. 4).
Рис. 4. Сравниваем числа
Часть кода можно дополнить операторными скобками:
##
// Условный оператор if
var n1 := 21;
WriteLn(' Первое число: ' + n1);
var n2 := 21;
WriteLn(' Второе число: ' + n2);
if (n1 = n2) then begin
WriteLn(' Числа равны')
end
else begin
WriteLn(' Числа не равны')
end;
В этом случае к коду добавляются «пустые» строки, но зато каждое действие выделено.
449
Для более пристального наблюдения за выполнением условного оператора if-else
можно выполнить программу в пошаговом режиме
. Стрелка точно укажет,
какая именно ветвь условного оператора выполняется (Рис. 5)!
Рис. 5. Выполнение кода под контролем
Эти отладочные операторы можно потом стереть или закомментировать, но
обратите внимание, насколько операторные скобки облегчили вам жизнь: вы
можете добавлять новые строки в блок операторов или стирать уже имеющиеся
– всё равно условный оператор будет работать верно. А вот без операторных
скобок вас ждут многочисленные неприятности и разочарования…
Вложенные условные операторы
Если друг оказался вдруг
И не друг, и не враг, а - так,
Если сразу не разберешь,
Плох он или хорош, Парня в горы тяни - рискни!
Не бросай одного его,
Пусть он в связке в одной с тобой Там поймешь, кто такой.
Владимир Высоцкий, Песня о друге
Если после ключевого слова if или else опять следует
условный оператор if (или if-else), то он называется
вложенным. В этом случае каждый оператор else
относится к ближайшему предшествующему
оператору if, который не имеет else.
450
В этом примере ветвь else принадлежит второму, вложенному оператору if:
if (условие1) then
if (условие2) then begin
. . .
end
else begin
. . .
end;
Чтобы не запутаться, всегда выравнивайте отступом соответствующие друг другу операторы if – else так, чтобы
они находились на одном уровне, а все операторы в ветвях
заключайте в операторные скобки! Так понять программу
будет значительно легче.
Если оператор else должен продолжать первый оператор if, то используйте составной оператор с операторными скобками:
if (условие1) then begin
if (условие2) then begin
. . .
end
end
else begin
. . .
end;
Конструкцию с двумя следующими друг за другом операторами if легко заменить
одним, если оба условия соединить логическим оператором and:
if (условие1) and (условие2) then begin
451
. . .
end
else begin
. . .
end;
По этой причине чаще используются условные операторы после ключевого слова
else. Так:
if (условие1) then begin
. . .
end
else if (условие2) then begin
. . .
end
else begin
. . .
end;
Или так:
if (условие1) then begin
. . .
end
else begin
if (условие2) then begin
. . .
end
else begin
. . .
end
end;
452
Вторая форма нагляднее, но программисты предпочитают первую, особенно если
условные операторы содержат взаимоисключающие условия:
if (условие1) then
. . .
end
else if (условие2)
. . .
end
else if (условие3)
. . .
end
else if (условие4)
. . .
end
. . .
end;
begin
begin
begin
begin
С помощью вложенных условных операторов вы можете, например, значительно
«глубже» анализировать данные, полученные от пользователя (Рис. 1):
##
var n1 := 21;
WriteLn(' Первое число: ' + n1);
var n2 := 21;
WriteLn(' Второе число: ' + n2);
if (n1 = n2) then begin
WriteLn(' Числа равны');
end
else if (n1 < n2) then begin
WriteLn(' Первое число меньше второго');
end
else begin
WriteLn(' Второе число меньше первого');
end;
453
Эти примеры показывают, что условные операторы можно комбинировать множеством различных способов. При этом получаются весьма сложные конструкции, которые непросто понять. В этом случае следует пользоваться блок-схемами.
Рис. 1. Сравниваем числа
Основной алгоритм последнего кода можно представить такой блок-схемой (Рис.
2).
Рис. 2. Блок-схема сравнения чисел
Естественно, вам не нужно изображать готовый алгоритм
графически. Наоборот, сначала следует разработать и
454
проверить алгоритм с помощью блок-схемы и только потом кодировать его. А это совсем простая задача!
Вычисление логических выражений
Бинарные логические операции and и or вычисляются по укороченному способу
(иначе этот способ называется сокращённым вычислением). Это значит, что они
проводятся до тех пор, пока не станет очевидно значение всего выражения, после
чего вычисления прекращаются.
Например, рассмотрим логическое выражение:
(7 > 13) and (7 < 13) false
Значение первого выражения в скобках равно false, поэтому и результат вычисления всего выражения равен false, даже если второе выражение истинно. Поэтому
значение второго выражения вообще не вычисляется. Этот приём не только сокращает время вычислений, но и помогает избегать ошибок в программе. Добавьте к проекту такой код:
##
var n := 0;
var m := 8;
if (n <> 0) and (m div n > 5) then
Println(' n =', n, 'm div n =', (m div n));
n += 1;
if (n <> 0) and (m div n > 5) then
Println(' n =', n, 'm div n =', (m div n));
Если вы запустите приложение, то увидите, что выполнен только второй условный
оператор if (Рис. 1).
455
Рис. 1. Избежали деления на нуль
В данном примере сначала проверяется, не равен ли делитель n нулю. Если это
так, то дальнейшие вычисления не выполняются. Если бы проводилось полное
вычисление логического выражения, то при вычислении выражения m div n возникла бы ошибка - деление на нуль.
Совершенно очевидно, что если в операции and первый операнд равен false, то второй операнд вычислять смысла нет,
поскольку результат операции всё равно будет равен false.
Если в операции or первый операнд равен true, то второй
операнд не может изменить результата операции - true.
456
Набор заданий If
В этом наборе 30 заданий на применение условных операторов if и if-else.
Задание If1
Итак, первое задание такое:
Так как с этого набора не все задания генерируются и проверяются автоматически, то нужно имитировать работу Задачника самостоятельно:
## //uses PT4;
//Task('If1');
// число:
//var a := ReadInteger;
var a := Random(-100, 100);
Writeln(a);
if (a > 0) then
a += 1; //Inc(a)
Writeln(a);
Если вы имеете полный Задачник, то расскоментируйте
строки и, наоборот, закомментируйте генерацию значения
для числа а.
457
А решать здесь нечего…
Задание If2
Переходим ко второму заданию:
Опять элементарная задача:
## //uses PT4;
//Task('If2');
// число:
//var a := ReadInteger;
var a := Random(-100, 100);
Writeln(a);
if (a > 0) then
a += 1
else
a -= 2;
Writeln(a);
458
Задание If3
Второе задание, но с продолжением:
##
//uses PT4;
//Task('If3');
// число:
//var a := ReadInteger;
var a := Random(-100, 100);
Writeln(a);
if (a >
a +=
else if
a -=
else //
a :=
0) then
1
(a < 0) then
2
a = 0
10;
Writeln(a);
В паскале логическое выражение не обязательно заключать
в скобки.
459
Задание If4°
Четвёртое задание обозначено кружком, который означает, что задача генерируется и проверяется автоматически:
Здесь удобно воспользоваться счётчиком положительных чисел:
## uses PT4;
Task('If4');
// числа:
var (a, b, c) := ReadInteger3;
// счётчик положительных чисел:
var n := 0;
if (a >
n +=
if (b >
n +=
if (c >
n +=
0) then
1;
0) then
1;
0) then
1;
Writeln(n);
460
Задание If5
Так как в этом задании нужно отдельно подсчитать положительные и отрицательные числа, то следует завести 2 счётчика:
## //uses PT4;
//Task('If5');
// числа:
var a := Random(-100, 100);
var b := Random(-100, 100);
var c := Random(-100, 100);
Println(a, b, c);
// счётчик положительных чисел:
var np := 0;
// счётчик отрицательных чисел:
var no := 0;
if (a > 0) then
np += 1
else if (a < 0) then
no += 1;
if (b > 0) then
np += 1
else if (b < 0) then
no += 1;
if (c > 0) then
461
np += 1
else if (c < 0) then
no += 1;
Println(np, no);
Задание If6°
В этой задаче предполагается, что числа разные, поэтому одно больше другого:
## uses PT4;
Task('If6');
// числа:
var (a, b) := Readreal2;
if (a > b) then
Writeln(a)
else
Writeln(b);
462
Задание If7
Вариант предыдущей задачи:
## //uses PT4;
//Task('If7');
// числа:
//var (a, b) := Readreal2;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2} {1:f2}',a,b);
if (a < b) then
Writeln('1')
else
Writeln('2');
463
Задание If8°
Задачи на 2 числа успешно продолжаются:
## uses PT4;
Task('If8');
// числа:
var (a, b) := ReadReal2;
if (a > b) then
Writeln(a, b)
else
Writeln(b, a);
464
Задание If9
Легко понять, что, если первое число больше второго, то они должны обменяться
значениями:
В паскале для этого имеется специальная процедура Swap, так что всё решение
укладывается в 2 строки:
## //uses PT4;
//Task('If9');
// числа:
//var (a, b) := ReadReal2;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2} {1:f2}', a, b);
if (a > b) then
Swap(a, b);
//Writeln(a, b);
WritelnFormat('{0:f2} {1:f2}', a, b);
Вместо процедуры Swap можно использовать кортежи:
if (a > b) then
465
(a, b) := (b, a);
Задание If10
Элементарная задача на знание условного оператора if – else:
## //uses PT4;
//Task('If10');
// числа:
//var (a, b) := ReadReal2;
var a := Random(-100,100);
var b := Random(-100,100);
Println(a, b);
if (a <> b) then
a += b
else
a := 0;
b := a;
Println(a, b);
466
Задание If11
Наблюдаем дальнейшее развитие продуктивной идеи:
## //uses PT4;
//Task('If11');
// числа:
//var (a, b) := ReadReal2;
var a := Random(-100,100);
var b := Random(-100,100);
Println(a, b);
if (a =
begin
a :=
b :=
end
else if
a :=
else
b :=
b) then
0;
0;
(a < b) then
b
a;
Println(a, b);
467
Задание If12°
Работаем по минимуму:
Наименьшее из трёх чисел легко найти так:
## uses PT4;
Task('If12');
// числа:
var (a, b, c) := ReadReal3;
// наименьшее число:
var min := a;
if (b < min) then
min := b;
if (c < min) then
min := c;
Writeln(min);
Решение задачи можно сократить и упростить, если применить встроенную функцию Min:
## uses PT4;
Task('If12');
468
// числа:
var (a, b, c) := ReadReal3;
// наименьшее число:
var minNum := Min(a, Min(b,c));
Writeln(minNum);
Но тогда в решении задачи отсутствует условный оператор.
Задание If13
А вот найти среднее из трёх чисел гораздо сложнее:
Решение незамысловатое, но длинное:
## //uses PT4;
//Task('If13');
// числа:
//var (a, b, c) := ReadReal3;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
var c := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2} {1:f2} {2:f2}', a, b, c);
469
if ((a > b) and (a < c)) or ((a < b) and (a > c)) then
WritelnFormat('{0:f2}', a)
else if ((b > a) and (b < c)) or ((b < a) and (b > c)) then
WritelnFormat('{0:f2}', b)
else
WritelnFormat('{0:f2}', c);
Задание If14
Очередная задача про три числа:
Ленивый способ решения задачи заключается в применении встроенных функций
Min и Max:
## //uses PT4;
//Task('If14');
// числа:
//var (a, b, c) := ReadReal3;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
var c := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2} {1:f2} {2:f2}', a, b, c);
// наименьшее число:
var minNum := Min(Min(a, b), c);
470
// наибольшее число:
var maxNum := Max(Max(a, b), c);
WritelnFormat('{0:f2} {1:f2}', minNum, maxNum);
Можно упростить код, если воспользоваться перегрузками этих функций для трёх
параметров:
// наименьшее
var minNum :=
// наибольшее
var maxNum :=
число:
Min(a, b, c);
число:
Max(a, b, c);
Универсальный способ решения на паскале: отсортировать числа в порядке возрастания, а затем взять первое (наименьшее) и третье (наибольшее):
## //uses PT4;
//Task('If14');
// числа:
//var (a, b, c) := ReadReal3;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
var c := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2} {1:f2} {2:f2}', a, b, c);
if (a > b)
Swap(a,
if (b > c)
Swap(b,
if (a > b)
Swap(a,
then
b);
then
c);
then
b);
WritelnFormat('{0:f2} {1:f2}', a, c);
471
Задание If15
Практически то же самое задание, что и предыдущее:
Сортируем числа и печатаем сумму двух последних (среднее и наибольшее):
## //uses PT4;
//Task('If15');
// числа:
//var (a, b, c) := ReadReal3;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
var c := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2} {1:f2} {2:f2}', a, b, c);
if (a > b)
Swap(a,
if (b > c)
Swap(b,
if (a > b)
Swap(a,
then
b);
then
c);
then
b);
WritelnFormat('{0:f2}', b + c);
472
Задание If16
Задание длинное:
Но мы легко определим, образуют ли заданные числа возрастающую последовательность, а затем умножим их на соответствующий коэффициент:
## //uses PT4;
//Task('If16');
// числа:
//var (a, b, c) := ReadReal3;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
var c := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2} {1:f2} {2:f2}', a, b, c);
// коэффициент:
var k := -1;
if (a < b) and (b < c) then // - упорядочены
k := 2;
a *= k;
b *= k;
c *= k;
WritelnFormat('{0:f2} {1:f2} {2:f2}', a, b, c);
473
Задание If17
Слегка усложнённый вариант предыдущего задания:
Опять наша главная задача – определить, образуют ли заданные числа возрастающую или убывающую последовательность:
## //uses PT4;
//Task('If15');
// числа:
//var (a, b, c) := ReadReal3;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
var c := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2} {1:f2} {2:f2}', a, b, c);
// коэффициент:
var k := -1;
if ((a < b) and (b < c)) or ((a > b) and (b > c)) then // - упорядочены
k := 2;
a *= k;
b *= k;
c *= k;
WritelnFormat('{0:f2} {1:f2} {2:f2}', a, b, c);
474
Задание If18
Старая песенка про три числа:
Если мы найдём пару равных чисел, то третье число – искомое:
## //uses PT4;
//Task('If18');
// числа:
//var (a, b, c) := ReadReal3;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
var c := b;
Println(a, b, c);
if (a = b) then
Writeln(3)
else if (a = c) then
Writeln(2)
else
Writeln(1);
475
Задание If19
Та же самая задача, что и предыдущая, но для четырёх чисел:
«Отличное» число не равно, по крайней мере, двум другим числам. По этому признаку мы легко его найдём:
## //uses PT4;
//Task('If19');
// числа:
//var (a, b, c, d) := ReadReal4;
var a := Random(-100, 100);
var b := Random(-100, 100);
var c := b;
var d := b;
Println(a, b, c, d);
if (a <> b) and (a <> c) then
Writeln(1)
else if (b <> a) and (b <> c) then
Writeln(2)
else if (c <> a) and (c <> b) then
Writeln(3)
else
Writeln(4);
476
Задание If20
В ход пошли отрезки:
Расстояние между двумя точками мы легко найдём. А сравнить расстояния и того
проще:
## //uses PT4;
//Task('If20');
// числа:
//var (a, b, c) := ReadReal3;
var a := Random() * 100.0 - 50.0;
var b := Random() * 100.0 - 50.0;
var c := b;
Println(a, b, c);
// расстояния:
var ab := Abs(a - b);
var ac := Abs(a - c);
if (ab < ac) then begin
WritelnFormat('{0:f2}',
WritelnFormat('{0:f2}',
end
else begin
WritelnFormat('{0:f2}',
WritelnFormat('{0:f2}',
end
b);
ab);
c);
ac);
477
Задание If21
Простейшее учебное упражнение на условный оператор:
## //uses PT4;
//Task('If21');
// числа:
//var (x, y) := ReadInteger2;
var x := Random(-100, 100);
var y := Random(-100, 100);
println(x, y);
if (x = 0) and (y = 0) then
Writeln(0)
else if (x = 0)
then Write(2)
else if (y = 0)
then Write(1)
else Write(3);
478
Задание If22°
Задачи про координатную плоскость мы уже решали неоднократно (Рис. 1):
Рис. 1. Координатная плоскость
## uses PT4;
Task('If22');
// числа:
var (x, y) := ReadReal2;
479
if (x > 0) and (y > 0) then
Writeln(1)
else if (x < 0) and (y > 0)
then Writeln(2)
else if (x < 0) and (y < 0)
then Writeln(3)
else
Writeln(4);
Задание If23
Весьма прямоугольная задача:
Чтобы не (пере)мудрить, будем считать, что нам известны координаты первых
трёх по счёту вершин прямоугольника (Рис. 1).
В реальной задаче это могут быть другие вершины, поэтому их нужно найти.
Сделать это нетрудно, глядя на рисунок.
Если горизонтальные координаты двух вершин равны, то они принадлежат одной
горизонтальной стороне прямоугольника (на нашем рисунке x1 = x3). Значит, горизонтальная координата неизвестной вершины равна горизонтальной координате третьей из заданных вершин (на нашем рисунке x4 = x2).
Аналогично можно найти и вертикальную координату неизвестной вершины.
480
Рис. 1. Прямо угольник
##
//uses PT4;
//Task('If23');
// числа:
//var (x1,
//var (x2,
//var (x3,
//var (x4,
y1)
y2)
y3)
y4)
:=
:=
:=
:=
ReadInteger2;
ReadInteger2;
ReadInteger2;
ReadInteger2;
var x1 := Random(-100, 100);
var y1 := Random(-100, 100);
var x2 := Random(-100, 100);
var y2 := Random(-100, 100);
var x3 := x1;
var y3 := y2;
var x4 := 0;
var y4 := 0;
Println(x1, y1, x2, y2, x3, y3);
if (x2 = x3)
then x4 := x1
481
else if (x3 = x1)
then x4 := x2
else
x4 := x3;
if (y2 = y3)
then y4 := y1
else if (y3 = y1)
then y4 := y2
else
y4 := y3;
Println(x4, y4);
Задание If24
Задача наипростейшая:
## //uses PT4;
//Task('If24');
// число:
//var x = ReadReal;
var x := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2}', x);
482
// значение функции:
var fx := 0.0;
if (x > 0) then
fx := 2 * Sin(x)
else
fx := 6 - x;
WritelnFormat('{0:f2}', fx);
Задание If25
Несущественное усложнение предыдущего задания:
## //uses PT4;
//Task('If25');
// число:
//var x = ReadReal;
var x := Random(-100, 100);
Writeln(x);
// значение функции:
var fx := 0;
if (x < - 2) or (x > 2) then //Abs(x) > 2
fx := 2 * x
else
fx := -3 * x;
483
Writeln(fx);
Задание If26°
Опять чуть-чуть сложнее:
## uses PT4;
Task('If26');
// число:
var x := ReadReal;
// значение функции:
var fx := 0.0;
if (x <= 0) then
fx := -x
else if (x > 0) and (x < 2) then
fx := x * x
else
fx := 4;
Writeln(fx);
484
Задание If27
А вот здесь нас ждёт сюрприз!
Интервалов бесконечное множество, поэтому нам необходимо найти в них какую-то закономерность.
Так как границы интервала задаются целыми числами, а число х - вещественное,
то необходимо преобразовать его к целому типу. В паскале для этого имеется
функция Trunc, которая возвращает целую часть вещественного числа.
Легко проверить, что после применения этой функции от х останется целое число,
равное левой граница какого-либо интервала. Например:
x = 0.99 0
x = 1.77 1
x = 2.01 2
Номер интервала нам не нужен, но мы должны определить, к какой группе относится интервал для числа х.
Легко заметить, что первая группа интервалов начинается с чётных чисел, а вторая
– с нечётных.
Задача решена!
## //uses PT4;
485
//Task('If27');
// число:
//var x := ReadReal;
var x := Random() * 100.0 - 50.0;
WritelnFormat('{0:f2}', x);
// значение функции:
var fx := 0;
if (x < 0) then
fx := 0
else if (Odd(Trunc(x))) then
fx := -1
else
fx := 1;
Writeln(fx);
Задание If28
Задача исключительно на внимательность при переписывании условия задачи на
язык программирования:
## //uses PT4;
486
//Task('If28');
// год:
//var год := ReadInteger;
var год := Random(1, 2023);
Writeln(год);
if (год mod 4 = 0) and
not((год mod 100 = 0) and
(год mod 400 <> 0)) then // - високосный
Writeln(366)
else
Writeln(365);
Задание If29
Опять лёгкое упражнение:
## //uses PT4;
//Task('If29');
// число:
//var год := ReadInteger;
var n := Random(-100, 100);
Writeln(n);
487
// строка с сообщением:
var str := String.Empty;
if (n = 0) then
str += 'нулевое '
else if (n > 0) then
str += 'положительное '
else
str += 'отрицательное ';
if (n <> 0) then
if (Odd(n)) then
str += 'нечётное '
else
str += 'чётное ';
str += 'число';
Writeln(str);
Задание If30
Последнее задание в этой серии также не порадовало оригинальностью:
## //uses PT4;
//Task('If30');
// число:
//var n := ReadInteger;
488
var n := Random(1, 999);
Writeln(n);
// строка с сообщением:
var str := String.Empty;
if (Odd(n)) then
str += 'нечётное '
else
str += 'чётное ';
if (n >= 100) then
str += 'трёхзначное '
else if (n >= 10) then
str += 'двузначное '
else
str += 'однозначное ';
str += 'число';
Writeln(str);
Тернарный условный оператор ?:
Записывается он витиевато:
условие ? выражениеTrue : выражениеFalse
Условие – это логическое выражение, которое может быть заключено в круглые
скобки. Для записи логического выражения используют операторы отношения и
сравнения =, <>, <, <=, >, >=, а также условные операторы not, and, or, xor.
Логическое выражение может быть либо истинным (условие выполняется, значение равно true), либо ложным (не выполняется, значение равно false).
Если условие истинно, то вычисляется выражениеTrue.
Если условие ложно, то вычисляется выражениеFalse.
Вычисляется только одно из этих выражений.
489
Результат операции равен значению вычисленного выражения.
Тип результата операции определяется типом выражений, которые должны
быть совместимы.
Таким образом, тернарный условный оператор представляет собой выражение,
имеющее тип и значение. Из этого следует, что результат операции должен быть
присвоен переменной, либо использоваться в других операторах.
Короткий пример:
##
var n := 10;
var s := n >= 10 ? ' Многозначное число' : ' Однозначное число';
Println(s);
var m := 0;
if (m > n ? 1 : 0) <> 0 then
Println(' m > n')
else Println(' m <= n');
В первом случае значение операции равно строке ' Многозначное число', которое присваивается переменной s.
Во втором случае значение в скобках равно 0, оно сравнивается с 0. Результат
операции сравнения равен false. Это значение используется в операторе if, поэтому программа напечатает строку ' m <= n' (Рис. 1).
Рис. 1. Разобрались
Вторая форма тернарного оператора позаимствована у Питона:
490
if условие then выражениеTrue else выражениеFalse
Опять короткий пример использования этого тернарного оператора (Рис. 2):
var a := 1;
var b := 2;
var min := if a < b then a else b;
Println(' Меньшее число =', min);
Рис. 2. И по-питоньски
Если записать этот тернарный оператор не по-питоньски, а по паскальски, то мы
получим обычный условный оператор if-else:
if условие then
инструкция1
else
инструкция2
Но он выполняет инструкции, а не возвращает результат вычисления значения
выражения.
Оператор множественного выбора case
Выбирай, но осторожно. Но выбирай!
Михаил Жванецкий
Направо пойдёшь – коня потеряешь;
налево пойдёшь – себя потеряешь;
прямо пойдёшь – и себя, и коня потеряешь!
Сказочный выбор
491
Условные операторы if обычно применяют,
когда вариантов выбора не очень много (дватри), в противном случае гораздо удобнее
пользоваться оператором case, который
делает запись более компактной и понятной.
В общем случае оператор case имеет вид:
case переключатель of
список_выбора1: инструкция1;
список_выбора2: инструкция2;
. . .
список_выбораN: инструкцияN;
else инструкция;
end;
Переключатель – это любое допустимое выражение/переменная целого,
символьного или строкового типа.
Переключатель называют также селектором, или индексом выбора.
Списки выбора (константы выбора, метки случаев) – это одно константное
выражение (литерал) совместимого с переключателем типа, диапазон значений
или несколько констант, записанных через запятую. В пределах одного оператора
case списки выбора не должны повторяться и пересекаться! Инструкции
записывают после двоеточия, а завершаются они точкой с запятой.
Ветвь else может отсутствовать, но в любом операторе case допускается только
один оператор else. После ключевого слова else двоеточие не ставится!
Чтобы разобрать работу оператора case, мы напишем новую программу.
492
Проект Оператор case
В этом проекте мы будем определять, какое число пользователь ввёл с
клавиатуры – простое или составное. Поскольку этот проект демонстрирует
только действие оператора множественного выбора, то мы не будем включать в
него проверки правильности ввода, тогда программа будет очень простой:
##
var num := ReadInteger(' Введите число от 2 до 10: ');
case num of
2, 3, 5, 7: WriteLn(' Простое число');
else WriteLn(' Составное число');
end;
WriteLn;
Пользователь вводит число num, которое мы анализируем в операторе case. Если
это двойка, тройка, пятёрка или семёрка, то мы печатаем строку Простое число,
после чего управление передаётся инструкции WriteLn;
Если пользователь задал другое число, то выполняется ветвь else. На экране печатается строка Составное число и управление передаётся инструкции WriteLn;
В целом картина на экране получается правильная и замечательная (Рис. 1).
Рис. 1. Проверяем числа на простоту
Если мы заменим оператор case оператором if-else, то он будет выглядеть более
громоздко:
493
##
var num := ReadInteger(' Введите число от 2 до 10: ');
if (num = 2) or (num = 3) or (num = 5) or (num = 7) then
WriteLn(' Простое число')
else
WriteLn(' Составное число');
WriteLn;
Мы можем обойтись и без ветви else, но тогда нам придётся выписать все
возможные константы выбора:
##
var num := ReadInteger(' Введите число от 2 до 10: ');
case num of
2, 3, 5, 7: WriteLn(' Простое число');
4, 6, 8, 9, 10: WriteLn(' Составное число');
end;
WriteLn;
Теперь более подробно разберём, как действует оператор case в нашей
программе:
Значение переключателя (здесь это переменная num) последовательно
сравнивается со всеми списками выбора, начиная с первого:
Если это значение переключателя совпало со значением в одном из
списков выбора (а совпадение может быть только единственным), то
выполняются инструкции для этого списка выбора, а затем управление
переходит к инструкции, следующий за ключевым словом end оператора
case.
494
Если значение переключателя не совпало ни с одним списком (константой)
выбора, то выполняются инструкции после ключевого слова else, а затем
управление передаётся – согласно правилу предыдущего пункта. Если
ключевое слово else отсутствует, то ни одна инструкция в case вообще не
выполняется.
Для нашего примера.
Если значение num равно 2, 3, 5, 7, то мы получим сообщение Простое число.
Если значение num равно 4, 6, 8, 9, 10, то мы получим сообщение Составное
число.
Если значение num равно 0 (пользователь может его ввести, поскольку мы не
контролируем его действия), то мы получим сообщение Составное число в
первой записи (с оператором else) и не получим никакого сообщения во второй
записи (без оператора else).
Из этого следует, что если мы хотим корректно обрабатывать любой ввод
пользователя (мы сейчас не говорим об ошибках при наборе числа), то оператор
case нужно записать так (Рис. 2):
Рис. 2. Улучшенный контроль ввода
Блок-схему для общего случая оператора case начертить непросто, поскольку он
имеет очень много вариантов, различающихся числом списков выбора, наличием
или отсутствием ветки else.
495
Я думаю, вы без особого труда, начертите блок-схему оператора case для нашей программы. Хотя бумаги потребуется целый рулон…
Набор заданий Case
В этом наборе 20 заданий на применение оператора выбора case.
Задание Case1
Задача простая, но нужно аккуратно выписать все дни недели:
## //uses PT4;
//Task('Case1');
// целое число:
var n := ReadInteger('Введите целое число 1..7 > ');
var s := string.Empty;
case n of
1: s := 'понедельник';
2: s := 'вторник';
3: s := 'среда';
4: s := 'четверг';
5: s := 'пятница';
6: s := 'суббота';
496
else s := 'воскресенье';
end;
Print('День недели:', s);
Задание Case2°
Задача, подобная предыдущей, но нужно учесть и ошибочный ввод:
## uses PT4;
Task('Case2');
// оценка:
var k := ReadInteger('Введите оценку 1..5 > ');
var s := string.Empty;
case k of
1: s := 'плохо';
2: s := 'неудовлетворительно';
3: s := 'удовлетворительно';
4: s := 'хорошо';
5: s := 'отлично';
else s := 'ошибка';
end;
Print(s)
497
Задание Case3
Задача, подобная предыдущим, но выбор больше:
Номера зимних месяцев идут не по порядку: 1, 2, 12. Номера остальных месяцев
«правильные». Но если найти остаток от деления номера месяца на 12, то остатки
для всех времён года располагаются верно. Воспользуемся этим наблюдением в
своей программе:
## //uses PT4;
//
Task('Case3');
// номер месяца:
var n := ReadInteger('Введите номер месяца 1..12 > ');
var k := n mod 12;
var s := string.Empty;
case k of
0, 1, 2: s := 'зима';
3, 4, 5: s := 'весна';
6, 7, 8: s := 'лето';
else s := 'осень';
end;
Println(s);
498
Задание Case4°
Опять календарная задача:
Чтобы не считать дни по косточкам, взглянем на календарь 2018 года, который как
раз невисокосный (Рис. 1).
Выпишем номера месяцев для каждого
числа дней:
Номера месяцев, в которых 31 день: 1, 3, 5, 7, 8, 10, 12
Номера месяцев, в которых 30 дней: 4, 6, 9, 11
Номер месяца, в котором 28 дней: 2
Начинаем с февраля, затем проверяем месяцы, в которых 30 дней, - потому что их
меньше. А все остальные месяцы состоят из 31 дня:
## uses PT4;
Task('Case4');
// номер месяца:
var n := ReadInteger('Введите номер месяца 1..12 > ');
case n of
2: Println(28);
4,6,9,11:Println(30);
else Println(31);
end;
499
Рис. 1. Не все календари врут
Задание Case5
Ничего нового в этой задаче нет:
500
## //uses PT4;
//Task('Case5');
// номер действия:
var n := ReadInteger('Введите номер действия 1..4 > ');
// числа:
var a := ReadReal('Введите первое число
--> ');
var b := ReadReal('Введите второе число <> 0 --> ');
case n of
1: Println('A +
2: Println('A 3: Println('A *
else Println('A
end;
B
B
B
/
=', a
=', a
=', a
B =',
+
*
a
b);
b);
b);
/ b);
Задание Case6
Единственная сложность в этой задаче – вспомнить, сколько метров содержится
в миллиметрах:
## //uses PT4;
//Task('Case6');
501
{Case6. Единицы длины пронумерованы следующим образом:
1 — дециметр, 2 — километр, 3 — метр, 4 — миллиметр, 5 — сантиметр.
Дан номер единицы длины (целое число в диапазоне 1–5) и
длина отрезка в этих единицах (вещественное число).
Найти длину отрезка в метрах.}
// номер
var n :=
// длина
var a :=
единицы длины:
ReadInteger(' Введите номер единицы длины 1..5 >');
отрезка:
ReadReal(' Введите длину отрезка
>');
// длина отрезка
var len := 0.0;
case n of
1: len := a /
2: len := a *
3: len := a;
4: len := a /
else len := a
end;
в метрах:
10;
1000;
1000;
/ 100;
Println(' Длина отрезка в метрах =', len);
Задание Case7
Такая же задача, как предыдущая, но с килограммами:
502
## //uses PT4;
//Task('Case7');
{Case7. Единицы массы пронумерованы следующим образом:
1 — килограмм, 2 — миллиграмм, 3 — грамм, 4 — тонна, 5 — центнер.
Дан номер единицы массы (целое число в диапазоне 1–5) и
масса тела в этих единицах (вещественное число).
Найти массу тела в килограммах.}
// номер
var n :=
// масса
var m :=
единицы длины:
ReadInteger(' Введите номер единицы массы 1..5 >');
тела:
ReadReal(' Введите массу тела
>');
// массa тела в
var mk := 0.0;
case n of
1: mk := m;
2: mk := m /
3: mk := m /
4: mk := m *
else mk := m
end;
Println(' Mассa
килограммах:
1000000;
1000;
1000;
* 100;
тела в килограммах =', mk);
Задание Case8
Сложная календарная задача:
503
К сожалению, составители календаря не подумали о решении таких задач, поэтому мы должны рассмотреть все варианты.
1. Самый простой случай: предыдущий день относится к текущему месяцу. Тогда
нужно вычесть из номера сегодняшнего дня 1.
2. Если сегодняшний день – первое число, то предыдущий был последним днём
предыдущего месяца.
3. Если текущий месяц - январь, то в этом случае предыдущим месяцем был декабрь прошлого года.
4. Зная предыдущий месяц, мы найдём число дней в нём. Предыдущий день и
был последним в этом месяце:
## //uses PT4;
//Task('Case8');
{Case8. Даны два целых числа: D (день) и M (месяц),
определяющие правильную дату невисокосного года.
Вывести значения D и M для даты, предшествующей указанной.}
// номер
var m :=
// номер
var d :=
месяца:
ReadInteger(' Введите номер месяца >');
дня:
ReadInteger(' Введите номер дня
>');
// предыдущий день того же месяца:
var d1, m1 : integer;
if (d > 1) then begin
d1 := d - 1;
m1 := m
end
// последний день предыдущего месяца:
else if (m > 1) then
m1 := m - 1
else m1 := 12;
// предыдущий месяц
// число дней в нём:
if m <> m1 then
504
case m1 of
2: d1 := 28;
4,6,9,11: d1 := 30;
else d1 := 31
end;
Println(' Предыдущий день / месяц:', d1, m1);
Задание Case9°
Такая же задача, только дни нужно считать в обратную сторону:
## //uses PT4;
//Task('Case9');
{Case9°. Даны два целых числа: D (день) и M (месяц),
определяющие правильную дату невисокосного года.
Вывести значения D и M для даты, следующей за указанной.}
// номер
var m :=
// номер
var d :=
месяца:
ReadInteger(' Введите номер месяца >');
дня:
ReadInteger(' Введите номер дня
>');
// число дней в текущем месяце:
var md := 0;
case m of
2: md := 28;
505
4,6,9,11: md := 30;
else md := 31
end;
// следующий день того же месяца:
var d1, m1 : integer;
if (d < md) then begin
d1 := d + 1;
m1 := m
end
// первый день следующего месяца:
else begin
d1 := 1;
if (m < 12) then
m1 := m + 1
else m1 := 1;
end;
Println(' Следующий месяц / день:', m1, d1);
Задание Case10°
Задача про вертящегося робота:
Тут самое время взглянуть на компас – вот он (Рис. 1).
506
Рис. 1. Не компас, а конфуз
По нему хорошо видно, как изменяется направление робота после выполнения
команды:
## uses PT4;
Task('Case10');
{Case10°. Робот может перемещаться в четырех направлениях
(«С» — север, «З» — запад, «Ю» — юг, «В» — восток) и
принимать три цифровые команды:
0 — продолжать движение, 1 — поворот налево, −1 — поворот направо.
Дан символ C — исходное направление робота и
целое число N — посланная ему команда.
Вывести направление робота после выполнения полученной команды.}
// исходное направление робота:
var c := ReadChar(' Введите исходное направление робота СЗЮВ >');
// команда:
var n := ReadInteger(' Введите цифровую команду >');
var c1 := ' ';
case n of
// направление не меняется
0: c1 := c;
// поворот налево:
1: case c of
507
'С': c1 := 'З';
'З': c1 := 'Ю';
'Ю': c1 := 'В';
else c1 := 'С'
end;
// поворот направо:
else
case c of
'С': c1 := 'В';
'В': c1 := 'Ю';
'Ю': c1 := 'З';
else c1 := 'С';
end;
end;
Println({' Направление робота после выполнения полученной команды:',} c1);
Задание Case11
По сути, такая же задача, что и предыдущая, но теперь мы должны последовательно применить 2 команды:
Сделать это можно по-разному, но самый простой способ – расписать оба поворота:
508
## //uses PT4;
//Task('Case11');
{Case11. Локатор ориентирован на одну из сторон света
(«С» — север, «З» — запад, «Ю» — юг, «В» — восток) и
может принимать три цифровые команды поворота:
1 — поворот налево, −1 — поворот направо, 2 — поворот на 180°.
Дан символ C — исходная ориентация локатора и
целые числа N1 и N2 — две посланные команды.
Вывести ориентацию локатора после выполнения этих команд.}
// исходное направление робота:
var c := ReadChar(' Введите исходное направление робота СЗЮВ >');
// команда:
var n1 := ReadInteger(' Введите первую цифровую команду >');
var n2 := ReadInteger(' Введите вторую цифровую команду >');
var n := n1;
var c1 := ' ';
case n of
// поворот налево:
1: case c of
'С': c1 := 'З';
'З': c1 := 'Ю';
'Ю': c1 := 'В';
else c1 := 'С';
end;
// поворот направо:
-1: case c of
'С': c1 := 'В';
'В': c1 := 'Ю';
'Ю': c1 := 'З';
else c1 := 'С';
end;
// поворот на 180 градусов:
else case c of
'С': c1 := 'Ю';
'В': c1 := 'З';
'Ю': c1 := 'С';
else c1 := 'В';
end;
end;
509
c := c1;
n := n2;
case n of
// поворот налево:
1: case c of
'С': c1 := 'З';
'З': c1 := 'Ю';
'Ю': c1 := 'В';
else c1 := 'С';
end;
// поворот направо:
-1: case c of
'С': c1 := 'В';
'В': c1 := 'Ю';
'Ю': c1 := 'З';
else c1 := 'С';
end;
// поворот на 180 градусов
else case c of
'С': c1 := 'Ю';
'В': c1 := 'З';
'Ю': c1 := 'С';
else c1 := 'В';
end;
end;
Println(' Ориентация локатора после выполнения команд:', c1)
Задание Case12
510
И эту задачу можно решать по-разному. Но достаточно заметить, что во все формулы входит радиус окружности. Его легко вычислить, а затем подставить в приведённые формулы и найти значения остальных элементов окружности. Требуется дополнительная проверка, чтобы не печатать значение заданного элемента:
## //uses PT4;
//Task('Case12');
{Case12. Элементы окружности пронумерованы следующим образом:
1 — радиус R,
2 — диаметр D = 2·R,
3 — длина L = 2·π·R,
4 — площадь круга S = π·R^2.
Дан номер одного из этих элементов и его значение.
Вывести значения остальных элементов данной окружности (в том же порядке).
В качестве значения π использовать 3.14.}
// номер элемента:
var n := ReadInteger(' Введите номер элемента >');
// значение элемента:
var v := ReadReal(' Введите значение элемента > ');
var pi := 3.14;
// вычисляем радиус:
var r := 0.0;
case n of
// радиус:
1: r := v;
// диаметр:
2: r := v / 2;
// длина окружности:
3: r := v / 2 / pi;
// площадь круга
else r := Sqrt(v / pi);
end;
// вычисляем остальные элементы:
var d := 2 * r;
var l := 2 * pi * r;
var s := pi * r * r;
if n <> 1 then Println(' Радиус =', r);
511
if n <> 2 then Println(' Диаметр =', d);
if n <> 3 then Println(' Длина =', l);
if n <> 4 then Println(' Площадь =', s);
Задание Case13
Подобная задача, но с элементами прямоугольного треугольника:
Решаем задачу по тому же сценарию, что и предыдущую, но формулы придётся
выводить самостоятельно:
## //uses PT4;
//Task('Case13');
{Case13. Элементы равнобедренного прямоугольного треугольника пронумерованы следующим образом:
1 — катет a,
2 — гипотенуза c = a·(2)^1/2,
3 — высота h, опущенная на гипотенузу (h = c/2),
4 — площадь S = c·h/2.
Дан номер одного из этих элементов и его значение.
Вывести значения остальных элементов данного треугольника (в том же
порядке).}
// номер элемента:
var n := ReadInteger(' Введите номер элемента 1..4 >');
// значение элемента:
512
var v := ReadReal(' Введите значение элемента > ');
// вычисляем радиус:
var a := 0.0;
case n of
// катет:
1: a := v;
// гипотенуза:
2: a := v / Sqrt(2);
// высота:
3: a := 2 * v / Sqrt(2);
// площадь:
else a := Sqrt(2 * v);
end;
// вычисляем
var c := a *
var h := c /
var s := c *
if
if
if
if
n
n
n
n
<>
<>
<>
<>
1
2
3
4
остальные элементы:
Sqrt(2);
2;
h / 2;
then
then
then
then
Println('
Println('
Println('
Println('
Катет =', a);
Гипотенуза =', c);
Высота =', h);
Площадь =', s);
Задание Case14
Подобная задача, но с равносторонним треугольником:
513
Задача для тех, кто любит математику:
## //uses PT4;
//Task('Case14');
{Case14. Элементы равностороннего треугольника пронумерованы следующим
образом:
1 — сторона a,
2 — радиус R1 вписанной окружности (R1 = a·(3)1/2/6),
3 — радиус R2 описанной окружности (R2 = 2·R1),
4 — площадь S = a2·(3)1/2/4.
Дан номер одного из этих элементов и его значение.
Вывести значения остальных элементов данного треугольника (в том же
порядке).}
// номер элемента:
var n := ReadInteger(' Введите номер элемента 1..4 >');
// значение элемента:
var v := ReadReal(' Введите значение элемента > ');
// вычисляем сторону:
var a := 0.0;
case n of
// сторона:
1: a := v;
// радиус вписанной окружности:
2: a := v * 6 / Sqrt(3);
// радиус oписанной окружности:
3: a := v * 3 / Sqrt(3);
// площадь:
else a := 2 * Sqrt(v * Sqrt(3));
end;
// вычисляем остальные элементы:
var r1 := a * Sqrt(3) / 6;
var r2 := 2 * r1;
var s := a * a * Sqrt(3) / 4;
if
if
if
if
n
n
n
n
<>
<>
<>
<>
1
2
3
4
then
then
then
then
Println('
Println('
Println('
Println('
Сторона =', a);
Pадиус вписанной окружности =', r1);
Pадиус oписанной окружности =', r2);
Площадь =', s);
514
Задание Case15
От геометрии переходим к карточным играм:
Решить эту задача – не сложнее, чем пульку расписать:
## //uses PT4;
//Task('Case14');
{Case15. Мастям игральных карт присвоены порядковые номера:
1 — пики, 2 — трефы, 3 — бубны, 4 — червы.
Достоинству карт, старших десятки, присвоены номера:
11 — валет, 12 — дама, 13 — король, 14 — туз.
Даны два целых числа:
N — достоинство (6 ≤ N ≤ 14) и M — масть карты (1 ≤ M ≤ 4).
Вывести название соответствующей карты вида
«шестерка бубен», «дама червей», «туз треф» и т. п.}
// номер элемента:
var n := ReadInteger(' Введите достоинство карты 6..14 >');
// значение элемента:
var m := ReadInteger(' Введите масть карты 1..4
>');
var s: string;
case n of
6: s := ' шестёрка';
7: s := ' семёрка';
8: s := ' восьмёрка';
9: s := ' девятка';
10: s := ' десятка';
515
11: s := ' валет';
12: s := ' дама';
13: s := ' король';
else s := ' туз';
end;
case m of
1: s += '
2: s += '
3: s += '
else s +=
end;
бубен';
червей';
треф';
' пик';
Println(' Название карты:', s);
Задание Case16
Русский язык очень сложный. Особенно для тех, кто его плохо знает. Но мы знаем
хорошо, поэтому всё у нас согласуется:
## //uses PT4;
//Task('Case16');
{Case16. Дано целое число в диапазоне 20–69,
определяющее возраст (в годах).
Вывести строку-описание указанного возраста,
обеспечив правильное согласование числа со словом «год»,
например: 20 — «двадцать лет», 32 — «тридцать два года»,
516
41 — «сорок один год».}
// возраст (в годах):
var n := ReadInteger(' Введите возраст 20..69 >');
var s: string;
// десятки:
var d := n div 10;
case d of
2: s := 'двадцать';
3: s := 'тридцать';
4: s := 'сорок';
5: s := ' пятьдесят';
else s := 'шестьдесят';
end;
// единицы:
var e := n mod 10;
case e of
1: s += ' один';
2: s += ' два';
3: s += ' три';
4: s += ' четыре';
5: s += ' пять';
6: s += ' шесть';
7: s += ' семь';
8: s += ' восемь';
9: s += ' девять';
end;
// года:
case e of
0, 5, 6, 7, 8, 9: s += ' лет';
2, 3, 4: s += ' года';
else s += ' год';
end;
Println(' Возраст =', s);
517
Задание Case17
Русский язык зело лют!
## //uses PT4;
//Task('Case17');
{Case17. Дано целое число в диапазоне 10–40,
определяющее количество учебных заданий по некоторой теме.
Вывести строку-описание указанного количества заданий,
обеспечив правильное согласование числа со словами «учебное задание»,
например:
18 — «восемнадцать учебных заданий»,
23 — «двадцать три учебных задания»,
31 — «тридцать одно учебное задание».}
// число учебных заданий:
var n := ReadInteger(' Введите число учебных заданий 10..40 >');
var s: string;
// десятки:
var d := n div 10;
case d of
2: s := 'двадцать';
3: s := 'тридцать';
else s := 'сорок';
end;
518
// единицы:
var e := n mod 10;
// 10..19
case d of
1: case e of
0: s := 'десять';
1: s := 'одиннадцать';
2: s := 'двенадцать';
3: s := 'тринадцать';
4: s := 'четырнадцать';
5: s := 'пятнадцать';
6: s := 'шестнадцать';
7: s := 'семнадцать';
8: s := 'восемнадцать';
9: s := 'девятнадцать';
end;
// 20..40
else case e of
1: s += ' одно';
2: s += ' два';
3: s += ' три';
4: s += ' четыре';
5: s += ' пять';
6: s += ' шесть';
7: s += ' семь';
8: s += ' восемь';
9: s += ' девять';
end;
end;
if d = 1 then s := ' учебных заданий';
// задания:
case e of
0, 5, 6, 7, 8, 9: s += ' учебных заданий';
2, 3, 4: s += ' учебных задания';
1: s += ' учебное задание';
end;
Println(' Число заданий =', s);
519
Задание Case18°
Русские числительные очень сложные и коварные, поэтому будьте внимательны:
## uses PT4;
Task('Case18');
{Case18°. Дано целое число в диапазоне 100–999.
Вывести строку-описание данного числа, например:
256 — «двести пятьдесят шесть»,
814 — «восемьсот четырнадцать».}
// целое число:
var n := ReadInteger(' Введите число 100..999 >');
var s: string;
// сотни:
var h := n div 100;
case h of
1: s := 'сто';
2: s := 'двести';
3: s := 'триста';
4: s := 'четыреста';
5: s := 'пятьсот';
6: s := 'шестьсот';
7: s := 'семьсот';
8: s := 'восемьсот';
else s := 'девятьсот';
end;
// десятки:
var d := n div 10 mod 10;
520
case d of
2: s +=
3: s +=
4: s +=
5: s +=
6: s +=
7: s +=
8: s +=
9: s +=
end;
' двадцать';
' тридцать';
' сорок';
' пятьдесят';
' шестьдесят';
' семьдесят';
' восемьдесят';
'девяносто';
// единицы:
var e := n mod 10;
// 10..19
case d of
1: case e of
0: s += ' десять';
1: s += ' одиннадцать';
2: s += ' двенадцать';
3: s += ' тринадцать';
4: s += ' четырнадцать';
5: s += ' пятнадцать';
6: s += ' шестнадцать';
7: s += ' семнадцать';
8: s += ' восемнадцать';
9: s += ' девятнадцать';
end;
// 20..40
else case e of
1: s += ' один';
2: s += ' два';
3: s += ' три';
4: s += ' четыре';
5: s += ' пять';
6: s += ' шесть';
7: s += ' семь';
8: s += ' восемь';
9: s += ' девять';
end;
end;
Println({' Число =',} s);
521
Задание Case19
После основательной предварительной тренировки восточный календарь не покажется вам очень сложным для программирования:
## //uses PT4;
//Task('Case19');
{Case19. В восточном календаре принят 60-летний цикл,
состоящий из 12-летних подциклов, обозначаемых названиями цвета:
зеленый, красный, желтый, белый и черный.
В каждом подцикле годы носят названия животных:
крысы, коровы, тигра, зайца, дракона, змеи, лошади, овцы, обезьяны,
курицы, собаки и свиньи.
По номеру года определить его название,
если 1984 год — начало цикла: «год зеленой крысы».}
// номер года:
var n := ReadInteger(' Введите номер года >');
n -= 1984;
n := n mod 60;
var s: string;
// цвет:
var c := n div 12;
case c of
0: s := 'зелён';
522
1: s
2: s
3: s
else
end;
:= 'красн';
:= 'жёлт';
:= 'бел';
s := 'чёрн';
// год в подцикле:
var g := n mod 12;
case g of
0: s += 'ой крысы';
1: s += 'ой коровы';
2: s += 'ого тигра';
3: s += 'ого зайца';
4: s += 'ого дракона';
5: s += 'ой змеи';
6: s += 'ой лошади';
7: s += 'ой овцы';
8: s += 'ой обезьяны';
9: s += 'ой курицы';
10: s += 'ой собаки';
else s += 'ой свиньи';
end;
Println(' год', s);
Задание Case20
523
Астрологические прогнозы делать сложно, но знаки Зодиака мы запрограммируем! Дело осложняется тем, что каждый знак Зодиака попадает в 2 месяца, поэтому в каждом месяце окажется 2 знака Зодиака. Чтобы их различить, мы дополнительно учитываем день месяца:
## //uses PT4;
//Task('Case20');
{Case20. Даны два целых числа: D (день) и M (месяц),
определяющие правильную дату.
Вывести знак Зодиака, соответствующий этой дате:
«Водолей» (20.1–18.2),
«Рыбы» (19.2–20.3),
«Овен» (21.3–19.4),
«Телец» (20.4–20.5),
«Близнецы» (21.5–21.6),
«Рак» (22.6–22.7),
«Лев» (23.7–22.8),
«Дева» (23.8–22.9),
«Весы» (23.9–22.10),
«Скорпион» (23.10–22.11),
«Стрелец» (23.11–21.12),
«Козерог» (22.12–19.1).}
// число:
var d := ReadInteger(' Введите число
>');
// номер месяца:
var m := ReadInteger(' Введите номер месяца >');
var s:
case m
12:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
string;
of
s := d <
s := d <
s := d <
s := d <
s := d <
s := d <
s := d <
s := d <
s := d <
s := d <
s := d <
22
20
19
21
20
21
21
23
23
23
23
?
?
?
?
?
?
?
?
?
?
?
'Стрелец' : 'Козерог';
'Козерог' : 'Водолей';
'Водолей' : 'Рыбы';
'Рыбы' : 'Овен';
'Овен' : 'Телец';
'Телец' : 'Близнецы';
'Близнецы' : 'Рак';
'Рак' : 'Лев';
'Лев' : 'Дева';
'Дева' : 'Весы';
'Весы' : 'Скорпион';
524
11: s := d < 22 ? 'Скорпион' : 'Стрелец';
end;
Println(' Знак Зодиака:', s);
Обобщение
Условные операторы if и if-else позволяют выполнять только тот код, который
находится в «верной» ветви. Возможность выполнения (или невыполнения)
той или иной ветви этих операторов определяется значением условия – логического выражения.
Условные операторы могут быть вложенными.
Логические выражения – условия операторов if и if-else – вычисляются по укороченному способу, то есть прекращаются сразу же, как только станет известно
значение всего выражения.
Блок инструкций – это несколько строк исходного кода внутри операторных скобок.
Условные операторы и целые алгоритмы удобно представлять в виде блоксхем.
Условный оператор множественного выбора case используют вместо условных
операторов if и if-else, когда выбор нужного значения переключателя большой.
Вместо условия в операторе case используют списки выбора. Оператор case может включать ветвь else, которая выполняется, если значение переключателя
не совпало ни с одним значением из списков выбора.
Задание для самостоятельного решения
Напишите приложение Арифметический калькулятор. Он должен складывать,
вычитать, умножать и делить числа типа integer.
525
Пользователь сначала вводит два числа, а затем знак арифметической операции + - * / (тип string). Программа печатает результат выполнения операции.
Не забывайте, что на нуль делить нельзя!
526
Литература
527
528
529
530
531
532
533
534
535
536
537
538
539
540