Комплексное пособие

261
ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ ПРИОРИТЕТНЫЙ НАЦИОНАЛЬНЫЙ ПРОЕКТ «ОБРАЗОВАНИЕ» КАЗАНСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ ИМ. А.Н.ТУПОЛЕВА И.Ю. ЕЛИСЕЕВА, К.В. ШЕРШУКОВ ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ PASCAL (Программирование на языке высокого уровня, часть 1) Комплексное учебное пособие

Upload: anon769843966

Post on 28-Jul-2015

511 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Комплексное пособие

ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ

ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ

ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ

ПРИОРИТЕТНЫЙ НАЦИОНАЛЬНЫЙ ПРОЕКТ «ОБРАЗОВАНИЕ»

КАЗАНСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ

ИМ. А.Н.ТУПОЛЕВА

И.Ю. ЕЛИСЕЕВА, К.В. ШЕРШУКОВ

ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ PASCAL

(Программирование на языке высокого уровня, часть 1)

Комплексное учебное пособие

Page 2: Комплексное пособие

Казань – 2009

УДК 681.3.06

Елисеева И.Ю., Шершуков К.В.

Основы программирования на языке Pascal: Учебное пособие. – Казань: Изд-

во Казан. техн. ун-та, 2009. – 178 с.

Излагаются основы алгоритмизации и программирования на языке

высокого уровня на примере языка Pascal.

Учебное пособие содержит краткое описание основных средств языка

Pascal, примеры различных программ. Даются указания по самостоятельной

работе студентов и примеры заданий на лабораторные работы. Изложение

рассчитано на начинающих изучение программирования.

Для студентов направления подготовки бакалавров «Информатика и

вычислительная техника» и других лиц, изучающих программирование.

Табл. - , Ил. - , Библиогр. - назв.

© Елисеева Инна Юрьевна, 2009

© Шершуков Кирилл Вячеславович, 2009

2

Page 3: Комплексное пособие

Содержание

Предисловие.............................................................................................................4

Программирование на языке Pascal.......................................................................5

Эволюция языков программирования................................................................5

Алгоритмы...........................................................................................................15

Язык Turbo Pascal...............................................................................................16

Основные типы данных. Ввод-вывод...............................................................21

Операторы языка Паскаль.................................................................................39

Структурированные типы. Массивы................................................................51

Тип данных String...............................................................................................60

Структурированный тип данных - множество................................................72

Процедуры и функции.......................................................................................78

Работа с файлами................................................................................................89

Указатели и динамическая память..................................................................109

Модули Turbo Pascal........................................................................................127

Общая характеристика базовых графических средств языка Pascal...........142

Задания на лабораторные работы......................................................................152

Лабораторная работа №1. Основные приемы работы в среде Turbo Pascal

............................................................................................................................152

Лабораторная работа №2. Типы данных, выражения, ввод/вывод.............166

Лабораторная работа №3. Циклы...................................................................168

Лабораторная работа №4. Одномерные массивы.........................................171

Лабораторная работа №5. Матрицы..............................................................173

Лабораторная работа №6. Процедуры и функции.......................................176

Лабораторная работа №7. Множества, строки и записи.............................182

Лабораторная работа №8. Файлы..................................................................184

Контрольные вопросы.........................................................................................186

Литература...........................................................................................................191

3

Page 4: Комплексное пособие

Предисловие

Комплексное учебное пособие призвано обеспечить подготовку по

дисциплине «Программирование на языке высокого уровня» для студентов

вузов, обучающихся по направлению подготовки бакалавров «Информатика

и вычислительная техника».

Основу учебного пособия составляет расширенный конспект лекций по

программированию, много лет под разными названиями читаемых авторами

для студентов первого курса на кафедре прикладной математики и

информатики Казанского государственного технического университета

(КГТУ – КАИ).

Излагается теоретический материал лекционного курса, примеры

алгоритмов и программ, методические указания по самостоятельной работе

студентов примеры заданий на лабораторные работы. В качестве базового

языка используется язык Turbo Pascal.

Пособие используется совместно с пособием «Основы

программирования на языке С» (авторы А.Р. Бикмурзина, К.В. Шершуков). В

первом семестре изучается язык Pascal, в следующем семестре - язык C.

4

Page 5: Комплексное пособие

Программирование на языке Pascal

Эволюция языков программирования

История языков развития программирования тесным образом связана с

историей вычислительных машин. Даже простые арифметические операции с

большими числами затруднительны для человеческого мозга. Поэтому уже в

древности появилось простейшее счетное устройство - абак. В семнадцатом

веке была изобретена логарифмическая линейка. В 1642 году Блез Паскаль

сконструировал восьмиразрядный суммирующий механизм. В 1820 году

француз Шарль де Кольмар создал арифмометр, способный производить

умножение и деление.

Все основные идеи, которые лежат в основе работы компьютеров, были

изложены еще в 1833 году английским математиком Чарльзом Бэббиджем

(1791-1871). Он разработал проект машины для выполнения научных и

технических расчетов, где предугадал основные устройства современного

компьютера, а также его задачи. Управление такой машиной должно было

осуществляться программным путем. Для ввода и вывода данных Бэббидж

предлагал использовать перфокарты. В то время перфокарты уже

использовались в текстильной промышленности.

Первый язык программирования разработала Лавлейс Огаста Ада Кинг

(1815 – 1852) для машины Бэбиджа.

В комментариях к описанию машины, изданном в 1843 году, введены

понятия «операция», «переменная», «условный переход», «цикл». Приведена

программа для решения системы двух линейных уравнений с двумя

неизвестными

5

Page 6: Комплексное пособие

В 1888 году американский инженер Герман Холлерит сконструировал

первую электромеханическую счетную машину. Эта машина, названная

табулятором, могла считывать и сортировать статистические записи,

закодированные на перфокартах. В 1890 году изобретение Холлерита было

впервые использовано в 11-й американской переписи населения. Работа,

которую пятьсот сотрудников выполняли в течение семи лет, Холлерит

сделал с 43 помощниками на 43 табуляторах за один месяц.

    В 1896 году Герман Холлерит основал фирму Computing Tabulating

Recording Company, которая стала основой для будущей International Business

Machines Corporation (IBM).

В 1946 в США была создана первая электронная вычислительная

машина (ЭВМ) - ENIAC (Electronic Numerical integrator and Computer -

Электронный числовой интегратор и компьютер). Разработчики: Джон Мочи

(John Маuchу) и Дж. Преспер Эккерт (J. Prosper Eckert).

    Он был произведен на свет в Школе электрической техники Moore (при

университете в Пенсильвании).

    Время сложения - 200 мкс, умножения - 2800 мкс и деления - 24000 мкс.

    Компьютер содержал 17468 вакуумных ламп шестнадцати типов, 7200

кристаллических диодов и 4100 магнитных элементов.  Общая стоимость

базовой машины - 750000 долларов.

В Советском Союзе первая электронная цифровая вычислительная

машина была разработана в 1950 году под руководством академика

С.А. Лебедева в Академии наук Украинской ССР. Она называлась «МЭСМ»

(малая электронная счётная машина).

Основоположниками компьютерной науки по праву считаются Клод

Шеннон - создатель теории информации, Алан Тьюринг - математик,

разработавший теорию программ и алгоритмов, и Джон фон Нейман - автор

6

Page 7: Комплексное пособие

конструкции вычислительных устройств, которая до сих пор лежит в основе

большинства компьютеров. В те же годы возникла еще одна новая наука,

связанная с информатикой, - кибернетика, наука об управлении как одном из

основных информационных процессов. Основателем кибернетики является

американский математик Норберт Винер.

Развитие ЭВМ делится на несколько периодов. Поколения ЭВМ каждого

периода отличаются друг от друга элементной базой и математическим

обеспечением. Первое поколение (1945-1954) - ЭВМ на электронных лампах.

Их быстродействие не превышало 2—3 тыс. операций в секунду,

оперативная память не превышала 2 Кб.

Машинно-зависимые языки программирования низкого уровня –

двоичные машинные коды, Автокод, языки Ассемблера.

Таблица 1.

Год Язык (идея) Создатель ЭВМ Заметки о языке

46 Плюнкалкюль Цузе Z4 Немецкий инженер Цузе разработал этот язык

для ЭВМ Z4, но ни компилятора, ни

интерпретатора для него написано не было

(поскольку и язык, и ЭВМ он разрабатывал в

одиночку).

49 "Краткий код" Мочли Юнивак По своей сути, это была система обозначений

для быстрого ввода в ЭВМ алгебраических

выражений."Краткий код" работал как

примитивный интерпретатор.

49 Идея

подпрограммы

Грейс

Хоппер

Марк-1 Программисты под руководством Хоппер

впервые во всем мире реализовали идею

подпрограмм как многократно используемую

последовательность команд. Тогда они

просто переписывали куски машинного кода

друг у друга из блокнотов.

7

Page 8: Комплексное пособие

50 Ассемблер Грейс

Хоппер

Эдсак Первый ассемблер представлял из себя

систему мнемонических обозначений,

объединённую с библиотекой подпрограмм

52 АВТОКОД Гленн Марк-1 Автокод был первым полноценным

транслятором (компилятором), т.е. он

транслировал мнемоническую схему в

машинные коды.

52 А-0 Грейс

Хоппер

Юнивак А-0 был первым полноценным ассемблером,

получившим широкую известность. Он

предоставлял услуги как компилятора, так и

компоновщика.По сути, А-0 представлял

первое промышленное средство для создания

других программ.

56 B-0 Грейс

Хоппер

Юнивак Хоппер создала первый ассемблер, который

понимал мнемонические команды.

ЭВМ 2-го поколения были разработаны в 1950—60 гг. В качестве

основного элемента были использованы уже не электронные лампы, а

полупроводниковые диоды и транзисторы, а в качестве устройств памяти

стали применяться магнитные сердечники и магнитные барабаны - далекие

предки современных жестких дисков. Второе отличие этих машин — это то,

что появилась возможность программирования на алгоритмических языках.

Были разработаны первые языки высокого уровня - Фортран, Алгол, Кобол.

Таблица 2.

Год Язык (идея) Создатель ЭВМ Заметки о языке

54 FORTRAN Бэкус IBM-704 Был первым языком программирования

высокого уровня. Разрабатывался компанией

IBM для её новой ЭВМ.Коллектив под

руководством Бэкуса разработал не только

спецификацию языка, но и создал компилятор

8

Page 9: Комплексное пособие

для него. Это обеспечило достаточно быструю

и широкую распространенность языка.Кроме

того, Фортран был первым языком, для

которого были разработаны компиляторы для

разных ЭВМ (т.е. программа могла

выполняться на различных ЭВМ).Лучше всего

Фортран подходит для решения инженерных и

расчетных задач.

58 ALGOL – 58     Первая спецификация Алгола была рождена

европейским международным комитетом.

59 “CSC” – первая

компания по

разработке ПО

    В 59 году в США появилась первая компания,

занимающаяся созданием промышленных

программ.

59 БНФ Бэкус, Наур   Для описания спецификации Алгола Бэкус

создал специальную систему – “нормальную

форму”. Чуть позже эта система была

уточнена Науром.

59 CODASYL     Министерство обороны США создало

организацию CODASYL, главным

назначением которой было создание нового

языка, ориентированного на бизнес –

приложения.

60 ALGOL – 60 Бэкус   Новая спецификация Алгола, которую

отличали следующие идеи:

Блочная структура

Возможность рекурсии

Описание с использованием БНФ

59 COBOL CODASYL   Стандарт языка, принятый для создания

коммерческих приложений

58 Lisp Маккарти   Язык для исследований в области

искусственного интеллекта, предназначенный

для работы со списками и лямбда –

выражениями (был создан в МТИ).

9

Page 10: Комплексное пособие

Разработка в 60-х годах интегральных схем - целых устройств и узлов из

десятков и сотен транзисторов, выполненных на одном кристалле

полупроводника (то, что сейчас называют микросхемами) привело к

созданию ЭВМ 3-го поколения. В это же время появляется

полупроводниковая память, которая и по сей день используется в

персональных компьютерах в качестве оперативной.

Таблица 3.

Год Язык (идея) Создатель ЭВМ Заметки о языке

64 ПЛ/1 Рэдин (IBM)   Универсальный язык программирования,

разрабатывавшийся для системы System/360.

64 БЭЙСИК Кемени,

Курц

  Был разработан в Дартмундском колледже

как язык для обучения работе с

компьютером студентов всех

специальностей (и технических, и

гуманитарных). Начал разрабатываться в 59-

60х годах, когда существовал только

Фортран. Отличия от Фортрана:

o операторы ввода/вывода

o единая система чисел (без различия

на целые/вещественные)

Одновременно с разработкой языка велась

разработка ЭВМ, которая работала бы не в

пакетном режиме, а в режиме разделения

