Книга: Песни о Паскале
Глава 50 Неспортивные рекорды (записи)
Разделы на этой странице:
Глава 50
Неспортивные рекорды (записи)
Кушать подано!
Вообразите себя в гостях за столом, накрытым посудой и вкусностями. Только стол этот накрыт необычно: в одном углу – стопка тарелок, в другом – букет вилок, а там собраны все ножи. Неудобно, однако! Голодных гостей такие мелочи, ясно, не остановят, но согласитесь, – так накрывать не принято.
Или взять ранец со школярским добром: книгами, тетрадями, ручками и карандашами. Что, если нагрузить одного ученика всеми учебниками класса, другого – всеми тетрадями, а третьего – карандашами? Удобно им будет?
Однако ж, мы поступили именно так в одной из программ главы 41. Вспомните сортировку таблицы футбольного чемпионата. Там мы завели два массива: один – для набранных очков, другой – для названий команд. А затем в ходе сортировки меняли местами элементы этих массивов (программа «P_41_3»). Добавляя в таблицу чемпионата другие сведения о командах (забитые и пропущенные мячи, выигрыши, проигрыши и так далее), нам придётся заводить для них свои массивы. А потом возиться с перестановкой их элементов при сортировке, – тоска!
Нередко мы сталкиваемся с набором разнородных, но логически связанных предметов или данных, как в упомянутых выше случаях. И воспринимаем такие наборы как нечто целое, – это освобождает наш мозг от второстепенных деталей. Вот бы и в программировании найти средство логического соединения разнородных элементов!
Записи
В современных языках такое средство есть. В Паскале оно называется записью, по-английски – RECORD. «Рекорд» – знакомое словцо, не так ли? – оно имеет отношение к спорту. В самом деле, то, что мы называем спортивными рекордами, изначально было лишь записью в журнале регистрации спортивных достижений: кем, когда, где и сколько. Отсюда и пошло слово «рекорд».
Но вернемся к Паскалю. Итак, запись объединяет в единый набор логически связанные, но разнородные данные и дает этому набору имя. Такое объединение обозначают парой ключевых слов RECORD-END и размещают либо в секции объявления типов, либо в секции объявления переменных. Возьмем футбольную команду и соединим её название и набранные ею очки. Объявим для команды тип данных, который так и назовем – Team – «команда». А затем учредим две переменные этого типа, вот как это выглядит.
type Team = record { тип данных «команда» }
Aces : integer; { набранные очки }
Name : string; { название команды }
end;
var Team1, Team2 : Team; { две переменных типа «команда» }
Может показаться, что между ключевыми словами RECORD и END объявлены переменные Aces и Name. Так ли это? И да, и нет. Нет, – потому, что в секции TYPE переменные не объявляют. Да, – потому, что внутри переменных Team1 и Team2 (объявленных чуть ниже в секции VAR) действительно «живут» переменные с именами Aces и Name. Только называются они теперь полями переменных Team1 и Team2.
Как получить доступ к этим полям, спрятанным внутри переменных? Надо к имени переменной добавить так называемый квалификатор поля, или проще – имя этого поля. Вот так присваивают значения полям переменной Team1.
Team1.Aces := 25;
Team2.Name := ’Dinamo’;
Как видите, квалификатор поля отделяют от имени переменной точкой. Поля – это «кусочки» более сложных переменных (в данном случае переменных Team1 и Team2). Во всем остальном, кроме способа доступа, поля записей ничем не отличаются от обычных переменных.
Переменные, построенные на основе записей, называют структурными переменными или агрегатами. В чем их прелесть? В том, что обращаться с ними можно как с единым целым, например, копировать.
Team2 := Team1; { перенос всех полей из Team1 в Team2 }
Это существенно упрощает программы, в чем вы скоро убедитесь. А в сочетании с особыми типами данных – указателями – записи превращаются в «волшебные кирпичи», пригодные для возведения сложнейших структур, отражающих реальности нашего мира.
Второй тайм
Слышен свисток к началу второго тайма, вернемся на футбольное поле, точнее к программе «P_41_3», сортирующей команды в порядке занятых ими мест. Сотворим новую версию этой программы «P_50_1», заменив два массива (набранных очков и названий команд) одним. План игры на второй тайм таков. Объявим два типа данных: запись и массив записей. Первый из них – запись – будет содержать сведения об отдельной команде.
type TTeam = record
mAces : integer; { набранные очки }
mName : string; { названия команд }
end;
Напомню, что для улучшения читаемости программ мы условились начинать названия типов данных с буквы «T». По этой причине тип данных «команда» (Team) стал называться TTeam. Подобное соглашение примем и для полей записей. Чтобы отличить их от прочих переменных, будем начинать имена полей с буквы «m» (от Member – «элемент», «участник»). Поэтому поля названы здесь как mAces и mName.
Второй из объявляемых типов данных – TChamp (Champ – «чемпионат») – представляет собой массив футбольных команд.
TChamp = array [1..CSize] of TTeam; { тип для массива команд }
Стало быть, каждый элемент этого типа содержит внутри себя два поля: число mAces и строку mName. Теперь можно объявить и переменную типа TChamp, то есть, массив команд.
var Champ : TChamp; { массив команд }
Доступ к элементам массива Champ осуществляется так:
Champ[i] – i–й элемент массива, то есть i–я команда (тип TTeam)
Champ[i].mAces – количество набранных очков i–й командой
Champ[i].mName – название i–й команды
После всего сказанного рассмотрим программу «P_50_1» в целом.
{ P_50_1 – Футбольный чемпионат (версия 2) }
const CSize = 4; { количество команд }
{ объявление типов }
type TTeam = record
mAces : integer; { набранные очки }
mName : string; { названия команд }
end;
TChamp = array [1..CSize] of TTeam; { тип для массива команд }
var Champ : TChamp; { массив команд }
{ Процедура "пузырьковой" сортировки команд }
procedure BubbleSort(var arg: TChamp);
var i, j : Integer;
t : TTeam; { для временного хранения при обмене }
begin
for i:= 1 to CSize-1 do { внешний цикл }
for j:= 1 to CSize-i do { внутренний цикл }
{ если текущий элемент меньше следующего …}
if arg[j].mAces < arg[j+1].mAces then begin
{ то меняем местами соседние элементы }
t:= arg[j]; { временно запоминаем }
arg[j]:= arg[j+1]; { следующий -> в текущий }
arg[j+1]:= t; { текущий -> в следующий }
end;
end;
var i: integer;
begin {--- Главная программа ---}
{ Вводим названия команд и набранные очки }
for i:=1 to CSize do begin
Write('Название команды: '); Readln(Champ[i].mName);
Write('Набранные очки: '); Readln(Champ[i].mAces);
end;
BubbleSort(Champ); { сортируем }
{ Выводим результаты }
Writeln('Итоги чемпионата:');
Writeln('Место Команда Очки');
for i:=1 to CSize do begin
Writeln(i:3,' ':3, Champ[i].mName, Champ[i].mAces:(20-Length(Champ[i].mName)) );
end;
Readln;
end.
Процедура сортировки заметно упростилась. Ещё бы! Ведь теперь мы работаем с одним массивом, а не с двумя. Для временного хранения элемента массива (при обмене) в процедуре объявлена переменная типа TTeam. А в прежнем решении для этого нужны были две переменные. Прочие изменения в программе невелики, хотя и существенны: вместо обращений к элементам массива мы обращаемся к полям этих элементов (эти места выделены).
Напомню смысл выражения для ширины поля при печати набранных очков.
20-Length(Champ[i].mName)
Здесь учет длины названия команды обеспечивает ровную печать столбцов, стоящих правее.
Дополнительное время
Надеюсь, вы оценили приятный вкус структурных данных. Так продлим удовольствие, назначив после второго тайма дополнительное время. Соорудим третью версию программы, способную воспринимать и другие данные о командах, например, количество выигрышей и проигрышей. Для хранения этих новых сведений, очевидно, нужна память, то есть переменные. Но теперь обойдёмся без дополнительных массивов: объявим внутри записи TTeam ещё пару полей.
type TTeam = record
mAces : integer; { набранные очки }
mName : string; { названия команд }
mWins : integer; { количество выигрышей }
mFails: integer; { количество проигрышей }
end;
Внутрь каждого элемента массива Champ подселены ещё два поля, осталось лишь организовать ввод и вывод этих данных. Но к процедуре сортировки BubbleSort прикасаться уже не надо, – она не изменится! Поэтому в показанной ниже программе «P_50_2» я не стал её повторять. Не стал я заниматься и обработкой поля mFails – количество проигрышей. Уверен, что вы и без меня справитесь с этим.
{ P_59_2 – Футбольный чемпионат (версия 3) }
const CSize = 4; { количество команд }
{ объявление типов }
type TTeam = record
mAces : integer; { набранные очки }
mName : string; { названия команд }
mWins : integer; { количество выигрышей }
mFails: integer; { количество проигрышей }
end;
TChamp = array [1..CSize] of TTeam; { тип для массива команд }
var Champ : TChamp; { массив команд }
{ Процедура пузырьковой сортировки не изменилась! }
procedure BubbleSort(var arg: TChamp);
...
end;
var i: integer;
begin {--- Главная программа ---}
{ Вводим названия команд, набранные очки и прочие данные }
for i:=1 to CSize do begin
Write('Название команды: '); Readln(Champ[i].mName);
Write('Набранные очки: '); Readln(Champ[i].mAces);
Write('Выигрышей: '); Readln(Champ[i].mWins);
end;
{ сортируем }
BubbleSort(Champ);
{ Выводим результаты }
Writeln('Итоги чемпионата:');
Writeln('Место Команда Очки Выигрышей');
for i:=1 to CSize do begin
Write(i:3,' ':3, Champ[i].mName,
Champ[i].mAces:(20-Length(Champ[i].mName) ));
Writeln(Champ[i].mWins:8);
end;
Readln;
end.
Напоследок отвечу на один вероятный вопрос. Поля записи объявлены мною в некотором порядке, существенно ли это? Ничуть! Поля могут объявляться в любой последовательности, – это не влияет на их обработку.
Итоги
• Для соединения разнородных, но связанных общим смыслом данных используют записи.
• Запись заключается в пару ключевых слов RECORD-END, между которыми перечисляются имена и типы полей, входящих в запись.
• На основе записей могут быть построены как одиночные переменные, так и массивы.
• Доступ к полям записей выполняется через имя переменной и имя поля, разделяемые точкой.
А слабо?
А) Дополните программу «P_50_2» с тем, чтобы обработать все поля записи.
Б) Предложите структуру записи для полицейской базы данных. Какие данные следует, по вашему мнению, включить в неё?
В) Напишите программу для полицейской базы данных с применением записей. Обеспечьте ввод данных из файла, поиск по номеру и распечатку полей найденной записи.
Г) В текстовом файле тремя колонками представлены сведения о школьниках: фамилия, рост и вес. Ваша программа должна преобразовать его в три других файла, где эти же сведения отсортированы соответственно: 1) по фамилиям, 2) по росту и 3) по весу учеников.
Д) Домино. В этой игре используют 28 костяшек, каждая из которых содержит пару чисел от 0 до 6. Например: 0:0, 1:5, 6:6. Представьте костяшку записью, а игральный набор – массивом этих записей. Заполните массив костяшек и распечатайте его. «Смешайте» костяшки случайным образом и вновь распечатайте массив. Для удобства направьте распечатку в текстовый файл.
Е) Карты. Колода содержит 36 карт четырех мастей: трефы и пики – черные, а бубны и червы – красные. Относительная сила карты определяется числом от 6 до 14. Представьте карту записью, содержащей её масть, цвет и силу. Представьте колоду массивом записей, сформируйте полную колоду и распечатайте в текстовый файл. «Перетасуйте» колоду и вновь распечатайте в файл. При распечатке силу карт от 11 до 14 напечатайте их названиями: валет, дама, король, туз.
- Только для взрослых
- Детям до 16–ти
- Глава 1 Путь далек у нас с тобою…
- Глава 2 Вместо теории
- Глава 3 Консольный интерфейс
- Глава 4 Оружие – к бою!
- Глава 5 Программа номер один
- Глава 6 Подготовка к следующему штурму
- Глава 7 Развиваем успех
- Глава 8 Постоянные и переменные
- Глава 9 Переменные: продолжение знакомства
- Глава 10 Условный оператор
- Глава 11 Операторный блок
- Глава 12 Цикл с проверкой в конце
- Глава 13 Правда и кривда
- Глава 14 Дважды два – четыре
- Глава 15 Айда в Монте-Карло!
- Глава 16 Делу время, а потехе час
- Глава 17 И вновь за парту
- Глава 18 Аз, Буки
- Глава 19 Процедуры и функции: разделяй и властвуй
- Глава 20 Процедуры: первый опыт
- Глава 21 Отладка
- Глава 22 О передаче параметров
- Глава 23 Функции
- Глава 24 Криптография
- Глава 25 Текстовые файлы
- Глава 26 Я не читатель, – я писатель!
- Глава 27 Дайте кораблю минутный отдых!
- Глава 28 Редактор и справочная система
- Глава 29 Читайте по-новому
- Глава 30 Журнальная история
- Глава 31 Финал журнальной истории
- Глава 32 Порядковые типы данных
- Глава 33 Вещественные числа
- Глава 34 Структура программы
- Глава 35 Множества
- Глава 36 Множества в Паскале
- Глава 37 Ввод и вывод множеств
- Глава 38 Множества в «бою»
- Глава 39 Командная игра (массивы)
- Глава 40 Пристрелка на знакомых мишенях
- Глава 41 По порядку, становись!
- Глава 42 Кто ищет, тот всегда найдет
- Глава 43 Сортировка по-взрослому
- Глава 44 Строки
- Глава 45 Очереди и стеки
- Глава 46 Огромные числа
- Глава 47 Системы счисления
- Глава 48 Железная логика
- Глава 49 Сложные массивы
- Глава 50 Неспортивные рекорды (записи)
- Глава 51 Указатели в море памяти
- Глава 52 Динамические переменные
- Глава 53 Массив указателей
- Глава 54 Односвязные списки
- Глава 55 Слова, слова, слова…
- Глава 56 И снова очереди, и снова стеки…
- Глава 57 Графомания
- Глава 58 По графу шагом марш!
- Глава 59 Крупные проекты
- Глава 60 Мелкие хитрости
- Глава 61 «Кубики» программиста (ООП)
- Глава 62 Самое интересное только начинается!
- Приложение А Установка и настройка IDE Borland Pascal
- Приложение Б Консольная программа в среде Delphi
- Приложение В Особенности IDE Pascal ABCNet
- Приложение Г Зарезервированные слова
- Приложение Д Ошибки компиляции
- Приложение Е Ошибки исполнения
- Приложение Ж Директивы управления компиляцией
- Приложение З Назначение пунктов меню
- Приложение И Стандартная кодировка символов MS–DOS
- Приложение К Некоторые встроенные процедуры и функции
- Приложение Л Перечень программ
- Приложение М Пример олимпиадной задачи
- Библиография
- Содержание книги
- Популярные страницы
- 2. Пример создания базового отношения в записи на псевдокоде
- 3 Учетные записи пользователей
- ГЛАВА 8 Блокировки чтения-записи
- Как из-под учетной записи пользователя (без администраторских привилегий) включать и отключать оборудование и выполнять ...
- 10.6. Гостевые учетные записи
- Практическая работа 21. Настройка учетной записи в почтовой программе
- Практическая работа 59. Создание новой учетной записи и изучение действующих разграничений доступа к файлам
- 1.11.3. Популярные записи
- Техника восстановления главной загрузочной записи
- Основные параметры новой записи
- Проект записи CD-ROM
- Листинг 10.3. Использование однонаправленного чтения-записи XML-данных для загрузки XML-документа из файла и его сохране...