Алгоритмический язык Паскаль

Общая характеристика языков программирования. Описание языка Паскаль: основные субъекты языка; структура Паскаль-программы; типизация и объявление данных. Операторы присваивания и выражения. Структурные операторы, организация ветвлений и циклов.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 26.01.2011
Размер файла 276,6 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

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

program PLOCHAD_1;

var AB,BC,CD,AD,BD,S1,S,a,b,c,p:real;

procedure GERON_1;

begin p:=(a+b+c)/2;

S:=sqrt(p*(p-a)*(p-b)*(p-c));

end;

begin {*ОСНОВНАЯ ПРОГРАММА*}

read (AB,BC,CD,AD,AC);

a:=AB;b:=AD;c:=BD; GERON_1; S1:= S;

a:=BC;b:=CD;c:=BD; GERON_1; S1:= S1+S;

write(S1);

end.

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

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

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

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

параметры-аргументы - это константы, переменные, выражения;

параметры-результаты - это всегда переменные.

Рассмотрим заново программу вычисления площади четырехугольника. В ней все переменные объявлены в основной программе. Однако среди них есть переменные, которые задействованы только в процедуре. Это переменные A, B, C, P, S. Такие переменные принято называть локальными по отношению к процедуре. Остальные переменные называются глобальными. Среди локальных переменных можно выделить параметры-аргументы A, B, C и параметр-результат S. Принято формальные параметры описывать в заголовке процедуры с указанием их типа. Локальная же переменная P является вспомогательной и описывается в процедуре так же, как в основной программе.

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

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

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

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

Глобальные переменные объявляются в разделе VAR основной программы. Глобальные переменные называют глобальными, потому что они могут фигурировать не только в основной программе, но и в теле процедуры. Заметим, что иногда одна и та же переменная может быть и локальной, и глобальной. Например, если переменная J является одновременно локальной и глобальной, то локальная переменная J отличается от переменной J из главной программы. Изменения, происходящие с J в процедуре, не влияют на значение переменной J из главной программы, и наоборот. Это происходит потому, что, несмотря на сходство имен переменных, компилятор отводит локальной переменной J одну ячейку памяти, а глобальной переменной J - другую. Обычно стараются избегать совпадения имен переменных во избежание нежелательных посторонних эффектов, которые могут возникнуть из-за использования одних и тех же имен для разных переменных.

Для ясности рассмотрим пример, связанный с использованием локальных и глобальных переменных:

program NEST;

var A,B:integer;

procedure NESTEGG;

var A,X: char;

begin

A:= "!";

X:= "?";

B:= B+1;

end;

begin { ОСНОВНАЯ ПРОГРАММА }

A:= 0; B:= 100;

NESTEGG;{ ВЫЗОВ ПРОЦЕДУРЫ }

writeln(A,' ',B);

end.

В этой программе X - локальная переменная для процедуры NESTEGG, поэтому основная программа не может ни изменить ее значение, ни обратиться к ней. С другой стороны, переменная B (глобальная) известна и в программе, и в процедуре. Если переменная B является глобальной, т.е. объявлена в главной программе, то все входящие в состав этой главной программы процедуры могут ссылаться к ней, но только в том случае, если в них нет другого объявления для B. Любое объявление имени в процедуре делает недоступным объект, имеющий то же самое имя и объявленный в основной программе. Так, у нас A для основной программы есть INTEGER, но в процедуре есть A типа CHAR. Процедуре NESTEGG недоступна переменная A из главной программы. Все изменения, происходящие с A в процедуре, становятся несущественными при выходе из этой процедуры. Но, поскольку B известна в главной программе, то все изменения с B в процедуре важны и сохраняются после выхода из нее. Итак, будет напечатано: 0 101.

Как было сказано ранее, процедуры с параметрами-значениями требуют входных данных (смотри п. 5.1). Где они записываются и как задаются? На этот вопрос может ответить синтаксическая диаграмма заголовка процедуры:

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

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

Рассмотрим работу процедур такого типа на примерах.

ПРИМЕР 1. Нарисовать квадрат с произвольной длиной стороны в левом верхнем углу (длина стороны задается с клавиатуры).

В этой программе также надо оформить рисование квадрата в виде процедуры, но уже с входным параметром-аргументом - длиной стороны квадрата:

program RISUNOK_2;

var I: integer;

procedure KVADRAT(N: integer);

var J,K: integer;

begin

for J:=1 to N do write('*'); writeln;

for J:=1 to N-2 do

begin

write('*'); for K:=1 to N-2 do write(' ');

writeln('*');

end;

for J:=1 to N do write('*');

end;

begin { Основная программа }

write('Введите длину стороны - ');

readln(I); clrscr; KVADRAT(I);

end.

ПРИМЕР 2. Вычисление площади четырехугольника с применением процедуры с параметрами-значениями:

program PLOCHAD_2;

var AB,BC,CD,AD,AC,S1,S: real;

procedure GERON_2(a,b,c: real);

var P: real;

begin

P:= (a+b+c)/2; S:= sqrt(P*(P-a)*(P-b)*(P-c));

end;

begin {*ОСНОВНАЯ ПРОГРАММА*}

read (AB,BC,CD,AD,AC); GERON_2(AB,BC,AC); S1:= S;

GERON_2(AD,AC,CD); write ('S = ', S1+S)

end.

В данной программе определена процедура GERON_2 с тремя параметрами-значениями и локальной переменной P. Значение же площади треугольника помещается в глобальную переменную S. При вызове этой процедуры формальные параметры a, b, c замещаются на фактические параметры AB, BC, AC при первом обращении, и на AD, AC, CD - при втором.

