Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
delphi / песни о паскале.pdf
Скачиваний:
66
Добавлен:
26.03.2016
Размер:
5.16 Mб
Скачать

Глава 40 Пристрелка на знакомых мишенях

Итак, из арсенала Паскаля мы извлекли ещё одно мощное оружие — массивы. Опробуем его на знакомых мишенях, — некоторые наши программы можно улучшить, например, программу «вопрос-ответ» или полицейскую базу данных.

Вопрос-ответ – добиваемся гибкости

В 16-й главе мы смастерили шуточную программку, невпопад отвечающую на вопросы пользователей. Жаль только, что ответы намертво вбиты в саму программу. Скоро пользователям надоест смеяться над одним и тем же, и они забросят игрушку. Так пусть ваши приятели сами сочиняют смешные ответы и помещают их в текстовый файл, и тогда программа при запуске будет загружать их оттуда.

Прежде всего, подумаем над размещением вводимых из файла строк, где поселить их? «В массиве строк», — скажете, и будете правы. А сколько элементов запасти в этом массиве? Чем больше, тем лучше? Некоторые компиляторы накладывают ограничение на размер массива, но сотню строк они позволят, и этого пока достаточно. Итак, для хранения ответов объявим массив из 100 строковых переменных.

Перейдем к процедуре ввода этих строк. Техника ввода массива рассмотрена в предыдущей главе. Но теперь надо ещё и подсчитать введенные строки, иначе в дальнейшем мы не всегда сможем правильно индексировать массив, — ведь фактическое количество строк в файле может быть и меньше ста. С этой целью объявим переменную Fact, в которой и сделаем нужный нам подсчёт.

Обсудив эти моменты, обратимся к программе P_40_1.

{ P_40_1 – Программа "вопрос-ответ" с применением массива }

const CAnswers = 100; { размер массива с ответами } { объявление типа для массива ответов }

type TAnswers = array[1..CAnswers] of string;

var Answers : TAnswers;

{ объявление массива ответов }

Fact : integer;

{ фактическое количество ответов }

F : text;

{ файл с ответами }

S : string;

{ строка с вопросом }

288

Глава 40

Пристрелка на знакомых мишенях

{Процедура ввода ответов из файла с подсчетом введенных строк } procedure ReadFromFile(var aFile: text);

var i: integer; begin

Fact:=0; { для начала подсчета строк обнуляем счетчик }

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

for i:=1 to CAnswers do begin if Eof(aFile) then Break; Readln(aFile, Answers[i]); Fact:= Fact+1;

end;

end;

{если конец файла – выход}

{читаем строку в элемент массива }

{наращиваем счетчик строк }

begin

{--- Главная программа ---}

 

Assign(F, 'P_40_1.in');

Reset(F);

 

ReadFromFile(F); Close(F);

 

Randomize; { чтобы порядок вопросов не повторялся }

 

{ Начало главного цикла }

 

repeat

 

 

Write('Введите вопрос: '); Readln(S);

 

if S<>'' then

Writeln(Answers[Random(Fact)+1]);

end.

until S='';

 

 

 

Открыв файл «P_40_1.IN», мы вызываем процедуру ReadFromFile (читать из файла), которая загружает строки в массив Answers (ответы). Она же подсчитывает введенные строки в переменной Fact. Таким образом, если файл содержит больше сотни строк, то в массив попадёт первая сотня, а иначе — столько, сколько там есть фактически, и это количество покажет переменная Fact. Дальше всё работает, как в прежнем варианте: после ввода вопроса ответ случайным образом выбирается из массива. Индекс элемента с ответом определяется выражением Random(Fact)+1. Если помните, функция Random(Fact) возвращает значения в диапазоне от 0 до Fact-1, а индексы нашего массива начинаются с единицы.

Полицейская база данных – ускоряем поиск

А теперь освежите в памяти другое наше творение — программу поиска угнанных автомобилей в полицейской базе данных (глава 29). Её слабость в том, что поиск номеров выполняется в текстовом файле. Ах, если б вы знали, как «тормозит» такой поиск! Вы не заметили? Да, на десятках строк этого не ощутить, иное дело — сотни тысяч, или миллионы. Итак, перенесем список номеров из текстового файла в массив, и тогда поиск ускорится многократно!

289

Глава 40

Пристрелка на знакомых мишенях

В программе P_40_2 обратите внимание на пропуск пустых строк в процедуре ReadFromFile. Если этого не сделать, счётчик Fact может оказаться на 1 больше, чем должно, — так случится, если за последним числом будут пустые строки. Следующий далее оператор чтения числа пренебрегает границами между строками, поэтому в одной строке допустимы несколько чисел.

{ P_40_2 – Полицейская база данных с применением массива }

