Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Информатика_ч2-записи

.pdf
Скачиваний:
4
Добавлен:
15.04.2015
Размер:
417.35 Кб
Скачать

1

10.ЗАПИСИ. ТИП ДАННЫХ RECORD

Вописании данных и связей между ними используют понятия: запись логическая и запись физическая. Физическое описание данных определяет способ их хранения во внешней памяти ЭВМ. Логическое описание данных указывает на то, в каком виде эти данные представляются прикладному программисту или пользователю данных. В этом разделе и в последующих под записью будем понимать - ЛОГИЧЕСКУЮ запись, или структурную переменную, состоящую из нескольких компонент, доступ к которым осуществляется по имени. Компоненты записи (иногда их называют ПОЛЯМИ, или элементами) могут быть разных типов: скалярные переменные, массивы, записи, множества, указатели.

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

Эти поля (компоненты) могут описываться данными разных типов, именно поэтому записи иногда называют комбинированными типами.

Описание записи в разделе TYPE включает:

< имя типа записи > = RECORD

{ список полей }

<имя-компоненты 1 > : < тип компоненты 1 >;

<имя-компоненты 2 > : < тип компоненты 2 >;

. . .

<имя-компоненты L > : < тип компоненты L >

END;

Имя типа записи - представляет собой идентификатор, который может использоваться при конструировании новых типов или описания типов переменных в разделе VAR. Имена компонент записи соответствуют реквизитам информационного объекта, а типы компонент выбираются на основании форматов реквизитов, диапазонов изменения их значений. Кратность в экземплярах обеспечивается использованием регулярных структур ARRAY выбранных типов данных. Связи с другими объектами могут быть реализованы указателями (ссылками), включаемыми в состав компонент рассматриваемой записи. Запись в целом и каждая ее компонента имеют свои имена, к которым можно обращаться в программе.

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

10.1. Пример использования записи для работы с комплексными числами

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

2

Пример 116. Вычислить комплексную функцию Z(a, b, x), где a, b, x - комплексные переменные.

 

2 x 1

,

a b;

 

 

 

 

b

 

Z(a,b,x)

 

 

 

 

a b x

, a b

 

a b

 

 

(10-1)

В (10-1) используются операции сложения, умножения и деления комплексных чисел. Паскаль в отличие от Фортрана не имеет встроенных комплексных типов данных операций и операций над ними, поэтому в приведенном ниже коде программы для хранения комплексных чисел введена запись с именем COMPLEX, имеющая два поля RE

– вещественная и IM – мнимая составляющие комплексных чисел. Поскольку арифметика комплексных чисел в языке не предусмотрена, то вместо операций +, *, / вводятся три процедуры CSUM, CMUL, CDIV, реализующие следующие правила вычисления

комплексных чисел:

 

1) (a + b•i) + (c + d•i) = (a + c) + (b + d)•i;

- сложение двух вещественных чисел.

2) (a + b•i) * (c+d•i) = (a•c-b•d) + (b•c+a•d)•i; - умножение двух вещественных

чисел.

3) (a + b•i) / (c + d•i) = (a•c+b•d)/(c +d ) + ((b•c+a•d)/(c +d ))•i; - деление двух вещественных чисел.

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

4) (a + b•i) + k = (a + k) + b•i; - сложение комплексного и вещественного чисел. 5) (a + b•i)•k = a•k + b•k•i; - умножение комплексного и вещественного чисел.

В выражении (10-1) используется две вещественные константы 2 и 1, поэтому в общем случае свойства 4 и 5 следовало бы оформить в виде подпрограмм, но можно пойти другим путем. В предлагаемой программе сделано преобразование вещественных чисел 2 и 1 в комплексную форму (2 + 0•i) и (1 + 0•i), и, таким образом, сведены свойства 4 и 5 к свойствам 1 и 2, соответственно, с целью последующего использования при вычислениях процедур CSUM, CMUL.

PROGRAM PR116;

TYPE COMPLEX = RECORD

RE : REAL;

{ действительная часть комплексного числа}

IM : REAL

{ мнимая часть }

 

END;

{ конец описания записи - COMPLEX }

VAR

A, B, X, Z, K: COMPLEX;

PROCEDURE CSUM( C, D :COMPLEX; VAR E : COMPLEX);

{ Сложение двух комплексных чисел C и D, результат – число E } BEGIN

E.RE := C.RE + D.RE;

E.IM := C.IM + D.IM