Заметим также, что здесь фактические параметры представлены переменными, которые получают свое значение с помощью процедуры READ. Однако, если известны длины сторон треугольника, например, 6, 7, 4, то можно вычислить площадь этого треугольника, вызвав процедуру GERON_2(6,7,4), и получить ответ в переменной S.

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

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

Например:

PROCEDURE PRIMER(VAR a,b,c:INTEGER; VAR m:CHAR; VAR i,j:REAL);

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

ПРИМЕР 1. Обмен значениями переменных A и B

program ZERKALO;

var A,B: integer;

procedure OBMEN(var X,Y: integer);

begin X:= B; Y:= A end;

begin

A:= 1; B:= 2; writeln(A,B);

OBMEN(A,B); write(A,B);

end.

ПРИМЕР 2. Вычисление площади четырехугольника

program PLOCHAD_3;

var AB,BC,CD,AD,AC,S1,S2,a,b,c: real;

procedure GERON_3(var S: real);

var P: real;

begin

P:= (a+b+c)/2; S:= sqrt(P*(P-a)*(P-b)*(P-c));

end;

begin { Основная программа }

read (AB,BC,CD,AD,AC);

a:=AB; b:= BC; c:= AC; GERON_3(S1);

a:=AD; b:= AC; c:= CD; GERON_3(S2);

write ('S = ', S1+S2)

end.

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

НАПРИМЕР:

PROCEDURE PRIMER(VAR a,b,c:INTEGER; m:CHAR; VAR i,j:REAL);

Здесь a,b,c,i,j - параметры-результаты (переменные);

m - пераметр-аргумент (значение).

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

program PLOCHAD_4;

var AB,BC,CD,AD,AC,S1,S2: real;

procedure GERON_4(a,b,c:real; var S: real);

var P: real;

begin

P:= (a+b+c)/2;

S:= sqrt(P*(P-a)*(P-b)*(P-c));

end;

begin {*ОСНОВНАЯ ПРОГРАММА*}

read (AB,BC,CD,AD,AC);

GERON_4(AB,BC,AC,S1);

GERON_4(AD,AC,CD,S2);

write ('S = ', S1+S2)

end.

ПРИМЕЧАНИЕ. Для более полного усвоения введенных ранее терминов перечислим на базе последнего примера все виды параметров и переменных:

- глобальные переменные AB, BC, CD, AD, AC, S1, S2;

- локальные переменные a, b, c, S, P;

- формальные параметры a, b, c, S;

a) параметры-значения (аргументы) a,b,c;

б) параметр-переменная (результат) S;

- фактические параметры AB, BC, CD, AD, AC, S1, S2;

a) параметры-значения (аргументы) AB, BC, CD, AD, AC;

б) параметры-переменные (результаты) S1,S2.

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

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

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

Именно поэтому, объявив в процедуре параметр-результат как параметр-значение, этот результат так и останется в формальном параметре-переменной без его передачи в соответствующий фактический параметр.

5.2 Функции пользователя. Рекурсивные функции

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

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

FUNCTION имя (список параметров: тип): тип;

или

FUNCTION имя: тип;

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

Итак, заголовок функции отличается от заголовка процедуры не только сменой слова PROCEDURE на FUNCTION, но и удалением из списка параметров параметра-результата с присвоением его типа имени функции:

PROCEDURE <имя процедуры>(аргументы; VAR параметр-результат: тип);

| |

FUNCTION <имя функции> (аргументы): тип;

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

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

Известно, что Паскаль имеет набор стандартных функций. Однако этот набор ограничен. Пользователь может по желанию расширить список функций, создав свои функции - функции пользователя. Так, например, в Паскале есть SQR(X) = X2, а вот функции F(X)= Xn, где n принадлежит множеству целых чисел Z, нет. Используя определенное ранее понятие функции, можно создать для этого универсальную функцию, которая давала бы степени произвольного вещественного числа с любым целым показателем.

Определим вещественную функцию POWER, которая должна иметь два параметра-аргумента - для показателя и для основания степени:

function POWER (FACTOR:real;EXPONENT:integer):real;

var COUNT: integer; TFACTOR: real;

begin

¦ if EXPONENT = 0 then POWER:= 1

¦ else begin

¦ ¦ TFACTOR:= FACTOR;

¦ ¦ for COUNT:= 2 to ABS(EXPONENT) do

¦ ¦ TFACTOR:= TFACTOR*FACTOR;

¦ ¦ if EXPONENT<0 then POWER:= 1/TFACTOR

¦ ¦ else POWER:= TFACTOR

¦ end

end;

Теперь можно эту функцию вызывать следующим образом:

а) РI:=POWER(3.14,1);

б) WRITELN("PI=",POWER(3.14,1):5:2);

в) IF X > 2*POWER(6.2,3) THEN WRITE('ДА');

г) A:= POWER(X,2) + POWER(X,3) + POWER(X,4).

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

В математике известно рекурсивное определение факториала:

n! = 1, при n = 0;

n! = (n-1)!n, при n > 0.

Это рекурсивное определение можно реализовать с помощью соответствующей рекурсивной функции:

function FACTORIAL(VALUE:integer):integer;

begin

iF VALUE=0 then FACTORIAL:=1

else FACTORIAL:= VALUE*FACTORIAL(VALUE-1)

end;

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

program FINDFACTORIAL;

var N:integer;

begin

writeln('Введите число');

readln(N);

if N<0 then writeln('Нет факториала')

else writeln('Фактрориал',N,'равен',FACTORIAL(N))

end.

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

FACTORIAL:= VALUE*FACTORIAL(VALUE-1), где происходит вызов определяемой функции. Здесь идентификатор FACTORIAL в левой части оператора обозначает имя переменной для хранения значения функции, а в правой - имя вызываемой функции.

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

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

