Литмир - Электронная Библиотека

      for i:=1 to 30 do Readln(F, Names[i]);

Здесь F – это открытый для чтения текстовый файл, каждая строка которого содержит фамилию.

На первый взгляд все просто. Просто, да не гладко, – это будет работать лишь с файлом, в котором не менее 30 строк (по числу циклов). А иначе случится ошибка: противозаконное чтение за пределами файла. Как избежать её? Внимательней присматривайте за концом файла, вот так:

      i:=1;

      { пока не конец файла и не введены все элементы }

      while not Eof(F) and (i<=30) do begin

      Readln(F, Names[i]);

      i:= i+1;

      end;

А вот ещё один хороший вариант.

      for i:=1 to 30 do begin

      if Eof(F) then break; { если конец файла, прервать цикл }

      Readln(F, Names[i]);

      end;

Вывод массива в файл не представляет труда, вот пример.

      for i:=1 to 30 do Writeln(F, Names[i]);

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

Ошибки индексации

Объявление массива, как сказано, содержит границы для индексов: MIN – номер первого элемента, и MAX – номер последнего. А что случится при попытке обратиться к элементу с меньшим, чем MIN номером? Или наоборот – с большим, чем MAX? Иначе говоря, что случится при попытке доступа к несуществующему элементу массива? Такие ошибки преследуют даже опытных программистов, а последствия зависят от способа, которым вы совершите сей проступок.

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

      Names[200]:= ’Синичкин’;

Поскольку в массиве Names нет элемента с индексом 200, здесь вас остановит компилятор, – ошибка слишком явна, чтобы он промолчал. Вам не останется ничего иного, как исправить индекс, иначе программа не откомпилируется.

Но, когда индекс вычисляется при исполнении программы, нарушение границ проявляется и обрабатывается иначе, например:

      Readln(N);

      Writeln(Names[N]);

Нам не угадать, что введет пользователь в переменную N, – здесь ошибка нарушения границ может возникнуть при выполнении программы. В главе 27 мы рассматривали ошибки времени исполнения, – это как раз такой случай. Если указать индекс, выходящий за границы массива, то реакция программы будет зависеть от настройки компилятора, точнее, от опции контроля диапазонов. Напомню, что эта опция управляется директивой $R, а также доступна через меню по цепочке:

Options –> Compiler… –> Runtime Errors –> Range checking

Рассмотрим вариант компиляции при включенном контроле границ ($R+). Тогда, при нарушении границ индекса, программа выдаст аварийное сообщение «Range check error». То есть, она заметила нарушение границ индекса, «крикнула» об этом и прервала работу.

Теперь отключим контроль диапазонов ($R-) и перекомпилируем программу. Она станет «легче» и быстрее, и по ходу выполнения проверять границы не станет. Но ошибки не пройдут бесследно. Наоборот, последствия будут тяжелыми и непредсказуемыми! Отключать проверку диапазонов позволительно только в тщательно проверенной программе.

Лучший способ избежать нарушения границ индексов – взять проверку на себя. В данном случае это можно сделать так:

      repeat

      Readln(N);

      if N in [1..30]

      then Writeln(Names[N])

      else Writeln(’Ошибка! Введите индекс от 1 до 30’);

      until N in [1..30]

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

Итоги

• Массив – это сложный тип данных, объединяющий в себе несколько однотипных переменных – элементов массива.

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

• В объявлении массива указывают две его характеристики: диапазон индексов и тип элементов.

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

• Указание неверного индекса порождает ошибки либо при компиляции, либо при выполнении программы.

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

А слабо?

А) Массив A и переменная C объявлены так:

var A : array [’a’..’z’] of integer;

      C: char;

Допустимо ли такое объявление массива и почему? Сколько элементов содержит массив? Какие из указанных ниже операторов будут (или могут) вызывать ошибки нарушения диапазонов?

      A[’s’]:= 10;

      A[’R’]:= 10;

      C:=’d’; A[C]:= 10;

      Readln(C); A[C]:= 10;

Проверьте свои решения на практике.

Глава 40

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

Песни о Паскале (СИ) - _132.jpg

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

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

В 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;       { строка с вопросом }

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

procedure ReadFromFile(var aFile: text);

var i: integer;

begin

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

64
{"b":"596178","o":1}