Составной оператор
Составной оператор – это последовательность произвольных операторов
программы, заключенная в операторные скобки – зарезервированные слова
begin…end. Составные операторы – важный инструмент Турбо Паскаля,
дающий возможность писать программы по современной технологии
структурного программирования (без операторов перехода goto).
Язык Турбо Паскаль не накладывает никаких ограничений на характер
операторов, входящих в составной оператор. Среди них могут буть и другие
составные операторы – Турбо Паскаль допускает произвольную глубину их
вложенности:
Begin
.......
Begin
.......
Begin
.......
End;
.......
End;
.......
End;
44
(программист добавляет новый оператор, после которого символ «;» не
нужен, а поставить его там где он теперь необходим забывает). С этой точки
зрения символ «;» лучше ставить и перед словом end. Это будет означать, что
между последним оператором и операторной скобкой end располагается
пустой оператор. Пустой оператор не содержит ни каких действий, просто в
программу добавляется лишняя точка с запятой.
Условный оператор
Условный оператор позволяет проверить некоторое условие и в
зависимости от результатов проверки выполнить то или иное действие.
Таким образом, условный оператор – это средство ветвления
вычислительного процесса.
Структура условного оператора имеет следующий вид:
var
x, y, max : real;
.......
if x>max then y:=max
else y:=x;
45
При выполнении этого фрагмента переменная y получит значение
переменной x, если только это значение не превышает max, в противном
случае y станет равным max.
Часть else <оператор2> условного оператора может быть опущена. Тогда
при значении true условного выражения выполняется <оператор1>, в
противном случае этот оператор пропускается:
var
x, y, max : real;
.......
if x>max then max:=x;
y:=x;
var
a, b, c, d : integer;
a:=1;
b:=2;
c:=3;
d:=4;
if a>b then
if c<d then
if c<0 then c:=0
46
else a:=b; {a=1}
if a>b then
if c<d then
if c<0 then c:=0
else
else
else a:=b; {a=2}
var
n : integer; {Вводимое число}
ch : char; {Результат}
begin
write(‘n= ‘); {Вывести приглашение (подсказку)}
readln(n); {Ввести число}
{Проверить число на принадлежность диапазону 0..15}
if (n>=0) and (n<=15) then
begin {Да, принадлежит}
if n<10 then ch:=chr(ord(‘0’)+n)
else ch:=chr(ord(‘A’)+n-10);
writeln(‘n=’, ch);
end
else writeln(‘Ошибка’);
end.
47
В шестнадцатеричной системе счисления используются 16 цифр в
каждом разряде: цифры 0..9 обозначают первые 10 возможных значений
разряда, буквы A..F – остальные шесть.
В программе учитывается непрерывность и упорядоченность множества
цифр 0..9 и множества букв A..F.
CASE <ключ_выбора> OF
C1 : <оператор1>;
C2 : <оператор2>;
. . .
CN : <операторN>;
[ELSE <оператор0>;]
END;
Program calc;
Var a,b,rez:real;
oper:char;
Begin
write(‘Введите два числа: ’);
48
readln(a,b);
write(‘Введите операцию: ‘);
readln(oper);
case oper of
‘+’:rez:=a+b;
‘-’:rez:=a-b;
‘*’:rez:=a*b;
‘/’:rez:=a/b;
end;
writeln(‘Результат=‘,rez);
end.
Операторы повтора
В языке Турбо Паскаль имеются три различных оператора, с помощью
которых можно запрограммировать повторяющиеся фрагменты программ.
Такие операторы называются циклами. Различаются эти операторы способом
определения количества необходимых повторов, или, другими словами,
когда необходимо завершить работу цикла.
Первый вариант цикла называется циклом с предпроверкой условия и
записывается следующим образом:
49
Если в цикле необходимо выполнить несколько операторов, то
необходимо воспользоваться составным оператором:
repeat
<операторы>
until <условие выхода из цикла>;
Program Str3;
Var
I : Byte;
Begin
For I:=32 to 255 do
Write('VV',I:4, '-',Chr(I))
End.
51
Цикл в программе начинается с 32 потому, что символы с кодами от 0 до
31 являются управляющими и не имеют соответствующего графического
представления.
Пример
Совершенными называются числа, равные сумме всех своих делителей,
включая 1. Например, 6 – совершенное число, поскольку 6=1+2+3.
Требуется найти и вывести на экран все совершенные числа вместе с их
делителями, лежащие в диапазоне от 4 до 10000.
Var I,sum,del1,n:word;
Begin
for i:=4 to 10000 do
Begin
sum:=1; n:= trunc(sqrt(i));
for del1:=2 to n do
if I mod del1 =0 then
if del1<> I div del1 then
begin
sum:=sum+del1+(I div del1);
end
else
sum:=sum+del1;
if sum=i then
writeln(i);
End;
End.
Пример
Вычислить квадратный корень из произвольного вещественного числа,
введенного с клавиатуры, используя метод Ньютона:
1 A
Yn +1 =
Yn +
2 Yn
52
Если A – отрицательное число, то необходимо вывести сообщение об
ошибке.
Результат должен иметь относительную точность 1·10-6. Как только
получено значение Y0 оно используется для получения следующего
приближения Y0, по которому в свою очередь вычисляется Y0, и так до тех
пор, пока не будет достигнута требуемая точность, то есть, пока не станет
Yn +1 −Yn ≤1 ⋅10 −6
Var A,Y1,Y:real;
Begin
write(‘Введите число:’);
readln(A);
Y1:=A;
repeat
Y:=Y1;
Y1:=(Y+A/Y)/2;
until abs(Y1-Y)<0.000001;
writeln(‘Корень из числа=‘,Y1:10:5);
end.
For i:=0 to 9 do
for j:=0 to 9 do
for k:=0 to 9 do
if (i<>j)and(i<>k)and
(j<>k) then
write(I,j,k,’ ‘);
i:=1;
While i<=9 do
begin
53
J:=1;
while j<=9 do
begin
K:=1;
while k<=9 do
begin
write(I,j,k,’ ‘);
Inc(k,2);
end;
Inc(j,2);
end;
Inc(I,2);
End;
Одномерные массивы
Массивы содержат фиксированное число элементов одного типа, так
называемого типа элемента. Переменные типа массив объявляются
следующим образом:
var
<имя переменной>:array[<тип индекса>] of <тип элемента>;
54
может быть проиндексирован по каждой размерности всеми значениями
соответствующего индексного типа; число элементов поэтому равно числу
значений в каждом индексном типе. Число размерностей не ограничено.
Приведем пример переменной типа массив:
var
A: array[1..100] of Real
array[boolean,1..10] of Real
A[5]:=3.4;
For i:=1 to 100 do
Begin
writeln(‘Введите элемент A[‘,I,’]:’);
Readln(A[i]);
End;
Объявление констант:
Const
<имя конст.>=<значение>;
55
Сумма элементов массива
Const N=10;
Var a:array[1..N] of real;
i:word;
sum:real;
Begin
sum:=0;
for i:=1 to N do
sum:=sum+a[i];
writeln(‘Сумма=‘,sum:10:5);
end.
Const N=10;
Var a:array[1..N] of real;
i:word;
p:real;
Begin
p:=1;
for i:=1 to N do
p:=p*a[i];
writeln(‘Произведение=‘,p:10:5);
end.
randomize;
for i:=1 to N do
a[i]:=x1+random*(x2-x1);
56
b[1]:=1;
b[2]:=1;
for i:=3 to N do
b[i]:=b[i-1]+b[i-2];
for i:=1 to N do
if b[i] mod 2=0 then
b[i]:=sqr(b[i]);
i:=2;
while i<=N do
begin
a[i]:=sqr(a[i]);
Inc(I,2);
End;
57
{ Формирование массива с помощью датчика случайных чисел}
randomize;{Инициализация датчика случайных чисел }
for i:=1 to n do
a[i]:=random(10);
writeln('Полученный массив');
for i:=1 to n do
write (a[i]:5);
writeln;
s:=0; { Нахождение суммы }
for i:=1 to n do
s:=s+a[i];
writeln('s=',s);
end.
В приведенном примере в качестве исходных данных вводится размер
массива. Хотелось бы обратить внимание на использование константы n1.
Она сделает программу более универсальной, позволяя работать с
целочисленными массивами, размерность которых может изменяться от 1
до 100. Если будет введено число, меньшее 1 и большее 100, то возникнет
ошибка. Для формирования массива (да и во всех случаях, когда требуется
перебор всех элементов массива) лучше всего подходит оператор цикла со
счетчиком. В каждой итерации оператора цикла с датчика получаем
псевдослучайное число и присваиваем его очередному элементу массива
(индекс является переменной цикла). Результатом работы программы
является сформированный массив и сумма элементов этого массива.
Аналогично решается задача нахождения произведения элементов
массива, только начальное значение для произведения выбирается равным 1
и знак "+" меняется на знак "*".
Ниже приведена программа определения максимального элемента
массива и суммы положительных элементов, а также замены максимального
элемента массива суммой положительных элементов массива.
program sum;
const n1=100; {максимальный pазмеp массива}
58
type
mas = array[1..n1] of integer;
var
a:mas;
i, {индекс элемента массива}
n,s,
imax:integer;{индекс максимального элемента}
begin
writeln('Введите число элементов массива:');
read(n);
{Ввод массива}
for i:=1 to n do
begin
write ('Введите ',i,'-й элемент:');
read(a[i])
end;
s:=0;
imax:=1;{пpедполагаем, что пеpвый
элемент максимальный}
for i:=1 to n do
begin
{если элемент положительный, то
прибавляем его к сумме}
if a[i]>0 then s:=s+a[i];
{если текущий элемент массива больше
максимального, то запоминаем его индекс}
if a[imax]<a[i] then imax:=i;
end;
writeln('максимальный элемент массива =',a[imax]);
a[imax]:=s;{ замена максимального элемента суммой }
writeln('s=',s);
writeln('Обpаботанный массив:');
for i:=1 to n do
writeln (a[i]);
end.
59
В дальнейшем, в схемах алгоритма, подробно изображать ввод и вывод
массива не будем, чтобы алгоритм был нагляднее.
В приведенном примере массив вводится с клавиатуры. Для ввода
массива используется оператор цикла со счетчиком. За начальное значение
для индекса максимального элемента берем 1, т.е. предполагаем, что
первый элемент максимальный. Далее в цикле перебираются все элементы
массива и сравниваются c нулем для того, чтобы прибавлять или не
прибавлять элемент к сумме. В этом же цикле каждый элемент сравнивается
с a[imax] для выяснения, не встретился ли элемент, больший прежнего
максимального, и если встретился, то запоминается его индекс, чтобы
в следующий раз сравнивать текущий элемент с большим из перебранных. В
условном операторе if a[i]>a[imax] ветвь else отсутствует; это означает,
что в случае невыполнения условия imax остается без изменения, что и
обеспечивает наличие в области памяти с идентификатором imax значение
индекса максимального из перебранных элементов.
Многомерные массивы
Если тип элемента в типе массив также является массивом, то результат
можно рассматривать как массив массивов или как один многомерный
массив. Например,
array[boolean] of array[1..10] of Real;
интерпретируется компилятором точно так же, как массив:
array[boolean,1..10] of Real;
В случае многомерного массива можно использовать несколько
индексов или несколько выражений в индексе. Например:
Matrix[I][J]
Matrix[I,J]
60
Ввод элементов двумерного массива
For i:=1 to N do
for j:=1 to M do
begin
writeln(‘Введите элемент a2[‘,I,’,’,j,’]: ‘);
readln(a2[I,j]);
end;
Вывод на экран:
For i:=1 to N do
begin
for j:=1 to M do
write(a2[I,j]:8);
writeln;
end;
Описание подпрограммы
Описание подпрограммы состоит из заголовка и тела подпрограммы.
Заголовок процедуры имеет вид:
Заголовок функции:
64
FUNCTION <имя> [(<.сп.ф.п.>)] : <тип>:
<Имя функции>:=<Выражение>;
65
Указанное выражение должно приводить к значению того же типа, что и
тип результата функции, описанный выше.
Сразу за заголовком подпрограммы может следовать одна из стан-
дартных директив ASSEMBLER, EXTERNAL. FAR, FORWARD, INLINE,
INTERRUPT, NEAR. Эти директивы уточняют действия компилятора и
распространяются на всю подпрограмму и только на нее, т.е. если за
подпрограммой следует другая подпрограмма, стандартная директива,
указанная за заголовком первой, не распространяется на вторую.
Например, директива FORWARD используется при опережающем
описании для сообщения компилятору, что описание подпрограммы следует
где-то дальше по тексту программы (но в пределах текущего программного
модуля).
Вызов процедуры представляет в программе самостоятельную
инструкцию:
Параметры
Список формальных параметров необязателен и может отсутствовать.
Если же он есть, то в нем должны быть перечислены имена формальных
параметров и их тип, например:
66
Как видно из примера, параметры в списке отделяются друг от друга
точками с запятой. Несколько следующих подряд однотипных параметров
можно объединять в подсписки, например, вместо
67
за неукоснительным соблюдением этого правила осуществляется
компилятором Турбо Паскаля.
Для того чтобы понять, в каких случаях использовать параметры-
значения, а в каких - параметры-переменные, рассмотрим, как
осуществляется замена формальных параметров на фактические в момент
обращения к подпрограмме.
Если параметр определен как параметр-значение, то перед вызовом
подпрограммы это значение вычисляется, полученный результат копируется
во временную память и передается подпрограмме. Важно учесть, что даже
если в качестве фактического параметра указано простейшее выражение в
виде переменной или константы, все равно подпрограмме будет передана
лишь копия переменной (константы). Если же параметр определен как
параметр-переменная, то при вызове подпрограммы передается сама
переменная, а не ее копия. Любые возможные изменения в подпрограмме
параметра-значения никак не воспринимаются вызывающей программой, так
как в этом случае изменяется копия фактического параметра, в то время как
изменение параметра-переменной приводит к изменению самого
фактического параметра в вызывающей программе.
Представленный ниже пример поясняет изложенное. В программе
задаются два целых числа 5 и 7, эти числа передаются процедуре INC2, в
которой они удваиваются. Один из параметров передается как параметр-
переменная, другой - как параметр-значение. Значения параметров до и после
вызова процедуры, а также результат их удвоения выводятся на экран.
const
а : integer = 5;
b : integer = 7;
PROCEDURE lnc2 (var с : Integer; b : Integer);
begin {Inc2}
с := с + с;
b := b + b;
writeln(' удвоенные:', c:5, b:5);
68
end; {Inc2}
BEGIN {main}
writeln(' исходные:'. a:5, b:5);
lnc2(a,b);
writeln(' результат:', a:5, b:5);
END. {main}
69
исключает возможность вызова подпрограммы с фактическими параметрами
в виде выражений, что делает программу менее компактной. Во-вторых, и
главных, в подпрограмме возможно случайное использование формального
параметра, например, для временного хранения промежуточного результата,
т.е. всегда существует опасность непреднамеренно «испортить» фактическую
переменную. Вот почему параметрами-переменными следует объявлять
только те, через которые подпрограмма в действительности передает
результаты вызывающей программе. Чем меньше параметров объявлено
параметрами-переменными и чем меньше в подпрограмме используется
глобальных переменных, тем меньше опасность получения
непредусмотренных программистом побочных эффектов, связанных с
вызовом подпрограммы, тем проще программа в понимании и отладке. По
той же причине не рекомендуется использовать параметры-переменные в
заголовке функции: если результатом работы функции не может быть
единственное значение, то логичнее использовать процедуру или нужным
образом декомпозировать алгоритм на несколько подпрограмм.
Существует одно обстоятельство, которое следует учитывать при
выборе вида формальных параметров. Как уже говорилось, при объявлении
параметра-значения осуществляется копирование фактического параметра во
временную память. Если этим параметром будет массив большой
размерности, то существенные затраты времени и памяти на копирование
при многократных обращениях к подпрограмме могут стать решающим
доводом в пользу объявления такого параметра параметром-переменной или
передачи его в качестве глобальной переменной.
Примеры
Определение максимума из трех чисел:
Program Fn;
Var
A,B,C :Real;
70
Function Max(A,B:Real):Real;
{Описываем функцию Max с формальными}
Begin {параметрами A и B, которая принимает }
If A>B Then
Max:=A {значение максимального из них }
Else
Max:=B
{Здесь A и B - локальные переменные }
End;
Begin
Writeln('Введите три числа');
Readln(A,B,C);
Writeln('Максимальным из всех является ', Max(Max(A,B),C))
End.
Program Pr;
Var
S1,S2,S3 :Integer;
Procedure Swap(Var A,B: Integer);
{Процедура Swap с параметрами-переменными}
Var C : Integer; {C - независимая локальная переменная}
Begin
C:=A; A:=B; B:=C {Меняем местами содержимое A и B}
End;
Begin
Writeln('Введите три числа');
Readln(S1,S2,S3);
If S1>S2 Then Swap(S1,S2);
If S2>S3 Then Swap(S2,S3);
If S1>S2 Then Swap(S1,S2);
Writeln('Числа в порядке неубывания:V',S1,S2,S3)
End.
71
Рассмотрим следующий пример. В языке Турбо Паскаль нет операции
возведения в степень, однако с помощью встроенных функций LN(X) и
ЕХР(Х) нетрудно реализовать новую функцию с именем, например, POWER,
осуществляющую возведение любого вещественного числа в любую
вещественную степень. В следующем примере вводится пара чисел X и У и
выводится на экран дисплея результат возведения Х сначала в степень +У, а
затем - в степень - У. Для выхода из программы нужно ввести Ctrl-Z и
«Ввод».
var
х,у : real;
FUNCTION Power(a,b : real) : real;
begin {Power}
if a > 0 then Power := exp(b * In(a))
else
If a < 0 then
Power := exp(b * ln(abs(a))) eIse
if b=0 then Power := 1 else Power := 0
end {Power};
BEGIN {main}
repeat
readln(x,y);
wrlteln(power(x,y):12:10, power (x, -у) :15:10)
until EOF;
END. {main}
72
значение функции при выходе из нее. В программе функция POWER
вызывается дважды - сначала с параметрами Х и Y, а затем Х и -У, поэтому
будут получены два разных результата.
Механизм замены формальных параметров на фактические позволяет
нужным образом настроить алгоритм, реализованный в подпрограмме. Турбо
Паскаль следит за тем, чтобы количество и тип формальных параметров
строго соответствовали количеству и типам фактических параметров в
момент обращения к подпрограмме. Смысл используемых фактических
параметров зависит от того, в каком порядке они перечислены при вызове
подпрограммы. В примере первый по порядку фактический параметр будет
возводиться в степень, задаваемую вторым параметром, а не наоборот.
Пользователь должен сам следить за правильным порядком перечисления
фактических параметров при обращении к подпрограмме.
var
st : string;
if st[5] - 'A' then .. .
73
Самый первый байт в строке имеет индекс 0 и содержит текущую длину
строки. Первый значащий символ строки занимает второй байт и имеет
индекс 1. Над длиной строки можно осуществлять необходимые действия и
таким способом изменять длину. Например, удалить из строки все ведомые
пробелы можно следующим образом:
var
st : strlng[10];
i : word;
i := 10;
while (st[l]=' ') and (i<>0) do begin dec(i):
st[0] := chr(i) end;
st := 'а' + 'b':
st := st + 'с'; {st содержит 'abc'}
74
Все остальные действия над строками и символами реализуются с
помощью встроенных процедур и функций.
CONCAT(S1 [,S2, ... ,SN]) - функция типа STRING; возвращает строку,
представляющую собой сцепление строк-параметров SI, S2,... ,SN.
COPY(ST, INDEX, COUNT) - функция типа STRING; копирует из строки
ST COUNT символов, начиная с символа с номером INDEX.
DELETE(ST, INDEX, COUNT) - процедура; удаляет COUNT символов
из строки ST, начиная с символа с номером INDEX.
INSERT(SUBST, ST, INDEX) - процедура; вставляет подстроку SUBST в
строку ST, начиная с символа с номером INDEX.
LENGTH(ST) - функция типа INTEGER; возвращает длину строки ST.
POS(SUBST, ST) - функция типа INTEGER: отыскивает в строке ST
первое вхождение подстроки SUBST и возвращает номер позиции, с которой
она начинается; если подстрока не найдена, возвращается ноль.
STR(X [:WIDTH [:DECIMALS]], ST) - процедура; преобразует число Х
любого вещественного или целого типов в строку символов ST так, как это
делает процедура WRITELN перед выводом; параметры WIDTH и DECIMALS,
если они присутствуют, задают формат преобразования:
WIDTH определяет общую ширину поля, выделенного под
соответствующее символьное представление вещественного или целого
числа X, а DECIMALS - количество символов в дробной части (имеет смысл
только в том случае, когда Х - вещественное число).
VAL(ST, X, CODE) - процедура; преобразует строку символов ST во
внутреннее представление целой или вещественной переменной X, которое
определяется типом этой переменной; параметр CODE содержит ноль, если
преобразование прошло успешно, и тогда в Х помещается результат
преобразования, в противном случае он содержит номер позиции в строке
ST. где обнаружен ошибочный символ, и в этом случае содержимое Х не
меняется; ведущие пробелы в строке ST должны отсутствовать.
75
UPCASE(CH) - функция типа CHAR; возвращает для символьного
выражения CH, которое должно представлять собой строчную латинскую
букву, соответствующую заглавную букву; если значением CH является
любой другой символ, функция возвращает его без преобразований.
Примеры:
var
х : real;
у : Integer:
st,st1: string;
st:=concat('12','345'); {строка st содержит 12345}
st1:=copy(st,3,length(st)-2); {st1 содержит 345}
insert('-',st1,2); {строка st1 содержит 3-45}
delete(st,pos{'2',st),3); {строка st содержит 12}
str(pi:6:2,st); {строка st содержит 3.14)
st1:='3,1415':
Сравнение строк:
76