Рассмотрим рекурсивный процесс на примере вычисления факториала для N = 3. Получим следующие шаги:

1) N = 3, где N<>0, следовательно, FACTORIAL:=3*FACTORIAL(2);

2) N = 2, где N<>0, следовательно, FACTORIAL:=2*FACTORIAL(1);

3) N = 1, где N<>0, следовательно, FACTORIAL:=1*FACTORIAL(0);

4) N =0, следовательно, FACTORIAL:=1,

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

В выражение 1*FACTORIAL(0) вместо FACTORIAL(0) подставляется его значение 1, вычисляется произведение 1*1 и оно становится значением FACTORIAL(1). В выражение 2*FACTORIAL(1) вместо FACTORIAL(1) подставляется значение 1, вычисляется 2*1 и становится значением FACTORIAL(2). В выражение 3*FACTORIAL(2) вместо FACTORIAL(2) подставляется значение 2, вычисляется 3*2 и становится значением переменной FACTORIAL, которая возвращает в основную программу значение 3!.

Весь этот двухэтапный рекурсивный процесс реализуется в памяти ЭВМ с помощью организации в ней стека рекурсии. Дело в том, что для хранения значений переменной N (а значит, и переменной VALUE) отводится не одна ячейка, а стек с именем N. В этот стек последовательно заносятся значения 3, 2, 1, 0, причем значение 0 есть признак конца заполнения стека. Затем начинает работать цикл с телом FACTORIAL:= FACTORIAL * N, где значения N выбираются последовательно из стека в порядке 1,2,3. Исходным же значением переменной FACTORIAL является 1, как значение 0!.

Работа стека представлена на следующей схеме:

Заполнение стека

Стек №

Вычисление

(углубление)

(разуглубление)

FACTORIAL:=1

0

FACTORIAL:=1

FACTORIAL:=1*FACTORIAL(0)

1

FACTORIAL:=1*FACTORIAL

FACTORIAL:=2*FACTORIAL(1)

2

FACTORIAL:=2*FACTORIAL

FACTORIAL:=3*FACTORIAL(2)

3

FACTORIAL:=3*FACTORIAL

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

Данная функция явно носит рекурсивный характер, исходя из ее определения: Xn = 1, если n = 0;

Xn = (Xn-1)*X, если n > 1.

function POWER(FACTOR:real; EXPONENT:integer): REAL;

begin

if EXPONENT < 0

then POWER:=1/POWER(FACTOR,abs(EXPONENT))

else if EXPONENT > 0

then POWER:= FACTOR*POWER(FACTOR,EXPONENT-1)

ELSE POWER:=1

end;

ЗАМЕЧАНИЕ. Помимо рекурсивных функций в языке Паскаль можно определять по тому же принципу и рекурсивные процедуры. Подробно о них будет сказано в следующих разделах, а пока покажем, как рекурсивная функция может быть переделана в рекурсивную процедуру на примере вычисления факториала:

procedure FACTORIAL(VALUE:integer; var F: integer);

begin

iF VALUE=0 then F:=1

else begin FACTORIAL(VALUE-1,F);

F:=F*VALUE

end;

end;

Здесь уже, в отличие от функции FACTORIAL, для вычисления N! необходимо вызвать эту процедуру с помощью оператора процедуры FACTORIAL(N,FN), где FN - переменная для возвращения из процедуры значения N!.

6. МАССИВЫ. ДАННЫЕ ТИПА ARRAY

Скалярный тип - простой тип данных. Скалярное данное неделимо. Массивы - это структурированные типы данных. Массив состоит из нескольких элементов. Ко всему массиву можно обращаться по его имени. Можно обращаться к его элементу, но для этого надо задать индекс (индексы). Массивы бывают одномерные и многомерные. Для объявления массива необходимо задать типы его индексов и компонент.

Тип компонент массива - это просто тип данных, ассоциированный с каждой компонентой массива. Тип компонент может быть любым REAL, INTEGER, CHAR, BOOLEAN, перечислимым, интервальным. В качестве компоненты массива может быть взят и тип массив.

Тип индекса должен быть одним из упорядоченных типов, т.е. любым скалярным типом, кроме REAL: INTEGER, CHAR, интервальный, перечислимый. Тип индекса определяет границы изменения индекса. Если сделана попытка использовать несуществующую компоненту, то возникает ошибка (ошибка неверного индекса).

6.1 Одномерные массивы

Одномерный массив можно задать двумя способами:

а) с помощью служебного слова TYPE описывается тип массива, а затем с помощью VAR вводится переменная этого типа;

б) с помощью слова VAR сразу описывается переменная типа массив;

Например, объявление массива из 100 элементов типа REAL можно осуществить следующими двумя способами:

а) type R100 = array[1..100] of real;

var A: R100;

б) var A: array[1..100] of real.

Здесь задан массив с именем "А" и его элементы имеют имена: А[1],..., A[100]. Чаще всего для типа индекса используют интервальный тип на основе типов INTEGER и CHAR. Однако можно в качестве индексов брать перечислимый тип.

ПРИМЕР 1. Подсчет числа вхождений букв в текст определенной длины

program COUNTER;

var COUNT: array['a'..'z'] of integer;

CH: char; N: integer;

begin

for CH:= 'a' to 'z' do

COUNT [CH]:= 0; N:= 0;

repeat

read(CH); N:= N+1;

if (CH >= 'a') and (CH <= 'z') then

COUNT [CH]:= COUNT [CH]+1;

until CH = '.';

for CH:= 'a' to 'z' do

writeln(CH, COUNT [CH]:10, COUNT [CH]*100/N:10:2);

end.

