Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Статические структуры данных 3 страница




Teacher.adres.tel:='123456';

Приведем еще один пример, в котором фамилия преподавателя передается в переменную v, после чего печатается его день рождения:

v:=teacher.soname.first;

writeln(teacher.birthday);

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

В каждом из только что показанных примеров мы тщательно выписывали всю цепочку имен, начиная с наивысшего уровня Teacher, вплоть до имени конкретного объекта, на который нам нужно сослаться. Такой способ довольно обременителен. В качестве альтернативы в Паскале предусмотрено специальное средство - оператор With (присоединение). Оператор With позволяет задать некоторый префикс, представляющий собой обозначение одного или нескольких уровней записи. Этот префикс будет затем автоматически присоединен ко всем именам - компонентам соответствующей записи, которые присутствуют в теле предложения With. Формально предложение With строится по следующей схеме:

With <префикс> do

<оператор>

Здесь слово префикс обозначает имя одного или нескольких уровней записи. За заголовком with...do следует любой оператор Паскаля или группа операторов, обрамленная символами begin и end

Предположим, что нам требуется отпечатать значения двух полей: first и last. Соответствующее предложение With будет таким:

With Teacher.Soname do

writeln(first,' ',last);

В точечной нотации это равносильно предложению

writeln (Teacher.Soname.First,' ', (Teacher.Soname.Last);

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

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

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

Например,

With Teacher, Soname do

writeln (First,' ', Last);

Показанная форма эквивалента следующим:

With Teacher, Soname do With Teacher do

writeln (First,' ', Last); With Soname do

writeln (First,' ', Last);

Согласно определению Паскаля в списковой форме оператора With могут быть указаны имена вообще любых записей, а не только вложенных. Предположим, нам надо напечатать имя и фамилию преподавателя, а затем название города, в котором он проживает:

With Teacher do

Begin

With Soname do

writeln (First,' ',Last);

With Adres do

writeln (city)

End;

В списковой форме синтаксически правильной и вполне работоспособной будет следующая конструкция

With Teacher, Soname, Adres do writeln (First,' ',Last,' ',City);

 

6.4.3. Операции над записями

При соблюдении некоторых условий с записью можно обращаться как с единым объектом. Например, все содержимое одной записи можно назначить другой. Для этого необходимо, чтобы обе записи были совместимы по типу.

Так, в случае объявления

Var Teacher: array [1..20] of TeacherRec;

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

Teacher[2]:=Teacher[1];

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

 

6.4.4. Составление программ с записями.

 

Перейдем непосредственно к программированию поставленной задачи. Определим внутреннюю структуру базы данных. Наиболее логичным представляется применение массива записей. Назовем его student. Разберем "устройство" отдельного элемента этого массива.

Будет разумно рассматривать его состояние из двух основных частей - Name (имя и фамилия) и pers (персональные характеристики). Дальнейшее дробление структуры будет таким: Name распадается на две составляющие - last (фамилия) и first (имя), а Pers - на три индивидуальные характеристики конкретного лица - sex (пол), age (возраст), educ (образование).

Program Ex9;

Type

UrEduc = 0..5;

NameRec = record

last: string [10];

first: string [10]

end;

PersRec = record

Sex:char;

Age:integer;

Educ:UrEduc;

end;

StudRec = record

Name:NameRec;

Pers:PersRec;

end;

Klass = array [1..30] of StudRec;

Numb = 1..30;

Var

Student:Klass; n:numb; j:integer;

Procedure ReadData (Var Student:Klass; Var n:Numb);

{Данные об n студентах класса считываются из файла StudFile в pяд записей Student}

Var i:Numb;

StudFile:text;

Begin

Assign(StudFile,'a:\prog\StudFile.txt');

Reset(StudFile); Readln(StudFile,n);

For i:=1 to n do

with Student[i] do

begin

with name do { фамилия и имя }

begin

read(StudFile,last); read(StudFile, first)

end;

with pers do { пеpсональные сведения}

readln(StudFile,sex,age,educ);

end;{Student[i]}

Close(StudFile);

end;

Procedure FindAge(Student:klass; n: numb; j: integer);

{Эта пpоцедуpа пpосматpивает pяд Student и находит в нем всех, чей возpаст больше или pавен j}

Var i:numb; none:boolean;

Begin

none:=true;

Write('Студентынты, возpаст котоpых больше или pавен ');readln(j);

for i:=1 to n do

begin

with Student[i] do

if pers.age >=j then begin

with name do

writeln (last, ' ', first);

none:=false

end {then}

end; {for}

if none then write ('Таких студентов нет');

end; {FindAge}

begin

readdata (Student,n);

FindAge(Student,n,j);

end.

 

В своей первой части программа (посредством соответствующей подпрограммы) вводит из внешнего файла исходный набор данных, содержащий сведения о студентах класса, и создает тем самым базу данных нашей программы.

Во второй части программы происходит обслуживание базы данных - формирование ответов на вопросы по поводу ее содержимого. В разобранном случае подпрограмма FindAge осуществляет поиск студентов, чей возраст равен или превышает заданное значение возраста. Поскольку данные у нас хранятся в не отсортированном виде, единственно возможным способом поиска является сквозной просмотр всего списка, в ходе которого возраст каждого студента сравнивается с заданным. В качестве программного индикатора успешности или не успешности поиска используется булевская переменная (none - "никого нет"). Очевидно, что другие возможные процедуры обслуживания базы данных, осуществляющие поиск в базе по другим критериям (например, по половой принадлежности или по уровню образования) должны быть похожими на FindAge с незначительными модификациями. Попробуйте написать их самостоятельно.

 

6.4.5. Записи с вариантами

До сих пор, говоря о записях, мы имели дело только с такими, в которых структура полей неизменна. Располагая, например, десятью переменными типа StudRec, мы можем быть уверены, что в любой из них содержатся одни и те же поля: Name и Pers, а также все поля следующего уровня вложенности: first, last, sex, age, educ. Однако для многих приложений столь простой механизм хранения разнородной информации оказывается недостаточным. Для этих случаев Паскаль предлагает еще один способ организации данных - это вариантные записи (записи с вариантами).

Основная идея вариантной записи состоит в том, чтобы находясь в рамках единой структуры, определить в ней сразу несколько различных (альтернативных) записей. В самом общем случае такая запись может состоять из двух частей - фиксированной и вариантной. Фиксированная часть - это обычная совокупность полей; ее структура остается постоянной для всех экземпляров записи данного типа. Структура вариантной части записи не постоянна: она изменяется в зависимости от значения особого поля, называемого полем тега (от англ. tag - ярлык, этикетка, бирка). Применяется также термин поле признака. В качестве примера рассмотрим запись типа StudRec, и на ее основе построим новую, многовариантную версию. Определения типов для фиксированной части оставим те же:

Type

{*Внимание! Дополнительные описания для записей с вариантами!*}

Year = (fut,pres,past);

str6 = string [6];

str9 = string [9];

{ *** }

StudRec = record

Name:NameRec;

Pers:PersRec;

{ Внимание! Здесь начинается запись с вариантами! }

Case status: year of

fut: (datafut: array[1..10] of str6);

pres:(datapres: str6);

past:(datapas: array[1..10] of str6; a1: real; b1: str9)

end; {record}

Klass = array [1..30] of StudRec;

Var Student:Klass;

 

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

Собственно вариантная часть записи начинается с заголовка внешне очень напоминающего предложение Case:

Case status: year of

Сам заголовок служит определением особого поля записи, называемого полем тега. В данном примере поле тега носит имя status, а его тип year. В зависимости от значения тега вариантная часть записи будет иметь различные поля. Если status равен fut, вариантная часть будет представлена только 10-элементным рядом datafut; при значении status, равном pres, в вариантной части будет содержаться лишь одна переменная datapas; наконец, когда status равен past, мы обнаруживаем в вариантной записи сразу три поля:

datapas, a1, b1.

Отметим некоторые синтаксические особенности в определении вариантной записи. Описания всех полей, относящихся к определенному значению тега, заключены в круглые скобки. Вся вариантная часть не заканчивается словом end, парным слову case (как это делается в предложениях case). Единственное слово end завершает всю запись и одновременно ее вариантную часть, так как вариантная часть всегда размещается в самом конце записи.

 

6.5. Файловый тип

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

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

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

Создание внешних файлов данных для постоянного хранения на внешнем носителе и возможность обрабатывать эти файлы в программе являются эффективным средством программирования.

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

 

6.5.1. Определение типа. Классификация файлов

Существенной особенностью всех рассмотренных до сих пор типов данных является наличие в них конечного, наперед заданного числа компонент. Но существуют задачи, когда количество компонент заранее определить невозможно, оно выясняется только в процессе решения задачи, то есть при выполнении программы. Поэтому возникает необходимость в специальном типе значений, которые представляют собой произвольные последовательности элементов (компонентов) одного и того же типа, причем длина этих последовательностей заранее не определяется, а конкретизируется в процессе выполнения программы. Этот тип значений получил в Паскале название файлового. Компоненты файла могут иметь любой тип за исключением файлового.

Файловый тип может быть объявлен, как обычно, двумя способами (число компонент, называемое длиной файла, не фиксируется при определении файла. Это обстоятельство является самым существенным отличием файла от массива.):

Пример:

Type

T = file of char;

P = packed file of char;

Var

Finp:file of real; {файл действительных данных}

M:file of integer; {файл целых данных}

Ft:T; {файл символьных данных}

Файлы различаются:

1) по типу компонент файла:

- текстовые файлы предназначены для хранения текстовой информации. Компонентами файла являются литеры или строки, имеющие переменную длину; описание текстового файла File of char эквивалентно описанию text (тип text является стандартным). Поэтому в предыдущем примере текстовый файл Ft можно объявить

Var Ft:text;

- типированные (типизированные) - это дисковые файлы, состоящие из нумерованной последовательности компонент некоторого конкретного типа, причем длина каждой компоненты определена и постоянна;

- нетипированные (нетипизированные) файлы - при описании не указывается тип компонент, в этом случае в объявлении слово of и тип компоненты отсутствует

Type a = file;

Такие файлы обеспечивают совместимость с любыми другими файлами и позволяют организовать высокоскоростной обмен данными между диском и памятью (поэтому их еще называют низкоуровневые каналы ввода-вывода).

2) по методу доступа к его компонентам:

- файлы с последовательным доступом - каждый элемент становится доступным только после перебора всех предыдущих элементов;

- файлы с произвольным (прямым) доступом - возможно обращение к компоненту по его порядковому номеру в файле;

3) по времени своего существования:

- внутренние файлы (рабочие) существуют только во время исполнения программы; они носят вспомогательный характер;

- внешние файлы - существуют и вне программы. Они могут быть подготовлены автономно и сохраняются после работы программы;

