Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по программированию..pdf
Скачиваний:
10
Добавлен:
15.11.2022
Размер:
12.2 Mб
Скачать

4.Выделение операндов. Проверка операндов на допустимый диа­ пазон значений. Перевод в целые числа.

5.Выполнение операции. Проверка результата на допустимый ди­ апазон.

6.Вывод результата.

Program Interpretator;

Type Pozlnt - 0..Maxlnt

Var Line String;

A, В Pozlnt;

Znak Char;

Flag Boolean;

Rezult

Integer;

String; M Byte; Var N Byte);

Procedure Propusk(Stroke

Begin

 

 

{ ---------------------- - .................

- ....................................

Пропускает подряд стоящие пробелы в строке Stroka, начиная с символа номер М. В переменной N подучает номер первого символа, не являющегося пробелом.

End;

 

 

 

 

Function

Cifra(C

Char)

Boolean;

Begin

 

 

 

 

{ ...........

- .......................

 

- ..................................................

если символ с является цифрой,

 

Получает значение True,

 

и False - в противном случае.

Function

Sintах(Stroka

String)

Boolean;

Begin

 

 

 

 

{ .............

............ ...............

 

- ...................................................

 

Синтаксический контроль. Получает значение True, если в строке нет других символов хроме цифр, знаков операции, знака и пробелов. В противном случае - False.

End;

Function Semantika(Stroka String) Boolean;

Begin

{ ---------------------------------------------------------------------------------

Проверяет, соответствует ли структура строки формату

"а@Ъ«"? Если ”да”, то получает значение True, если

"нет”

False.

 

}

-----------------------------------------

 

-------------

End;

 

 

 

Procedure Operand(Stroka

String; Var A, В

Pozlnt;

Begin

Var Z

Char; Var Flag

Boolean);

 

 

 

{ ........................

-

................. - ------------------------------------------

Выделяет операнды. Проверяет их на допустимый диапазон значении. Переменная Flag получает значение True,

если результат проверки положительный, и False - в противном случае. Преобразует операнды в целые положительные числа А, В. В переменной Z получает знак операции.

---------------------------- >

End;

 

 

 

 

Procedure Calc(А,

В Pozlnt; Znak

Char; Var Rez

Integer;

Var Flag

Boolean);

 

 

Begin

 

 

 

 

{ ----------------------------------------------------------------------

результат

операШШ.

Проверяет

-----------

Вычисляет

 

принадлежность результата диапазону от -Maxlnt д<?

Maxlnt. Flag - признак результата проверки. Результат операции получается в переменной Rez.

------------------------ ----------- ----------- .------>

End;

Begin {------- Начало основной части программы ----} WriteLnOВведите выражение: *);

WriteLn;

Read(Line);

If Not Sintax(Line)

Then WriteLn(* Недопустимые символы’)

Else If Not Semantika(Line)

Then WriteLnО Неверное выражение’)

Else Begin

Operand(Line, A, B, Znak, Flag);

If Not Flag

Then WriteLn( ’Слишком большие операнды’)

Else Begin

Calc(A,В ,Znak,Rezult,Flag);

If Not Flag

Then WriteLn(’Большой результат1)

Else WriteLn(Rezult)

End

End

Теперь будем составлять подпрограммы.

Procedure Propusk(Stroka

String; М Byte; Var N

Byte);

Begin

M;

 

 

N

*) And (N < Length(Stroka))

Do

While

(StrokaCN] =

N := N + 1

End;

Function Cifra(C Char) Boolean;

Begin

Cifra := (С >= >0’) And (C <= >9>)

End;

Function

Sintax(Stroka

String)

 

Boolean;

Var I

Byte;

 

 

 

 

 

Begin

:= True;

 

 

 

 

Sintax

 

 

 

 

For I :■ 1 To Length(Stroka) Do

 

 

If Not

((StrokaEl]*’ ’) Or Cifra(Stroka[I]) Or (StrokaE^*^’)

 

Or (Stroka[l]ss,->) Or

(Stroka[I] =,*>) Or (Stroka[I] = ,=>))

Then Sintax := False

 

 

 

End;

 

 

 

 

 

 

Function

Semantika(Stroka

String)

Boolean;

Var I

Byte;

 

 

 

 

 

Begin

 

 

 

 

 

 

Semantika :■ True;

I);

 

 

 

Propusk(Stroka,

1,

 

 

 

If Not Cifra(Stroka[I])

 

 

 

Then

 

 

 

 

 

 

Begin

 

 

 

 

 

 

Semantika := False;

 

 

 

Exit

 

 

 

 

 

 

End;

 

 

 

 

 

 

While Cifra(Stroka[I]) Do

 

 

I:=I+1;

I,

I);

 

 

 

Propusk(Stroka,

 

 

 

If Not ((StrokaCl]

= »+’) Or (Stroka[I] = »-») Or (Stroka[I] - »*»))

Then

 

 

 

 

 

 

Begin

 

 

 

 

 

 

Semantika := False;

 

 

 

Exit

 

 

 

 

 

 

End;

 

 

 

 

 

 

I := I + 1;

I,

I);

 

 

 