END; { Конец процедуры CSUM }

PROCEDURE CMUL( C, D :COMPLEX; VAR E : COMPLEX);

{ Умножение двух комплексных чисел C и D, результат – число E }

3

BEGIN

E.RE := C.RE*D.RE - C.IM*D.IM;

E.IM := C.IM*D.RE + C.RE*D.IM

END;

{ Конец процедуры CMUL }

PROCEDURE CDIV( C, D :COMPLEX; VAR E : COMPLEX);

{ Деление двух комплексных чисел C и D, результат – число E }

VAR

S : REAL;

BEGIN

S := D.RE*D.RE + D.IM*D.IM;

E.RE := (C.RE*D.RE + C.IM*D.IM)/S;

E.IM := (C.IM*D.RE - C.RE*D.IM)/S

END;

{ Конец процедуры CDIV }

BEGIN

 

WRITELN('Введите комплексное число А'); READLN(A.RE, A.IM);

WRITELN('Введите комплексное число B'); READLN(B.RE, B.IM);

WRITELN('Введите комплексное число X'); READLN(X.RE, X.IM);

IF (A.RE = B.RE) AND (A.IM = B.IM)

THEN BEGIN

{ Комплексное число B равно комплексному

числу A }

 

K.RE := 2; K.IM := 0; { Запись действительного числа 2 в комплексной форме - (2 + 0•i) } CMUL(K, X, Z);

K.RE := 1; K.IM := 0; { Запись действительного числа 1 в комплексной форме - (1 +

0•i) }

CSUM(Z,K,Z);

CDIV(Z,B,Z) END

ELSE BEGIN { Комплексное число B не равно комплексному числу A

}

CMUL(B, X, Z); CSUM(A, Z, Z); CSUM(A, B, K); CDIV(Z, K, Z) END;

WRITELN('Z = (', Z.RE, ',', Z.IM,') ') { Вывод на экран комплексного числа Z } END.

10.2. Использование записей для описания таблиц

При решении на ЭВМ широкого круга информационных задач формализуется инфологическая модель, описывающая множество взаимосвязанных объектов, каждый из которых характеризуется своими признаками. При этом формализуется имя информационного объекта и его реквизитный состав (в том числе: имя реквизита, формат реквизита, диапазон изменения, кратность в экземплярах) и связи с другими информационными объектами. Эта модель ложится в основу построения информационной внутримашинной базы данных. Используется два пути программирования алгоритмов ведения баз данных: средствами типовых СУБД (систем управления базой данных, например ACCESS), или с применением универсальных языков типа Паскаль, Фортран, Бейсик, СИ и других.

СУБД обеспечивает:

4

1.Организацию, ведение базы данных и словарей (генерация структуры базы, коррекция и удаление данных);

2.Макетный ввод данных в базу;

3.Запрос на поиск и обработку информации об объектах;

4.Макетный вывод результатов;

5.Cервисные функции СУБД (дублирование, защита, восстановление, сжатие данных и другие).

При использовании универсального языка программирования эти функции должен реализовать программист в своих программах.

Использование СУБД рекомендуется для больших разнородных баз с меняющейся

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

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

Описание записи

 

Пример 117. Описать структуру данных, изображенных в табл. 46.

 

Студенты

 

Таблица 46

 

 

 

 

 

 

 

Номер

Фамилия И.О.

Дата

Номер

Размер

п/п

зачетной

 

рождения

группы

стипендии, руб.

 

книжки

 

 

 

 

1

910678

Петухов И.М.

13.01.82

ИП-11

550.00

2

910679

Шульгин Е.Ю.

01.12.81

ИП-11

480.00

3

910680

Щукин А.А.

05.11.81

ИП-11

550.00

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

Ниже приведена модель табл. 46, описанная на языке ПАСКАЛЬ. Type Student = record

Tab : Longint;

{Номер зачетной книжки}

Fio : String[20]; {Фамилия И.О. }

Data : String[8];

{Дата рождения}

Grup : String[7]; {Номер группы}

Stepa: Real

{Размер стипендии, руб. }

end;

 

Var Mstd: array[1..20] of Student; Std: Student;

5

В этом описании: Student – имя типа записи; Tab, Fio, Data, Grup, Stepa – имена полей (в синтаксисе данных типа RECORD их называют компонентами); Std – одна переменная, соответствующая сведениям об одном студенте; Mstd – массив записей, то есть сведения обо всей группе студентов, перечисленных в табл. 46. Поле номер по порядку в структуру таблицы не включено, т.к. обеспечивает макетный вывод информации на монитор или бумагу и формируется автоматически в соответствии с указанным критерием упорядочения записей в таблице.