4) по авторству создателя:

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

- файлы пользователя.

 

6.5.2. Действия с файлами

Переменные файлового типа нельзя использовать в выражениях. Основой ввода-вывода в Паскале является внешний последовательный файл. Над ним определены два вида действий. Этот файл можно просматривать (читать) по одному элементу с начала в каждый момент времени. В этот файл можно записывать новые элементы, путем добавления их в конец файла (в начале записи этот файл пустой).

Считывание данных из внешнего файла обладает тем преимуществом, что позволяет обрабатывать огромные массивы данных значительно быстрее и легче, чем при интерактивном (диалоговом) вводе.

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

Физически внешний файл располагается на запоминающем устройстве (например, винчестере или дискете). Если в программе используется внешний файл, компилятор Паскаля должен получить некоторую дополнительную информацию о нем. Прежде всего, программист должен объявить файловую переменную, которая будет представлять файл внутри программы.

Например:

Write ('Киев'); {выводит слово 'Киев' на экран}

Write (File1, 'Киев'); {заносит слово 'Киев' в конец файла с именем File1}

Кроме того, необходимо сообщить компилятору о местонахождении внешнего файла, что выражается в имени внешнего файла, под которым он зарегистрирован вне программы. (Например, f:\klass\k111\prog7.dat)

Для установления связи между файловой переменной и "внешним" именем файла в Паскале применяется предложение assign. После его выполнения файл необходимо открыть посредством предложения reset (для ввода информации) или rewrite (для вывода). Обращение собственно к содержимому файла осуществляется предложениями read или readln (считывание данных) или write или writeln (запись в файл); первым параметром указанных процедур ввода-вывода должно быть имя файловой переменной. Для прекращения дальнейших действий с файлом его следует закрыть предложением close.

 