ПОЯСНЕНИЕ. В этом примере тип индекса есть интервальный тип на базе типа CHAR, а тип компонент есть целое число. Таким образом, элементы массива - числа, а их индексы - буквы, т.е. число элементов массива равно 26 (число букв латинского алфавита). Рассмотрим теперь случай, когда тип индекса задан перечислимым типом, а компоненты массива представлены компонентами интервального типа на базе типа INTEGER.

ПРИМЕР 2. Присваивание переменной с именем месяца числа дней этого месяца

DAY:

Значение элементов

31

28

31

30

31

30

31

31

30

31

30

31

Значение Индексов

JAN

FEB

MAR

APR

MAY

JUN

JUL

AUG

SEP

OKT

NOV

DEC

program NUMBRDAY;

type MONAT = (JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG,

SEP, OKT, NOV, DEC);

var DAY: array [MONAT] of 28..31; T: MONAT;

begin

for T:= JAN to DEC do

case T of

JAN, MAR, MAY, JUL, AUG, OKT, DEC: DAY[T]:= 31;

APR, JUN, SEP, NOV: DAY[T]:= 30;

FEB: DAY[T]:= 28;

end;

end.

6.2 Многомерные массивы

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

Например, таблица символов M x N, где M - число строк и N - число столбцов, может быть описана:

var TAB: array[1..M, 1..N] of char.

ОБЩАЯ ФОРМА ЗАПИСИ

VAR <имя>:ARRAY [тип индекса строки, тип индекса столбца]

OF <тип компонент>;

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

type LINE = array[1..N] of char;

STOLB = array[1..M] of LINE;

var TAB: STOLB.

Здесь TAB[I] - переменная типа LINE, а TAB[I][J] - переменная

типа CHAR.

ОБЩАЯ ФОРМА ЗАПИСИ

TYPE <тип строки>=ARRAY [тип индекса] OF <тип компонент>;

<тип столбца> = ARRAY[тип индекса] OF <тип строки>;

VAR <переменная массива>: <тип столбца(массива)>;

Эти два вида определения массивов задают и два способа обращения к элементам массива: TAB[I,J] - в первом случае и TAB[I][J] - во втором.

Вполне очевидно, что сказанное выше для двумерного массива распространяется и на массивы большей размерности. Например, описание VAR CUBE: ARRAY[1..M, 1..N, 1..K] OF INTEGER определяет задание трехмерного массива целых чисел.

6.3 Способы работы с массивами

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

ПРИМЕР 3. Сумма элементов таблицы над верхней диагональю

program SUMMA;

const M =...; {число строк таблицы}

N =...; {число столбцов таблицы}

type LINE = array[1..n] of integer;

TAB = array[1..m] of LINE;

var s,i,j:integer; MAS:TAB;

procedure VVODMASSIV(var MAS:TAB);

begin

¦ for i:=1 to M do

¦ for j:=1 to N do

¦ readln(MAS[i][j]);

end;

procedure VIVODMASSIV(var MAS:TAB);

begin

¦ for i:=1 to M do

¦ begin

¦ ¦ for j:=1 to N do

¦ ¦ write(MAS[i][j]:5,' '); writeln;

¦ end;

end;

procedure OBRABOTKA(MAS:TAB; var SUM:integer);

begin

¦ SUM:= 0;

¦ for i:=1 to M do

¦ for j:=1 to N do

¦ if j > i then SUM:= SUM+MAS[i][j];

end;

begin

¦ VVODMASSIV(MAS); writeln('исходный массив');

¦ VIVODMASSIV(MAS); OBRABOTKA(MAS,s);writeln;

¦ writeln('сумма элементов = ',s);

end.

7. ОБРАБОТКА ЛИТЕРНЫХ ВЕЛИЧИН. ДАННЫЕ ТИПА CHAR И STRING

В Паскале, как и в других языках программирования, предусмотрена обработка текстов или строк. Для этой цели в языке существуют два типа данных: SHAR и STRING.

7.1 Тип данных CHAR

Типу данных CHAR соответствуют символьные константы и переменные. Символьная константа есть какой-то символ алфавита, взятый в кавычки. Символьные переменные получают значения символьных констант через оператор присваивания:

ALPFA:='p'; A:='t'; B:='3'; C:=' '; D:=''.

Все символы алфавита образуют множество литер. Каждый символ имеет свой код в ASCII. Это позволяет использовать булевские сравнения: =, <>, <, <=, >, >=.

Данные этого типа описываются с помощью служебного слова CHAR.

Например, переменную ALPFA можно описать VAR ALPFA: CHAR.

ОБЩАЯ ФОРМА ЗАПИСИ: VAR <переменная>: CHAR;

При работе с данными типа CHAR, если у нас есть последовательность символов, существуют два способа ввода этих символов с клавиатуры.

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

ПРИМЕР 1. С клавиатуры последовательно вводятся символы. Признаком конца ввода является точка. Составить программу выбрасывания групп символов, расположенных между скобками (,). Сами скобки тоже выбрасываются

program SKOBKI;

var c: char; i: integer;

begin

¦ i:=0; read(c);

¦ while c <> '.' do

¦ begin

¦ ¦ if c='(' then i:=1

¦ ¦ else if c = ')' then i:=0

¦ ¦ else if i=0 then write(c);

¦ ¦ read(c);

¦ end;

end.

ПОЯСНЕНИЕ. I = 1 означает, что ранее была прочитана левая скобка, которой пока еще не нашлось парной правой. В этой ситуации прочитанные символы не выводятся на экран. В результате работы этой программы на экране будет представлена строка символов. Здесь вся последовательность символов вводится сразу по первому оператору READ, а затем в цикле из буфера клавиатуры выбираются, анализируются и печатаются символы вне круглых скобок. Например, если вводится последовательность "asg(zx)ytr.", то экран будет выглядеть так:

asg(zx)ytr. - результат работы оператора READ;

asgytr - результат работы оператора WRITE.

В этой программе можно было бы использовать оператор READLN, но тогда после набора каждого символа необходимо нажимать клавишу ввода. Кроме того, на экран будет выводиться не строка символов, а столбец, состоящий из вводимых и отпечатанных элементов. Например, при вводе последовательности "asg(zx)ytr." экран уже будет выглядеть так:

a g x t

a | g |) | t

s | (| y | r

s z y r.

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

ПРИМЕР 2. Программа вывода последовательности букв:

a,ab,abc,...,abc...xyz

program SUITE; РАБОТА ПРОГРАММЫ

var c,d: char; a

begin ab

for c:='a' to 'z' do abc

begin abcd

for d:='a' to c do write(d); abcde

writeln(' ');...

end; abcde...xyz

7.2 Массивы литер

В рассмотренных программах все символы вводились последовательно в процессе работы цикла или хранились временно в буфере клавиатуры. Это не всегда удобно. Поэтому в языках делают строки как последовательность литер. Строку можно задать, как массив литер, при этом в качестве длины строки может выступать верхняя граница массива. Например, VAR HAMLET: ARRAY[1..17] OF CHAR.

Здесь HAMLET - массив литер, компоненты которого имеют тип CHAR; индекс имеет нижнюю границу, равную 1, верхнюю - 17. Для ввода строки в массив HAMLET необходимо организовать цикл из 17 повторений. При каждом повторе этого цикла с клавиатуры вводится очередной символ строки и нажимается клавиша ввода:

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

for n:=17 downto 1 do write (HAMLET [n]).

ПРИМЕР 3. Дана последовательность символов CHAR: S1,S2,...,S10. Определить, совпадает ли начальная часть с ее конечной частью

program SOWPADENIE;

label 1;

type t = array[1..5] of char;

var s:t; y:char; i:integer;

begin

¦ for i:=1 to 5 do read(s[i]); readln;

¦ for i:=1 to 5 do

¦ begin

¦ ¦ read(y);

¦ ¦ if s[i] <> y then

¦ ¦ begin

¦ ¦ ¦ write('не совпадает');

¦ ¦ ¦ goto 1;

¦ ¦ end;

¦ end;

¦ write('совпадает'); 1:;

end.

ПОЯСНЕНИЕ. В данной программе сначала вводятся по циклу первые пять членов последовательности в массив S[I], причем все пять символов набираются сразу и набор завершается клавишей ввода. Затем с помощью оператора READLN очищается буфер клавиатуры, куда оператор READ(Y) заносит следующие пять символов. Во втором цикле из этого буфера поочередно выбираются символы и сравниваются с ранее введенными. Если все символы совпадают, то печатается текст 'совпадает'. В случае несовпадения печатается текст 'не совпадает' и дальнейшее считывание символов из буфера клавиатуры прекращается.

Чтобы не вводить всю вторую половину символов, а ограничиться только вводом до первого несовпадающего символа, необходимо в программе заменить оператор READ(Y) на оператор READLN(Y).

7.3 Тип данных STRING

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

Это не всегда удобно. Хотелось бы иметь такую переменную, в которую можно было бы поместить текст произвольной (но ограниченной) длины. Такую возможность предоставляет тип STRING. Здесь, объявив переменную:

var HAMLET: string[17],

можно ей путем оператора присваивания (а не через цикл) задать значение текста произвольной длины (от 0 до 17).

НАПРИМЕР:

HAMLET:= 'Быть или не быть';

HAMLET:= 'Бедный Йорик';

HAMLET:= ' '; HAMLET:= ''.

Отметим также, что при компиляции программы в случае объявления строки-массива в памяти ЭВМ резервируется место под массив, который должен быть полностью заполнен потом в процессе работы программы. Для типа STRING также резервируется место в памяти того же объема, но здесь необязательно его заполнять целиком. Незаполненные места представлены пробелами.

ОБЩАЯ ФОРМА ЗАПИСИ:

TYPE <имя типа> = STRING [N];

VAR <имя переменной>: <имя типа>;

или

VAR <имя переменной>: STRING [N];

Здесь N - целая константа, задающая максимальную длину текста.

Доступ к элементам строки производится с помощью индексов, т.к. в этом типе также все элементы имеют свой (числовой) индекс от 1 до N. В результате получается величина типа CHAR.

НАПРИМЕР: HAMLET:= 'ПРОГРАММА';

HAMLET [1] = 'П'; HAMLET [9] = 'А'.

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

Текущая длина строковой переменной может быть определена с помощью встроенной функции LENGTH. Например, можно распечатать в цикле значение строки HAMLET:

for c:=1 to length(HAMLET) do write(HAMLET [c]).

Конечно, подобные циклы не надо использовать в реальных программах. Переменные типа STRING могут быть напечатаны с помощью единственного оператора WRITE или WRITELN. Для того, чтобы ввести значение типа STRING, необходимо использовать READLN или READ.

При этом, в отличие от ввода строки-массива, в типе STRING вся строка вводится целиком - клавиша ENTER нажимается один раз после последнего введенного символа.

ПРИМЕР 4. С клавиатуры вводится последовательность слов длиной в 4 символа. Напечатать эти слова, пока не встретится слово STOP.

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

repeat

readln(LINE_OF_TEXT); writeln(LINE_OF_TEXT);

until LINE_OF_TEXT = 'STOP',

где LINE_OF_TEXT есть переменная типа STRING[4].

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

символа, а оператор WRITELN - печатать это слово:

repeat

read(LINE_OF_TEXT);

writeln(LINE_OF_TEXT);

until LINE_OF_TEXT = 'STOP'.

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

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

7.4 Строковые функции и процедуры

Они введены для облегчения манипуляции со строками. Имеется 8 строковых функций и процедур.

1. Функция CONCAT (склеивание).

Синтаксис: concat(S1, S2,..., Sn: string): string.

Возвращает строку, полученную конкатенацией строк S1,...,Sn.

ПРИМЕР: NUMBER:= concat('12','34','50'); NUMBER = '123450'.

2. Функция LENGTH(длина).

Синтаксис: length(S: string): integer.

Возвращает длину строки S.

ПРИМЕР: N:= length('345'); N = 3.

3. Функция POS(позиция).

Функция POS в качестве аргументов использует две строки и определяет, содержится ли первая строка во второй. Возвращает номер символа, начиная с которого S входит в T. Если вхождения нет, то возвращает 0.

ПРИМЕР: N:= pos('E','HELLO'); N:= pos('A','HELLO');

N = 2. N = 0.

4. Функция COPY(вырезка фрагмента).

Синтаксис: copy(S: string; N1,N: integer): string.

Возвращает подстроку, полученную из N символов строки S, начиная с позиции N1. Значение переменной S при этом не меняется.

ПРИМЕР: FRAGMENT:= copy('PROGRAMM',2,3);

FRAGMENT = 'ROG'.

5. Процедура DELETE (стирание фрагмента).

Убирает из строки S LEN символов, начиная с POS, при этом длина строки уменьшается на LEN позиций.

ПРИМЕР: delete(FRAGMENT,2,3);

FRAGMENT:= 'PROGRAMM'; FRAGMENT = 'PRAMM'.

6. Процедура INSERT(вставка).

Синтаксис: insert(S: string; var D: string; POS: integer).

Вставляет строку S в строку D перед символом с номером POS, при этом длина строки D увеличивается на LENGTH(S) позиций.

ПРИМЕР: insert ('ROG', FRAGMENT, 2);

FRAGMENT:= 'PRAMM'; FRAGMENT = 'PROGRAMM'.

7. Процедура STR(преобразование в строку).

Синтаксис: str(I: integer; var S: string);

str(R: real; var S: string).

Преобразует I или R из числа в строку и записывает эту строку в S, причем R и I могут записываться форматно, как в процедуре WRITE.

ПРИМЕР: a) R:= 123.654; str(R:5:2, S); S = '123.65';