Работа с полями записи

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

Std.Tab := 910678; Std.Fio := ’Петухов И.М.’; Std.Data := ’13.01.82’;

Std.Grup := ’ИП-11’;

Std.Stepa := 550.00;

В этой программе формируются сведения о студенте Петухове. К сожалению оператор присваивания в Паскале не поддерживает инструкцию вида - Mstd[1] := Std, что существенно бы упростило работу с записями.

Использование оператора WITH … DO

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

WITH <Переменная типа RECORD> DO <Оператор>;

Используем предыдущий пример для пояснения работы оператора присоединения. WITH Std

DO BEGIN

Tab := 910678; Fio := ’Петухов И.М.’; Data := ’13.01.82’;

Grup := ’ИП-11’;

Stepa := 550.00;

END;

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

Ввод данных в массив записей с клавиатуры

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

6

FOR I := 1 TO 20

DO BEGIN

WRITELN(’Введите данные о студенте № ’, I:1);

WITH Mstd[I]

DO BEGIN

WRITELN(’Номер зачетной книжки’); READLN(Tab);

WRITELN(’Фамилия И.О.’); READLN(FIO);

WRITELN(’Дата рождения’); READLN(Data);

WRITELN(’Номер группы’); READLN(Grup);

WRITELN(’Размер стипендии, руб.’); READLN(Stepa);

END;

10.3. Вложение записей

Любое из полей записи может в свою очередь быть записью. В этом случае говорят

о вложении записей.

 

 

 

 

Пример 118. Описать структуру данных, изображенных в табл. 47.

 

Успеваемость группы

 

 

Таблица 47

 

 

 

 

 

 

 

 

Номер

Аттестация

 

 

 

 

зачетной

Дисциплина

 

Дисциплина

Дисциплина

Дисциплина

Дисциплина

книжки

1

 

2

3

4

5

910678

А

 

А

Н/А

А

Н/А

910679

А

 

А

А

Н/А

А

910680

А

 

А

А

А

А

Эта таблица структурно отличается от табл. 46. В табл. 46 все поля были одного уровня. А в табл. 47 пять полей: Дисциплина 1, Дисциплина 2, Дисциплина 3, Дисциплина 4, Дисциплина 5 – образуют группу, которая подведена под общее имя - Аттестация.

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

TYPE ATTASTACIA = RECORD

D1 : BOOLEAN;

{ Дисциплина 1}

D2 : BOOLEAN;

{ Дисциплина 2}

D3 : BOOLEAN;

{ Дисциплина 3}

D4 : BOOLEAN;

{ Дисциплина 4}

D5 : BOOLEAN;

{ Дисциплина 5}

END;

USPEVAEMOST = RECORD

TAB : LONGINT; {Номер зачетной книжки} ATT : ATTASTACIA

END;

VAR USP: ARRAY[1..20] OF USPEVAEMOST;

Из текста программы видно, что для кодирования результатов аттестации выбран логический тип данных - BOOLEAN. То есть значению “A” аттестован соответствует - TRUE, а ситуации не аттестован “Н/А” соответствует – FALSE.

Существует ограничение на глубину вложения записей - не более 9

7

Присвоение значений полям вложенных записей

Ниже приведен пример прямого присвоения значений полям первой записи USP[1] в массиве записей USP – успеваемость группы. Уровень вложения соответствует числу разделителей имен, то есть точек в идентификаторе поля.

USP[1].TAB := 910678;

{Уровень вложения 1}

USP[1].ATT.D1 := TRUE;

{Уровень вложения 2}

USP[1].ATT.D2 := TRUE;

 

USP[1].ATT.D3 := FALSE;

 

USP[1].ATT.D4 := TRUE;

 

USP[1].ATT.D5 := FALSE;

Используем оператор WITH для этого же примера.

WITH USP[1]

{Уровень вложения 1}

DO BEGIN

 

 

TAB := 910678;

 

 

WITH ATT

{Уровень вложения 2}

 

DO BEGIN

 

D1

:= TRUE;

 

D2

:= TRUE;

 

D3

:= FALSE;

 

D4

:= TRUE;

 

D5

:= FALSE

 

 

END

 

END;

Замечания.