Пример:

Program Ex10;

Var File1:text;

Begin

Assign (File1,'a:\file1.txt');{назначает файлу имя}

Rewrite(File1);{создает пустой файл и открывает его по записи}

Writeln(File1,'Очень полезно изучать');

Writeln(File1,'Паскаль');

Writeln(File1,'в ИСР Borland Pascal 7.0');

Close(File1);

End.

Пример:

Program Ex11;

Var File1:text; St:string;

Begin

Assign (File1,'a:\file1.txt');

Append(File1);{Добавляет текст к концу файла}

Writeln(File1,'А теперь закончим');

Reset (File1); {Открытие файла по чтению}

While not EOF(File1) do

begin

Readln(File1,st);{чтение из файла}

Writeln(St); {и вывод на экpан}

end;

Close(File1);

End.

 

Если требуется осуществить произвольный доступ к большой группе данных, то типизированные файлы значительно эффективнее текстовых, так как длина каждой компоненты постоянна и легко вычислить позицию каждой компоненты в файле и напрямую считать или записать этот элемент. Компоненты типизированного файла нумеруются по порядку, начиная с нуля, то есть первая компонента имеет номер 0, вторая - 1, третья - 3 и т.д.

 

Пример:

Program Ex12;

{Создает файл, содержащий квадраты 10 чисел типа Real}

Var File1:file of real;

R:real; N:integer;

Begin

Assign (File1,'a:\fi2.dat');

Rewrite (File1); {Создает новый пустой файл и готовит его к записи}

For N:=1 to 10 do

begin

R:=sqr(N);

Write (File1,R);

{Записывает числа в файл в двоичном внутреннем формате}

end;

Close(File1);

end.

 

Пример:

Program Ex13;

{Считывает с экpана числа в диапазоне от 1 до 10 и выдает их квадpаты, записанные в файле, созданном предыдущей программой}

Var

File1:file of real;

R:real; N:integer;

Begin

Assign (File1,'a:\fi2.dat');

Reset (File1);

Write ('Введите число (1-10):');

Readln(N);

Seek (File1,N-1);

{текущая позиция файла передвигается в заданную позицию}

Read(File1,R);

Writeln('Квадpат ',n,' pавен ',r:4:1);

End.

 

6.5.3. Процедуры и функции для работы с файлами

Итак, мы использовали несколько процедур и функций. Уточним их определение.

Assign(имя файла, внешнее имя) - процедура назначает имя внешнего файла файловой переменной. С момента выполнения этой процедуры все действия над файловой переменной будут эквивалентны действиям над внешним файлом.

Rewrite(имя файла) - процедура создает и открывает новый файл для записи. Если на диске уже был файл с таким именем, он уничтожается. Файл не содержит ни одной компоненты, он только подготовлен для загрузки.