б) I:= 5683; str(I, S); s = '5683'.

8. Процедура VAL(преобразование в число).

Синтаксис: val(S: string; var I, J: integer).

val(S: string; var I: real; var J: integer).

Преобразует строковую переменную S в число типа I. Переменная J получает значение 0, если перевод прошел без ошибок. Если же сделана попытка конвертировать в число строку, где есть нецифровые символы, то переменная J принимает значение позиции первого нецифрового символа, при этом работа процедуры будет прервана.

ПРИМЕР: S:= '4326'; S:= '43p8';

val (S,I,J); val (S,I,J);

I = 4326, J = 0 I - не определено, J = 3.

Рассмотрим теперь пример на применение указанных функций и процедур обработки строк.

ПРИМЕР 4. Изменение порядка слов в строке

program REVERSE;

var OLD_LINE, NEW_LINE: string[50];

PROBEL: integer; WORD: string[50];

begin

¦ NEW_LINE:= ''; readln(OLD_LINE);

¦ OLD_LINE:= concat(OLD_LINE,' ');

¦ while OLD_LINE <> '' do

¦ begin

¦ ¦ PROBEL:= pos(' ', OLD_LINE);

¦ ¦ word:= copy(OLD_LINE, 1, PROBEL);

¦ ¦ NEW_LINE:= concat(WORD, NEW_LINE);

¦ ¦ delete(OLD_LINE, 1, PROBEL);

¦ end;

¦ writeln(NEW_LINE)

end.

ПОЯСНЕНИЕ. С клавиатуры вводится строка OLD_LINE и к ней справа подклеивается пробел. Это делается для того, чтобы строка имела одну и ту же структуру: слово плюс пробел. Затем в цикле, признаком конца которого является пустая константа, выделяется очередное по порядку слово и подклеивается слева в переменную NEW_ LINE. После выборки очередного слова из OLD_LINE оно оттуда выбрасывается, что приводит к постепенному уменьшению строки. Здесь переменная PROBEL служит для хранения позиции первого пробела в строке, а WORD - для выбранного из OLD_LINE слова.

Например, строка ' Наша Таня громко плачет' преобразуется в строку ' плачет громко Таня Наша'.

8. МНОЖЕСТВА. ДАННЫЕ ТИПА SET

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

Стандартные: REAL, INTEGER, CHAR, BOOLEAN. Для каждого из этих типов рассматриваются соответствующие операции над его элементами. В Паскале имеются средства, позволяющие определять, исходя из имеющихся типов, новые нестандартные типы. Примерами таких нестандартных типов являются данные типа STRING и ARRAY, т.е. литерный тип и массивы. Массив - это упорядоченный набор данных одного типа, у каждого из которых есть индекс (номер). Способ индексации, тип элементов, длина массива содержатся в определении того типа, которому принадлежит массив:

TYPE T = ARRAY[1..20] OF REAL.

Это определение типа, имя которого T. Объектами типа T будут упорядоченные наборы по 20 элементов, имеющих тип REAL; диапазон изменения значения индекса от 1 до 20. Определив с помощью TYPE тип T, можно теперь описать некоторую переменную этого типа:

VAR А: T.

Значениями переменной "А" будут массивы длины 20, элементы которых имеют тип REAL. Для того, чтобы рассматривать эти элементы по отдельности, применяются обозначения A[1], A[2],..., A[20].