const CNumbers = 1000; { размер массива с номерами автомобилей }

 

{ объявление типа для массива номеров }

type

TNumbers = array[1..CNumbers] of integer;

var

Numbers : TNumbers;

{ объявление массива номеров }

 

Fact : integer;

{ фактическое количество номеров в файле }

 

F : text;

{ файл с номерами }

 

Num : integer;

{ номер проверяемого автомобиля }

{ Процедура ввода номеров из файла }

procedure ReadFromFile(var aFile: text); var i: integer;

begin

Fact:=0; { для начала подсчета

номеров обнуляем счетчик }

for i:=1 to CNumbers do begin { цикл по массиву номеров }

while Eoln(aFile) do

{ Пропуск пустых строк }

if Eof(aFile) then Break else Readln(aFile);

if Eof(aFile) then Break;

{ если конец файла - выход из цикла }

Read(aFile, Numbers[i]);

{ читаем номер в элемент массива }

Fact:= Fact+1;

{ наращиваем счетчик номеров }

end;

 

 

end;

{ Функция поиска в массиве номеров автомобилей } function FindNumber(aNum: integer): boolean;

var i: integer; begin

FindNumber:= false;

 

for i:=1 to Fact do

 

if aNum=Numbers[i] then begin

 

FindNumber:= true;

{ нашли ! }

Break;

{ выход из цикла }

end

 

end;

290

Глава 40

Пристрелка на знакомых мишенях

begin

{--- Главная программа ---}

 

{ открываем файл и читаем номера автомобилей }

 

Assign(F, 'P_38_2.in');

Reset(F);

 

ReadFromFile(F);

{ ввод номеров из файла }

 

Close(F);

 

repeat

{ Главный цикл }

 

Write('Укажите номер автомобиля: ');

Readln(Num);

if FindNumber(Num)

 

 

then Writeln('Эта машина в розыске, хватайте его!')

else Writeln('Пропустите его');

until Num=0; { 0 – признак завершения программы}

end.

Ещё раз о статистике

Следующая программка будет маленькой, да удаленькой. Вернемся к статистике, с которой познакомились при обработке классного журнала. Напомню, что статистика — это наука, изучающая массовые явления. В текстах наших программ полным-полно разных букв, — давайте посчитаем их. Результатом работы программы будет таблица, похожая на эту:

a119

b45

c72

. . .

Здесь левый столбец составляют буквы, а правый — количество этих букв в некотором файле. Упростим себе задачу, ограничившись подсчетом лишь маленьких латинских букв от «a» до «z».

Для подсчета общего количества символов в файле хватило бы одного счетчика. Но здесь 26 букв, а значит и счетчиков надо столько же. Массив счетчиков напрашивается сам собой, его тип можно объявить так:

type TCounts = array [1..26] of integer;

Однако не спешите этого делать. Вспомните о том, что индексом массива может быть любой порядковый тип данных. А к ним, наряду с числами, относятся символьный и даже булев тип. Стало быть, допустимы такие массивы:

291

Глава 40

Пристрелка на знакомых мишенях

type TA = array ['A'..'F'] of integer;

TB = array [false..true] of integer;

Первый из них содержит 6 элементов, а индексируется символьным выражением. Второй содержит всего два элемента, индексы которого имеют булев тип. В решаемой задаче напрашивается символьная индексация, а потому объявим тип для массива счетчиков так:

type TCounts = array ['a'..'z'] of integer;

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

Входным файлом программы будет текст её самой же. Вот она, простая и красивая:

{P_40_3 – Подсчет количества различных букв в файле }

{Тип массива из целых чисел, индекс – символьный } type TCounts = array ['a'..'z'] of integer;

var

Counts : TCounts; { массив из счетчиков букв }

 

c: char;

{ текущий символ файла, он же – индекс счетчика }

 

F : text;

{ файл с текстом программы }

begin

{--- главная программа ---}

{Перед началом подсчета все счетчики обнуляем } for c:='a' to 'z' do Counts[c]:=0;

{Открываем входной файл для чтения }

Assign(F,

'P_40_3.pas');

Reset(F);

while not

Eof(F) do begin

{ Цикл чтения и подсчета букв }

Read(F,

c);

{ чтение одного символа из файла }

if c in

['a'..'z']

{ если символ в нужном диапазоне }

then Counts[c]:= Counts[c]+1; { наращиваем его счетчик } end;

Close(F);

{ После подсчета распечатаем все счетчики } for c:='a' to 'z' do Writeln (c, Counts[c]:6); Write('Нажмите Enter'); Readln;

end.

Здесь осталась лишь одна шероховатость — при печати результатов часть строк не поместится на экране. Так направьте вывод в текстовый файл. Или слабо?

292

Соседние файлы в папке delphi