Терехин В.В.
TURBO PASCAL Учебное пособие
Новокузнецк 2004
Министерство Образования Российской Федерации Кемеровский...
95 downloads
505 Views
813KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Терехин В.В.
TURBO PASCAL Учебное пособие
Новокузнецк 2004
Министерство Образования Российской Федерации Кемеровский государственный университет В. В. Терёхин
TURBO PASCAL Учебное пособие
Новокузнецк 2004 ББК 32.973 2
УДК - 681.142.2 ТПечатается по решению редакционно-издательского совета Кемеровского государственного университета. Рецензенты: ………………… ……………….. Терёхин В.В. TURBO PASCAL:Учебное пособие /Кемеровский государственный университет. – Новокузнецк: Кузбассвузиздат, 2004. -376с. ISBN …………………… Автор скомпоновал основные сведения
Книга рассчитана на студентов 2-5 курсов по специальности «Прикладная математика и информатика», «Автоматизированные системы обработки информации и управления», «Прикладная информатика в экономике». К ……………..
ББК 32.81
ISBN …………………… © Терёхин В.В., 2004 © Кем еровский государственный университет, 2004
3
Содержание 1 Введение. Интегрированная среда Турбо Паскаля............................6 2 Aлфавит Турбо Паскаля ..........................................................................12 3 Идентификаторы .......................................................................................13 4 Структура программы .............................................................................13 5 Описание переменных ..............................................................................15 6 Описание констант....................................................................................16 7 Описание и использование меток ..........................................................17 8 Классификация типов данных. Стандартные типы данных ............18 8.1 Классификация типов данных.........................................................18 8.2 Целочисленные типы.........................................................................19 8.2 Логический тип...................................................................................20 8.3 Символьный тип ................................................................................20 8.4 Вещественные тип..............................................................................21 9 Описание типов пользователя ................................................................22 10 Выражения...............................................................................................24 10.1 Порядок выполнения операций.....................................................24 10.2 Выражения целого типа ..................................................................25 10.3 Вещественные выражения..............................................................26 10.4 Логические выражения ...................................................................27 11 Операторы ввода/вывода.......................................................................31 11.1 Операторы ввода (Read, Readln)....................................................32 11.2 Операторы вывода (Write, Writeln) ..............................................32 12 Оператор присваивания.........................................................................35 13 Составной оператор ................................................................................36 14 Использование стандартных процедур и функций...........................37 14.1 Понятие формальных и фактических параметров .....37 14.2 Некоторые полезные процедуры и функции...............................39 15 Условный оператор (ветвление)...........................................................42 16 Оператор множественного выбора (варианта) - case........................44 17 Циклы........................................................................................................47 17.1 Цикл типа for ....................................................................................47 17.2 Цикл типа While ...............................................................................53 17.3 Цикл типа Repeat... Until .................................................................55 17.4 Дополнительные операторы при программировании циклов ....................................................................57 18 Массивы ....................................................................................................58 18.1 Одномерные массивы ......................................................................59 18.2 Сортировка одномерного массива ................................................62 18.3 Массивы с большей размерностью ...............................................64 18.4 Констант-массивы............................................................................69 4
19 Строки .......................................................................................................72 19.1 Строковый тип .................................................................................72 19.2 Операции над строками ..................................................................74 20 Генератор случайных чисел ..................................................................82 21 Записи ........................................................................................................84 21.1 Записи с фиксированными частями .............................................84 21.2 Записи с вариантами........................................................................88 22 Множества ................................................................................................91 23 Процедуры и функции описанные пользователем .................93 24 Параметры-переменные не имеющие типа........................................98 25 Процедурные типы ................................................................................99 26 Файлы......................................................................................................103 26.1 Типизированные файлы ...............................................................104 26.2 Текстовые файлы ...........................................................................118
5
1 Введение. Интегрированная среда Турбо Паскаля Одним из самых популярных я распространенных программных продуктов фирмы Borland по праву считается интегрированный пакет Turbo Pascal. Программная среда Турбо Паскаля называется интегрированной потому что состоит из редактора, компилятора, компоновщика, отладчика и обеспечивает создание, отладку и исполнение программ, написанных на Паскале, без обращения к каким-либо другим программным средствам. При запуске среды Турбо Паскаля появляется три видимых управляющих элемента: полоса меню в верхней части, область окна в центре и строка статуса внизу. Активизация верхней полосы меню – F10, перемещение по пунктам меню - клавиши: вверх, вниз, вправо, влево, а для выбора подменю - клавиша Enter. Существует возможность использования «горячих клавиш» нажимаются одновременно клавиша Alt и подсвеченная буква заголовка меню. Выход из меню - клавиша Esc. Необходимо отметить, что некоторые пункты меню являются недоступными в том случае, когда нет смысла их выбирать. Практически вся работа в среде Турбо Паскаля происходит в окнах. Окно - это прямоугольная область экрана, которую можно перемещать, изменять ее размеры, перекрывать, закрывать и открывать. Активное окно — это окно, с которым Вы в настоящий момент времени работаете. Существуют несколько типов окон, но большинство из них имеют общие элементы: - полоса заголовка; - закрывающая кнопка; - полосы скроллинга; - уголок для изменения размеров окна; - кнопка масштабирования; - номер окна. Легко отличить активное окно от неактивного по двой6
ной рамочке. Активное окно всегда имеет закрывающую кнопку, кнопку масштабирования, кнопки перемещения и уголок изменения размеров. Если окна перекрываются, то активное окно всегда находится на переднем плане. Как мы уже говорили, каждое открытое окно имеет уникальный номер в верхнем правом углу. При нажатии Alt-О можно получить список всех открытых окон. Для того, чтобы сделать окно активным, можно воспользоваться комбинацией клавиш Alt. Строка статуса появляется в самой нижней части экрана и выполняет следующие функции: • напоминает основные комбинации клавиш для быстрого доступа к командам меню; • предоставляет быстрый вариант выполнения команд посредствам выбора активных зон мышью; • информирует о работе среды (например, сообщение "Saving... " появляется, когда сохраняется редактируемый файл); • предоставляет краткую справочную информацию по командам меню. Следующим важным средством управления средой являются диалоговые окна. Диалоговое окно - это наиболее удобный способ показать и сделать многочисленные установки среды. Диалоговое окно может содержать пять основных элементов: зависимые переключатели, независимые переключатели, кнопки, окна ввода и окна списка. Для перехода от одного элемента диалогового окна к другому (в порядке установленном создателями среды) можно использовать клавишу Tab или комбинацию Shift—Tab. Эти возможности отличаются только направлением обхода. Каждый элемент, когда он становится активным, подсвечивается. Редактор Турбо Паскаль имеет следующие возможности: • редактирование нескольких больших файлов (до 1 Мб); • открытие нескольких файлов одновременно; 7
• передвижение, перекрытие и изменение размеров окон редактора; • копирование текста из окна справочной системы; • копирование между окнами. Для выделения части текста при копировании, удалении и т. д. можно воспользоваться комбинацией клавиш Shift и стрелок. Занести фрагмент в буфер обмена - Ctrl-Insert, а из буфера обмена - Shift-Insert, удалить - Ctrl-Delete, перенести в буфер обмена - Shift-Delete. Одним из основных достоинств среды является встроенная контекстно-ориентированная справочная система, которая позволяет получить справочную информацию посредством нажатия клавиши F1. Меню Help (Alt-H) позволяет использовать расширенные возможности системы: поиск в оглавлении (Shift-F1), контекстный поиск (Ctrl-F1), просмотр предыдущей страницы помощи (Alt-Fl). Если вы уже находитесь в справочной системе можно получить информацию о самой системе (F1). Любой справочный экран может содержать одно или более ключевых слов (подсвеченных элементов), дающих возможность получения дополнительной справочной информации. Команды работы с файловой системой находятся в верхним меню File. Сохранить файл из активного окна на диск - Save (F2), загрузить с диска — Open (F3), сохранить содержание активного окна под новым именем - Save as..., сохранить содержание всех окон - Save all и т. д. В меню Edit продублированы основные команды работы с блоками и команда последовательной отмены действий в редакторе -Undo (Alt-BkSp). Меню Run предназначено для запуска программы в обычном режиме - Run (Ctrl-F9), в режимах пошаговой отладки и т. д. В меню Compile собраны команды связанные с компиляцией программ: Compile (Alt-F9), Make (F9) и др. Меню Debug позволяет управлять отладкой программы, получать и устанавливать отладочную информацию: устанавли8
вать точки прерывания программы - Breakpoints, наблюдать за значениями переменных, вызывая специальное окно - Watch, смотреть за окном, в котором выполняется программа - User screen (Alt-F5), и т. д. Меню Tools позволяет осуществлять управление инструментарием среды, в том числе и вызывать внешние программы— утилиты: турбо-ассемблер, турбо-дебагер и т. д. В меню Options собраны команды конфигурирования и настройки среды Турбо Паскаль. Меню Window содержит команды управления окнами: порядок расположения окон на рабочей поверхности — Tile, Cascade, закрытия: Close и Close all, перехода: Next (F6), Previous (ShiftF6) и др. Встроенный отладчик среды Турбо Паскаля позволяет производить пошаговое выполнение программы и просматривать переменные: каким образом изменяются их значения во время выполнения операторов программы. Чтобы начать сеанс отладки, необходимо выбирать команду Run/Trace Into или нажать F7. Если программа изменялась с момента последней компиляции, то она будет откомпилирована снова. После этого на служебном слове begin в начале программы появится подсвеченная полоса, которая будет переходить от строки к строке по мере нажатия клавиши F7 и выполнения очередного оператора программы. Для вызова окна наблюдения за значениями переменных можно воспользоваться командой Debug/Add Watch (или Ctrl-F7). При выборе данной команды появляется строка редактирования, в которой требуется указать имя переменной для наблюдения. Для удобства работы неплохо изменить размер и положение окна для редактирования программы и окна Watch, избежав перекрытий. После этого при пошаговой отладке можно видеть значения переменных на каждом шаге. Иногда необходимо начать отладку программы не с первой строки. В этом случае можно воспользоваться точками прерывания (Debug\Breakpoints), тогда при обычном запуске про9
грамма будет выполняться не до конца, а до строки, в которой эта точка установлена. В таблицах 1-3 приведены «горячие» клавиши различных режимов. Таблица 1- «Горячие» клавиши редактирования Клавиша(и) Элемент меню Функция Удаляет выделенный текст из окCtrl-Del Edit/Clear на и не помещает его в буфер обмена. Копирует выделенный текст в Ctrl-Ins Edit/Copy буфер обмена. Помещает выделенный текст в Shift-Del Edit/Cut буфер обмена и удаляет его. Помещает текст из буфера обмена Shift-Ins Edit/Paste в активное окно. Ctrl-L Search/ Search Повторяет команду Find или Again Replace . Сохраняет файл в активном окне F2 File/Save редактора. Позволяет открыть файл. F3 File/Open Таблица 2 – «Горячие» клавиши управления окнами Клавиша(н) Элемент меню Функция Alt-# Alt-O Alt-F3 Alt-F5 Shift-F6
Показывает окно, где # - номер окна, которое Вы хотите посмотреть. Показывает список открытых Window/List окон. Закрывает активное окно. Window/Close Показывает экран пользоватеWindow/User ля. Screen Window/Previous Проходит назад через все открытые окна. нет
10
F5 F6 Ctrl-F5 Shift-F5
Увеличивает (уменьшает) активное окно. Проходит вперед через все Window/Next активные окна. Window/Size/Move Изменяет позицию активного окна (сдвиг - стрелками). Window/Size/Move Изменяет размер активного окна (изменение – Shift + стрелка). Window/Zoom
Таблица 3 - «Горячие» клавиши отладки/запуска Клавиша(и) Элемент меню Функция Alt-F9
Compile/Compile
Компилирует последний файл в редакторе.
Ctrl-F2
Run/Program Reset
Переустанавливает выполняемую программу.
Ctrl-F4
Debug/Evaluate/ Вычисляет выражение. Modify Debug/Add Watch Добавляет выражение для просмотра.
Ctrl-Fl
Ctrl-F9 F4
Debug/Toggle Breakpoint Run/Run Run/Go To Cursor
Устанавливает или очищает условные точки прерывания. Запускает программу. Запускает программу до позиции курсора.
F7
Run/Trace Into
Выполняет прослеживание внутри процедур.
F8
Run/Step Over
Осуществляет перескакивание через вызовы процедур.
Ctrl-F7
11
F9
Compile/Make
Выполняет Make (компилирует/редактирует связи) программы.
2 Aлфавит Турбо Паскаля В алфавите Турбо Паскаля используются следующие символы: • буквы латинского алфавита как в верхнем A.. Z, так и в нижнем a.. z регистрах; • десятичные цифры 0.. 9; • шестнадцатеричные цифры 0.. 9, А, В, С, D, E, F; • прописные и заглавные буквы русского алфавита А... Я, а... я и символы псевдографики; • специальные символы + , _ , * , / , = , > , < , [ , ] , ( , ) ; • символы знаков препинания (. , : ;) ; • пары специальных символов = , := , .. , (* , *) . В таблице 4 приведены 48 наиболее употребительных ключевых слов языка Турбо Паскаль. Всего же их около восьмидесяти. Зарезервированные (ключевые) слова могут употребляться только по своему прямому назначению. Таблица 4 – Ключевые слова языка Паскаль. absolute end inline procedure and external interface program array file interrupt record begin for label repeat case forward mod set const function nil shl div goto not shr do if of string downto implementaor then else in packed to
type unit until uses var while with xor
12
3 Идентификаторы Идентификатор представляет собой последовательность из латинских букв, цифр и символа подчеркивания, которая всегда начинается с буквы или символа подчеркивания. Длина идентификатора ограничивается только длиной строки, но значимыми являются только первые 63 символа. Заглавные и прописные буквы в идентификаторах не различаются. Идентификаторы используются как имена программ, типов, констант, переменных, меток, процедур и функций. Недопустимо использование ключевых слов в качестве идентификаторов. Примеры: А, С, Top_Not, RLeft_m - допустимые идентификаторы; 2Sum - недопустимый идентификатор, т. к, начинается с цифры; Now Elem - недопустимый идентификатор, т. к. содержит пробел; Sin - недопустимый идентификатор, так как совпадает с именем стандартной тригонометрической функции. 4 Структура программы Основная часть программы написанной на Паскале описательные разделы. Поэтому, говоря о структуре программы следует отметить следующее. 1. Некоторые описательные разделы могут отсутствовать в реальной программе, а их порядок и повторное включение зависят только от внутренней логики программы. Например, если в описании типа используется константа, то описание этой константы должно предшествовать описанию типа и т. д., а если при описании следующей константы потребуется данный тип, то необходимо открыть раздел описания констант второй раз и т. д. 2. Структуру программы в точности повторяют структуры подпрограмм: процедуры и функции. Они отличается 13
только заголовком и заключительным символом: тело программы заканчивается служебным словом END с точкой (end.), а тело подпрограммы - с точкой-запятой (end;). Структура программы: program ; const ; type ; var ; label ; ; begin ; end. Самая простая программа может не содержать оператора program, описательных разделов и иметь пустое тело. Однако, она может быть откомпилирована и запущена. begin end. Следующая программа будет посложней, она выводит на экран сообщение: program p2; be g in writeln('Моя первая программа на Паскале'); end. Программа, которая получает два числа и выводит их сумму на экран, содержит один описательный раздел - раздел описания переменных: 14
program рЗ; var А, В: integer; begin Writeln('Введите два числа А и В’); Read(А, В); Writeln(‘A + В= ' , А + В) ; end. Ясно, что программы могут быть очень сложными, содержать все разделы описания, процедуры и функции. По мере знакомства с языком мы их также будем использовать. 5 Описание переменных Каждая переменная, встречающаяся в программе, должна быть описана. Описание переменной должно предшествовать ее использованию. Раздел описания переменных может повторяться в программе несколько раз. Он начинается служебным словом Var, a заканчивается с началом любого другого описательного раздела, заголовком процедуры, функции или началом тела программы. Раздел описания переменных может быть вложен в описание процедуры или функции. При этом переменные, описанные в основной программе, называются глобальными, а в подпрограммах - локальными. При компиляции под каждую переменную выделяется участок памяти, размер которого зависит от типа переменной. Сама переменная определяется, во-первых, именем - идентификатором, во-вторых - типом, а в-третьих - значением, которое записывается в выделенный участок памяти. В дальнейшем вы поймете, что изменить значение переменной можно путем изменения соответствующего участка памяти, но до тех пор мы будем считать, что для этого необходимо использовать оператор присваивания. 15
Итак, структура описания переменных такова: var : ; : ; …………………………………………………………. : ; Примеры: 1) var А, В, С, D: Real; I, J, К, L, M: Integer; U: Char; S: String; 2) var M: array [1.. 100] of Integer; T: Real; N, I: Integer; 6 Описание констант Существует два вида констант: константы "без типа" - нетипизированные и константы "с типом" типизированные (типированные). Их различия обусловлены процессом компиляции программ (компиляция - преобразование программы с алгоритмического языка в машинный код). При написании программ для нас имеет значение то, что типизированные константы изменяемы во время выполнения программы, а нетипизированные изменены быть не могут. В свою очередь нетипизированные константы могут быть использованы при описании других констант, переменных и типов. Структура описания нетипизированных констант: 16
= ; Примеры: const А = 75; Т = 3. 56; S = 'ABCD'; Структура описания типизированных констант: : = ; Примеры: const A: Integer 43; R: Real= 345. 123; S: String[10]= 'Мама мыла раму'; 7 Описание и использование меток Использование меток при программировании на структурированных, процедурных языках (к которым относится Паскаль) считается дурным тоном. Но бывают случаи, когда для использования меток существуют веские причины, например, начальный этап создания программы, когда автор еще не видит другого решения задачи. Идентификатор метки может начинаться с цифры. Описание меток: Label ; Метки ставятся в том блоке программы, в котором они описываются. Метку можно поставить перед любым оператором, 17
что позволяет выполнить прямой переход на этот оператор. Метка в программе: : Переход к метке осуществляется следующим образом (оператор перехода к метке): Goto ; Пример: program p4; label 11, 12, 13, 14; begin goto 11; 13: Writeln('метка 3 ' ) ; goto 14; 12: Writeln('метка 2 ' ) ; goto 13; 11: Writeln{'метка 1 ' ) ; goto 12; 14: end. Программа выводит на экран сообщения по порядку: ‘метка 1’ , 'метка 2’ , 'метка 3’, но операторы вывода в программе расположены в обратном порядке. Такой эффект достигается использованием меток. 8 Классификация типов данных. Стандартные типы данных 8.1 Классификация типов данных При объявлении переменной необходимо указать ее тип. Тип переменной описывает набор значений, которые она может принимать, действия, которые могут быть над ней выполнены, а также указывает на объём оперативной памяти, занимаемой переменной данного типа. Объявление типа опреде18
ляет идентификатор, который собственно и обозначает тип. Имеется шесть основных классов типов: • простые типы; • строковые типы; • структурные типы; • тип указатель; • процедурные типы; • объектные типы. Простые (скалярные) типы разделяются на два блока: • порядковые; • вещественные. Turbo Pascal имеет семь встроенных порядковых типов: Integer (целый), Shortint (короткий целый), Longint (длинный целый), Byte (длиной в байт), Word (длиной в слово), Boolean (логический) и Char (символьный). Кроме того, имеется два других класса порядковых типов, определяемых пользователем: перечислимые типы и типы поддиапазона. 8.2 Целочисленные типы Первые пять порядковых типов относятся к категории целочисленных типов. В графе “Тип” в нижележащей таблицы приведены ключевые слова - обозначения целых типов. Каждый из них определяет некоторое подмножество целых чисел. Тип Shortint
Диапазон -128.. 127
Размер в памяти 1 байт
Integer
-32768. .32767
2 байта
Longint
-21212147483648..2147483647
4 байта
Byte
0..255
1байт
Word
0..65535
2 байта 19
8.2 Логический тип Значениями логического типа являются встроенные идентификаторы False и True. Этот тип переменных задаётся ключевым словом Boolean. Поскольку логический тип является перечислимым, между этими значениями имеют место следующие отношения: False < True .
8.3 Символьный тип Множеством значений этого типа являются символы, упорядоченные в соответствии с расширенным набором символов кода ASCII. Тип этих переменных задаётся ключевым словом Char. Значение переменной символьного типа можно задать в операторе присваивания с помощью символьной константы или функции Chr . Эта функция устанавливает соответствие между однобайтовыми целыми значениями кода и символами. Противоположной по отношению к Chr является функция Ord, которая возвращает код символьного аргумента. Знак # и последующая за ним целая беззнаковая константа обозначают символ. Например, в программе есть описание Var ch: Char; Тогда операторы ch: = chr(7); ch: = #7; присваивают символьной переменной ch одно и то же символьное значение – звуковой сигнал (это управляющий символ). В работе могут понадобится значения некоторых управляющих символов, которые приведены ниже. Код Ctrl - поИспользоМнемоДействие 20
следовательность #7
^G
вание функции Chr Chr(7)
ническое обозначение BEL
#10
^J
Chr(10)
LF
#12
Chr(12)
FF
#13
Chr(7)
CR
#26 #27
Chr(7) Chr(7)
SUB ESC
Звуковой сигнал динамика Перевод строки Прогон страницы Возврат каретки Конец файла Символ Escape
8.4 Вещественные тип В Турбо Паскале имеются пять встроенных вещественных типов: Real, Single, Double, Extended и Сотр. Вещественные типы различаются диапазоном и точностью значений. Тип Диапазон Значащие цифры Размер в (кол-во) байтах Real
2.9Б-39..1.7Е38
11-12
6
Single
1.5E-45..3.4E38
7-8
4
Double
5.0E-324..1.7E308
15-16
8
Extended
3.4E-932..1.1E4932
19-20
10
Comp
-9.2el8.. 9.2el8
19-20
8
Turbo Pascal поддерживает две модели генерации кода для выполнения действий над вещественными типами (для чисел с плавающей точкой): программную и аппаратную. Выбор соответствующей модели осуществляется с помощью директи21
вы компилятора SN. При отсутствии математического сопроцессора директива компилятора в тексте программы $Е обеспечит его полную эмуляцию. 9 Описание типов пользователя Существует несколько возможностей создания (описания) типов пользователя. 1. Полное соответствие стандартному типу. В этом случае переменные нового типа обладают такими же свойствами, что и переменные базового типа. type = : Примеры: type Mylnteger = Integer; MyReal = Real; MyString = String[255]; 2. Поддиапазон стандартного типа. Такие типы называются ограниченными. Базовым типом в этом случае может быть любой перечислимый тип. Ограниченный тип сохраняет все свойства базового и отличается лишь тем, что имеет ограниченный диапазон значений. Использование ограниченных типов, определенных пользователем, значительно улучшает наглядность и читаемость программ. Кроме того, специальная опция компилятора позволяет включить контроль выхода переменных за пределы объявленного диапазона, а это удобно при отладке программы. Включение контроля — {$R+}, а выключение его — {$R—}. type < идентификатор - имя типа > = < начальное значение бaзового типа >.. < конечное значение базового типа >; 22
Примеры: 1) type Mylnteger = -327.. 327; СharS = 'A ' .. 'Z ' ; 2) program p5 ; type MyType = 0. . 9; var varl, var2 : MyType; begin {$R-} varl: =5 5; {выход за диапазон, но ошибки не возникает} {$R+} var2:= 55; {выход за диапазон, ошибка} end. 3. Новый перечислимый тип. При его определении в соответствующем порядке задаются все необходимые значения, которые может принимать переменная данного типа. Значения переменных нового типа будут представлены при помощи идентификаторов, которые, таким образом, будут являться константами нового типа. Примеры: type Operator = ( plus, minus, multi, divide ); Day = ( Mon, Tues, Wed, Thur, Fri, Sat, Sun); Из примера видно, что переменные типа Operator могут принимать одно из четырех значений plus, minus, multi, divide. Операции отношения =, , >, =, - больше чем; < - меньше чем; >= - больше или равно; В > 0
В операциях сравнения для символов и строк необходимо вспомнить, что у каждого элемента скалярного, перечислимого типа есть свой код - порядковый номер. Его можно получить, используя функцию Ord. Заведомо известно, что коды всех латинских и русских букв упорядочены в соответствии с латинским и русским алфавитами, а коды всех цифр упорядочены по их арифметическим значениям. Данное отношение порядка и позволяет сравнивать любые символы и строки. Пример: 'А' < ' D ' ‘X ’ < ‘Y ’ ‘ 2 ’ < ‘5 ’ ‘ ABCD’
e do begin …………………. for i : = 1 to m do begin ………………………… if y 1 then break; …………………………… s: = s+p; end; ……………………… В этом примере во внутреннем цикле пропускаются итерации в случае отрицательных или равных нулю величин y, а во внешнем – цикл прервется, если величина p превысит 1. Задачи для самостоятельного решения 57
n
1. Дано натуральное число n. Вычислить
2k
∑ (k + 1)(k k =1
2
+ k)
.
2. Дано натуральное число n. Вычислить n
∑ k =1
k!+ k n − k +1 k
7 k k + C (i + 2)
.
i =0
3. Найти значения полинома у = 8m + 4.3m2 -1,46m3 для 1.0 ≤ m ≤ 5.9 с шагом hm = 0.1 . 4. Еще один алгоритм Евклида для нахождения НОД неотрицательных целых чисел основан на следующих свойствах этой величины. Пусть m и n - одновременно не равные нулю целые неотрицательные числа и пусть m ≥ n. Тогда, если n=0, то НОД(m,n)=m, а если n ≠ 0, то для чисел n, m и r , где r - остаток от деления m на n, выполняется равенство НОД(m,n)=НОД(n,r). Например, НОД(15,6)=НОД(6,3)=НОД(3, 0)=3. Даны натуральные числа n, m. Используя алгоритм Евлида, найти их наибольший общий делитель. 5. Вычислить y = 3 + 6 + ... + 96 + 99 . 6. Дано
действительное число х ≠ 0 . Вычислить функ3 5 7 цию y = x − 3 + 5 − 7 + ... . Вычисления прекратить, когда x x x очередной член будет по абсолютному значению меньше 1 0-6 . 7. Дано натуральное число n. Вычислить сумму и произведение его цифр. 8. Дано натуральное число n >2. Вывести на экран все простые числа из диапазона [2,n]. 18 Массивы Массивом называют последовательность однотипных данных, имеющих один идентификатор - имя и различающихся по номерам (индексам) в этой последовательно58
сти.
Чтобы задать массив необходимо указать имя массива, тип его элементов, количество индексов (размерность массива), диапазоны изменения индексов. 18.1 Одномерные массивы Описание одномерных массивов имеет вид
: array [] of ; - это поддиапазон любого перечислимого типа (1 .. 10, Mon .. Sat, ‘A’ .. ‘Z’ и др.). Типом элементов массива может быть любой простой тип. Кроме того, элементами массива могут быть другие массивы. Переменные массивного типа описывают, как и остальные переменные в разделе Var. Примеры: A: array[l ..10] of integer; {массив с индексами от 1 до 10, элементы массива целые числа} В: array['А' . . ' Z ' ] of Real; {массив с индексами от 'А' до ‘Z’ , элементы массива - вещественные числа} С: array[10 .. 20] of Char; {массив с индексами от 10 до 20, элементы массива - символы} D: array[1..3] of array[1..2] of real; {массив с индексами от 1 до 3, его элементами являются другие массивы}
Если два массива А и В однотипные, то допускаются следующие операторы присваивания: А: = В; В: = А; Необходимо отметить, что элементы массивов имеют те же свойства, что и обычные переменные соответствующих ти59
пов. Доступ к элементу массива в программе осуществляется по его номеру — индексу, который указывается в квадратных скобках. Примеры: 1) A[1]: = 7; A[2]: = A[6]; A[6]:=AQR(f); На месте индекса элемента массива может стоять идентификатор переменной . В этом случае во время выполнения программы будет осуществлена подстановка – значение этой переменной. Примеры: 1) i:=7; A[i] := 23; {-> А[7] : = 23;} 2) for j:= 1 to 10 do A[j]:= j*j; Одномерный массив можно представить как вектор c элементами (А1, А2,..., АN). Часто приходится вводить элементы массива с клавиатуры, для этого проще всего использовать цикл: for i: = 1 to n do read (A[i]) ;
или с выводом сообщения: for i:= 1 to n do begin Writeln('введите А[' , i , ']'); Readln(A[i] ) ; end; 60
Подобным образом можно организовать вывод элементов массива на экран. Например, в строку без комментариев: for i:= 1 to n do Writeln(А[i] : 4);
или в столбец и с комментариями: for i:= 1 to n do Writeln('А[' , i , ']= ' , A[i]);
Как правило, и любые другие операции с элементами массива осуществляются в цикле, и лучше всего для этих целей подходит цикл типа for … do. Часто размер массива приходится несколько раз изменять во время отладки программы. Изменение диапазона в описание массива влечёт за собой изменение параметров цикла и возможно других переменных. Можно облегчить подобные преобразования, если при указании диапазона изменения индексов использовать нетипизированные константы. Задача. Ввести массив с клавиатуры, найти максимальный и минимальный элементы. program p18; const n = 10; var A: array[1, n] of real; i: integer; max, min: real; begin {ввод элементов массива} Writeln(‘введите элементы массива, ‘ , n, ‘ элементов'); for i:= 1 to n do Read (A [i] ); {поиск максимума и минимума} max:= А [ 1] ; min:= A [ l] ; for i:= 2 to n do begin 61
if A[i] > max then max:= A[i] ; if A[i] < min then min:= A[i]; end; {вывод максимума и минимума} Writeln('max= ', max, ' min= ‘ , min); end. Задача. Элементы массива вводятся с клавиатуры, заменить в нем все отрицательные элементы их квадратами, а положи-тельные - кубами. Вывести на экран исходный и новый масси-вы. program p19; const n = 10; Var А, В: array[ 1.. n] of real; i: integer; begin {ввод элементов массива} Writeln(‘введите элементы массива, ‘ , n, ‘ элементов'); for i:= 1 to n do Read (A [i] ); B:=A; {запомнили исходный массив } For i:= 1 to n do if A[i] < 0 then A[i] := sqr(A[i]) else if A[i] > 0 then A[i] := sqr (A[i] ) * A[i] ; {вывод элементов массивов} Writeln('Исходный массив: ') ; for i:= 1 to n do Write (B[i] : 8: 4) ; Writeln; Writeln('Новый массив: '); for i:= 1 to n do Write(A[i]: 8: 4) ; 18.2 Сортировка одномерного массива Сортировкой называют набор операций, упорядочивающий массив в соответствии с индексами, на множестве 62
которых изначально определено отношение порядка. Вопрос о возрастании или убывании упорядоченного массива для нас не принципиален. Как правило, программы, сортирующие массив по возрастанию, легко изменяются для сортировки по убыванию. Существует множество алгоритмов сортировки (пузырьковая сортировка, сортировка по дереву, быстрая сортировка, сортировка слиянием, сортировка Шелла и т. д.), они имеют большую практическую значимость, являются фундаментальными в некоторых областях информатики. В данном пособии мы приводим не самый лучший, но, безусловно, самый распространенный и очень понятный алгоритм пузырьковой сортировки. Название «Пузырьковая сортировка» происходит от образной интерпретации, по которой алгоритм заставляет «легкие» элементы мало-помалу всплывать на «поверхность». Суть алгоритма такова. Начиная с первого, сравниваются два соседних элемента массива A[i] и A[i+l], если A[i] > A[i+1], то элементы меняются местами. В первый раз мы проходим массив начиная с индекса 1, до индекса n - 1, во второй с 1 до n - 2 и т. д. Любой массив будет отсортирован за n проходов. Таким образом, порядок сложности данного алгоритма (максимальное количество операций проверок и перестановок 2 элементов массива) пропорционален n /2, что характерно для многих алгоритмов сортировки, хотя массив может быть отсортирован уже после первого прохода. Наиболее очевидное усовершенствование данного алгоритма состоит в том, что можно следить за перестановками: если при очередном проходе не было перестановок, значит массив уже упорядочен и требуется завершить сортировку. program p20; const n= 10; var 63
a: array [1.. n] of Real; i, j : integer; temp: Real; Change: Boolean; begin {ввод элементов массива} Writeln (' введите элементы массива, ', n, ' элементов ' ) ; for i := 1 to n do Read (A [i] ) ; {сортировка} j:= 0; repeat change := false; j := j + l; for i : = 1 to n - j do if A[i] > A[i + l] then begin change := true; {... если A[i] > A[i+l]} {то элементы меняются местами} temp : = A [i+1] ; A[i+1] := A[i]; A[i] := temp; end; {прекращаем сортировку, если не было перестановок} until not change; {выводим на экран отсортированный массив} for i:= I to n do Write (A [i] : 6: 2) ; Writeln; end. 18.3 Массивы с большей размерностью Мы уже знаем, что возможна организация массива массивов, а точнее элементами массива могут быть другие массивы. Описание массива в этом случае может выглядеть так: ...: array[... ] of array... 64
Подобная запись достаточно громоздка (несколько раз записывается служебное слово array и т. д. ), но синтаксис языка Паскаля позволяет описывать многомерные массивы проще. : array [] of ; Примеры: 1) М: array[1.. 3] of array [1.. 3] of Real; Подобное описание эквивалентно следующему: М: array [1.. 3, 1.. 3] of Real; В первом случае доступ к простому элементу осуществляется так: M[i][j], а во втором M[i, jl . 2) Т: array[1 .. 2, 1 .. 3, 1 .. 4] of Integer; U: array[1 .. 10, 'A1 .. 'Z'] of char; Работа с n-мерными массивами заставляет программиста организовать n вложенных циклов. Подробнее остановимся на двумерных массивах. Двумерные массивы используются, в основном, для определения матриц с индексами, изменяющимися по строкам и по столбцам. А[1, 1] , А[1, 2] , . . . , A[l, N] А[2, 1] , А[2, 2] , . . . , А[2, N] А[М, 1] , A[M, 2] , . . . , А[М, N]
С элементами двумерных массивов можно работать, указывая два индекса (номер строки и номер столбца) через запятую в квадратных скобках. Примеры: М[1, 2] := 7; 65
М[7, 5] :=46; M[i, j]:= 75; M[k, 1] := SQR(M[i,
j]
+ M[j,
i] ) ;
Ввод элементов двумерного массива по строкам: for i := 1 to n do for j:= 1 to m do Read (M[i, j]);
или с сообщениями: for i:= 1 to n do for j:= l to m do begin Write('введите М[', i, ‘, ‘ , j, '] '); Readln(M[i, j]); end;
Вывод элементов двумерного массива в виде матрицы: for i:= 1 to n do begin for j:= 1 to m do Write(M[i, j] : S: 3) ; Writeln; end; Часто при работе с двумерными массивами (матрицами) приходится оперировать с элементами, обладающими некоторыми признаками, в частности, связанными с положением элементов относительно диагоналей матрицы. Например, элемент находится на главной диагонали рисунок 1a, на побочной диагонали рисунок 2б, ниже главной диагонали, ниже побочной и т. д. (рисунки 1в÷ж).
a)
б)
в)
г) 66
д)
е) Рисунок 1
ж)
Положение этих элементов может быть описано следующими математическими отношениями: - на главной диагонали - { M[ i , j ] | i = j} - выше главной диагонали - { M[ i , j ] | i < j} - выше главной и выше побочной диагонали – { M[ i , j ] | i < j } ∩ { M[ i , j ] | i - не применяются. Чтобы добавить в множество какой-либо элемент, можно добавить множество, состоящее из единственного элемента. Либо использовать процедуру include(S,a) , где S – множество, в которое добавляем, a – добавляемый элемент. Имеется и обратная процедура – exclude(S , a) - для исключения элемента из множества. Здесь параметры S и a имеют тот же смысл. Пример: program p43; var S: set of ‘A’ .. ‘Z’ ; 92
ch: char; Begin S := [ ]; ch := ‘A’; repeat S := S+[ch] ; Inc(ch); Until ch >= ‘Z’ ; ……………………..
Задачи для самостоятельного решения Написать программу, осуществляющую алгоритм решета Эратосфена для получения всех простых чисел, не превосходящих заданного натурального числа n . Алгоритм состоит в следующем: последовательно, начиная от двух, находим простое число и вычёркивают все числа, кратные найденному числу и не превосходящие n. 23 Процедуры и функции описанные пользователем Начальные сведения о процедурах и функциях даны в разделе "Использование стандартных процедур и функций". Мы познакомились с описанием заголовков, классификацией параметров и т. д. Кроме того, мы уже упоминали о том, что структура процедур и функций во многом повторяет структуру программы. Например, описание процедуры имеет вид: procedure ( ) ; const type var label 93
begin end;
и описание функции : function ( ) : ; const type var label begin end;
Функция через свой идентификатор передает значение определенного в заголовке типа. Для этого в теле функции записывается следующий оператор присваивания: : = ; Формальные параметры в процедуре или функции не отличаются от других описанных в ней переменных и могут быть использованы как переменные. Описательные разделы (type, const и др. ) могут отсутствовать, чередоваться, повторяться, если это не нарушает внутренней логики и правильности программы. Надо отметить, что непосредственно в самих процедурах или функциях можно описывать другие процедуры и функции. Возможность описания и использования процедур, вложенных процедур и т. д. заставляет задуматься над использованием переменных, описанных в подпрограммах. Для решения 94
этой проблемы приведем следующие правила локализации переменных. 1. Глобальными переменными называются переменные, описанные в основной программе. Они доступны в любом ее месте и во всех ее подпрограммах. 2. Подпрограмма описывается в некотором описательном разделе назовем его внешним и сама имеет описательный раздел - назовем его внутренним. Локальные переменные - это переменные, описанные в процедурах и функциях, они доступны во всех частях данной подпрограммы и в любых внутренних описательных разделах, но недоступны в тех блоках программы, которые соответствуют внешним описательным разделам. Пример: program p34; var х: Integer ; procedure proс1; var у: Integer; procedure proc2; var z: Integer; begin {тело процедуры ргос2} {доступны переменные: х, у, z} end; begin {тело процедуры prod} {доступны переменные: х, у} end; begin {тело программы} {доступна переменная: х} end. 95
Задача: Написать функцию для возведения целых чисел в натуральную степень. program р35; function fstep(x, n: integer) : Longint; {x - целое число, n - натуральная степень } var i: integer; p: Longint ; begin p:= x; for i:= 2 to n do p:= p * x; fstep:= p; {- значение функции} end; begin Writeln (fstep (3 , 3)); Writeln (fstep (5, 6) ) ; Writeln(fstep(7, 4)); end. Задача: Решить предыдущую задачу используя процедуру. program рЗб; procedure pstep(x, n: integer ; Var p: Longint); {x целое число, n - натуральная степень, р результат выполнения процедуры, передаваемый через параметр-переменную} var i: integer; begin p:=x; for i: = 2 to n do p := p * x; end; var 96
k: Longint; begin pstep(3, 3, k); Writeln(k); pstep (5, 6, k) ,Writeln(k); pstep (7, 4, k); Writeln(k); end. Задача: Используя символы псевдографики, напишите процедуру, выводящую на экран прямоугольное окно с рамкой и заголовком. Параметры окна должны задаваться при вызове процедуры. program p37; uses crt; procedure Wind(x, у, k, h: Integer; s: string); var i: integer; begin { '┌’ , ' ┐’ , '┘' , '└ ' , ' | ‘ , '─' набор символов для рисования рамки} {выводим углы} gotoxy(x, у); write( '┌ ‘); gotoxy(x + k, у); write('┐'); gotoxy(x + k, у + h) ; write('┘'); gotoxy(x, у + h) ; write( '└'); {в цикле выводим символы горизонтальных линий рамки} for i:= 1 to k - 1 do begin gotoxy (x + i, y) ; write ( ' - ' ); gotoxy(x + i, у + h ); write('-'); end; {в цикле выводим символы вертикальных линий рамки} 97
for i := 1 to h-1 do begin gotoxy(x, у + i); write(' | ' ) ; gotoxy(x + k, у + i); wri te(' | ') ; end; {выводим заголовок окна} gotoxy(x + (1 - length (S)) div 2 ); write(S); end; begin clrscr ; Wind(2, 3, 20, 6, ‘Oкно № 1'); end. 24 Параметры-переменные не имеющие типа
Если в качестве формального параметра используется параметр-переменная, для которой тип не указан, то фактический параметр связывается с формальным параметром как с ссылочной переменной. При этом совмещаются физические адреса фактического и формального параметров, а интерпретация данных производится по типу фактического параметра. При использовании формального параметра без типа внутри процедуры необходимо приводить его к ожидаемому типу, т. е. параметр указывается в круглых скобках после имени типа. Связываемый с такими параметрами тип является фиктивным, но он определяет форму доступа к компонентам данных. Примеры: Integer(m) Real(t) Char(g) String(h) В следующей программе описана процедура с параметром без типа, а в теле процедуры параметр сначала интерпретируется и выводится на экран как целое значение, затем как 98
вещественное и строковое. В теле программы процедура вызывается три раза: с параметром переменной целого типа (при этом ее интерпретации в процедуре как вещественного числа и строки - бессмысленны), вещественного и строкового. Пример: program p38; procedure proc (var t) ; begin writeln(integer(t)) ; writeln(real(t)); writeln(string(t)) end; var i integer; r real ; s string; beg in i = 2323; bol(i) ; r = 12. 232; bol (r) ; s = ' ABCD ' ; bol(s) ; end. 25 Процедурные типы Часто возникает необходимость использовать процедуры и функции в качестве формальных параметров. В этом случае среда турбо-Паскаля дает возможность описать специальный процедурный тип. type : ргоcedure (); 99
: function ( : ; По существу, запись объявления типа полностью совпадает с записью заголовка процедуры или функции, за исключением того, что в ней опущен идентификатор процедуры (или функции). Примеры: Proc = procedure; SwapProc = procedure(var x, у: integer); StrProc = procedure(s: string); MathFunc = function(x: real): real; DeviceFunc = function(var f: text): integer; MaxPunc = function(a, b: real; f: MathFunc): real; Для работы с переменными процедурного типа, необходимо процедуры и функции, используемые в процедурных присваиваниях и вызовах, описывать как подпрограммы с межсегментной адресацией (дальним вызовом). Для этого после заголовка подпрограммы ставиться служебное слово far. Примеры: program р39; type TProc = procedure; procedure Exec_Proc( р: TProc); begin p; end; procedure p1; far; begin Writeln('процедура №1'); end; procedure p2; far; begin Writeln('процедура №2') ; end; 100
procedure p3; far; begin Writeln ('процедура №3’) ; End; var p: TProc; begin p:= p1; Exec_Proc(p); Exec_Proc(p2); Exec_Proc(p3); end. program p40; type TFunc= function(x: real): real; procedure Func_Tab(f: TFunc; a, b, h; real); var x: real; begin x: = a; While x 0) and (p. у > 0)) or ((р. х < 0) and (p. у < 0)) then {если точка принадлежит первой или третьей четверти, то выводим ее во второй файл; данное условие можно было записать проще, но менее понятно: if p.x*p. y>0 then... } Write(f2, p); end; nl:=FileSize(f1); {получаем объем первого файла} n2:=FileSize(f2); {... второго} Writeln('nl= ', nl, ' n2 = ', n2); Close(fl); {закрываем файлы} Close (f2) ; end. Если мы открываем файл в программе, то неплохо бы предвидеть различные аварийные ситуации: отсутствует файл с таким именем, не вставлен диск в дисковод и др. При возникновении подобных ситуаций в обычном режиме программа прерывается по ошибке. Но существует возможность избежать этого: директива компилятору {$i-} выключает режим проверки и реакции на ошибки ввода/вывода, а директива {$i+} включает. Однако продолжить выполнение программы в аварийной ситуации недостаточно, важно запрограммировать реакцию на нее - обработать ошибку. Для этого предназначена функция IOResult (результат выполнения операции ввода/вывода). function IOResult: Integer; Функция возвращает целое значение. Если операция ввода/вывода не привела к ошибке, то ее значение ноль, в противном случае функция возвращает номер ошибки. Если ошибка произошла, то все последующие операции ввода/вывода игнорируются до тех пор, пока не будет вызвана функция IOResult. 112
Номера ошибок: Disk read error (ошибка диска при чтению); Disk write error (ошибка диска при записи); File not assigned (файловая переменная не связана с физическим файлом); 103 File not open (файл не открыт); 104 File not open for input (файл не открыт для ввода); 105 File not open for output (файл не открыт для вывода); 106 Invalid numeric format (недопустимый числовой формат). Задача. Проверить существует ли файл с введенным с клавиатуры именем. Если существует, то получить файл с новым именем, в котором порядок следования компонент - байт, изменен на обратный. program p4 9; var fl, f2: file of byte; b: byte ; sl, s2: String; n, i: Longint; begin Write('введите имя исходного файла '); Readln(sl); Write('введите имя результирующего файла '); Readln(s2); Assign(fl,s1);{связываем файловые переменные с } Assign{f2,s2);{введенными именами файлов} {$i-} {- отключаем контроль ошибок в/в} Reset (f1); {первый файл открываем для чтения) if IOResult 0 then begin Writeln('Произошла ошибка, файл ', s1,'не существует'); Halt; {прерываем программу} end;
100 101 102
113
{$I+} {- включаем контроль ошибок в/в } Rewrite(f2); { второй файл для записи} n:= FileSize (f1); for i:= n - 1 downto 0 do begin Seek(fl, i); {- устанавливаем указатель на i-ую компоненту первого файла} Read(fl, b); {- читаем эту компоненту} Write(f2, b); {и записываем во второй файл} end; Close(fl); {закрываем файлы} Close (f2) ; End. Задача. Создайте программу, осуществляющую поиск по начальной части фамилии автора и выводящую на экран подходящие записи из файла о книгах (программа р47). program p50; type Books = record N: Integer; Avtor: String[45]; Nazv: String[70]; Str: Integer; God: Integer; end; var bf: file of Books; r: Books; i: integer; s: String; begin Writeln('Введите начальную часть фамилии автора'); Readln(s); Assign(bf, 'bibl.dat’); {Si-} {- отключаем контроль ошибок в/в} 114
Reset(bf); {файл открываем для чтения} if IOResult 0 then begin Writeln('Произошла ошибка, файл bibl.dat не существует'); Halt; (прерываем программу} end; {$I+} {- включаем контроль ошибок в/в} While not Eof(bf) do begin Read(bf, r); { Функция Pos(SubS, S: String): Byte возвращает позицию, начиная с которой в строке S располагается подстрока SubS (0 - S не содержит SubS).} if pos(s, r. avtor) = 1 then Writeln(r. n: 3, r. avtor: 12, r. nazv: 14, r. str: 6, r. god: 8) ; end; Close(bf) ; end. Для работы с файловой системой нам могут понадобиться следующие процедуры из модуля System: procedure ChDir(s: string); Процедура изменяет текущий каталог. Здесь s-выражение, содержащее путь к новому каталогу. Пример: program p51; Var S: String; begin Write('Введите путь к каталогу'); Readln(S); {$i-} ChDir(S); if IOResult 0 then Writeln('Данный каталог отсутствует'); 115
end.
Следующая процедура procedure GetDir(d: byte; var s: string); - возвращает имя текущего каталога для заданного логического диска. Здесь d – выражение целого типа; s -параметр переменная. (d=0 - означает текущий логический диск, d=1 - диск A, d=2 - диск В и т. д.) Пример: program p52 ; var s: String; begin GetDir (0, s) ; Writeln (' текущий каталог ', s); end. Процедура procedure MkDir(s: string); создает новый каталог. Здесь s - строковое выражение, содержащее путь и имя каталога. Следующая процедура procedure RmDir(s; string); удаляет пустой каталог. Здесь s - путь и имя каталога. Пример: program р53; var S: String; begin S : = ' ABCD ' ; {создаем новый каталог} MkDir(S) ; { . . . и сразу его удаляем} RmDir (S) ; end. Процедура procedure Erase(var j); удаляет файл. Здесь f- переменная файлового типа, связанная 116
с именем внешнего файла с помощью процедуры Assign. Пример: program p54; var F: file; Ch : Char ; S: String; begin Write (' Введите имя удаляемого файла ')/' Readln(S); Assign(F, S) ; {Si-} Reset (F) ; if lOResult 0 then Writeln (' файл ' , S, ' отсутствует') else begin Close (F) ; Write ( 'Удалять ', S, '? (y/no) ' ) ; Readln(Ch) ; {Function UpCase(C: char): Char Преобразует латинскую букву в заглавную.} if UpCase(Ch) = 'Y' then Erase (F) ; end; end. Процедура procedure Rename(var f; newname: string); переименовывает файл. Здесь f - переменная файлового типа; newname - строка, содержащая новое имя внешнего файла. Пример: program p55; var f: file; S1, S2: String; begin 117
Write('Введите имя файла'); Readln(S1); Write('Введите новое имя файла '); Readln(S2); Assign(f, S1); Writeln{'Файл ', S1, ' переименован в ', S2); Rename(f, S2} ; end. Задачи для самостоятельного решения 1. Дан файл f, компоненты которого являются целыми числами. Переписать в файл g все компоненты файла f являющиеся точными квадратами. 2. Дан символьный файл f. Получить файл g, образованный из файла f заменой всех его прописных (больших) букв одноименными строчными (малыми). 3. Дан файл содержащий сведения о веществах. Указывается название вещества, его удельный вес и проводимость (проводник, полупроводник, диэлектрик). Вывести на экран названия и удельные веса всех полупроводников. 4. Дан файл, содержащий сведения о различных датах. Каждая дата это число, месяц, год. Найти самую позднюю дату. 5. Написать программу, выводящую на экран все подкаталоги корневого каталога диска С, имена которых состоят не более чем из четырех символов. 26.2 Текстовые файлы В DOS текстовые файлы физически не отличаются от любых других, но в Паскале различия существенны. Элементами текстовых файлов являются символы, объединенные в строки, но текстовый файл это не file of Char или file of String. Каждая строка заканчивается в текстовом файле символом возврата каретки CR=#13 и перевода строки LF=#10. Заканчивается текстовый файл признаком конца файла SUB=#26. Работа с текстовыми файлами очень напоминает работу с консолью. 118
Чтение из текстовых файлов очень похоже на ввод с клавиатуры, а запись в файл напоминает вывод на экран. Указатель в текстовом файле имеет много общего с текстовым курсором. Доступ к элементам текстового файла организуется последовательно. Указатель при считывании очередного элемента файла перемещается к следующему элементу. Для записи в текстовый файл или чтения их него можно использовать процедуры Read, Readln, Write, Writeln. В качестве первого параметра в этих процедурах указывается файловая переменная, например: Read(fp, a, s); Здесь происходит присваивание переменным a и s значений двух очередных элементов их файла, связанного с файловой переменной fp. При выполнении программы на Паскале автоматически открываются два стандартных файла текстового типа. Стандартные файлы имеют имена файловых переменных Input и Output. Стандартная файловая переменная Input представляет собой доступный только для чтения файл для ввода символов с клавиатуры. Вторая файловая переменная Output связана с доступным только для записи стандартным устройством вывода символов и графических элементов на экран монитора. Обращение к файлам Input и Output.происходит автоматически, без каких-либо дополнительных средств с помощью операторов Read, Readln, Write, Writeln. Имя файла в этих процедурах не указывается, если работа ведётся со стандартным файлом. Приведём пример переназначения стандартных файлов (т.е. ввод с клавиатуры и вывод на экран) дисковым файлам. program p73; var N, M: longint; ………. begin assign(Input, 'c:\test.txt'); reset (Input) ; 119
……………. Read(N, M); …………….. close (Input); ………………… assign(Output, 'c:\test_rez.txt'); rewrite(Output) ; ……….. Write(N, M); ………………. close (Output) ; end. Таким образом, эта программа введёт значения переменных N и M из текстового файла test.txt и выведёт результаты работы (значения переменных N и M) в файл test_rez.txt . Файловая переменная для текстового файла описывается следующим образом: :Text; При работе с текстовым файлом, файловую переменную связывают с именем файла, обращаясь к процедуре Assign, а открывают для чтения и записи процедурами Reset и Rewrite соответственно. Процедура Reset открывает текстовый файл только для чтения. Открытый файл закрывается с помощью процедуры Close. В текстовый файл, как и на экран, мы можем выводить значения выражений практически любого типа. При выводе значений операторами Write и WriteLn можно пользоваться стандартными средствами форматирования данных. Примеры: Write(f, x: 6: 4); Writeln(g, 'Т= ' , f 5: 2) ; После вывода оператором Write указатель текстового файла остается в конце выведенной строки, a WriteLn - переходит на начало следующей. Примеры: 120
program p56; {Программа выводит в текстовый файл матрицу n*m} const n= 3; m= 4 ; var Т: array[1.. n, 1.. m] of real; f: Text; {описываем файловую переменную} S: String; i, j: integer; begin Writeln('введите элементы матрицы ', n, '*', m) ; For i:= 1 to n do for j : = 1 to m do begin Write ('T[' , i, *, ' , j, '] = ') ; Readln(T[i, j ] ) ; end; Writeln('введите имя файла'); Readln(s); Assign(f, s); {связываем файловую переменную с именем файла} {$i-} Rewrite(f); {открываем текстовый файл для записи} If IOResult 0 then begin Writeln('Ошибка при открытии файла'); Halt; end; {$i+} for i:= 1 to n do begin for j:= 1 to m do Write(f, T[i, j] : 8: 3) ; Writeln(f) ; 121
end; Close (f); end. program p57; {Программа читает матрицу n*m из текстового файла} const n= 3; m= 4; var Т: array[1.. n, 1.. m] of real; f: Text; S: String; i, j: integer; begin Writeln('введите имя файла'); Readln(s); Assign(f, s); {$i-} Reset(f); {открываем текстовый файл для чтения} if lOResult 0 then begin Writeln('Ошибка при открытии файла'}; Halt; End; {$i+} for i:= 1 to n do begin for j:= 1 to m do begin Read(f, T[i, j] ) ; Write(T[i, j] : 8: 3); end; Writeln; End; 122
Close(f); end. Задача. Дан текстовый файл, создать второй текстовый файл, уплотнив первый, заменяя в каждой строке серии из двух или более пробелов (32 - ASCII) одним пробелом. program р58; var fl, f2: Text; S: String; Sl, S2: String; {функция параметром получает неуплотненную строку, а возвращает уплотненную} function Uplot(S: String): String; var Z: boolean; begin Z:= false; repeat if pos(' ', S) 0 then Delete (S, pos (' ', S) , 1) else Z:= true; Until Z; Uplot:= S; end; begin Write ('введите имя исходного файла '); Readln(sl); Write('введите имя файла с результатом'); Readln(s2); Assign(fl, s1); Assign(f2, s2) ; {$i-} Reset(fl); if lOResult 0 then 123
begin Writeln('Произошла ошибка, файл ', s1, 'не существует'); Halt ; end; {$i+} Rewrite(f2); While not Eof(fl) do begin Readln(fl, S); Writeln(f2, Uplot(S)); end; Close(fl) ; Close(f2) ; end. Задача. Даны два текстовых файла. Вывести на экран количество строк в первом и во втором файлах. Если количество строк одинаковое, то вывести на экран те строки второго файла, которые отличаются от соответствующих строк первого. program p59; const Namel = 'filel. txt'; Name2= ‘file2. txt'; var fl, f2: Text; L, K: Integer; S1, S2: String; begin Assign(fl, Namel); Assign(f2, Name2); {$i-} Reset(fl) ; Reset(f2) ; 124
if IQResult 0 then begin Writeln('Ошибка при открытии файлов'); Halt; end; {находим количество строк в первом файле} L:= 0; While not Eof(fl) do begin Readln(fl); inc(L); end; {находим количество строк во втором файле} К:= 0; While not Eof(f2) do begin Readln(f2); inc(K); end; Close (fl) ; Close (f 2) ; Reset (fl) ; Reset (f2) ; if К L then begin Writeln('файл ', namel, ' - ', L, ' строк' ); Writeln('файл ', namе2, ' - ', К, ' строк’ ); end else begin K:= 0; While not Eof(fl) do begin Readln(fl, SI) ; Readln(f2, S2); Inc(K); 125
if S1 S2 then begin Writeln(' (' , K, '): ' , S1) ; Writeln(' (', K, ') : ' , S2) ; end; end; end; Close (fl) ; Close (f2); end. Иногда необходимо открыть текстовый файл для записи, и, не удаляя находящуюся в нем информацию, дописать что-то в его конец. procedure Append(var f: Text); Процедура Append открывает текстовый файл для дозаписи. Если файл с именем, указанным в Assign, не существует, то вызов процедуры Append приведет к ошибке. Пример: program р60; {Программа дописывает в текстовый файл с матрицей новую матрицу - результат транспонирования первой} Const n = 3; m = 4; var Т: array[1..n, 1.. m] of real; ТТ: array[1.. m, 1.. n] of real; f: Text; S: String; i, j: integer; begin Writeln('введите имя файла'); Readln(s); Assign(f, s); 126
{$i-} Reset (f) ; if IOResult 0 then begin Writeln('Ошибка при открытии файла'); Halt; end; for i : = 1 to n do for j := 1 to m do begin Read(f, T[i, j] ); TT[j, i] := T[i, j] ; end; Close (f); {закрываем файл} {и повторно открываем его для до записи} Append ( f ) ; {выводим в файл пустую строку разделитель матриц) Writeln(f ) ; for i:= 1 to m do begin {выводим матрицу} for j := 1 to n do Write (f , TT[i, j] : 8: 3) ; Writeln(f) ; end; Close (f) ; end.
Полезны для работы с текстовыми файлами три стандартные логические функции (ниже f - файловая переменная): • EOLN(f) – возвращает значение true, если в файле достигнут конец строки, false – в противном случае; • SEEKEOLN(f) – пропускает пробелы и знаки табуляции до конца строки или до первого значащего символа и возвращает значение true, если достигнут конец строки, false – в противном случае; 127
•
SEEKEOF(f) – пропускает все пробелы, знаки табуляции и маркеры конца строки до конца файла или до первого значащего символа и возвращает значение true, если достигнут конец файла, false – в противном случае.
Задачи для самостоятельного решения 1. Написать программу, формирующую текстовый файл, состоящий из 9 строк, в первой из которых - одна литера «1», во второй - две литеры «2», ..., в девятой - девять литер «9». 2. Дан текстовый файл. Подсчитать в нем количество слов, у которых первый и последний символы совпадают между собой. 3. Дан текстовый файл f. Записать строки файла f в файл g. Порядок слов в строках файла g должен быть обратным по отношению к порядку слов в строках исходного файла. 4. Дан текстовый файл. Написать программу, которая, игнорируя исходное деление этого файла на строки, переформатирует его, разбивая на строки так, чтобы каждая строка оканчивалась точкой, либо содержала ровно 60 символов, если среди них нет точки. 5. С клавиатуры вводится имя текстового файла. Написать программу, выводящую содержимое этого файла на экран или сообщение об отсутствии данного файла в текущем каталоге. 27 Указатели Все структуры, переменные, с которыми мы познакомились ранее, являлись статическими. Для данных объектов память выделяется в самом начале выполнения программы, а их размер не может быть изменен во время её выполнения. Структуры данных, размер которых можно изменять во время выполнения программы, называют динамическими. Например, массив с переменной длинной называют динамическим массивом. Обращение к динамическим объектам производится по 128
их адресу в памяти. Для хранения адреса динамической переменной используется ссылочный тип, а переменная ссылочного типа называется указателем. Значением переменной типа «указатель» является либо nil, либо адрес динамической переменной и занимает она двойное слово (сегмент, смещение). Указатели бывают типизированные и нетипизированные. Для типизированного указателя описание ссылочного типа имеет вид: Type : ^ ; Например: Type arr = array[1..100] of real; par = ^arr; pint = ^int; Var a: par; {а – указатель на массив } n: pint ; {n – указатель на целое } b: array[1..5] of ^real; {массив указателей на переменные вещественного типа} Встроенный тип Pointer обозначает нетипизированный указатель, т.е. указатель, который не указывает ни на какой определённый тип. Для порождения динамического объекта служат стандартные процедуры New и GetMem. procedure New( var P:); procedure GetMem(var P: Pointer; Size:Word); Процедура New выделяет участок памяти, необходимый для размещения всей переменной указанного типа, а в процедуре GetMem указывается размер необходимого блока памяти. В программе доступ к динамическому объекту происходит через переменную-указатель, после которой ставится символ ^. Пример. program р72 ; 129
var pi : ^Integer;
{описываем указатель на целую переменную} рг: ^ Rеа1; {описываем указатель на вещественную переменную} begin {выделяем память для первой динамической переменной} New (pi) ; {присвоим значение динамической переменной} pi ^: = 25; Writeln (рi^) ; {выводим ее значение на экран} {выделяем память для первой динамической переменной} New(pr) ; pг ^:= 0.5; Writeln (рr^) ; {выводим ее значение на экран} end. Процедурой GetMem удобно пользоваться, когда необходимо создать структурированную динамическую переменную, например, динамический массив. В массиве элементы имеют один тип. Размер, занимаемый n элементами массива, можно получить умножив размер одного элемента на n. А размер элемента возвращает функция SizeOf. function SizeOf(): integer; Динамические переменные удаляются из памяти процедурами Dispose или FreeMem. procedure Dispose(var P:); Эта процедура освобождает весь участок памяти, выделенный под данную динамическую переменную. procedure FreeMem(var P: Pointer; Size: Word); Данная процедура освобождает участок памяти, размер которого определяет параметр Size. Приведённые процедуры обычно используются 130
парно: процедура Dispose с процедурой New, a. FreeMem - с Get Мет. Пример. program p73; type Element= Integer; DArray= array [1.. 2] of Element; var PA: ^DArray; n, i: integer; begin Write('Введите количество элементов '); Readln(n); {выделяем необходимый участок памяти для динамического массива} GetMem(PA, SizeOf(Element) * n) ; {введем элементы массива с клавиатуры} for i:= 1 to n do Read(PA^[i]); {выведем массив на экран} for i: = 1 to n do Write(PA^[i]: 2); FreeMem(PA, SizeOf(Element) * n); PA:=nil; ………. end. После того, как память освобождена, указателю следует присвоить значение nil во избежание в дальнейшем неприятностей. Для преобразования типов указателей используется нетипизированный указатель типа Pointer, который может иметь значение указателя любого другого типа. Пример: program p76; var р: pointer; pb: ^byte; 131
рс: ^Char; begin new(pb); pbA:= 65; p:= pb; pc:= p; writeln(pc^ ); dispose(pb); end. Задачи для самостоятельного решения 1. Дано целое число k и вещественные матрицы X[1:k,1:k] и Y[1:k+10,1:k+10]. Если наибольший элемент какой либо матрицы больше единицы, то все элементы такой матрицы разделить на этот наибольший элемент, в противном случае оставить матрицу без изменения. 2. Даны целые числа n, m и действительные матрицы а[1:п,1:п], b[1:m,1:m], с[1:п+т,1:п+т]. Преобразовать эти матрицы по следующему правилу, если элементы первой строки образуют неубывающую последовательность и наибольший диагональный элемент (то есть наибольший из элементов, находящихся на главной диагонали), неотрицателен, то упорядочить по неубыванию элементы и всех остальных строк.
132