Федеральное агентство по образованию Государственное образовательное учреждение высшего профессионального образования Московский государственный институт электроники и математики (технический университет) Кафедра «Управление и информатика в технических системах» Алгоритмический язык Паскаль Учебное пособие по дисциплине «Программирование и основы алгоритмизации» Москва 2010 г. Составитель ст. преп. В.Г. Кулаков Учебное пособие по дисциплине «Программирование и основы алгоритмизации» предназначено для студентов первого курса дневного отделения. Основной целью пособия является освоение студентами правил элементарного программирования на языке Паскаль. Учебное пособие составлено в соответствии с программой и планом для специальности «Управление и информатика в технических системах» - 220100. УДК 004.451.9 Алгоритмический язык Паскаль. Учебное пособие по дисциплине «Программирование и основы алгоритмизации» / Моск. гос. ин-т электроники и математики; Сост. В.Г. Кулаков. М., 2010, 41 с. Библиогр.: 6 назв. 2 Содержание Стр. 1. Язык программирования Паскаль 2. Описание языка 3. Основные символы 4. Элементарные конструкции 5. Концепция типа данных 6. Стандартные типы данных 7. Константы 8. Перечисляемый тип данных 9. Интервальный тип данных 10. Переменные 11. Структура программы 12. Выражения 13. Операторы 14. Структурированные типы данных 15. Процедуры и функции 16. Стандартные математические функции 17. Рекурсия 18. Операторы выхода 19. Модули 20. Множества 21. Записи 22. Файлы 23. Последовательный и прямой доступ к данным 24. Указатели 25. Динамические переменные 26. Подпрограммы для работы в графическом режиме 4 4 5 5 6 7 9 10 10 11 11 12 12 18 21 23 25 25 26 27 28 29 33 35 35 37 Список использованной литературы 40 3 1. Язык программирования Паскаль Язык Паскаль разработан Никлаусом Виртом в 1970 году как язык для обучения процедурному программированию. Название языку дано в честь выдающегося французского ученого и философа Блеза Паскаля, а в качестве прототипа был использован алгоритмический язык Алгол-68. Огромную роль в массовом распространении языка Паскаль сыграла компания Borland International, которая создала Turbo-среду для разработки программного обеспечения на персональных компьютерах. Turbo Pascal работал под управлением операционных систем CP/M и MS-DOS на компьютерах с процессорами Intel серии x86. Первая версия языка Turbo Pascal была выпущена в 1983 г. В настоящее время язык Паскаль продолжает использоваться с целью обучения основам алгоритмизации и программирования. Имеется множество различных компиляторов, предназначенных для работы под управлением операционных систем Windows, Unix и Linux. 2. Описание языка Описание любого языка программирования должно включать описания символов, элементарных конструкций, выражений и операторов. Описание символов заключается в перечислении допустимых символов языка. Под описанием элементарных конструкций понимают правила их образования. Описание выражений – это правила образования любых выражений, имеющих смысл в данном языке. Описание операторов состоит из рассмотрения всех типов операторов, допустимых в языке. Описание каждого элемента языка задается его синтаксисом и семантикой. Синтаксические определения устанавливают правила построения элементов языка. Семантика определяет смысл и правила использования тех элементов языка, для которых были даны синтаксические определения. Символы языка – это основные неделимые знаки, в терминах которых пишутся все тексты на языке. Элементарные конструкции – это минимальные единицы языка, имеющие самостоятельный смысл. Они образуются из основных символов языка. Выражение в алгоритмическом языке состоит из элементарных конструкций и символов, оно задает правило вычисления некоторого значения. Оператор задает полное описание некоторого действия, которое необходимо выполнить. Для описания сложного действия может потребоваться группа операторов. В этом случае операторы объединяются в составной оператор или блок. Действия, заданные операторами, выполняются над данными. Предложения алгоритмического языка, в которых даются сведения о типах данных, называются описаниями или неисполняемыми операторами. Объединенная единым алгоритмом совокупность описаний и операторов образует программу на алгоритмическом языке. 4 3. Основные символы Основные символы языка – буквы, цифры и специальные символы составляют его алфавит. Язык Паскаль включает следующий набор основных символов: 1) латинские буквы; 2) арабские цифры; 3) пробел; 4) подчеркивание; 5) знаки операций; 6) ограничители; 7) спецификаторы; 8) служебные слова. 4. Элементарные конструкции Элементарные конструкции языка Паскаль включают в себя имена, числа и строки. Имена (идентификаторы) присваивают называния элементам программы – константам, меткам, типам, переменным, процедурам, функциям, модулям и объектам. Имя – это последовательность букв и цифр, начинающаяся с буквы. В именах может использоваться подчеркивание. Имя может содержать произвольное количество символов, но значащими являются 63 символа. В отличие от компилятора языка Си, компилятор Паскаля не различает строчные и прописные буквы. Не разрешается в языке Паскаль использовать в качестве имен служебные слова и стандартные имена, которыми названы стандартные константы, типы, процедуры, функции и файлы. Примеры имен: b12 SIGMA gamma I80_86 Числа в языке Паскаль обычно записываются в десятичной системе счисления. Они могут быть целыми и действительными. Положительный знак числа может быть опущен. Целые числа записываются в форме без десятичной точки, например: 217 -45 Действительные числа записываются в форме с десятичной точкой или в форме с использованием десятичного порядка, который изображается буквой Е: 38.7 -0.019 5Е12 73.1Е-16 5 Паскаль допускает запись целых чисел в шестнадцатеричной системе счисления: $40 $ABC0 Строки в языке Паскаль – это последовательность символов, записанная между апострофами. Примеры строк: 'STRING' 'ПРОГРАММА' Строка может содержать ноль и более символов из расширенного набора символов кода ASCII. Строка, ничего не содержащая между апострофами, называется нулевой или пустой. Два последовательных апострофа в строке символов обозначают один символ – апостроф. 5. Концепция типа данных В математике принято классифицировать переменные в соответствии с некоторыми важными характеристиками. Производится строгое разграничение между вещественными, комплексными и логическими переменными, между переменными, представляющими отдельные значения и множество значений и так далее. При обработке данных на ЭВМ такая классификация еще более важна. В любом алгоритмическом языке каждая константа, переменная, выражение или функция бывают определенного типа. В языке Паскаль существует правило: тип явно задается в описании переменной или функции, которое предшествует их использованию. Концепция типа языка Паскаль имеет следующие основные свойства: любой тип данных определяет множество значений, к которому принадлежит константа, которые может принимать переменная или выражение, или вырабатывать операция или функция; тип значения, задаваемого константой, переменной или выражением, можно определить по их виду или описанию; каждая операция или функция требует аргументов фиксированного типа и выдает результат фиксированного типа. Транслятор использует информацию о типах для проверки вычислимости и правильности различных конструкций. Тип определяет: возможные значения переменных, констант, функций, выражений, принадлежащих к данному типу; внутреннюю форму представления данных в ЭВМ; операции и функции, которые могут выполняться над величинами, принадлежащими к данному типу. Обязательное описание типа приводит к избыточности в тексте программ, но такая избыточность является важным вспомогательным средством разработки программ и рассматривается как необходимое свойство современных 6 алгоритмических языков высокого уровня. В языке Паскаль существуют скалярные и структурированные типы данных. К скалярным относятся стандартные типы и типы, определяемые пользователем. Стандартные типы включают целые, действительные, символьный, логические и адресный типы. Типы, определяемые пользователем: перечисляемый и интервальный. Структурированные типы имеют четыре разновидности: массивы, множества, записи и файлы. В языке Паскаль введены понятия эквивалентности и совместимости типов. Два типа Т1 и Т2 являются эквивалентными, если Т1 и Т2 представляют собой одно и то же имя типа или тип Т2 описан с использованием типа Т1 с помощью равенства. Менее строгие ограничения определены совместимостью типов. Например, типы являются совместимыми, если: они эквивалентны; являются оба либо целыми, либо действительными; один тип – интервальный, другой – его базовый; оба интервальные с общим базовым; один тип – строковый, другой – символьный. Ограничения на совместимость типов можно обойти с помощью приведения типов. Приведение типов позволяет рассматривать одну и ту же величину в памяти ЭВМ как принадлежащую разным типам. Для этого используется конструкция Имя_Типа(переменная или значение). Например, Integer('Z') преобразует код символа Z в целое число. 6. Стандартные типы данных К стандартным относятся целые, действительные, логические, символьный и адресный типы. Целые типы определяют константы, переменные и функции, значения которых реализуются множеством целых чисел, допустимых в данной ЭВМ. Целые типы данных перечислены в таблице 1. Таблица 1. Целые типы данных Тип Диапазон значений Shortint Integer Longint Byte Word Требуемая память, байт 1 2 4 1 2 -128 … 127 -32768 … 32767 -2147483648 … 2147483647 0 … 255 0 … 65535 7 Над целыми операндами можно выполнять следующие арифметические операции: + – сложение, – вычитание, * – умножение, div – деление, mod – получение остатка от деления. Результат арифметической операции над целыми операндами есть величина целого типа. Операции отношения, примененные к целым операндам, дают результат логического типа TRUE (истина) или FALSE (ложь). В языке Паскаль имеются следующие операции отношения: = – равенство, <> – неравенство, >= – больше или равно, <= – меньше или равно, > – больше, < – меньше. Действительные типы определяет те данные, которые реализуются подмножеством действительных чисел, допустимых в данной ЭВМ. Действительные типы данных перечислены в таблице 2. Таблица 2. Действительные типы данных Тип Диапазон значений Real Single Double Количество цифр мантиссы 11 7 15 2.9e-39 … 1.7e+38 1.5e-45 … 3.4e+38 5.0e-324 … 1.7e+308 Требуемая память, байт 6 4 8 Над действительными операндами можно выполнять следующие арифметические операции, дающие действительный результат: сложение, вычитание, умножение, деление. К величинам действительного типа применимы все операции отношения, дающие булевский результат. Один из операндов, участвующих в этих операциях, может быть целым. Логический тип (Boolean) определяет данные, которые могут принимать логические значения TRUE и FALSE. К булевским операндам применимы логические операции not, and, or и xor. Логический тип определен таким образом, что FALSE < TRUE. Это позволяет применять к булевским операндам все операции отношения. Символьный тип (Char) определяет упорядоченную совокупность символов, допустимых в данной ЭВМ. Значение символьной переменной или константы – это один символ из допустимого набора. 8 Символьная константа может записываться в тексте программы тремя способами: как один символ, заключенный в апострофы (например, 'A'); с помощью конструкции вида #K, где K – код соответствующего символа, при этом значение K должно находиться в пределах 0 … 255; с помощью конструкции вида ^C, где C – код соответствующего управляющего символа, при этом значение C должно быть на 64 больше кода управляющего символа. К величинам символьного типа применимы все операции отношения. Адресный тип (Pointer) определяет переменные, которые могут содержать значения адресов данных. Для хранения адреса требуются два слова (4 байта), одно из них определяет сегмент, второе – смещение. Для получения значения адреса какой-либо переменной введена унарная операция @. 7. Константы Константа – это идентификатор, отмечающий значение, которое не может изменяться. Тип констант в языке Паскаль определяется по их виду. Константы целого типа – это целые числа; константы действительного типа – действительные числа; логические константы – логические значения TRUE и FALSE; символьные константы – строки длиной в один символ. Язык Паскаль допускает использовать синонимы для обозначения констант. В этом случае текст программы содержит раздел описания констант, который размещается в программе или подпрограмме перед первым словом begin и начинается с зарезервированного слова const. Объявления констант имеют следующий формат: идентификатор = значение; В стандартном Паскале допускается использовать только простые константы, например 100 или 'A'. Турбо Паскаль позволяет использовать выражения-константы. Выражение-константа представляет собой выражение, которое может вычисляться компилятором без необходимости выполнения программы. Приведем примеры выражений-констант: 256 - 1 (2.5 + 1) / (2.5 - 1) 'Borland' + ' ' + 'Pascal' Приведем некоторые примеры использования выражений в описаниях констант: const Min = 0; Max = 100; Center = (Max - Min) div 2; Message = 'Out of memory'; ErrStr = 'Error:' + Message + '.'; 9 8. Перечисляемый тип данных Перечисляемый тип представляет собой упорядоченную последовательность констант. Имена отдельных констант отделяются друг от друга запятыми, а вся совокупность констант заключается в круглые скобки. Программист объединяет в одну группу в соответствии с каким-либо признаком совокупность значений, составляющих перечисляемый тип. Например, перечисляемый тип Rainbow (радуга) объединяет скалярные значения RED, ORANGE, YELLOW, GREEN, LIGHT_BLUE, BLUE, VIOLET. Перечисляемый тип Traffic_Light (светофор) объединяет значения RED, YELLOW, GREEN. Перечисляемый тип описывается в разделе описания типов, который начинается со служебного слова type, например: type Rainbow = (RED,ORANGE,YELLOW,GREEN,LIGHT_BLUE,BLUE,VIOLET); Упорядоченная последовательность значений, составляющих перечисляемый тип, автоматически нумеруется, начиная с нуля. Каждое значение является константой и может принадлежать только одному из перечисляемых типов, заданных в программе. Например, перечисляемый тип Traffic_Light не может быть определен в одной программе с типом Rainbow, так как оба типа содержат одинаковые константы. Описание переменных, которые объявлены в разделе описания типов, производится с помощью имен типов. Например: type Traffic_Light = (RED, YELLOW, GREEN); var Section: Traffic_Light; Это означает, что переменная Section может принимать значения RED, YELLOW или GREEN. К переменным перечисляемого типа может быть применим оператор присваивания: Section:= YELLOW; 9. Интервальный тип данных Отрезок скалярного (целочисленного или символьного) типа может быть определен как интервальный тип. Отрезок задается константами, указывающими минимальное и максимальное значения и разделенными двумя точками. Константы могут принадлежать к целому, символьному, логическому или перечисляемому типам. Скалярный тип, на котором строится отрезок, называется базовым типом. Пример: type ABC = ’A’..’Z’; Digits = ’0’..’9’; Минимальное и максимальное значения называются нижней и верхней границами отрезка. Нижняя граница должна быть меньше верхней. Над переменными, относящимися к интервальному типу, могут выполняться все операции и применяться все стандартные функции, которые допустимы для соответствующего базового типа. 10 При использовании интервальных типов в программе может осуществляться контроль за тем, чтобы значения переменных не выходили за границы, введенные в описании типа. 10. Переменные Переменная – это величина, которая может изменять свое значение во время выполнения программы. При описании переменной необходимо указать ее тип. Тип переменной описывает набор значений, которые она может принимать, и действия, которые могут быть над ней выполнены. Тип переменных определяется пользователем в разделе описания переменных, который размещается в программе или подпрограмме после раздела описания констант и перед первым словом begin. Раздел описания переменных начинается с зарезервированного слова var. Для описания переменных используется следующий формат: список переменных : тип; Список содержит идентификаторы однотипных переменных, разделенные запятыми. Пример описания переменных: var F, G: Real; I, J, K: Integer; C: Char; В откомпилированной программе для всех переменных отведено место в памяти, и всем переменным присвоены нулевые значения. Для задания начальных значений переменным (инициализации переменных) Паскаль позволяет присваивать начальные значения переменным одновременно с их описанием. Для этого используется конструкция имя переменной: тип = значение; которая должна быть размещена в разделе описания констант, например: const Weight: real = 0.4; 11. Структура программы Программа на языке Паскаль состоит из заголовка, разделов описаний и раздела операторов. Заголовок программы содержит имя программы, например: Program PRIM; Описания могут включать в себя раздел подключаемых библиотек (модулей), раздел описания меток, раздел описания констант, раздел описания типов, раздел описания переменных, раздел описания процедур и функций. Раздел описания модулей определяется служебным словом USES и содержит имена подключаемых модулей (библиотек). Раздел описания модулей должен быть первым среди разделов описаний. Имена модулей отделяются друг от друга запятыми: uses CRT, Graph; 11 Любой оператор в программе может быть помечен меткой. В качестве метки используются произвольные целые без знака, содержащие не более четырех цифр, либо имена. Метка ставится перед оператором и отделяется от него двоеточием. Все метки, используемые в программе, должны быть перечислены в разделе описания меток, например: label 3, 471, 29, Quit; Описание констант позволяет использовать имена как синонимы констант, их необходимо определить в разделе описаний констант: const K= 1024; MAX= 16384; В разделе описания переменных необходимо определить тип всех переменных, используемых в программе: var P,Q,R: integer; A,B: char; F1,F2: boolean; Описание типов, процедур и функций будет рассмотрено ниже. Отдельные разделы описаний могут отсутствовать, но следует помнить, что должны быть обязательно описаны все компоненты программы. Раздел операторов представляет собой составной оператор, который содержит между служебными словами begin и end последовательность операторов. Операторы отделяются друг от друга точкой с запятой. Текст программы заканчивается точкой. Кроме описаний и операторов программа может содержать комментарии, которые представляют собой произвольную последовательность символов, расположенную между открывающей фигурной скобкой и закрывающей фигурной скобкой. 12. Выражения Выражение состоит из констант, переменных, указателей функций, знаков операций и скобок. Выражение задает правило вычисления некоторого значения. Порядок вычисления определяется старшинством (приоритетом) содержащихся в нем операций. В языке Паскаль принят следующий приоритет операций: 1) унарная операция not, унарный минус, взятие адреса (@); 2) операции типа умножения (*, /, div, mod, and, shl, shr); 3) операции типа сложения (+, -, or, xor); 4) операции отношения (=, <>, <, >, <=, >=, in, {}). Выражения могут состоять из более простых выражений. Выражения входят в состав операторов языка Паскаль, а также могут быть аргументами встроенных функций. 13. Операторы Оператором называют специальную совокупность служебных слов, идентификаторов и специальных знаков выполняющих определенные действия. Операторы отделяются друг от друга точкой с запятой. 12 Оператор Паскаля состоит из выражений. Выражения оператора могут состоять из операндов и операций. Обычно в выражениях выполняется сравнение либо арифметические, логические или булевские операции. Оператор присваивания состоит из двоеточия и знака равенства: := Справа от оператора записывают выражение, слева указывают имя переменной, которой присваивается значение выражения: имя:= выражение; Примеры: x:=1; a:=5.02; b:=32*a+Sin(x); S:='Иван Иваныч'; Тип переменной и тип выражения должны совпадать кроме случая, когда выражение относится к целому типу, а переменная – к действительному. При этом происходит преобразование значения выражения к действительному типу. Составной оператор начинается с ключевого begin, за которым следуют операторы языка Паскаль, и заканчивается ключевым словом end: begin операторы end; Составной оператор объединяет операторы в группу. Этим оператором начинается и заканчивается раздел выполнения основной программы или подпрограммы. После последнего оператора end основной программы ставится точка. Для ввода исходных данных используются операторы ввода: Read(A1, A2, … AK); ReadLn(A1, A2, … AK); ReadLn; Первый из них реализует чтение К значений исходных данных и присваивание этих значений переменным А1, А2, …, АК. Второй оператор выполняет чтение К значений исходных данных, пропуск остальных значений до начала следующей строки, присваивание считанных значений переменным А1, А2, …, АК. Третий оператор выполняет пропуск строки данных. При вводе исходных данных происходит преобразование из внешней формы представления во внутреннюю, определяемую типом переменных. Переменные, образующие список ввода, могут принадлежать к целому, действительному или символьному типам. Чтение данных логического типа в языке Паскаль не предусмотрено. Операторы ввода при чтении значений переменных целого и действительного типа пропускает пробелы, предшествующие числу. В то же время эти операторы не пропускают пробелов, предшествующих значениям символьных переменных, так как пробелы являются равноправными символами строк. Пример записи операторов ввода: var V, S: Real; W, J: Integer; C, D: Char; 13 ... Read(V, S, W, J); Read(C, D); Значения исходных данных могут отделяться друг от друга пробелами и нажатием клавиш табуляции и Enter. Для вывода результатов работы программы на экран используются операторы вывода: Write(A1, A2,… AK); WriteLn(A1, A2,… AK); WriteLn; Первый из этих операторов реализует вывод значений переменных А1, А2, …, АК в строку экрана. Второй оператор выполняет вывод значений переменных А1, А2, …, АК и переход к началу следующей строки. Третий оператор выполняет пропуск строки и переход к началу следующей строки. Переменные, составляющие список вывода, могут относиться к целому, действительному, символьному или булевскому типам. В качестве элемента списка вывода кроме имен переменных могут использоваться выражения и строки. Вывод каждого значения в строку экрана происходит в соответствии с шириной поля вывода, определяемой конкретной реализацией языка. Форма представления значений в поле вывода соответствует типу переменных. Оператор вывода позволяет задать ширину поля вывода для каждого элемента списка вывода. В этом случае элемент списка вывода имеет вид А:К, где А – выражение или строка, К – выражение либо константа целого типа. Если выводимое значение занимает в поле вывода меньше позиций, чем К, то перед этим значением располагаются пробелы. Если выводимое значение не помещается в ширину поля К, то для этого значения будет отведено необходимое количество позиций. Для величин действительного типа элемент списка вывода может иметь вид А:К:М, где А – переменная или выражение действительного типа, К – ширина поля вывода, М – число цифр дробной части выводимого значения. К и М – выражения или константы целого типа. В этом случае действительные значения выводятся в форме десятичного числа с фиксированной точкой. Пример записи операторов вывода: var A, B: real; P, Q: integer; ... writeln(A, B:10:2); writeln(P, Q:8); Пример простой программы, которая запрашивает у пользователя три числа, вычисляет сумму введенных чисел и выводит полученный результат на экран: PROGRAM SUM; var A,B,C,S: real; begin read(A,B,C); S:= A+B+C; writeln('S=', S:8:3) end. 14 Битовая арифметика введена в Паскаль для обеспечения возможности работы с двоичными разрядами (битами). Операции битовой арифметики применимы только к целым типам. Первая группа битовых операций – логические операции not (отрицание), and (И), or (ИЛИ) и xor (исключающее ИЛИ). Операция not является унарной, она изменяет каждый разряд целого числа на обратный. Операции and, or и xor – бинарные, операнды этих операций – целые величины одинаковой длины. Операции выполняются поочередно над всеми двоичными разрядами операндов. Вторая группа операций – это операции сдвига влево shl и вправо shr: I shl N I shr N Эти операции сдвигают двоичную последовательность значения I влево или вправо на N двоичных разрядов. При этом биты, уходящие за пределы разрядной сетки, теряются, а освободившиеся двоичные разряды заполняются нулями. При сдвиге вправо отрицательных значений освободившиеся разряды заполняются единицами. Условный оператор включает в себя операторы, которые выполняются или не выполняются в зависимости от записанного в операторе условия. Оператор имеет вид: If условие Then оператор1 Else оператор2; Условие – выражение логического типа. Оператор1 выполняется, если условие верно (TRUE); оператор2 выполняется, если условие не верно (FALSE). В условном операторе может отсутствовать блок Else т. е. условный оператор может иметь вид: If условие Then оператор; Поскольку операции сравнения имеют низший приоритет, то при проверке нескольких условий эти условия заключаются в скобки. Условный оператор может применяться для идентификации объекта по определенным признакам составляющих его элементов. Если объектом является треугольник, то элементами могут быть три его угла a, b и c: if (a>90) or (b>90) or (c>90) then writeln('Треугольник - тупоугольный'); if (a<90) and (b <90) and (c<90) then writeln('Треугольник - остроугольный'); В случае зависимых событий могут применяться вложенные условные операторы. Во вложенных условных операторах служебное слово else относится к ближайшей конструкции If. Оператор цикла с параметром применяется при выполнении расчетов или других действий, повторяющихся определенное количество раз. Оператор для цикла с инкрементом параметра имеет вид: For i:= N1 To N2 Do оператор; Оператор для цикла с декрементом имеет вид: For i:= N1 DownTo N2 Do оператор; Здесь i – параметр цикла, N1– начальное значение параметр, N2 – конечное значение. N1 и N2 могут быть константами, переменными или выражениями. 15 Цикл с инкрементом выполняется при условии N1 <= N2. Значение параметра i возрастает с шагом 1 от N1 до N2. Цикл с декрементом выполняется при условии N1 >= N2. Значение параметра i убывает с шагом 1 от N1 до N2. В операторе цикла не разрешается присваивать параметру цикла какое-либо значение. После окончания цикла значение параметра не определено. Оператор цикла часто применяется для суммирования некоторой последовательности чисел. Сумма членов последовательности величин a1, a2, …, aN называется конечной суммой. Приведем пример расчета суммы последовательности SN = 12 + 32 + 52 + … + (2*N–1)2: PROGRAM SUM_K; var a,S,i,N: word; begin write('Введите число членов суммы N='); readln(N); S:= 0; {Цикл суммирования} for i:= 1 to N do begin a:= Sqr(2*i-1); S:= S+a end; writeln('Конечная сумма S=', S); writeln('Нажмите Enter'); readln end. В Паскале применяются два оператора цикла с условием. Цикл с предусловием выполняет проверку условия выполнением оператора: перед каждым While условие Do оператор; Цикл с постусловием выполняет проверку условия после каждого выполнения оператора: Repeat операторы Until условие; Условие – это выражение логического типа (Boolean). В цикле While оператор выполняется если условие верно (True), если условие ложно (False), то цикл заканчивается, т. е. цикл While повторяется пока выполняется условие. Цикл While начинается проверкой условия, поэтому, если начальное условие ложно, то оператор не выполняется ни разу. Для включения в тело цикла нескольких операторов применяется составной оператор. Цикл Repeat повторяется, если условие ложно, и заканчивается, если условие верно, т. е. цикл повторяется до выполнения условия. Цикл Repeat заканчивается проверкой условия, поэтому операторы выполняются не менее одного раза. В теле цикла может записываться более одного оператора. Циклы с условием обычно используются в тех случаях, если количество повторений блока операторов заранее не известно, например, при расчете суммы членов бесконечного ряда с заданной погрешностью. 16 Если члены ряда являются функциями аргумента x, то ряд называется функциональным. Приведем пример расчета значения функции y=sin(x) с использованием представления функции в виде ряда: y = x – x3/3! + … + (–1)(N+1)x(2*N+1)/(2*N+1)! + … , где a0=x, aN=k*aN-1, k=(–x2)/(2*N*(2*N+1)), N=0, 1, 2, … Каждый член ряда аN при N>0 можно получить умножением предыдущего члена ряда aN-1 на коэффициент k. Приближенное значение функции находится как частичная сумма N членов ряда. Погрешность вычисления значения функции зависит от количества членов ряда и значения х, поэтому расчет заканчивается при |aN| < eps, где eps – допустимая погрешность. PROGRAM SIN_R; var y,x,eps,a,k: real; n: word; begin write('Введите значение x='); readln(x); write('Введите значение погрешности еps='); readln(eps); writeln; n:= 0; a:= x; {первый член ряда} y:= a; {первая частичная сумма ряда} while abs(a)>eps do begin n:= n+1; k:= -x*x/(2*n*(2*n+1)); a:= a*k; y:= y+a; writeln('Приближенное значение функции ',y:11:8,' при n=',n) end; writeln('Нажмите Enter'); readln; end. Операторы ограничения и прерывания цикла применяются внутри операторов цикла. Операторы имеют вид: Continue; – ограничение цикла, Break; – прерывание цикла. Действие оператора Continue заключается в передаче управления на начало цикла, при этом проверяется условие выхода из цикла. Действие оператора Break заключается в передаче управления оператору, следующему за последним оператором цикла. Во вложенных циклах операторы Continue и Break действуют только на цикл в котором они записаны. Оператор перехода служит для передачи управления помеченному оператору и имеет вид: Goto метка; Обычно операторы в программе выполняются в том порядке, в каком они записаны. Оператор перехода прерывает естественный порядок выполнения программы и указывает, что дальнейшее выполнение должно продолжаться, начиная с оператора, помеченного указанной меткой. 17 Меткой может быть целое положительное число или идентификатор. Меткой помечается оператор, которому передается управление, например: M1: write('Введите x>=0'); readln(x); if x<0 then goto M1; Метки описываются в разделе описания, например: label M1; Метка не может стоять перед оператором Begin. Оператор варианта Case состоит из выражения (переключателя) и списка операторов, каждому из которых предшествует одна или более констант (они называются константами выбора) или ключевое слово else: case выражение of константа_1: оператор; … константа_N: оператор; else оператор; end; Переключатель должен иметь тип Byte, Shortint, Integer, Boolean или Char; строковый и длинный целый типы являются недопустимыми. Константы выбора должны быть уникальными и иметь тип, совместимый с типом переключателя. Оператор варианта приводит к выполнению оператора, которому предшествует константа выбора, равная значению переключателя или диапазону выбора, в котором находится значение переключателя. Если такой константы выбора или такого диапазона выбора не существует и присутствует ветвь else, то выполнятся оператор, следующий за ключевым словом else. Если же ветвь else отсутствует, то никакой оператор не выполняется. Приведем пример оператора варианта: case I of 0, 2, 4, 6, 8: writeln('Четная цифра'); 1, 3, 5, 7, 9: writeln('Нечетная цифра'); end; 14. Структурированные типы данных Массивы представляют собой упорядоченную совокупность однотипных величин. Каждая отдельная величина называется компонентой массива. Тип компонент называется базовым типом. Тип компонент может быть любым, кроме файлового. Вся совокупность компонент определяется одним именем. Для обозначения отдельных компонент используется конструкция, называемая переменной с индексом: A[5] S[k+1] B[3,5] В качестве индекса может быть использовано выражение. Тип индексов может быть только интервальным или перечисляемым. Индексы интервального типа, для 18 которого базовым является целый тип, могут принимать отрицательные, нулевое и положительные значения. Чтобы использовать массив в программе на Паскале, требуется, во первых, определить параметры массива (тип индекса и тип компонента), во-вторых, описать переменную-массив. Описание типа массива задается следующим образом: имя типа = array [список типов] of тип; Тип индекса в определении типа заключается в квадратные скобки после служебного слова array, а тип компонента задается после служебного слова of. Пример: type wordtype = array[1..12] of char; var Name: wordtype; Второй способ описания массива – упрощенный: тип массива определяется неявно вместе с описанием переменной. Пример: var Name: array[1..12] of char; Двумерные массивы хранятся в памяти ЭВМ по строкам. Первый индекс определяет номер строки, второй – номер столбца. Пример описания матрицы целых чисел, состоящей из 5 строк и 10 столбцов: var Matrix: array[1..5, 1..10] of integer; Пример описания трехмерного массива: var B: array[1..5, 1..10, 1..8] of integer; В операторной части программы один массив может быть присвоен другому, если их типы идентичны, например: R1:=Z; Для ввода или вывода массива в список ввода или вывода помещается переменная с индексом, а операторы ввода или вывода выполняются в цикле. Инициализация массивов выполняется с помощью типизированных констант, например: type Dim10 = array[1..10] of real; const M10: Dim10 = (0, 2.1, 4, 5.65, 6.1, 6.7, 7.2, 8, 8.7, 9.3); При инициализации двумерных массивов значения компонент каждого из входящих в него одномерных массивов записывается в скобках: type Dim3x2 = array[1..3,1..2] of integer; const M3x2: Dim3x2 = ((1,2)(3,4)(5,6)); Особое место в языке Паскаль занимают массивы символов. Стандартный Паскаль допускает два способа хранения символьных массивов в памяти ЭВМ: распакованный и упакованный. Распакованные массивы символов хранятся в памяти ЭВМ по одному символу в машинном слове, упакованные – по одному символу в байте. При описании упакованного массива символов используют служебное слово PACKED, например: var Mas: packed array[1..20] of char; Описание распакованного массива символов имеет вид: var M: array[1..20] of char; Для преобразования символьного массива из распакованной формы в упакованную и наоборот, из упакованной в распакованную, в язык Паскаль введены две стандартные функции Pack и UnPack. 19 Упакованный массив символов образует символьную строку. Символьная строка может быть либо строковой константой, либо строковой переменной. Строковая константа, или строка, представляет собой совокупность символов, заключенную в апострофы. Строка – это элементарная конструкция языка Паскаль. Строковые константы могут входить в состав выражений. Как и числовые константы, они могут быть описаны в разделе описания констант. Строковые переменные – это одномерные упакованные массивы символов, для описания которых введен тип String. Например, если строка содержит до 30 символов, ее тип будет определен как type s= String[30]; Длина строки не может содержать более, чем 255 символов. В Турбо Паскале определено понятие строки переменной длины, в этом случае ее описание задается как type s= String; Тип String без указания длины совместим со всеми типами строк. Особенностью строковых переменных является то, что к ним можно обращаться как к скалярным переменным, так и к массивам. Во втором случае применяется конструкция «переменная с индексом», что обеспечивает доступ к отдельным символам строки. При этом нижняя граница индекса равна 1. Отдельный символ строки совместим с типом Char. В памяти ЭВМ строка занимает количество байтов, на единицу большее ее длины. Нулевой байт строки содержит ее длину. Для строк определены операции присваивания, слияния (конкатенации) и сравнения. Для сравнения строк применяются все операции отношения. Сравнение строк происходит посимвольно, начиная с первого символа. Строки равны, если имеют одинаковую длину и посимвольно эквивалентны. Строки могут быть элементами списка ввода – вывода, при этом записывается имя строки без индекса. При вводе строковых переменных количество вводимых символов может быть меньше, чем длина строки. В этом случае вводимые символы размещаются с начала строки, а оставшиеся байты заполняются пробелами. Если количество вводимых символов превышает длину строки, лишние символы отбрасываются. Для того, чтобы присоединить к концу строки символ или другую строку, можно использовать операцию сложения. Для определения длины строки предназначена стандартную функцию Length, которая получает в качестве аргумента строку (значение типа String), а возвращает длину строки (значение типа Integer). Пример программы, которая присоединяет одну строку к концу другой: PROGRAM SCON; var s1, s2: string; k: integer; begin { Ввод первой строки } write(’Введите строку: ’); 20 readln(s1); { Вычисление и вывод на экран длины введенной строки } k:= length(s1); writeln(’Длина строки = ’, k, ’ символов’); { Ввод второй строки } write(’Введите слово: ’); readln(s2); { Объединение строк и вывод результата } s1:= s1 + ’ ’ + s2; writeln(’Результат: ’, s1) end. Инициализация строк может производиться с помощью типизированных констант: const sName: String[9]= 'IBM PC/AT'; 15. Процедуры и функции Алгоритм решения задачи проектируется путем декомпозиции всей задачи в отдельные подзадачи. Обычно подзадачи реализуются в виде подпрограмм. Подпрограмма – это последовательность операторов, которые определены и записаны только в одном месте программы, однако их можно вызвать для выполнения из одной или нескольких точек программы. Каждая подпрограмма определяется уникальным именем. В языке Паскаль существуют два типа подпрограмм – процедуры и функции. Процедура или функция – это именованная последовательность описаний и операторов. Различие между процедурами и функциями заключается в том, что процедура просто выполняет некоторую последовательность действий, а функция, кроме того, возвращает в точку вызова некоторое значение. При использовании подпрограммы Паскаль-программа должна содержать текст подпрограммы и обращение к ней. Тексты процедур и функций помещаются в раздел описаний процедур и функций. Подпрограмма может содержать такие же разделы описаний, что и программа, а именно: разделы описания модулей, меток, констант, типов, переменных, процедур и функций. Передача данных в подпрограмму выполняется с помощью специальных переменных – параметров. Параметры, определенные в заголовке подпрограммы, называются формальными. Выражения, задающие конкретные значения при обращении к подпрограмме, называются фактическими параметрами. При обращении к подпрограмме ее формальные параметры замещаются фактическими. Тип каждого фактического параметра должен совпадать с типом соответствующего формального параметра В списке формальных параметров при объявлении подпрограммы должны быть указаны их имена и типы. Имя параметра отделяется от типа двоеточием, а параметры друг от друга – точкой с запятой. Имена параметров одного типа могут объединяться в подсписки, в которых имена отделяются друг от друга запятой. 21 В подпрограммах могут использоваться: параметры, передаваемые по значению; параметры, передаваемые по ссылке; параметры-процедуры; параметры-функции; нетипизированные параметры Параметры, передаваемые по значению, используются для передачи данных в процедуру или функцию: в подпрограмму передается копия каждого формального параметра, даже если в их роли выступают переменные или константы. В процессе выполнения подпрограммы значения таких параметров могут изменяться как угодно, но это никак не повлияет на значения фактических параметров. Параметры, передаваемые по ссылке, используются для хранения результатов выполнения процедуры или функции. Они перечисляются после слова var с обязательным указанием типа. Каждому такому параметру может соответствовать только фактический параметр в виде переменной. При вызове подпрограммы ей передается ссылка на переменную. Нетипизированные параметры передаются по ссылке, однако для них не указывается тип. В этом случае в подпрограмму можно передавать переменныепараметры любого типа, а на программиста возлагается ответственность за корректное приведение типов внутри подпрограммы. Стандартные подпрограммы являются частью языка программирования. Все стандартные процедуры и функции реализованы в специальных библиотечных модулях, которые подключаются сразу после заголовка программы с помощью оператора uses. К стандартным относятся следующие модули: System – модуль, обеспечивающий работу всей системы Турбо Паскаля (всегда подключается автоматически и в разделе uses не указывается). Crt – модуль управления дисплеем и клавиатурой. Dos – модуль, позволяющий использовать прерывания MS DOS. Graph – модуль для работы с монитором в графическом режиме. Printer – модуль для организации печати на принтере. Пользовательские подпрограммы создаются самим пользователем и объявляются после объявления переменных перед первым оператором begin программы. Если процедура объявлена в отдельном модуле, для обращения к ней необходимо дать ссылку на модуль в разделе uses. Для объявления процедуры используется следующая конструкция: procedure имя(параметры); const объявления констант; type объявления типов; var объявления переменных; объявления других процедур и функций; begin операторы end; 22 Для вызова процедуры необходимо указать ее имя, а затем – перечень фактических параметров в круглых скобках. Например, если объявлена процедура procedure ShowMessage(s: string, len: integer); begin writeln(s:len); {len – ширина поля вывода} end; то для ее вызова должен использоваться оператор следующего вида: ShowMessage(’Hello’, 10); Если процедура объявлена без списка параметров, то она вызывается только по имени, без использования круглых скобок. Например, если объявлена процедура procedure ShowHello; begin writeln(’Hello’); end; для ее вызова должен использоваться оператор: ShowHello; Для объявления функции используется конструкция: function имя(параметры): тип результата; const объявления констант; type объявления типов; var объявления переменных; объявления других процедур и функций; begin операторы end; В теле функции должен быть как минимум один оператор, в котором имени функции присваивается возвращаемое значение. В точку вызова функции возвращается результат последнего присваивания. Вызов функции может быть частью выражения, так как функция возвращает некоторое значение. Для вызова необходимо указать имя функции и перечень параметров в круглых скобках. Константы, типы, переменные, подпрограммы, объявленные внутри подпрограммы, доступны только внутри этой подпрограммы. В то же время любые глобальные (объявленные в заголовке программы) константы, типы, переменные, процедуры и функции доступны в любой точке программы, включая все подпрограммы. 16. Стандартные математические функции Рассмотрим часто используемые математические функции. Функция Abs возвращает абсолютное значение аргумента. Описание: Abs(x); Тип результата соответствует типу параметра. Функция ArcTan возвращает арктангенс аргумента. 23 Описание: function ArcTan(x: Real): Real; Арктангенс используется для получения других обратных тригонометрических функций: x arcsin( x) arctg 2 1 x , 1 x2 arccos( x) arctg x 1 arcctg ( x) atctg . x , Функция Cos возвращает косинус аргумента. Описание: function Cos(x: Real): Real; Функция Exp возвращает экспоненциальное значение аргумента. Описание: function Exp(x: Real): Real; Функция Ln возвращает натуральный логарифм аргумента. Описание: function Ln(x: Real): Real; Пример: PROGRAM LOG; var Q: real; begin write('Введите Q: '); readln(Q); writeln('Логарифм Q: ',ln(Q):8:2) end. Функция Pi возвращает значение числа Pi. Описание: function Pi: Real; Функция Random возвращает случайное число. Описание: function Random[(Range: Word)]; Примечания: Если параметр Range (диапазон) не задан, то результатом будет вещественное число x в диапазоне 0 <= х < 1. Если задан параметр Range, то он должен представлять собой выражение целого типа, а результатом будет случайное число длиной в слово в диапазоне 0 <= х < N, где N – значение, заданное параметром Range. Процедура Randomize инициализирует встроенный генератор случайных чисел случайным значением. Описание: procedure Randomize; Пример: PROGRAM RNDM; begin Randomize; Writeln(’Случайное число от 0 до 1: ’, Random)); Writeln(’Случайное число от 0 до 100: ’, Random(101)); end. 24 Функция Round округляет значение вещественного типа до ближайшего целого числа. Описание: function Round(x: Real): Longint; Функция Sin возвращает синус аргумента. Описание: function Sin(x: Real): Real; Функция Sqr возвращает квадрат аргумента. Описание: function Sqr(x); Тип результата соответствует типу параметра. Функция Sqrt возвращает квадратный корень аргумента. Описание: function Sqrt(x: Real): Real; Функция Trunc усекает значение вещественного типа до значения целого типа. Описание: function Trunc(x: Real): Longint; 17. Рекурсия Рекурсия – это способность подпрограммы вызывать саму себя. Классическим примером является использование рекурсии для вычисления факториала: program FactorEx; var Num: integer; function Factorial(N: integer): longint; begin if N=1 then Factorial:= 1 else Factorial:= N*Factorial(N-1); end; begin write(’Введите число:’); readln(Num); writeln(’Факториал числа ’, Num, ’ = ’, Factorial(Num)); end. 18. Операторы выхода Для завершения работы программ, процедур и функций без предварительного перехода по меткам к закрывающему end в Турбо Паскаль введены процедуры Exit и Halt. Вызов Exit завершает работу программного блока. Если Exit выполняется в подпрограмме, то выполнение подпрограммы прекращается и управление передается вызывающей программе. Если Exit выполняется в основной программе, ее работа завершается. Вызов процедуры Halt, где бы она не находилась, завершает работу программы и передает управление операционной системе. Процедура Halt имеет структуру Halt(n), где n – код возврата, который может быть проанализирован операционной системой. Значение n=0 соответствует нормальному завершению работы программы. Вызов процедуры Halt без параметра эквивалентен вызову Halt(0). 25 19. Модули Модуль (UNIT) – это особым образом оформленная библиотека подпрограмм. Модуль в отличие от программы не может быть запущен на выполнение самостоятельно, он может только участвовать в построении программ и других модулей. Модули позволяют создавать личные библиотеки процедур и функций и строить программы практически любого размера. Модуль представляет собой отдельно хранимую и независимо компилируемую программную единицу. В общем случае модуль – это совокупность программных ресурсов, предназначенных для использования другими программами. Под программными ресурсами понимаются любые элементы языка: константы, типы, переменные, подпрограммы. Модуль сам по себе не является выполняемой программой, его элементы используются другими программными единицами. Все программные элементы модуля можно разбить на две части: программные элементы, предназначенные для использования другими программами или модулями (их называют видимыми вне модуля); программные элементы, необходимые только для работы самого модуля (их называют невидимыми или скрытыми). В соответствии с этим модуль, кроме заголовка, содержит две основные части, называемые интерфейсом и реализацией. В общем случае модуль имеет следующую структуру: unit имя модуля; {заголовок модуля} interface {описание видимых программных элементов модуля} {описание скрытых программных элементов модуля} begin {операторы инициализации элементов модуля} end. Использование в модулях процедур и функций имеет свои особенности. Заголовок подпрограммы содержит все сведения, необходимые для ее вызова: имя, перечень и тип параметров, тип результата для функций, эта информация должна быть доступна для других программ и модулей. С другой стороны, текст подпрограммы, реализующий ее алгоритм, другими программами и модулями не может быть использован. Поэтому заголовок процедур и функций помещают в интерфейсную часть модуля, а текст – в часть реализации. Интерфейсная часть модуля содержит только видимые (доступные для других программ и модулей) заголовки процедур и функций (без служебного слова forward). Полный текст процедуры или функции помещают в часть реализации, причем заголовок может не содержать список формальных параметров. Для подключения модуля к программе необходимо указать его имя в разделе описания модулей, например: uses CRT, Graph; 26 В том случае, если имена переменных в интерфейсной части модуля и в программе, использующей этот модуль, совпадают, обращение будет происходить к переменной, описанной в программе. Для обращения к переменной, описанной в модуле, необходимо применить составное имя, состоящее из имени модуля и имени переменной, разделенных точкой. Например, пусть имеется модуль, в котором описана переменная К: unit M; interface var K: Integer; implementation ................. end. Пусть программа, использующая этот модуль, также содержит переменную К: Program P; uses M; var K: Char; begin ............ end. Для того, чтобы в программе P иметь доступ к переменной K из модуля M, необходимо задать составное имя M.K. Использование составных имен применяется не только к именам переменных, а ко всем именам, описанным в интерфейсной части модуля. Если в модуле имеется раздел инициализации, то операторы из этого раздела будут выполнены перед началом выполнения программы, в которой используется этот модуль. 20. Множества Понятие множества в языке Паскаль основывается на математическом представлении о множествах: это ограниченная совокупность различных элементов. Для построения конкретного множественного типа используется перечисляемый или интервальный тип данных. Тип элементов, составляющих множество, называется базовым типом. Множество описывается с помощью служебных слов Set of, например: type M= Set of B; Здесь М – множество, В – базовый тип. Пример описания переменной множественного типа: type M= Set of 'A'..'D'; var MS: M; Принадлежность переменных к множеству может быть определена прямо в разделе описания переменных: var C: Set of 0..7; 27 Константы множественного типа записываются в виде заключенной в квадратные скобки последовательности элементов или интервалов базового типа, разделенных запятыми, например: ['A', 'C'] [0, 2, 7] [3, 7, 11..14] Константа вида [ ] означает пустое подмножество. 21. Записи Запись представляет собой совокупность логически связанных компонент, принадлежащих к разным типам. Компоненты записи называются полями, каждое из которых определяется именем. Поле записи содержит имя поля, вслед за которым через двоеточие указывается тип этого поля. Поля записи могут относиться к любому типу, допустимому в языке Паскаль, за исключением файлового типа. Описание записи осуществляется с помощью служебного слова RECORD, вслед за которым описываются компоненты записи. Завершается описание служебным словом END. Например, записная книжка содержит фамилии, инициалы и номера телефона, поэтому отдельную строку в книжке удобно представить в виде следующей записи: type Row=Record FIO: String[20]; TEL: String[7] end; var str: Row; Описание записей возможно и без использования имени типа, например: var str: Record FIO: String[20]; TEL: String[7] end; Обращение к записи в целом допускается только в операторах присваивания, где слева и справа от знака присваивания используются имена записей одинакового типа. Во всех остальных случаях оперируют отдельными полями записей. Чтобы обратиться к отдельной компоненте записи, необходимо задать имя записи и через точку указать имя нужного поля, например str.FIO или str.TEL. Такое имя называется составным. Компонентой записи может быть запись, в таком случае составное имя будет содержать не два, а большее количество имен. Обращение к компонентам можно упростить, если воспользоваться оператором присоединения with. Он позволяет заменить составные имена, характеризующие каждое поле, на имена полей, а имя записи определить в операторе присоединения: with M do OP; Здесь М – имя записи, ОР – оператор (задает область действия, в пределах которой можно не использовать составные имена). 28 Инициализация записей осуществляется с помощью типизированных констант: type RecType= Record x,y: Word; dim: Array[1..3] of Byte end; const Rec: RecType= (x: 127; y: 255; dim: (2, 4, 8)); 22. Файлы Файловый тип данных (файл) определяет упорядоченную совокупность произвольного числа однотипных компонент. Общее свойство массива, множества и записи заключается в том, что количество их компонент определено на этапе написания программы, тогда как количество компонент файла в тексте программы не определяется и может быть произвольным. Понятие файла достаточно широко. Это может быть файл на диске, коммуникационный порт, устройство печати, клавиатура или другие устройства. При работе с файлами выполняются операции ввода-вывода. Операция ввода означает копирование данных с внешнего устройства (из входного файла) в оперативную память ЭВМ, операция вывода – это пересылка данных из оперативной памяти на внешнее устройство (в выходной файл). Файлы на внешних устройствах часто называют физическими файлами. Их имена определяются операционной системой. В программах на языке Паскаль имена файлов задаются с помощью строк. Например, имя файла на диске может иметь вид 'C:\ABC150\LAB1.DAT' или 'lab3.pas'. Операционная система не делает особого различия между файлами на дисках и устройствами ЭВМ. В Турбо Паскале могут использоваться имена устройств и портов, определенные в MS-DOS, например: 'CON', 'LPT1', 'PRN', 'COM1'. Ввод и вывод данных осуществляется через буфер. Буфер – это область в памяти, которая выделяется для каждого файла. При записи в файл вся информация сначала направляется в буфер и накапливается до тех пор, пока весь объем буфера не будет заполнен. Только после этого или после специальной команды сброса происходит передача данных на внешнее устройство. При чтении из файла данные вначале считываются в буфер, причем данных считывается не столько, сколько запрашивается, а сколько поместится в буфер. Механизм буферизации позволяет более быстро и эффективно обмениваться информацией с внешними устройствами. Для работы с файлами в программе необходимо определить файловую переменную. Паскаль поддерживает три типа файлов: текстовые, компонентные, бестиповые. Описание файлов текстового типа производится с помощью служебного слова Text, например: var tStory: Text; Описание компонентных файлов имеет вид: var fComp: File of T; где T – тип компоненты. 29 Пример описания файлов компонентного типа: var f1: File of Real; f2: File of Integer; Бестиповые файлы описываются с помощью служебного слова File: var f: File; Файловые переменные, которые описаны в программе, называют логическими файлами. Подпрограммы, обеспечивающие ввод-вывод данных, работают с логическими файлами. Физический файл должен быть связан с логическим до выполнения процедур открытия файлов. Турбо Паскаль вводит ряд процедур и функций, применимых для любых типов файлов: Assign, Reset, Rewrite, Close, Rename, Erase, Eof, IOResult. Процедура Assign(var f; FileName: String) связывает логический файл f с физическим файлом, полное имя которого задано в строке FileName. Процедура Reset(var f) открывает логический файл f для последующего чтения данных (открывает входной файл). Процедура Rewrite(var f) открывает логический файл f для последующей записи данных (открывает выходной файл). Процедура Close(var f) закрывает логический файл. Вызов процедуры Close необходим при завершении работы с выходным файлом. Если по какой-то причине процедура Close не будет выполнена, файл все-же будет создан на внешнем устройстве, но содержимое последнего буфера в него не будет перенесено. Для входных файлов использование оператора Close необязательно. Логическая функция EOF(var f): Boolean возвращает значение TRUE, когда при чтении достигнут конец файла. Процедура Rename(var f; NewName: String) позволяет переименовать физический файл, связанный с логическим файлом f. Переименование возможно после закрытия файла. Процедура Erase(var f) уничтожает физический файл, который был связан с переменной f. Файл к моменту вызова процедуры Erase должен быть закрыт. Функция IOResult: Integer возвращает целое число, соответствующее коду последней ошибки ввода-вывода. При нормальном завершении операции функция вернет значение 0. Особое место в языке Паскаль занимают текстовые файлы, компоненты которых имеют символьный тип. Для описания текстовых файлов используется тип Тext: var TF1, TF2: Text; Текстовые файлы представляют собой последовательность строк, а строки – последовательность символов. Строки имеют переменную длину, каждая строка завершается признаком конца строки. С признаком конца строки связана функция EOLn(var T: Text): Boolean, где Т – имя текстового файла. Эта функция принимает значение TRUE, если достигнут конец строки, и значение FALSE, если конец строки не достигнут. Для операций над текстовыми файлами определен также оператор ReadLn(T), который пропускает строку до начала следующей, и WriteLn(T), который завершает строку файла признаком конца строки. 30 Для работы с текстовыми файлами введена расширенная форма операторов ввода и вывода. Оператор Read(T, X1, X2, ... XK) эквивалентен группе операторов begin Read(T,X1); ........... Read(T,XK) end; Здесь Т – текстовый файл, а переменные Х1, Х2, … ХК могут быть переменными целого, действительного или символьного типа, или строкой. Оператор Write(T, X1, X2, ... XK) эквивалентен группе операторов begin Write(T,X1); ........... Write(T,XK) end; Здесь Т – также текстовый файл, но переменные Х1, Х2, … ХК могут быть целого, действительного, символьного, логического типа или строкой. К текстовым файлам относятся стандартные файлы INPUT и OUTPUT, работа с которыми имеет следующие особенности: имена этих файлов в списках ввода-вывода не указываются; применение процедур Reset, Rewrite и Close запрещено; для работы с INPUT и OUTPUT используется функция EOLn без параметров. Пример программы, которая вводит строку с клавиатуры и сохраняет в текстовом файле с именем text.txt: PROGRAM SAVESTR; var s: string; outf: Text; { тип файла – текстовый } begin { Открыть файл для записи данных } assign(outf,'text.txt'); rewrite(outf); writeln('Введите строку:'); readln(s); writeln(outf,s); { запись строки в файл } close(outf) { закрытие файла } end. Турбо Паскаль вводит дополнительные процедуры и функции, применимые только к текстовым файлам: SetTextBuf, Append, Flush, SeekEOLn, SeekEOF. Процедура SetTextBuf(var f: Text; var Buf; BufSize: Word) служит для увеличения или уменьшения буфера ввода-вывода файла f (размер буфера по умолчанию 128 байт). Увеличение размера буфера сокращает количество обращений к диску. Рекомендуется изменять размер буфера до открытия файла. Буфер начнется с первого байта переменной Buf. Размер буфера задается в необязательном параметре BufSize, а если этот параметр отсутствует, размер буфера определяется длиной переменной Buf. Процедура Append(var f: Text) открывает уже существующий файл для дозаписи в конец файла. 31 Процедура Flush(var f: Text) принудительно записывает данные из буфера в файл. Функция SeekEOLn(var f: Text): Boolean возвращает значение True, если до конца строки остались только пробелы. Функция SeekEOF(var f: Text): Boolean возвращает значение True, если до конца файла остались строки, заполненные пробелами. Компонентный файл – это файл с объявленным типом его компонент. Компонентные файлы состоят из машинных представлений значений переменных, они хранят данные в том же виде, что и память ЭВМ. Описание величин файлового типа имеет вид: type M= File Of T; где М – имя файлового типа, Т – тип компоненты. Например: type FIO= String[20]; SPISOK=File of FIO; var STUD, PREP: SPISOK; Здесь STUD, PREP – имена файлов, компонентами которых являются строки. Описание файлов можно задавать в разделе описания переменных: var fsimv: File of Char; fr: File of Real; Компонентами файла могут быть все скалярные типы, а из структурированных – массивы, множества, записи. Операции над компонентными файлами производятся с помощью процедур Reset, Rewrite, Read, Write и Close. Для ввода-вывода используются процедуры Read(f, X) и Write(f, X), где f – имя логического файла, Х – переменная, массив, строка, множество или запись. Процедура Read(f, X) читает одну компоненту файла и записывает ее в X.. Процедура Write(f, X) записывает X в файл как одну из компонент. Для работы с компонентными файлами введена расширенная форма операторов ввода и вывода Read(f, X1, X2 … XK) и Write(f, X1, X2, … XK), где f – файл, а переменные Х1, Х2, … ХК должны иметь тип компонент файла f. Рассмотрим в качестве примера программу, которая заполняет случайными значениями в диапазоне от 0 до 1 массив из 100 элементов типа Real и сохраняет его в виде двоичного файла numbers.bin: PROGRAM RNDNUM; var i: integer; a: array[1..100] of real; outf: File of real; begin randomize; assign(outf,'numbers.bin'); rewrite(outf); for i:=1 to 100 do begin a[i]:=random; write(outf,a[i]); end; close(outf) end. 32 Бестиповые файлы позволяют записывать на диск произвольные участки памяти ЭВМ и считывать их с диска в память. Операции обмена с бестиповыми файлами осуществляется с помощью процедур BlokRead и BlockWrite. Кроме того, вводится расширенная форма процедур Reset и Rewrite. Перед использованием логический файл var f: File; должен быть связан с физическим с помощью процедуры Assign. Далее файл должен быть открыт для чтения или для записи процедурой Reset или Rewrite, а после окончания работы закрыт процедурой Close. При открытии файла длина буфера устанавливается по умолчанию в 128 байт. Турбо Паскаль позволяет изменить размер буфера, для чего следует открывать файл расширенной записью процедур Reset(var f: File; BufSize: Word) или Rewrite(var f: File; BufSize: Word) Параметр BufSize задает число байтов, считываемых из файла или записываемых в него за одно обращение (минимальное значение – 1 байт, максимальное – 64К байт). Чтение данных осуществляется процедурой BlockRead(var f: File; var X; Count: Word; var QuantBlock: Word); Эта процедура читает в переменную X блоки данных, количество которых заданно параметром Count. Размер блока равен размеру буфера. За одно обращение нельзя прочесть больше, чем 64К байт. Необязательный параметр QuantBlock возвращает число блоков, прочитанных текущей операцией BlockRead. В случае успешного завершения операции чтения QuantBlock = Count, в случае аварийной ситуации параметр QuantBlock будет содержать число успешно прочитанных блоков. Запись данных выполняется процедурой BlockWrite(var f: File; var X; Count: Word; var QuantBlock:Word); которая записывает из переменной X в файл количество блоков, заданное параметром Count. Размер блока равен размеру буфера. Необязательный параметр QuantBlock возвращает число блоков, записанных текущей операцией BlockWrite. 23. Последовательный и прямой доступ к данным Смысл последовательного доступа заключается в том, что в каждый момент времени доступна лишь одна компонента из всей последовательности. Для того, чтобы обратиться к компоненте с номером К, необходимо просмотреть от начала файла К-1 предшествующих компонент. После обращения к компоненте с номером К можно обращаться к компоненте с номером К+1. Отсюда следует, что процессы записи и чтения компонент файла не могут произвольно чередоваться. Таким образом, файл вначале строится при помощи последовательного добавления компонент, а затем может последовательно просматриваться от начала до конца. 33 Рассмотренные ранее средства работы с файлами обеспечивают последовательный доступ. Турбо Паскаль позволяет применять способ прямого доступа к компонентным и бестиповым файлам,. Прямой доступ означает возможность заранее определить в файле блок, к которому будет применена операция ввода-вывода. В случае бестиповых файлов блок равен размеру буфера, для компонентных файлов блок – это одна компонента файла. Прямой доступ предполагает, что файл представляет собой последовательность блоков. Если файл содержит n блоков, то они нумеруются от 1 до n. Кроме того, вводится понятие условной границы между блоками, при этом условная граница с номером 0 расположена перед блоком с номером 1, граница с номером 1 расположена перед блоком с номером 2 и, наконец, условная граница с номером n находится после блока с номером n. Реализация прямого доступа осуществляется с помощью подпрограмм FileSize, FilePos, Seek и Truncate. Функция FileSize(var f): Longint возвращает количество блоков в файле f. Функция FilePos(var f): Longint возвращает текущую позицию в файле f. Позиция в файле – это номер условной границы. Для только что открытого файла текущей позицией будет граница с номером 0. Это значит, что можно записать или прочесть блок с номером 1. После чтения или записи первого блока текущая позиция переместится на границу с номером 1, и можно будет обращаться к блоку с номером 2. После прочтения последней записи значение FilePos равно значению FileSize. Процедура Seek(var f; N: Longint) устанавливает текущую позицию в файле. В параметре N должен быть задан номер условной границы, предшествующей блоку, к которому будет производиться обращение. Процедура Truncate(var f) устанавливает в текущей позиции признак конца файла и удаляет все последующие блоки. Рассмотрим в качестве примера программу, которая выводит на экран размер указанного пользователем файла в байтах: PROGRAM FSIZE; var s: string; inf: file of byte; begin write('Введите имя файла: '); readln(s); assign(inf,s); reset(inf); writeln('Размер файла ',filesize(inf),' байт'); close(inf); readln end. 34 24. Указатели Операционная система MS-DOS все адресуемое пространство делит на сегменты. Сегмент – это участок памяти размером 64К байт. Для задания адреса необходимо определить адрес начала сегмента и смещение относительно начала сегмента. В Турбо Паскале определен адресный тип Pointer – указатель. Переменные типа Pointer var p: Pointer; содержат адрес какого-либо элемента программы и занимают 4 байта, при этом адрес хранится как два слова, одно из них определяет сегмент, второе – смещение. Переменную типа указатель можно описать другим способом. type NameType= ^T; var p: NameType; Здесь p – переменная типа указатель, связанная с типом Т с помощью имени типа NameType. Описать переменную типа указатель можно непосредственно в разделе описания переменных: var p: ^T; Необходимо различать переменную типа указатель и переменную, на которую этот указатель ссылается. Например если p – ссылка на переменную типа Т, то p^ – обозначение этой самой переменной. Для переменных типа указатель введено стандартное значение NIL, которое означает, что указатель не ссылается ни к какому объекту. Константа NIL используется для любых указателей. Над указателями не определено никаких операций, кроме проверки на равенство и неравенство. Переменные типа указатель могут быть записаны в левой части оператора присваивания, при этом в правой части может находиться либо функция определения адреса Addr(X), либо выражение @X, где @ – унарная операция взятия адреса, X – имя переменной любого типа, в том числе процедурного. Переменные типа указатель не могут быть элементами списка ввода-вывода. 25. Динамические переменные Статической переменной называется описанная явным образом в программе переменная, обращение к ней осуществляется по имени. Место в памяти для размещения статических переменных определяется при компиляции программы. В отличие от таких переменных в программах, написанных на языке Паскаль, могут быть созданы динамические переменные. Основное свойство динамических переменных заключается в том, что они создаются и память для них выделяется во время выполнения программы. Размещаются динамические переменные в динамической области памяти (heap). 35 Динамическая переменная не указывается явно в описаниях переменных и к ней нельзя обратиться по имени. Доступ к таким переменным осуществляется с помощью указателей и ссылок. Работа с динамической областью памяти реализуется с помощью процедур и функций New, Dispose, GetMem, FreeMem, Mark, Release, MaxAvail, MemAvail, SizeOf. Процедура New(var p: Pointer) выделяет место в динамической области памяти для размещения динамической переменной p^ и ее адрес присваивает указателю p. Процедура Dispose(var p: Pointer) освобождает участок памяти, выделенный для размещения динамической переменной процедурой New, и значение указателя p становится неопределенным. Проуедура GetMem(var p: Pointer; size: Word) выделяет участок памяти в heapобласти и присваивает адрес его начала указателю p. Размер участка в байтах задается параметром size. Процедура FreeMem(var p: Pointer; size: Word) освобождает участок памяти, адрес начала которого определен указателем p, а размер – параметром size. Значение указателя p становится неопределенным. Процедура Mark(var p: Pointer) записывает в указатель p адрес начала участка свободной динамической памяти на момент ее вызова. Процедура Release(var p: Pointer) освобождает участок динамической памяти, начиная с адреса, записанного в указатель p процедурой Mark, т.е. очищает память, которая была занята после вызова процедуры Mark. Функция MaxAvail: Longint возвращает длину в байтах самого длинного свободного участка динамической памяти. Функция MemAvail: Longint полный объем свободной динамической памяти в байтах. Вспомогательная функция SizeOf(X): Word возвращает объем в байтах, занимаемый X, причем X может быть именем переменной или именем типа. Рассмотрим некоторые примеры работы с указателями. var p1, p2: ^Integer; Здесь p1 и p2 – указатели или переменные ссылочного типа. p1:=NIL; p2:=NIL; После выполнения этих операторов присваивания указатели p1 и p2 не будут ссылаться ни на какой конкретный объект. New(p1); New(p2); Процедура New(p1) выполняет следующие действия: в памяти ЭВМ выделяется участок для размещения величины целого типа; адрес этого участка присваивается переменной p1. Аналогично, процедура New(p2) обеспечит выделение участка памяти, адрес которого будет записан в p2. После выполнения операторов присваивания p1^:=2; p2^:=4; в выделенные участки памяти будут записаны значения 2 и 4 соответственно: В результате выполнения оператора присваивания p1^:=p2^; 36 в участок памяти, на который ссылается указатель p1, будет записано значение 4. После выполнения оператора присваивания p2:=p1; оба указателя будут содержать адрес первого участка памяти: Переменные p1^, p2^ являются динамическими, так как память для них выделяется в процессе выполнения программы с помощью процедуры New. Динамические переменные могут входить в состав выражений, например: p1^:=p1^+8; Пример. В результате выполнения программы: Program DemoPointer; var p1,p2,p3:^Integer; begin p1:=NIL; p2:=NIL; p3:=NIL; New(p1); New(p2); New(p3); p1^:=2; p2^:=4; p3^:=p1^+Sqr(p2^); writeln('p1^=',p1^,' p2^=',p2^,' p3^=',p3^); end. на экран дисплея будут выведены результаты: p1^=2 p2^=4 p3^=18 26. Подпрограммы для работы в графическом режиме Модуль Graph содержит около 80 процедур и функций, предназначенных для работы с экраном дисплея в графическом режиме. Рассмотрим некоторые часто используемые процедуры: Bar(X1,Y1,X2,Y2: Integer) – рисует прямоугольник с координатами противоположных вершин (X1,Y1) и (X2,Y2), используя текущий стиль и цвет. Circle(X,Y: Integer; Radius: Word) – рисует окружность радиуса Radius с центром в точке (X,Y). ClearDevice – очищает экран, устанавливая текущей точку (0,0). CloseGraph – закрывает графический режим. DrawPoly(NumPoints: Word; var PolyPoints) – рисует ломанную линию или контур многоугольника с числом вершин NumPoints и координатами вершин, указанными в массиве PolyPoints. Ellipse(X,Y: Integer; StartAngle,EndAngle, XRadius,YRadius: Word) – рисует эллиптическую дугу от начального угла к конечному с центром в точке (X,Y), горизонтальным радиусом Xradius и вертикальным радиусом YRadius. FillEllipse(X,Y: Integer; XRadius,YRadius: Word) – рисует закрашенный эллипс с центром в точке (X,Y), горизонтальным радиусом Xradius и вертикальным радиусом YRadius. FillPoly(NumPoints: Word; var PolyPoints) – рисует закрашенный многоугольник с числом вершин NumPoints и координатами вершин, указанными в массиве PolyPoints. 37 InitGraph(var GrDriver, GrMode: Integer; Path: String) – инициализирует графический режим. Line(X1,Y1,X2,Y2: Integer) – рисует прямую линию от точки (X1,Y1) до точки (X2,Y2). LineRel(dX,dY: Integer) – рисует прямую линию от текущей точки (X,Y) до точки (X+dX,Y+dY). LineTo(X,Y: Integer) – рисует прямую линию от текущей точки до точки (X,Y). MoveRel(dX,dY: Integer) – передвигает указатель из текущей точки (X,Y) в точку (X+dX,Y+dY). MoveTo(X,Y: Integer) – передвигает указатель из текущей точки в точку (X,Y). OutText(TextString: String) – выводит текст на экран, начиная с того места, где находится указатель. OutTextXY(X,Y: Integer; TextString: String) – выводит текст на экран, начиная с точки с координатами (X,Y). PutPixel(X,Y: Integer; ColorPixel: Word) – выводит точку с координатами (X,Y) и цветом ColorPixel. Rectangle(X1,Y1,X2,Y2: Integer) – рисует рамку с координатами противоположных вершин (X1,Y1) и (X2,Y2). SetBkColor(Color: Word) – устанавливает цвет фона. SetColor(Color: Word) – устанавливает основной цвет для рисования. SetFillPattern(Pattern: FillPatternType; Color: Word) – устанавливает определѐнный пользователем шаблон заполнения. SetFillStyle(Pattern, Color: Word) – устанавливает тип и цвет заполнения. SetLineStyle(LineStyle, Pattern, Thickness: Word) – устанавливает стиль, образец и толщину линий. Часто используются также следующие функции: GetX: Integer – возвращает текущую координату X. GetY: Integer – возвращает текущую координату Y. GetMaxX: Integer – возвращает максимальную горизонтальную координату X. GetMaxY: Integer – возвращает максимальную вертикальную координату Y. Для работы с графикой программы на Турбо Паскале используют так называемые bgi-драйверы: требуется или скопировать bgi-драйвер в рабочий каталог, или указать путь к bgi-драйверу. Все современные AT-совместимые компьютеры используют драйвер egavga.bgi, который работает в режиме 640480 точек, 16 цветов. Соответственно, код цвета рисования может принимать значения от 0 до 15. Начало системы координат расположено в левом верхнем углу экрана, координатная ось Y направлена сверху вниз. Рассмотрим в качестве примера программу, которая включает графический режим, на рисует красную точку в центре экрана, выбирает желтый цвет для рисования, рисует отрезок, прямоугольник, треугольник, окружность, эллипс и строку текста, ожидает нажатия клавиши Enter, а затем восстанавливает текстовый режим и завершает работу: 38 PROGRAM GTEST; uses Graph; var Drv,Mode: integer; Triangle: array[1..4] of PointType; begin Drv:= Detect; InitGraph(Drv, Mode, ''); PutPixel(320,240,12); {Нарисовать красную точку в центре экрана} SetColor(14); {Установить желтый цвет рисования} Line(10,5,80,30); {Нарисовать линию} Rectangle(5,35,70,60); {Нарисовать прямоугольник} {Задать координаты вершин треугольника} Triangle[1].X:=40; Triangle[1].Y:=70; Triangle[2].X:=20; Triangle[2].Y:=90; Triangle[3].X:=60; Triangle[3].Y:=90; Triangle[4].X:=40; Triangle[4].Y:=70; DrawPoly(4, Triangle); {Нарисовать треугольник} Circle(50,120,20); {Нарисовать окружность} Ellipse(50,160,0,360,30,15); {Нарисовать эллипс} OutTextXY(15,200,’Hello!’); {Вывести текст} readln; CloseGraph end. Тип PointType предназначен для хранения координат точки. Описание: type PointType = Record X. Y: Integer; end; Для процедуры FillPoly необходимо указать координаты вершин многоугольника в виде массива точек, а процедура DrawPoly требует на одну точку больше – координаты начальной и конечной точек должны совпадать. Дело в том, что процедура DrawPoly используется не только для рисования многоугольников, но и для вывода ломанных линий. Тип FillPatternType определяет образец закраски. Описание: FillPatternType = array[1..8] of Byte; Приведем в качестве примера программу, которая закрашивает треугольник в красный цвет: PROGRAM REDT; uses Graph; {Использовать шаблон для сплошной заливки} const Pat: FillPatternType = ($FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF); var Drv,Mode: integer; Triangle: array[1..3] of PointType; begin Drv:= Detect; InitGraph(Drv, Mode, ''); SetColor(12); SetFillPattern(Pat, 12); 39 Triangle[1].X:=200; Triangle[1].Y:=100; Triangle[2].X:=100; Triangle[2].Y:=200; Triangle[3].X:=300; Triangle[3].Y:=200; FillPoly(3, Triangle); readln; CloseGraph end. Список использованной литературы 1. 2. 3. 4. 5. 6. Белашов В.Ю., Чернова Н.М. Эффективные алгоритмы и программы вычислительной математики. – Магадан: СВКНИИ ДВО РАН, 1997. – 160 с.: ил. Беспалов В. В. Основы применения вычислительной техники и программирование: учебное пособие./В.В. Беспалов – Томск: Изд-во Томского политехнического университета, 2007. – 107 с. Вирт Н. Алгоритмы + структуры данных = программы: Пер. с англ. – М: Мир, 1985. – 406 с.: ил. Рапаков Г.Г., Ружецкая С.Ю. Программирование на языке Pascal. – СПб: БХВПетербург, 2004. – 480 с.: ил. Шпак Ю.А. Turbo Pascal 7.0 на примерах / Под ред. Ю.С. Ковтанюка. – К: Юниор, 2003. – 496 с.: ил. Turbo Pascal / С.А. Немнюгин. – СПб.: Питер, 2000. – 496 с.: ил. 40 Учебное издание АЛГОРИТМИЧЕСКИЙ ЯЗЫК ПАСКАЛЬ. УЧЕБНОЕ ПОСОБИЕ ПО ДИСЦИПЛИНЕ «ПРОГРАММИРОВАНИЕ И ОСНОВЫ АЛГОРИТМИЗАЦИИ» СОСТАВИТЕЛЬ: КУЛАКОВ ВЛАДИМИР ГЕННАДЬЕВИЧ Редактор Технический редактор http://www.miem.edu.ru/rio rio@miem.edu.ru Подписано в печать . Формат 60х84/16. Бумага типографская №2. Печать - ризография. Усл. печ.л. Уч-изд.л. Тираж 50 экз. Заказ . Бесплатно. Изд № . Московский государственный институт электроники и математики 109028 Москва, Б. Трехсвятительский пер. 3. Отдел оперативной полиграфии Московского государственного института электроники и математики. 113054 Москва, ул. М. Пионерская, 12. 41