Propusk(Stroka,

 

 

 

While Cifra(Stroka[l]) Do

Begin

 

 

Stroka[I];

 

Q

:* Q +

 

I

 

I +

1

 

 

 

 

End;

 

 

 

 

 

 

 

If Error(Q)

 

 

 

 

 

Then

 

 

 

 

 

 

 

 

Begin

:* False;

 

 

 

Flag

 

 

 

Exit

 

 

 

 

 

 

 

End;

 

 

 

 

I,

I);

 

Propusk(Stroka,

 

Z :*» Stroka[I] ;

 

 

 

I

I +

1;

 

 

I,

I);

 

Propusk(Stroka,

 

P :*

 

 

 

 

 

 

 

Do

While Cifra(Stroka[I])

Begin

 

 

 

 

 

 

 

P

:* P + StrokaCl];

 

I

 

I +

1

 

 

 

 

End;

 

 

 

 

 

 

 

If Error(P)

 

 

 

 

 

Then

 

 

 

 

 

 

 

 

Begin

 

 

 

 

 

 

 

Flag :■ False;

 

 

Exit

 

 

 

 

 

 

 

End;

 

A,

Code);

 

 

 

Val(Q,

 

 

 

Val(P,

B,

Code)

 

 

 

 

{Стандартная процедура Val преобразует цифровую

End;

строку в соответствующее число; Code - код ошибки}

 

 

 

 

 

 

 

 

Procedure

Calc(А,

В

Pozlnt; Znak Char;

Var X,

Y, Z

Var Rez

Integer; Var Flag Boolean);

Real;

 

Begin

:« True;

 

 

 

 

Flag

 

 

 

 

Y:= A;

Z:= B;

Case

Znak Of

+ Z;

*+'

X

:= Y

 

X

:* Y

- Z;

 

X

:= Y

* Z

End;

If Abs(X) > Maxlnt

Then

Мы уже говорили о том, что качественная программа ни в каком варианте не должна завершиться аварийно. Тесты программы Inter- pretator должны продемонстрировать, что при правильном вводе ис­ ходной строки будут всегда получаться правильные результаты, а при наличии ошибок (синтаксических, семантических, выход за диапазон) будут получены соответствующие сообщения. План тестирования на­ шей программы может быть, например, таким:

N

Что вводим

 

Что должно получиться

1

25+73=

 

 

98

2

5274

-

12315

= -7041

3

614 *

25

=

 

15350

4

25,5

+ 31,2

=

Недопустимые символы

5

5=6-1

 

 

 

Неверное выражение

6

72315

-

256

=

Слишком большие операнды

7

32000*100=

 

Большой результат

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

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

Для значений, хранящихся в такой таблице, удобно использовать двухиндексные обозначения. Например, # 1981,2 обозначает температуру в феврале 1981 года и т.п. А вся совокупность данных, соста­ вляющих таблицу, математически обозначается так:

i = 1981..1990; j = 1..12.

Обработка таких данных производится с двухиндексными величинами. Например, средняя температура марта за 10 лет вычисляется по фор­ муле:

I

1990

# с р .м а р т = ттг

# 1 ,3 *

1Ui=1981

А значение средней температуры за весь десятилетний период вы­ числяется так:

1

1990

1

12

iU t=1981

и

£*«•./

l£ j=1

11990 12

=Ш Е

1ZUi=1981 j=l

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

Г[1], Г[5], ТЩ, #[1981,9], Я М И т .п .

Массив, хранящий линейную таблицу, называется одномерным, прямоугольную таблицу — двумерным. В программах могут исполь­ зоваться массивы и большей размерности.

Тип элементов массива называется его базовым типом. Очевидно, для рассмотренных массивов температур базовым типом является ве­ щественный (Real).

Описание массивов. Переменная регулярного типа описывается в разделе описания переменных в следующей форме:

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

Var Н Array[1981..1990] Of Array[1..12] Of Real;

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

н[1981] [1] ; н[1985] [10]; Н[1990] [12] .

Однако чаще употребляется другая, эквивалентная форма обозначения элементов двумерного массива:

Н [1981,1]; Н[1985,10]; Н[1990,12].

Переменная Н [1981] обозначает всю первую строку таблицы, т.е. весь массив температур за 1981 год.

Другим эквивалентным вариантом приведенному выше описанию является следующее:

Type Month = Array [1..12] Of Real;

Year = Array [1981..1990] Of Month;

Var H Year;

Наиболее краткий вариант описания данного массива такой:

Var Н Array[1981..1990, 1..12] Of Real;

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

Var A Array[1..10, 1..20, 1..30] Of Integer;

Это массив, состоящий из 10 20 30 = 6000 целых чисел и занимающий в памяти 6000 2 = 12000 байт. В Паскале нет ограничения сверху на размерность массива. Однако в каждой конкретной реализации Паскаля ограничивается объем памяти, выделяемый под массивы. В Турбо-Паскале это ограничение равно 64 килобайтам.

По аналогии с математикой одномерные числовые массивы часто называют векторами, а двумерные — матрицами.

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

Const Imax=10; JmaxB20;

Var Mas Array[1 ..Imax, l..Jmax] Of Integer;

Теперь для изменения размеров массива Mas и всех операторов прог­ раммы, связанных с этими размерами, достаточно отредактировать только одну строку в программе — раздел констант.

Действия над массивом как единым целым. Такие действия допустимы лишь в двух случаях:

-присваивание значений одного массива другому;

-передача массива в качестве фактического параметра при обращении

кподпрограмме.

Впервом случае оба массива должны быть идентичны по описанию.

Пример:

Type Mas = Аггау[1..5, 1. 10] Of Real;

Var Р, Q Mas;

При выполнении операции присваивания

Р := q

все элементы массива Р станут равны соответствующим элементам массива Q.

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

Н[1989] := Н[1981].

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

Type Mas = Аггау[1..5, 1 .10] Of Real; Var Y: Mas;

Procedure PRIM(X: Mas);

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

PRIM(Y);

116

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

For I :* 1 То 12 Do

ReadLn(T[I]);

For I :» 1 To IMax Do

For J :* 1 To Jmax Do

ReadLnCMasCl, J]);

