Курс лекций для специальности «Прикладная математика» Первый семестр

Вид материалаКурс лекций

Содержание


Строковый тип данных
Запись - структура данных, содержащая конечное число компонент различного типа. Компоненты называются полями.
Описатель записей
Вариантная часть всегда следует за фиксированной, если она есть.
Подобный материал:
1   2   3   4   5   6   7   8   9   10   ...   13

Лекция 7

7.1 Строки


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

<имя переменной>:STRING[длина]

или

<имя переменной>:STRING

В стандарте Паскаля такого типа данных нет.

Параметр длина задает максимальную длину строки (максимальное число символов цепочки). Если максимальный размер строки не указан, то он автоматически принимается равным 255 – максимально возможной длине строки. Для переменной типа string резервируется участок памяти длиной длина+1 байт. Дополнительный байт используется для хранения значения текущей длины строки.

В языке Паскаль широко используются константы строкового типа. Они представляют собой цепочки произвольных символов используемой кодовой таблицы, заключенные в апострофы. Например: ‘ВОТ’ – цепочка из трех символов, ‘’ – пустая цепочка.

Строка обладает всеми свойствами массива литер, то есть, структуры данных, описанной описателем array[0..длина] of char. Если имеются описания s,s1:string[10], то, в отличие от массива, допустимы присваивания

s:=’BOT’

s1:=’’.

При этом текущая длина строки s будет равна 3, текущая строка s1 – 0. Текущая длина строки – целое положительное число в диапазоне от 0 до длина – хранится в нулевом элементе строки как данное типа char (s[0]=chr(3), s1[0]=chr(0)). В первом элементе строки s – s[1] – хранится символ ‘B’, во втором – ‘O’, в третьем – ‘T’, значение элемента s[4] неопределенно, обращение к нему является ошибкой, поскольку индекс превышает текущее значение длины строки.

Текущая длина строки не должна превышать максимальную длину.

К строкам применимы стандартные процедуры ввода и вывода. Если выдать на экран значения строк s и s1, то получим:

writeln(s) – на экране строка ‘ВОТ’,

writeln(s1) – на экране пустая строка.

Над строковыми данными определена бинарная операция конкатенации (+). Результатом конкатенации двух строк является строка, содержащая последовательно все символы левого операнда, а затем все символы правого операнда. Вот примеры использования конкатенации:

writeln(s) – на экране текст ВОТВОТ;

s1:=s+’ KOT’; writeln(s1) – на экране ВОТ КОТ.

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


program Enter_int;

type status=(beginning,znak,Ok,Err);

var s:string; zn,k,i:integer; c:char;

n:longint;

stat:status;

cifra:boolean;

begin

repeat

writeln(‘Введите целое по модулю меньшее ’,$7FFF:1);

readln(s);

k:=length(s);

zn:=1;

n:=0;

stat:=beginning;

for i:=1 to k do

begin

c:=s[i];

cifra:=(c>='0') and (c<='9');

case stat of

beginning: case c of

' ': ;

'+': stat:=znak;

'-': begin stat:=znak; zn:=-1 end;

'0'..'9': begin n:=n*10+ord(c)-ord('0');

stat:=Ok end;

else stat:=Err

end;

znak: if cifra then

begin

n:=n*10+ord(c)-ord('0'); stat:=Ok

end else stat:=Err;

Ok: if cifra then

begin

n:=n*10+ord(c)-ord('0'); stat:=Ok

end else stat:=Err;

end;

end;

n:=zn*n;

if abs(n)>=$7FFF then stat:=Err;

until stat=Ok;

writeln('rezult ',n)

end.


Переменную типа STRING можно сравнивать с другой переменной или константой типа STRING, используя отношения =, <, >, <=, >=, <>. Используется лексикографический порядок (как в каталогах библиотек).


В TP имеются следующие функции для обработки строк:
  • CONCAT - функция имеет произвольное число параметров строкового типа, результат - строка, полученная последовательной склейкой параметров. Если длина полученной строки превышает 255 символов, то происходит усечение;
  • COPY(S:string; ind,count:integer):string - возвращает подстроку S длиной count, начиная с литеры номер ind. При несоответствии с максимальной длиной используется усечение;
  • DELETE(var S:string; ind,count:integer) - удаляет из S count символов, начиная с ind;
  • INSERT(St:string; var S:string; ind:integer) - вставляет в S St, начиная с позиции ind;
  • LENGTH(S:string) - функция, возвращает текущую длину строки S;