1.Из нашего примера видно, что в конкретном случае использование оператора WITH существенно усложнило структуру программы.

2.Помимо рассмотренного нами типа записей в Паскале существуют еще, так называемые, записи с вариантами - тип RECORD … CASE …. OF … Это нелепое изобретение не нашло никакого практического внедрения ни в теоретической информатике, ни в инженерной деятельности, поэтому не стоит этот тип данных даже изучать. (от авт.)

8

11.ФАЙЛЫ ЗАПИСЕЙ

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

Напомним, что файл - это структурированный тип данных, состоящий из компонентов одного типа. Файлы записей часто называют базой данных и относят к так называемым типизированным файлам. Типизированный Файл с точки зрения языка ПАСКАЛЬ - это структурированный тип данных, состоящий из последовательности компонентов одного типа и одной длины. Для типизированных файлов файловый тип и файловую переменную задают с помощью следующей синтаксической конструкции:

TYPE <Имя типа файла> = FILE OF <Тип компонент файла>;

VAR <Идентификатор файловой переменной>: <Имя типа файла>;

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

Определение типа файлов начинается ключевыми словами FILE OF, после которого задается тип компонентов файла, который описывает, что содержит данный файл. Далее следует идентификатор предварительно определенного типа файла. Число компонентов, называемое длиной файла, определением типа файла не фиксируется.

Идентификатор файловой переменной определяет имя файла в программе. Можно в разделе VAR определить несколько файловых переменных, что дает, возможность программе работать одновременно с несколькими файлами одного или различных типов.

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

Type

Student = record

Tab:

Longint;

{Номер зачетной книжки}

Fio:

String[20];

{Фамилия И.О.}

Data:

String[8];

{Дата рождения}

Grup: String[7];

{Номер группы}

Stepa: Real

{Размер стипендии, руб.}

end;

 

 

Var

Std: Student; Mstd: array[0..19] of Student;

Fstd: File of Student;

В этом примере имя типа файла в явном виде не используется. Для описания файла, использован второй способ, так называемое неявное определение файлового типа, непосредственно в разделе VAR:

Var F: file of <тип компонент>;

где F - переменная для доступа к файлу (файловая переменная).

9

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

11.1 Структура файла

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

Закрыт для чтения и записи; Открыт для записи, закрыт для чтения;

Открыт для чтения закрыт для записи компонент; Открыт для чтения, открыт для записи компонент.

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

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

Рис. 32. Схема файла: а) файл содержит N компонент, б) пустой файл.

На рис. 32.а представлен файл, с именем S, содержащий N компонент (записей). А на рис. 32.б изображен пустой файл, в котором нет ни одной компоненты, только название и метка конца файла.

10

Каждому файлу пользователя должно быть присвоено уникальное имя (в рамках каталога в котором этот файл хранится), которое используется при обращении к этому файлу. Имя должно соответствовать стандарту MS-DOS, и состоит из собственно имени (от 1 до 8 символов: букв или цифр) и необязательного типа файла (до 3-х символов). Если тип файла присутствует, он отделяется от первой части имени точкой. Тип файла присваивается обычно в мнемонической зависимости от содержимого файла.

Пример имени файла: STUDENTS.DAT

Для обращения к файлу необходимо указать путь, то есть имя диска, на котором расположен нужный файл (A, B, C, D, E …) корневой директорий \, и поддиректории, если они есть. Пример пути и имени файла, расположенного в корневом каталоге на дискете: A:\STUDENTS.DAT

11.2. Встроенные процедуры и функции обработки файлов

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

Для организации доступа к файлу записей следует объявить файловую переменную F следующим образом: VAR F: FILE OF <тип компонент>;

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

Rewrite (F) - создать новый пустой файл. Эта процедура служит для создания нового файла на диске. Имя файла должно быть предварительно определено в процедуре Assign. Если на диске уже был файл с таким именем, он уничтожается. Указатель файла устанавливается в первую позицию (с номером 0). Фактически файл не содержит ни одного компонента, он только подготовлен для загрузки (см. схему на рис. 33).

Рис. 33. Состояние файла F после выполнения команды Rewrite (F)

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

Рис. 34. Состояние файла F после выполнения команды Reset (F)

Read (F, Z) - читать текущий компонент из файла. С помощью этой команды производится чтение из дискового файла, определенного файловой переменной F значений Zl, Z2, ... , ZN. После завершения выполнения процедуры, то есть чтения