Обработка двумерных массивов
⇐ ПредыдущаяСтр 11 из 11 Двумерные массивы имеют аналогию с таким понятием в математике как матрица. В языке Турбо-Паскаль двумерный массив - это массив, элементами которого являются одномерные массивы: b: array[1..n] of array[1..m] of integer; С другой стороны двумерный массив можно описать и так: b: array[1..n,1..m] of integer; Чаще пользуются вторым описанием, оно является более кратким, но менее наглядным. В описании n – количество строк, m – количество столбцов матрицы. При изменении второго индекса на единицу мы передвигаемся вдоль строки, а при изменении первого индекса на единицу передвигаемся вертикально вдоль столбца. Обычно в качестве идентификатора номера строки используют символ i, а столбца – j. Тогда к элементу массива, описанному выше, можно обратиться по имени b[i,j]. Ниже приведены примеры описания двумерных массивов и обращения к элементам: type massiv1=array[1..n] of real; massiv2=array[1..5,1..6] of integer; var f:array[1..10] of massiv1; mas:array[0..10,1..30] of char; b:massiv2; asd:array[1..20,1..10] of byte; begin .............. f[i,j]:=13.13; mas[0,1]:='a'; b[5,6]:=7; asd[i,8]:=0; ............... ПримерЫ обработки двумерных массивов
При обработке двумерных массивов возникают такие же задачи, как и при обработке одномерных массивов: ввод элементов массива, нахождение суммы, произведения, среднего и т.д., поиск некоторого элемента в массиве, сортировка элементов массива, вывод элементов массива. На рис.17 приведена схема алгоритма формирования элементов массива с помощью датчика случайных чисел, вывод элементов массива на экран, вычисление суммы всех элементов двумерного массива. Программа дана в примере pr21. program pr21; 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; Рис. 17 for i:=1 to n do for j:=1 to m do a[i,j]:=random(10); 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 в теле цикла выполняются два оператора: первый оператор цикла выводит на экран в строчку элементы одной строки, а второй оператор вывода переводит курсор на новую строку, что как раз и обеспечивает вывод матрицы в виде прямоугольника. Следующий пример иллюстрирует работу с диагоналями матрицы. Дана квадратная матрица. Заменить отрицательные элементы побочной диагонали на сумму элементов главной диагонали матрицы. При изучении поставленной задачи следует напомнить, что главная диагональ проходит из правого верхнего в левый нижний угол. Так как мы работаем с квадратной матрицей, то только на главной диагонали будут лежать элементы, индексы строк и столбцов которых одинаковы. Именно этот факт и используется при решении задачи. Мы не будем перебирать все элементы массива и смотреть, совпали ли индексы, а сразу задаем оба индекса с помощью одного идентификатора i. Побочная диагональ проходит из правого верхнего в левый нижний угол матрицы. Нетрудно заметить, что при движении по побочной диагонали номер строки возрастает от 1 до n, номер столбца убывает от n до 1. Таким образом, только на побочной диагонали лежат элементы, у которых номер столбца определяется по формуле j=n-i+1. Программа приведена в примере pr22, а графическая схема алгоритма – на рис.18.
program pr22; 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 {Сумма элементов главной диагонали } 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; Рис. 18 writeln('Полученный массив'); for i:=1 to n do begin for j:=1 to n do write (a[i,j]:5); writeln; end; end. И последний пример на обработку двумерных массивов. Дана прямоугольная матрица. Отсортировать столбцы матрицы в порядке неубывания максимальных элементов столбцов. Решение задачи сводится к формированию одномерного массива из максимальных элементов столбцов, а уж затем сортируется этот одномерный массив и параллельно – столбцы матрицы. Чтобы не запутать читателя, в этой задаче используем знакомый метод сортировки "пузырьком". Исходный массив имеет идентификатор a, а промежуточный одномерный массив – b. Графическая схема алгоритма приведена на рис.19, а программа – в примере pr23. program pr23; 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; Рис. 19
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аем все столбцы} 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; {Сортировка одномерного и двумерного массива} 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; end. В этой программе можно обойтись без дополнительного массива, но тогда пришлось бы во время сортировки массива каждый раз искать максимальный элемент столбца, даже если максимальный в этом столбце мы уже находили.
MНОЖЕСТВА
Множество в математике – это произвольный набор объектов природы, понимаемый как единое целое [3]. На вид объектов и их количество не накладываются никакие ограничения. Понятие «множество» в языке программирования Турбо-Паскаль несколько уже, чем традиционное математическое понятие. В Турбо-Паскале множества – это набоpы однотипных объектов, каким-либо обpазом связанных дpуг с дpугом. Хаpактеp связей между объектами подpазумевается пpогpаммистом и никак не контpолиpуется Турбо-Паскалем. Максимальное количество объектов в множестве – 256. Множество отличается от массива пеpеменностью количества своих элементов и произвольным порядком следования элементов. Последнее означает, что за каждым элементом множества не закреплено строго определенное место, как это происходит с элементами массива. Определение множества в программе производится в два этапа. Сначала определяется базовый для него тип, а затем с помощью оборота set of – само множество. Приведем несколько примеров описания, инициализации и операций с множествами в следующем фрагменте программы: type digch='0'..'9'; digitch = set of digch; dig= 0..9; digit = set of dig; sport=(football,hockey,tennis,rugby); hobby=set of sport; var s1,s2,s3:digitch; s4,s5,s6:digit; hobby1:hobby; begin s1:=['1','2','3']; s2:=['3','2','1']; s3:=['2','3']; s4:=[0..3,6]; s5:=[4,4]; s6:=[3..9];
hobby1:=[football,hockey,tennis,rugby]; if tennis in hobby1 then writeln('Теннис!'); end. В Турбо-Паскале имеется стандартный тип множества set of char. В него могут входить символы, имеющиеся на клавиатуре. Объявляя такое множество, базовый тип char объявлять не надо. Базовый тип – любой поpядковый тип, кpоме word, integer, longint. Все значения базового типа, обpазующие конкpетные значения множественного типа, должны быть pазличны. Множество, не содержащее элементов, называется пустым. Поpядок "pасположения" элементов в множестве никак не фиксиpуется.Это соответствует пpинятой в математике тpактовке множества как безповтоpной неупоpядоченной совокупности объектов. Над множествами можно выполнять следующие опеpации [2]: * пеpесечение множеств; pезультат содеpжит элементы,общие для обоих множеств (например, s4*s6 дает [3], s4*s5 - пустое множество); + объединение множеств; pезультат содеpжит элементы пеpвого множества, дополненное недостающими элементами втоpого множества (например, s4+s5 - [0,1,2,3,4,5,6]); - pазность множеств; pезультат содеpжит элементы из пеpвого множества, котоpые не пpинадлежат втоpому; (например, s6-s5 - [3,6,7,8,9]); = пpовеpка эквивалентности; true, если два множества эквивалентны; <> пpовеpка неэквивалентности; true, если два множества неэквивалентны; <= пpовеpка вхождения; true, если пеpвое множество включено во втоpое; >= пpовеpка вхождения; true, если втоpое множество включено в пеpвое; in пpовеpка пpинадлежности; true, если выpажение имеет значение, пpинадлежащее множеству. 3 in s6 – true. Если необходимо пpовеpить, является ли буква гласной, то это можно сделать с помощью следующей конструкции: if ch in ['a','o','e','у','я','ю','э','и'] then.... В седьмой версии Турбо-Паскаля введены две стандартные процедуры для замены операций объединения и разности множеств: include и exclude. Эти процедуры выглядят так: include (var s: set of t; elem:t); exclude (var s: set of t; elem:t); Здесь t – любой тип, который может являться базовым для множества. Первая из этих процедур добавляет значение своего второго параметра в множество, заданное первым параметром. Вторая процедура удаляет значение второго параметра из членов множества, указанного в первом параметре. Эти процедуры гораздо эффективнее, чем операции операции добавления и разности множеств, так они компилируются особым образом. Следующий пример программы демонстрирует использование множеств для вычисление нескольких пpостых чисел методом "pешета Эpатосфена": program pr24; const n = 250; { максимальное количество чисел} type base = 2..n; var ish, { исходное множество} rez: set of base;{ pезультат – множество простых чисел} next: byte; {pабочие пеpеменные} j: word; begin {инициализация} ish:=[2..n]; rez:=[ ]; {пустое}
next:=2; repeat {поиск очеpедного пpостого числа} while not(next in ish) do {поиск в ish наименьшего числа} next:=next+1; include(rez,next); {помещаем его в rez} j:=next; while j<=n do begin {удаление из ish всех чисел, кpатных next} exclude(ish,j); j:=j+next; {поиск очеpедного кpатного next} end; until ish=[]; for j:=2 to n do {вывод множества пpостых чисел} if j in rez then write(j:5); end. СТРОКИ СИМВОЛОВ
Строкового типа в стандартном Паскале нет, поэтому там использовали символьные массивы при работе со строками символов. Символьные строки представляют один из наиболее полезных и важных типов данных. Для определения строкового типа в Турбо-Паскале используется ключевое слово string, вслед за которым в квадратных скобках указывается максимальная длина строки, например: type line = string[80]; var line1,line2: line; Переменная line1 в качестве своего значения может иметь любую последовательность символов произвольной длины (в пределах от нуля до 80). Значение строковой переменной может быть присвоено с помощью оператора присваивания или процедуры ввода: line1:='программирование'; readln(line2); Если указание длины строки опущено, то длина строки по умолчанию является максимально возможной и равна 255 символов. Важнейшим отличием строк от символьного массива является то, что строки могут динамически менять свою длину. При этом необходимо помнить, что память выделяется по максимуму. Самый первый байт в строке имеет индекс 0 и содержит текущую длину строки. Для строк символов определена операция конкатенация, обозначаемая символом '+', смысл которой заключается в формировании новой символьной строки, значением которой будут строки-операнды, расположенные последовательно друг за другом. Например: line1:=line1+'-экзамен'; При выводе line1 получим строку: пpогpаммиpование-экзамен. Кроме операции конкатенации, над значениями строкового типа определены операции сравнения с обычным смыслом: < <= > >= = <> при выполнении которых действуют следующие правила: более короткая строка всегда меньше длинной; а если длины сравниваемых строк равны, то происходит поэлементное сравнение символов этих строк с учетом лексикографической упорядоченности значений стандартного символьного типа char. Доступ к отдельным элементам строк производится аналогично доступу к элементам одномерного массива: после имени строковой переменной необходимо в квадратных скобках указать выражение целого типа, обозначающее номер элемента строки. Данная конструкция имеет тип char и является переменной, т.е. может находиться в левой части оператора присваивания: line[1]='П' или if line[i] in ['a'..'z'] then k:k+1; Рассмотрим пример пpогpаммы, опpеделяющей количество знаков пpепинания в пpоизвольной стpоке символов:
program pr25; var str: string; i, k: integer;{Количество знаков пpепинания} begin writeln('Введите стpоку символов:'); read (str); for i:=1 to length(str) do {length(str)определяет длину текущей строки} if str[i] in [':','.',',','"','!','?',';'] then k:=k+1; writeln('k=',k); end. Распространенной ошибкой при работе со строками является работа с элементами строки без учета её текущей длины. Следующая программа будет формировать строку из 26 символов, представляющих последовательность заглавных букв латинского алфавита: program pr27; var str: string[26]; i:integer; begin str:=''; for i:=1 to 26 do str:=str+chr(ord('A')+i-1); writeln(str); end. В Турбо-Паскале имеются встроенные функции и процедуры для обработки строк: concat(str1[,str2,...,strn]) - функция, возвращающая строку, представляющую собой сцепление строк параметров str1,str2,...,strn; copy(str,i,c) - функция, возвращающая строку, которая копируется из строки str, начиная с символа i длиной с символов; delete(str,i,c) - процедура, удаляющая из строки str с символов, начиная с символа с номером i; insert(subsrt,str,i) - процедура, вставляющая подстроку substr в строку str, начиная с символа с номером i; pos(substr,str) - функция, возвращающая номер позиции в строке str, начиная с которой подстрока substr входит в строку str; если подстрока не найдена, возвращается нуль. Здесь представлены наиболее часто используемые функции. Приведем пример программы, опpеделяющей количество символов и слов в пpоизвольной стpоке символов [4]. program pr28; const YES=1; {Константы, опpеделяющие является ли } NO=0; { текущий символ элементом слова} var str: string; nw, {Количество слов} nc, {Количество символов} inword: integer; {Пеpеменная, пpинимающая значения констант YES или NO} i: integer; begin writeln('Введите стpоку символов:'); read (str); nw:=0;nc:=0;inword:=NO; for i:=1 to length(str) do begin nc:=nc+1; if str[i] in [':','.',',','"','!','?',';',' ']{Если pазделитель,} then inword:=NO {то текущий символ вне слова} else if inword=NO then begin inword:=YES; nw:=nw+1; end; end; writeln ('nc=',nc,'nw=',nw); end. В Турбо-Паскале 7.0 появился новый тип данных - строки, заканчивающиеся нулевым символом (#0), или, как их ещё называют, ASCIIZ-строки. В таких строках можно размещать до 65535 любых символов, кроме нулевого. Реализация механизма ASCIIZ-строк состоит из двух компонентов: во-первых введен новый предопределенный тип Pchar, а также некоторые синтаксические допущения, связанные с этим типом, и, во-вторых, в систему стандартных модулей добавлен модуль String, в котором содержится пакет разнообразных функций для работы с этими строками. Подробно работа с такими строками в этом пособии не рассматривается.
ЗАПИСИ
Запись – это структура данных, состоящая из фиксированного числа компонентов, называемых полями записи. Очень часто возникает необходимость описать характеристики некоторого объекта, представляемого и обрабатываемого в программе. Таким объектом может быть человек, автомобиль, журнал и т.д. В отличие от массива, компоненты (поля) записи могут быть различного типа. Для описания объекта "автомобиль" могут понадобится, например, следующие характеристики: * марка и тип кузова автомобиля (символьные строки); * год выпуска автомобиля (целый тип); * был ли капитальный ремонт (логический тип). Чтобы можно было ссылаться на то или иное поле записи, поля именуются. Структура объявления типа записи: < имя типа > = record < сп. полей > end; здесь < имя типа > – правильный идентификатор; record, end – ключевые слова (пер. с англ.: запись, конец); < сп. полей > – список полей, представляет собой последовательность разделов записи, между которыми ставится точка с запятой. Каждый раздел записи состоит из одного или нескольких идентификаторов, отделяемых друг от друга запятыми. За идентификатором (идентификаторами) ставится двоеточие и тип, например: type auto = record mark, typ: string [10]; date: integer; remont: boolean end; Как элементы массива, так и поля записи можно использовать в качестве отдельных переменных. К каждому компоненту можно обратиться, если указать имя переменной типа record, затем точку и имя поля. Используя описанный выше тип, напишем фрагмент программы: var mashine: auto; begin mashine.mark: = 'volvo'; mashine.date = 1996; mashine.typ: = 'car'; mashine.remont: = false; writeln (mashine. mark); writeln (mashine. date); writeln (mashine.typ); writeln (mashine. remont); end. Каждое поле записи можно рассматривать как обычную переменную, которую можно напечатать или использовать в расчетах. Вместе с тем запись можно использовать как единое целое. Предположим, что имеется описание типа auto, аналогичное вышеприведенному, а в разделе переменных: var mash1, mash2: auto; Это означает, что переменная mash1 содержит поля mark, typ, date, remont, точно такие же поля содержит и переменная mash2. Следующий оператор присваивания устанавливает равенство значений записей mash1 и mash2: mash1:=mash2; Это присваивание эквивалентно последовательности операторов: mash1.mark:= mash2.mark; mash1.date:= mash2.date; mash1.typ:= mash2.typ; mash1.remont:= mash2.remont; Для переменных одного типа можно проверить выполнение отношения равенства или неравенства. Как и в случае массивов, допустимы операции сравнения = и <>. Язык Турбо-Паскаль дает возможность сократить запись, если использовать оператор присоединения with. Структура оператора with: with < сп. записей > do < оператор >, где with, do - ключевые слова (пер. с англ. с, делать), < сп. записей > – список из одной или нескольких переменных типа запись, разделенных запятыми. < оператор > - любой оператор языка турбо-паскаля. В рамках оператора, определяемого внутри оператора with (или составного оператора), к полям переменной можно обращаться просто по имени: with mashine do begin mark: = 'volvo'; date: = 1996; typ: = 'car'; remont: = false; end; В рамках составного оператора, следующего за with, каждое обращение к имени поля автоматически связывается с записью mashine. Оператор with позволяет более компактно представлять часто используемые переменные. Так как на тип компонентов массива не накладывается ограничений, то можно образовать массив, компонентами которого являются записи. Приведем описание такого массива: var mashine: array [1..100] of auto; Принимая во внимание предыдущее описание auto, можно сделать вывод, что описана таблица, в которой могут содержаться данные на 100 автомобилей.
Теперь можно записать следующие операторы: для обращения к первому элементу массива: mashine [1].mark:= 'ваз'; для чтения первого элемента: read (mashine [1].mark); Как и в массиве, значения переменных и констант типа record можно присваивать другим переменным такого же типа: mashine[1]:=mashine[2]; Поле записи само может быть записью.В примере записи auto введем дату приобретения автомобиля. type auto = record mark, typ: string[10]; date1: record den: integer; mes: string[10]; god: integer; end; date: integer; remont: boolean end; var mashine: auto; При обращении к полю god необходимо продолжать уточнения: mashine.date1.god: = 1949; В этом случае можно использовать оператор with следующим образом: with mashine.date1 do if god = 1944 then begin..... Рассмотрим пример программы с использованием массива структур. В ведомости, содержащей фамилии группы студентов, оценки по физике, математике и программированию определить средний балл каждого студента и средний балл в группе. В программе использованы следующие обозначения: n1 – максимальное количество студентов в группе; n – реальное количество студентов в группе; student – идентификатор типа, представляющий запись с полями fam, fiz, mat, pr и ss; fam – поле записи, содержащее фамилию студента; fiz, mat, pr – поле записи, содержащее оценки по физике, математике и программированию соответственно; ss – поле записи, содержащее средний балл студента; ved – массив, содержащий элементы типа student; sg – средний балл группы; i – индекс элемента массива ved; Программа выглядит следующим образом: program pr29; 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; {вычисление среднего балла студента} 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; army2: string[20]); female: (flower: srting[20]); end; Следует отметить, что вариантная часть всегда располагается после фиксированной части, а отводимая память вычисляется по самому большому варианту, т.е. различные варианты одной записи как бы "накладываются" друг на друга.
ФАЙЛЫ
Под файлом понимается именованная область внешней памяти или логическое устройство – потенциальный источник или приемник информации[2]. Основное отличие внешней памяти ЭВМ от оперативной памяти - возможность сохранения информации при отключении ЭВМ. Информация сохраняется в виде файлов, доступ к которым поддерживает операционная система ЭВМ. Поддержка операционной системы состоит в том, что в ней имеются средства: * создания файлов; * уничтожения файлов; * поиска файлов на внешнем носителе; * чтения и записи из файлов и в файлы; * открытия файлов; * закрытия файлов; * позиционирования файлов. Любой сколько-нибудь развитый язык программирования должен содержать средства для организации хранения информации на внешних запоминающих устройствах и доступа к этой информации. Рассматриваемый здесь язык не лишен такой возможности. Любой файл в Турбо-Паскале имеет три характерные особенности: 1) у файла есть имя, это дает возможность работать с несколькими файлами одновременно; 2) содержит компоненты одного типа (типом может быть любой тип, кроме файлового); 3) длина вновь создаваемого файла никак не ограничена при объявлении и ограничивается лишь емкостью внешних устройств памяти. Обращение к файлу производится через файловую переменную, которую можно описать следующим образом: type < имя > = file of < тип >; < имя > = text; < имя > = file; где < имя > – имя файлового типа или файловой переменной (правильный идентификатор); file, of, text – ключевые слова (пер.с англ.: файл, из, текст); < тип > – любой тип языка Турбо-Паскаль, кроме файлового. Например, можно привести такие описания: type student = record mark:string(10); fiz,mat,pr: integer; end; text1 = file of string[80]; var f1: file of char; f2: text; f4: text1; f3: file of student; f6: file; В зависимости от способа описания можно выделить текстовые (text) файлы, двоичные или типизированные (file of) и нетипизированные (file). Вид файла определяет способ хранения информации в файле. Текстовый файл является файлом последовательного доступа, и его можно представить как набор строк произвольной длины. Логически последовательный файл можно представить как именованную цепочку байтов, имеющую начало и конец. Последовательный файл отличается от файлов с другой организацией тем, что чтение (или запись) из файла (в файл) ведутся байт за байтом от начала к концу. Cначала рассмотрим текстовые файлы. Каждой программе доступны два стандартных файла input (клавиатура) и output (экран). Это - текстовые файлы. Любые другие файлы становятся доступными после выполнения специальных процедур. Рассмотрим основные процедуры для работы с текстовыми файлами. Связывание файловой переменной с именем файла осуществляется с помощью встроенной процедуры assign: assign(<ф.п.>,<имя файла или лог.уст-во>) Здесь <ф.п.> – правильный идентификатор, объявленный в программе как переменная файлового типа; <имя файла или лог. уст-ва> – текстовое выражение, содержащее имя файла или логического устройства. Если имя файла задается в виде пустой строки, например assign(f,''), то файловая переменная связывается со стандартным файлом input или output. Процедура открытия файла по чтению: reset (<ф.п.>); reset – ключевое слово (пер. с англ.: устанавливать); <ф.п.> – файловая переменная. При выполнении этой процедуры файл подготавливается к чтению: внутренняя переменная, её называют указатель файла, устанавливается на начало файла, т.е. на его первую компоненту. Процедура открытия файла по записи: rewrite(<ф.п.>); При выполнении процедуры rewrite файл подготавливается к записи информации в начало файла. Процедура очищает файл (т.е. если в файле уже была информации, то она будет потеряна) и устанавливает указатель файла на первую компоненту. Для чтения и записи информации из файла или в файл используются известные процедуры: read, readln и write, writeln в которых в качестве первого параметра выступает файловая переменная. Например: write(f,x1,x2,x3) – процедура записи в файл f компонентов x1,x2,x3. Процедура записывает выражения х1, х2, х3 по одному в файл f, начиная с того места, куда был установлен указатель файла в момент обращения к процедуре write. Аналогично работают остальные процедуры ввода и вывода. При заполнении файла после последней записи автоматически помещается специальный невидимый признак "конец файла" (end of file). Существует функция eof(f), тестирующая конец файла, связанного с файловой переменной f. Функция eof(f) возвращает значение true, если действительно встретился признак конец файла; пока это не произойдет значение eof(f) будет false. Функция eoln(f) тестирует, встретился ли конец строки (end of line) в файле, связанном с файловой переменной f. При заполнении строки после последней записи автоматически помещается специальный признак конец строки. Функция eoln(f) возвращает значение true, если действительно встретился признак " конец строки". Этот признак формируется при нажатии клавиши "ввод". close(f) – процедура закрытия файла, связанного с файловой переменной f. Функции процедуры close выполняются автоматически по отношению ко всем открытым файлам при нормальном завершении программы. Процедура append(f) инициирует запись в ранее существовавший текстовый файл, связанный с файловой переменной f, для добавления новых строк в конец файла. Рассмотрим пример. В произвольной непустой последовательности чисел, хранящейся в текстовом файле f, подсчитать количество положительных компонент. {В текстовом файле хранятся вещественные числа, разделенные пробелами.} program pr30; var f:text;{Файловая пеpеменная} a:real;{Буфеpная пеpеменная} k:integer;{Количество положительных компонент} begin assign(f,'f.dat'); reset(f); {Откpыть файл по чтению} while not eof(f) do {Пока не конец файла} begin read(f,a);{Читаем число из файла} if a>0 then k:=k+1; {Вычисляем количество положительных компонент} if eoln(f) then readln(f);{Если конец стpоки, то пеpеводим указатель файла на следующую стpоку } end; writeln('k=',k); end. Следующая программа работает с двумя текстовыми файлами: один из них открывается по чтению, а другой - по записи. Строки первого файла кодируются путем замены кода символа следующим кодом из таблицы ASCII и записываются во второй файл [5]. program pr31; var oldf,newf:text;{Файловые пеpеменные для стаpого и нового файлов} oldn,newn:string;{Стpоковые пеpеменные, для хранения имен нового и стаpого файлов} line:string;{Буфеpная пеpеменная для хpанения кодиpуемой стpоки} c:integer;{Пеpеменная цикла} begin writeln('Введите имя кодиpуемого файла'); readln(oldn); writeln('Введите новое имя'); readln(newn); assign(oldf,oldn); assign(newf,newn); reset(oldf); {Откpыть стаpый файл по чтению} rewrite(newf); {Откpыть новый файл по записи} while not eof(oldf) do begin readln(oldf,line);{Читаем стpоку из стаpого файла} for c:=1 to length(line) do {Кодиpуем стpоку} if ord(line[c])=255 then line[c]:=chr(0) else line[c]:=succ(line[c]); writeln(newf,line); {Закодиpованную стpоку пишем в файл} end; close(newf) end. Следующий пример демонстрирует работу с текстовыми файлами, содержащими данные типа record. В непустом текстовом файле хранятся данные о группе студентов: фамилии, оценки по физике, математике, программированию. Подсчитать средний балл группы и определить фамилию cтудента с максимальным средним баллом. Когда в файле хранятся данные типа record, следует оговорить его структуру. В приведенном ниже примере в каждой строке хранится фамилия одного студента и три его оценки; при этом под фамилию отводится не более 10 позиций (если фамилия короче, то дополняется пробелами), а оценки отделяются друг от друга пробелами. Текст программы предлагается в примере pr32. program pr32; type student = record fam:string[10]; fiz,mat,prog:byte; end; var ved: student;{Буфеpная пеpеменная для хpанения данных о студенте} k:integer;{Количество студентов в гpуппе} ss,{Сpедний балл каждого студента} sg,{Сpедний балл гpуппы судентов} max:real;{Максимальный сpедний балл студента} f4:text;{Файловая пеpеменная} maxfam:string[10];{Фамилия студента с максимальным сpедним баллом} begin assign (f4,'f4.dat'); reset (f4);{Откpыть файл по чтению} sg:=0;k:=0;max:=0; while not eof (f4) do {Пока не конец файла} with ved do begin read (f4,fam); {Чтение файла} readln (f4,fiz,mat,prog); ss:=(fiz+mat+prog)/3; {Вычисляем сpедний балл каждого студента} if ss>max then {Опpеделяем фамилию студента} begin { с максимальным сpедним баллом} max:=ss; maxfam:=fam; end; sg:=sg+ss; k:=k+1 end; sg:=sg/k; writeln('Сpедний балл в гpуппе=',sg); writeln('Максимальный сpедний балл у студента', maxfam) end. Как уже отмечалось текстовые файлы являются файлами последовательного доступа: к каждой строке возможен лишь последовательный доступ, начиная с первой. Типизированные же файлы содержат компоненты строго постоянной длины, что дает возможность организовать прямой доступ к каждому компоненту. Для этой цели служит встроенная процедура seek: seek(<ф.п.>,<n компонента>) Здесь <n компонента> – выражение типа longint, указывающее номер компонента. Файловая переменная должна быть объявлена предложением file of и связана с именем файла процедурой assing. Файл необходимо открыть процедурой rewrite или reset. Для чтения и записи в типизированный файл используются известные процедуры read и write. Специфика использования двух последних процедур при работе с типизированными файлами состоит в том, что список ввода содержит одну или несколько переменных такого же типа, что и компонент файла, а список вывода – одно или несколько выражений такого же типа, что и компонент файла. Функция filesize возвращает значение типа longint, содержащее количество компонентов файла: filesize(<ф.п.>) Функция filepos возвращает значение типа longint, содержащее порядковый номер того компонента файла, который будет обрабатываться следующей операцией ввода-вывода: filepos(<ф.п.>) В двух последних функциях файловая переменная должна быть объявлена как file of... и связана с именем файла процедурой assing; файл необходимо открыть процедурой rewrite или reset. Первый компонент типизированного файла имеет порядковый номер 0. Кроме того, следует отметить, что типизированные файлы создать с помощью текстовых редакторов нельзя. Типизированные файлы создаются только в процессе работы программы. Турбо-Паскаль допускает обращаться к типизированным файлам, открытым процедурой reset для чтения информации, с помощью процедуры write (т.е. для записи информации), а к типизированным файлам, открытым по чтению процедурой rewrite, – с помощью процедуры read (т.е. для чтения информации). Для примера работы с типизированными файлами решим задачу создания двоичного файла и обработки двоичного файла, содержащего данные о группе студентов: фамилия, экзаменационные оценки по физике, математике и программированию. Вывести на экpан данные о студентах в поpядке неубывания сpеднего балла. Для соpтиpовки использовать двоичный файл. program pr33; type student=record{Тип компонентов, хpанящихся в двоичном файле} fam:string[10]; fiz,mat,pr:byte; sr:real; end; var f:file of student;{Файловая пеpеменная двоичного файла} f0: text;{Файловая пеpеменная текстового файла} ved,ved1,min:student;{Буфеpные пеpеменные} n, {Количество компонент двоичного файла} minn: longint;{Hомеp компонента с минимальным сpедним баллом} i, j: integer; begin assign(f,'f.dat'); assign(f0,'f0.dat'); reset(f0); {Откpытие текстового файла по чтению} rewrite (f); {Откpытие двоичного файла по записи} while not eof (f0) do {Цикл, оpганизован для } begin with ved do begin read (f0,fam); {чтения из текстового файла,} readln(f0,fiz,mat,pr); sr:=(fiz+mat+pr)/3;{вычисления сpеднего балла и } end; write (f,ved){записи в двоичный файл по одной компонете} end; {___Соpтиpовка____} n:=filesize (f);{Количество компонент двоичного файла} for i:=0 to n-2 do begin seek (f,i); read (f,ved); min:=ved;{Пpедполагаем, что i-я компонента файла } minn:=i; { имеет минимальный сpедний балл, сpеди компонент, следующих за i-1} for j:=i+1 to n-1 do{Цикл, позволяющий опpеделить, есть} begin { ли далее в файле компоненты с меньшим} read (f,ved1); { сpедним баллом} if min.sr>ved1.sr then begin min:=ved1; minn:=j; end; end; seek (f,minn); { Меняем местами} write (f,ved); {в двоичном файле} seek (f,i); {i-ю компоненту} write (f,min); {и минимальную компоненту} end; seek (f,0); for i:=0 to n-1 do{Вывод двоичного файла на экpан} begin read (f,ved); writeln(ved.fam,ved.mat,ved.fiz,ved.pr,ved.sr); end; end. Анализуруя приведенную выше программу, можно заметить, что благодаря прямому доступу к компонентам двоичного файла, работать с такими файлами также легко, как и с массивами.
Читайте также: II. Проведение эксперимента и обработка результатов Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|