Две процедуры можно рассматривать как процедуры преобразования типа:
  • VAL(S:string; var V; var code:integer) - где V - переменная целого или вещественного типа. Процедура выделяет из строки последовательность символов, преобразует к типу соответствующей переменной и присваивает полученное значение этой переменной. Процедура VAL является строковым аналогом процедуры READ. Если при чтении из строки встречается недопустимый символ, то в переменной code возвращается его номер. В противном случае этот параметр равен нулю;
  • STR(X; var S:string) - преобразует численное значение целого или вещественного типа в его строковое представление. Эта процедура является строковым аналогом процедуры WRITE. После выражения X можно указать длину и точность представления данных.


Вот примеры использования процедур VAL и STR.


var X:real; S:string; i:integer;

begin

X:=3.1415926;

STR(X:8:4, S); S:='X=' + S;

Writeln(S); { на экране 'X= 3.1416'}

S:=DELETE(S,1,2); {удалили первые два символа}

VAL(S,X,i);

if i=0 then writeln(X:10:6) {на экране ' 3.141600'}

end.


В качестве упражнения перепишите программу Enter_int, используя функции и процедуры обработки строк.

7.2 Записи


Запись - структура данных, содержащая конечное число компонент различного типа. Компоненты называются полями. Как любой тип, определяемый программистом, тип "запись" должен быть объявлен в разделе TYPE. При описание типа запись указывает тип каждого поля и идентификатор, который именует поле. Тип данных RECORD предоставляет возможность объединить в одну связанную структуру различные по типу и смыслу поля, причем элементами записи могут быть и структурированные типы данных, например массивы и другие (подчиненные) записи. Для обработки доступна как вся запись целиком, так и отдельные поля.


Описатель записей:

RECORD <фиксированная часть> <вариантная часть> END


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


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


TYPE

REC = RECORD

A, B : INTEGER;

C : CHAR

END;

DATE = RECORD

DAY : 1..31;

MONTH : 1..12;

YEAR: 1900..2100

END;


Если VAR X:REC; Y, Z:DATE; то к полям записей X, Y и Z имеется доступ по имени поля. Например, X.A - поле A записи X, элемент типа INTEGER.


Инициализация записи - инициализация всех полей записи Y.DAY := 17; Y.MONTH := 3; Y.YEAR := 1992;


Если запись Y инициализирована, то можно ее использовать в правой части оператора присваивания Z := Y ; Z и Y совместимы по присваиванию, поскольку относятся к одному и тому же типу данных.


Посмотрите, как используется запись в программе Datas лекции 5.


Вариантная часть всегда следует за фиксированной, если она есть.

CASE <тег:> тип of <список описаний вариантов>


Описание варианта - это константное значение или диапазон константных значений, относящихся к типу «тип» описания вариантной части. Далее ставится двоеточие, и в скобках - описание полей варианта. Описание полей варианта осуществляется по тем же правилам, что и полей фиксированной части. Имена всех полей должны быть уникальными идентификаторами внутри записи.

Следующий пример показывают способ задания поля тега.


TYPE SHAPE = (TRIANGLE, RECTANGLE, SQUARE, CIRCLE);

COORDINATES = RECORD { фиксированная часть }

X, Y, AREA : REAL;

CASE S : SHAPE OF { вариантная часть }

TRIANGLE : (SIDE : REAL; BASE : REAL);

RECTANGLE: (SIDEA, SIDEB : REAL);

SQUARE : (EDGE : REAL);

CIRCLE : (RADIUS : REAL)

END;


В памяти поля разместятся как показано на рисунке


фиксированная часть

вариантная часть

X

Y

AREA

S

SIDE

BASE

X

Y

AREA

S

SIDEA

SIDEB

X

Y

AREA

S

EDGE

-

X

Y

AREA

S

RADIUS