Здесь каждое следующее значение будет вводиться с новой строки. Для построчного ввода используется оператор read.

Аналогично в цикле по индексной переменной организуется вывод значений массива. Например:

For I :*1 То 12 Do Write(T[I] :8:4);

Следующий фрагмент программы организует построчный вывод матрицы на экран:

For I:«l То IMax Do

Begin

For J:*l to JMax Do

Write(Mas[I,J]:6);

WriteLn

End;

После печати очередной строки матрицы оператор writeln без пара­ метров переведет курсор в начало новой строки. Следует заметить, что в последнем примере матрица на экране будет получена в есте­ ственной форме прямоугольной таблицы, если Jmax не превышает 12 (сами подумайте, почему).

Рассмотрим несколько примеров типовых программ обработка мас­

сивов.

Пример 1. Вернемся к массиву среднемесячных температур Т[1..12]. Требуется вычислить среднегодовую температуру, а также ежемесячные отклонения от этой величины.

Program Example;

Cont

N

*

12;

Type

Vec

*= Array [1..N] Of Real;

Var T,

Dt*: Vec;

 

St

 

Real;

 

I

 

Integer;

Begin

{____________ Ввод исходных данных.

 

.}

WriteLn(*Вводите таблицу температур ’);

 

 

For I := 1 То N Do

 

 

 

 

 