времени (отсюда – необходимость

операторов ввода. Позже появится и

структурно-ориентированный стандарт

TrueBASIC.

66 АЛГОЛ – W Хоар, Вирт   Новый стандарт языка, который был

предложен Хоаром и Виртом как

альтернатива существующей спецификации

(буква W – от фамилии Вирт).

68 АЛГОЛ – 68     Этот вариант Алгола очень не понравился

10

Page 11: Комплексное пособие

Вирту.

68 Статья о

структурном

программирован

ии

Дейкстра   В этой статье Дейкстра доказывал вредность

оператора “GOTO” (т.к. он нарушает

последовательность операторов) и

показывал, что любая программа может быть

написана с использованием 3-х структур:

Последовательность

Альтернатива

Повторение

69 AПЛ Кеннет

Айверсон

(IBM)

  Очень компактный универсальный язык

программирования. Именно для этого языка

была организация ACM открыла первую

SIG(Software Interest Group).

70 ПАСКАЛЬ Никлаус

Вирт

  Был разработан Виртом как

противопоставление Алголу-68. Язык с

высокой структурированностью. До сих пор

– лучший язык для обучения

программированию.

71 ФОРТ Чарльз Мур   Самый компактный язык программирования.

Обладает высокой степенью расширяемости.

Первое промышленное применение –

управление радиотелескопами.

72 С Керниган,

Ричи,

Bell Lab.

  Язык был разработан для написания

операционной системы UNIX. В рекламных

целях UNIX в университетах

распространялся почти бесплатно, вместе с

UNIX’ом распространялся и С. До сих пор С

– один из лучших языков для системного

программирования.

72 ПРОЛОГ Алан

Колмери

  Логический язык программирования, в

котором описываются факты и отношения

между ними.

75 HOLWG Уайтекер   HOLWG – рабочая группа по управлением

Уайтекера, была создана Пентагоном для

получения языка, который мог бы

11

Page 12: Комплексное пособие

использоваться на всех компьютерах

министерства обороны США. Результатом в

79 году стал язык Ада.

76 UCSD Pascal Кеннет Боулз Apple II Введены модули

79 АДА Жан Ихбиа   Универсальный язык программирования,

был разработан по заказу МО США. После

создания вышло требование переписать все

существующие приложения на Аде.

81 Turbo Pascal Андерс

Хейлсберг

Обычно считается, что период с 1975 г. принадлежит компьютерам

четвертого поколения. Их элементной базой стали большие интегральные

схемы (БИС. В одном кристалле интегрировано до 100 тысяч элементов).

Быстродействие этих машин составляло десятки млн. операций в секунду, а

оперативная память достигла сотен Мб. Появились микропроцессоры (1971 г.

фирма Intel), микро-ЭВМ и персональные ЭВМ. Стало возможным

коммунальное использование мощности разных машин (соединение машин в

единый вычислительный узел и работа с разделением времени).

Таблица 4.

Год Язык

(идея)

Создатель ЭВМ Заметки о языке

85 С++ Бьярн

Страуструп

  Объектно-ориентированное расширение языка С

85 Object

Pascal

Ларри

Теслер,

Никлаус

Вирт

Apple

86 Perl Ларри Уолл   Язык создавался в помощь системному

администратору операционной системы Unix для

обработки различного рода текстов и выделения

нужной информации. Развился до мощного средства

12

Page 13: Комплексное пособие

работы с текстами. Является интерпретируемым

языком и реализован практически на всех

существующих платформах. Применяется при

обработке текстов, а также для динамической

генерации веб-страниц на веб-серверах.

87 Oberon Никлаус

Вирт

  Оберон отличается от Модулы-2 отсутствием многих

необязательных конструкций; добавлены же в язык

средства объектно-ориентированного

программирования -- расширяемые записи. Оберон --

это самый простой универсальный язык.

91 Python     Интерпретируемый объектно-ориентированный язык

программирования. По структуре и области

применения близок к Perl, однако менее

распространен и более строг и логичен.

92 Oberon-2 Никлаус

Вирт  В 1992 году были приняты расширения языка

Оберон, предложенные Ханспетером Мёссенбёком.

Расширенный язык получил название Оберон-2.

Основное нововведение -- связанные с типами

процедуры. Сейчас Оберон-2 является фактическим

стандартом языка

93 Delphi Андерс

Хейлсберг

   Delphi 1 был первым инструментарием разработки

Windows приложений, объединившим в себе

оптимизирующий компилятор, визуальную среду

программирования и мощные возможности работы с

базами данных.

95 PHP Расмус

Лердорф  Cкриптовый язык программирования общего

назначения, интенсивно применяющийся для

создания веб-приложений. В настоящее время

поддерживается подавляющим большинством

хостинг-провайдеров и является одним из лидеров

среди языков программирования, применяющихся

для создания динамических веб-сайтов.

96 Java Кен Арнольд,

Джеймс   Наследует синтаксис C и C++ и избавлен от

некоторых неприятных черт последнего.

13

Page 14: Комплексное пособие

Гослинг Отличительной особенностью языка является

компиляция в код некоей абстрактной машины, для

которой затем пишется эмулятор (Java Virtual

Machine) для реальных систем. Кроме того, в Java нет

указателей и множественного наследования, что

сильно повышает надежность программирования.

99 C# Андерс

Хейлсберг

  Основной язык разработки приложений для

платформы Microsoft .NET. Компилятор с C# входит

в стандартную установку самой .NET, поэтому

программы на нём можно создавать и компилировать

даже без инструментальных средств, вроде Visual

Studio. C# относится к семье языков с C-подобным

синтаксисом, из них его синтаксис наиболее близок к

C++ и Java. Язык имеет статическую типизацию,

поддерживает полиморфизм, перегрузку операторов

(в том числе операторов явного и неявного

приведения типа), делегаты, атрибуты, события,

свойства, обобщённые типы и методы, итераторы,

анонимные функции с поддержкой замыканий, LINQ,

исключения, комментарии в формате XML.

ЭВМ пятого поколения — это ЭВМ будущего. Программа разработки,

так называемого, пятого поколения ЭВМ была принята в Японии в 1982 г.

Предполагалось, что к 1991 г. будут созданы принципиально новые

компьютеры, ориентированные на решение задач искусственного интеллекта.

С помощью языка Пролог и новшеств в конструкции компьютеров

планировалось вплотную подойти к решению одной из основных задач этой

ветви компьютерной науки - задачи хранения и обработки знаний. Коротко

говоря, для компьютеров пятого поколения не пришлось бы писать

программ, а достаточно было бы объяснить на "почти естественном" языке,

что от них требуется. Предполагается, что их элементной базой будут

служить не СБИС, а созданные на их базе устройства с элементами

14

Page 15: Комплексное пособие

искусственного интеллекта. Для увеличения памяти и быстродействия будут

использоваться достижения оптоэлектроники и биопроцессоры.

К сожалению, японский проект ЭВМ пятого поколения повторил

трагическую судьбу ранних исследований в области искусственного

интеллекта. Более 50-ти миллиардов йен инвестиций были потрачены

впустую, проект прекращен, а разработанные устройства по

производительности оказались не выше массовых систем того времени.

Однако, проведенные в ходе проекта исследования и накопленный опыт по

методам представления знаний и параллельного логического вывода сильно

помогли прогрессу в области систем искусственного интеллекта в целом.

Алгоритмы

Слово «алгоритм» происходит от имени узбекского математика Хорезми

(по арабски ал - Хорезми), который в IX веке разработал правила 4-х

арифметических действий над числами в десятичной системе счисления.

Алгоритм - точное предписание по выполнению ограниченного числа

определенных действий, последовательно преобразующих исходные данные

в конечный результат.

Совокупность действий по преобразованию исходных данных в

конечный результат составляет процесс выполнения алгоритма, называемый

вычислительным процессом или просто процессом. Тот кто выполняет

алгоритм называется процессор (человек или часть ЭВМ). Алгоритм,

предназначенный для выполнения ЭВМ называется программой.

Алгоритм обладает следующими свойствами:

дискретностью - алгоритм состоит из конкретных действий;

определенностью - точностью, не оставляющей место для произвола,

т.е. алгоритм понятен для возможных исполнителей благодаря этому

свойству процесс выполнения алгоритма носит механический характер;

15

Page 16: Комплексное пособие

результативностью - свойством приводить к искомому результату за

конечное число действий (шагов);

Массовостью - пригодностью для решения задач из некоторого класса.

Пример

Дано X, Вычислить 3x2+6x+2. Допустимые операции - сложение и

умножение 2-х чисел. Т.о. есть предпосылки для разработки алгоритма:

исходные данные - X;

действия - сложение, умножение, которое применительно к выражению

3x2+6x+2 дадут искомый результат.

Т.к. среди действий нет возведения в степень выражение необходимо

записать в виде 3xx+6x+2.

Получим следующий алгоритм:

начало;

вычислить X´X, результат обозначить через Y;

вычислить 3´4, результат обозначить через Z;

вычислить 6´X, результат обозначить через W;

вычислить Z+W, результат обозначить через U;

вычислить U+2, результат обозначить через S;

конец;

Язык Turbo Pascal

Язык программирования Pascal это:

Алгоритмический язык программирования высокого уровня

Разработан Никлаусом Виртом в 1970 году для обучения студентов

программированию.

Хорошо структурированный язык с жестким контролем типов данных

В дальнейшем под языком Pascal будем подразумевать Turbo Pascal.

Любой алгоритмический язык программирования состоит из следующих

элементов:

Алфавит

16

Page 17: Комплексное пособие

Лексемы

o Идентификаторы

o Константы

o Знаки операций и разделители

o Комментарии

Выражения

Типы данных и операции

Операторы

Структура программы

Алфавит

Алфавит языка: кодовая таблица ASCII. Для оригинального языка

Pascal:

1. латинские буквы и символ подчеркивания: ABC...Zabc...z_

2. арабские цифры: 012...9

3. 22 специальных символа: +-*/=><.,:;@')(][}{#$^

Символы алфавита используются для построения базовых элементов

Pascal-программ - минимальных единиц языка, имеющих самостоятельный

смысл. Базовые элементы также называют лексемами.

Лексемы

4. Служебные (зарезервированные) слова.

5. Имена. Они вводятся для обозначения в программе переменных, констант,

типов, процедур и функций.

6. Числа и символьные строки.

7. Знаки операций и разделители. Они формируются из одного или

нескольких специальных символов.

8. Комментарии - произвольная последовательность символов (не

обязательно из алфавита языка, то есть допускаются и русские буквы),

заключенную в фигурные скобки { }.

17

Page 18: Комплексное пособие

Идентификаторы

Правило составления идентификаторов: первый символ – латинская

буква, остальные – латинские буквы, цифры или символ подчеркивания

Определите, какие выражения являются правильным идентификатором:

3Yfgh

V x

R_36%

Fgh23_

&A

Выражения

Выражения могут содержать, переменные, константы, вызовы функций,

знаки операций, круглые скобки. Записываются в соответствии с правилами

использования операций

Определите, какие выражения записаны правильно:

A+B

Sin(x)*(2+y)

D(+2/)c

‘A’*2

Операторы

В языке Pascal предусмотрены следующие операторы:

оператор присваивания

составной оператор

пустой оператор

условный оператор

оператор варианта

оператор цикла с предусловием

18

Page 19: Комплексное пособие

оператор цикла с постусловием

оператор цикла с параметром

присоединения

оператор процедуры

Оператор присваивания

Самым простым действием над переменной является занесение в нее

величины соответствующего типа. Иногда говорят об этом, как о присвоении

переменной конкретного значения. Такая команда (оператор) в общем виде

выглядит на языке Паскаль следующим образом:

<Имя переменной>:=<Выражение>;

Выражение, указанное справа от знака ":=", должно приводить к

значению того же типа, какого и сама переменная, или типа, совместимого с

переменной относительно команды присваивания. Например, переменной

типа Real можно присвоить значение типа Integer или Word (впрочем,

наоборот делать нельзя). Выражение будет сначала вычислено, затем, его

результат будет положен в ячейки памяти, отведенные для переменной.

Структура программы

[Program <Имя программы>;]

[Uses <Имена подключаемых модулей>;]

[Label <Список меток>;]

[Const <Объявления констант>;]

[Type < Объявления типов>;]

[Var < Объявления переменных>;]

[<Раздел подпрограмм>]

Begin

[<Операторы>]

19

Page 20: Комплексное пособие

End.

Разделы, заключенные в квадратные скобки, являются необязательными.

Таким образом, минимальная синтаксически допустимая программа

выглядит следующим образом:

Begin

End.

Нетрудно догадаться, что эта программа будет компилироваться и

запускаться (сразу же завершая свою работу), но никаких действий

выполнять не будет.

Более осмысленный пример на языке Pascal:

program Summa;

var

A,B,Sum : integer;

begin

Wгitе(’Введите два числа: ‘);

Readln(A,B);

Sum :=А+В;

Wгitеln(’Сумма равна’,Sum);

Wгitе(’Нажмите Enter’);

Readln;

end.

Для запуска программы из среды Turbo Pascal выберите команду Run в

меню Run. Вы попадете в окно пользователя, появится сообщение:

Введите два числа:

Наберите два любых целых числа с пробелом между ними и нажмите

Enter. Появится следующее сообщение:

Сумма равна

а за ним - сумма двух чисел. В следующей строке появится сообщение:

20

Page 21: Комплексное пособие

Нажмите клавишу Enter

Программа будет ожидать нажатия клавиши Епtег. Для наблюдения за

выводом из своей программы, выберите команду User Screen в меню Window

(или нажмите Аlt-F5).

Основные типы данных. Ввод-вывод

Любые данные, т.е. константы, переменные, значения функций или

выражения, в турбо Паскале характеризуются своими типами. Тип

определяет множество допустимых значений, которые может иметь тот или

иной объект, а также множество допустимых операций, которые применимы

к нему. Кроме того, тип определяет также и формат внутреннего

представления данных в памяти ПК.

Операции языка Pascal и их приоритеты

На этом рисунке приведены группы операций в порядке убывания их

приоритетов. Внутри группы приоритет операций одинаков.

Объявление переменных

var

Операции языка Pascal

Унарные

Бинарные

Аппликативные

Мультипликативные

Операции отношения

21

Page 22: Комплексное пособие

<имя переменной>:<имя типа1>;

<имя1>[,<имя2>,…]:<тип2>;

var

a,b:integer;

ch:char;

Типы данных

Турбо Паскаль характеризуется разветвленной структурой типов

данных.

В Турбо Паскале предусмотрен механизм создания новых типов данных,

благодаря чему общее количество типов, используемых в программе, может

быть сколь угодно большим.

22

Page 23: Комплексное пособие

Простые типы

К простым типам относятся порядковые и вещественные типы.

Порядковые типы отличаются тем, что каждый из них имеет конечное

число возможных значений. Эти значения можно определенным способом

упорядочить и, следовательно, с каждым из них можно сопоставить

некоторое целое число – порядковый номер значения.

Вещественные типы, строго говоря, тоже имеют конечное число

значений, которое определяется форматом внутреннего представления

вещественного числа. Однако количество возможных значений

Типы данных

Простые

Структурированные

Порядковые

Вещественные

Символьный

Целочисленные

Перечисление

Логический

Диапазон

Массивы

Строки

Записи

Файлы

Указатели

23

Page 24: Комплексное пособие

вещественных типов настолько велико, что сопоставить с каждым из них

целое число (его номер) не представляется возможным.

Порядковые типы

К порядковым типам относятся целые, логические, символьный,

перечисляемый и тип-диапазон. К любому из них применима функция

ORD(X), которая возвращает порядковый номер значения выражения Х. Для

целых типов функция ORD(X) возвращает само значение Х, т.е. ORD(X)=X

для Х, принадлежащего любому целому типу. Применение ORD(X) к

логическому, символьному и перечисляемому типам дает положительное

целое число в диапазоне от 0 до 1(логический тип), от 0 до 255(символьный),

от 0 до 65535(перечисляемый). Тип-диапазон сохраняет все свойства

базового порядкового типа, поэтому результат применения к нему функции

ORD(X) зависит от свойств этого типа.

К порядковым типам можно также применять функции:

PRED (X) – возвращает предыдущее значение порядкового типа(значение

которое соответствует порядковому номеру ORD (X)-1 то есть

ORD(PRED(X))=ORD(X)-1

SUCC (X) - возвращает следующее значение порядкового типа, которое

соответствует порядковому номеру ORD (X)+1 т.е.

ОRD(SUCC(X)=ORD(X)+1.

Например, если в программе определена переменная

Var

C: Char;

.........

с:=’5’;

то функция PRED(C) вернет значение ‘4’, а функция SUCC(C) значение ‘6’.

Если представить себе любой порядковый тип как упорядоченное

множество значений, возрастающих слева направо и занимающих на

24

Page 25: Комплексное пособие

числовой оси некоторый отрезок, то функция PRED(C) не определена для

левого, а SUCC(X) для правого конца отрезка.

Целые типы.

Диапазон возможных значений целых типов зависит от их внутреннего

представления, которое может занимать один, два или четыре байта. В табл.

1 приводится название целых типов, длина их внутреннего представления в

байтах и диапазон их возможных значений.

Таблица 5.

Длина, байт Название типа Диапазон значений

1 Byte 0..255

1 Shorting -128.127

2 Word 0...65535

2 Integer -32768...32767

4 longint -2147483648...

2147483647

При использовании процедур и функций с целочисленными

параметрами следует руководствоваться «вложенностью типов», т.е. везде,

где может использоваться WORD, допускается использование BYTE(но не

наоборот), в LONGINT «входит» INTEGER, который, в свою очередь

включает в себя SHORTINT.

Перечень процедур и функций, применимых к целочисленным типам

приведен в таблице 2. Буквами b, s, w, i, l обозначены выражения

соответственно типа BYTE, SHORTINT, WORD, INTEGER, LONGINT, x –

выражение любого из этих типов; буквы vb, vs, vw, vi, vl, vx обозначают

переменные соответствующих типов. В квадратных скобках –

необязательный параметр.

25

Page 26: Комплексное пособие

Таблица 6.

Обращение Тип результата Действие

Abs (x) X Возвращает модуль х

Chr (b) Char Возвращает символ по его коду

Dec(vx[,i]) Процедура Уменьшает значение vx на i, при

отсутствии i -на 1

Inc(vx,[i]) Процедура Увеличивает значение vx на i, при

отсутствии i -на 1

Hi(i) Byte Возвращает старший байт аргумента

Hi(w) Byte То же

Lo (i) Byte Возвращает младший байт аргумента

Lo(w) Byte То же

Odd(l) Boolean Возвращает TRUE , если аргумент

нечетное число, False – если четное

Random(w) Как у параметра Возвращает псевдослучайное число,

равномерно распределенное на

интервале 0 <= х <w

Sqr(X) То же Возвращает квадрат аргумента

Swap(i) Integer Меняет местами байты в слове

Swap(w) Word То же

При действиях с целыми числами тип результата будет соответствовать

типу операндов, а если операнды относятся к различным целым типам, - типу

того операнда, который имеет максимальную мощность (максимальный

диапазон значений). Возможное переполнение результата никак не

контролируется, что может привести к недоразумениям, например:

Var

26

Page 27: Комплексное пособие

A: integer;

X, y: real;

Begin

A:=32767;

X:= a+2;

Y:=longint (a)+2;

Writeln (x:10:0,y:10:0 );

End.

В результате прогона получим

-32677 32769

Логический тип

Значениями логического типа может быть одна из предварительно

объявленных констант FALSE(ложь) или TRUE (истина). Для них

справедливы правила:

Ord (false) = 0;

Ord (true)=1;

False<True;

Succ (False)=True;

Pred (true)=False;

Поскольку логический тип относится к порядковым типам, его можно

использовать, например, в операторе

...............

Var

i : Boolean;

. . . .

for i:=false to true do ...

27

Page 28: Комплексное пособие

Логические операции

Таблица 7.

A Not A

False True

True False

Таблица 8.

A B A and B

False False False

False True False

True False False

True True True

Таблица 9.

A B A or B

False False False

False True True

True False True

True True True

Таблица 10.

A B A xor B

False False False

False True True

True False True

True True False

Пример

if I mod 7 = 0 then

if I mod 13 = 0 then

writeln(I);

28

Page 29: Комплексное пособие

if (I mod 7 = 0) and (I mod 13 = 0) then

writeln(I);

Символьный тип

Значением символьного типа является множество всех символов ПК.

Каждому символу приписывается целое число в диапазоне 0..255. Это число

служит кодом внутреннего представления символа, его возвращает функция

ORD.

Для кодировки используется код ASCII. Это 7-битный код, т.е. с его

помощью можно закодировать лишь 128 символов в диапазоне от 0 до 127. В

то же время в 8-битном байте, отведенном для хранения символов в Турбо

Паскале, можно закодировать в два раза больше символов в диапазоне 0..255.

Первая половина символов ПК с кодами 0..127 соответствует стандарту

ASCII. Вторая половина с кодами 128-255 не ограничена жесткими рамками

стандарта и может меняться на ПК разных типов.

Символы с кодами 0…31 относятся к служебным кодам. Если эти коды

используются в символьном тексте программы, они считаются пробелами.

При использовании их в операциях ввода - вывода они могут иметь

следующее самостоятельное значение:

Таблица 11.

Символ Код Значение

Bel 7 Звонок: вывод на экран этого символа

сопровождается звуковым сигналом

Ht 9 Горизонтальная табуляция: при выводе на

экран смещает курсор в позицию кратную

8, плюс 1

Lf 10 Перевод строки: при выводе на экран все

последующие символы будут выводиться,

29

Page 30: Комплексное пособие

начиная с той же позиции, но на

следующей строке.

VT 11 Вертикальная табуляция: при выводе на

экран заменяется спец.символом

FF 12 Прогон страницы: при выводе на принтер

формирует страницу, при выводе на экран

заменяется спец. символом

Cr 13 Возврат каретки: водится нажатием на

клавишу enter (при вводе с помощью read

или readln означает команду “ввод” и в

буфер ввода не помещается; при выводе

означает команду “продолжить вывод с

начала текущей строки”)

Sub 26 Конец файла: вводится с клавиатуры

нажатием ctrl+Z; при выводе заменяется

спец. знаком

Esc 27 Конец работы: вводится с клавиатуры

нажатием на клавишу esc; при выводе

заменяется спец.символом

К типу CHAR применимы операции отношения, а также встроенные

функции:

CHR (B) – функция типа CHAR преобразует выражение В типа BYTE в

символ и возвращает его своим значением;

UPCASE (CH) – функция типа CHAR; возвращает символ в верхнем

регистре, если он определен для аргумента CH типа CHAR, в противном

случае возвращает сам символ Ch:

Var c1,c2:char;

Begin

30

Page 31: Комплексное пособие

C1:=upcase (‘s’);

C2:=upcase (‘ ф ’);

Writeln (c1,’ ‘, c2);

End.

В результате прогона программы на экран будет выдано

S ф

Так как функция UPCASE не обрабатывает кириллицу.

Раздел описания типов

Раздел описания типов начинается ключевым словом Type и содержит

описания новых типов данных, созданных программистом:

Type

<Имя типа1>=<Описание1>;

<Имя типа2>=<Описание2>;

...

Перечисляемый тип

Задается перечислением тех значений, которые он может получать.

Каждое значение именуется некоторым идентификатором и располагается в

списке, обрамленным круглыми скобками:

Type

Colors = (red, white, blue);

Применение перечисляемых типов делает программы нагляднее.

Если, например, в программе используются данные, связанные с

месяцами года то:

Type

31

Page 32: Комплексное пособие

Тип месяц = (янв, фев, мар, апр, май, июн, июл, авг, сен,

окт, ноя, дек);

Var

Месяц :ТипМесяц;

..........

If месяц= авг then writeln(‘Море!!!’);

Этот фрагмент программы был бы очень наглядным. Увы! В Паскале

нельзя использовать кириллицу в идентификаторах, поэтому мы вынуждены

писать так:

tуре

TypeMonth=(jan, feb, mar, may, apr, jun, jul, aug, sep, oct,

nov, dec);

Var

Month:TypeMonth;

..........

If Month = aug then writeln(‘Хорошо бы поехать к морю!’);

Соответствия между значениями перечисляемого типа и порядковыми

номерами этих значений устанавливается порядком перечисления: первое

значение в списке получает значение 0, второе – 1 и т.д. Максимальная

мощность перечисляемого типа составляет 65535 значений, поэтому

фактически перечисляемый тип задает некоторое подмножество целого типа

WORD и может рассматриваться как компактное объявление сразу группы

целочисленных констант со значениями 0,1 и т.д.

Использование перечисляемых типов повышает надежность программ

благодаря возможности контроля тех значений, которые получат

соответствующие переменные. Пусть задано:

Type

Colors =(black, red, white);

Ordenal = (one, two, three);

32

Page 33: Комплексное пособие

Days = (monday, tuesday, wednesday);

С точки зрения мощности и внутреннего представления все три типа

эквивалентны:

Ord (black)=0,…, ord (white)=2,

Ord (one)=0, ... , ord (three)=2,

Ord (monday)=0, ... , ord (wednesday)=2,

Однако если определены переменные

Var

col: colors;

Num:ordenal;

Day:days;

То допустимы операторы

Col:=black;

Num:=succ (two);

Day:=pred (tuesday);

но недопустимы

Col:=one;

Day:=black;

и т.д.

Как уже упоминалось, между значениями перечисляемого типа и

множеством целых чисел существует однозначное соответствие, задаваемое

функцией ord(x). В Турбо Паскале допускается и обратное преобразование:

любое выражение типа WORD можно преобразовать в значения

перечисляемого типа, если только значение целочисленного выражения не

превышает мощности перечисляемого типа.

33

Page 34: Комплексное пособие

Например, для рассмотренного выше объявления типов эквивалентны

следующие присваивания:

Col:=one;

Col:=colors (0);

Разумеется присваивание

Col:=0;

Будет недопустимым.

Переменные любого перечисляемого типа можно объявлять без

предварительного описания этого типа:

Var col: (black, white);

Тип диапазон

Это подмножество есть подмножество своего базового типа, в качестве

которого может выступать любой порядковый тип, кроме типа-диапазона.

Тип-диапазон задается границами своих значений внутри базового типа:

<мин. знач.>..<макс. знач.>

Например:

Type

Digit = ‘0’.. '9';

Dig2 = 48..57;

Тип диапазон не обязательно описывать в разделе type, а можно

указывать непосредственно при объявлении переменной:

Var

Date: 1..31;

34

Page 35: Комплексное пособие

Month: 1 .. 12;

Lchr:’A’..’Z’;

При объявлении типа диапазона нужно руководствоваться следующими

правилами:

1. Два символа «..» рассматриваются как один символ, поэтому между ними

недопустимы пробелы;

2. Левая граница диапазона не может превышать правую границу.

Тип-диапазон наследует все свойства базового типа, но с

ограничениями, связанными с его меньшей мощностью. В частности если

определена переменная

Type

Days = (mo, tu, we, th, fr, sut, sa);

Weekend = sa.. su;

Var

w: Weekend;

...................

W:=sa;

то ord(w) вернет значение 5, в то время как PRED(W) приведет к ошибке.

Вещественные типы

В отличие от порядковых типов, значения которых всегда

сопоставляется с рядом целых чисел и, следовательно, представляются в ПК

абсолютно точно, значения вещественных типов определяют произвольное

число лишь с некоторой конечной точностью, зависящей от внутреннего

формата вещественного числа.

Таблица 12.

Длина, байты Название типа Мантисса Диапазон

десятичного

35

Page 36: Комплексное пособие

порядка

4 Single 7...8 -45...+38

6 Real 11...12 -39...+38

8 Double 15...16 -324...+308

10 Extended 19...20 -4951...+4932

8 Comp 19...20 -2^63+1...

+2^63-1

Как видно из таблицы вещественное число в Паскале занимает от 4-х до

10 смежных байт и имеет следующую структуру в памяти ПК.

S E M

Здесь s-знаковый разряд числа; е – экспоненциальная часть, содержит

двоичный порядок.m- мантисса числа.

Мантисса имеет длину от 23 до 63 двоичных разрядов, что и

обеспечивает точность 7..8 для single и 19..20 для extended десятичных цифр.

Десятичная точка подразумевается перед левым (старшим) разрядом

мантиссы, но при действиях с числом ее положение сдвигается влево или

вправо в соответствии с двоичным порядком числа, хранящимся

экспоненциальной части, поэтому действия над вещественными числами

называют арифметикой с плавающей точкой, запятой.

Паскаль характеризуется богатой гаммой вещественных типов, однако

доступ к типам single, double, extended возможен только при особых режимах

компиляции. Дело в том, что эти типы рассчитаны на аппаратную поддержку

арифметики с плавающей точкой и для их эффективного использования в

состав ПК должен входить арифметический сопроцессор 8087, 80287 или их

отечественный аналог К1810ВМ87.

Компилятор позволяет создавать программы, работающие на любых ПК

и использующие любые вещественные типы. В процессе запуска Турбо

36

Page 37: Комплексное пособие

Паскаль проверяет состав аппаратных средств и выявляет наличие или

отсутствие сопроцессора.

Арифметический сопроцессор всегда обрабатывает числа в формате

extended, а три других вещественных типа в этом случае получаются

простым усечением результатов до нужных размеров и применяются я в

основном для экономии памяти.

Например:

{$N+, E+}

Type

RealType= real;

Var

Epsilon:= realtype;

Begin

Epsilon:=1;

while 1+epsilon/2>1 do

Epsilon:=epsilon/2;

Writeln (epsilon);

End.

Независимо от объявления типа REALTYPE на печать будет выдан рез-т:

1.08420217248550Е-0019,что соответствует типу extended.

Чтобы получить правильный результат программу необходимо изменить

следующим образом:

{$N+, E+}

Type

Realtype = real;

Var

epsilon, eps1: realtype;

Begin

Epsilon:=1;

Repeat

37

Page 38: Комплексное пособие

Epsilon:=epsilon/2;

Eps1:=epsilon+1;

Until eps1>1;

Writeln (2*epsilon)

End.

Следует учесть, что тип REAL оптимизирован для работы без

сопроцессора. Если ваш ПК оснащен сопроцессором, использование типа

REAL приведет к дополнительным затратам времени на преобразование

REAL к EXTENDED. Поэтому никогда не используйте REAL на ПК с

сопроцессором, т.к. дополнительные затраты времени на преобразование

типов могут свести на нет все преимущества сопроцессора. При разработке

программ, критичных ко времени счета, следует заменять его типами SINGLE

или DOUBLE: по сравнению с типом REAL скорость вычислений на машинах

с сопроцессором в этом случае увеличивается в 2-3 раза. Если в ПК нет

арифметического сопроцессора, скорость обработки данных всех

вещественных типов приблизительно одинакова.

Особое положение в Паскале занимает тип COMP, который трактуется

как вещественное число без экспоненциальной и дробной части. COMP- это

"большое" целое число со знаком, сохраняющее 19.. 20 значащих десятичных

цифр. В то же время в выражениях COMP полностью совместим с любыми

другими вещественными типами: над ними определены все вещественные

операции, он может использоваться как аргумент математических функций и

т.д. Наиболее подходящей областью применения типа COMP являются

бухгалтерские расчеты: денежные суммы выражаются в копейках и действия

над ними сводятся к операциям с достаточно длинными целыми числами.

Для работы с вещественными данными могут использоваться

встроенные математические функции, представленные в таблице 3. В этой

таблице REAL означает любой вещественный тип, INTEGER- любой целый

тип.

38

Page 39: Комплексное пособие

Таблица 13.

Обращение Тип параметра Тип результата Примечание

Abs(x) Real, integer Тип аргумента Модуль аргумента

ArcTan(x) Real Real Арктангенс (радианы)

Cos (x) “ “ Косинус (радианы)

Exp (x) “ “ Экспонента

Frac (x) “ “ Дробная часть числа

Int (x) “ “ Целая часть числа

Ln (x) “ “ Логарифм натуральный

Pi - Real П = 3.141592653...

Random - Real Равномерное

псевдослучайное число

0<=x<1

Random(i) Integer Integer Равномерное

псевдослучайное целое

число 0<=i<1

Randomize - - Инициация датчика

случайных чисел

Sin(x) Real Real Синус (радианы)

Sqr(x) Real, integer Тип аргумента Квадрат аргумента

Sqrt (x) real Real Корень квадратный

Операторы языка Паскаль

Составной оператор

Составной оператор – это последовательность произвольных операторов

программы, заключенная в операторные скобки – зарезервированные слова

begin…end. Составные операторы – важный инструмент Турбо Паскаля,

39

Page 40: Комплексное пособие

дающий возможность писать программы по современной технологии

структурного программирования (без операторов перехода goto).

Язык Турбо Паскаль не накладывает никаких ограничений на характер

операторов, входящих в составной оператор. Среди них могут буть и другие

составные операторы – Турбо Паскаль допускает произвольную глубину их

вложенности:

Begin

.......

Begin

.......

Begin

.......

End;

.......

End;

.......

End;

Фактически, весь раздел операторов, обрамленный словами begin…end,

представляет собой один составной оператор. Поскольку зарезервированное

слово end является закрывающей операторной скобкой, оно одновременно

указывает и конец предыдущего оператора, поэтому ставить перед ним

символ «;» необязательно. Однако, в процессе работы над программой перед

словом end могут появиться новые операторы. В этом случае часто возникает

ошибка из-за отсутствия символа «;» после предпоследнего оператора

(программист добавляет новый оператор, после которого символ «;» не

нужен, а поставить его там где он теперь необходим забывает). С этой точки

зрения символ «;» лучше ставить и перед словом end. Это будет означать, что

между последним оператором и операторной скобкой end располагается

пустой оператор. Пустой оператор не содержит ни каких действий, просто в

программу добавляется лишняя точка с запятой.

40

Page 41: Комплексное пособие

Условный оператор

Условный оператор позволяет проверить некоторое условие и в

зависимости от результатов проверки выполнить то или иное действие.

Таким образом, условный оператор – это средство ветвления

вычислительного процесса.

Структура условного оператора имеет следующий вид:

if <условие> then <оператор1> else <оператор2>;

где if, then, else – зарезервированные слова (если, то, иначе);

<условие> – произвольное выражение логического типа;

<оператор1>, <оператор2>, – любые операторы языка Турбо Паскаль.

Условный оператор работает по следующему алгоритму. Сначала

вычисляется условное выражение <условие>. Если результат есть true

(истина), то выполняется <оператор1>, а <оператор2> пропускается; если

результат есть false (ложь), наоборот, <оператор1> пропускается, а

выполняется <оператор2>. Например:

var

x, y, max : real;

.......

if x>max then y:=max

else y:=x;

При выполнении этого фрагмента переменная y получит значение

переменной x, если только это значение не превышает max, в противном

случае y станет равным max.

Часть else <оператор2> условного оператора может быть опущена. Тогда

при значении true условного выражения выполняется <оператор1>, в

противном случае этот оператор пропускается:

var

41

Page 42: Комплексное пособие

x, y, max : real;

.......

if x>max then max:=x;

y:=x;

В этом примере переменная y всегда будет иметь значение переменной

x, а в max запоминается значение x если оно больше значения max.

Поскольку любой из операторов <оператор1> и <оператор2> может

быть любого типа, в том числе и условным, а в то же время не каждый из

«вложенных» условных операторов может иметь часть else <оператор2>, то

возникает неоднозначность трактовки условий, т.е. непонятно какой else к

какому if…then относится. Эта неоднозначность в Турбо Паскале решается

следующим образом: любая встретившаяся часть else соответствует

ближайшей к ней «сверху» части if…then условного оператора. Например:

var

a, b, c, d : integer;

a:=1;

b:=2;

c:=3;

d:=4;

if a>b then

if c<d then

if c<0 then c:=0

else a:=b; {a=1}

if a>b then

if c<d then

if c<0 then c:=0

else

else

else a:=b; {a=2}

42

Page 43: Комплексное пособие

Обратите внимание на то, что перед else точка с запятой не ставится.

Символ «;» в Паскале означает конец оператора, а оператор if заканчивается

там где заканчивается <оператор2> (если есть часть else).

В случае, когда необходимо выполнить несколько операторов, а не один

(<оператор1> или <оператор2>) их необходимо заключить в операторные

скобки begin … end, получив, тем самым, составной оператор.

Рассмотрим программу, которая вводит произвольное целое число в

диапазоне 0..15, преобразует его к шестнадцатеричному основанию и

выводит на экран полученное.

var

n : integer; {Вводимое число}

ch : char; {Результат}

begin

write(‘n= ‘); {Вывести приглашение (подсказку)}

readln(n); {Ввести число}

{Проверить число на принадлежность диапазону 0..15}

if (n>=0) and (n<=15) then

begin {Да, принадлежит}

if n<10 then ch:=chr(ord(‘0’)+n)

else ch:=chr(ord(‘A’)+n-10);

writeln(‘n=’, ch);

end

else writeln(‘Ошибка’);

end.

В шестнадцатеричной системе счисления используются 16 цифр в

каждом разряде: цифры 0..9 обозначают первые 10 возможных значений

разряда, буквы A..F – остальные шесть.

В программе учитывается непрерывность и упорядоченность множества

цифр 0..9 и множества букв A..F.

43

Page 44: Комплексное пособие

Оператор выбора Case

Если у вас не два возможных варианта выполнения программы, а

больше, то может использоваться оператор выбора CASE. Структура этого

оператора в Турбо Паскале:

CASE <ключ_выбора> OF

C1 : <оператор1>;

C2 : <оператор2>;

. . .

CN : <операторN>;

[ELSE <оператор0>;]

END;

Здесь <ключ_выбора> - это выражение порядкового типа, в зависимости

от значения которого принимается решение; C1,...,CN - значения, с которыми

сравнивается значение <ключа>; <оператор1>,..., <операторN> - оператор

(возможно составные), из которых выполняется rnr, с константой которого

происходит первое совпадение значения <ключа>, <оператор0> выполнится,

если значение ключа не совпадает ни с одной из констант C1,...,CN.

Пример

Program calc;

Var a,b,rez:real;

oper:char;

Begin

write(‘Введите два числа: ’);

readln(a,b);

write(‘Введите операцию: ‘);

readln(oper);

case oper of

‘+’:rez:=a+b;

‘-’:rez:=a-b;

‘*’:rez:=a*b;

44

Page 45: Комплексное пособие

‘/’:rez:=a/b;

end;

writeln(‘Результат=‘,rez);

end.

Операторы повтора

В языке Турбо Паскаль имеются три различных оператора, с помощью

которых можно запрограммировать повторяющиеся фрагменты программ.

Такие операторы называются циклами. Различаются эти операторы способом

определения количества необходимых повторов, или, другими словами,

когда необходимо завершить работу цикла.

Первый вариант цикла называется циклом с предпроверкой условия и

записывается следующим образом:

while <условие выполнения цикла> do <оператор>;

Выполнение цикла начинается с проверки <условия выполнения цикла>.

Если оно истинно, то выполняется <оператор> (тело цикла). Потом снова

проверяется <условие выполнения цикла> и, если оно истинно, то

выполняется <оператор> и т.д. Если на коком-то шаге <условие выполнения

цикла> станет ложным, то выполнение цикла будет завершено. Таким

образом, пока <условие выполнения цикла> истинно будет выполняться

<оператор>. Если <условие выполнения цикла> изначально ложно, то

<оператор> ни разу не будет выполнен.

Если в цикле необходимо выполнить несколько операторов, то

необходимо воспользоваться составным оператором:

while <условие выполнения цикла> do

begin

<операторы>

end;

45

Page 46: Комплексное пособие

Второй вариант цикла называется циклом с постпроверкой условия и

записывается следующим образом:

repeat

<операторы>

until <условие выхода из цикла>;

Выполнение цикла начинается с выполнения <операторов> (тела цикла),

потом проверяется <условие выхода из цикла>. Если оно ложно, то снова

выполняются <операторы>. Потом снова проверяется <условие выхода из

цикла> и т.д. Если на коком-то шаге <условие выхода из цикла> станет

истинным, то выполнение цикла будет завершено. Таким образом, будут

выполняться <операторы> до тех пор, пока <условие выхода из цикла> не

станет истинным. Кикам бы ни было <условие выхода из цикла> в начале

работы цикла, <операторы> будут выполнены, по крайней мере, один раз.

Тело цикла может содержать несколько операторов, причем нет

необходимости использовать составной оператор, поскольку в качестве

операторных скобок здесь выступают ключевые слова repeat и until.

Оба оператора цикла предполагают, что

1. на момент начала выполнения цикла определены (имеют начальные

значения) все переменные участвующие в вычислении значений условий и

2. тело цикла содержит оператор или операторы, которые изменяют эти

переменные таким образом, чтобы условие изменило свое значение и цикл

завершил свою работу.

Следующий вариант оператора цикла включает в себя оба этих условия.

и записывается следующим образом:

for <переменная цикла>:=<начальное значение> to <верхняя

граница> do

<оператор>;

46

Page 47: Комплексное пособие

Выполнение цикла начинается с присвоения <переменная цикла>

<начального значения>. Далее, если значение <переменная цикла> меньше

или равно значению <верхней границы>, то выполняется <оператор>. Потом

значение переменной цикла увеличивается на единицу и снова проверяется

условие, что значение <переменной цикла> меньше или равно значению

<верхней границы>, выполняется <оператор> и т.д.

Есть еще один вариант цикла for:

for <переменная цикла>:=<начальное значение> downto <нижняя

граница>

do <оператор>;

Здесь на каждом шаге значение переменной цикла уменьшается на

единицу.

Если в теле цикла необходимо выполнить несколько операторов, то

снова можно воспользоваться составным оператором.

Следующая маленькая программа выводит на экран кодовую таблицу:

Program Str3;

Var

I : Byte;

Begin

For I:=32 to 255 do

Write('VV',I:4, '-',Chr(I))

End.

Цикл в программе начинается с 32 потому, что символы с кодами от 0 до

31 являются управляющими и не имеют соответствующего графического

представления.

Пример

47

Page 48: Комплексное пособие

Совершенными называются числа, равные сумме всех своих делителей,

включая 1. Например, 6 – совершенное число, поскольку 6=1+2+3.

Требуется найти и вывести на экран все совершенные числа вместе с их

делителями, лежащие в диапазоне от 4 до 10000.

Var I,sum,del1,n:word;

Begin

for i:=4 to 10000 do

Begin

sum:=1; n:= trunc(sqrt(i));

for del1:=2 to n do

if I mod del1 =0 then

if del1<> I div del1 then

begin

sum:=sum+del1+(I div del1);

end

else

sum:=sum+del1;

if sum=i then

writeln(i);

End;

End.

Пример

Вычислить квадратный корень из произвольного вещественного числа,

введенного с клавиатуры, используя метод Ньютона:

Здесь A – введенное число, Y0=A.

Если A – отрицательное число, то необходимо вывести сообщение об

ошибке.

Результат должен иметь относительную точность 1·10-6. Как только

получено значение Y0 оно используется для получения следующего

48

Page 49: Комплексное пособие

приближения Y0, по которому в свою очередь вычисляется Y0, и так до тех

пор, пока не будет достигнута требуемая точность, то есть, пока не станет

Var A,Y1,Y:real;

Begin

write(‘Введите число:’);

readln(A);

Y1:=A;

repeat

Y:=Y1;

Y1:=(Y+A/Y)/2;

until abs(Y1-Y)<0.000001;

writeln(‘Корень из числа=‘,Y1:10:5);

end.

Вывод трехзначных чисел из неповторяющихся цифр

For i:=0 to 9 do

for j:=0 to 9 do

for k:=0 to 9 do

if (i<>j)and(i<>k)and

(j<>k) then

write(I,j,k,’ ‘);

Вывод чисел из нечетных цифр

i:=1;

While i<=9 do

begin

J:=1;

while j<=9 do

begin

K:=1;

49

Page 50: Комплексное пособие

while k<=9 do

begin

write(I,j,k,’ ‘);

Inc(k,2);

end;

Inc(j,2);

end;

Inc(I,2);

End;

Оператор перехода

В языке Турбо-Паскаль имеются различные управляющие операторы,

позволяющие написать любую программу. Тем не менее в языке имеется

оператор безусловного перехода.

Безусловный переход приводит к передаче управления из одного места в

программе в другое. Структура оператора перехода следующая:

goto <метка>

Здесь goto ключевое слово (англ.: перейти на [метку]).

Метка это произвольный идентификатор, позволяющий пометить

некоторый оператор, чтобы ссылаться на него. Для совместимости со

стандартным Паскалем разрешается в качестве метки использовать целые

числа. Метка ставится перед оператором получающим управление и

отделяется от него двоеточием. Как любой идентификатор метку необходимо

описать в разделе описания меток, который начинается с ключевого слова

label, за которым следует список меток:

...............

label m,1,loop;

begin

.........

goto 1;

m: .........

goto loop;

50

Page 51: Комплексное пособие

1: ............

goto m;

Метка, описанная в программе, обязательно должна использоваться.

Метка, описанная в функции или процедуре, должна использоваться в той

функции или процедуре, в которой она описана.

Структурированные типы. Массивы

Массивы являются структурированным типом. Структурированные

типы данных отличаются от обычных типов тем, что переменные таких

типов, имеют более одного значения, т.е. состоят из нескольких

компонентов. Структурированные типы характеризуются методом

структурирования и типами своих компонентов. Если тип компонента

является структурированным, то получаемый в результате

структурированный тип имеет более одного уровня структурирования.

Одномерные массивы

Массивы содержат фиксированное число элементов одного типа, так

называемого типа элемента. Переменные типа массив объявляются

следующим образом:

var

<имя переменной>:array[<тип индекса>] of <тип элемента>;

Допустимыми индексными типами являются все порядковые типы, за

исключением длинного целого и поддиапазонов длинного целого. Массив

может быть проиндексирован по каждой размерности всеми значениями

соответствующего индексного типа; число элементов поэтому равно числу

значений в каждом индексном типе. Число размерностей не ограничено.

Приведем пример переменной типа массив:

51

Page 52: Комплексное пособие

var

A: array[1..100] of Real

Если тип элемента в типе массив также является массивом, то результат

можно рассматривать как массив массивов или как один многомерный

массив. Например,

array[boolean] of array[1..100] of Real

интерпретируется компилятором точно так же, как массив:

array[boolean,1..10] of Real

Конкретный элемент массива обозначается с помощью ссылки на

переменную массива, за которой указывается индекс, определяющий данный

элемент.

A[5]:=3.4;

For i:=1 to 100 do

Begin

writeln(‘Введите элемент A[‘,I,’]:’);

Readln(A[i]);

End;

При объявлении массивов удобно пользоваться константами,

задающими количество элементов в массиве. Объявление констант:

Const

<имя конст.>=<значение>;

52

Page 53: Комплексное пособие

Примеры

При обработке массивов возникают такие задачи, как ввод элементов

массива, нахождение суммы, произведения, среднего и т.д., поиск

некоторого элемента в массиве, сортировка элементов массива, вывод

элементов массива.

Сумма элементов массива

Const N=10;

Var a:array[1..N] of real;

i:word;

sum:real;

Begin

sum:=0;

for i:=1 to N do

sum:=sum+a[i];

writeln(‘Сумма=‘,sum:10:5);

end.

Произведение элементов массива

Const N=10;

Var a:array[1..N] of real;

i:word;

p:real;

Begin

p:=1;

for i:=1 to N do

p:=p*a[i];

writeln(‘Произведение=‘,p:10:5);

end.

Заполнение массива псевдослучайными числами:

randomize;

53

Page 54: Комплексное пособие

for i:=1 to N do

a[i]:=x1+random*(x2-x1);

Заполнение массива числами Фибоначчи:

b[1]:=1;

b[2]:=1;

for i:=3 to N do

b[i]:=b[i-1]+b[i-2];

Возведение в квадрат четных элементов массива (элементов с четными

значениями):

for i:=1 to N do

if b[i] mod 2=0 then

b[i]:=sqr(b[i]);

Возведение в квадрат элементов массива с четным индексом:

i:=2;

while i<=N do

begin

a[i]:=sqr(a[i]);

Inc(I,2);

End;

Ниже приведена программа формирования элементов массива с

помощью датчика случайных чисел, вывод элементов массива на экран,

вычисление суммы всех элементов.

program rand1;

const n1=100; {максимальный размер массива}

type mas = array[1..n1] of integer;

var a:mas;

54

Page 55: Комплексное пособие

i, {индекс элемента массива}

n,s: integer;

begin

writeln('Введите число элементов массива:');

read(n);

{ Формирование массива с помощью датчика случайных чисел}

randomize;{Инициализация датчика случайных чисел }

for i:=1 to n do

a[i]:=random(10);

writeln('Полученный массив');

for i:=1 to n do

write (a[i]:5);

writeln;

s:=0; { Нахождение суммы }

for i:=1 to n do

s:=s+a[i];

writeln('s=',s);

end.

В приведенном примере в качестве исходных данных вводится размер

массива. Хотелось бы обратить внимание на использование константы n1.

Она сделает программу более универсальной, позволяя работать с

целочисленными массивами, размерность которых может изменяться от 1

до 100. Если будет введено число, меньшее 1 и большее 100, то возникнет

ошибка. Для формирования массива (да и во всех случаях, когда требуется

перебор всех элементов массива) лучше всего подходит оператор цикла со

счетчиком. В каждой итерации оператора цикла с датчика получаем

псевдослучайное число и присваиваем его очередному элементу массива

(индекс является переменной цикла). Результатом работы программы

является сформированный массив и сумма элементов этого массива.

Аналогично решается задача нахождения произведения элементов

массива, только начальное значение для произведения выбирается равным 1

и знак "+" меняется на знак "*".

55

Page 56: Комплексное пособие

Ниже приведена программа определения максимального элемента

массива и суммы положительных элементов, а также замены максимального

элемента массива суммой положительных элементов массива.

program sum;

const n1=100; {максимальный pазмеp массива}

type

mas = array[1..n1] of integer;

var

a:mas;

i, {индекс элемента массива}

n,s,

imax:integer;{индекс максимального элемента}

begin

writeln('Введите число элементов массива:');

read(n);

{Ввод массива}

for i:=1 to n do

begin

write ('Введите ',i,'-й элемент:');

read(a[i])

end;

s:=0;

imax:=1;{пpедполагаем, что пеpвый

элемент максимальный}

for i:=1 to n do

begin

{если элемент положительный, то

прибавляем его к сумме}

if a[i]>0 then s:=s+a[i];

{если текущий элемент массива больше

максимального, то запоминаем его индекс}

if a[imax]<a[i] then imax:=i;

end;

writeln('максимальный элемент массива =',a[imax]);

a[imax]:=s;{ замена максимального элемента суммой }

56

Page 57: Комплексное пособие

writeln('s=',s);

writeln('Обpаботанный массив:');

for i:=1 to n do

writeln (a[i]);

end.

В дальнейшем, в схемах алгоритма, подробно изображать ввод и вывод

массива не будем, чтобы алгоритм был нагляднее.

В приведенном примере массив вводится с клавиатуры. Для ввода

массива используется оператор цикла со счетчиком. За начальное значение

для индекса максимального элемента берем 1, т.е. предполагаем, что

первый элемент максимальный. Далее в цикле перебираются все элементы

массива и сравниваются c нулем для того, чтобы прибавлять или не

прибавлять элемент к сумме. В этом же цикле каждый элемент сравнивается

с a[imax] для выяснения, не встретился ли элемент, больший прежнего

максимального, и если встретился, то запоминается его индекс, чтобы

в следующий раз сравнивать текущий элемент с большим из перебранных. В

условном операторе if a[i]>a[imax] ветвь else отсутствует; это означает,

что в случае невыполнения условия imax остается без изменения, что и

обеспечивает наличие в области памяти с идентификатором imax значение

индекса максимального из перебранных элементов.

Ниже приведена программа сортировки элементов одномерного массива

"методом пузырька" в порядке неубывания. Суть сортировки этим методом

состоит в том, что сравниваются два соседних элемента и, если они

расположены в порядке убывания, то меняются местами, и этот факт

фиксируется в переменной fl.

После сравнения всех элементов массива принимается решение по

состоянию fl об очередном прохождении по массиву.

program sort1;

const n1=100; {максимальный pазмеp массива}

type

57

Page 58: Комплексное пособие

mas = array[1..n1] of real;

var

a:mas;

i, {индекс элемента массива}

n:integer;

fl:boolean;{флаг пеpестановок}

d:real;{дополнительная пеpеменная для пеpестановки

местами двух элементов массива}

begin

writeln('Введите число элементов массива:');

read(n);

{Ввод массива}

for i:=1 to n do

begin

write ('Введите ',i,'-й элемент:');

read(a[i])

end;

writeln('Исходный массив');

for i:=1 to n do

write (a[i]:5);

writeln;

{ Соpтиpовка }

repeat { повторить }

fl:=true;{ флаг поднять}

{ в очередной раз просматриваем элементы массива }

for i:=1 to n-1 do

if a[i]>a[i+1] then {сравниваем два соседних элемента}

begin{ меняем местами соседние элементы}

d:=a[i];

a[i]:=a[i+1];

a[i+1]:=d;

fl:=false;{если был обмен,то флаг опускаем }

end;

until fl;{если флаг не опускался,то массив отсортирован }

writeln('Обpаботанный массив:');

58

Page 59: Комплексное пособие

for i:=1 to n do

write (a[i]:5:2);

writeln;

end.

Основной цикл repeat прекращает выполняться, когда значение

логической переменной fl остается равной true после выполнения

вложенного цикла for. Это происходит в том случае, если ни одну пару

элементов не удается переставить, что указывает на то, что все элементы

стоят на своих местах.

Многомерные массивы

Если тип элемента в типе массив также является массивом, то результат

можно рассматривать как массив массивов или как один многомерный

массив. Например,

array[boolean] of array[1..10] of Real;

интерпретируется компилятором точно так же, как массив:

array[boolean,1..10] of Real;

В случае многомерного массива можно использовать несколько

индексов или несколько выражений в индексе. Например:

Matrix[I][J]

что тождественно записи:

Matrix[I,J]

Примеры

При обработке двумерных массивов возникают такие же задачи, как и

при обработке одномерных массивов: ввод элементов массива, нахождение

суммы, произведения, среднего и т.д., поиск некоторого элемента в массиве,

сортировка элементов массива, вывод элементов массива.

59

Page 60: Комплексное пособие

Ввод элементов двумерного массива

For i:=1 to N do

for j:=1 to M do

begin

writeln(‘Введите элемент a2[‘,I,’,’,j,’]: ‘);

readln(a2[I,j]);

end;

Вывод на экран:

For i:=1 to N do

begin

for j:=1 to M do

write(a2[I,j]:8);

writeln;

end;

Ниже приведена программа алгоритма формирования элементов массива

с помощью датчика случайных чисел, вывод элементов массива на экран,

вычисление суммы всех элементов двумерного массива.

program rand2;

const n1=10; {максимальнoе количество стpок массива}

m1=10; { максимальное количество столбцов массива}

type mas = array[1..n1,1..m1] of integer;

var a: mas;

i, { текущий номеp строки }

j, { текущий номеp столбца }

n,s,m : integer;

begin

writeln('Введите число стpок и столбцов массива:');

read(n,m);

randomize;

for i:=1 to n do

for j:=1 to m do

a[i,j]:=random(10);

60

Page 61: Комплексное пособие

writeln('Полученный массив');

for i:=1 to n do

begin

for j:=1 to m do

write (a[i,j]:5);

writeln;

end;

s:=0;

for i:=1 to n do

for j:=1 to m do

s:=s+a[i,j];

writeln('s=',s);

end.

Анализируя предложенную программу, можно заметить, что для ввода,

вывода и нахождения суммы элементов массива используются три раза

вложенные циклы. Так как массив располагается в непрерывной области

памяти построчно, более рационально будет и обрабатывать элементы

построчно. В программе во вложенных циклах для каждого значения

индекса i индекс j изменяется от 1 до m, т.е. индекс j изменяется чаще.

Таким образом, обрабатываются элементы массива построчно. Хотелось бы

обратить внимание на вывод элементов массива на экран. Здесь для каждого

значения i в теле цикла выполняются два оператора: первый оператор

цикла выводит на экран в строчку элементы одной строки, а второй

оператор вывода переводит курсор на новую строку, что как раз и

обеспечивает вывод матрицы в виде прямоугольника.

Следующий пример иллюстрирует работу с диагоналями матрицы. Дана

квадратная матрица. Заменить отрицательные элементы побочной диагонали

на сумму элементов главной диагонали матрицы. При изучении

поставленной задачи следует напомнить, что главная диагональ проходит из

правого верхнего в левый нижний угол. Так как мы работаем с квадратной

матрицей, то только на главной диагонали будут лежать элементы, индексы

строк и столбцов которых одинаковы. Именно этот факт и используется при 61

Page 62: Комплексное пособие

решении задачи. Мы не будем перебирать все элементы массива и смотреть,

совпали ли индексы, а сразу задаем оба индекса с помощью одного

идентификатора i. Побочная диагональ проходит из правого верхнего в

левый нижний угол матрицы. Нетрудно заметить, что при движении по

побочной диагонали номер строки возрастает от 1 до n, номер столбца

убывает от n до 1. Таким образом, только на побочной диагонали лежат

элементы, у которых номер столбца определяется по формуле j=n-i+1.

program diag;

const n1=10; {максимальнoе количество стpок массива}

type

mas = array[1..n1,1..n1] of integer;{квадpатная матpица}

var a:mas;

i, { текущий номеp стpоки }

j, { текущий номеp столбца }

n,s:integer;

begin

writeln('Введите число стpок и столбцов массива:');

read(n);

for i:=1 to n do

for j:=1 to n do

begin

writeln('Введите элемент массива');

read(a[i,j]);

end;

writeln('Исходный массив');

for i:=1 to n do

begin

for j:=1 to n do

write (a[i,j]:5);

writeln;

end;

s:=0;

for i:=1 to n do {Сумма элементов главной диагонали }

62

Page 63: Комплексное пособие

s:=s+a[i,i];

writeln('s=',s);

for i:=1 to n do{Замена элементов побочной диагонали}

begin

j:=n-i+1;

if a[i,j]<0 then a[i,j]:=s;

end;

writeln('Полученный массив');

for i:=1 to n do

begin

for j:=1 to n do

write (a[i,j]:5);

writeln;

end;

end.

Фрагмент программы для транспонирования матрицы относительно

побочной диагонали:

For i:=1 to N-1 do

for j:=1 to N-i do

begin

tmp:=c2[I,j];

c2[I,j]:=c2[N-j+1,N-i+1];

c2[N-j+1,N-i+1]:=tmp;

end;

И последний пример на обработку двумерных массивов. Дана

прямоугольная матрица. Отсортировать столбцы матрицы в порядке

неубывания максимальных элементов столбцов.

Решение задачи сводится к формированию одномерного массива из

максимальных элементов столбцов, а уж затем сортируется этот

одномерный массив и параллельно – столбцы матрицы. Чтобы не

запутать читателя, в этой задаче используем знакомый метод сортировки

63

Page 64: Комплексное пособие

"пузырьком". Исходный массив имеет идентификатор a, а промежуточный

одномерный массив – b.

program sort2;

const n1=10; {максимальнoе количество стpок массива}

m1=10; {максимальнoе количество столбцов массива}

type

mas = array[1..n1,1..m1] of integer;{квадpатная матpица}

var

a:mas;

b:array[1..m1] of integer;

{массив из максимальных элементов столбцов}

i, { текущий номеp стpоки }

j, { текущий номеp столбца }

n,m,d:integer;

fl:boolean;

begin

writeln('Введите число стpок и столбцов массива:');

read(n,m);

for i:=1 to n do

for j:=1 to m do

begin

writeln('Введите элемент массива');

read(a[i,j]);

end;

writeln('Исходный массив');

for i:=1 to n do

begin

for j:=1 to m do

write (a[i,j]:5);

writeln;

end;

{Фоpмиpование одномеpного массива из максимальных

элементов столбцов}

for j:=1 to m do {Пеpебиpаем все столбцы}

64

Page 65: Комплексное пособие

begin

b[j]:=a[1,j];{Пpинимаем пеpвый элемент в столбце за

максимальный }

for i:=2 to n do{Пеpебиpаем все элементы в столбце}

if a[i,j]>b[j] then b[j]:=a[i,j];

end;

end;

{Сортировка одномерного и двумерного массива}

repeat

fl:=true;{Поднять флаг}

for j:=1 to m-1 do {Перебрать элементы одномерного

массива}

if b[j]>b[j+1] then { Проверить нужна ли перестановка }

begin

fl:=false;{опустить флаг}

{Переставить элементы одномерного массива и}

d:=b[j];

b[j]:=b[j+1];

b[j+1]:=d;

{столбцы двумерного массива}

for i:=1 to n do

begin

d:=a[i,j];

a[i,j]:=a[i,j+1];

a[i,j+1]:=d;

end;

end;

until fl;{Завершить сортировку,если флаг не опускался}

writeln('Отсортированный массив');

for i:=1 to n do

begin

for j:=1 to m do

write (a[i,j]:5);

writeln;

end;

65

Page 66: Комплексное пособие

end.

В этой программе можно обойтись без дополнительного массива, но

тогда пришлось бы во время сортировки массива каждый раз искать

максимальный элемент столбца, даже если максимальный в этом столбце

мы уже находили.

Тип данных String

Тип STRING (строка) в Турбо Паскале широко используется для

обработки текстов. Он во многом похож на одномерный массив символов

ARRAY [O..N] OF CHAR, однако, в отличие от последнего, количество

символов в строке-переменной может меняться от 0 до N, где N - макси-

мальное количество символов в строке. Значение N определяется объяв-

лением типа STRING[N] и может быть любой константой порядкового типа,

но не больше 255 . Турбо Паскаль разрешает не указывать N, в этом случае

длина строки принимается максимально возможной, а именно N-255 .

Строка в Турбо Паскале трактуется как цепочка символов. К любому

символу в строке можно обратиться точно так же, как к элементу одномер-

ного массива ARRAY [O..N] OF CHAR, например:

var

st : string;

if st[5] - 'A' then .. .

Самый первый байт в строке имеет индекс 0 и содержит текущую длину

строки. Первый значащий символ строки занимает второй байт и имеет

индекс 1. Над длиной строки можно осуществлять необходимые действия и

таким способом изменять длину. Например, удалить из строки все ведомые

пробелы можно следующим образом:

var

st : strlng[10];

i : word;

66

Page 67: Комплексное пособие

i := 10;

while (st[l]=' ') and (i<>0) do begin dec(i):

st[0] := chr(i) end;

Значение ORD(st[0]) , т.е. текущую длину строки, можно получить и с

помощью функции LENGTH(st), например:

while ( Iength(st)<>0) and (st[ length(st)]-' ') do

s[0] := chr(length(st)-1)

К строкам можно применять операцию «+» - сцепление, например:

st := 'а' + 'b':

st := st + 'с'; {st содержит 'abc'}

Если длина сцепленной строки превысит максимально допустимую

длину N, то «лишние» символы отбрасываются. Следующая программа,

например, напечатает символ 1:

var

st:string[1];

begin

st:='123';

writeln(st)

end.

Все остальные действия над строками и символами реализуются с

помощью встроенных процедур и функций.

CONCAT(S1 [,S2, ... ,SN]) - функция типа STRING; возвращает строку,

представляющую собой сцепление строк-параметров SI, S2,... ,SN.

COPY(ST, INDEX, COUNT) - функция типа STRING; копирует из строки

ST COUNT символов, начиная с символа с номером INDEX.

DELETE(ST, INDEX, COUNT) - процедура; удаляет COUNT символов

из строки ST, начиная с символа с номером INDEX.

67

Page 68: Комплексное пособие

INSERT(SUBST, ST, INDEX) - процедура; вставляет подстроку SUBST в

строку ST, начиная с символа с номером INDEX.

LENGTH(ST) - функция типа INTEGER; возвращает длину строки ST.

POS(SUBST, ST) - функция типа INTEGER: отыскивает в строке ST

первое вхождение подстроки SUBST и возвращает номер позиции, с которой

она начинается; если подстрока не найдена, возвращается ноль.

STR(X [:WIDTH [:DECIMALS]], ST) - процедура; преобразует число Х

любого вещественного или целого типов в строку символов ST так, как это

делает процедура WRITELN перед выводом; параметры WIDTH и DECIMALS,

если они присутствуют, задают формат преобразования:

WIDTH определяет общую ширину поля, выделенного под

соответствующее символьное представление вещественного или целого

числа X, а DECIMALS - количество символов в дробной части (имеет смысл

только в том случае, когда Х - вещественное число).

VAL(ST, X, CODE) - процедура; преобразует строку символов ST во

внутреннее представление целой или вещественной переменной X, которое

определяется типом этой переменной; параметр CODE содержит ноль, если

преобразование прошло успешно, и тогда в Х помещается результат

преобразования, в противном случае он содержит номер позиции в строке

ST. где обнаружен ошибочный символ, и в этом случае содержимое Х не

меняется; ведущие пробелы в строке ST должны отсутствовать.

UPCASE(CH) - функция типа CHAR; возвращает для символьного

выражения CH, которое должно представлять собой строчную латинскую

букву, соответствующую заглавную букву; если значением CH является

любой другой символ, функция возвращает его без преобразований.

Примеры:

var

х : real;

у : Integer:

st,st1: string;

68

Page 69: Комплексное пособие

st:=concat('12','345'); {строка st содержит 12345}

st1:=copy(st,3,length(st)-2); {st1 содержит 345}

insert('-',st1,2); {строка st1 содержит 3-45}

delete(st,pos{'2',st),3); {строка st содержит 12}

str(pi:6:2,st); {строка st содержит 3.14)

st1:='3,1415':

Сравнение строк:

'Turbo' < 'Turbo Pascal'

'Паскаль' > 'Turbo Pascal'

Структурированный тип данных – записи

Записи

Запись – это структура данных, состоящая из фиксированного числа

компонентов, называемых полями записи. В отличие от массива, компоненты

(поля) записи могут быт различного типа. Чтобы можно было ссылаться на

тот или иной компонент записи, поля именуются.

Структура объявления записи такова:

<имя типа>= record <список полей> end;

Здесь <имя типа> – правильный идентификатор;

record, end – зарезервированные слова;

<список полей> – список полей; представляет собой последовательность

разделов записи, между которыми ставится точка с запятой.

Каждый раздел записи состоит из одного или нескольких

идентификаторов полей, отделяемых друг от друга запятыми. За

идентификатором (идентификаторами) ставится двоеточие и описание типа

поля (полей), например:

Type

Birthday=record

69

Page 70: Комплексное пособие

day, month: byte;

year : word;

end;

var

a,b: Birthday;

...

В этом примере тип Birthday (день рождения) содержит три поля с

именами day, month и year (день, месяц и год); переменные a, b сидержат

записи типа Birthday.

Как и в массиве, значения переменных типа запись можно присваивать

другим переменным того же типа, например

A:=b;

К каждому из компонентов записи можно получить доступ, если

использовать составное имя, т.е. указать имя переменной, затем точку и имя

поля:

a.day:=27;

b.year:=1939;

Для вложенных полей приходится продолжать уточнения:

var

c: record

name : string;

bd : Birthday;

end;

...

if c.bd.year=1939 then ...

70

Page 71: Комплексное пособие

Оператор WITH

Если в программе содержится большое число обращений к

компонентам записи (полям), то указание имени записи и имени поля с

помощью сочленяющей точки будет громоздким . Для упрощения вводится

оператор WITH - присоединение. Его еще называют оператором над

записями.

Общая форма

WITH имя переменной-записи DO оператор

Тогда в операторе или составном операторе следующем за DO имя

переменной записи можно опускать , а использовать только имя поля.

Пример обращения к полям:

gl.price := 200;

with gl do

begin

price := 200;

number := 10

end;

Оператор with удобнее использовать, если требуется обращаться к

нескольким полям одной и той же записи.

Пример. Сведения о товарах на складе хранятся в текстовом файле. Для

каждогс товара отводится одна строка, в первых 20 позициях которой

записано наименование товара, а затем через произвольное количество

пробелов его цена и количе ство единиц. Программа по запросу выдает

сведения о товаре или сообщение о тол что товар не найден.

program store;

const Max_n = 100;

type

71

Page 72: Комплексное пособие

str20 = string [20];

goods = record

name : str20;

price : real;

number : integer;

end;

var stock : array[l..Max_n] of goods;

i, j, len : integer;

name : str20;

found : boolean;

count : integer;

begin

write('Введите количество товаров: ');

readln(count);

for i:=1 to count do begin

writeln(‘Введите в отдельных строках наимен., цену и кол-во’);

with stock[i] do

readln(name, price, number);

end.

Рассмотрим пример программы с использованием массива структур. В

ведомости, содержащей фамилии группы студентов, оценки по физике,

математике и программированию определить средний балл каждого студента

и средний балл в группе.

В программе использованы следующие обозначения :

n1– максимальное количество студентов в группе;

n – реальное количество студентов в группе;

student– идентификатор типа, представляющий запись с полями

fam, fiz, mat, pr и ss;

fam – поле записи, содержащее фамилию студента;

72

Page 73: Комплексное пособие

fiz, mat, pr – поле записи, содержащее оценки по физике, математике

и программированию соответственно;

ss – поле записи, содержащее средний балл студента;

ved – массив, содержащий элементы типа student;

sg – средний балл группы;

i – индекс элемента массива ved;

Программа выглядит следующим образом:

program stud;

const n1=30;

type student=record

fam:string[10];

fiz,mat,pr:integer;

ss:real;

end;

var ved:array[1..n1] of student;

i,n:integer;

sg:real;

begin

writeln('сколько студентов в группе?');

read(n);

for i:=1 to n do

with ved[i] do

begin

writeln('введите фамилию студента');

read(fam);

writeln('введите оценки');

read(fiz,mat,pr)

end;

sg:=0;

for i:=1 to n do

with ved[i] do

begin

ss:=(fiz+mat+pr)/3; {вычисление среднего балла

73

Page 74: Комплексное пособие

студента}

sg:=sg+ss;

end;

sg:=sg/n;{вычисление среднего балла группы}

writeln('ведомость группы');

write('! фамилия ! физика ! матем ! прогр !');

writeln('! cp. балл !')

for i:=1 to n do

with ved[i] do

begin

write('!',fam:10,'!',fiz:10,'!',mat:10,'!',pr:10);

writeln('!',ss:10:2,'!');

end;

writeln('средний балл в группе =',sg);

end.

Иногда бывает необходимо иметь в программе несколько родственных,

но не совсем идентичных записей. Такая необходимость возникает,

например, для программы, которая обрабатывает информацию о человеке и

тогда, в зависимости от значения поля sex (мужской или женский),

появляются поля:

время прохождения очередных военных сборов;

род войск, в которых проходил военный сбор;

или же:

любимые цветы.

Для таких случаев в Турбо-Паскале предусмотрены записи с

вариантами. Такие записи содержат фиксированную и вариантную часть,

которая начинается с ключевого слова case. Рассмотрим пример:

type personsex=(male,female);

person = record

name,secondname,surname : string[20];

birthday : date;

case sex : personsex of

male : ( army1 : date;

74

Page 75: Комплексное пособие

army2 : string[20]);

female : (flower : srting[20]);

end;

Следует отметить, что вариантная часть всегда располагается после

фиксированной части, а отводимая память вычисляется по самому большому

варианту, т.е. различные варианты одной записи как бы "накладываются"

друг на друга.

Структурированный тип данных - множество

Определение множеств

Множества – это наборы однотипных логически связанных друг с

другом объектов. Характер связей между объектами лишь подразумевается

программистом и никак не контролируется Турбо Паскалем. Количество

элементов, входящих в множество, может меняться от 0 до 256 (множество,

не содержащее элементов, называется пустым). Именно непостоянством

количества своих элементов множества отличаются от массивов и записей.

Два множества считаются эквивалентными тогда и только тогда, когда

все их элементы одинаковы, причем порядок следования элементов в

множестве безразличен. Если все элементы одного множества входят также и

в другое, говорят о включении первого множества во второе. Пустое

множество включается в любое другое.

Пример определения и задания множеств:

type

DigitChar = set of '0'..'9';

Digit = set of 0..9;

var

s1,s2,s3: DigitChar;

s4,s5,s6: Digit;

...

s1:=['1','2','3'];

s2:=['3','2','1'];

75

Page 76: Комплексное пособие

s1:=['2','3'];

s1:=[0..3,6];

s1:=[4,5];

s1:=[3..9];

...

В этом примере множества s1 и s2 эквивалентны, а множество s3

включено в s2, но не эквивалентно ему.

Описание типа множество имеет вид

<имя типа> = set of <базовый тип>;

Здесь <имя типа> – правильный идентификатор;

set, of – зарезервированные слова (множество, из);

<базовый тип> – базовый тип элементов множества, в качестве которого

может использоваться любой порядковый тип, кроме Word, Integer, Longint.

Для задания множества используется так называемый конструктор

множества: список спецификаций элементов множества, отделяемых друг от

друга запятыми; список обрамляется квадратными скобками.

Спецификациями элементов могут быть константы или выражения базового

типа, а также – тип-диапазон того же базового типа.

Операции над множествами

Над множествами определены следующие операции:

* – пересечение множеств; результат содержит элементы, общие для

обоих множеств. Например, s4*s6 содержит [3], s4*s5 – пустое множество.

+ – объединение множеств; результат содержит элементы из первого

множества дополненные недостающими элементами из второго множества:

s4+s5 содержит [0,1,2,3,4,5,6];

s5+s6 содержит [3,4,5,6,7,8,9];

- – разность множеств; результат содержит те элементы из первого

множества, которые не принадлежат второму:

s6-s5 содержит [3,6,7,8,9];

76

Page 77: Комплексное пособие

s4-s5 содержит [0,1,2,3,6];

= – проверка эквивалентности; возвращает true, если множества

эквивалентны.

<> – проверка неэквивалентности; возвращает true, если множества

неэквивалентны.

<= – проверка вхождения; возвращает true, если первое множество

является подмножеством второго.

>= – проверка вхождения; возвращает true, если второе множество

является подмножеством первого.

in – проверка принадлежности; в этой бинарной операции первый

элемент – выражение, а второй – множество того же типа; возвращает true,

если выражение имеет значение, принадлежащее множеству:

3 in s6 возвращает true;

2*2 in s1 возвращает false;

Пример

В следующем примере реализуется алгоритм выделения из первой сотни

натуральных чисел всех простых. В его основе (также как и в примере из

лабораторной работы №3) лежит прием, известный под названием «решето

Эратосфена». Сравните программы, приведенные здесь и в лабораторной

работе №3.

{ Выделение всех простых чисел из первых N целых }

const

N = 100; {Количество элементов исходного множества}

type

SetOfNumber = set of 1..N:

var

n1,next,i : word; {Вспомогательные переменные}

BeginSet, {Исходное множество}

PrimerSet : SetOfNumber; {Множество простых чисел} BEGIN

BeginSet := [2..N]; {Создать исходное множество}

77

Page 78: Комплексное пособие

PrimerSet := [1]; {Первое простое число}

Next := 2; {Следующее простое число}

while BeginSet <> [] do {Начало основного цикла}

begin

n1:= next; {n1-число,кратное очередному

простому (next)}

while n1 <- N do {Цикл удаления из исходного

множества непростых чисел:}

begin

BeginSet := BeginSet-[n1];

n1 :=n1+next; {Следующее кратное}

end; {Конец цикла удаления}

PrimerSet := PrimerSet+[next];

repeat {Получить следующее простое, которое есть

первое невычеркнутое из исходного множества}

inc(next)

until (next In BeginSet) or (next > N)

end; {Конец основного цикла)

{ Вывод результата: }

for i := 1 to N do

if I in PrimerSet then write(i:8);

writeln;

END.

Процедуры и функции

Описание подпрограммы

Описание подпрограммы состоит из заголовка и тела подпрограммы.

Заголовок процедуры имеет вид:

PROCEDURE <имя> [(<сп.ф. п. >)];

Заголовок функции:

78

Page 79: Комплексное пособие

FUNCTION <имя> [(<.сп.ф.п.>)] : <тип>:

Здесь <имя> - имя подпрограммы (правильный идентификатор);

<сп.ф.п-> - список формальных параметров,

<тип> - тип возвращаемого функцией результата.

Полный формат описания процедуры:

Procedure <Имя процедуры> (<Имя форм. параметра 1>:<Тип1>;

< Имя форм. параметра 2>:<Тип2>);

<Раздел описаний>

Begin

<Тело процедуры>

End;

Раздел описаний может иметь такие же подразделы, как и раздел

описаний основной программы (описание процедур и функций - в том

числе). Однако все описанные здесь объекты "видимы" лишь в этой

процедуре. Они здесь локальны также, как и имена формальных параметров.

Объекты, описанные ранее в разделе описаний основной программы и не

переопределенные в процедуре, называются глобальными для этой

подпрограммы и доступны для использования.

Формат описания функции:

Function <Имя функции> (<Имя форм. параметра 1>:<Тип>;

< Имя форм. параметра 2>:<Тип>?) : <Тип результата>;

<Раздел описаний>

Begin

<Тело функции>

End;

В теле функции обязательно должна быть хотя бы команда присвоения

такого вида:

<Имя функции>:=<Выражение>;

79

Page 80: Комплексное пособие

Указанное выражение должно приводить к значению того же типа, что и

тип результата функции, описанный выше.

Сразу за заголовком подпрограммы может следовать одна из стан-

дартных директив ASSEMBLER, EXTERNAL. FAR, FORWARD, INLINE,

INTERRUPT, NEAR. Эти директивы уточняют действия компилятора и

распространяются на всю подпрограмму и только на нее, т.е. если за

подпрограммой следует другая подпрограмма, стандартная директива,

указанная за заголовком первой, не распространяется на вторую.

Например, директива FORWARD используется при опережающем

описании для сообщения компилятору, что описание подпрограммы следует

где-то дальше по тексту программы (но в пределах текущего программного

модуля).

Вызов процедуры представляет в программе самостоятельную

инструкцию:

<Имя процедуры>(<Фактический параметр 1>, <Фактический параметр

2>,…);

Типы фактических параметров должны быть такими же, что и у

соответствующих им формальных.

Вызов функции должен входить в выражение. При вычислении значения

такого выражения функция будет вызвана, действия, находящиеся в ее теле,

будут выполнены, в выражение будет подставлено значение результата

функции.

Параметры

Список формальных параметров необязателен и может отсутствовать.

Если же он есть, то в нем должны быть перечислены имена формальных

параметров и их тип, например:

Procedure SB (a : real; b : Integer: с : char);

80

Page 81: Комплексное пособие

Как видно из примера, параметры в списке отделяются друг от друга

точками с запятой. Несколько следующих подряд однотипных параметров

можно объединять в подсписки, например, вместо

Function F (а : real; b : real) : real;

можно написать проще:

Function F (a, b : real) : real;

Операторы тела подпрограммы рассматривают список формальных

параметров как своеобразное расширение раздела описаний: все переменные

из этого списка могут использоваться в любых выражениях внутри

подпрограммы. Таким способом осуществляется настройка алгоритма

подпрограммы на конкретную задачу.

Любой из формальных параметров подпрограммы может быть либо

параметром-значением, либо параметром-переменной. В предыдущем

примере параметры А и В определены как параметры-значения. Если

параметры определяются как параметры-переменные, перед ними

необходимо ставить зарезервированное слово VAR, например:

Function Power (var a : real; b : real) : real;

Здесь параметр А – параметр-переменная, а В – параметр-значение.

Определение формального параметра тем или иным способом

существенно только для вызывающей программы: если формальный

параметр объявлен как параметр-переменная, то при вызове подпрограммы

ему должен соответствовать фактический параметр в виде переменной нуж-

ного типа; если формальный параметр объявлен как параметр-значение, то

при вызове ему может соответствовать произвольное выражение. Контроль

81

Page 82: Комплексное пособие

за неукоснительным соблюдением этого правила осуществляется

компилятором Турбо Паскаля.

Для того чтобы понять, в каких случаях использовать параметры-

значения, а в каких - параметры-переменные, рассмотрим, как

осуществляется замена формальных параметров на фактические в момент

обращения к подпрограмме.

Если параметр определен как параметр-значение, то перед вызовом

подпрограммы это значение вычисляется, полученный результат копируется

во временную память и передается подпрограмме. Важно учесть, что даже

если в качестве фактического параметра указано простейшее выражение в

виде переменной или константы, все равно подпрограмме будет передана

лишь копия переменной (константы). Если же параметр определен как

параметр-переменная, то при вызове подпрограммы передается сама

переменная, а не ее копия. Любые возможные изменения в подпрограмме

параметра-значения никак не воспринимаются вызывающей программой, так

как в этом случае изменяется копия фактического параметра, в то время как

изменение параметра-переменной приводит к изменению самого

фактического параметра в вызывающей программе.

Представленный ниже пример поясняет изложенное. В программе

задаются два целых числа 5 и 7, эти числа передаются процедуре INC2, в

которой они удваиваются. Один из параметров передается как параметр-

переменная, другой - как параметр-значение. Значения параметров до и после

вызова процедуры, а также результат их удвоения выводятся на экран.

const

а : integer = 5;

b : integer = 7;

PROCEDURE lnc2 (var с : Integer; b : Integer);

begin {Inc2}

с := с + с;

b := b + b;

writeln(' удвоенные:', c:5, b:5);

82

Page 83: Комплексное пособие

end; {Inc2}

BEGIN {main}

writeln(' исходные:'. a:5, b:5);

lnc2(a,b);

writeln(' результат:', a:5, b:5);

END. {main}

В результате прогона программы будет выведено:

Исходные: 5 7 удвоенные 10 14 результат 10 7

Как видно из примера, удвоение второго формального параметра в

процедуре INC2 не вызвало изменения фактической переменной В, так как

этот параметр описан в заголовке процедуры как параметр-значение. Этот

пример может служить еще и иллюстрацией механизма "закрывания"

глобальной переменной одноименной локальной: хотя переменная В

объявлена как глобальная (она описана в вызывающей программе перед

описанием процедуры), в теле процедуры ее «закрыла» локальная пере-

менная В, объявленная как параметр-значение.

Итак, параметры-переменные используются как средство связи ал-

горитма, реализованного в подпрограмме, с «внешним миром»: с помощью

этих параметров подпрограмма может передавать результаты своей работы

вызывающей программе. Разумеется, в распоряжении программиста всегда

есть и другой способ передачи результатов - через глобальные переменные.

Однако злоупотребление глобальными связями делает программу, как

правило, запутанной, трудной в понимании и сложной в отладке. В

соответствии с требованиями хорошего стиля программирования

рекомендуется там, где это возможно, использовать передачу результатов

через фактические параметры-переменные.

С другой стороны, описание всех формальных параметров как

параметров-переменных нежелательно по двум причинам. Во-первых, это

83

Page 84: Комплексное пособие

исключает возможность вызова подпрограммы с фактическими параметрами

в виде выражений, что делает программу менее компактной. Во-вторых, и

главных, в подпрограмме возможно случайное использование формального

параметра, например, для временного хранения промежуточного результата,

т.е. всегда существует опасность непреднамеренно «испортить» фактическую

переменную. Вот почему параметрами-переменными следует объявлять

только те, через которые подпрограмма в действительности передает

результаты вызывающей программе. Чем меньше параметров объявлено

параметрами-переменными и чем меньше в подпрограмме используется

глобальных переменных, тем меньше опасность получения

непредусмотренных программистом побочных эффектов, связанных с

вызовом подпрограммы, тем проще программа в понимании и отладке. По

той же причине не рекомендуется использовать параметры-переменные в

заголовке функции: если результатом работы функции не может быть

единственное значение, то логичнее использовать процедуру или нужным

образом декомпозировать алгоритм на несколько подпрограмм.

Существует одно обстоятельство, которое следует учитывать при

выборе вида формальных параметров. Как уже говорилось, при объявлении

параметра-значения осуществляется копирование фактического параметра во

временную память. Если этим параметром будет массив большой

размерности, то существенные затраты времени и памяти на копирование

при многократных обращениях к подпрограмме могут стать решающим

доводом в пользу объявления такого параметра параметром-переменной или

передачи его в качестве глобальной переменной.

Примеры

Определение максимума из трех чисел:

Program Fn;

Var

A,B,C :Real;

84

Page 85: Комплексное пособие

Function Max(A,B:Real):Real;

{Описываем функцию Max с формальными}

Begin {параметрами A и B, которая принимает }

If A>B Then

Max:=A {значение максимального из них }

Else

Max:=B

{Здесь A и B - локальные переменные }

End;

Begin

Writeln('Введите три числа');

Readln(A,B,C);

Writeln('Максимальным из всех является ', Max(Max(A,B),C))

End.

Упорядочивание трёх чисел в порядке неубывания:

Program Pr;

Var

S1,S2,S3 :Integer;

Procedure Swap(Var A,B: Integer);

{Процедура Swap с параметрами-переменными}

Var C : Integer; {C - независимая локальная переменная}

Begin

C:=A; A:=B; B:=C {Меняем местами содержимое A и B}

End;

Begin

Writeln('Введите три числа');

Readln(S1,S2,S3);

If S1>S2 Then Swap(S1,S2);

If S2>S3 Then Swap(S2,S3);

If S1>S2 Then Swap(S1,S2);

Writeln('Числа в порядке неубывания:V',S1,S2,S3)

End.

85

Page 86: Комплексное пособие

Рассмотрим следующий пример. В языке Турбо Паскаль нет операции

возведения в степень, однако с помощью встроенных функций LN(X) и

ЕХР(Х) нетрудно реализовать новую функцию с именем, например, POWER,

осуществляющую возведение любого вещественного числа в любую

вещественную степень. В следующем примере вводится пара чисел X и У и

выводится на экран дисплея результат возведения Х сначала в степень +У, а

затем - в степень - У. Для выхода из программы нужно ввести Ctrl-Z и

«Ввод».

var

х,у : real;

FUNCTION Power(a,b : real) : real;

begin {Power}

if a > 0 then Power := exp(b * In(a))

else

If a < 0 then

Power := exp(b * ln(abs(a))) eIse

if b=0 then Power := 1 else Power := 0

end {Power};

BEGIN {main}

repeat

readln(x,y);

wrlteln(power(x,y):12:10, power (x, -у) :15:10)

until EOF;

END. {main}

Для вызова функции POWER мы просто указали ее в качестве параметра

при обращении к встроенной процедуре WRITELN. Параметры Х и У в

момент обращения к функции - это фактические параметры. Они

подставляются вместо формальных параметров А и В в заголовке функции и

затем над ними осуществляются нужные действия. Полученный результат

присваивается идентификатору функции - именно он и будет возвращен как

86

Page 87: Комплексное пособие

значение функции при выходе из нее. В программе функция POWER

вызывается дважды - сначала с параметрами Х и Y, а затем Х и -У, поэтому

будут получены два разных результата.

Механизм замены формальных параметров на фактические позволяет

нужным образом настроить алгоритм, реализованный в подпрограмме. Турбо

Паскаль следит за тем, чтобы количество и тип формальных параметров

строго соответствовали количеству и типам фактических параметров в

момент обращения к подпрограмме. Смысл используемых фактических

параметров зависит от того, в каком порядке они перечислены при вызове

подпрограммы. В примере первый по порядку фактический параметр будет

возводиться в степень, задаваемую вторым параметром, а не наоборот.

Пользователь должен сам следить за правильным порядком перечисления

фактических параметров при обращении к подпрограмме.

Параметры-массивы и параметры-строки

Может сложиться впечатление, что объявление переменных в списке

формальных параметров подпрограммы ничем не отличается от объявления

их в разделе описания переменных. Действительно, в обоих случаях много

общего, но есть одно существенное различие: типом любого параметра в

списке формальных параметров может быть только стандартный или ранее

объявленный тип. Поэтому нельзя, например, объявить следующую

процедуру:

Procedure S (a : array (1..10] of real);

так как в списке формальных параметров фактически объявляется тип-

диапазон, указывающий границы индексов массива.

Если мы хотим передать какой-то элемент массива, то проблем, как

правило, не возникает, но если в подпрограмму передается весь массив, то

следует первоначально описать его тип. Например:

87

Page 88: Комплексное пособие

type

atype = array [1..10] of real;

PROCEDURE S (a : atype);

Поскольку строка является фактически своеобразным массивом, ее

передача в подпрограмму осуществляется аналогичным образом:

type

intype = string[15];

outype = string[30];

FUNCTION St (s : intype) : outype;

Требование описать любой тип-массив или тип-строку перед

объявлением подпрограммы на первый взгляд кажется несущественным.

Действительно, в рамках простейших вычислительных задач обычно заранее

известна структура всех используемых в программе данных, поэтому

статическое описание массивов не вызывает проблем. Однако разработка

программных средств универсального назначения, например, типа широко

используемых в среде Фортрана ОС ЕС библиотек подпрограмм для научных

и инженерных расчетов, связана со значительными трудностями. По

существу, речь идет о том, что в Турбо Паскале невозможно использовать в

подпрограммах массивы с «плавающими» границами изменения индексов.

Например, если разработана программа, обрабатывающая матрицу из 10 х 10

элементов, то для обработки матрицы из 9 х 11 элементов необходимо

переопределить тип, т.е. перекомпилировать всю программу (сейчас речь

идет не о динамическом размещении массивов в куче, а о статическом

описании массивов и передаче их как параметров в подпрограммы). Этот

недостаток, как и отсутствие в языке средств обработки исключительных

ситуаций (прерываний), унаследован из стандартного Паскаля и представляет

собой объект постоянной и вполне заслуженной его критики. Разработчики

Турбо Паскаля не рискнули кардинально изменить свойства базового языка,

88

Page 89: Комплексное пособие

но, тем не менее, включили в него некоторые средства, позволяющие в

известной степени смягчить отмеченные недостатки.

Прежде всего, в среде Турбо Паскаля можно установить режим

компиляции, при котором отключается контроль за совпадением длины

фактического и формального параметра-строки. Это позволяет легко решить

вопрос о передаче подпрограмме строки произвольной длины. При передаче

строки меньшего размера формальный параметр будет иметь ту же длину,

что и параметр обращения; передача строки большего размера приведет к ее

усечению до максимального размера формального параметра. Следует

сказать, что контроль включается только при передаче строки, объявленной

как формальный параметр-переменная. Если соответствующий параметр

объявлен параметром-значением, эта опция игнорируется и длина не

контролируется.

Работа с файлами

Файловые переменные

Под файлом понимается либо именованная область внешней памяти ПК

(жесткого диска, гибкой дискеты, электронного «виртуального» диска), либо

логическое устройство – потенциальный источник или приемник

информации.

Любой файл имеет три характерные особенности. Во-первых, у него

есть имя, что дает возможность программе работать одновременно с не-

сколькими файлами. Во-вторых, он содержит компоненты одного типа.

Типом компонентов может быть любой тип Турбо Паскаля, кроме файлов.

Иными словами, нельзя создать «файл файлов». В-третьих, длина вновь

создаваемого файла никак не оговаривается при его объявлении и ограни-

чивается только емкостью устройств внешней памяти.

Файловый тип или переменную файлового типа можно задать одним из

трех способов:89

Page 90: Комплексное пособие

<имя> = FILE OF <mun>;

<имя> = TEXT:

<имя> = FILE;

Здесь <имя> - имя файлового типа (правильный идентификатор);

FILE, OF - зарезервированные слова (файл, из);

TEXT - имя стандартного типа текстовых файлов;

<тип> - любой тип Турбо Паскаля, кроме файлов.

Например:

type

product = record name string;

соde : word;

cost : comp;

end;

text80 = file of string[80];

var

f1 : file of char;

f2 : text;

f3 : file;

f4 : text80;

f5 : file of product;

В зависимости от способа объявления можно выделить три вида файлов:

типизированные файлы (задаются предложением FILE OF...);

текстовые файлы (определяются типом TEXT);

нетипизированные файлы (определяются типом FILE).

В наших примерах FI, F4 и F5 - типизированные файлы, F2 -текстовый

файл, F3 - нетипизированный файл. Вид файла, вообще говоря, определяет

способ хранения информации в файле. Однако в Турбо Паскале нет средств

контроля вида ранее созданных файлов. При объявлении уже существующих

файлов программист должен сам следить за соответствием вида объявления

характеру файла.

90

Page 91: Комплексное пособие

Любой программе доступны два предварительно объявленных файла со

стандартными файловыми переменными: INPUT - для чтения данных с

клавиатуры и OUTPUT - для вывода на экран. Стандартный Паскаль требует

обязательного упоминания этих файлов в заголовке программы, например,

так

PROGRAM NameOfProfgram( input, output);

В Турбо Паскале это необязательно, вот почему заголовок программы

можно опускать.

Связывание файловой переменной с именем файла

Любые другие файлы, а также логические устройства становятся

доступны программе только после выполнения особой процедуры открытия

файла (логического устройства). Эта процедура заключается в связывании

ранее объявленной файловой переменной с именем существующего или

вновь создаваемого файла, а также в указании направления обмена

информацией: чтение из файла или запись в него.

Файловая переменная связывается с именем файла в результате

обращения к стандартной процедуре ASSIGN:

ASSIGN (<ф.п.>, <имя файла или, л.у.>);

Здесь <ф.п.> - файловая переменная (правильный идентификатор,

объявленный в программе как переменная файлового типа);

<имя файла или л.у.> - текстовое выражение, содержащее имя файла или

логическое устройство.

Если имя файла задается в виде пустой строки, например, ASSIGN(f,"),

то в зависимости от направления обмена данными файловая переменная

связывается со стандартным файлом INPUT или OUTPUT.

91

Page 92: Комплексное пособие

Имя файла - это любое выражение строкового типа, которое строится

по правилам определения имен в MS DOS (операционной системе ПК):

имя содержит до восьми разрешенных символов; разрешенные

символы - это прописные и строчные латинские буквы, цифры и

символы: !@#$%^&()'~-_

имя начинается с любого разрешенного символа;

за именем может следовать расширение - последовательность до

трех разрешенных символов; расширение, если оно есть, отделяется

от имени точкой.

Перед именем может ставиться так называемый путь к файлу: имя диска

и/или имя текущего каталога и имена каталогов вышестоящих уровней.

Имя диска - это один из символов A...Z , после которого ставится

двоеточие. Имена А: и В: относятся к дисковым накопителям на гибких

дискетах, имена С:. D: и т.д. - к жестким дискам.

За именем диска может указываться имя каталога, содержащего файл.

Если имени каталога предшествует обратная косая черта, то путь к файлу

начинается из корневого каталога, если черты нет - из текущего каталога,

установленного в системе по умолчанию. За именем каталога может

следовать одно или несколько имен каталогов нижнего уровня. Каждому из

них должна предшествовать обратная косая черта. Весь путь к файлу

отделяется от имени файла обратной косой чертой. Максимальная длина

имени вместе с путем - 79 символов, например:

var

finp:text;

fout : file of string;

const

name = ' c:\dir\subdir\out.txt';

assign(finp, '123.dat');

assign(fout, name);

92

Page 93: Комплексное пособие

Инициация файла

Инициировать файл означает указать для этого файла направление

передачи данных. В Турбо Паскале можно открыть файл для чтения, для

записи информации, а также для чтения и записи одновременно.

Для чтения файл инициируется с помощью стандартной процедуры

RESET:

RESET (<ф. п.>);

Здесь <ф.п.> - файловая переменная, связанная ранее процедурой

ASSIGN с уже существующим файлом или логическим устройством-при-

емником информации.

При выполнении этой процедуры дисковый файл или логическое

устройство подготавливается к чтению информации. В результате специ-

альная переменная-указатель, связанная с этим файлом, будет указывать на

начало файла, т.е. на компонент с порядковым номером 0.

Если делается попытка инициировать чтение из несуществующего

файла или из логического устройства PRN, возникает ошибка периода

исполнения, которая может быть сообщена программе ненулевым значением

встроенной функции IORESULT типа WORD. Например, следующий

фрагмент программы позволяет установить, существует ли требуемый файл

на диске:

var

f : file of char;

assign(f,'myfile.dat');

{$I-} {Отключить контроль ошибок ввода-вывода}

reset(f):

{SI+} {Включить контроль ошибок ввода-вывода)

If IOResult о 0 then

..... {Файл не существует}

else

93

Page 94: Комплексное пособие

..... {Файл существует}

В этом фрагменте с помощью директивы компилятора {$I-} отключается

автоматический контроль ошибок ввода-вывода. Если этого не сделать, то

отсутствие файла приведет к аварийному завершению программы.

В Турбо Паскале разрешается обращаться к типизированным файлам,

открытым процедурой RESET (т.е. для чтения информации), с помощью

процедуры WRITE (т.е. для записи информации). Такая возможность

позволяет легко обновлять ранее созданные типизированные файлы и при

необходимости расширять их. Для текстовых файлов, открытых процедурой

RESET, нельзя использовать процедуру WRITE или WRITELN.

Стандартная процедура REWRITE (<ф.п.>) инициирует запись

информации в файл или в логическое устройство, связанное ранее с

файловой переменной <ф. п. >. Процедурой REWRITE нельзя инициировать

запись информации в ранее существовавший дисковый файл: при

выполнении этой процедуры старый файл уничтожается и никаких

сообщений об этом в программу не передается. Новый файл

подготавливается к приему информации и его указатель принимает значение

0.

Стандартная процедура APPEND (<ф.п.>) инициирует запись в ранее

существовавший текстовый файл для его расширения, при этом указатель

файла устанавливается в его конец. Процедура APPEND применима только к

текстовым файлам, т.е. их файловая переменная должна иметь тип TEXT (см.

выше). Процедурой APPEND нельзя инициировать запись в типизированный

или нетипизированный файл. Если текстовый файл ранее уже был открыт с

помощью RESET или REWRITE, использование процедуры APPEND приведет

к закрытию этого файла и открытию его вновь, но уже для добавления

записей.

94

Page 95: Комплексное пособие

Процедуры и функции для работы с файлами

Ниже описываются процедуры и функции, которые можно использовать

с файлами любого вида. Специфика работы с типизированными, текстовыми

и нетипизированными файлами рассматривается в следующих разделах.

Процедура CLOSE. Закрывает файл, однако связь файловой переменной

с именем файла, установленная ранее процедурой ASSIGN, сохраняется.

Формат обращения:

CLOSE (<ф.п.>)

При создании нового или расширении старого файла процедура

обеспечивает сохранение в файле всех новых записей и регистрацию файла в

каталоге. Функции процедуры CLOSE выполняются автоматически по

отношению ко всем открытым файлам при нормальном завершении

программы. Поскольку связь файла с файловой переменной сохраняется,

файл можно повторно открыть без дополнительного использования

процедуры ASSIGN.

Процедура RENAME. Переименовывает файл. Формат обращения:

RENAME (<ф.п.>, <новое имя>)

Здесь <новое имя> - строковое выражение, содержащее новое ими

файла. Перед выполнением процедуры необходимо закрыть файл, если он

ранее был открыт процедурами RESET, REWRITE или APPEND.

Процедура ERASE. Уничтожает файл. Формат обращения:

ERASE(<ф.п.>)

Перед выполнением процедуры необходимо закрыть файл, если он ранее

был открыт процедурами RESET, REWRITE или APPEND.

95

Page 96: Комплексное пособие

Следующий фрагмент программы показывает, как можно использовать

процедуры RENAME и CLOSE при работе с файлами. Предположим, что

требуется отредактировать файл, имя которого содержит переменная NAME.

Перед редактированием необходимо убедиться, что нужный файл имеется на

диске, и переименовать его - заменить расширение этого файла на .ВАК

(страховочная копия). Если файл с таким расширением уже существует, его

надо стереть.

var

fi : text; {Исходный файл}

fo : text; {Отредактированный файл}

name : string;

name_bak: string;

k,i : word;

const

bak = '.bak';

........

{ Получить в name_bak имя файла с расширением .ВАК: }

k := pos('.',name):

If k=0 then k := length(name) + 1;

name_bak := copy(name,1,k-1) + bak;

{ Проверить существование исходного файла: }

assign(fi,name):

{$I-} reset(fi);

If IOResult о 0 then halt; {Файл не существует}

close(fi):

{ Проверить существование .ВАК-файла: } assign(fo,name_bak);

reset(fo);

{$I+} If IOResult = 0 then

begin {Файл .ВАК существует}

close(fo);

erase(fo);

end;

{ Проверки закончены, подготовка к работе: }

96

Page 97: Комплексное пособие

rename(fi,name_bak);

reset(fi);

assign(fo,name);

rewrite(fo);

Обратите внимание: проверка на существование BAK-файла в данном примере необходима, так как обращение

rename(fi,name_bak);

вызовет ошибку в случае, если такой файл существует.

Процедура FLUSH. Очищает внутренний буфер файла и, таким

образом, гарантирует сохранность всех последних изменений файла на диске.

Формат обращения:

FLUSH (<ф.п.>);

Любое обращение к файлу в Турбо Паскале осуществляется через

некоторый буфер, что необходимо для согласования внутреннего пред-

ставления файлового компонента (записи) с принятым в ДОС форматом

хранения данных на диске. В ходе выполнения процедуры FLUSH все новые

записи будут действительно записаны на диск. Процедура игнорируется,

если файл был инициирован для чтения процедурой RESET.

Функция EOF(<ф.п.>): BOOLEAN. Логическая функция, тестирующая

конец файла. Возвращает TRUE, если файловый указатель стоит в конце

файла. При записи это означает, что очередной компонент будет добавлен в

конец файла, при чтении - что файл исчерпан.

Процедура CHDIR. Изменение текущего каталога. Формат обращения:

CHDIR (<путь>)

Здесь <путь> - строковое выражение, содержащее путь к устанав-

ливаемому по умолчанию каталогу.97

Page 98: Комплексное пособие

Процедура GETDIR. Позволяет определить имя текущего каталога

(каталога по умолчанию). Формат обращения:

GETDIR(<ycmpoйcmвo>, <каталог>)

Здесь <устройство> - выражение типа WORD , содержащее номер

устройства: 0 - устройство по умолчанию, 1 - диск А, 2 - диск В и т.д.;

<каталог> - переменная типа STRING, в которой возвращается путь к

текущему каталогу на указанном диске.

Процедура MKDIR. Создает новый каталог на указанном диске. Формат

обращения:

MKDIR(<каталог>);

Здесь <каталог> - выражение типа STRING, задающее путь к каталогу.

Последним именем в пути, т.е. именем вновь создаваемого каталога не может

быть имя уже существующего каталога.

Процедура RMDIR. Удаляет каталог. Формат обращения:

RMDIR(<каталог>);

Удаляемый каталог должен быть пустым, т.е. не содержать файлов или

имен каталогов нижнего уровня.

Функция IORESULT : WORD. Возвращает условный признак последней

операции ввода-вывода.

Если операция завершилась успешно, функция возвращает ноль. Коды

ошибочных операций ввода-вывода представлены в прил.З. Следует

помнить, что IORESULT становится доступной только при отключенном

автоконтроле ошибок ввода-вывода. Директива компилятора {$I-} отклю-

чает, а директива {$I+} включает автоконтроль. Если автоконтроль от-

ключен, а операция ввода-вывода привела к возникновению ошибки,

98

Page 99: Комплексное пособие

устанавливается флаг ошибки и все последующие обращения к вводу-выводу

блокируются, пока не будет вызвана функция IORESULT.

Ряд полезных файловых процедур и функций становится доступным при

использовании библиотечного модуля DOS.TPU, входящего в стандартную

библиотеку TURBO.TPL . Эти процедуры и функции указаны ниже. Доступ к

ним возможен только после объявления USES DOS в начале программы

(подробнее о работе с модулями см. гл.9).

Текстовые файлы

Текстовые файлы связываются с файловыми переменными, принад-

лежащими стандартному типу TEXT. Текстовые файлы предназначены для

хранения текстовой информации. Именно в такого типа файлах хранятся,

например, исходные тексты программ. Компоненты (записи) текстового

файла могут иметь переменную длину, что существенно влияет на характер

работы с ними.

Текстовый файл трактуется в Турбо Паскале как совокупность строк

переменной длины. Доступ к каждой строке возможен лишь последова-

тельно, начиная с первой. При создании текстового файла в конце каждой

записи (строки) ставится специальный признак EOLN (End Of LiNe -конец

строки). а в конце всего файла - признак EOF (End Of File - конец файла). Эти

признаки можно протестировать одноименными логическими функциями

(см. ниже). При формировании текстовых файлов используются следующие

системные соглашения:

EOLN - последовательность кодов ASCII 13 (CR) и 10 (LF);

EOF - код 26 стандарта ASCII.

Для доступа к записям применяются процедуры READ, READLN,

WRITE, WRITELN. Они отличаются возможностью обращения к ним с

переменным числом фактических параметров, в качестве которых могут

использоваться символы, строки и числа. Первым параметром в любой из

перечисленных процедур может стоять файловая переменная. В этом случае

99

Page 100: Комплексное пособие

осуществляется обращение к дисковому файлу или логическому устройству,

связанному с переменной процедурой ASSIGN. Если файловая переменная

не указана, происходит обращение к стандартным файлам Input и Output.

Процедура READ. Обеспечивает ввод символов, строки чисел. Формат

обращения:

READ (<ф.п.>,<сп.ввода>);

или

READ (<сп.ввода>);

Здесь <сп.ввода> - список ввода: последовательность из одной или более

переменных типа CHAR, STRING, а также любого целого или вещественного

типа.

При вводе переменных типа CHAR выполняется чтение одного символа

из файла и присваивание считанного значения переменной. Если перед

выполнением чтения указатель файла достиг конца очередной строки. то

результатом чтения будет символ CR (ASCII код 13), а если достигнут конец

файла, то - символ EOF (код 26). При вводе с клавиатуры символ CR

вводится при нажатии на клавишу «Ввод», а символ EOF - при

одновременном нажатии клавиш CTRL и Z .

При вводе переменных типа STRING количество считанных процедурой

и помещенных в строку символов равно максимальной длине строки, если

только раньше не встретились символы CR или EOF. В этом случае сами

символы CR и EOF в строку не помещаются. Если количество символов во

входном потоке данных больше максимальной длины строки, «лишние»

символы до конца строки отбрасываются, а новое обращение к READ

возвращает пустую строку. Таким образом, процедура READ не в состоянии

прочесть последовательность строк: первая строка будет прочитана

100

Page 101: Комплексное пособие

нормально, а все последующие окажутся пустыми. Для ввода после-

довательности строк нужно использовать процедуру READLN (см. ниже).

При вводе числовых переменных процедура READ вначале выделяет

подстроку во входном потоке по следующему правилу: все ведущие

пробелы, символы табуляции и маркеры конца строк EOLN пропускаются;

после выделения первого значащего символа, наоборот, любой из пе-

речисленных символов или символ EOF служат признаком конца подстроки.

Выделенная таким образом подстрока затем рассматривается как символьное

представление числовой константы соответствующего типа и преобразуется

во внутреннее представление, а полученное значение присваивается

переменной. Если в подстроке был нарушен требуемый формат

представления численной константы, возникает ошибка ввода-вывода. Если

при пропуске ведущих пробелов встретился символ EOF, переменная

получает значение 0. Отметим, что в Турбо Паскале не предусмотрен ввод

шестнадцатиричных констант.

Процедура READ прекрасно приспособлена к вводу чисел. При об-

ращении к ней за вводом очередного целого или вещественного числа

процедура «перескакивает» маркеры конца строк, т.е. фактически весь файл

рассматривается ею как одна длинная строка, содержащая текстовое

представление чисел. В сочетании с проверкой конца файла функцией EOF

процедура READ позволяет организовать простой ввод массивов данных,

например, так:

const

N = 1000; { максимальная длина ввода }

var

f : text;

m : array [1..N] of real;

i : Integer;

BEGIN

assign(f, 'prog.dat');

101

Page 102: Комплексное пособие

reset(f);

i := 1;

while not EOF(f) and (I <= N) do

begin

read(f,m[i]);

inc(i);

end;

сlоse(f);

end.

Процедура READLN. Обеспечивает ввод символов, строк и чисел. Эта

процедура идентична процедуре READ за исключением того, что после

считывания последней переменной оставшаяся часть строки до маркера

EOLN пропускается, поэтому следующее обращение к READLN или READ

начинается с первого символа новой строки. Кроме того, эту процедуру

можно вызвать без параметра <сп.ввода> (см. процедуру READ), что

приведет к пропуску всех символов текущей строки вплоть до EOLN.

Процедура WRITE. Обеспечивает вывод информации в текстовый файл

или передачу ее на логическое устройство. Формат обращения:

WRITE(<ф.п.>,<сп.вывода>) или WRITE(<сп.вывода>);

Здесь <сп.вывода> - список вывода: последовательность из одного или

более выражений типа CHAR, STRING, BOOLEAN, а также любого целого

или вещественного типа.

Файловая переменная <ф.п.>, если она указана, должна быть пред-

варительно описана как переменная типа TEXT и связана с именем файла

или логическим устройством процедурой ASSIGN. Если файловая пере-

менная отсутствует, подразумевается вывод в стандартный файл OUTPUT,

который обычно связан с экраном ПК.

Любой элемент списка вывода может иметь форму

102

Page 103: Комплексное пособие

OutExpr [ : MInWidth [ : DecPlaces ] ]

Здесь OUTEXPR - выводимое выражение;

MINWIDTH, DECPLACES - выражения типа WORD (квадратные скобки

означают возможность отсутствия заключенных в них параметров).

Подпараметр MINWIDTH , если он присутствует, указывает мини-

мальную ширину поля, в которое будет записываться символьное пред-

ставление значения OUTEXPR. Если символьное представление имеет

меньшую длину, чем MINWIDTH, оно будет дополнено слева пробелами,

если - большую длину, то подпараметр MINWIDTH итерируется и выводится

необходимое число символов.

Подпараметр DECPLACES задает количество десятичных знаков в

дробной части вещественного числа. Он может использоваться только

совместно с MINWIDTH и только по отношению к выводимому выражению

одного из вещественных типов.

Если ширина поля вывода не указана, соответствующий параметр

выводится вслед за предыдущим без какого-либо их разделения.

Символы и строки передаются выводному файлу без изменений, но

снабжаются ведущими пробелами, если задана ширина поля вывода и эта

ширина больше требуемой для вывода.

При выводе логических выражений в зависимости от их значения

выводятся строки TRUE или FALSE. (Ввод логических констант проце-

дурами READ или READLN не предусмотрен).

При выводе на экран в случае, когда длина выводимой последова-

тельности символов превышает ширину экрана или созданного на нем окна,

«лишние» символы переносятся на следующую экранную строку. При

заполнении экрана или окна его содержимое сдвигается вверх на одну

строку.

Процедура WRITELN. Эта процедура полностью идентична процедуре

WRITE за исключением того, что выводимая строка символов завершается

103

Page 104: Комплексное пособие

кодами CR и LF. При вызове WRITELN можно опускать параметр

<сп.вывода>: в этом случае в файл передается маркер EOLN, что при выводе

на экран приведет к переводу курсора в начало следующей строки.

Логическая функция EOLN. Возвращает TRUE, если во входном

текстовом файле достигнут маркер конца строки. Формат обращения:

EOLN(<ф.n.>);

Если параметр <ф.п.> опущен, функция проверяет стандартный файл

INPUT.

Существует некоторое отличие в работе функций EOLN и EOF с

дисковыми файлами и логическими устройствами. Дело в том, что для

логического устройства невозможно предвидеть, каким будет результат

чтения очередного символа. Поэтому при работе с логическим устройством

функция EOLN возвращает TRUE, если последним считанным с устройства

символом был EOLN или EOF, в то время как при чтении с диска TRUE

возвращается в случае, если следующим считываемым символом будет

EOLN или EOF. Аналогичное различие наблюдается и в функции EOF: для

логического устройства TRUE возвращается в случае, если последним

символом был EOF, а при чтении с диска - если следующим считываемым

символом будет EOF. Иными словами, функции тестируют соответствующие

признаки для логического устройства после очередного чтения, а для файла -

перед чтением.

Логическая функция SEEKEOLN. Пропускает все пробелы и знаки

табуляции до маркера конца строки EOLN или до первого значащего символа

и возвращает TRUE, если маркер обнаружен. Формат обращения;

SEEKEOLN(<ф.п.>);

Если параметр <ф.п.> опущен, функция проверяет стандартный файл

INPUT,

104

Page 105: Комплексное пособие

Логическая функция SEEKEOF. Пропускает все пробелы, знаки

табуляции и маркеры конца строки EOLN до маркера конца файла или до

первого значащего символа и возвращает TRUE, если маркер обнаружен.

Формат обращения:

SEEKEOF(<ф.п.>);

Если параметр <ф.п.> опущен, функция проверяет стандартный файл

INPUT.

В следующем примере, иллюстрирующем работу с текстовым файлом,

подсчитывается общее количество символов в файле и результат делится на

40000 - таким способом можно оценить объем рукописи в так называемых

учетно-издательских листах:

var

f: text;

s: string;

const

Sum: longint = 0; {Здесь будет количество символов}

BEGIN

Writе('Имя файла: '); {Запросить}

Readln(s); {и ввести имя файла}

assign(f ,s);

Reset(f); {Открыть файл}

while not EOF(f) do {Подсчитать}

begin {количество}

Readln(f,s); {символов}

inc(Sum, Length(s)) {в тексте}

end; {этой программы}

Close(f); {Закрыть файл}

Writeln('Объем - ',Sum/40000:6:2,' уч.изд.л.');

END.

105

Page 106: Комплексное пособие

Типизированные файлы

Длина любого компонента типизированного файла строго постоянна,

что дает возможность организовать прямой доступ к каждому из них (т.е.

доступ к компоненту по его порядковому номеру).

Перед первым обращением к процедурам ввода-вывода указатель файла

стоит в его начале и указывает на первый компонент с номером 0. После

каждого чтения или записи указатель сдвигается к следующему компоненту

файла. Переменные в списках ввода-вывода должны иметь тот же тип, что и

компоненты файла. Если этих переменных в списке несколько, указатель

будет смещаться после каждой операции обмена данными между

переменными и дисковым файлом.

Процедура READ. Обеспечивает чтение очередных компонентов

типизированного файла. Формат обращения:

READ (<ф.п.>,<сп.ввода>);

Здесь <сп.ввода> - список ввода, содержащий одну или более

переменных такого же типа, что и компоненты файла.

Файловая переменная <ф. п. > должна быть объявлена предложением

FILE OF... и связана с именем файла процедурой ASSIGN. Файл необходимо

открыть процедурой RESET. Если файл исчерпан, обращение к READ

вызовет ошибку ввода-вывода.

Процедура WRITE. Используется для записи данных в типизированный

файл. Формат обращения:

WRITE (<ф.п.>,<сп.вывода>);

Здесь <сп. вывода> - список вывода, содержащий одно или более

выражений того же типа, что и компоненты файла.

Процедура SEEK. Смещает указатель файла к требуемому компоненту.

Формат обращения:

106

Page 107: Комплексное пособие

SEEK (<ф. п. >,<N компонента>);

Здесь <N компонента> - выражение типа LONGINT, указывающее

номер компонента файла.

Первый компонент файла имеет номер 0. Процедуру нельзя применять к

текстовым файлам.

Функция FILESIZE. Возвращает значение типа LONGINT, которое

содержит количество компонентов файла. Формат обращения:

FILESIZE(<ф.п.>);

Функцию нельзя использовать для текстовых файлов. Чтобы пере-

местить указатель в конец файла, можно написать:

seek(FileVar, FileSize(FileVar));

где FILEVAR - файловая переменная.

Функция FILEPOS. Возвращает значение типа LONGINT, содержащее

порядковый номер компонента файла, который будет обрабатываться

следующей операцией ввода-вывода. Формат обращения:

FILEPOS(<ф.п.>);

Функцию нельзя использовать для текстовых файлов. Первый ком-

понент файла имеет порядковый номер 0.

Нетипизированные файлы

Нетипизированные файлы объявляются как файловые переменные типа

FILE и отличаются тем, что для них не указан тип компонентов. Отсутствие

типа делает эти файлы, с одной стороны, совместимыми с любыми другими

107

Page 108: Комплексное пособие

файлами, а с другой - позволяет организовать высокоскоростной обмен

данными между диском и памятью.

При инициации нетипизированного файла процедурами RESET или

REWRITE можно указать длину записи нетипизированного файла в байтах.

Например, так:

var

f : file;

..........

assign(f, 'myfile.dat');

reset(f,5l2);

Длина записи нетипизированного файла указывается вторым

параметром при обращении к процедурам RESET или REWRITE, в качестве

которого может использоваться выражение типа WORD. Если длина записи

не указана, она принимается равной 128 байтам.

При работе с нетипизированными файлами могут применяться все

процедуры и функции, доступные типизированным файлам, за исключением

READ и WRITE, которые заменяются соответственно высокоскоростными

процедурами BLOCKREAD и BLOCKWRITE . Для вызова этих процедур

используются следующие предложения:

BLOCKREAD(<ф.п.>,<буф>,<N>[,<NN>]);

BLOCKWRITE(<ф.п.>,<буф>,<N>[,<NN>]);

Здесь <буф> - буфер: имя переменной, которая будет участвовать в

обмене данными с дисками;

<N> - количество записей, которые должны быть прочитаны или

записаны за одно обращение к диску;

<NN> - необязательный параметр, содержащий при выходе из про-

цедуры количество фактически обработанных записей.

108

Page 109: Комплексное пособие

За одно обращение к процедурам может быть передано до N*RECS байт,

rppRECS - длина записи нетипизированного файла. Передача идет, начиная с

первого байта переменной <буф>. Программист должен позаботиться о том,

чтобы длина внутреннего представления переменной <буф> была

достаточной для размещения всех N*RECS байт при чтении информации с

диска. Если при чтении у казана переменная <буф> недостаточной длины

или если в процессе записи на диск не окажется нужного свободного

пространства, возникнет ошибка ввода-вывода, которую можно за-

блокировать, указав необязательный параметр <NN> (переменная типа

WORD).

После завершения процедуры указатель смещается на <NN> записей.

Процедурами SEEK, FILEPOS и FILESIZE можно обеспечить доступ к любой

записи нетипизированного файла.

Указатели и динамическая память

Указатель - это ссылка на данные или код вашей программы. Он

представляет адрес в памяти элемента, на который указывает. Использование

указателей позволяет писать большие и более гибкие программы и особенно

полезно, когда вы начинаете писать объектно-ориентированные программы.

Данная глава должна помочь вам лучше использовать указатели,

независимо от того, начинаете ли вы работать с Паскалем или уже давно

программируете на Паскале, но раньше не работали с указателями. Она

охватывает следующие темы:

Зачем и когда используются указатели.

Что такое указатель.

Как использовать указатели.

Эффективная работа с указателями.

109

Page 110: Комплексное пособие

1. Для чего используются указатели?

Рано или поздно каждый программист, работающий на Паскале,

попадает в ситуацию, требующую использования указателей. Указатели

требуется применять в следующих случаях:

Если ваша программа работает с большими объемами данных

(общий объем которых превышает 64К).

Если ваша программа во время компиляция использует данные

неизвестного размера.

Если программа использует временные буферы данных.

Если ваша программа работает с несколькими типами данных.

Если ваша программа использует связанные списки данных или

объектов.

Давайте подробнее рассмотрим каждую причину использования

указателей.

Работа с большими объемами данных

По мере того как программы становятся более сложными, и требуются

работа с большим количеством данных, область объемом в 64К,

зарезервированная в Turbo Pascal для данных, может оказаться

недостаточной, чтобы содержать все необходимые программе данные.

Указатели позволяют вам обойти эту проблему.

Когда вы описываете в Turbo Pascal глобальные переменные,

компилятор выделяет для них память в области, которая называется

сегментом данных. Сегмент данных имеет максимальный размер 64К. Это

означает, что общий объем всех ваших глобальных переменных не может

превышать 64К. Для многих программ этот предел значения не имеет, но в

некоторых случаях вам может потребоваться больший объем.

Примечание: Локальные переменные не помещаются в сегмент данных

и в пределе 64К не учитываются.

110

Page 111: Комплексное пособие

Предположим, например, что у вас есть программа, требующая массива

в 400 строк по 100 символов каждая. Для этого массива требуется примерно

40К, что меньше максимума в 64К. Если остальные ваши переменные

помещаются в оставшиеся 24К, массив такого объема проблемы не

представляет.

Но что если вам нужно два таких массива? Это потребовало бы 80К, и

64К сегмента данных не хватит. Чтобы работать с большими объемами

данных, вам нужно использовать динамически распределяемую область

памяти. Ваша программа может выделить в динамически распределяемой

области 80К, поддерживая указатель в виде ссылку на адрес данных.

Указатель занимает в сегменте данных только 4 килобайта.

Что такое динамически распределяемая область памяти?

Динамически распределяемая область памяти - это вся память, которую

ваша операционная система делает доступной для программы и которая не

используется ее кодом, сегментом данных и стеком. Объемом

распределяемой динамической памяти вы можете управлять с помощью

директивы компилятора $M.

Обычно в Turbo Pascal вы можете зарезервировать память в

динамически распределяемой области, получить к ней доступ через

указатель, а затем снова освободить память. Подробности о распределении

памяти в динамически распределяемой области вы можете найти ниже в

разделе "Как использовать указатели?".

Работа с данными неизвестного размера

Некоторые элементы данных Turbo Pascal (в частности, строки и

массивы) требуют задания размеров во время компиляции, даже если при

выполнении программы вам не потребуется вся выделенная память. Простым

примером может быть программа, считывающая вводимую пользователем

строку, например, имя пользователь. Чтобы записать имя в обычной

строковой переменной, вам потребовалось бы зарезервировать достаточно

111

Page 112: Комплексное пособие

памяти для максимальной возможной строки, даже если набранное имя

содержит всего несколько букв. Если вы распределяете переменные в

динамически распределяемой области памяти во время выполнения, то

можете выделить точно столько байт, сколько необходимо для фактической

строки данных.

Это тривиальный пример, но в приложении, содержащем сотни и тысячи

таких элементов данных (таких как множественные окна или считываемые из

файлов списки) выделение точного объема пространства может вместо

ситуации нехватки памяти привести к успешному выполнению.

Работа с временными буферами данных

Указатели и динамически распределяемая область памяти особенно

полезны в тех случаях, когда вам требуется временное выделение памяти, и

вы не хотите удерживать ее на все время выполнения программы. Например,

редактору файлов обычно требуется буфер данных для каждого

редактируемого файла. Вместо описания на этапе компиляции, что вам

необходимо определенное число буфером заданного размера, которые всегда

распределяются для файлов, вы можете выделить их столько, сколько

необходимо в каждый конкретный момент, что делает память доступной для

других целей.

Другим общим примером использования временной памяти является

сортировка. Обычно когда вы сортируете большой объем данных, то делаете

копию массива, сортируете копию, а затем записываете отсортированные

данные обратно в исходный массив. Это сохраняет целостность ваших

данных, но требует также наличия во время сортировки двух копий данных.

Если вы хотите распределить сортируемый массив в динамически

распределяемой памяти, то можете отсортировать его и скопировать обратно

в оригинал, а затем уничтожить сортируемый массив, освободив память для

других нужд.

112

Page 113: Комплексное пособие

Работа с несколькими типами данных

Одной из общих причин использования указателей является ссылка на

переменные структуры данных, то есть записи или массивы, которые не

всегда имеют одну и ту же структуру. Например, вы можете выделить блок

памяти, зарезервированный для "протокола" элементов строк различной

длины, набранных в поле ввода данных. Чтобы прочитать список протокола,

подпрограмма должна просмотреть блок и найти отдельные строки. Для

указания начала блока вы можете использовать простой указатель. В этом

случае указатель работает аналогично передаче функции или процедуре

нетипизированного параметра var - вы просто хотите сообщить, где что-то

находится, без указания того, что это такое.

Примечание: О нетипизированных параметрах-переменных

рассказывается в Главе ?? ("Процедуры и функции").

Связанные списки

Одним из общих случаев использования указателей является соединение

связанных списков записи. Во многих простых приложениях типа баз данных

вы можете размещать записи данных в массивах или типизированных

файлах, но иногда требуется что-то более гибкое, чем массив, который имеет

фиксированный размер. Распределяя динамические записи, так что каждая

запись имеет поле, указывающее на следующую запись, вы можете

построить список, содержащий столько элементов, сколько вам требуется.

Что такое указатель?

Указатель - это какой-либо адрес в памяти вашего компьютера. Это

может быть адрес переменной, записи данных, либо процедуры или функции.

Обычно вам не важно, где расположен элемент в памяти. Вы можете просто

ссылаться на него по имени, и Turbo Pascal знает, где его нужно искать.

Именно это происходит, когда вы описываете переменную. Например,

если программа включает в себя следующий код, то вы указываете

113

Page 114: Комплексное пособие

компилятору на необходимость зарезервировать область в памяти, на

которую будете ссылаться по имени SomeNumber.

var SomeNumber: Integer;

Вам не нужно беспокоиться о том, где SomeNumber находится в памяти.

Именно для этого задается имя.

Адрес размещения SomeNumber в памяти можно найти с помощью

операции @. @SomeNumber - это адрес вашей целочисленной переменной.

Вы можете присвоить этот адрес переменной-указателю, то есть переменной,

содержащей адрес данных или кода в памяти.

Ссылочный тип

Чтобы хранить указатели, вам требуется переменная-указатель, а для

создания переменной-указателя вам необходим ссылочный тип (или тип

"указатель"). Простейшим ссылочным типом является стандартный тип с

именем Pointer. Переменная типа Pointer - это общий (нетипизированный)

указатель, то есть, просто адрес. Он не содержит информации о том, на что

он указывает.

Таким образом, чтобы использовать тот же пример SomeNumber, вы

можете присвоить его адрес переменной-указателю:

var

SomeNumber: Integer;

SomeAddress: Pointer;

begin

SomeNumber := 17; {присвоить SomeNumber

значение}

SomeAddress := @SomeNumber; {присвоить SomeAddress

адрес}

SomeAddress := Addr(SomeNumber); {другой способ

получения

адреса}

114

Page 115: Комплексное пособие

end.

Нетипизированные указатели в Паскале не используются, поскольку они

очень ограничены. Они наиболее полезны, когда указываемый элемент будет

изменяться, так как нетипизированный указатель совместим с любым другим

указателем. Типизированные указатели значительно более полезны, и как вы

узнаете в следующем разделе, они более надежны.

Типизированные указатели

Обычно вы определяете ссылочные типы, которые указывают на

конкретный вид элемента, например, целое значение или запись данных. Как

вы далее увидите, можно извлечь преимущество из того факта, что указателю

известно, на что он указывает. Чтобы определить типизированный указатель,

вы можете описать новый тип, определенный символом каре (^), за которым

следуют один или более идентификаторов. Например, чтобы определить

указатель на Integer, вы можете сделать следующее:

type PIneger = ^Integer;

Теперь вы можете описать переменные типа PInteger. Если вы не

собираетесь часто использовать ссылочный тип, то можете просто описать

переменные, как указатели на уже определенный тип. Например, если вы

определили PInteger как ^Integer, то следующие описания переменной

эквивалентны:

var

X: ^Integer:

Y: PInteger;

115

Page 116: Комплексное пособие

Разыменование указателей

До сих пор мы видели, как можно присваивать указателям значения, но

если вы не можете получить значения обратно, польза от этого невелика.

Разыменовав типизированный указатель, вы можете интерпретировать так,

как если бы это была переменная типа, на которую он указывает. Чтобы

разыменовать указатель, поместите символ каре (^) после идентификатора

указателя.

Ниже показаны некоторые примеры разыменования указателя:

type PInteger = ^Integer;

var

SomeNumber: Integer; { присвоить SomeNumber 17 }

SomeAddress := @SomeNumber; { SomeAddress указывает

на SomeNumber }

Writeln(SomeNumber); { напечатать 17 }

Writeln(SomeAddress); { не допускается; указатели

печатать нельзя }

Writeln(SomeAddress^); { напечатать 17 }

AnotherAddress := SomeAddress; { также указывает на

SomeNumber }

AnotehrAddress^ := 99; { новое значение для

SomeNumber }

Writeln(SomeNumber); { напечатать 99 }

end.

Наиболее важными строками здесь являются следующие:

AnotherAddress := SomeAddress; { также указывает

на SomeNumber }

AnotehrAddress^ := 99; { новое значение для

SomeNumber }

116

Page 117: Комплексное пособие

Как использовать указатели?

Теперь вы получили достаточно хорошее представление о том, в каких

ситуациях вы можете использовать указатели, и можно рассмотреть их

фактическое применение. В данном разделе охватываются следующие темы:

Распределение динамических переменных.

Освобождение выделенной для динамических переменных памяти.

Распределение и освобождение выделенных объемов памяти.

Проверка доступного в динамически распределяемой области

пространства.

Turbo Pascal предусматривает две пары процедур для выделения и

освобождения памяти, распределяемой для динамических переменных. Чаще

всего используются процедуры New и Dispose, которые отвечают

большинству потребностей. Процедуры GetMem и FreeMem выполняют те

же функции, но на более низком уровне.

Выделение памяти для динамических переменных

Одним из наиболее важных моментов использования указателей

является распределение динамических переменных в динамически

распределяемой области памяти. Turbo Pascal предусматривает два способа

выделения для указателя памяти: процедура New и процедура GetMem.

Использование New как процедуры

New - это очень простая процедура. После описания переменной-

указателя вы можете вызвать процедуру New для выделения пространства в

динамически распределяемой памяти для указываемого переменной

элемента. Приведем пример:

var

IntPointer: ^Integer;

StringPointer: ^String;

begin

117

Page 118: Комплексное пособие

New(IntPointer); { выделяет в динамически

распреде-

ляемой области два байта }

New(StringPointer); { выделяет в динамически

распреде-

. ляемой области 256 байт }

.

.

end.

После вызова процедуры New переменная-указатель указывает на

память, выделенную в динамически распределяемой памяти. В данном

примере IntPointer указывает на двухбайтовую область, выделенную

процедурой New, а IntPointer^ - это допустимая целочисленная переменная

(хотя это целочисленное значение еще не определено). Аналогично,

StringPointer указывает на выделенный для строки 256-байтовый блок, а его

разыменование дает доступную для использования строковую переменную.

Использование New как функции

Кроме выделения памяти для конкретной динамической переменной вы

можете использовать New как функцию, возвращающую указатель

конкретного типа. Например, если PInteger - это тип, определенный как

^Integer, а IntPopinter имеет тип PInteger, то следующие два оператора

эквивалентны:

IntPointer := New(PInteger);

Это особенно полезно в случаях, когда может потребоваться

присваивать переменной-указателю элементы различных типов. Иногда

желательно распределять динамическую переменную, не присваивая явно

указатель конкретной переменной. Вероятно, вы можете сделать это только

создав для процедуры и функции параметр:

118

Page 119: Комплексное пособие

SomeProcedure(New(PointerType));

В этом случае SomeProcedure будет добавлять передаваемый параметр к

некоторому списку. В противном случае распределяемая память будет

потеряна. Библиотеки Borland Turbo Vision и Turbo Pascal широко

используют этот метод для присваивания динамических объектов спискам.

Освобождение памяти, выделенной для динамических переменных

Память, распределенная для переменных с помощью New, после

завершения работы с ними должна освобождаться. Это позволит

использовать динамически распределяемую память для других переменных.

Чтобы освободить память, выделенную для динамической переменной, вы

должны использовать процедуру Dispose. В предыдущем примере вы можете

добавить следующее:

Dispose(StringPointer);

Dispose(IntPointer);

Нужно помнить, что если вы распределяете динамические переменные с

помощью New, то освобождать выделенную для них память после

завершения работы с этими переменными нужно с помощью Dispose.

Процедуры GetMem и FreeMem

Иногда нежелательно выделять память тем способом, как это делает

New. Вам может потребоваться выделить больше или меньше памяти, чем

это делает New по умолчанию, либо до начала выполнения вы можете просто

не знать, сколько памяти вам нужно использовать. Turbo Pascal выполняет

такое распределение с помощью процедуры GetMem.

Процедура GetMem воспринимает два параметра: переменную-

указатель, для которой вы хотите распределить память, и число

распределяемых байт.

119

Page 120: Комплексное пособие

Динамическое выделение памяти для строки

Пусть, например, у вас есть прикладная программа, которая считывает

1000 строк из файла и записывает их в динамическую память. Вы не знаете,

насколько длинной будет каждая из этих строк, поэтому вам потребуется

описать строковый тип такого размера, который будет соответствовать

максимальной возможной строке. Если предположить, что не все строки

имеют максимальную длину, то у вас будет бесполезно использоваться

память.

Чтобы решить эту проблему, вы можете считать каждую строку в буфер,

затем выделить столько памяти, сколько требуется для фактических данных в

строке. Пример этого показан ниже:

type PString = ^String;

var

ReadBuffer: String;

LinewRead: array[1..1000] of PString;

TheFile: Text;

LineNumber: Integer;

begin

Assign(TheFile, 'FOO.TXT');

Reset(TheFile);

for LineNumber := 1 to 1000 do

begin

Readln(ReadBuffer);

GetMem(LinesRead[LineNumber], Length(ReadBuffer) + 1);

LinesRead[LineNumber]^ := ReadBuffer;

end;

end.

120

Page 121: Комплексное пособие

Вместо выделения для строк 256К (256 символов на строку 1000 раз) вы

выделили 4К (4 байта на указатель 1000 раз), плюс объем, фактически

занимаемый текстом.

Освобождение выделенной памяти

Аналогично тому, как требуется освобождать память, выделенную с

помощью New, вам нужно освобождать память, распределенную с помощью

процедуры GetMem. Это можно сделать с помощью процедуры FreeMem.

Аналогично тому, как каждому вызову New должен соответствовать парный

вызов Dispose, каждому вызову процедуры GetMem должен соответствовать

вызов FreeMem.

Как и GetMem, процедура FreeMem воспринимает два параметра:

освобождаемую переменную и объем освобождаемой памяти. Важно, чтобы

объем освобождаемой памяти точно совпадал с объемом выделенной памяти.

New и Dispose, основываясь на типе указателя, всегда знают, сколько байт

нужно выделять или освобождать. Но в случае GetMem и FreeMem объем

выделяемой памяти находится всецело под вашим контролем.

Если вы освободите меньше байт, чем было выделено, то оставшиеся

байты теряются (происходит "утечка" динамически распределяемой памяти).

Если вы освободите большее число байт, чем было выделено, то можете

освободить память, распределенную для другой переменной, что может

привести к порче данных. В защищенном режиме освобождение большего

объема памяти, чем было выделено, вызовет ошибку по нарушению защиты

(GP).

Предположим, например, что вы собираетесь выделить память для

одной или более записей данных типа TCheck:

type

PCheck = ^ TCheck;

TCheck = record

Amount: Real;

121

Page 122: Комплексное пособие

Mounth: 1..12;

Day: 1..31;

Year: 1990..2000;

Payee: string[39];

end.

Каждая запись типа TCheck занимает 50 байт, поэтому, если у вас есть

переменная ThisCheck типа PCheck, вы можете распределить динамическую

запись следующим образом:

GetMem(ThisGheck, 50);

а позднее освободить ее с помощью вызова:

FreeMem(ThisCheck, 50);

Использование с процедурой GetMem функции SizeOf

Однако убедиться, что вы каждый раз выделяете и освобождаете один и

тот же объем памяти, недостаточно. Вы должны обеспечить распределение

правильного объема памяти. Предположим, вы изменили определение

TCheck. Например, если вы переопределили TCheck.Payee как 50-

символьную строку вместо 39-символьной, то не сможете получить и

освобождать достаточно памяти. Надежнее всего использовать в программе

функцию SizeOf, например:

GetMem(ThisCheck, SizeOf(TCheck));

.

.

.

FreeMem(ThisCheck, SizeOf(TCheck));

122

Page 123: Комплексное пособие

Это не только обеспечивает, что вы выделяете и освобождаете один и

тот же объем, но гарантирует, что при изменении размера типа ваша

программа все равно будет выделять нужную память.

Проверка объема доступной динамически распределяемой памяти

В Turbo Pascal определены две функции, возвращающие важную

информацию о динамически распределяемой области памяти: MemAvail и

MaxAvail.

Функция MemAvail возвращает общее число байт, доступных для

распределения в динамической памяти. Перед выделением большого объема

в динамически распределяемой памяти полезно убедиться, что такой объем

памяти доступен.

Функция MaxAvail возвращает размер наибольшего доступного блока

непрерывной памяти в динамически распределяемой области. Первоначально

при запуске программы MaxAvail равно MemAvail, поскольку вся

динамически распределяемая область памяти является доступной и

непрерывной. После распределения нескольких блоков памяти пространство

в динамически распределяемой области скорее всего станет

фрагментированным. Это означает, что между частями свободного

пространства имеются распределенные блоки. Функция MaxAvail возвращает

размер наибольшего свободного блока.

Общие проблемы использования указателей

Указатели позволяют вам делать в Паскале некоторые важные вещи, но

есть пара моментов, которые при работе с указателями нужно отслеживать.

При использовании указателей допускаются следующие общие ошибки:

разыменование неинициализированных указателей;

потери динамически распределяемой памяти ("утечки").

123

Page 124: Комплексное пособие

Разыменование неинициализированных указателей

Одним из общих источников ошибок при работе с указателями является

разыменование указателя, который еще не был инициализирован. Как и в

случае других переменных Паскаля, значение переменной-указателя не будет

определено, пока вы не присвоите ей значение, так что она сможет указывать

на какой-то адрес в памяти.

Перед использованием указателей им всегда нужно присваивать

значения. Если вы разыменовываете указатель, которому еще не присвоено

значение, то считанные из него данные могут представлять собой случайные

биты, а присваивание значения указываемому элементу может затереть

другие данные, вашу программу или даже операционную систему. Это

звучит несколько пугающе, но при определенной дисциплине такие вещи

легко отслеживаются.

Использование пустого указателя

Чтобы избежать разыменования указателей, которые не указывают на

что-либо значащее, нужен некоторый способ информирования о том, что

указатель недопустим. В Паскале предусмотрено зарезервированное слово

nil, которое вы можете использовать в качестве содержательного значения

указателей, которые в данный момент ни на что не указывают. Указатель nil

является допустимым, но ни с чем не связанным. Перед разыменованием

указателя вы должны убедиться, что он отличен от nil (не пуст).

Предположим, например, что у вас есть функция, возвращающая

указатель на некоторый элемент в памяти. Вы можете указать, что такая

функция не может найти элемент, возвращая значение nil.

var ItemPointer: Pointer;

function FindIten: Pointer;

begin

.

124

Page 125: Комплексное пособие

.

.

{ найти элемент, возвращая указатель на него или

nil,

если элемент не найден }

end;

begin

ItemPointer := nil; { начнем в предположении

nil }

ItemPointer := FindItem; { вызвать

функцию }

if ItemPointer <> nil then ... { для надежности разымено-

вания ItemPointer }

end.

Потери динамически распределяемой памяти

При использовании динамически распределяемых переменных часто

возникает общая проблема, называемая утечкой динамической памяти.

Утечка памяти - это ситуация, когда пространство выделяется в динамически

распределяемой памяти и затем теряется - по каким-то причинам ваш

указатель не указывает больше на распределенную область, так что вы не

можете освободить пространство.

Общей причиной утечек памяти является переприсваивание

динамических переменных без освобождения предыдущих. Простейшим

случаем является следующий:

var IntPointer: ^Integer;

begin

New(IntPointer);

New(IntPointer);

125

Page 126: Комплексное пособие

end.

При первом вызове New в динамически распределяемой памяти

выделяется 8 байт, и на них устанавливается указатель IntPointer. Второй

вызов New выделяет другие 8 байт, и IntPointer устанавливается на них.

Теперь у вас нет указателя, ссылающегося на первые 8 байт, поэтому вы не

можете их освободить. В программе эти байты будут потеряны.

Естественно, утечка памяти может быть не такой очевидной, как в

Примере 8.6. Выделение памяти почти никогда не происходит в

последовательных операторах, но может выполняться в отдельных

процедурах или далеко отстоящих друг от друга частях программы. В любом

случае лучший способ отслеживания динамических переменных это

установка их в nil при освобождении. Тогда при попытке распределить их

снова вы можете убедиться что они имеют значение nil:

var IntPointer: ^Integer;

begin

New(IntPointer);

.

.

.

Dispose(IntPointer);

IntPointer := nil;

.

.

.

if IntPointer = nil then New(IntPointer);

end.

126

Page 127: Комплексное пособие

Модули Turbo Pascal

В данной главе разъясняется, что такое модуль, как он используется,

какие встроенные модули доступны пользователю, как писать собственные

программные модули и как компилировать их.

Turbo Pascal обеспечивает вам доступ к большому числу встроенных

констант, типов данных, переменных, процедур и функций. Некоторые из

них специфичны для Turbo Pascal, другие специфичны для приложений

Windows. Их количество велико, однако, в своей программе вы редко

используете их все сразу. Поэтому они разделены на связанные группы,

называемые модулями. В этом случае можно использовать только те модули,

которые необходимы в программе.

Используя модули, вы можете разбивать программу на отдельные части

и компилировать их отдельно. Программный модуль (unit) представляет

собой набор констант, типов данных, переменных, процедур и функций,

которые могут совместно использоваться несколькими программами.

Каждый модуль аналогичен отдельной программе на Паскале: он может

иметь основное тело, которое вызывается перед запуском вашей программы

и осуществляет необходимую инициализацию.

Все описания внутри модуля связаны друг с другом. Например, модуль

Strings содержит все описания, необходимые для подпрограмм работы со

строками с завершающим нулем.

Turbo Pascal предоставляет пользователю ряд стандартных модулей,

таких как System, Crt WinCrt и др. Они поддерживают наши программы

Turbo Pascal и все записаны в одну из трех библиотек исполняющей системы

(в зависимости от целевой платформы).

Ваша программа может использовать любую из процедур и функций в

этих модулях, и вам не потребуется писать их заново.

127

Page 128: Комплексное пособие

Структура модуля

Структура модуля аналогична структуре программы, однако есть

несколько существенных различий. Например, рассмотрим модуль:

unit <идентификатор>;

interface

uses <список модулей>; { Необязательный }

{ глобальные описания }

implementation

uses <список_модулей>; { Необязательный }

{ локальные описания }

{ реализация процедур и функций }

begin

{ код инициализации }

end.

Заголовок модуля начинается зарезервированным словом unit, за

которым следует имя модуля (идентификатор) точно так же, как и в случае

имени программы. Следующим элементом в модуле является ключевое слово

interface. Оно обозначает начало интерфейсной секции модуля - части,

доступной всем другим модулям или программам, в которых он

используется.

Программный модуль может использовать другие модули, для этого они

определяются в операторе uses. Оператор uses (если он имеет место) может

содержаться в двух местах. Во-первых, он может следовать сразу после

ключевого слова interface. В этом случае любые константы и типы данных,

описанные в интерфейсной секции этих модулей, могут использоваться в

любом описании в интерфейсной части данного модуля.

Во-вторых, он может следовать немедленно за ключевым словом

implementation. В этом случае все описания из этих модулей могут

использоваться только в секции реализации.

128

Page 129: Комплексное пособие

Интерфейсная секция

Интерфейсная часть - "общедоступная" часть в модуле - начинается

зарезервированным словом interface, следует сразу после заголовка модуля и

заканчивается перед зарезервированным словом implementation. Интерфейс

определяет, что является "видимым" (доступным) для любой программы (или

модуля), использующей данный модуль.

В интерфейсной части (секции) модуля можно определять константы,

типы данных, переменные, процедуры и функции. Как и в программе, они

могут быть расположены в любом порядке, и секции могут встречаться

повторно (например, ваша программа может содержать секцию var, за

которой следует секция const, а затем другая секция var).

Процедуры и функции, видимые для любой программы, использующей

данный модуль, описываются в секции интерфейса, однако их

действительные тела - реализации - находятся в секции реализации. Вам не

нужно использовать описания forward, и они не допускаются. В

интерфейсной части перечисляются все заголовки процедуры и функции.

Секция реализации содержит программную логику процедур и функций.

Секция реализации

Секция реализации - "приватная" часть - начинается зарезервированным

словом implementation. Все, что описано в секции интерфейса, является

видимым в секции реализации: константы, типы, переменные, процедуры и

функции. Кроме того, в секции реализации могут быть свои дополнительные

описания, которые не являются видимыми для программ, использующих этот

модуль. Программа не знает об их существовании и не может ссылаться на

них или обращаться к ним. Однако, эти скрытые элементы могут

использоваться (и, как правило, используются) "видимыми" процедурами и

функциями, то есть теми подпрограммами, чьи заголовки указаны в секции

интерфейса.

129

Page 130: Комплексное пособие

Оператор uses может содержаться в секции реализации (implementation)

и должен непосредственно следовать за ключевым словом implementation.

Обычные процедуры и функции, описанные в интерфейсной секции, то

есть те из них, которые не являются подставляемыми (inline), должны

повторно указываются в секции реализации. Заголовок procedure/function

должен быть или идентичным тому, который указан в секции интерфейса,

или иметь более краткую форму. В случае краткой формы наберите ключевое

слово (procedure или function), а за ним укажите имя подпрограммы

(идентификатор). Затем подпрограмма должна содержать все свои локальные

описания (метки, константы, типы, переменные и вложенные процедуры и

функции), за которыми должно находиться основное тело самой

подпрограммы. Пусть в интерфейсной части указаны следующие описания:

procedure ISwap(var V1,V2 : integer);

function IMax(V1,V2 : integer) : integer;

Тогда Секция реализации будет иметь следующий вид:

procedure ISwap;

var

Temp := integer;

begin

Temp := V1; V1 := V2; V2 := Temp

end; {конец процедуры Swap}

function IMax(V1,V2 : integer): integer;

begin

if V1 > V2

then IMax := V1

else IMax := V2

end; { конец функции Max }

130

Page 131: Комплексное пособие

Подпрограммы, локальные для секции реализации (то есть не описанные

в секции реализации), должны иметь полный (несокращенный) заголовок

procedure/function.

Секция инициализации

Обычно вся секция реализации модуля заключена между

зарезервированными словами implementation и end. Однако, если перед end

поместить зарезервированное слово begin, а между ними - операторы, то

получившийся составной оператор, очень похожий на основное тело

программы, становится секцией инициализации модуля (initialization).

Секция инициализации представляет собой место, где

инициализируются структуры данных (переменных), которые использует

программный модуль или которые он делает доступными программе,

использующей данный модуль. Вы можете использовать эту секцию для

открытия файлов, которые программа использует позднее.

При выполнении программы, использующей некоторый модуль, секция

инициализации этого модуля вызывается перед запуском основного тела

программы. Если программа использует более одного модуля, то секции

инициализации всех модулей вызываются (в порядке, указанном в операторе

uses в программе) перед тем, как выполнить основное тело программы.

Как используются модули?

Модули, которые использует ваша программа, уже оттранслированы и

хранятся, как машинный код, а не как исходный код на Паскале, поскольку

они не являются включаемыми файлами. Даже интерфейсная секция

хранится в специальном двоичном формате таблицы идентификаторов,

используемом в Turbo Pascal. Более того, определенные стандартные модули

хранятся в специальном файле (TURBO.TPL, TPW.TPL или TPP.TPL) и

автоматически загружаются в память вместе с Turbo Pascal.

131

Page 132: Комплексное пособие

В результате использование одного или нескольких модулей очень

незначительно увеличивает время компиляции вашей программы (обычно

менее, чем на секунду).

Фактически, если модуль скомпилирован, его использование сохраняет

вам время при перекомпиляции. Поскольку компилятор не перекомпилирует

модуль, пока он не изменяется, использование модулей в программе ускорит

процесс ее построения.

Как указывалось ранее, для использования специального модуля или

набора модулей необходимо в начале программы поместить оператор uses,

после которого указать список имен тех модулей, которые будут

использоваться. Имена их должны разделяться запятыми:

program MyProg;

uses thisUnit, thatUnit, theOtherUnit;

Когда компилятор встречает такой оператор uses, он прибавляет

информацию из секции интерфейса каждого модуля к таблице

идентификаторов и присоединяет машинный код, представленный в секции

реализации, к самой программе.

Модули присоединяются к таблице идентификаторов в указанном

порядке. Порядок модулей в операторе uses значения не имеет. Если модуль

thisUnit использует thatUnit или наоборот, вы можете описать их в любом

порядке, а компилятор определит, какой модуль нужно скомпоновать с

программой MyProg первым. Фактически, если модуль thisUnit использует

thatUnit, но MyProg не вызывает непосредственно ни одну из подпрограмм в

модуле thatUnit, вы можете "скрыть" подпрограммы модуля thatUnit, опустив

его в операторе uses:

unit thisUnit;

uses thatUnit;

.

132

Page 133: Комплексное пособие

.

.

program MyProg;

uses thisUnit, theOtherUnit;

.

.

.

В этом примере модуль thisUnit может вызывать любую подпрограмму

модуля thatUnit, а программа MyProg может вызывать любую из

подпрограмм модуля thisUnit или theOtherUnit. Однако, программа MyProg

не может вызывать подпрограммы модуля thatUnit, поскольку thatUnit не

указывается в операторе uses программы MyProg.

Если в программе не указан оператор uses, Turbo Pascal в любом случае

присоединит стандартный модуль System. Этот модуль обеспечит

выполнение некоторых стандартных подпрограмм Turbo Pascal, а также

нескольких подпрограмм, специфических для Turbo Pascal.

Ссылки на описания модуля

Как только вы включили модуль в свою программу, все константы, типы

данных, переменные, процедуры и функции, описанные в секции интерфейса

этого модуля, становятся доступными для вашей программы. Например,

допустим, имеется следующий модуль:

unit MyStuff;

interface

const

MyValue = 915;

type

MyStars = (Deneb,Antares,Betelgeuse);

var

MyWord : string[20];

133

Page 134: Комплексное пособие

procedure SetMyWord(Star : MyStars);

function TheAnswer : integer;

implementation

.

.

.

end.

Как можно видеть здесь в интерфейсной части модуля, та часть модуля,

которая находится в интерфейсной секции, является видимой для вашей

программы (и может ею использоваться). С учетом этого можно написать

следующую программу:

program TestStuff;

uses MyStuff;

var

I : integer;

AStar : MyStars;

begin

Writeln(myValue);

AStar := Deneb;

SetMyWord(AStar);

Writeln(MyWord);

I := TheAnswer;

Writeln(I)

end.

После включения в программу оператора uses MyStuff вы можете

ссылаться на все идентификаторы, описанные в интерфейсной секции модуля

МyStuff (МyWord, МyValue и так далее). Однако, рассмотрим следующую

ситуацию:

program TestStuff;

uses MyStuff;

134

Page 135: Комплексное пособие

const

MyValue = 22;

var

I : integer;

AStar : MyStars;

function TheAnswer : integer;

begin

TheAnswer := 1

end;

begin

Writeln(myValue);

AStar := Deneb;

SetMyWord(AStar);

Writeln(MyWord);

I := TheAnswer;

Writeln(I)

end.

В этой программе переопределяются некоторые из идентификаторов,

описанных в МyStuff. Будучи скомпилированной и выполненной, эта

программа будет использовать собственные определения для МyValue и

ТheAnswer, поскольку они были описаны позднее, чем определения в

МyStuff.

Вероятно, вам интересно знать, каким образом в такой ситуации можно

ссылаться на идентификаторы в МyStuff. Для этого необходимо перед

каждым идентификатором помещать имя МyStuff с точкой (.). Например,

рассмотрим еще одну версию этой программы:

program TestStuff;

uses MyStuff;

const

MyValue = 22;

135

Page 136: Комплексное пособие

var

I : integer;

AStar : MyStars;

function TheAnswer : integer;

begin

TheAnswer := 1

end;

begin

Writeln(MyStuff.MyValue);

AStar := Deneb;

SetMyWord(AStar);

Writeln(MyWord);

I := MyStuff.TheAnswer

Writeln(I)

end.

Эта третья программа даст такие же ответы, что и первая, даже в том

случае, если вы переопределите MyValue и TheAnswer. В действительности

вы имели полное право написать первую программу следующим образом:

program TestStuff;

uses MyStuff;

var

I : integer;

AStar : MyStuff.MyStars;

begin

Writeln(MyStuff.MyValue);

AStar := My.Stuff.Deneb;

MyStuff.SetMyWord(AStar);

Writeln(My.Stuff.MyWord);

I := MyStuff.TheAnswer;

Writeln(I)

136

Page 137: Комплексное пособие

end.

Отметим, что имя модуля может предшествовать любому

идентификатору: константе, типу данных, переменной или подпрограмме.

Оператор uses секции реализации

Turbo Pascal позволяет вам размещать в секции реализации оператор

uses. В случае его присутствия оператор uses должен следовать

непосредственно за ключевым словом implementation (аналогично тому, как в

интерфейсной секции оператор uses должен следовать непосредственно за

ключевым словом interface).

Размещение в секции реализации оператора uses позволяет "скрыть"

внутренние детали модуля, поскольку используемые в секции реализации

модули оказываются "невидимыми" для того, кто этот модуль использует.

Более важным, однако, является то, что это позволяет вам строить

взаимозависимые модули.

Поскольку программные модули в Borland Pascal не обязаны иметь

строго иерархическую структуру, то допускается использовать циклические

ссылки на модули. О циклических ссылках на модули рассказывается в Главе

10 "Справочного руководства по языку".

Стандартные модули

Модули библиотек исполняющей системы Turbo Pascal загружаются в

память вместе с Turbo Pascal; вы всегда можете их использовать. Обычно

библиотеки исполняющей системы (TURВО.TPL, TPW.TPL и TPP.TPL)

находятся в том же каталоге, что и компилятор (TURBO.EXE. BPW.EXE и

BP.EXE).

Создание ваших собственных модулей

Если вы хотите написать модуль, содержащий некоторые полезные

подпрограммы, и использовать эти подпрограммы в своих программах,

137

Page 138: Комплексное пособие

напишите модули и сохраните его под именем, заданным в заголовке модуля.

Turbo Pascal сохраняет файл с расширением .PAS, как и любой другой файл,

созданный в редакторе Turbo Pascal. В исходном файле может содержаться

только один модуль.

Компиляция модуля

Скомпилировать модуль вы можете двумя способами. Вы можете:

Скомпилируйте модуль с помощью команды Compile¦Compile.

Например, если ваш модуль называется MYUNIT.PAS, если целевой

платформой является Windows, он компилируется в MYUNIT.TWP.

Для компиляции программы, которая включает в себя оператор uses,

используйте команду Compile¦Make или Compile¦Build.

В зависимости от целевой платформы, создается файл .TPU, .TPW

или .TPP.

Доступность модуля для программы

Скопируйте свой новый файл .TPU, .TPW или .TPP в каталог модулей,

заданный в диалоговом окне Options¦Directories, или используйте параметр

командной строки /U при работе с компилятором режима командной строки.

Если вы поместите свой модуль в заданный каталог модулей, то сможете

ссылаться на этот модуль, даже если он не находится в текущем каталоге или

в библиотеках исполняющей системы.

Включите в любую программу, где вы хотите использовать свой новый

модуль, оператор uses. Например, если ваш новый модуль называется

INTLIB.TPW, то задайте в своей программе оператор следующего вида:

uses IntLib;

Чтобы найти модуль, имя которого указано в операторе uses, Turbo

Pascal проверяет его наличие в библиотеке исполняющей системы,

загруженной в память в время инициализации.

138

Page 139: Комплексное пособие

Примечание: О том, как поместить модуль в библиотеку исполняющей

системы, рассказывается ниже.

Если модуль в библиотеке исполняющей системы отсутствует, то

компилятор ищет его на диске, сначала в текущем каталоге, затем в

каталогах, заданных в качестве каталогов модулей (Options¦ Directories).

Компилятор предполагает, что имя файла совпадает с именем модуля, а

расширение имени файла - это .TPU, .TPW или .TPP. Исходный текст модуля

имеет расширение .PAS.

Пример. Теперь напишем небольшой модуль. Назовем его IntLib и

вставим в него две простые подпрограммы для целых чисел - процедуру и

функцию:

unit IntLib;

interface

procedure ISwap(var I,J : integer);

function IMax(I,J : integer) : integer;

implementation

procedure ISwap;

var

Temp : integer;

begin

Temp := I; I := J; J := Temp

end; { конец процедуры ISwap }

function IMax;

begin

if I > J

then IMax := I

else IMax := J

end; { конец функции IMax }

end. { конец модуля IntLib }

139

Page 140: Комплексное пособие

Наберите этот модуль, запишите его в файл INTLIВ.PAS, а затем

скомпилируйте, задав в качестве целевой платформы защищенный режим

DOS. В результате получим код модуля в файле INTLIВ.ТРP. Перешлем его в

каталог модулей (если такой имеется), или оставив в том же каталоге, где

находится следующая программа, которая использует модуль IntLib:

program IntTest;

uses IntLib;

var

A,B : integer;

begin

Write('Введите два целочисленных значения: ');

Readln(A,B);

ISwap(A,B);

Writeln('A = ',A,' B = ',B);

Writeln('Максимальное значение равно ',IMax(A,B));

end. { конец программы IntTest }

Модули и большие программы

До сих пор мы говорили о модулях как о библиотеках - наборах

полезных подпрограмм, которые могут использоваться несколькими

программами. Однако, у модуля есть еще одна функция - разбивать большую

программу на составные части.

Два аспекта Turbo Pascal способствуют использованию модулей в такой

функции:

высокая скорость компиляции и компоновки;

способность работать с несколькими файлами одновременно,

например, с программой и несколькими модулями.

Обычно большая программа разбивается на модули, которые

группируют процедуры по их функциям. Например, программа редактора

может быть разделена на части, выполняющие инициализацию, распечатку,

140

Page 141: Комплексное пособие

чтение и запись файлов, форматирование и так далее. Так же, как имеется

основная программа, определяющая глобальные константы, типы данных,

переменные, процедуры и функции, так же может иметь место и

"глобальный" модуль, который используется всеми другими модулями.

Набросок большой программы-редактора может иметь вид:

program Editor;

uses

WinCrt, String { стандартные модули из TPW.TPL }

EditGlobals, { модули, написанные пользователем }

EditInuit,

EditPrint,

EditRead, EditWrite,

EditFormat;

{ описание, процедуры и функции программы }

begin { основная программа }

end. { конец программы Editor }

Модули в данной программе могут содержаться в TPW.TPL, библиотеке

исполняющей системы Windows, или быть отдельными файлами .TPW. В

последнем случае Turbo Pascal выполняет за вас управление проектом. Это

означает, что при перекомпиляции программы Editor с помощью встроенного

в компилятор средства формирования Turbo Pascal сравнивает даты каждого

файла .PAS и .TPW и перекомпилирует любой модуль, исходный код

которого перекомпилирован.

Другая причина использования модулей в больших программах состоит

в ограничения кодового сегмента. Процессоры 8086 (и родственные им)

ограничивают размер сегмента кода 64 килобайтами. Это означает, что

основная программа и любой данный сегмент не может превышать 64К.

Turbo Pascal интерпретирует это, создавая для каждого модуля отдельный

141

Page 142: Комплексное пособие

сегмент кода. Без этого объем кода вашей программы не мог бы превышать

64К.

Общая характеристика базовых графических средств языка

Pascal.

Для реализации графических операций в прикладных программах

необходима базовая графическая система (БГС). Эта система может входить

в состав системы программирования(Borland Pascal, Borland C) или быть

частью операционного окружения (системы класса Windows).В частности, в

системе Borland Pascal базовые графические средства представлены набором

графических драйверов (файлы типа EGAVGA.BGI) и набором констант,

типов, переменных, процедур и функций, собранных в модуле Graph (файл

GRAPH.TPU).Аналогичные средства существуют и для языка С.

В целом, все процедуры и функции модуля Graph можно разбить на

следующие основные группы:

инициализация и завершение графического режима;

вывод основных графических примитивов;

установка атрибутов графических примитивов;

запрос значений атрибутов;

копирование.

Инициализация графического режима.

Инициализация должна выполняться перед непосредственным

использованием процедур модуля Graph для построения изображения.

Инициализация заключается в задании используемого графического драйвера

и графического режима для этого драйвера. Процедура инициализации

загружает указанный драйвер в оперативную память и настраивает систему

на работу в графическом режиме.

Для указания используемого драйвера можно воспользоваться

следующими константами:

Ega = 3142

Page 143: Комплексное пособие

Vga = 9

Detect = 0.

Константа Detect используется для указания необходимости

автоматического распознавания, имеющегося в наличии графического

адаптера.

После задания драйвера для указания соответствующего режима можно

воспользоваться следующими константами:

EgaHi = 1 - экран 640 на 350 точек с 16 цветами

VgaHi = 2 - экран 640 на 480 точек с 16 цветами

Инициализация графического режима производится вызовом процедуры

InitGraph (var GrDr:integer; PathDr: string), где параметры переменные GrDr и

GrMod определяют используемый драйвер и режим, а параметр PathDr

определяет путь к графическому драйверу в соответствии с правилами

MS/DOS. В простейшем случае параметр PathDr можно задать как пустую

строку, что соответствует ситуации, когда графический драйвер находится в

текущем каталоге. Теперь можно привести два варианта инициализации

графического режима - с явным и автоматическим заданием драйвера и

режима:

Вариант 1:

var GrDr,GrMod: integer;

begin

GrDr:=Vga; {используется драйвер VGA}

GrMod:=VgaHi;

InitGraph(GrDr,GrMod,’’);

Вариант 2:

var GrDr,GrMod: integer;

begin

GrDr:= Detect; {требуется автоопределение}

143

Page 144: Комплексное пособие

InitGraph(GrDr,GrMod,’’);

Для завершения работы в графическом режиме надо вызвать процедуру

CloseGraph, которая выгружает драйвер и восстанавливает исходное

состояние экрана.

Вывод основных графических примитивов.

Любое сложное изображение, в конечном счете, составляется из набора

нескольких простейших геометрических элементов, называемых

примитивами. Система Турбо Паскаль предлагает следующий набор

графических примитивов: точка, отрезок, окружность, дуга, дуга эллипса,

прямоугольник, круговой сектор, сектор эллипса, многоугольник, текст.

Каждый из этих примитивов на экране может выглядеть различным

образом, в соответствии со своими атрибутами. Основными атрибутами для

всех примитивов, кроме текста, являются: цвет, тип линии, толщина линии,

шаблон заполнения области (там, где эта операция имеет смысл).

Установка цвета вывода примитива производится процедурой

SetColor(цвет: integer),

где 0<=цвет<=15 и цветовая палитра совпадает с текстовым режимом.

Установка цвета фона производится процедурой

SetBkColor(цвет: integer).

Установка типа и толщины линии - процедурой

SetLineStyle(тип_линии, образец, толщина: integer).

Для задания типа линии предусмотрены следующие константы:

SolidLn=0 - непрерывная линия;

DottedLn=1 - точечная линия;

CenterLn=2 - штрихпунктирная линия;

DoshedLn=3 - пунктирная линия;

UserBitLn=4 - тип линии, определяемый пользователем;

в этом случае параметр ‘ образец ’ задает образец линии; во всех

остальных случаях следует брать ‘образец’=0.144

Page 145: Комплексное пособие

Замечание: атрибут ‘тип линии’ действует только для прямолинейных

примитивов. Для задания толщины линии можно использовать следующие 2

константы:

NormWidth=1 - нормальная толщина;

ThickWidth=3 - утолщенная линия.

Установка шаблона и цвета закраски замкнутых областей производится

с помощью процедуры

SetFillStyle(шаблон,цвет: integer).

Для задания шаблона можно использовать следующие константы:

EmptyFill=0 - закраска фоновым цветом;

SolidFill=1 - закраска заданным цветом;

LineFill=2 - закраска шаблоном вида - - - - - - -;

LtSlashFill=3 - закраска шаблоном вида / / / / / /;

SlashFill=4 - закраска шаблоном из толстых линий ////////;

BkSlashFill=5 - закраска шаблоном из толстых линий \\\\\\\;

LtBkSlashFill=6 - закраска шаблоном вида \ \ \ \ \ \;

HatchFill=7 - закраска редкой штриховкой;

XHatchFill=8 - закраска пересекающейся штриховкой;

InterLeaveFill=9 - закраска прерывистой линией;

WideDotFill=10 - закраска редкими точками;

CloseDotFill=11 - закраска частыми точками.

Пользователь имеет возможность создавать свои собственные шаблоны

заполнения с помощью процедуры SetFillPottern.

Для рисования т о ч к и на экране используется процедура

PutPixel(x,y,цвет: integer).

Точка - наименьший адресуемый элемент изображения, который

принято называть пикселом. Можно запросить цвет заданной точки экрана,

обратившись к функции

GetPixel(x,y: integer): integer.

Для вывода о т р е з к а прямой линии используются процедуры

145

Page 146: Комплексное пособие

Line(x1,y1,x2,y2: integer) - отрезок от (x1,y1) до

(x2,y2);

LineTo(x,y: integer)- отрезок от текущей точки до точки

(x,y);

LineRel(dx,dy: integer) - отрезок от текущей точки до

точки, определяемой смещением dx, dy.

Для задания текущей точки имеется специальный указатель текущей

позиции (УТП), который аналогичен курсору в текстовом режиме, но в

отличие от него невидим на экране. Изменение значения УТП отслеживается

графическими процедурами. Для перемещения УТП можно использовать

следующие процедуры:

MoveTo(x,y: integer) - перемещение УТП в точку (x,y);

MoveRel(dx,dy: integer) - смещение УТП на (dx,dy)

относительно его исходного положения.

Можно запросить значения УТП, обратившись к целочисленным

функциям GetX и GetY, которые аналогичны функциям WhereX и WhereY

для текстового режима.

Вывод прямоугольника с горизонтальными и вертикальными

сторонами производится процедурой

Rectangle(x1,y1,x2,y2: integer),

где (x1, y1) - левый верхний угол, а (x2, y2) - правый нижний угол

прямоугольника.

Вывод окружности с центром (x1, y1) и радиусом R производится

процедурой

Circle(x,y,R: integer).

Вывод дуги окружности производится процедурой

Arc(x,y,нач_угол,кон_угол,R: Integer),

где (x, y) - центр образующей окружности радиуса R, а нач_угол и

кон_угол задают начальный и конечный угол дуги (в градусах); дуга

146

Page 147: Комплексное пособие

рисуется против часовой стрелки в соответствии с общепринятыми

соглашениями.

Вывод дуги эллипса производится процедурой

Ellipse(x,y,нач_угол,кон_угол,RX,RY: integer),

где (x, y) - координаты центра, RX и RY - полуоси, а нач_угол и

кон_угол задают начальный и конечный углы дуги, аналогично дуге

окружности; если нач_угол=0, а кон_угол=359, то будет нарисован полный

эллипс.

Вывод контура многоугольника производится процедурой

DrawPoly(n: integer; var коорд_верш),

где n - число вершин, а параметр-переменная коорд_верш определяет

координаты всех вершин многоугольника. Тип этого параметра не задан,

поэтому он называется не типизированным, что является н е с т а н д а р т н о

й возможностью системы Турбо Паскаль. Соответствующий фактический

параметр может быть л ю б о г о типа. Например, удобно этот фактический

параметр описать как массив записей вида:

var коор : array[1..n] of record

x,y: integer

end;

При вычерчивании замкнутого многоугольника с m вершинами

начальная и конечная вершины рассматриваются как две отдельные

вершины, координаты которых одинаковы, поэтому n=m+1.

Для построения закрашенного многоугольника можно использовать

процедуру

FillPoly(n: integer; var коорд_верш),

где формальные параметры полностью аналогичны предыдущей

процедуре.

Отличие данной процедуры от предыдущей состоит в том, что сначала

рисуется контур многоугольника с использованием цвета, типа и толщины

линий, заданных процедурами SetColor и SetLineStyle, а затем многоугольник

147

Page 148: Комплексное пособие

закрашивается в соответствии с шаблоном и цветом, заданными процедурой

SetFillStyle.

Аналогичные действия, но по отношению к произвольной замкнутой

области, выполняется процедура

FloodFill(x,y,цвет_гран: integer).

Она заполняет замкнутую область с границей, определяемой заданным

цветом (параметр цвет_гран), в соответствии с заданным шаблоном закраски.

Если точка (x, y) находится внутри области, то закрашивается внутренность

области, иначе - весь экран за исключением заданной области.

Для вывода закрашенного кругового сектора можно использовать

процедуру

PieSlice(x,y,нач_угол,кон_угол,R: integer),

где формальные параметры полностью аналогичны параметрам

процедуры Arc.

Контур сектора вычерчивается в соответствии с заданным цветом, типом

и толщиной линии, а потом закрашивается в соответствии с заданным

шаблоном и цветом закраски.

Аналогичная процедура для закраски эллиптического сектора имеет

вид

Sector(x,y,нач_угол,кон_угол,RX,RY: integer).

Процедура

Bar(x1,x2,x2,y2: integer)

выводит прямоугольник , закрашенный в соответствии с установками

процедуры SetFillStyle.

Система программирования Турбо Паскаль предусматривает ряд

возможностей для вывода текстовой информации в графическом режиме.

Прежде всего, имеется возможность выбора одного из типов шрифта. По

умолчанию всегда выбирается точечный (растровый) шрифт, который для

вывода любого символа использует точечную матрицу размерности 8 на 8.

148

Page 149: Комплексное пособие

При желании вместо точечного шрифта можно использовать один из

штриховых (векторных) шрифтов, в которых любой символ описывается как

набор отрезков (векторов). Штриховые шрифты хранятся в специальных

файлах на диске и при необходимости загружаются в оперативную память.

Для задания типа шрифта можно использовать следующие константы:

DefaultFont=0 - точечный шрифт;

TriplexFont=1 - основной штриховой шрифт (файл triplex.chr);

SmallFont=2 - уменьшенный штриховой шрифт(файл small.chr);

SanSeriFont=3 - дополнительный штриховой шрифт(sanserif.chr);

GothicFont=4 - готический шрифт (файл gothic.chr).

Для задания горизонтального или вертикального направления вывода

текста можно использовать следующие константы:

HorizDir=0 - горизонтальное направление (слева - направо):

VertDir=1 - вертикальное направление(снизу-вверх).

Кроме того, имеется возможность управления размером символов. По

умолчанию для точечного шрифта выбирается наименьший возможный

размер, определяемый целочисленной константой NormSize=1.

Размер символов точечного шрифта можно увеличить в 2,3,...,10 раз.

Задание типа шрифта, направления вывода и размеров символов

производится процедурой

SetTextStyle(шрифт,направл,размер: integer).

Изменение высоты и ширины символов для штриховых шрифтов

производится процедурой

SetUserCharSize.

Выводимый текст можно выравнивать в горизонтальном или

вертикальном направлениях. Горизонтальное выравнивание определяется

следующими константами :

LeftText=0 - текст выводится вправо от заданной точки, т.е.

выравнивается по л е в о й границе текста;

149

Page 150: Комплексное пособие

CenterText=1 - центрирование текста, т.е. заданная точка соответствует

середине выводимого текста;

RightText=2 - текст выводится влево от заданной точки, т.е.

выравнивается по правой границе текста.

Аналогично, для вертикального выравнивания определены константы:

BottomText=0 - текст выводится н и ж е заданной точки;

CenterText=1 - центрирование текста;

TopText=2 - текст выводится в ы ш е заданной точки.

Нулевые значения констант выбираются по умолчанию. Для задания

выравнивания текста используется процедура

SetTextJustify(горизонт,вертик: integer).

Вывод текста производится двумя процедурами:

OutTextXY(x,y: integer; строка: string);

OutText(строка: string).

Первая выводит текст относительно заданной точки (x,y), а вторая -

относительно имеющего значение УТП (обе - с учетом выравнивания

текста).При использовании точечного шрифта (он всегда выбирается по

умолчанию) надо знать, что если выводимая строка не помещается

полностью на экране, то она просто не выводится!

Однако, при использовании штриховых шрифтов не выводится лишь та

часть строки, которая выходит за пределы экрана.

Задание области вывода

Область вывода (или область просмотра, поле вывода, графическое

окно)- это часть графического экрана, куда направляется весь графический

вывод без изменения остальной части экрана. В этом смысли понятие

области вывода аналогично понятию окна в текстовом режиме. Область

вывода задается процедурой

SetViewPort(x1,y1,x2,y2: integer; режим_отсечения:

boolean),

150

Page 151: Комплексное пособие

где (x1, y1) - координаты левого верхнего угла поля вывода, а (x2, y2) -

координаты правого нижнего угла. Булевский параметр ‘режим_отсечения’

определяет, включен или нет для данного поля вывода режим отсечения по

границе поля: если включен (константа ClipOn=true), то все выводимые

примитивы отсекаются по границе поля, т.е. не выходят за его пределы, в

противном случае (константа ClipOff = false) изображение может выходить за

границы области. Нормальное состояние области вывода соответствует

режиму включения отсечения.

На экране одновременно может существовать несколько областей

вывода. Для возврата в исходное состояние, соответствующее ПОЛНОМУ

экрану, можно сделать следующий вызов:

SetViewPort(0,0,GetMaxX,GetMaxY,True),

где GetMaxX и GetMaxY - функции модуля Graph, возвращающие

максимально возможные для данного графического режима значения

координат X и Y. Эти функции чрезвычайно полезны при написании

программ, работающих с различными адаптерами.

Для очистки области вывода можно использовать процедуру:

ClearViewPort.

151

Page 152: Комплексное пособие

Задания на лабораторные работы

Лабораторная работа №1.

Основные приемы работы в среде Turbo Pascal

Задание на лабораторную работу

Внимательно изучите следующий раздел. Следуя приведенным в них

указаниям, наберите, сохраните, скомпилируйте и посмотрите в отладчике

пример программы на языке Паскаль. Попробуйте повторить эти действия

самостоятельно с другим примером. В результате выполнения лабораторной

работы Вы должны научиться создавать, компилировать и отлаживать

программы на языке Паскаль в среде Turbo Pascal.

Работа в среде Turbo Pascal

Запуск среды Turbo Pascal

Для запуска среды достаточно, находясь в каталоге, содержащем

систему Турбо Паскаля, в ответ на подсказку DOS набрать TURBO и нажать

клавишу Enter. При этом запустится программа TURBO.EXE, которая и

создаёт среду. Для выхода из среды наберите Alt-Х.

Первое знакомство. Основное меню

При входе в интегрированную среду Турбо Паскаля 7.0 на экране

появляется окно, в верхней части которого высвечивается полоса с

надписями - заголовками секций меню, перечисляющими услуги,

предоставляемые средой. На рисунке приведен вид среды Turbo Pascal при

запуске ее из операционной системы Windows 95.

152

Page 153: Комплексное пособие

Вход в меню осуществляется одновременным нажатием клавиш Alt и

клавиши с буквой, выделенной в заголовке нужной секции меню. Например,

для входа в секцию File необходимо нажать Alt-F. Другим способом входа в

меню является нажатие функциональной клавиши F10 с последующим

перемещением в нужную позицию меню с помощью курсора (вправо или

влево). Выбранная позиция меню подсвечивается. При нажатии клавиши

Enter подсвеченная секция меню раскрывается в виде окна, содержащего

дальнейшую детализацию меню.

Например, если в меню оказывается подсвеченной секция Edit, то при

нажатии клавиши Enter раскрывается следующее окно:

153

Page 154: Комплексное пособие

Комбинация клавиш, указанные справа от названия действия,

определяют способ прямого входа в меню для выполнения указанного

действия.

Например, для выполнения действия «Сору» можно, находясь в меню, с

помощью курсора «наехать» на нужную позицию, подсветив ее, и нажать

клавишу Enter. Другим способом является использование клавиш. Не входя в

меню, можно выполнить операцию «Сору», нажав клавиши Ctrl-Ins.

Для выхода из меню достаточно нажать клавишу Esc.

Работа в редакционном окне, создание программы

Нажмите F10, чтобы войти в полосу меню, а затем «наедьте» Курсором

на позицию File, нажмите Enter (либо наберите Alt-F). Раскрывается секция

меню File:

154

Page 155: Комплексное пособие

Выберите строку New, нажмите клавишу Enter. На экране раскрывается

пустое окно, озаглавленное NONAME00.PAS. Это имя, данное средой по

умолчанию Вашей будущей программе. Если Вы повторите операцию,

раскроется еще одно окно, но уже с именем NONAME01.PAS. Таким образом

можно раскрыть достаточное число редакционных окон. Для Переключения

окон достаточно, удерживая нажатой клавишу Alt, нажать клавишу с цифрой

- окна пронумерованы. Например, для возврата в первое окно нужно набрать

Alt-1.

Итак, перед Вами пустое окно, в левом верхнем углу которого мигает

курсор. При наборе текста с помощью клавиатуры курсор будет

перемещаться. Приступите к вводу текста программы, нажимая Enter в конце

каждой строки:

program Summa;

var

A,B,Sum : integer;

begin

Wгitе(’Введите два числа: ‘);

Readln(A,B);

Sum :=А+В;

155

Page 156: Комплексное пособие

Wгitеln(’Сумма равна’,Sum);

Wгitе(’Нажмите Enter’);

Readln;

end.

Примечание. Не забывайте про точку с запятой, а за последним end

поставьте точку. Для удаления ошибочно набранного текста используйте

Backspace, а для передвижения внутри окна редактора используйте клавиши

со стрелками.

Сохранение программы

Для сохранения программы на диске выберите команду Save as из меню

Filе. Турбо Паскаль открывает диалоговый окно Save File As для

переименования файла и сохранения его в другом каталоге (директории) или

на другом диске.

Диалоговое окно содержит поле ввода Save file as, список файлов Files,

информационную панель, стандартные кнопки ОК, CANCEL, HELP и список

предыстории. Переключение между элементами окна осуществляется

клавишей Tab.

156

Page 157: Комплексное пособие

В поле ввода Save file as записывается имя, под которым Вы собираетесь

запомнить файл (либо файловая маска для поля Files).

В нашем случае необходимо набрать SUMMA.PAS н нажать Enter.

Рассмотрим детальнее остальные элементы диалогового бокса.

Поле Files содержит имена файлов в Текущем каталоге (директорий), в

соответствии с маской, установленной в поле Save file as.

Например, если в поле Save file as записано *.РАS, то в поле Files

появятся имена всех файлов каталога, содержащих расширение РАS.

Список предыстории добавляет к полю ввода все имена, которые

появлялись в нем во время последних вызовов диалогового окна. В список

предыстории можно войти в том случае, если справа от поля ввода Save file

as видите стрелку «вниз». Для входа в список следует нажать клавишу

«стрелка вниз» на клавиатуре. Этот список используется для повторного

ввода текста, который Вы уже вводили.

Выбор нужного элемента осуществляется курсором, при этом под-

свечивается выбранная позиция. Затем следует нажать клавишу Enter.

Выбранное имя файла попадает в поле ввода Save file as.

Если выбор не сделан, для выхода из списка предыстории нажмите

клавишу Esc. Информационная панель отображает путь к выбранному

файлу, его имя, дату, время создания и размер.

Кнопка ОК служит для подтверждения выполненных действий. Кнопка

CANCEL отменяет все действия и выводит из диалогового окна. Кнопка

HELP выводит окно с подсказкой.

Компиляция программы

Для компиляции программы выберите опцию Соmplile в основном

меню, для чего нажмите F10, С

Секция содержит подменю:

157

Page 158: Комплексное пособие

Команды меню Compile используются при компиляции и реализации

операций Make и Build.

Команда Compile компилирует файл в активном редакционном окне.

При компиляции или выполнения команды Make на экране высвечивается

окно состояния с результатами. После завершения компиляции или команды

Make для ликвидации окна статуса компиляции достаточно нажать любую

клавишу.

При обнаружении ошибки в верхней части редакционного окна

появляется сообщение.

Команда Make включает встроенный Project Manager для создания файла

.EXE.

Файлы рекомпилируются в соответствии со следующими правилами:

если Compile/Primary File содержит в списке первичный файл, он

компилируется, в противном случае компилируется последний файл,

загруженный в редактор. Турбо Паскаль проверяет все файлы, от

которых зависит компилируемый файл.

Если исходный файл для данного модуля (Unit) модифицировал-

ся после того, как объектный код (.TPU) файла был создан, модуль

перекомпилируется.

158

Page 159: Комплексное пособие

Если и интерфейс для данного модуля изменен, все другие

модули, от него зависящие, перекомпилируются.

Если модуль использует .OBJ file и он новее, чем .TPU file

данного модуля, модуль перекомпилируется.

Если модуль включает Include file и он новее, чем .TPU file

данного модуля, модуль перекомпилируется.

Команда Build перестраивает все файлы независимо от их НОВИЗНЫ.

Команда идентична команде Make, но не является условной (Make

перестраивает только файлы, изменённые после предыдущей сомпиляции).

Команда Dеstinаtiоn Memory (Disk) определяет место запоминания

выполняемого кода в памяти или на диске (файл с расширением .EXE).

Устанавливая Destination Disk, Вы увеличиваете память, доступную

среде для компиляции и отладки программы.

При установке Destination Memory при выходе из среды код исчезает.

Замечание. Даже если DestinatIon установлена в память, любые модули,

рекомпилированные с помощью Make или Build, хранят свои обновленные

файлы с расширением .TPU на диске.

При установке Destination на диск Турбо Паскаль создает файл .ЕХЕ,

имя которого выбирается из двух имен следующим образом: имя первичного

файла или, если не определено первичное имя, то назначается имя файла в

активном редакционном окне.

Турбо Паскаль запоминает результирующий файл .EXE в том же

каталоге, что и исходный файл или в каталоге, заданном в установке ЕХЕ &

TPU Directory меню Options/Directories.

Переустановка команды Destination происходит нажатием клавиши Enter

(установка Destination Memory сменится на Destination Disk и наоборот).

Итак, выполните команду Compile.

После начала компиляции в центре экрана появляется окно с

информацией о процессе компиляции. Если во время компиляции не

159

Page 160: Комплексное пособие

обнаружено ошибок, в этом окне появится сообщение «Compilation

successful: press any kеу» (компиляция успешна: нажмите любую клавишу).

Окно остается на экране до тех пор, пока Вы не нажмете любую

клавишу.

Как уже было сказано, при обнаружении ошибки, Турбо Паскаль

останавливает процесс трансляции, устанавливает курсор на ошибку в

редакционном окне и выдает сообщение об ошибке. Нажатие любой клавиши

убирает сообщение, а нажатие Ctrl-Q W обеспечивает его показ до тех пор,

пока Вы не измените файл или не перекомпилируете его.

Сделав исправления, сохраните обновленный файл и заново

скомпилируйте его.

Однако, для запоминания файла на этот раз нет необходимости

вызывать диалоговое окно Save as, достаточно нажать клавишу F2. Старый

вариант программы будет удален, а новый вариант будет сохранен в том же

файле. Если необходимо сохранить старый вариант, то надо воспользоваться

командой меню File/Save as и ввести новое имя файла или выбрать другой

каталог.

Выполнение программы

Для пуска программы выберите секцию Run в основном меню.

Секция содержит подменю:

160

Page 161: Комплексное пособие

Команды меню Run позволяют запускать Программу на выполнение,

начинать и заканчивать сеанс отладки.

Команда Run запускает Вашу программу на выполнение. При этом

используются любые параметры, передаваемые ей командой Run/Parameters.

Если исходный код модифицировался после последней компиляции,

компилятор автоматически сделает Make и свяжет программу.

Команда Program reset останавливает текущую отладку, освобождает

память, занятую программой и закрывает все файлы, используемые

программой.

Команда Go to cursor пускает программу от места останова (под-

свеченная строка исходного текста в редакционном окне) до строки, возле

которой установлен курсор. Если курсор находится на строке, не содержащей

выполняемых операторов, Турбо Паскаль высвечивает предупреждение. Эта

команда может инициировать отладку. Команда не устанавливает

постоянной точки прерывания, но позволяет программе останавливаться на

уже установленных постоянных точках, встречающихся до строки,

помеченной курсором. Если это произойдет, необходимо снова

воспользоваться командой Go to cursor. Удобно использовать эту команду

161

Page 162: Комплексное пособие

для предварительной установки run bar (подсвеченной строки, на которой

остановлена отладка).

Команда Trace into пускает Вашу программу построчно (оператор за

оператором). При достижении процедуры команда начинает пооператорное

выполнение процедуры (в отличие от команды Step Over, выполняющей

процедуру за один шаг).

Команда Step Over выполняет следующий оператор в текущей про-

цедуре, не трассируя вызовы процедур низшего уровня, даже если они

доступны отладчику, т.е. ее следует использовать для пооператорного

выполнения текущей процедуры без ухода в другие процедуры.

Итак, Вы в меню Run. Выберите команду Run. Вы попадете в окно

пользователя, появится сообщение:

Введите два числа:

Наберите два любых целых числа с пробелом между ними и нажмите

Enter. Появится следующее сообщение:

Сумма равна

а за ним - сумма двух чисел. В следующей строке появится сообщение:

Нажмите клавишу Enter

Программа будет ожидать нажатия клавиши Епtег. Для наблюдения за

выводом из своей программы, выберите команду User Screen в меню Window

(или нажмите Аlt-F5).

Отладка программы

Продемонстрируем использование интегрированного отладчика,

встроенного в среду Турбо Паскаля 7.0.

Интегрированный отладчик позволяет перемещаться по строкам

программы, одновременно наблюдая за изменением значений переменных.

Для начала сеанса отладки, выберите команду Trace Into меню Run (или

нажмите F7). Run bar (подсвеченная полоса) устанавливается на первой

строке (в данном случае begin).

162

Page 163: Комплексное пособие

Первое нажатие клавиши F7 инициализирует сеанс отладки. Теперь

нажмите F7, чтобы начать выполнение программы. Следующая выполнимая

строка - оператор Write. Нажмите F7 снова. Появится экран пользователя.

Это произойдет потому, что утверждение Readln ожидает ввода двух чисел.

Наберите два целых числа, разделенные пробелом. Нажмите Enter. Вы

вернетесь назад в редакционное окно, с Run bar на операторе присваивания.

Нажмите F7 и выполните оператор присваивания. Теперь полоса запуска

находится на операторе Writeln. Нажмите F7 дважды. Теперь Вы должны

выполнить Readln. НажмитеF7, посмотрите вывод своей программы и затем

нажмите Enter. Нажмите F7 и Вы выйдете из программы.

Для того чтобы наблюдать за значениями объявленных переменных,

войдите в секцию меню Debug.

Команда Add watch помещает наблюдаемое выражение в окно Watch.

При выборе Add Watch отладчик открывает диалоговое окно Add Watch. Во

входном боксе Watch expression высвечивается выражение по умолчанию (то,

на которое указывает курсор в редакционном окне).

Для поиска и выбора другого выражения (из числа уже

использовавшихся) можно открыть список предыстории. Если Вы вводите

163

Page 164: Комплексное пособие

допустимое выражение, нажав клавишу Enter или задействован Ok, отладчик

добавляет выражение и его текущее значение в окно Watch.

Если окно Watch является активным, для введения нового выражения

для наблюдения нужно нажать клавишу Ins.

Наберите А в окне ввода Watch Expression и нажмите Enter. А появится в

окне Watch вместе со своим текущим значением. Теперь используйте

команду Add Watch для добавления В и Sum в окно Watch.

Выберите Trace Into в секции Run (или нажмите F7) для того, чтобы

сделать шаг в своей программе. В окне Watch появятся А = 0, В =0, Sum = 0.

Когда после ввода чисел Вы нажмете Enter н вернетесь в редакционное окно,

значения А и В изменятся на введенные Вами. После выполнения оператора

вычисления суммы изменится и значение Sum.

Так, секция Options позволяет провести оптимальную настройку самой

среды, секция Edit содержит команды передачи фрагментов из одного окна в

другое либо внутри одного окна. Секция Search обеспечивает поиск и замену

фрагментов. Секция Window позволяет изменять размер окон, а также способ

их выдачи на экран. Наконец, секция Help поможет разобраться во всех

тонкостях использования среды.

Задание для самостоятельной работы

Введите текст программы в редакторе исходного кода среды Turbo

Pascal. Скомпилируйте программу и запустите ее на выполнение.

Определите, что делает программа.

Пример 1

Program P1;

var S:string;

begin

S:=’Просьба не беспокоить!’;

Writeln(S);

Readln;

164

Page 165: Комплексное пособие

End.

Пример 2

Program P2;

var i:integer;

begin

for i:=1 to 10 do

Writeln(i);

Readln;

End.

Пример 3

Program P3;

var i:integer;

begin

Write(’Введите цифру 1 или 2:’);

Readln(i);

if i=1 then Writeln(’Один’)

else Writeln(’Два’);

Readln;

End.

165

Page 166: Комплексное пособие

Лабораторная работа №2.

Типы данных, выражения, ввод/вывод

Задание на лабораторную работу

Напишите программу для расчета по двум формулам. Предварительно

подготовьте тестовые примеры для второй формулы с помощью

калькулятора (результаты вычисления по обеим формулам должны

совпадать). Отсутствующие в языке функции выразите через имеющиеся.

Необходимая информация

Для выполнения лабораторной работы необходимо изучить раздел

«Основные типы данных. Ввод/вывод».

Варианты индивидуальных заданий

1. 2.

3.4.

5. 6.

7.8.

9.10.

166

Page 167: Комплексное пособие

11. 12.

13.

14.

15. 16.

17. 18.

19. 20.

167

Page 168: Комплексное пособие

Лабораторная работа №3.

Циклы

Задание на лабораторную работу

Изучите материал приведённый ниже. Продумайте алгоритм и напишите

программу на языке Pascal для решения указанной преподавателем задачи

(см. Варианты индивидуальных заданий). Программа должна

предусматривать ввод исходных данных с клавиатуры и вывод результата на

экран.

Необходимая информация

Для выполнения лабораторной работы необходимо изучить раздел

«Операторы языка Pascal».

Варианты индивидуальных заданий

1. Ввести с клавиатуры последовательность из n (вводится с клавиатуры)

целых чисел. Вычислить в процессе ввода сумму и произведение введённых

чисел.

2. Вычислить квадратный корень из произвольного вещественного

числа, введенного с клавиатуры, используя метод Ньютона:

Здесь A – введенное число, Y0=A.

Если A – отрицательное число, то необходимо вывести сообщение об

ошибке.

Результат должен иметь относительную точность 1·10-6. Как только

получено значение Y0 оно используется для получения следующего

приближения Y0, по которому в свою очередь вычисляется Y0, и так до тех

пор, пока не будет достигнута требуемая точность, то есть, пока не станет

168

Page 169: Комплексное пособие

3. Вычисление числа e

Определить число e – основание натуральных логарифмов с помощью

ряда:

для всех значений n от 1 до 20. Для каждого случая напечатать n и

соответствующее приближение e.

4. Последовательности без повторений

Вывести на экран все числа из 3 цифр, причем внутри одного числа не

должно быть двух одинаковых цифр. Например, к таким числам относятся:

012, 271, 490. Число 6 такой последовательностью не является, так как

начинается с двух нулей.

5. Вывести на экран все трехзначные числа, состоящие из нечетных

цифр и их количество.

6. Вывести на экран все числа от 100 до 10000, которые делятся одновременно

на 7 и на 13 и их количество.

7. Вывести на экран все числа от 100 до 10000, сумма цифр которых равна

заданному числу.

8. Вывести на экран числа 1, 1, 2, 3, 5, 8, … (первые два числа – единицы,

каждое последующее равно сумме двух предыдущих). Не использовать массив.

9. Ввести с клавиатуры последовательность из n (вводится с клавиатуры)

целых чисел. Определить в процессе ввода количество положительных и

отрицательных чисел.

10. Ввести с клавиатуры последовательность из n (вводится с

клавиатуры) целых чисел. Определить в процессе ввода количество четных и

нечетных чисел.

169

Page 170: Комплексное пособие

11. Ввести с клавиатуры последовательность из n (вводится с

клавиатуры) целых чисел. Определить в процессе ввода среднее

арифметическое четных чисел последовательности.

12. Ввести с клавиатуры последовательность из n (вводится с

клавиатуры) целых чисел. Определить в процессе ввода, составляют ли числа

возрастающую последовательность.

13*. Совершенные числа

Совершенными называются числа, равные сумме всех своих делителей,

включая 1. Например, 6 – совершенное число, поскольку 6=1+2+3. Требуется

найти и вывести на экран все совершенные числа вместе с их делителями,

лежащие в диапазоне от 4 до 10000.

170

Page 171: Комплексное пособие

Лабораторная работа №4.

Одномерные массивы

Задание на лабораторную работу

Одной из классических задач является поиск простых чисел. Ниже

обсуждаются два алгоритма её решения. Напишите программу для алгоритма

«Решето Эратосфена». Самостоятельно продумайте алгоритм решения и

напишите программу для одного из вариантов индивидуальных заданий.

Необходимая информация

Для выполнения лабораторной работы необходимо изучить раздел

«Структурированные типы. Массивы».

Варианты индивидуальных заданий

1. Ввести массив целых чисел из n элементов (задано константой).

Переместить все нулевые элементы в начало массива. Вывести массив на

экран.

2. Ввести с клавиатуры целочисленный массив из n элементов (задано

константой). Подсчитать количество чисел, значение которых (x) лежит в

заданных пределах L<x<M, где L и M вводятся с клавиатуры. Вывести на

экран полученное значение.

3. Ввести с клавиатуры целочисленный массив из n элементов (задано

константой). Подсчитать количество чисел, значение которых меньше

значений обоих соседних элементов. Вывести на экран полученное значение.

4. Ввести с клавиатуры вещественный массив из n элементов (задано

константой). Вычислить разность суммы положительных и абсолютного

значения суммы отрицательных элементов. Вывести на экран полученное

значение.

5. Ввести с клавиатуры вещественный массив из n элементов (задано

константой). Вычислить разность суммы элементов с четными индексами и

171

Page 172: Комплексное пособие

суммы элементов с нечетными индексами. Вывести на экран полученное

значение.

6. Ввести массив целых чисел из n элементов (задано константой).

Переместить все отрицательные элементы в конец массива. Вывести массив

на экран.

7. Ввести массив целых чисел из n элементов (задано константой).

Проверить, что элементы с нечетным индексом расположены в порядке

неубывания. Вывести на экран результат.

8. Ввести массив вещественных чисел из n элементов (задано константой).

Вычислить сумму элементов, расположенных до максимального элемента.

Вывести на экран полученное значение.

9. Ввести массив вещественных чисел из n элементов (задано константой).

Вычислить разность суммы первой половины элементов и произведения

второй половины элементов. Вывести на экран полученное значение.

10.Ввести массив целых чисел из n элементов (задано константой).

Проверить, что элементы с четным индексом расположены в порядке

убывания. Вывести на экран результат.

11.Ввести массив вещественных чисел из n элементов (задано константой).

Вычислить произведение элементов, расположенных после минимального

элемента. Вывести на экран полученное значение.

12.Ввести массив целых чисел из n элементов (задано константой).

Последовательно поменять местами элементы на четных и нечетных местах

(1-й и 2-й, 3-й и 4-й и тд.. Вывести на экран полученное значение.

13.*Ввести с клавиатуры целочисленный массив из n элементов (задано

константой). Найти второй по величине элемент. Вывести на экран

найденный элемент, его индекс.

14.*Даны действительные числа а0, а1, ..., а5. Получить (в виде массива

коэффициентов) многочлен шестой степени (х—а0)(х—а1) ... (х—а5).

172

Page 173: Комплексное пособие

Лабораторная работа №5.

Матрицы

Задание на лабораторную работу

Изучите материал приведённый ниже. Самостоятельно продумайте

алгоритм решения и напишите программу для одного из вариантов

индивидуальных заданий.

Необходимая информация

Для выполнения лабораторной работы необходимо изучить раздел

«Структурированные типы. Массивы».

Варианты индивидуальных заданий

1. Ввести с клавиатуры вещественную матрицу размерности n´m (заданы

константами). Найти максимальный и минимальный элементы и их

индексы. Вывести на экран найденные элементы, их индексы.

2. Ввести с клавиатуры вещественную матрицу размерности n´m (заданы

константами). Заменить все отрицательные числа их абсолютным

значением. Вывести на экран полученную матрицу.

3. Ввести с клавиатуры вещественную матрицу размерности n´m (заданы

константами). Вычислить среднее арифметическое для каждого столбца.

Вывести исходную матрицу и полученные значения на экран.

4. Ввести с клавиатуры вещественную матрицу размерности n´m (заданы

константами). Заменить все положительные числа их квадратом. Вывести

на экран полученную матрицу.

5. Ввести с клавиатуры целочисленную матрицу размерности n´m (заданы

константами). Подсчитать количество положительных и отрицательных

чисел. Вывести на экран полученные значения.

173

Page 174: Комплексное пособие

6. Ввести с клавиатуры целочисленную матрицу размерности n´m (заданы

константами). Найти максимальный элемент среди элементов с нечетной

суммой индексов. Вывести на экран найденный элемент, его индексы.

7. Ввести с клавиатуры целочисленную матрицу размерности n´m (заданы

константами). Подсчитать количество четных и нечетных чисел. Вывести

на экран полученные значения.

8. Ввести с клавиатуры вещественную матрицу размерности n´m (заданы

константами). Вычислить среднее арифметическое для каждой строки.

Вывести исходную матрицу и полученные значения на экран.

9. Ввести с клавиатуры вещественную матрицу размерности n´n (задана

константой). Подсчитать количество нулевых элементов, расположенных

на главной и побочной диагоналях.

10.Ввести с клавиатуры целочисленную матрицу размерности n´m (заданы

константами). Найти элемент кратный заданному числу. Вывести на экран

найденный элемент, его индексы, степень кратности.

11.Поиск наибольшего числа в трехмерном массиве

Пусть массив Т имеет размерность 3х5х7. Найти наибольшее

содержащееся в нем число и вывести его и его индексы на экран.

12.*Поиск двух одинаковых чисел в двумерном массиве.

Массив А размерностью 30х7 содержит два (и только два) одинаковых

числа. Необходимо найти их и вывести на экран их индексы. Избегайте

лишних сравнений (особенно сравнений элемента с самим собой).

13.Суммирование элементов двумерного массива, сумма индексов которых

равна заданной константе

Массив X размерностью 10х30 содержит вещественные числа. Требуется

ввести целое число k и вычислить сумму элементов Xi,j, для которых i+j=k.

Естественно, следует убедиться, что значение позволяет найти решение,

иначе нужно вывести сообщение об ошибке.

Задачу можно решить не перебирая все элементы массива!

14.*Решение нижней треугольной системы

174

Page 175: Комплексное пособие

Требуется написать программу, которая решает треугольную систему

порядка n:

В программе необходимо ввести следующие данные:

A – квадратная матрица коэффициентов,

B – вектор свободных членов.

Порядок системы n задается в виде константы. Вектор X будет хранить

решение. Кроме того, понадобится индикатор ошибки k.

Если все кончилось благополучно, то индикатор будет иметь значение

false (ошибки не было), иначе – true (произошла ошибка). Это означает, что в

какой-то момент один из делителей оказался равным нулю. Алгоритм поиска

решения очень прост. Достаточно найти x1 из первого уравнения, подставить

его во второе, чтобы найти x2 и продолжать таким образом до тех пор, пока

не будет вычислено значение xn.

175

Page 176: Комплексное пособие

Лабораторная работа №6.

Процедуры и функции

Задание на лабораторную работу

Размерности массивов следует задать именованными константами. Все

необходимые данные должны передаваться подпрограммам в качестве

параметров; все величины, используемые только внутри подпрограмм,

должны быть описаны как локальные. Использование глобальных

переменных в подпрограммах не допускается. Вывод результатов работы

подпрограмм должен выполняться в главной программе.

Необходимая информация

Для выполнения лабораторной работы необходимо изучить разделы

«Структурированные типы. Массивы», «Процедуры и функции».

Варианты индивидуальных заданий

1.

Дана целочисленная прямоугольная матрица. Определить:

1. Количество строк, не содержащих ни одного нулевого элемента

(оформить в виде функции).

2. Максимальное из чисел, встречающихся в заданной матрице более одного

раза (оформить в виде процедуры).

2.

Дана целочисленная прямоугольная матрица.

1. Определить количество столбцов, не содержащих ни одного нулевого

элемента (оформить в виде функции).

2. Характеристикой строки целочисленной матрицы назовем сумму ее

положительных четных элементов. Переставляя строки заданной

176

Page 177: Комплексное пособие

матрицы, расположить их в соответствии с ростом характеристик

(оформить в виде процедуры).

3.

Дана целочисленная прямоугольная матрица. Определить:

1. Количество столбцов, содержащих хотя бы один нулевой элемент

(оформить в виде функции),

2. Номер строки, в которой находится самая длинная серия одинаковых

элементов (оформить в виде процедуры).

4.

Дана целочисленная квадратная матрица. Определить:

1. Произведение элементов в тех строках, которые не содержат

отрицательных элементов (оформить в виде функции).

2. Максимум среди сумм элементов диагоналей, параллельных главной

диагонали матрицы (оформить в виде процедуры).

5.

Дана целочисленная квадратная матрица. Определить:

1. Сумму элементов в тех столбцах, которые не содержат отрицательных

элементов (оформить в виде функции).

2. Минимум среди сумм модулей элементов диагоналей, параллельных

побочной диагонали матрицы (оформить в виде процедуры).

6.

Дана целочисленная прямоугольная матрица. Определить:

1. Сумму элементов в тех строках, которые содержат хотя бы один

отрицательный элемент (оформить в виде функции).

2. Номера строк и столбцов всех седловых точек матрицы (оформить в виде

процедуры).

ПРИМЕЧАНИЕ

177

Page 178: Комплексное пособие

Матрица А имеет седловую точку Ау, если Ау является минимальным

элементом в i-й строке и максимальным в j-м столбце.

7.

1. Для заданной матрицы размером 8x8 найти такие kt что k-я строка

матрицы совпадает с k-u столбцом (оформить в виде процедуры).

2. Найти сумму элементов в тех строках, которые содержат хотя бы один

отрицательный элемент (оформить в виде функции).

8.

1. Характеристикой столбца целочисленной матрицы назовем сумму

модулей его отрицательных нечетных элементов. Переставляя столбцы

заданной матрицы, расположить их в соответствии с ростом

характеристик (оформить в виде процедуры).

2. Найти сумму элементов в тех столбцах, которые содержат хотя бы один

отрицательный элемент (оформить в виде функции).

9.

1. Соседями элемента Аij в матрице назовем элементы Аkl, где i-1ki+1, j-

1l j + 1, (k,l) (i,j). Операция сглаживания матрицы дает новую

матрицу того же размера, каждый элемент которой получается как

среднее арифметическое имеющихся соседей соответствующего элемента

исходной матрицы. Построить результат сглаживания заданной

вещественной матрицы размером 10х10 (оформить в виде процедуры).

2. В сглаженной матрице найти сумму модулей элементов, расположенных

ниже главной диагонали (оформить в виде функции).

10.

1. Соседями элемента Аij в матрице назовем элементы Аkl, где i-1ki+1, j-

1l j + 1, (k,l) (i,j). Элемент матрицы называется локальным

минимумом, если он строго меньше всех имеющихся у него соседей

(определение соседних элементов см. в варианте 9). Подсчитать

178

Page 179: Комплексное пособие

количество локальных минимумов заданной матрицы размером 10x10

(оформить в виде процедуры).

2. Найти сумму модулей элементов, расположенных выше главной

диагонали (оформить в виде функции).

11.

1. Коэффициенты системы линейных уравнений заданы в виде

прямоугольной матрицы. С помощью допустимых преобразований

привести систему к треугольному виду (оформить в виде процедуры).

2. Найти количество строк, среднее арифметическое элементов которых

меньше заданной величины (оформить в виде функции).

12.

1. Уплотнить заданную матрицу, удаляя из нее строки и столбцы,

заполненные нулями (оформить в виде процедуры).

2. Найти номер первой из строк, содержащих хотя бы один положительный

элемент (оформить в виде функции).

13.

Осуществить циклический сдвиг элементов прямоугольной матрицы на

п элементов вправо или вниз (в зависимости от введенного режима), п

может быть больше количества элементов в строке или столбце (оформить в

виде процедуры).

14.

Осуществить циклический сдвиг элементов квадратной матрицы

размером MxN вправо на k элементов таким образом: элементы первой

строки сдвигаются в последний столбец сверху вниз, из него — в

последнюю строку справа налево, из нее — в первый столбец снизу вверх, из

него — в первую строку; для остальных элементов — аналогично (оформить

в виде процедуры).

179

Page 180: Комплексное пособие

15.

1. Дана целочисленная прямоугольная матрица. Определить номер первого

из столбцов, содержащих хотя бы один нулевой элемент (оформить в виде

функции).

2. Характеристикой строки целочисленной матрицы назовем сумму ее

отрицательных четных элементов. Переставляя строки заданной матрицы,

расположить их в соответствии с убыванием характеристик (оформить в

виде процедуры).

16.

1. Упорядочить строки целочисленной прямоугольной матрицы по

возрастанию количества одинаковых элементов в каждой строке

(оформить в виде процедуры).

2. Найти номер первого из столбцов, не содержащих ни одного

отрицательного элемента (оформить в виде функции).

17.

1. Путем перестановки элементов квадратной вещественной матрицы

добиться того, чтобы ее максимальный элемент находился в левом

верхнем углу, следующий по величине — в позиции (2, 2), следующий по

величине — в позиции (3, 3) и т. д., заполнив таким образом всю главную

диагональ (оформить в виде процедуры).

2. Найти номер первой из строк, не содержащих ни одного положительного

элемента (оформить в виде функции).

18.

Дана целочисленная прямоугольная матрица. Определить:

1. Количество строк, содержащих хотя бы один нулевой элемент (оформить

в виде функции).

2. Номер столбца, в котором находится самая длинная серия одинаковых

элементов (оформить в виде процедуры).

180

Page 181: Комплексное пособие

19.

Дана целочисленная квадратная матрица. Определить:

1. Сумму элементов в тех строках, которые не содержат отрицательных

элементов (оформить в виде функции).

2. Минимум среди сумм элементов диагоналей, параллельных главной

диагонали матрицы (оформить в виде процедуры).

20.

Дани целочисленная прямоугольная матрица. Определить:

1. Количество отрицательных элементов в тех строках, которые содержат

хотя бы один нулевой элемент (Оформить в виде функции).

2. Номера строк и столбцов всех седловых точек матрицы (оформить в виде

процедуры).

ПРИМЕЧАНИЕ

Матрица А имеет седловую точку Аij, если Aij является минимальным

элементом в i-й строке и максимальным в j-м столбце.

181

Page 182: Комплексное пособие

Лабораторная работа №7.

Множества, строки и записи

Задание на лабораторную работу

Сравнить программы для поиска простых чисел, приведенные ниже (с

использованием множеств) и в лабораторной работе №3. Выполнить один из

вариантов индивидуальных заданий, пользуясь информацией из следующего

раздела.

Необходимая информация

Для выполнения лабораторной работы необходимо изучить разделы

«Структурированный тип данных – записи», «Структурированный тип

данных – множества».

Варианты индивидуальных заданий

1. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО, дата рождения. Программа должна

выполнять следующие действия: ввод данных, поиск человека по

заданной дате рождения и вывод информации о нём.

2. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: Название товара, цена. Программа должна

выполнять следующие действия: ввод данных, изменение цены заданного

товара.

3. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО сотрудника, подразделение, оклад.

Программа должна выполнять следующие действия: ввод данных,

просмотр списка сотрудников заданного подразделения по одному

человеку с командами «перейти к следующему» и «перейти к

предыдущему».

182

Page 183: Комплексное пособие

4. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО автора, название книги, общее количество

книг в библиотеке, количество выданных книг, номер шкафа, где хранится

книга. Программа должна выполнять следующие действия: ввод данных,

по заданным полям «Автор» и «Название» определить возможно ли

выдать книгу, если да – указать номер шкафа.

5. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: Наименование товара, цена. Программа должна

выполнять следующие действия: ввод данных, удаления товара.

6. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО студента, массив оценок. Программа

должна выполнять следующие действия: ввод данных (фамилии

студентов, массивы оценок заполняются нулями), запись заданному

студенту очередной оценки.

7. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: Наименование товара, цена, количество на

складе. Программа должна выполнять следующие действия: ввод данных,

вывод на экран «счета» (т.е. наименования товара, количества, стоимости

единицы товара и общая стоимость заказа) на заданное количество товара,

если он есть на складе.

8. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО сотрудника, почасовая оплата,

количество часов. Программа должна выполнять следующие действия:

ввод данных (изначально информация записывается в поля "ФИО

сотрудника" и " почасовая оплата", поле "количество часов" заполняется

нулями), запись количества часов заданному сотруднику, расчет и вывод

ведомости на зарплату сотрудникам (т.е. выводится таблица с колонками:

ФИО сотрудника, почасовая оплата, количество часов, зарплата за месяц).

183

Page 184: Комплексное пособие

Лабораторная работа №8.

Файлы

Задание на лабораторную работу

Добавить к программе из лабораторной работы №7 следующие

действия:

сохранение информации в текстовый файл

загрузка информации из текстового файла

сохранение информации в типизированный файл

загрузка информации из типизированного файла

Оформить все действия в виде процедур.

Необходимая информация

Для выполнения лабораторной работы необходимо изучить разделы

«Структурированный тип данных – записи», «Структурированный тип

данных – множества».

Варианты индивидуальных заданий

Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО, дата рождения. Программа должна

выполнять следующие действия: ввод данных, поиск человека по заданной

дате рождения и вывод информации о нём.

9. Написать программу, в которой описывается массив записей, хранящий

следующую информацию: Название товара, цена. Программа должна

выполнять следующие действия: ввод данных, изменение цены заданного

товара.

10.Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО сотрудника, подразделение, оклад.

Программа должна выполнять следующие действия: ввод данных, просмотр

184

Page 185: Комплексное пособие

списка сотрудников заданного подразделения по одному человеку с

командами «перейти к следующему» и «перейти к предыдущему».

11.Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО автора, название книги, общее количество

книг в библиотеке, количество выданных книг, номер шкафа, где хранится

книга. Программа должна выполнять следующие действия: ввод данных, по

заданным полям «Автор» и «Название» определить возможно ли выдать

книгу, если да – указать номер шкафа.

12.Написать программу, в которой описывается массив записей, хранящий

следующую информацию: Наименование товара, цена. Программа должна

выполнять следующие действия: ввод данных, удаления товара.

13.Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО студента, массив оценок. Программа должна

выполнять следующие действия: ввод данных (фамилии студентов, массивы

оценок заполняются нулями), запись заданному студенту очередной оценки.

14.Написать программу, в которой описывается массив записей, хранящий

следующую информацию: Наименование товара, цена, количество на складе.

Программа должна выполнять следующие действия: ввод данных, вывод на

экран «счета» (т.е. наименования товара, количества, стоимости единицы

товара и общая стоимость заказа) на заданное количество товара, если он

есть на складе.

15.Написать программу, в которой описывается массив записей, хранящий

следующую информацию: ФИО сотрудника, почасовая оплата, количество

часов. Программа должна выполнять следующие действия: ввод данных

(изначально информация записывается в поля "ФИО сотрудника" и "

почасовая оплата", поле "количество часов" заполняется нулями), запись

количества часов заданному сотруднику, расчет и вывод ведомости на

зарплату сотрудникам (т.е. выводится таблица с колонками: ФИО

сотрудника, почасовая оплата, количество часов, зарплата за месяц).

185

Page 186: Комплексное пособие

Контрольные вопросы

16.Что такое алгоритм?

17.Какие есть алгоритмические структуры?

18.Как представляются алгоритмические структуры с помощью блок-схем?

19.Что такое язык программирования?

20.Как классифицируются языки программирования?

21.Какие есть способы трансляции программ?

22.Зачем нужно транслировать программы?

23.Алфавит языка Паскаль.

24.Идентификаторы языка Паскаль.

25.Что такое константа?

26.Что такое переменная?

27.Что такое тип данных?

28.Приведите пример простейшей программы на языке Паскаль.

29.Приведите структуру программы на языке Паскаль.

30.Перечислите простые типы данных. Дайте краткую характеристику

каждому типу.

31.Приведите пример использования целых чисел.

32.Приведите пример использования вещественных чисел.

33.Приведите пример использования символов.

34.Назначение функций ввода/вывода. Пример использования.

35.Процедуры write и writeln. Синтаксическая конструкция, логика работы.

36.Приведите пример использования процедуры write или writeln.

37.Процедуры read и readln. Синтаксическая конструкция, логика работы.

38.Приведите пример использования процедуры read или readln.

39.Оператор присваивания. Синтаксическая конструкция, логика работы.

40.Какие арифметические операции есть в языке Паскаль? Приведите пример

их использования.

186

Page 187: Комплексное пособие

41.Какие операции отношения есть в языке Паскаль? Приведите пример их

использования.

42.Какие логические операции есть в языке Паскаль? Приведите пример их

использования.

43.Приоритет операций.

44.Приведите пример выражения, напишите порядок вычисления выражения.

45.Алгоритмическая структура выбор вариантов.

46.Оператор if. Синтаксическая конструкция, логика работы.

47.Оператор case. Синтаксическая конструкция, логика работы.

48.Приведите пример использования оператора case.

49.Приведите пример использования оператора if.

50.Оператор цикла while. Опишите синтаксическую конструкцию, логику

работы.

51.Оператор цикла repeat…until. Опишите синтаксическую конструкцию,

логику работы.

52.Оператор цикла for. Опишите синтаксическую конструкцию, логику

работы.

53.Приведите пример использования оператора цикла while.

54.Приведите пример использования оператора цикла repeat…until.

55.Приведите пример использования оператора цикла for.

56.Приведите пример использования оператора цикла for с символьной

переменной цикла.

57.Оператор goto. Опишите синтаксическую конструкцию, логику работы.

58.Перечислите структурированные типы, дайте им характеристику.

59.Как объявить переменную типа массив? Опишите синтаксическую

конструкцию, приведите пример.

60.Как объявить переменную типа строка? Опишите синтаксическую

конструкцию, приведите пример.

61.Как объявить переменную типа запись? Опишите синтаксическую

конструкцию, приведите пример.

187

Page 188: Комплексное пособие

62.Как изменить значение элемента массива?

63.Что такое двумерный массив?

64.Как изменить значение элемента двумерного массива?

65.Как ввести все элементы массива?

66.Как ввести все поля записи?

67.Как вывести все элементы массива?

68.Как вывести все поля записи?

69.Функция length(). Назначение, описание, пример использования.

70.Какие операции можно выполнять с переменными типа строка?

71.Для чего и как используется оператор with? Приведите пример.

72.Объявление переменных типа массив записей.

73.Приведите пример добавления элемента в массив структур.

74.Приведите пример удаления элемента из массива структур.

75.Приведите пример поиска элемента в массиве структур.

76.Что такое подпрограмма?

77.Какие виды подпрограмм есть в языке Паскаль?

78.Как описать и использовать свою функцию на языке Паскаль? Приведите

пример.

79.Что такое параметры и возвращаемое значение функции. Привести

пример.

80.Как описать и использовать свою процедуру на языке Паскаль? Приведите

пример.

81.Что такое параметры-значения и как их использовать?

82.Что такое параметры-переменные и как их использовать?

83.Каковы правила определения видимости?

84.Что такое модуль?

85.Какие разделы содержит модуль?

86.Как модули подключаются к основной программе?

87.Какие функции и процедуры модуля можно вызывать извне модуля, а

какие нет?

188

Page 189: Комплексное пособие

88.Что такое файл?

89.Какие виды файлов есть в языке Паскаль?

90.Что такое текстовый файл?

91.Как объявить переменную типа текстовый файл?

92.Что такое типизированный файл?

93.Как объявить переменную типа типизированный файл?

94.Что такое нетипизированный файл?

95.Как объявить переменную типа нетипизированный файл?

96.Какие режимы можно использовать в Паскале при инициации файлов?

97.Как создать новый каталог?

98.Как изменить текущий каталог?

99.Как переименовать файл?

100. Как переместить файл?

101. Как скопировать файл?

102. Как удалить файл?

103. Как удалить каталог?

104. Как открыть файл?

105. Как закрыть файл?

106. Как используются процедуры записи и чтения информации при работе

с текстовыми файлами.

107. Как используются процедуры записи и чтения информации при работе

с типизированными файлами.

108. Как используются процедуры записи и чтения информации при работе

с нетипизированными файлами.

109. Операция @. Назначение, описание, пример использования.

110. Что такое указатель?

111. Как выделить память? Привести пример.

112. Как освободить динамически выделенную память? Привести пример.

113. Как задать цвет текста в графическом режиме работы монитора?

114. Как задать цвет фона в графическом режиме работы монитора?

189

Page 190: Комплексное пособие

115. Что такое графический драйвер?

116. Что такое режим драйвера?

117. Что такое графический примитив?

118. Как нарисовать линию?

119. Как нарисовать эллипс?

120. Как нарисовать закрашенный эллипс?

121. Как нарисовать прямоугольник?

122. Как нарисовать закрашенный прямоугольник?

123. Как нарисовать точку?

124. Как задать область вывода?

125. Как задать тип линии?

126. Как переместить картинку по экрану?

127. Как инициализировать графический режим работы монитора?

128. Как восстановить текстовый режим работы монитора?

190

Page 191: Комплексное пособие

Литература

а) Основная литература

1. Фаронов В.В. Turbo Pascal 7.0 Начальный курс. Учебное пособие. М.:

«ОМД Групп», 2003.- 616с.

2. Павловская Т.А. Паскаль. Программирование на языке высокого

уровня. Учебник для ВУЗов. СПб: «Питер», 2007. – 393с.

3. Павловская Т.А. Паскаль. Программирование на языке высокого

уровня. Практикум. СПб: «Питер», 2007. – 317с.

б) Дополнительная литература

1. Лавров С. Программирование. Математические основы, средства,

теория СПб.: BHV, 2002. – 304 с.

2. Культин Н. Turbo Pascal в задачах и примерах. Учебное пособие. СПб.:

BHV, 2007. – 384 с.

3. Немюгин С.А. Turbo Pascal. Программирование на языке высокого

уровня. Учебник для ВУЗов. 2 изд. СПб: «Питер», 2007. – 544 с.

4. Керниган Б. Язык программирования Си. изд.2 Киев: Диалектика, 2006.

– 352 с.

191