-

Если S = RECTANGLE, то доступны поля SIDEA и SIDEB. Например, при инициализации записи:

X : COORDINATES;

X.S := RECTANGLE;

X.SIDEA := 17.5;

X.SIDEB := 20.4;


В стандартном языке Pascal (и в TP) можно вообще не указывать поле тега:


COORDINATES RECORD

X, Y : REAL; { фиксированная часть }

AREA : REAL;

CASE SHAPE OF { вариантная часть }

END


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


Проанализируйте самостоятельно следующий пример:

program record_;

type

T_education=(begining,medium,higher);

T_profession=(teacher,driver,woker);

T_category=(A,B,C,D);

T_anketa=

record

name :string[20];

case profession:T_profession of

teacher:(education:T_education;

pedagogical_length_of_service:byte);

driver :(licence:record

case drivers_licence:boolean of

true :(category:T_category;

drivers_length_of_servie:byte);

false:(drivers_school:string[20])

end);

woker :(specialization:string[20];

class:string[20])

end;

var a1,a2,a3:T_anketa;

begin

writeln(sizeof(T_profession)); {1}

writeln(sizeof(T_anketa)); {64}

a1.name:='Ivan';

a1.profession:=teacher;

a1.education:=higher;

a1.pedagogical_length_of_service:=1;

a2.name:='Vlad';

a2.profession:=driver;

a2.licence.drivers_licence:=true;

a2.licence.category:=B;

a3.name:='Mike';

a3.profession:=woker;

a3.specialization:='shoe-maker';

a3.class:='master';

end.


Оператор присоединения WITH позволяет один раз указать имя записи и обращаться непосредственно к полям записи. Синтаксис оператора WITH:


WITH <список переменных> DO <оператор>,


где в списке «список переменных» указываются имена записей.


Например, если Y запись типа DATE (см. пример выше), то значения полям этой записи можно присвоить так:


WITH Y DO BEGIN

DAY :=17; MONTH := 3; YER := 1992

END;


Оператор WITH V1, V2,...,Vn DO S;

эквивалентен последовательности операторов присоединения

WITH V1 DO WITH V2 DO ... WITH Vn DO S;

Вот как массив строк может помочь распечатать (выдать на экран) данное перечислимого типа (день недели 1 января 1901 года):

program datas;

type

week_day=(Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday);

dat=1..31;

month=(January,Fabruary,March,April,May,June,July,

August,September,October,November,December);

year=1900..2100;

attr_of_day=record

w_d:week_day;

d:dat;

m:month;

y:year

end;

var

today:attr_of_day;

kol:integer;

prn_week_day:array[week_day] of string[9]


function pred_week_day(w:week_day):week_day;

begin

if w=Monday then pred_week_day:=Sunday else pred_week_day:=pred(w)

end;


function pred_month(m:month):month;

begin

if m=January then pred_month:=December else pred_month:=pred(m)

end;


procedure pred_dat(var t:attr_of_day);

begin

if t.d=1 then

begin

t.m:=pred_month(t.m);

if t.m=December then t.y:=t.y-1;

case t.m of

January,March,May,July,August,October,December:t.d:=31;

Fabruary:if (t.y mod 4)=0 then t.d:=29 else t.d:=28;

April,June,September,November:t.d:=30

end

end else t.d:=t.d-1;

t.w_d:=pred_week_day(today.w_d);

end;


begin

prn_week_day[Monday]:=’Monday’

prn_week_day[Tuesday]:=‘Tuesday’

prn_week_day[Wednesday]:=‘Wednesday’

prn_week_day[Thursday]:=‘Thursday’

prn_week_day[Friday]:=‘Friday’

prn_week_day[Saturday]:=‘Saturday’

prn_week_day[Sunday]:=‘Sunday’

today.w_d:=Monday;

today.d:=2;

today.m:=October;

today.y:=2006;

repeat

pred_dat(today);

if (today.y<=2000) and (today.w_d=Monday) and (today.d=13)

then kol:=kol+1;

until (today.y=1901) and (today.m=January) and (today.d=1);

writeln('Kol= ',kol:4);

writeln(prn_week_day[today.w_d])

end.