«Основы программирования в среде Lazarus УДК 004 ББК 32.973-01 Рецензенты: доктор физико-математических наук, профессор Сопуев А.С. доктор физико-математических наук, профессор Сатыбаев А.С. М23 Мансуров К.Т. Основы ...»
Мансуров К.Т.
Основы программирования
в среде Lazarus
УДК 004
ББК 32.973-01
Рецензенты:
доктор физико-математических наук, профессор Сопуев А.С.
доктор физико-математических наук, профессор Сатыбаев А.С.
М23 Мансуров К.Т. Основы программирования в среде Lazarus, 2010. –
772 с.: ил.
ISBN 978-9967-03-646-8
В книге излагаются основы программирования на языке Паскаль. Она вводит читателя в круг тех идей, понятий, принципов и методов, на которых зиждется современное программирование.
Изложение языка Паскаль ведется применительно к компилятору Free Pascal и среде Lazarus, которые относятся к категории свободного программного обеспечения. Достоинством СПО является общедоступность и бесплатность. Так, и Free Pascal и Lazarus можно свободно скачать в Интернете. В отличие от продуктов семейства Delphi, использование Free Pascal и Lazarus позволит снять все проблемы нелегального использования лицензионного ПО. В то же время Lazarus по своим возможностям практически не уступает Delphi. Таким образом, Lazarus является идеальным средством для изучения языка программирования Паскаль в школах и вузах в полном соответствии с Концепцией развития разработки и использования свободного программного обеспечения в Российской Федерации. В пакете свободного программного обеспечения (ПСПО) для образовательных учреждений РФ Free Pascal и Lazarus также имеются.
В книге приведены многочисленные примеры программ. Подробно рассмотрены типичные и наиболее часто используемые алгоритмы. Особое внимание уделено разработке программ с графическим интерфейсом, а также объектно-ориентированному программированию. Рассмотрены особенности программирования в среде Lazarus в ОС Windows и Linux. К книге прилагается DVD диск с исходными кодами всех программ, рассмотренных в книге.
Учебник предназначен для студентов и преподавателей, а также для школьников и лиц, самостоятельно изучающих программирование на языке Паскаль.
Учебник и все материалы, входящие в него распространяются на условиях лицензии GNU FDL.
М 2404090000- © Мансуров К.Т., ISBN 978-9967-03-646- Содержание Предисловие
Глава 1 Основы программирования
1.1. Понятие алгоритма.
1.1.1 Алгоритм Евклида
1.1.2 Задача о поездах и мухе
1.1.3 Вместо лирического отступления
1.2. Этапы подготовки задачи для решения на компьютере
1.3. Примеры разработки алгоритмов
1.3.1 Решение квадратного уравнения.
1.3.2 Вычисление интегралов
1.3.3 Обработка результатов эксперимента
1.3.4 Решение системы линейных алгебраических уравнений
Глава 2 Введение в язык программирования Pascal
2.1. Основные элементы языка
2.1.1 Переменные. Стандартные типы.
2.1.2 Операции отношения
2.1.3 Раздел описаний переменных
2.1.4 Выражения. Порядок выполнения операций.
2.1.5 Константы
2.1.6 Комментарии в программе
2.1.7 Операторы
2.1.7.1. Оператор присваивания
2.1.7.2. Операторы ввода/вывода
2.1.7.3. Операторы инкремента и декремента
2.1.8 Среда разработки Lazarus
2.1.9 Русский язык в консольных приложениях
2.1.10 Первая программа
2.1.11 Открытие существующего проекта
2.1.12 Другие способы создания консольных приложений
2.1.13 Типовой пустой проект
2.1.14 Операции с целыми числами
2.1.15 Вместо лирического отступления 2
2.1.16 Стандартные функции с целыми аргументами
2.1.17 Операции с вещественными числами (тип real).
2.1.18 Форматирование вывода
2.1.19 Одновременное использование вещественных и целых чисел....... 2.1.20 Другие стандартные функции с вещественными аргументами...... 2.1.21 Булевы переменные
2.1.22 Условные операторы
2.1.22.1 Оператор if …. then
Содержание 2.1.22.2. Оператор if …then... else
2.1.23 Операторы цикла
2.1.23.1. Оператор цикла с предусловием
2.1.23.2. Оператор цикла с постусловием
2.1.23.3. Оператор цикла с параметром.
2.1.23.4. Второй вариант оператора цикла с параметром
2.1.24 Оператор выбора case
2.1.25 Организация простейшего контроля ввода данных.
2.1.26 Вычисление сумм сходящихся рядов
2.2. Реализация некоторых алгоритмов главы 1.
2.2.1 Программа решения задачи о поездах и мухе
2.2.2 Программа вычисления определенного интеграла
Глава 3 Более сложные элементы языка
3.1. Общая структура Паскаль – программы
3.1.1 Процедуры и функции
3.1.1.1 Структура процедуры
3.1.1.2. Структура функции
3.1.1.3 Глобальные и локальные переменные
3.1.1.4 Способы передачи параметров
3.1.1.5 Процедуры завершения
3.2. Еще раз о типах данных
3.2.1 Классификация типов данных
3.2.1.1 Целый тип
3.2.1.2. Интервальный тип
3.2.1.3. Перечислимый тип
3.2.1.4. Множества
3.2.1.5. Логический тип
3.2.1.6. Вещественный тип
3.2.1.7. Указатели
3.3. Обработка символьной информации в Паскале
3.3.1 Символьные и строковые типы данных.
3.3.1.1. Тип Char
3.3.1.2. Функции для работы с символами
3.3.1.3. Тип String
3.3.1.4. Строковые процедуры и функции
3.4. Массивы
3.4.1 Динамические массивы
3.4.2 Программа решения системы линейных алгебраических уравнений методом Гаусса
3.4.1.1. Вариант 1 – с goto
3.4.1.2. Вариант 2 – без goto
3.4.1.3. Вариант 3 – более лучшая реализация
3.5. Модули в Паскале
3.5.1 Структура модуля
3.5.2 Системные модули
3.5.2.1. Модуль CRT
3.6. Файлы
3.6.1 Тип данных – запись
3.6.2 Файловые типы
3.6.3 Процедуры для работы с файлами
3.6.3.1. Общие процедуры для работы с файлами всех типов
3.6.3.2. Процедуры для работы с текстовыми файлами
3.6.3.3. Процедуры для работы с типизированными файлами
3.6.3.4. Процедуры для работы с нетипизированными файлами
3.6.3.5. Организация контроля ввода/вывода при работе файлами
3.6.3.6. Создание простой базы данных с типизированными файлами.
Глава 4 Типовые алгоритмы обработки информации
4.1. Алгоритмы сортировки
4.1.1 Обменная сортировка (метод "пузырька")
4.1.2 Сортировка выбором
4.1.3 Сортировка вставками
4.1.4 Метод быстрой сортировки
4.2. Алгоритмы поиска
4.2.1 Поиск в массивах
4.2.2 Вставка и удаление элементов в упорядоченном массиве................ 4.3. Динамические структуры данных
4.3.1 Представление в памяти компьютера динамических структур........ 4.3.2 Реализация стека с помощью массивов
4.3.3 Представление двоичного дерева в виде массива и реализация алгоритма обхода двоичного дерева слева.
4.3.4 Указатели
4.3.5 Стандартные операции с линейными списками
4.3.6 Реализация динамических структур линейными списками.............. 4.3.6.1. Реализация стека
4.3.6.2. Реализация очереди с помощью линейного списка
4.3.6.3. Реализация двоичного дерева с помощью линейного списка
4.3.7 Сортировка и поиск с помощью двоичного дерева
Глава 5 Основы объектно-ориентированного программирования
5.1. Три источника и три составные части ООП.
5.2. Классы и объекты.
5.2.1 Обращение к членам класса.
5.3. Инкапсуляция
5.3.1 Спецификаторы доступа.
5.3.2 Свойства.
5.4. Наследование
5.5. Полиморфизм
5.5.1 Раннее связывание.
5.5.2 Позднее связывание.
5.5.3 Конструкторы и деструкторы.
Глава 6 Программирование приложений с графическим интерфейсом............ 6.1. Элементы графического интерфейса
6.2. Различия между консольными и графическими приложениями............ 6.3. Визуальное программирование в среде Lazarus
6.3.1 Создание графического приложения
6.3.2 Форма и ее основные свойства
6.3.3 Компоненты
6.3.4 Обработчики событий
6.3.5 Простейшие компоненты
6.3.5.1. Компонент TLabel
6.3.5.2. Кнопки TButton, TBitBtn и TSpeedButton
6.3.6 Организация ввода данных. Однострочные редакторы TEdit, TLabeledEdit
6.3.6.1. Компонент TEdit
6.3.6.2. Компонент TLabeledEdit
6.3.7 Обработка исключений. Компонент TMaskEdit. Организация контроля ввода данных
6.3.7.1. Компонент TMaskEdit
6.3.8 Специальные компоненты для ввода чисел
6.3.9 Тестирование и отладка программы
6.3.10 Компоненты отображения и выбора данных
6.3.10.1. Компонент TMemo
6.3.10.2. Компонент TStringGrid
6.3.10.3. Компоненты выбора
6.3.10.4. Компоненты отображения структурированных данных
6.3.11 Организация меню. Механизм действий - Actions
6.3.11.1. Компонент TMainMenu
6.3.11.2. Компонент TToolBar
6.3.11.3. Компонент TActionList
6.3.11.4. Создание приложений с изменяемыми размерами окон
Послесловие
Литература
Алфавитный указатель
Предисловие Настоящая книга возникла в результате переработки лекций, которые я читал на протяжении ряда лет студентам Ошского технологического университета.
В книге излагаются основы программирования на языке Паскаль. Она вводит читателя в круг тех идей, понятий, принципов и методов, на которых зиждется современное программирование.
Во многих школах и вузах преподавание языка Паскаль ведется с применением компилятора Турбо-Паскаль фирмы Borland. Хотя Турбо-Паскаль ныне уже не поддерживается, тем не менее, он является платным продуктом. Правопреемником Borland в настоящее время является компания Embarcadero Technologies.
Несмотря на то, что многие ведущие разработчики программного обеспечения, включая и Embarcadero Technologies, имеют специальные предложения для учебных заведений с существенными скидками, многие вузы, а тем более и школы, к сожалению, не в состоянии приобретать новейшие средства разработки программ, например, такие как Embarcadero RAD Studio 2010, Microsoft Visual Studio и многие другие.
Поэтому совершенно естественным является подход к использованию в образовательных учреждениях свободного программного обеспечения. Не случайно в России принята Концепция развития разработки и использования свободного программного обеспечения, которая касается также и образования.
Достоинством СПО является общедоступность и бесплатность.
Изложение языка Паскаль в этой книге ведется применительно к компилятору Free Pascal и среде Lazarus, которые относятся к категории свободного программного обеспечения. Так, и Free Pascal и Lazarus можно свободно скаПредисловие чать в Интернете. В отличие от продуктов семейства Delphi, использование Free Pascal и Lazarus позволит снять все проблемы нелегального использования лицензионного ПО. В то же время Lazarus по своим возможностям практически не уступает Delphi. Таким образом, Lazarus является идеальным средством для изучения языка программирования Паскаль в школах и вузах в полном соответствии с упомянутой выше Концепцией. В пакете свободного программного обеспечения (ПСПО) для образовательных учреждений РФ Free Pascal и Lazarus также имеются.
Книга состоит из шести глав.
В первой главе излагается понятие алгоритма, способы записи алгоритмов, даются примеры разработки алгоритмов. Рассматриваются этапы решения задачи на компьютере.
Во второй главе рассматриваются элементарные конструкции языка Паскаль. Дается краткий обзор IDE Lazarus. Рассматриваются способы создания консольных приложений. Рассмотрены особенности программирования в среде Lazarus в ОС Windows и Linux. Так, для Windows в консольных приложениях существует проблема с русским языком. В главе дается способ решения этой проблемы. Для Linux приводится способ настройки приложения для его выполнения в терминале. Рассмотрены простейшие методы контроля данных.
В третьей главе рассматриваются более сложные элементы языка, в частности подробно разбираются типы данных, методы обработки символьных и строковых данных, функции и процедуры, способы передачи параметров, массивы, в том числе динамические массивы. Подробно изучаются файлы, методы доступа, типы файлов, обработка ошибок ввода-вывода.
В четвертой главе изучаются типовые алгоритмы. К типовым алгоритмам отнесены алгоритмы сортировки и поиска, а также алгоритмы работы с динамическими структурами. Рассмотрены ряд алгоритмов, проводится сравнение и анализ эффективности этих алгоритмов.
Подробно изучаются указатели. С применением указателей показаны способы реализации динамических структур данных, таких как, например, стеки, списки и т.д.
В пятой главе, которая, на взгляд автора, имеет огромное значение, изучаются принципы объектно-ориентированного программирования. Поскольку современное программирование зиждется именно на ООП и знание и умение применять принципы ООП является неотъемлемой составляющей в подготовке специалистов в области программного обеспечения.
И, наконец, шестая глава посвящена программированию приложений с графическим интерфейсом. Эта глава является наиболее существенной частью книги, поскольку подавляющее большинство приложений разрабатывается на основе графического интерфейса. Подробно разбираются принципиальные различия консольных приложений и графических приложений. Приводятся описания основных и часто используемых компонентов. Рассмотрены вопросы тестирования и отладки программ, обработка исключений, механизм действий Actions и многие другие вопросы.
В книге последовательно проводится линия на создание кроссплатформенных приложений.
Все примеры были проверены на ОС Windows XP SP3 и дистрибутивах Linux:
Альт Линукс 5.0 Школьный Мастер Ubuntu 9. Mandriva Linux 2009.0 (Free) Глава 1 Основы программирования 1.1. Понятие алгоритма.
Компьютер - это устройство для решения задач. Не обязательно задач чисто математического характера. Это могут быть и задачи управления станками или ракетами, и задачи планирования производства, и задачи информационносправочного обслуживания, и задачи обработки гипертекстовой информации и мультимедиа, т.е. обработки звуковой и видеоинформации. Чтобы решить какую - либо задачу на компьютере необходимо сначала придумать как ее вообще решить, т.е. придумать алгоритм ее решении. Алгоритм – является одним из краеугольных понятий информатики и программирования.
Итак, что же понимается под алгоритмом?
Алгоритм - это строгая и четкая, конечная система правил, которая определяет последовательность действий над некоторыми объектами и после конечного числа шагов приводит к достижению поставленной цели.
Из определения алгоритма следует, что он должен удовлетворять следующим требованием:
1) конечность (финитность) Алгоритм всегда должен заканчиваться после конечного числа шагов.
Процедуру, обладающую всеми характеристиками алгоритма, за исключением конечности, вызывают вычислительным методом.
2) определенность (детерминированность) Каждый шаг алгоритма должен быть строго определен. Действия, которые необходимо произвести, должны быть строго и недвусмысленно определены в каждом возможном случае, так чтобы если дать алгоритм нескольким людям, то они, действуя по этому алгоритму, получали один и тот же результат. Поскольку обычный язык полон двусмысленностей, то чтобы преодолеть это затруднение, для описания алгоритмов разработаны формально определенные языки программирования, или машинные языки, в которых каждое утверждение имеет абсолютно точный смысл.
Запись алгоритма на языке программирования называется программой.
3) Алгоритм должен иметь некоторое число входных данных, т.е. величин, объектов заданных ему до начала работы. Эти данные берутся из некоего конкретного множества объектов.
4) Алгоритм имеет одну или несколько выходных величин, т.е. величин, имеющих вполне определенное отношение к входным данным.
5) Эффективность От алгоритма требуют, чтобы он был эффективным. Это означает, что все операции, которые необходимо произвести в алгоритме, должны быть достаточно простыми, чтобы их в принципе можно было выполнить точно и за конечный отрезок времени с помощью карандаша и бумаги.
Следует отметить, что для практических целей "финитность" является наиболее важным требованием – используемый алгоритм должен иметь не просто конечное, а предельно конечное, разумное число шагов. Например, в принципе имеется алгоритм, определяющий, является ли начальное положение в игре в шахматы форсировано выигранным для белых или нет. Но для выполнения этого алгоритма требуется фантастически огромный промежуток времени.
Пусть имеется компьютер, обладающий быстродействием 100 млн. операций в секунду. Тогда этот компьютер будет выполнять алгоритм в течение 1023 лет.
Для сравнения укажем, что период времени с начала возникновения жизни на земле и до наших дней намного меньше 1023 лет.
Пример алгоритма.
1.1.1 Алгоритм Евклида.
Алгоритм Евклида нахождения наибольшего общего делителя двух целых чисел, т.е. наибольшее целое число, которое делит нацело заданные числа.
1. Рассмотреть А как первое число и В как второе число. Перейти к п.2.
2. Сравнить первое и второе числа. Если они равны, то перейти к п.5. Если нет, то перейти к п.3.
3. Если первое число меньше второго, то переставить их местами. Перейти к п.4.
4. Вычесть из первого числа второе и рассмотреть полученную разность как новое первое число. Перейти к п.2.
5. Рассмотреть первое число как результат.
Этот набор правил является алгоритмом, т.к. следуя ему, любой человек умеющий вычитать, может получить наибольший общий делитель для любой пары чисел. Следуя этому алгоритму, найдем НОД чисел 544 и 119.
Меняем местами А=В=17=НОД Данный способ записи алгоритмов возможен, но неудобен. Во-первых, нет наглядности, во-вторых, "многословен". Одним из способов записи алгоритма являются блок- схемы. Блок- схемой называется такое графическое изображение структуры алгоритма, в котором каждый этап или шаг процесса переработки данных представляется в виде прямоугольника, ромба, овала или другой геометрической фигуры, называемой блоком.
Эти фигуры соединяются между собой линиями со стрелками, отображающими последовательность выполнения алгоритма. Внутри каждой фигуры разрешается писать произвольный текст, в котором на понятном человеку языке сообщаются о нужных вычислениях в соответствующей части программы.
Приняты определенные стандарты графических обозначений. Так, прямоугольник обозначает вычислительные действия, в результате которых изменяются значения данных. Ромбом обозначают этап разветвления алгоритма. Выбор одного из двух возможных направлений дальнейшего счета производится в зависимости от выполнения условия, записанного в ромбе. Овалом обозначают начало и конец алгоритма. В параллелограммах записывают процедуры ввода и вывода данных. Запишем алгоритм Евклида в виде блок- схемы:
Программирование->Lazarus (Ubuntu).
Проще всего этот ярлык перетащить на рабочий стол. Кроме того, можно /usr/lib/lazarus) и дважды щелкнуть по имени файла lazarus или startlazarus, если вы используете файловый менеджер или дать команду./lazarus (./startlazarus), если вы используете консоль.
В Windows во время установки можно задать опцию "Создать значок на рабочем столе". Если вы этого не сделали, то можете запускать из меню Пуск->Программы->Lazarus. Вы также можете скопировать этот ярлык на рабочий стол. Наконец, можно перейти в папку установки (чаще всего C:\lazarus) и дважды щелкнуть по имени файла lazarus.exe или startlazarus.exe.
Итак, IDE Lazarus имеет вид, показанный на рис. 2.1, 2.2.
Рис. 2.2 Вид IDE Lazarus в Linux, рабочий стол KDE Глава 2 Введение в язык программирования Pascal Как видите, IDE Lazarus выглядит одинаково в обеих операционных системах, только цветовое оформление окон чуть разнится.
Среда Lazarus состоит из нескольких, вообще говоря, не связанных окон.
1. Главное окно, рис. 2.3.
С помощью этого окна можно управлять процессом разработки приложения. В нем предусмотрены команды управления файлами, компиляцией, редактированием, окнами и т.д. Окно разбито на три функциональных блока:
Главное меню. В нм расположены команды управления файлами, команды управления компиляцией и свойствами всего приложения, команды управления окнами и настройками среды и многое другое. Меню располагается в верхней части основного окна.
Панель инструментов. Панель инструментов предоставляет быстрый доступ к основным командам главного меню. Она расположена в левой части главного окна, под главным меню.
Палитра компонентов. Предоставляет доступ к основным компонентам среды разработки, например: поле ввода, надпись, меню, кнопка и т.п.
2. Инспектор объектов, рис. 2.7.
В верхней части окна показывается иерархия объектов, а снизу, расположены три вкладки: "Свойства", "События", "Избранное". Назначение инспектора объекта – это просмотр всех свойств и методов объектов. На вкладке "Свойства" перечисляются все свойства выбранного объекта. На вкладке "События" перечисляются все события для объекта. На вкладке "Избранное" избранные свойства и методы. Подробнее об этом будет сказано в главе 6.
Глава 2 Введение в язык программирования Pascal 3. Редактор исходного кода Lazarus Именно в этом окне мы будем набирать тексты своих программ. Многие функции и возможности этого редактора совпадают с возможностями обычных текстовых редакторов, например Блокнота. Текст в редакторе можно выделять, копировать, вырезать, вставлять. Кроме того, в редакторе можно осуществлять поиск заданного фрагмента текста, выполнять вставку и замену. Но, конечно, этот редактор исходных текстов Lazarus обладает еще рядом дополнительных возможностей для комфортной работы применительно к разработке программ.
Основное преимущество редактора заключается в том, что он обладает возможностями подсветки синтаксиса, причм не только Pascal, но и других языков, а также рядом других удобств. В частности, выделенный фрагмент текста можно сдвигать вправо или влево на количество позиций, указанных в настройках Окружение ->Параметры…->Редактор -> Общие -> Отступ блока, что очень удобно для форматирования с целью структурирования кода. ВыделенОсновные элементы языка ный фрагмент можно закомментировать или раскомментировать, перевести в верхний или нижний регистр и т.д.
Все возможные операции в редакторе собраны в меню Правка и Поиск главного меню Lazarus, рис. 2.9, 2.10.
4. Окно сообщений В этом окне выводятся сообщения компилятора, компоновщика и отладчика.
На этом мы закончим наш краткий обзор среды Lazarus. Мы рассмотрели далеко не все виды окон IDE, да и те, что рассмотрели, мы рассмотрели бегло, лишь для того, чтобы получить первое представление о среде Lazarus. ЗаниГлава 2 Введение в язык программирования Pascal маться нудным рассказом обо всех пунктах, опциях и возможностях Lazarus я сейчас не буду. Ведь не все будет понятно, да и … скучно! Ведь вам, уважаемый читатель, "не терпится в бой"! Поэтому будем рассматривать только те элементы, которые будут нам нужны на первых порах. А, остальное мы будем изучать по мере необходимости и в нужных местах. Так, мне кажется, будет лучше!
Сначала настроим IDE так, как нам будет удобнее работать. Как уже говорилось, при первом запуске окна IDE Lazarus не связаны и представляют собой "плавающие" окна. Советую вам их соединить так, как показано на рис. 2.11.
путем изменения размеров окон, чтобы Lazarus занимал весь экран.
Рис. 2.11. Вид IDE Lazarus после изменения размеров и положения окон Окружение выберите пункт Окно. Далее для каждого окна установите опцию "Пользовательская позиция" и нажмите кнопку "Применить", рис. 2.12.
В Windows все окна Lazarus после этого жестко скрепляются, поэтому, если, например, у вас Lazarus был свернут, то после разворачивания будут видны все окна. В Linux не так. Размеры и положение окон сохраняются, но вы можете открывать окна по отдельности, рис. 2.13.
Глава 2 Введение в язык программирования Pascal Далее в том же окне Параметры IDE выберите пункт Отладчик и снимите галочку с опции "Показывать сообщение при остановке". Этим мы избавимся от надоедливого сообщения "Выполнение остановлено" при каждом завершении наших программ, рис. 2.14.
Рис. 2.14. Окно настройки параметров отладчика Изучение языка лучше всего начинать с консольных приложений. Консольное приложение — программа, которая не имеет графического интерфейса и выполняется в текстовом режиме в консоли. В Windows консоли обычно соответствует окно командной строки. В Linux консоли соответствует окно терминала. Для таких программ устройством ввода является клавиатура, а устройством вывода — монитор, работающий в текстовом режиме отображения симОсновные элементы языка вольной информации (буквы, цифры и специальные знаки).
Консольное приложение позволяет сосредоточиться на существе той или иной конструкции языка, поэтому мы начнем с консольных приложений. Однако нельзя считать, что консольные приложения предназначены лишь для изучения языка. Можно и с помощью консольных приложений разрабатывать очень сложные программы. Например, компилятор Free Pascal является консольным приложением, то есть может быть запущен в консоли, из командных файлов или из IDE Lazarus.
Для создания консольного приложения необходим только текстовый редактор и компилятор Free Pascal. В принципе для этого Lazarus не нужен. Однако мы все же будем использовать Lazarus, поскольку IDE Lazarus позволяет создавать в том числе и консольные приложения. А его мощный текстовый редактор с подсветкой синтаксиса и другими широкими возможностями значительно облегчит нам написание программ.
2.1.9 Русский язык в консольных приложениях В консольных приложениях под Windows, к сожалению, возникают проблемы с выводом на экран русских букв. Это вызвано различием в кодировке символов в Windows, которая работает в графическом режиме и ее консоли, которая работает в текстовом режиме. Не вдаваясь пока в тонкости, скажу лишь, что мы в своих программах будем использовать специальную функцию UTF8ToConsole(), которая позволит нам корректно отображать русские буквы на экране в консольных приложениях для платформы Windows в операторах writeln и write.
Используйте функцию UTF8ToConsole() вот таким образом:
writeln(UTF8ToConsole('Русский текст'));
Глава 2 Введение в язык программирования Pascal В Linux таких проблем нет, поэтому можно писать просто Но мы и в Linux будем писать writeln(UTF8ToConsole('Русский текст'));
Это позволит нам без проблем переносить программы из Linux в Windows, т.е. наши программы без каких-либо переделок будут безошибочно компилироваться и выполняться как на платформе Linux, так и на платформе Windows.
2.1.10 Первая программа Запустите Lazarus. Выберите пункт меню Проект, Создать проект… (рис.
2.15).
Создайте консольное приложение (рис. 2.16). Для этого выберите Консольное приложение и нажмите Создать.
Возьмите себе за правило сразу же сохранять только что созданный проект, даже если он пока пустой. Это должно стать вашей хорошей привычкой, такой же, как чистить зубы утром и вечером! Дело в том, что во время сохранения, вы можете создать папку для своего проекта, и все файлы текущего проекта будут сохранены в отдельной папке. Это поможет вам структурировать ваши проекты и не запутаться в них, если их будет много.
Для сохранения проекта проще всего воспользоваться кнопками на панели инструментов, рис. 2.17.
В открывшемся диалоговом окне сохранения проекта создайте новую папку в нужном месте, укажите имя проекта и нажмите Сохранить, рис. 2.18, 2.19.
Глава 2 Введение в язык программирования Pascal Рис. 2.18. Стандартное диалоговое окно сохранения в Windows Рис. 2.19. Стандартное диалоговое окно сохранения в Linux При задании имени папки и имени проекта старайтесь, чтобы имена отражали суть проекта. Это поможет вам легко ориентироваться в своих проектах, особенно когда их накопится достаточно много. Также помните, что если вы даете имя, состоящее из нескольких слов, то в Linux нельзя ставить пробелы между словами. В этом случае Lazarus не сможет открыть ваш проект, рис. 2.20.
Имя проекта всегда задавайте в нижнем регистре.
После сохранения в папке с проектом появятся несколько файлов, которые мы рассмотрим позже. В окне редактора исходного кода вы увидите текст. Это заготовка кода для консольного приложения, автоматически вставляемого Lazarus (рис. 2.21).
Рис. 2.21. Заготовка кода для консольного приложения, автоматически вставляемого Lazarus Глава 2 Введение в язык программирования Pascal Мы не будем сейчас обращать внимание на этот код и разбирать его, поскольку у нас для этого пока недостаточно знаний. Просто удалите этот код.
Для этого установите курсор в любое место окна редактора исходного текста и нажмите Ctrl+A. Весь текст в окне выделится. Нажмите клавишу Delete. Введите следующий код программы:
program summa;
{$mode objfpc}{$H+} uses FileUtil; { Подключение модуля FileUtil для корректного отображения русских букв с помощью функции UTF8ToConsole } var result, A, B: integer;
begin readln(A, B);
result:=A + B;
writeln(UTF8ToConsole('1-е введенное число= '), A);
writeln(UTF8ToConsole('2-е введенное число= '), B);
writeln(UTF8ToConsole('Сумма двух чисел = '), result);
end.
Окно редактора исходного кода в Windows будет иметь вид, рис. 2.22:
Рис. 2.22. Окно редактора исходного кода в Windows В Linux это же окно будет иметь вид, рис. 2.23.
Глава 2 Введение в язык программирования Pascal Обратите внимание на объявление uses Этим объявлением мы подключаем модуль FileUtil в котором определена функция UTF8ToConsole().
Если вас смущает что значит модуль и функция в Паскале, то немного потерпите. В главе 3 мы подробно рассмотрим все эти вопросы. Напоминаю, что мы вынуждены это делать, чтобы в Windows в окне DOS при работе вашей программы корректно отображался русский шрифт. Также пока примите на веру и проделайте следующее.
Откройте меню Проект->Инспектор проекта и нажмите на кнопку со значком "+", рис. 2.24.
В появившемся окне "Добавить к проекту" нажмите на кнопку "Новое требование", рис. 2.25.
В раскрывающемся списке "Имя пакета" найдите и выберите пакет LCL.
Нажмите клавиши Ctrl+F9. Начнется компиляция и сборка программы. Если вы ввели текст программы без ошибок в точности как приведено выше, то компиляция завершится успешно. В окне Сообщения вы увидите сообщение Проект "summa" успешно собран.
В папке проекта появятся, в дополнение к уже существующим, еще несколько файлов. В частности, готовый к исполнению файл. В Windows это будет файл с расширением exe, в Linux файл без расширения.
Чтобы запустить программу на выполнение прямо из среды Lazarus нажмите клавишу F9 или кнопку "Запуск" (зеленый треугольник) на панели инструментов или меню Запуск->Запуск, рис. 2.26.
Пользователям Linux для того, чтобы запускать программы из среды Lazarus в терминале необходимо в меню Запуск->Параметры запуска устаноГлава 2 Введение в язык программирования Pascal вить флажок "Использовать приложение для запуска", рис. 2.27, 2.28.
При этом для некоторых дистрибутивов Linux надо заменить строку /usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine) /usr/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine) Для запуска программы вне среды Lazarus в Windows достаточно дважды щелкнуть по имени исполняемого exe-файла.
В Linux выдать команду./ В дальнейшем, для единообразия в изложении, будем предполагать, что все примеры в книге запускаются из среды Lazarus.
После запуска программы у вас появится окно вида, рис. 2.29 (Windows) и рис. 2.30 (Linux).
Глава 2 Введение в язык программирования Pascal Рис. 2.29. Окно исполняемой программы в Windows Введите значения переменных A и B. Это должны быть целые числа. Для завершения ввода числа нажмите Enter.
Окно вывода программы в Linux будет иметь вид, рис. 2.31:
В Windows после ввода второго числа в окне что-то промелькнет и окно закроется. Как сделать так, чтобы окно не закрывалось, и мы могли увидеть результаты выполнения программы?
Для этого можно вставить в код программы оператор readln без параметров перед завершающим оператором end с точкой. Снова нажмите клавишу F9. На этот раз после ввода чисел окно не закроется и вы сможете увидеть результаты работы программы, рис. 2.32.
Глава 2 Введение в язык программирования Pascal Чтобы закрыть окно программы нажмите Enter.
Проанализируем нашу программу. Вроде программа работает, сумма вычисляется правильно. И все же даже в этой простейшей программе видны существенные недостатки. Недостатки с точки зрения организации взаимосвязи с пользователем или, как говорят, интерфейса связи с пользователем.
Во-первых, после запуска нашей программы появляется пустое окно. Это сразу же вызывает негативные ассоциации. Что-то случилось с компьютером?
Он завис?
Ну, мы-то с вами знаем, что нужно ввести два числа, но пользователь может и не знать об этом! Как исправить это? А очень просто! Вставьте оператор writeln(UTF8ToConsole('Введите два целых числа'));
перед оператором ввода readln(A, B);
Окно программы будет выглядеть так, рис. 2.33, 2.34:
Теперь даже ежу понятно, что нужно ввести два числа!
Во-вторых, (это касается опять же Windows) неплохо было бы дать пользователю инструкцию как выйти их программы. Окно программы будет закрыто только после нажатия клавиши Enter. Нажатие любых других клавиш к закрытию окна не приведет! Можно, конечно, воспользоваться кнопкой закрытия окна. Но желательно, чтобы программа сама закрывала свое собственное окно.
И опять, пользователь ведь не знает, что для выхода из программы нужно нажать клавишу Enter. Есть два варианта выхода из этой ситуации:
1. В конце программы, но перед readln вставить оператор writeln(UTF8ToConsole ('Для выхода нажмите Enter'));
2. Воспользоваться функцией readkey без параметров. Окно программы будет закрываться при нажатии любой клавиши. Этот вариант предпочтительней, uses Crt, чтобы включить модуль CRT о котором речь пойдет позже и в котором и есть эта функция. Но, даже в этом случае, будет правильнее, если вставить оператор (разумеется, перед readkey) writeln(UTF8ToConsole('Для выхода нажмите любую клавишу'));
Глава 2 Введение в язык программирования Pascal Окончательный текст программы будет выглядеть следующим образом:
program summa;
{$mode objfpc}{$H+} uses Crt, FileUtil; {Подключение модуля CRT для использования функции readkey и модуля FileUtil для корректного отображения русских букв с помощью функции UTF8ToConsole} var result, A, B: integer;
begin writeln(UTF8ToConsole('Введите два числа'));
readln(A, B);
result:=A + B;
writeln(UTF8ToConsole('1-е введенное число= '), A);
writeln(UTF8ToConsole('2-е введенное число= '), B);
writeln(UTF8ToConsole('Сумма двух чисел = '), result);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Результаты работы программы приведены на рис. 2.35, 2.36.
Рис. 2.35. Результаты работы программы в Windows Пользователи Linux обратите внимание, что если вы выполняете программу в терминале, то выдается еще дополнительно сообщение "Press enter". Все же операторы writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
Глава 2 Введение в язык программирования Pascal мы оставим, так как книга рассчитана не только для "линуксоидов", но и для "оконщиков"! А в Windows, как мы уже видели, эти операторы нужны. Ну, а пользователям Linux оставляем право выбирать, использовать эти операторы или нет, равно как и применять функцию UTF8ToConsole().
2.1.11 Открытие существующего проекта Открыть существующий проект из среды Lazarus можно, воспользовавшись кнопкой в панели инструментов, рис. 2.37.
Рис. 2.37. Кнопка открытия существующего проекта или в меню "Файл" выбрать пункт "Открыть…" или нажать клавиши Ctrl+О.
Будет открыт стандартный диалог, рис. 2.38, 2.39.
Рис. 2.38. Стандартный диалог открытия проекта в Linux Рис. 2.39. Стандартный диалог открытия проекта в Windows Если у вас Lazarus не запущен, то можно открыть существующий проект дважды щелкнув по имени файла с расширением *.lpi или *.lpr. Файл с расширением lpi (Lazarus Project Information) это основной файл проекта Lazarus, сохраняется в XML формате.
Файл с расширением lpr – исходный код основной программы. Не смотря на специфичное для Lazarus расширение на самом деле это обычный Pascal-код.
В Linux, если вместо Lazarus будет запускаться другая программа (чаще всего Konqueror или KWrite), то надо настроить файловый менеджер, чтобы он открывал Lazarus по двойному щелчку по имени файла.
Щелкните по имени файла проекта правой клавишей мыши. В открывшемся контекстном меню выберите пункт "Свойства…", рис. 2.40. Далее в открывшемся окне "Свойства" нажмите на кнопку с изображением гаечного ключа, рис. 2.41. В окне "Изменить тип файла" нажмите на кнопку "Добавить…", рис.
2.42. Откроется окно "Выбор приложения…", рис. 2.43. В этом окне введите Глава 2 Введение в язык программирования Pascal имя приложения с путем к нему, например /usr/lib/lazarus/lazarus или /usr/lib/lazarus/startlazarus или нажмите на кнопку выбора файла и в окне "Редактор типов файла" найдите папку, где установлен Lazarus, рис. 2.44.
Рис. 2.43. Окно выбора приложения для открытия файла Глава 2 Введение в язык программирования Pascal Рис. 2.44. Выбор Lazarus для открытия файла проекта 2.1.12 Другие способы создания консольных приложений Lazarus предоставляет и другие способы создания консольных приложений. Рассмотрим снова меню Проект-> Создать проект…, рис. 2.45.
Рис. 2.45. Другие способы создания консольных приложений Консольное приложение можно создать, выбрав пункты "Программа" и "Программа пользователя".
При выборе "Программа" Lazarus сделает следующую заготовку:
program Project1;
{$mode objfpc}{$H+} uses {$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} { you can add units after this };
{$IFDEF WINDOWS}{$R project1.rc}{$ENDIF} begin end.
Исходный код программы будет автоматически поддерживаться Lazarus и будет сохранен в файле с расширением.lpr.
При выборе "Программа пользователя" Lazarus сделает следующую заготовку:
program Project1;
{$mode objfpc}{$H+} uses Classes, SysUtils { you can add units after this };
{$IFDEF WINDOWS}{$R project1.rc}{$ENDIF} begin end.
При этом исходный код программы будет сохранен в файле с расширением.pas.
Сравнивая эти три способа создания консольных приложений, можно сдеГлава 2 Введение в язык программирования Pascal лать вывод, что самым "продвинутым" способом будет первый способ (каким мы и воспользовались). Правда, пока мы только "продемонстрировали" свои намерения. Ведь мы полностью заменили код, который нам предлагал Lazarus.
Дело в том, что заготовка программы, предложенная Lazarus, предполагает, что мы знаем объектно-ориентированное программирование (ООП) и еще много чего, например, обработку исключений. Нам до этого еще далеко!
Но мы, выбрав пункт "Консольное приложение" подтверждаем свою решимость "идти до конца" – изучить язык, изучить ООП и затем создавать консольные приложения "как положено"!
А пока, в нашей книге, мы не будем делать различий в способах создания консольных приложений. Вы можете выбирать любой способ, какой вам понравится.
В заключение отметим, что создавать новые консольные проекты, а также множество других видов проектов и программных объектов можно через меню Файл -> Создать…, рис. 2.46.
2.1.13 Типовой пустой проект Как вы видели из 2.1.10 после создания нового проекта, его необходимо настраивать. В частности, включить в проект пакет LCL (см. рис. 2.24, 2.25), а в Linux настроить параметры запуска (см. рис. 2.27, 2.28). При большом числе создаваемых проектов это напрягает. В нашей книге мы будем создавать довольно много консольных приложений. Автор очень надеется, что вы, уважаемый читатель, все примеры, приведенные в книге, будете скрупулезно выполнять на компьютере. Ведь только так можно научиться программировать! Даже простой набор текстов программ в редакторе исходного кода Lazarus позволит вам намного быстрее освоить и запомнить многие синтаксические конструкции языка Паскаль. Как было сказано в 1.1.3 одного чтения и "понимания" примеров книги будет совершенно недостаточно!
Поэтому удобнее всего для выполнения примеров создать пустой проект со всеми настройками, о которых говорилось выше и всегда, когда необходимо создавать новый проект, использовать уже готовый пустой проект. Давайте поступим следующим образом:
1. Создайте консольное приложение любым удобным для вас способом.
2. Вместо заготовки Lazarus введите в окне редактора исходного кода следующий текст:
program project1;
{$mode objfpc}{$H+} CRT, FileUtil, SysUtils;
{Вставьте сюда исходный код вашей программы} Глава 2 Введение в язык программирования Pascal writeln(UTF8ToConsole('Нажмите любую клавишу'));
3. Установите необходимые свойства проекта, т.е. включите в проект пакет LCL, в Linux настройте параметры запуска.
4. Сохраните проект в папке "Типовой пустой проект для консольных приложений". Не забывайте, что в Linux в названиях папок не допускаются пробелы, поэтому присвойте этой папке имя без пробелов, например такое:
"Типовой_пустой_проект_для_консольных_приложений".
Теперь, если вам необходимо создать новый проект, откройте этот пустой проект и тут же сохраните его в другой папке с помощью меню Файл-> Сохранить как… При этом можно и нужно сохранить проект под другим именем, отражающим характер решаемой задачи. Ваш новый проект будет уже иметь необходимые нам настройки.
2.1.14 Операции с целыми числами До сих пор мы рассматривали лишь одну операцию с целыми числами – сложение. Естественно в Паскале разрешены и другие операции. Рассмотрим программу, показывающую все возможные операции с целыми числами:
program int_operations;
uses Crt, FileUtil;
var A, B, C: integer;
begin writeln(UTF8ToConsole('Введите два числа'));
readln(A, B);
writeln('A= ',A,' B= ',B);
writeln(UTF8ToConsole('Демонстрация сложения, C= '),C);
writeln(UTF8ToConsole('Демонстрация умножения, C= '),C);
writeln(UTF8ToConsole('Демонстрация деления нацело, C= '),C);
writeln(UTF8ToConsole('Остаток от деления, C= '),C);
writeln(UTF8ToConsole('Демонстрация вычитания, C= '),C);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Из этой программы видно, что знак умножения * (а не буква х). Тем самым избегают возможности спутать его с буквой х.
Далее с целыми числами определены операции:
div (от английского divide – делить) – деление нацело.
Пусть А = 17, В = 3, отсюда 17:3 = 5*3+2 и дает результат mod (от английского modulo – определить остаток) – определение остатка от деления нацело.
A mod B дает результат Откомпилируйте и выполните свою программу (клавиша F9).
Все нормально? Программа работает? У вас еще не выходило такое? (рис.
2.47, 2.48) Глава 2 Введение в язык программирования Pascal Рис. 2.48. Оператор, при выполнении которого произошла ошибка В Linux окно вывода будет таким:
Или, если вы запускаете программу в консоли, то окно будет иметь вид:
Даже если такого сообщения не выходило, многие читатели, наверное, уже догадались, что мы в этой программе не учли. Да-да, вы абсолютно правы, в программе имеется операция деления. А ведь пользователь мог в качестве второго числа ввести ноль. Но делить на ноль, как известно, нельзя!
Здесь мне бы хотелось снова отступить от конкретики и порассуждать на "общие" темы.
2.1.15 Вместо лирического отступления В процессе разработки программы многие начинающие программисты совершенно не обращают внимания на такие, казалось бы, мелочи. А зря! Ваши программы должны быть защищены от любых мыслимых и немыслимых ошибок или непреднамеренных действий пользователя. Казалось бы, в совершенно очевидных ситуациях, когда пользователь ни при каких обстоятельствах не должен был бы ввести число ноль, из тысячи пользователей найдется хотя бы один, который обязательно введет 0! Даже если вы выведете яркое, написанное крупным шрифтом предупреждение, что нельзя вводить здесь число 0. Тому есть миллион причин. Пользователь мог в это время задуматься о чем-то друГлава 2 Введение в язык программирования Pascal гом, его могли в этот момент чем-то отвлечь, он мог просто не обратить внимания на ваше предупреждение или забыть о нем. В конце концов, он мог нажать не на ту клавишу! Например, цифра 9 на клавиатуре расположена рядом с цифрой 0. И, наконец, обязательно найдутся такие пользователи, которые захотят посмотреть, а что будет, если я все-таки введу ноль!
Ясно, что если в ваших программах будут встречаться такие "казусы", то вашему престижу как программиста будет нанесен невосполнимый урон, особенно если вы пишете программы на коммерческой основе, т.е. продаете их.
Это также отразится на количестве продаж вашей программы.
Таким образом, контроль за такими "не предусмотренными" действиями пользователя лежит на программисте! Есть такое понятие в программировании – писать программы, рассчитанные на "дурака" (fool-tolerance).
Поэтому любите своего пользователя, уважайте его, заботьтесь о том, чтобы ему было легко и комфортно работать с вашей программой (даже есть такое понятие дружественность программы), но пишите свои программы так, чтобы они были защищены от любых непреднамеренных, неумелых и даже "невозможных" действий пользователя.
Чаще всего такого рода ошибки возникают при вводе пользователем каких-то данных. Со способами защиты своей программы от таких непреднамеренных действий пользователя мы познакомимся позже (см. раздел 2.1.25. и 6.3.7.). Здесь я просто заострил ваше внимание на этой проблеме, чтобы вы всегда помнили об этом в процессе написания своих программ.
2.1.16 Стандартные функции с целыми аргументами Рассмотрим программу:
program functions;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var a, b, c: integer;
begin b:= abs(a);
writeln(UTF8ToConsole('Абсолютная величина числа a= '), b);
c:= sqr(b);
writeln(UTF8ToConsole('Квадрат числа b= '), c);
c:= sqr(b + b);
writeln(UTF8ToConsole('Квадрат числа (b + b)= '), c);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Оператор b:= abs(a); присваивает переменной b абсолютное значение числа a.
Под абсолютным значением числа понимается значение этого числа, если отбросить знак.
Оператор c:= sqr(b)- присваивает переменной c квадрат числа b, т.е.
b 2, sqr (от английского square – квадрат). Число в скобках называется арc гументом функции. В качестве аргумента может быть выражение, например, b2 4ac запишется на Паскале следующим образом:
Глава 2 Введение в язык программирования Pascal Как уже отмечалось, в операторах write и writeln можно использовать любые допустимые выражения, т.е. можно записывать так:
writeln('Квадрат числа (b + b)= ', sqr(b + b));
2.1.17 Операции с вещественными числами (тип real).
С вещественными числами можно выполнять различные операции. Все возможные операции иллюстрируются следующей программой:
program real_numbers;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var a, b, c: real;
begin a:= 17.3;
b:= 3.4;
writeln(UTF8ToConsole('Умножение вещественных чисел c = '), c);
writeln(UTF8ToConsole('Деление вещественных чисел c = '), c);
writeln(UTF8ToConsole('Сложение вещественных чисел c = '), c);
writeln(UTF8ToConsole('Вычитание вещественных чисел c = '), c);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
2.1.18 Форматирование вывода При выводе значений вещественного типа используется так называемое экспоненциальное представление, в котором используется степень десяти. Вы это могли видеть при выполнении предыдущего примера. Такой вид чисел на экран часто неудобен. В операторах вывода можно использовать форматирование для указания ширины поля вывода. Вид оператора вывода в этом случае будет таким:
write(переменная_1:w:d, … переменная_n:w:d);
writeln(переменная_1:w:d, … переменная_n:w:d);
где w – общая ширина поля вывода, d – количество знаков после запятой, т.е. дробной части числа. w и d должны быть константами или выражениями целого типа. Для того чтобы общая ширина поля вывода определялась автоматически, указывайте w = 0. Например:
writeln('a * b = ', c:0:2);
В этом случае на экран будет выведено a * b = 5.882000000000000Е+ 2.1.19 Одновременное использование вещественных и целых чисел.
В программе могут встречаться переменные разных типов:
program int_real;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var Глава 2 Введение в язык программирования Pascal n, k: integer;
a, b: real;
begin a:= 3.6;
n:= 4;
b:= n;
writeln(UTF8ToConsole('Вещественная переменная b= '), b);
n:= trunc(a);
writeln(UTF8ToConsole('Операция truncate n= '), n);
k:= round(a);
writeln(UTF8ToConsole('Операция round k= '), k);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
В программе мы видим запись b:= n; где вещественной переменной b присваивается значение целой переменной n. Кроме того, в таких записях как b:= n + 4.6; или b:= 3 * 7.2 + n; встречаются вещественные и целые числа, стоящие в правой части выражения. Такие записи разрешены. Компилятор автоматически преобразует выражение в правой части оператора присваивания к вещественному типу. И наоборот, присвоение вещественных значений целым переменным просто запрещены. Т.е. если написать оператор присваивания компилятор выдаст ошибку.
Для этого используются стандартные функции trunc и round. С помощью функции trunc производится преобразование вещественного числа в целое путем отбрасывания всех цифр, стоящих после десятичной точки (trunОсновные элементы языка cate – усекать), round – позволяет преобразовать вещественное число в целое путем округления (round – округлять).
2.1.20 Другие стандартные функции с вещественными аргументами Еще раз напоминаю, что аргументом функции (т.е. то, что стоит в скобках) может быть выражение. Например, 2.1.21 Булевы переменные Булевы переменные (логические переменные) – это переменные, имеющие только два значения false (ложь) и true (истина). Над булевыми переменными определены логические операции not (логическое отрицание, "НЕ"), and (логическое "И"), or (логическое "ИЛИ"), xor (исключающее "ИЛИ").
Кроме того, определены следующие операции отношения:
Глава 2 Введение в язык программирования Pascal Результатом этих операций отношения являются логические false или true.
Рассмотрим следующее выражение:
В зависимости от значения x это выражение будет либо истинным ( true), либо ложным (false).
program logic;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x: integer;
flag: boolean;
begin x:= 4;
flag:= x > 3;
writeln('flag = ', flag);
flag:= x < 3;
writeln('flag = ', flag);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Допускается размещать справа и слева от знаков отношений арифметические выражения: x + 6.5 < x + 5 такие выражения называются логическими или булевыми выражениями.
Рассмотрим программу, где используются логические функции:
program logic_1;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x: integer;
L1, L2, Result: boolean;
begin x:= 4;
L1:= x > 3;
L2:= x < 3;
writeln(UTF8ToConsole('Булева переменная L1= '), L1);
writeln(UTF8ToConsole('Булева переменная L2= '), L2);
Result := L1 AND L2;
writeln(UTF8ToConsole('L1 AND L2 равно '), Result);
Result := L1 OR L2;
writeln (UTF8ToConsole('L1 OR L2 равно '), Result);
Result := NOT Result;
writeln (UTF8ToConsole('NOT Result равно '), Result);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
2.1.22 Условные операторы.
Условные операторы – это такие операторы, с помощью которых можно изменять последовательность выполнения операторов программы.
Глава 2 Введение в язык программирования Pascal 2.1.22.1 Оператор if …. then Этот оператор имеет вид:
где оператор – любой оператор Паскаля, условие – логическое выражение.
Если это условие выполняется (т.е. это условие дает значение true), то будет выполнен оператор стоящий после слова then.
Рассмотрим пример:
Здесь записано: "Если X < 3, то вывести на экран значение X".
Оператор if…then можно представить в виде структурной схемы, с помощью которой показывается ход выполнения программы:
writeln('X= ', X:0:2, '; Y= ', Y:0:2);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
program ex2;{Вариант 2 - использование оператора if…then…else } {$mode objfpc}{$H+} uses CRT, FileUtil;
var X, Y: real;
begin writeln(UTF8ToConsole('Введите значение Х'));
readln(X);
else else writeln('X= ', X:0:2, '; Y= ', Y:0:2);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Часто бывает необходимо, чтобы выполнялись или не выполнялись группа из нескольких операторов. Для этого эти операторы объединяются в блок, в котором перед первым оператором ставится слово begin, а после последнего слово end. Все операторы между begin и end образуют так называемый составной оператор, а begin и end как бы выполняют роль скобок. Их часто так и называют – операторные скобки.
program demo; {Демонстрация применения составного оператора} {$mode objfpc}{$H+} uses CRT, FileUtil;
Глава 2 Введение в язык программирования Pascal var X: integer;
begin writeln(UTF8ToConsole ('Введите значение Х' ));
readln(X);
begin writeln(UTF8ToConsole('Выполнение программы по условию true'));
writeln('X = ', X);
{ составной оператор считается как бы одним оператором, поэтому перед else ;
не ставится} else begin writeln(UTF8ToConsole('Выполнение программы по условию false'));
writeln('X = ', X) ;
end;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Иллюстрация в общем виде: составной оператор записывается внутри служебных слов begin и end:
где S1, S2, S3, S4 - операторы Паскаля, в том числе и составные операторы, т.е. составные операторы могут быть вложены друг в друга. Схематично это выглядит так:
Составной оператор Здесь s3 и p2 также составные операторы.
Условные операторы также могут быть вложены друг в друга.
Соответствующая блок-схема приведена на рис. 2.54.
Глава 2 Введение в язык программирования Pascal Рис. 2.54. Блок-схема выполнения вложенных условных операторов 2.1.23 Операторы цикла Операторы цикла используются для организации многократного повторения выполнения одних и тех же операторов. В языке Паскаль существует три типа операторов цикла.
2.1.23.1. Оператор цикла с предусловием Этот оператор имеет вид:
где условие – булевское выражение, оператор – любой оператор Паскаля, в частности может быть и составным оператором. Слова while и do являются служебными словами, а оператор после do часто называют телом цикла. Выполняется этот оператор следующим образом: сначала вычисляется значение булевого выражения. Если это значение есть true, то выполняется оператор после слова do и снова происходит возврат к вычислению булевого выражения.
Так повторяется, пока булевое выражение имеет значение true. Как только значение булевского выражения станет false, то происходит выход из цикла, т. е. оператор после служебного слова do уже не выполняется, а будет выполОсновные элементы языка няться следующий после оператора цикла оператор.
В данном операторе вычисление выражения происходит раньше, чем будет выполняться оператор после do, поэтому он и называется оператор цикла с предусловием. Может так случиться, что оператор после do не будет выполнен вообще, если значение условия с первого раза будет false.
Структурная схема цикла с предусловием Рис. 2.55. Структурная схема цикла с предусловием 2.1.23.2. Оператор цикла с постусловием где оператор – любой оператор Паскаля, в том числе и составной, условие – булевское выражение.
repeat и until - служебные слова.
Этот оператор выполняется следующим образом: сначала выполняется оператор следующий за служебным словом repeat, затем вычисляется значение булевского выражения (условия). Если значение условия false, то происходит возврат к выполнению оператора и после этого снова вычисляется значение булевского выражения. Так повторяется до тех пор, пока значение булевского выражения false. Как только условие станет true, выполнение оператора цикла прекращается.
Глава 2 Введение в язык программирования Pascal Структурная схема оператора Рис. 2.56. Структурная схема цикла с постусловием В отличие от оператора цикла while-do здесь оператор будет выполнен хотя бы один раз, независимо от значения условий.
Предупреждение! Чтобы рассмотренные выше операторы цикла выполнялись конечное число раз, при построении цикла необходимо предусмотреть, чтобы среди выполняемых операторов обязательно был оператор, который изменял бы значение условия, таким образом, чтобы когда-нибудь значение условия принимало бы false(для оператора while-do)или true(для оператора repeat- until).
В противном случае цикл будет повторяться бесконечное число раз и программа "зациклится". Ответственность за правильное применение этих операторов цикла несет на себе программист!
Пример:
program sum_1; {Вариант 1 цикл с предусловием} {$mode objfpc}{$H+} uses CRT, FileUtil;
var x, Sum: integer;
begin Sum:= 0; // в этой переменной накапливается сумма x:= 1;
while x 100;
writeln('Sum= ',Sum);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Глава 2 Введение в язык программирования Pascal Пример: Вычислить функцию:
Напишем программу вычисления функции с использованием оператора if…then и оператора цикла while…do:
program fun_1;{Вариант 1} {$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y: integer;
begin x:=-10;
while x 0 then end;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey; end.
Напишем программу вычисления этой же функции с использованием оператора if…then…else и оператора цикла while…do:
program fun_2;{Вариант 2} {$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y: integer;
begin x:=-10;
while x 0 then end;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
В программах fun_1 и fun_2, как вы могли заметить, использовались составные операторы.
Глава 2 Введение в язык программирования Pascal program fun_3;{Вариант 3 с использованием оператора цикла с постусловием} {$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y: integer;
begin x:=-10;
repeat until x > 10;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Заметим, что в операторе цикла с постусловием, если после слова repeat используется не один, а несколько операторов, то не обязательно использовать операторные скобки begin и end, поскольку служебные слова repeat и until сами выполняют роль операторных скобок.
2.1.23.3. Оператор цикла с параметром.
Иногда заранее точно известно, сколько раз должно быть выполнено определенное действие. Для задач такого типа в языке Паскаль, имеется оператор цикла с параметром. Этот оператор имеет вид:
for переменная:= выражение 1 to выражение 2 do оператор;
где for, to, do – служебные слова; переменная- переменная целого типа, называемая индексом или параметром цикла.
Выражение 1, выражение 2 – арифметические выражения целого типа, т.е.
значения выражений должны быть целыми;
оператор – простой или составной оператор.
Для того чтобы оператор цикла выполнялся хотя бы один раз, значение выражения 1 должно быть меньше или равно значению выражения 2 (на практике значения выражения 1 всегда меньше значения выражения 2). Оператор работает следующим образом: вначале переменной (параметру цикла) присваивается значение выражения 1, затем сравнивается значение параметра цикла и значение выражения 2. Если параметр цикла меньше значения выражения 2, то выполняется оператор после слова do. Затем параметр цикла увеличивается на 1, после этого вновь сравнивается значение параметра цикла и выражение 2, если параметр цикла меньше, то вновь выполняется оператор после слова do. И так продолжается до тех пор, пока параметр цикла не станет больше выражения 2. Как только это происходит, оператор цикла заканчивается.
Пример: давайте вычислим снова значения функции Глава 2 Введение в язык программирования Pascal program fun_4; {оператор цикла с параметром for...to} {$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y: integer;
begin for x:=-10 to 10 do begin end;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
2.1.23.4. Второй вариант оператора цикла с параметром Оператор цикла с параметром может быть записан и в таком виде:
for переменная:= выражение 1 downto выражение 2 do оператор;
В этом варианте параметр цикла (переменная) после каждого повторения не увеличивается, а уменьшается на 1. Значение выражения 1 больше или равно (на практике всегда больше) значения выражения 2.
Оператор цикла заканчивается как только параметр цикла станет меньше выражения 2.
program fun_5; {оператор цикла с параметром for...downto} {$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y: integer;
begin for x:= 10 downto - 10 do begin end;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
program summa_1; {Вариант 1 используется оператор цикла for} {$mode objfpc}{$H+} Глава 2 Введение в язык программирования Pascal uses CRT, FileUtil;
var x, s: integer;
begin s:= 0; // в этой переменной накапливается сумма for x:= 1 to 10 do writeln('x= ', x, UTF8ToConsole(' сумма s= '), s);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
program summa_2;{Вариант 2 используется оператор цикла while…do} {$mode objfpc}{$H+} uses CRT, FileUtil;
var x, s: integer;
begin s:= 0; // в этой переменной накапливается сумма x:= 1;
while x ;
< Описание переменных >;
< Тело главной программы >;
С основными элементами этой структуры мы уже знакомы. Нами остались не рассмотренными,,.
Метки нужны для организации перехода на какой – либо оператор. Для этого оператор помечается меткой. Оператор перехода имеет вид:
и позволяет передать управление оператору с меткой.
Программа, содержащая метки обычно плохо читается и, как правило, является не структурированной. Вполне можно писать программы вообще не используя метки. Итак, забыли про метки и поехали дальше!
3.1.1 Процедуры и функции При разработке больших программ почти всегда появляются часто повторяющиеся фрагменты кода. Чтобы не повторять эти фрагменты в разных частях программы, их можно записать один раз, присвоить им какие-нибудь имена и использовать их в нужных местах программы. Такие именованные фрагменты кода называются подпрограммами.
Подпрограммы делятся на процедуры и функции. Текст процедуры или функции записывается в разделе описаний, после описания переменных. В дальнейшем для того, чтобы использовать эту процедуру или функцию достаточно указать ее имя. В некоторых случаях процедура (функция) использует некоторые значения, которые должны передаваться из главной программы или из других процедур (функций). Эти значения называются параметрами. Параметры указываются в заголовке процедуры (функции) в скобках. Указывается имя переменной и через двоеточие тип переменной. Если переменных одного типа несколько, то они разделяются запятыми. Параметры разных типов разделяются точкой с запятой.
Отличие функции от процедуры в том, что функция обязательно должна возвратить некоторое вычисленное значение вызывающей программе.
3.1.1.1 Структура процедуры procedure [(параметры)];
< Описание локальных переменных >;
< Описание внутренних процедур >;
< Описание внутренних функций >;
Параметры, указанные в заголовке называются формальными параметрами. Для вызова процедуры необходимо просто указать ее имя и параметры (если они имеются). Параметры, указанные при вызове процедуры называются фактическими параметрами.
3.1.1.2. Структура функции function [(параметры)]:тип функции;
< Описание локальных переменных >;
< Описание внутренних процедур >;
< Описание внутренних функций >;
В заголовке функции указывается ее имя, параметры (если они есть) и тип значения, которую функция должна возвратить. Для вызова функции необходимо указать ее имя и фактические параметры (при их наличии). Причем имя функции можно указывать в выражениях!
В теле функции должен присутствовать хотя бы один оператор, который присваивает имени функции некоторое значение. В противном случае значение функции остается неопределенным, что может привести к непредсказуемым последствиям. При вычислении выражений, имя функции замещается вычисленным значением.
В последнее время входит в моду присваивать значение внутри функции не имени функции, а системной переменной Result.
Функция или процедура может в свою очередь вызывать другие функции или процедуры, причем может вызывать и саму себя! Уровень вложенности при этом не ограничен. Хотя на практике стараются избегать слишком глубоко вложенных функций (процедур), так как это увеличивает вероятность появления трудно находимых ошибок и, кроме того, ухудшает читабельность и понимание логики работы программы.
3.1.1.3 Глобальные и локальные переменные Обычно любая программа, функция или процедура использует какие-то переменные, константы, функции и процедуры. В программе любой объект перед ее использованием должен быть описан в разделе описаний. При этом у каждой переменной, а также константы, функции или процедуры есть своя область видимости, где они могут использоваться. Если объект описан в подпрограмме, то доступ к ней из вызывающей программы невозможен. Этот объект является локальным по отношению к подпрограмме, где он описан, т.е. "не виГлава 3 Более сложные элементы языка дим" в вызывающей программе. Такие переменные, константы, функции и процедуры называются локальными. В то же время, объекты, описанные в вызывающей программе, доступны вызываемым подпрограммам, т.е. "видимы" им.
Такие объекты называются глобальными.
Рассмотрим пример, чтобы глубже понять вышесказанное:
program console_app;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x: integer; // Глобальная переменная procedure local_global; // процедура без параметров begin x:= 25; // Глобальная переменная х доступна процедуре writeln(UTF8ToConsole('Значение переменной x'));
writeln(UTF8ToConsole('внутри процедуры = '), x);
end; // конец процедуры // начало главной программы begin writeln(UTF8ToConsole('Глобальная переменная x'));
writeln(UTF8ToConsole('до вызова процедуры = '), x);
local_global; // вызов процедуры writeln(UTF8ToConsole('Глобальная переменная x'));
writeln(UTF8ToConsole('после вызова процедуры = '), x);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Как видим, процедура изменила значение глобальной переменной. Следует иметь в виду, что переменная, являющаяся локальной в данной подпрограмме, становится глобальной для всех подпрограмм низшего уровня. Рассмотрим пример:
program console_app;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x: integer; // глобальная переменная procedure local_global; // процедура без параметров var y: integer; // Локальная переменная procedure A; // Процедура внутри процедуры local_global begin y:= 100; // Внутри процедуры А переменная y является глобальной writeln(UTF8ToConsole('В процедуре А y= '), y);
end; // конец вложенной процедуры begin A; // вызов процедуры низшего уровня writeln(UTF8ToConsole('После вызова процедуры А y= '), y);
end; // конец процедуры // начало главной программы begin x:= 1;
writeln(UTF8ToConsole('Глобальная переменная x'));
writeln(UTF8ToConsole('до вызова процедуры равна '), x);
local_global; // вызов процедуры // y:=1; если убрать знак комментария, компилятор выдаст ошибку, // A; т.к. локальные объекты невидимы для главной программы writeln(UTF8ToConsole('Глобальная переменная x'));
writeln(UTF8ToConsole('после вызова процедуры равна '), x);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Переменная y является локальной в процедуре local_global, в то же время она доступна процедуре А, т.е. для нее она является глобальной.
Обратите внимание, что локальные объекты недоступны вызывающей программе. Таким образом, из главной программы нельзя вызвать процедуру А и нельзя изменить значение переменной y. Главная программа просто не знает об их существовании! Процедура local_global выступает для главной программы "черным ящиком". Для обмена данными между вызывающей программой и подпрограммой не стоит использовать глобальные переменные. Для этого используется механизм передачи параметров, о котором пойдет речь в следующем разделе.
Использование глобальных переменных может привести к трудноуловимым ошибкам, поскольку, когда подпрограмма изменяет значение глобальной переменной, главная программа об этом может и "не знать". Подпрограмма должна быть независима и самодостаточна ("черный ящик"!) в том смысле, что должна решать свою задачу исключительно "своими силами", лишь при необходимости получая от вызывающей программы данные через параметры и также через параметры передавая результаты своей работы. Если это функция, то она должна возвращать единственное значение через свое имя.
Почему локальные переменные "невидимы" вызывающей программе? Дело в том, что локальным переменным память распределяется по-другому, чем глобальным переменным. Память для глобальных переменных выделяется статически компилятором в области памяти, называемой сегментом данных или статической памятью. Глобальные переменные "живут" в статической памяти от запуска главной программы и вплоть до ее закрытия. Поэтому они доступны всем подпрограммам. Для локальных переменных создается специальная область памяти, называемая стеком. Параметры подпрограммы также размещаются в стеке. После завершения работы подпрограммы, память, отведенная для нее, автоматически освобождается и может быть распределена уже для другой подпрограммы.
Есть еще один тип переменных, которые по существу являются локальными, но память им выделяется в сегменте данных. Это так называемые статические переменные. Тот факт, что они находятся в сегменте данных означает, что такие переменные после выхода из подпрограммы не уничтожаются. Таким образом, если подпрограмма будет вызвана повторно, то значение статической переменной сохранится и ее можно будет использовать.
В Паскале статической переменной служит так называемая типизированная константа. Ее описание имеет вид:
Константа: Тип = Значение;
Отличие от обычной константы в том, что указывается тип и для таких констант выделяется память. Значение типизированной константы в подпрограмме можно изменять (только не в Delphi! Там типизированная константа является "настоящей" константой).
program project1;
{$mode objfpc}{$H+} uses CRT, FileUtil;
procedure static_var; // процедура const x: integer = 0;
begin writeln(UTF8ToConsole('До изменения x= '), x);
x:= х + 25;
writeln(UTF8ToConsole('После изменения x= '), x);
end; // конец процедуры begin writeln(UTF8ToConsole('Изменение статической переменной x'));
writeln(UTF8ToConsole('внутри процедуры после первого вызова'));
static_var;
writeln(UTF8ToConsole('Изменение статической переменной x'));
writeln(UTF8ToConsole('внутри процедуры после второго вызова'));
static_var;
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
После первого вызова процедуры значение переменной х становится равным 25. После второго вызова х=50, т.е. статическая переменная сохранила свое значение 25 после первого вызова процедуры.
Имена локальных переменных в подпрограмме могут совпадать с глобальными именами вызывающей программы. В этом случае при входе в подпрограмму доступна только локальная переменная, а глобальная становится недоступной, например:
program console_app;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x: integer; // Глобальная переменная procedure local_global; // процедура без параметров var x: integer; // Локальная переменная с тем же именем begin x:= 25;
writeln(UTF8ToConsole('Локальная переменная x= '), x);
end; // конец процедуры // начало главной программы begin x:= 1;
writeln(UTF8ToConsole('Значение глобальной переменной x));
writeln(UTF8ToConsole(' до вызова процедуры '), x);
local_global; // вызов процедуры writeln(UTF8ToConsole('Значение глобальной переменной x));
writeln(UTF8ToConsole(' после вызова процедуры '), x);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Мы видим, что значение глобальной переменной не изменилось. Локальная переменная перекрыла глобальную и оператор присваивания в процедуре присвоило значение 25 совсем другой переменной, хотя и с тем же именем х.
Таким образом, одноименные глобальные и локальные переменные - это разные переменные. Любое обращение к таким переменным в теле подпрограммы трактуется как обращение к локальным переменным, т. е. глобальные переменные в этом случае попросту недоступны.
Пример использования функции.
Вычислить значение y sin x путем разложения sin x в ряд Тейлора с точx [0,1], Вычисленное значение sin x для каждого x сравнить с "точным" значением путем применения стандартной функции Паскаля sin(x).
Напомню, что мы уже писали эту программу (см. 2.1.26), но без применения функций. Разложение sin x в ряд Тейлора имеет вид:
No_standard_sin(x).
program sinus_fun;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y, y1, dx:real;// глобальные переменные, доступны функции function No_standard_sin (x: real): real;
var eps, s, t: real; // локальные переменные, недоступны n: integer;
begin s:= x;
t:= x;
n:= 2;
eps:= 1e-7;
repeat t:= -t * sqr(x)/(n * (n + 1));
until abs(t) < eps;
No_standard_sin:= s; // возврат значения функции //Result:= s; // можно и так end;
begin x:= 0;
dx:= 0.2;
writeln(UTF8ToConsole('Значения синуса'));
writeln(UTF8ToConsole('моя функции, стандартная функции'));
while x eps then end;
writeln(UTF8ToConsole('Значение интеграла s= '), s:0:4);
end; // конец процедуры begin // начало основной программы {задаем интервал на котором вычисляется интеграл} a:= 0;
b:= pi/4;
1e-5; // заданная точность вычисления интеграла eps:= Simpson(a, b, eps); // вызов процедуры вычисления интеграла writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
3.1.1.4 Способы передачи параметров Передача параметров по значению При таком способе передачи параметров в функцию или процедуру передается копия переменной. Внутри функции или процедуры можно менять значения переданных параметров, однако в вызывающей программе значения параметров остаются неизменными.
Рассмотрим пример:
program parameters;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y: real;
n: integer;
{Объявление процедуры с параметром} procedure example(x, y: real; n: integer);
begin x:= 1.5;
end;
begin writeln('x= ', x:0:2, ' y= ', y:0:2, ' n= ', n);
example(x, y, n);
writeln('x= ', x:0:2, ' y= ', y:0:2, ' n= ', n);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
end.
Как видите, после вызова процедуры значения переменных x, y, n не изменились.
В предыдущих двух примерах мы использовали передачу параметров по значению.
Передача параметров по ссылке Другая ситуация при передаче параметров по ссылке. В этом случае изменение параметра внутри функции (процедуры) влечет за собой и изменение значения переменной в вызывающей программе. Для передачи параметра по ссылке нужно перед именем параметра в заголовке указать ключевое слово var. Рассмотрим предыдущий пример, но передадим параметры x и n по ссылке.
program parameters;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y: real;
n: integer;
{Объявление процедуры с параметром} procedure example(var x: real; y: real; var n: integer);
begin x:= 1.5;
y:= 2.8;
n:= 10;
end;
begin x:= 1;
y:= 1;
n:= 1;
writeln('x= ', x:0:2, ' y= ', y:0:2, ' n= ', n);
example(x, y, n);
writeln('x= ', x:0:2, ' y= ', y:0:2, ' n= ', n);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
Здесь уже значения переменных x и n изменились!
Передача параметров-констант Если при передаче параметров по значению внутри функции (процедуры) их значения можно изменять, то при передаче параметров как констант внутри функции или процедуры их вообще невозможно изменить. При попытке их изОбщая структура Паскаль – программы менения компилятор выдаст ошибку. Для передачи параметра как константы нужно перед именем параметра задать ключевое слово const.
program parameters;
{$mode objfpc}{$H+} uses CRT, FileUtil;
var x, y: real;
n: integer;
{Объявление процедуры с параметром} procedure example(var x: real; y: real;
begin x:= 1.5;
y:= 2.8;
{Попытка изменить параметр-константу} //n:= 10; // здесь, если убрать комментарий, компилятор укажет на ошибку end;
begin x:= 1;
y:= 1;
n:= 1;
writeln('x= ', x:0:2, ' y= ', y:0:2, ' n= ', n);
example(x, y, n);
writeln('x= ', x:0:2, ' y= ', y:0:2, ' n= ', n);
writeln(UTF8ToConsole('Нажмите любую клавишу'));
readkey;
end.
3.1.1.5 Процедуры завершения Для досрочного завершения функции или процедуры, а также основной программы применяются специальные процедуры exit и halt. Если exit выполняется в функции (процедуре), то ее выполнение немедленно прекращается, даже если не все операторы были выполнены и управление передается вызывающей программе (функции, процедуре). Далее будет выполняться следующий за вызовом этой функции (процедуры) оператор. Если exit выполняется в основной программе, то работа программы завершается и управление передается операционной системе.
Процедура halt сразу завершает работу программы и передает управление операционной системе. Чаще всего halt используют для аварийного завершения программы.
3.2. Еще раз о типах данных До сих пор при составлении программ мы использовали всего три типа данных – целый, вещественный и логический, к тому же использовали не все их возможности. Однако в Паскале имеется очень широкий набор типов данных, причем язык предусматривает создание пользовательских типов данных. Здесь мы дадим классификацию типов данных в Паскале и рассмотрим некоторые из них.
3.2.1 Классификация типов данных Все типы в Паскале подразделяются на стандартные и пользовательские типы. Пользовательские типы создаются на основе стандартных. При описании пользовательских типов используется ключевое слово type.
К стандартным типам относятся:
целый;
вещественный;
символьный;
логический.
Кроме того, все типы можно разделить на категории:
простые;
строковые;
даты и времени;
структурированные;
указатели;
объекты;
классы;
варианты.
Простые типы, в свою очередь, делятся на порядковые и вещественные.
Порядковый тип характеризуется тем, что каждому его значению можно поставить в соответствие целое число – его порядковый номер в совокупности значений. Например, для целого типа само значение числа является его порядковым номером. Для логического типа значению true соответствует 1, а значению false соответствует 0.
3.2.1.1 Целый тип Кроме уже знакомого нам типа integer, в Паскале имеются и другие целочисленные типы. Они различаются диапазоном представления целого числа в памяти компьютера (размером выделяемой памяти) и способом представления числа (со знаком или без знака). В таблице 3.1 приведены важнейшие характеристики целочисленных типов данных (напоминаю, что мы рассматриваем язык применительно к компилятору Free Pascal).
Integer -2147483648..+2147483647 LongInt -2147483648..+2147483647 Как видите, количество целочисленных типов достаточно велико, однако наиболее часто используемыми являются типы integer и cardinal. Эти два типа обеспечивают максимальную производительность на 32-битных платформах. Заметим, что указанный диапазон, соответствующий LongInt, верен только для режимов компиляции OBJFPC и DELPHI. В остальных случаях (в т.ч. и по умолчанию) Integer соответствует SmallInt (2 байта).
3.2.1.2. Интервальный тип Интервальный тип определяется на основе порядкового типа и позволяет ограничить диапазон допустимых значений в виде некоторого интервала вида:
Минимальное значение..Максимальное значение При этом символы ".." между минимальным и максимальным значениями считаются одним символом, т.е. пробелы между этими точками недопустимы.
Естественно, максимальное значение должно быть больше минимального. Описание переменной интервального типа имеет вид:
var : Минимальное значение..Максимальное значение;
Например:
var day: 1..31;
3.2.1.3. Перечислимый тип В этом типе, как следует из названия, значения задаются простым перечислением через запятую, причем весь список заключается в скобки, например:
var education: (student, bachelor, graduate, doctor);
course: (first, second, third, fourth, fifth);
Порядковый номер элемента списка начинается с 0, таким образом student имеет порядковый номер 0, bachelor порядковый номер 1, graduate номер 2, doctor номер 3.
3.2.1.4. Множества Множество в Object Pascal представляют собой группу элементов, с которыми можно сравнивать другие элементы с целью определения входят эти элементы в состав множества или нет. Множества предоставляют программисту возможность достаточно просто представить коллекцию символов, чисел или других перечислимых типов данных. Объявление множества имеет вид:
Здесь num – множество, состоящее из десяти целых чисел.
num1 – множество состоящее из целых чисел от 20 до 100. Значением переменной типа множество является набор значений или интервалов порядкового типа, заключенных в квадратные скобки. Такая форма определения множества называется конструктором множества.
Присвоение значения переменным:
num1:=[21..75, 81, 82..95];
Чтобы определить принадлежит ли переменная множеству, используется оператор in:
if 81 in num1 then Можно множество заранее не определять, а сразу использовать конструктор множества в операторе in:
if range in [1..50, 75..100] then 3.2.1.5. Логический тип Логический тип имеет только два значения true (истина, да) и false (ложь, нет). Причем, логическому true соответствует порядковое число 1, а false 0. Таким образом true "больше" false!
Возможные логические типы представлены в таблице 3.2.
Рекомендуется использовать тип boolean, остальные типы введены для совместимости с другими языками.
3.2.1.6. Вещественный тип Вещественные числа представляются в памяти компьютера в форме с плавающей точкой и позволяют производить вычисления с большой точностью и значительно большим диапазоном значений чисел, в том числе и дробных.
Основные вещественные типы представлены в таблице 3.3.
Максимальную производительность и точность обеспечивает тип Extended. Тип Currency минимизирует ошибки округления и его целесообразно применять для денежных расчетов. Тип Comp на самом деле целое 64-х разрядное число, но оно обрабатывается так же как и вещественные типы, т.е. в выражениях полностью совместим с вещественными типами.
3.2.1.7. Указатели Указатель это переменная особенного типа, в которой содержатся не сами данные, а адрес памяти, где эти данные хранятся. Точнее адрес первого байта этих данных. Таким образом, указатель как бы ссылается на данные посредством своего значения (адреса). Примером указателя в обычной жизни может служить номер телефона. Само по себе это число ничего не значит, но если вы наберете этот номер в своем мобильном телефоне, вы "попадете" к нужному абоненту.
Указатели бывают типизированные и нетипизированные. При объявлении типизированного указателя всегда указывается тип данных, на которые ссылается указатель. Описание указателя имеет вид:
var имя переменной: ^тип;
Например:
var px: ^integer; // указатель на данные целого типа py: ^real; // указатель на данные вещественного типа pname: ^string; // указатель на данные типа строка pphone: ^string[7];
Компилятор строго следит за правильностью использования указателя и типом данных, на которые ссылается этот указатель.
Для нетипизированных указателей тип данных не указывается. В этом случае программист сам должен заботиться о правильном использовании указателя и типов данных. При его описании используется ключевое слово pointer.
Пример описания нетипизированного указателя:
var p: pointer;
Более подробно мы будем изучать указатели в главе 4.
В дальнейшем мы рассмотрим еще типы данных, в частности, в следующем разделе познакомимся с типами данных, позволяющих обрабатывать символьную информацию.
3.3. Обработка символьной информации в Паскале 3.3.1 Символьные и строковые типы данных.
Первые применения ЭВМ были в основном для решения так называемых вычислительных задач, т.е. задач возникающих в математике, в научно – технических задачах, где требуется решение различных уравнений, вычисление значений функций и т.д. Но применение компьютеров для вычислительных задач составляет всего 20 – 25% по сравнению с их применением в других областях. К таким задачам относятся задачи, возникающие в лингвистике, логике, 3.3Обработка символьной информации в Паскале психологии, теории игр и т.д.
Компьютеры широко применяются для набора различных текстов и документов, перевода текстов. Компьютеры сочиняют музыку, пишут стихи, играют в шахматы. Конечно, при решении таких задач вычисления производятся, но не в таком объеме, как при решении вычислительных задач. В основном в нечисловых задачах компьютер оперирует с символьной информацией.
Необходимо понимать, что вся информация, хранящаяся в памяти компьютера, представлена в виде двоичных чисел. Все дело в том, что под этими двоичными числами понимается, действительно ли это какие-то числа или чтолибо другое. Так вот под "другое" имеются в виду символы или совокупность символов. Т.е. каждый символ кодируется в виде двоичных чисел. Только обрабатываются эти числа совершенно по-другому. Программист знает, когда он работает с числами, когда с символами и поэтому предусматривает для каждого случая соответствующие способы работы с этими числами. А в памяти компьютера двоичное представление символа или группы символов может совпадать с каким-нибудь "настоящим" числом.
Примечательно, что возможность применения компьютеров для решения нечисловых задач понимали еще тогда, когда и компьютеров-то вообще не было! Вот что писала знаменитая Ада Лавлейс еще в 1843 году: "Многие не сведущие в математике люди думают, что поскольку назначение аналитической машины Бэббиджа – выдавать результаты в численном виде, то природа происходящих в ней процессов должна быть арифметической и численной, а не алгебраической и аналитической. Но они ошибаются. Машина может упорядочивать и комбинировать числовые значения так же, как и буквы или любые другие символы общего характера. В сущности, при выполнении соответствующих условий она могла бы выдавать результаты и в алгебраическом виде".
В 1963 г. американская организация по стандартизации American Standards Association (ASA) предложила для представления символов, т.е. цифр, букв и других знаков специальный семибитный код, который стал называться кодовой таблицей ASCII (American Standard Code for Information Interchange). Номер, который символ имеет в таблице ASCII, называется кодом этого символа. Символ можно представить, указав его в кавычках, а можно использовать значок #, за которым следует код символа. Например, буква 'А', в таблице ASCII имеет номер 65, т е. его код равен 65, тогда можно указать # 65 и это будет означать букву 'А'.
Однако эта кодовая таблица содержала кроме цифр и знаков только буквы английского алфавита. Поэтому был принят стандарт на 8-битную таблицу ASCII, в которой первые 128 символов оставались те же, что и в 7-битной таблице, а символы с 128 по 255 отводились для не английских символов. Позднее Microsoft расширила таблицу ASCII и она была переименована и стала называться ANSI (American National Standards Institute). В таблице 3.4. приведена первая половина (с кодами 0…127) этого стандарта.
Как мы видим, первая половина таблицы содержит все буквы латинского алфавита, цифры от 0 до 9, а также все наиболее употребимые знаки, такие как знак +, -, /, *, скобки и т.д.
Вторая половина символов с кодами 128…255 меняется для различных национальных алфавитов. С появлением национальных локализаций для второй половины таблицы ASCII было введено понятие «кодовая страница» (code page, CP). Для кодирования русских букв в MS DOS стали применять кодировку CP866, ранее известную как альтернативная кодировка ВЦ Академии Наук СССР.
В Windows для представления кириллицы используется кодовая страница CP-1251. Стандартные Windows-шрифты Arial Cyr, Courier New Cyr и Times New Roman Cyr для представления символов кириллицы (без букв '' и 'Ё') используют последние 64 кода (от 192 до 256): 'А'…'Я' кодируются значениями 192…223, 'а'…'я' – 224…255.
А в консоли Windows используется кодировка CP866. Этим и объясняются проблемы при выводе русских букв на экран в консольных приложениях.
3.3Обработка символьной информации в Паскале Кодировка символов в соответствии со стандартом ANSI Существуют и другие стандарты кодировки символов. В частности, для представления букв некоторых языков, таких как китайский, японский, корейский и др. 8-ми разрядов не хватает. Поэтому разработан специальный стандарт Unicode.
Юникод, или Уникод (Unicode) — стандарт кодирования символов, позволяющий представить знаки практически всех письменных языков.
Стандарт предложен в 1991 году некоммерческой организацией «Консорциум Юникода» (Unicode Consortium, Unicode Inc.). Применение этого стандарта позволяет закодировать очень большое число символов из разных письменностей: в документах Unicode могут соседствовать китайские иероглифы, математические символы, буквы греческого алфавита, латиницы и кириллицы, при этом становятся ненужными кодовые страницы.
Стандарт состоит из двух основных разделов: универсальный набор символов (UCS, Universal Character Set) и семейство кодировок (UTF, Unicode Transformation Format).
Универсальный набор символов задат однозначное соответствие символов кодам — элементам кодового пространства, представляющим неотрицательные целые числа.
Семейство кодировок определяет машинное представление последовательности кодов UCS.
Коды в стандарте Юникод разделены на несколько областей. Область с кодами от U+0000 до U+007F содержит символы набора ASCII с соответствующими кодами. Далее расположены области знаков различных письменностей, знаки пунктуации и технические символы. Часть кодов зарезервирована для использования в будущем.
В Lazarus по умолчанию используется кодировка UTF-8. В UTF-8 все символы разделены на несколько групп. Символы с кодами менее 128 кодируются одним байтом, первый бит которого равен нулю, а последующие 7 бит в точности соответствуют первым 128 символам 7-битной таблицы ASCII, следующие 1920 символов – кодируются двумя байтами. Последующие символы кодируются тремя и четырьмя байтами.
Для нас важным является тот факт, что символы кириллицы кодируются в UTF-8 в точности двумя байтами.