Переменная А - переменная типа T, переменные A[1],...,A[20] - переменные типа REAL. С ними можно обращаться как с обычными переменными типа REAL: X, Y, Z и т.д. В квадратных скобках необязательно должно быть целое число, им может быть произвольное выражение типа INTEGER, например: A[I], A[2*I], A[2*I-1]. Значение индекса обязано лежать в указанном диапазоне от 1 до 20. Операции над объектами типа T - это доступ к отдельным элементам массивов через индексы и изменение отдельных элементов массивов с помощью операций, связанных с типом REAL.

Итак, если в Паскаль-программе определен тип с помощью конструкции ARRAY..OF, то он называется регулярным типом. Общий вид регулярного типа есть:

type U = array [N1..N2] of R.

Тип R называется базовым по отношению к типу U. Объекты регулярного типа называются массивами. Пусть R в свою очередь определен как регулярный тип:

type R = array [M1..M2] of S;

и пусть переменная А - переменная типа U. Тогда A[I] - переменная типа R, а А[I][J] - переменная типа S. Таким образом, получается переменная, представляющая собой двумерный массив как массив массивов.

8.1 Определение типа множество

Переменные типа массив относятся к так называемым структурированным типам данных. В языке Паскаль имеются и другие структурированные типы данных, к которым принадлежит и тип данных множество. Математическое понятие множества подразумевает совокупность элементов. В отличие от массива (одномерного) множество состоит из элементов, где порядок их следования не играет роли:

{1,3,5}, {5,3,1}, {1,5,3} - одно и то же множество.

В математике для обозначения множеств используются скобки {,}. В Паскале вместо фигурных скобок для представления множеств используются квадратные: [1,3,5].

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

ОБЩАЯ ФОРМА ЗАПИСИ:

TYPE <имя типа>: SET OF <тип компонент>;

VAR <имя переменной>: <имя типа>;

или

VAR <имя переменной>: SET OF <тип компонент>;

ПРИМЕРЫ: var LETTERS: set of 'A'..'Z';

DAYS: set of 1..31; MNOGCHAR: set of char.

Итак, мы увидели, что в описании типа множество есть общее с описанием типа массив, но есть и существенные отличия:

а) нет типа индекса (элементы множества не индексируются);

б) есть, как в массиве, тип компонент.

НАПРИМЕР:

type DAYSOFWEEK = (SUN, MON, TUE, WED, THU, FRI, SAT);

var WEEKDAYS, WEEKEND: set of DAYSOFWEEK.

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

a) WEEKDAYS:= [MON, TUE, WED, THU, FRI];

б) WEEKEND:= [SAT, SUN],

причем в случае а) можно поступить иначе: WEEKDAYS:= [MON..FRI].

Заметим также, что указанные множества из элементов перечислимого типа нельзя сформировать с помощью оператора READ (в силу специфики этого типа).

Аналогом нуля в типе множество есть пустое множество: [].

8.2 Операции над множествами

Над множествами можно производить следующие операции:

1. Определение принадлежности элемента множеству.

2. Сравнение множеств.

3. Действия над множествами.

Рассмотрим подробнее эти операции.

Принадлежность множеству

В языке Паскаль обеспечен механизм для определения принадлежности некоторого значения множеству его элементов. Этот механизм реализуется в рамках создания булевского выражения с использованием оператора IN. Структура применения этого оператора имеет вид:

В результате работы этого оператора получается булевское выражение. Например, выражения WED in WEEKDAYS, SAT in WEEKEND являются истинными булевскими выражениями, а выражения SAT in WEEKDAYS, MON in WEEKEND являются ложными.

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

ПРИМЕР 1. Пусть переменная DAY принимает значения всех дней недели. Тогда можно написать программу печати, где этот день недели является рабочим или днем отдыха:

for DAY:= SUN to SAT do

if DAY in WEEKDAY

then WRITELN('Сегодня рабочий день')

else WRITELN('Сегодня день отдыха').

Заметим, что здесь перед циклом нужно определить переменную DAY как переменную перечислимого типа:

var DAY: DAYSOFWEEK.

Итак, мы видим, что на базе перечислимого типа DAYSOFWEEK можно сформировать переменную DAY и множества WEEKDAYS и WEEKEND.

Булевское выражение на базе IN можно сочетать с другими типами булевских выражений.

НАПРИМЕР:

if (DAY in WEEKEND) and (DAY <> SAT) then

writeln('Сегодня - воскресенье').

Множества имеют различные применения в организации программ.

Одним из них является упрощение написания оператора IF.

Рассмотрим два примера:

1) if (T=0) or (T=32) or (T=212) or (T=276) then...

2) if T in [0, 32, 212, 276] then...

Эти операторы эквивалентны, но второй значительно проще.

Использование множеств позволяет улучшить наглядность и понимание алгоритма работы программы. Например, можно определить, является ли литерная переменная, именуемая ONE_CHAR, цифрой, записав: if ONE_CHAR in ['0'..'9'] then...

Действия над множествами

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

а) объединение;

б) пересечение;

в) разность.

Рассмотрим эти операции подробно, но предварительно произведем описание:

type COUNTRIES = (ENG, FR, USA, SP, IT);

var MAP1, MAP2: COUNTRIES.

а) ОБЪЕДИНЕНИЕ (+):

[ENG, FR] + [IT]-> [ENG, FR, IT];

б) ПЕРЕСЕЧЕНИЕ (*):

[ENG, FR, USA] * [ENG, USA, IT] -> [ENG, USA];

в) РАЗНОСТЬ (-):

[ENG..IT] - [ENG..SP] -> [IT].

Эти три операции используются для построения выражений над множествами.