Writeln (имя файла, список параметров для записи) - запись в файл.

Append (имя файла) - процедура открывает существующий текстовый файл для присоединения.

Close (имя файла) - закрывает открытый файл. Если файл был открыт, никогда не следует выходить из программы, предварительно не закрыв его.

Reset (имя файла) - процедура открывает существующий файл для чтения. Если эта процедура применена к несуществующему файлу, возникает ошибка ввода-вывода.

Readln (имя файла, список параметров для чтения) - чтение из файла;

Eof (имя файла) - функция проверяет метку "конец файла". Значение функции равно true, если указатель находится сразу за последней компонентой файла и false в любом другом случае.

Seek(имя файла, номер компоненты) - устанавливает указатель на компоненту с указанным порядковым номером. Наличие этой процедуры придает работе с файлами "привкус работы с одномерным массивом".

Существует и ряд других процедур и функций для работы с файлами:

Flush (имя файла) - очистить буфер файла. К закрытому файлу не применяется.

Erase (имя файла) - уничтожить файл. Если производится уничтожение файла, его необходимо предварительно закрыть с помощью процедуры Close.

Rename (имя файла, новое имя файла) - переименовать файл.

FilePos (имя файла) - определить текущий номер компоненты. Функция возвращает целочисленное значение, равное номеру компоненты, на которую установлен указатель.

FileSize (имя файла) - определить длину файла. Функция возвращает целочисленное значение, равное количеству компонент файла. Обычно используется для проверки, содержит файл какую-либо информацию или является пустым.

 

6.5.4. Стандартные файлы

В Паскале все внешние устройства (клавиатура, экран, принтер) трактуются как логические устройства, которым соответствуют заранее определенные (стандартные) файлы. Эти файлы фактически являются драйверами, обеспечивающими операции ввода-вывода между процессором и конкретными физическими устройствами.

Допустимо использование следующих логических устройств:

con: - пульт управления (для ввода - клавиатура, для вывода - дисплей). Вводимая информация отображается на экране и может редактироваться.

trm: - терминал (для ввода - клавиатура, для вывода - экран).

Вводимая информация отображается на экране, но редактироваться не может.

kbd: - клавиатура. Используется для ввода с клавиатуры. Вводимая информация на экране не отображается.

lst: - принтер. Используется только для вывода.

Для организации работы с логическими устройствами используются стандартные файлы. Система сама открывает и закрывает эти файлы, поэтому к ним не применяются процедуры Assign, Reset, Rewrite, Close.

 

Имена логических устройств и соответствующих им стандартных файлов, за исключением имен файлов ввода (input) и вывода (output), совпадают.

Например, чтобы направить выходные данные программы прямо на экран, достаточно в качестве имени внешнего файла указать 'con:'. Хотя программировать ввод-вывод с использованием стандартных файлов проще, употребление файловых переменных позволяет делать программу более гибкой.

 

Вопросы для самоконтроля:

1. Что такое «массив»?

2. Что такое индекс?

3. Где и как может быть объявлен массив?

4. Как ввести матрицу?

5. Как осуществить перестановку?

6. Что такое строка в в Паскале?

7. Чем отличается строка от массива?

8. Какие строки называются равными?

9. Что называется множеством в Паскале?

10. Какие операции допустимы в Паскале?

11. Назовите порядок операций со множествами по старшинству?

12. Как объявляются объекты типа «запись»?

13. Для каких целей используется оператор присоединения?

14. Что такое поле записи?

15. Какие операции допустимы с записями?

16. В чем состоит идея вариантной записи?

17. Дать определение файла.

18. Какие вы знаете типы файлов?

19. Как объявляется переменная файлового типа?

20. Какие вы знаете процедуры работы с файлами?

21. Как организовать проверку конца файла?

 


ГЛАВА 7




Поделиться с друзьями:


Дата добавления: 2014-12-27; Просмотров: 400; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.13 сек.