Begin

 

2,

 

 

 

 

 

 

Write(I

 

 

 

 

 

 

ReadLn(T[I] )

 

 

 

 

 

End;

{_________Вычисление средней температуры__________ }

 

St := 0;

 

 

 

 

 

 

 

For I := 1 To N Do

 

 

 

 

 

St

:= St + T[IJ ;

 

 

 

 

 

St

:= St

/ N;

 

 

 

 

 

For

{____ Вычисление таблицы отклонений от среднего___ }

I

:= 1 То

N Do

 

 

 

 

 

Dt[I]

:« St

- T[I];

 

 

 

 

 

 

{___________ Вывод результатов___________________ }

WriteLn(’Средняя температура рйЬна

’f St

6

2);

WriteLn;

 

 

от средней температуры:’);

 

WriteLn(’Отклонения

 

For

I

:= 1 To

N Do

DtCl]

6

2)

 

 

WriteLn(I

1, ’

 

 

End.

 

 

 

 

 

 

 

 

 

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

П ример 2. В ы бор максимального элемента. Пусть Из рас­ смотренного выше массива температур требуется отобрать самую высокую температуру и номер месяца, ей соответствующий. ^ горитма решения этой задачи: чтобы получить максимальную Темпе­ ратуру в вещественной переменной ТМах, сначала в нее заносится первое значение массива Т[1]. Затем поочередно сравнивается зна­ чение ТМах с остальными элементами массива температур, и каждое значение, большее чем ТМах, присваивается этой переменнойДдд по_ лучения номера самого теплого месяца в целой переменной N umK{ax в нее следует каждый раз засылать номер элемента массива тО^^ратур одновременно с занесением в ТМах его значения.

ТМах := Т [1]; NumMax := 1;

For I 2 То 12 Do

If T[I] > ТМах

Then

Begin

TMax := T[I] ;

NumMax := I

End;

Заметим, что если в массиве температур несколько значений, рав­ ных максимальному, то в NumMax будет получен первый номер из этих элементов. Чтобы получить последнюю дату, нужно в операторе if заменить знак отношения ” > ” на ” > = ”

П ример 3. С ортировка массива. В одномерном массиве X из N элементов требуется произвести перестановку значений так, чтобы они расположились по возрастанию, т.е. Х\ < Х 2 < •.> < X N.

Существует целый класс алгоритмов сортировки. Ниже описан ал­ горитм, который называется “метод пузырька”

Идея: производится последовательное упорядочивание смежных пар элементов массива: Х\ и Х 2, X 2 и X 3, ..., X^^i и Ху. В итоге мак­ симальное значение переместится в Х ^ . Затем ту же процедуру по­ вторяют до Xjy-i и т.д., вплоть до цепочки из двух элементов Х\ и X*i' Такой алгоритм будет иметь структуру двух вложенных циклов, причем внутренний цикл — переменной (сокращающейся) длины.

For I 1 То Ы - 1 Do

For К := 1 То N - I Do

If Х[К] > Х[К + 1]

Then

Begin

А := X[К];

Х[К] := Х[К + 1]; Х[К + 1] := А End;

П ример 4. Дан описанный выше двумерный массив среднемесяч­ ных температур за 10 лет. Определить, в каком году было самое теплое лето, т.е. в каком году была наибольшая средняя температура летних

месяцев.

Идея решения: в векторе S получить средние температуры летних месяцев за 10 лет. Затем найти номер наибольшего элемента в этом векторе, это и будет искомый год.

Program Example_2;

Type Month = Array[1.. 12] Of Real;

Year ■ A r r a y [1981..1990] Of Month;

Var H Year;