НАПРИМЕР: MAP1:= [FR]; MAP1:= MAP1 + [USA]; MAP2:= MAP1;

MAP1:= MAP1 * (MAP2 + [IT]).

ПРИМЕР 2. РЕШЕТО ЭРАТОСФЕНА. Найти простые числа, не превосходящие заданного.

Алгоритм базируется на вычеркивании чисел, кратных выбранному:

program ERATOS;

const MAXPRIM = 15;

var PRIMES: set of 2..MAXPRIM;

COUNT, MULTIPLE: integer;

begin

¦ writeln('простые числа, меньше ', MAXPRIM);

¦ PRIMES:= [2..MAXPRIM];

¦ for COUNT:= 2 to MAXPRIM do

¦ if COUNT in PRIMES then

¦ begin

¦ ¦ writeln(COUNT);

¦ ¦ for MULTIPLE:=1 to (MAXPRIM div COUNT) do

¦ ¦ PRIMES:= PRIMES-[COUNT*MULTIPLE]

¦ end;

end.

ПОЯСНЕНИЕ. Начинаем с набора множества, состоящего из всех целых чисел в интервале 2..15. Программа при помощи цикла FOR проверяет каждое целое число, входящее в множество. Если целое число является элементом множества, то оно печатается, и из множества удаляются все целые числа, кратные данному числу.

Сравнение множеств

Операция IN весьма полезна, и она позволяет, например, выяснить, являются ли два множества равными. Например, если мы хотим узнать, равны ли множества MAP1 и MAP2, то можно написать:

EGALE:= true;

for MEMBER:= ENG to IT DO

if (MEMBER in MAP1) <> (MEMBER in MAP2) then EGALE:= false.

Это громоздко, поэтому в Паскале есть булевские выражения с применением операций сравнения: =, <>, >=, <=.

НАПРИМЕР: MAP1 = MAP2;

MAP1 <> MAP2;

MAP1 - MAP2 <> [FR];

MAP1 + MAP2 <> [ENG..IT];

MAP1 >= MAP2 (eсли выражение истинно, то MAP2 есть подмножество MAP1).

8.3 Печать множеств

При работе с множествами немаловажным является вопрос распечатки элементов множества. Отметим, что в большинстве версий языка в операторах WRITE нельзя называть переменные типа "множество". Например, нельзя распечатать множество таким образом:

VAR A: SET OF 1..9;

WRITE(A).

Здесь нет ничего удивительного, т.к. даже если А есть массив, то его тоже нельзя распечатать сразу с помощью одного оператора WRITE(А). Для вывода элементов массива организуются циклы.

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

if K in SET1 then write(K).

Как правило, для целей распечатки элементов множеств организуются свои процедуры. Пусть мы имеем дело с множествами, состоящими из целых чисел в границах NIZ и VERH. Зададим множественный тип TS для этих границ:

type INT = NIZ..VERH; TS = set оf INT.

Тогда можно написать процедуру, содержащую в качестве параметра множество:

procedure PRINTSET (OS: TS);

var M: INT;

begin

¦ for M:= NIZ to VERH do

¦ if M in OS then writeln(M);

end.

Теперь можно обращаться к этой процедуре для печати множеств, если только они состоят из элементов, не выходящих из интервала NIZ..VERH. Пусть в разделе констант было описано:

const NIZ = 0; VERH = 10;

тогда можно распечатать множества, обратившись к процедуре:

а) PRINTSET ([5,6,7]); б) PRINTSET ([2]); в) PRINTSET ([3..8]).

Обращение к процедуре можно организовать также в виде:

var SET1, SET2: TS;

SET1:= [..... ]; SET2:= [......]

PRINTSET (SET1); PRINTSET (SET1+SET2); и т.д.

ПРИМЕР 3. В заключение рассмотрим пример целиком, где продемонстрируем все те действия, которые определены над множествами:

program IGRA;

type KOST = 1..6; BROSOK = set of KOST;

var A,B,C: BROSOK;

procedure SRAWNENIE (D: BROSOK);

var K: KOST;


Подобные документы

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

    лекция [55,7 K], добавлен 21.05.2009

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

    курсовая работа [290,9 K], добавлен 05.12.2008

  • Алгоритмы и алфавит языка Турбо Паскаль. Основные типы данных. Операторы присваивания, перехода и выбора. Понятие массива в Паскале. Особенности работы со строками в программе. Использование линейного поиска и поиска с барьером. Основные виды сортировок.

    учебное пособие [53,2 K], добавлен 09.11.2009

  • Общая характеристика языка программирования Турбо Паскаль: операторы, циклы, файлы. Процедуры и функции модуля Crt. Структурная и функциональная схема программы учета учащихся, таблица идентификаторов. Список и описание использованных подпрограмм.

    курсовая работа [702,9 K], добавлен 29.01.2011

  • История и основы структурного программирования в среде Turbo Pascal. Работа с различными типами данных. Операторы языка. Работа с символьными и строковыми переменами, одномерным, двумерным массивами. Классификация компьютерных игр. Игры на языке Паскаль.

    курсовая работа [28,8 K], добавлен 06.05.2014

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

    курсовая работа [78,9 K], добавлен 28.12.2012

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

    лабораторная работа [189,8 K], добавлен 17.04.2012

  • Разработка консольного приложения, которое обрабатывает входной файл с расширением .pas и транслирует в выходной файл с расширением .cpp или .txt (по выбору пользователя). Синонимичные операторы языков Паскаль и С. Разработка алгоритма решения задачи.

    курсовая работа [329,6 K], добавлен 04.06.2013

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

    курсовая работа [305,9 K], добавлен 03.07.2011

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

    лабораторная работа [15,7 K], добавлен 12.06.2010

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.