Вы находитесь на странице: 1из 33

Лекция 6-7.

Операторы языка Паскаль

Составной оператор
Составной оператор – это последовательность произвольных операторов
программы, заключенная в операторные скобки – зарезервированные слова
begin…end. Составные операторы – важный инструмент Турбо Паскаля,
дающий возможность писать программы по современной технологии
структурного программирования (без операторов перехода goto).
Язык Турбо Паскаль не накладывает никаких ограничений на характер
операторов, входящих в составной оператор. Среди них могут буть и другие
составные операторы – Турбо Паскаль допускает произвольную глубину их
вложенности:

Begin
.......
Begin
.......
Begin
.......
End;
.......
End;
.......
End;

Фактически, весь раздел операторов, обрамленный словами begin…end,


представляет собой один составной оператор. Поскольку зарезервированное
слово end является закрывающей операторной скобкой, оно одновременно
указывает и конец предыдущего оператора, поэтому ставить перед ним
символ «;» необязательно. Однако, в процессе работы над программой перед
словом end могут появиться новые операторы. В этом случае часто возникает
ошибка из-за отсутствия символа «;» после предпоследнего оператора

44
(программист добавляет новый оператор, после которого символ «;» не
нужен, а поставить его там где он теперь необходим забывает). С этой точки
зрения символ «;» лучше ставить и перед словом end. Это будет означать, что
между последним оператором и операторной скобкой end располагается
пустой оператор. Пустой оператор не содержит ни каких действий, просто в
программу добавляется лишняя точка с запятой.

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

if <условие> then <оператор1> else <оператор2>;

где if, then, else – зарезервированные слова (если, то, иначе);


<условие> – произвольное выражение логического типа;
<оператор1>, <оператор2>, – любые операторы языка Турбо Паскаль.
Условный оператор работает по следующему алгоритму. Сначала
вычисляется условное выражение <условие>. Если результат есть true
(истина), то выполняется <оператор1>, а <оператор2> пропускается; если
результат есть false (ложь), наоборот, <оператор1> пропускается, а
выполняется <оператор2>. Например:

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;

В этом примере переменная y всегда будет иметь значение переменной


x, а в max запоминается значение x если оно больше значения max.
Поскольку любой из операторов <оператор1> и <оператор2> может
быть любого типа, в том числе и условным, а в то же время не каждый из
«вложенных» условных операторов может иметь часть else <оператор2>, то
возникает неоднозначность трактовки условий, т.е. непонятно какой else к
какому if…then относится. Эта неоднозначность в Турбо Паскале решается
следующим образом: любая встретившаяся часть else соответствует
ближайшей к ней «сверху» части if…then условного оператора. Например:

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}

Обратите внимание на то, что перед else точка с запятой не ставится.


Символ «;» в Паскале означает конец оператора, а оператор if заканчивается
там где заканчивается <оператор2> (если есть часть else).
В случае, когда необходимо выполнить несколько операторов, а не один
(<оператор1> или <оператор2>) их необходимо заключить в операторные
скобки begin … end, получив, тем самым, составной оператор.
Рассмотрим программу, которая вводит произвольное целое число в
диапазоне 0..15, преобразует его к шестнадцатеричному основанию и
выводит на экран полученное.

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


Если у вас не два возможных варианта выполнения программы, а
больше, то может использоваться оператор выбора CASE. Структура этого
оператора в Турбо Паскале:

CASE <ключ_выбора> OF
C1 : <оператор1>;
C2 : <оператор2>;
. . .
CN : <операторN>;
[ELSE <оператор0>;]
END;

Здесь <ключ_выбора> - это выражение порядкового типа, в зависимости


от значения которого принимается решение; C1,...,CN - значения, с которыми
сравнивается значение <ключа>; <оператор1>,..., <операторN> - оператор
(возможно составные), из которых выполняется rnr, с константой которого
происходит первое совпадение значения <ключа>, <оператор0> выполнится,
если значение ключа не совпадает ни с одной из констант C1,...,CN.
Пример

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.

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

while <условие выполнения цикла> do <оператор>;

Выполнение цикла начинается с проверки <условия выполнения цикла>.


Если оно истинно, то выполняется <оператор> (тело цикла). Потом снова
проверяется <условие выполнения цикла> и, если оно истинно, то
выполняется <оператор> и т.д. Если на коком-то шаге <условие выполнения
цикла> станет ложным, то выполнение цикла будет завершено. Таким
образом, пока <условие выполнения цикла> истинно будет выполняться
<оператор>. Если <условие выполнения цикла> изначально ложно, то
<оператор> ни разу не будет выполнен.

49
Если в цикле необходимо выполнить несколько операторов, то
необходимо воспользоваться составным оператором:

while <условие выполнения цикла> do


begin
<операторы>
end;

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


записывается следующим образом:

repeat
<операторы>
until <условие выхода из цикла>;

Выполнение цикла начинается с выполнения <операторов> (тела цикла),


потом проверяется <условие выхода из цикла>. Если оно ложно, то снова
выполняются <операторы>. Потом снова проверяется <условие выхода из
цикла> и т.д. Если на коком-то шаге <условие выхода из цикла> станет
истинным, то выполнение цикла будет завершено. Таким образом, будут
выполняться <операторы> до тех пор, пока <условие выхода из цикла> не
станет истинным. Кикам бы ни было <условие выхода из цикла> в начале
работы цикла, <операторы> будут выполнены, по крайней мере, один раз.
Тело цикла может содержать несколько операторов, причем нет
необходимости использовать составной оператор, поскольку в качестве
операторных скобок здесь выступают ключевые слова repeat и until.
Оба оператора цикла предполагают, что
1. на момент начала выполнения цикла определены (имеют начальные
значения) все переменные участвующие в вычислении значений условий и
2. тело цикла содержит оператор или операторы, которые изменяют эти
переменные таким образом, чтобы условие изменило свое значение и цикл
завершил свою работу.
50
Следующий вариант оператора цикла включает в себя оба этих условия.
и записывается следующим образом:

for <переменная цикла>:=<начальное значение> to <верхняя


граница> do
<оператор>;

Выполнение цикла начинается с присвоения <переменная цикла>


<начального значения>. Далее, если значение <переменная цикла> меньше
или равно значению <верхней границы>, то выполняется <оператор>. Потом
значение переменной цикла увеличивается на единицу и снова проверяется
условие, что значение <переменной цикла> меньше или равно значению
<верхней границы>, выполняется <оператор> и т.д.
Есть еще один вариант цикла for:

for <переменная цикла>:=<начальное значение> downto <нижняя


граница>
do <оператор>;

Здесь на каждом шаге значение переменной цикла уменьшается на


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

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 

Здесь A – введенное число, Y0=A.

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;

Лекция 7-8. Структурированные типы. Массивы


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

Одномерные массивы
Массивы содержат фиксированное число элементов одного типа, так
называемого типа элемента. Переменные типа массив объявляются
следующим образом:

var
<имя переменной>:array[<тип индекса>] of <тип элемента>;

Допустимыми индексными типами являются все порядковые типы, за


исключением длинного целого и поддиапазонов длинного целого. Массив

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

var
A: array[1..100] of Real

Если тип элемента в типе массив также является массивом, то результат


можно рассматривать как массив массивов или как один многомерный
массив. Например,

array[boolean] of 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;

Ниже приведена программа формирования элементов массива с


помощью датчика случайных чисел, вывод элементов массива на экран,
вычисление суммы всех элементов.
program rand1;
const n1=100; {максимальный размер массива}
type mas = array[1..n1] of integer;
var a:mas;
i, {индекс элемента массива}
n,s: integer;
begin
writeln('Введите число элементов массива:');
read(n);

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;

Ниже приведена программа алгоритма формирования элементов


массива с помощью датчика случайных чисел, вывод элементов массива на
экран, вычисление суммы всех элементов двумерного массива.
program rand2;
const n1=10; {максимальнoе количество стpок массива}
m1=10; { максимальное количество столбцов массива}
type mas = array[1..n1,1..m1] of integer;
var a: mas;
i, { текущий номеp строки }
j, { текущий номеp столбца }
n,s,m : integer;
begin
writeln('Введите число стpок и столбцов массива:');
read(n,m);
randomize;
for i:=1 to n do
for j:=1 to m do
a[i,j]:=random(10);
61
writeln('Полученный массив');
for i:=1 to n do
begin
for j:=1 to m do
write (a[i,j]:5);
writeln;
end;
s:=0;
for i:=1 to n do
for j:=1 to m do
s:=s+a[i,j];
writeln('s=',s);
end.
Анализируя предложенную программу, можно заметить, что для ввода,
вывода и нахождения суммы элементов массива используются три раза
вложенные циклы. Так как массив располагается в непрерывной области
памяти построчно, более рационально будет и обрабатывать элементы
построчно. В программе во вложенных циклах для каждого значения
индекса i индекс j изменяется от 1 до m, т.е. индекс j изменяется чаще.
Таким образом, обрабатываются элементы массива построчно. Хотелось бы
обратить внимание на вывод элементов массива на экран. Здесь для каждого
значения i в теле цикла выполняются два оператора: первый оператор
цикла выводит на экран в строчку элементы одной строки, а второй
оператор вывода переводит курсор на новую строку, что как раз и
обеспечивает вывод матрицы в виде прямоугольника.
Следующий пример иллюстрирует работу с диагоналями матрицы. Дана
квадратная матрица. Заменить отрицательные элементы побочной диагонали
на сумму элементов главной диагонали матрицы. При изучении
поставленной задачи следует напомнить, что главная диагональ проходит из
правого верхнего в левый нижний угол. Так как мы работаем с квадратной
матрицей, то только на главной диагонали будут лежать элементы, индексы
строк и столбцов которых одинаковы. Именно этот факт и используется при
62
решении задачи. Мы не будем перебирать все элементы массива и смотреть,
совпали ли индексы, а сразу задаем оба индекса с помощью одного
идентификатора i. Побочная диагональ проходит из правого верхнего в
левый нижний угол матрицы. Нетрудно заметить, что при движении по
побочной диагонали номер строки возрастает от 1 до n, номер столбца
убывает от n до 1. Таким образом, только на побочной диагонали лежат
элементы, у которых номер столбца определяется по формуле j=n-i+1.
program diag;
const n1=10; {максимальнoе количество стpок массива}
type
mas = array[1..n1,1..n1] of integer;{квадpатная матpица}
var a:mas;
i, { текущий номеp стpоки }
j, { текущий номеp столбца }
n,s:integer;
begin
writeln('Введите число стpок и столбцов массива:');
read(n);
for i:=1 to n do
for j:=1 to n do
begin
writeln('Введите элемент массива');
read(a[i,j]);
end;
writeln('Исходный массив');
for i:=1 to n do
begin
for j:=1 to n do
write (a[i,j]:5);
writeln;
end;
s:=0;
for i:=1 to n do {Сумма элементов главной диагонали }
s:=s+a[i,i];
63
writeln('s=',s);
for i:=1 to n do{Замена элементов побочной диагонали}
begin
j:=n-i+1;
if a[i,j]<0 then a[i,j]:=s;
end;
writeln('Полученный массив');
for i:=1 to n do
begin
for j:=1 to n do
write (a[i,j]:5);
writeln;
end;
end.
Фрагмент программы для транспонирования матрицы относительно
побочной диагонали:

For i:=1 to N-1 do


for j:=1 to N-i do
begin
tmp:=c2[I,j];
c2[I,j]:=c2[N-j+1,N-i+1];
c2[N-j+1,N-i+1]:=tmp;
end;

Лекция 9. Процедуры и функции

Описание подпрограммы
Описание подпрограммы состоит из заголовка и тела подпрограммы.
Заголовок процедуры имеет вид:

PROCEDURE <имя> [(<сп.ф. п. >)];

Заголовок функции:

64
FUNCTION <имя> [(<.сп.ф.п.>)] : <тип>:

Здесь <имя> - имя подпрограммы (правильный идентификатор);


<сп.ф.п-> - список формальных параметров,
<тип> - тип возвращаемого функцией результата.
Полный формат описания процедуры:
Procedure <Имя процедуры> (<Имя форм. параметра 1>:<Тип1>;
< Имя форм. параметра 2>:<Тип2>);
<Раздел описаний>
Begin
<Тело процедуры>
End;

Раздел описаний может иметь такие же подразделы, как и раздел


описаний основной программы (описание процедур и функций - в том
числе). Однако все описанные здесь объекты "видимы" лишь в этой
процедуре. Они здесь локальны также, как и имена формальных параметров.
Объекты, описанные ранее в разделе описаний основной программы и не
переопределенные в процедуре, называются глобальными для этой
подпрограммы и доступны для использования.
Формат описания функции:
Function <Имя функции> (<Имя форм. параметра 1>:<Тип>;
< Имя форм. параметра 2>:<Тип>?) : <Тип результата>;
<Раздел описаний>
Begin
<Тело функции>
End;

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


такого вида:

<Имя функции>:=<Выражение>;

65
Указанное выражение должно приводить к значению того же типа, что и
тип результата функции, описанный выше.
Сразу за заголовком подпрограммы может следовать одна из стан-
дартных директив ASSEMBLER, EXTERNAL. FAR, FORWARD, INLINE,
INTERRUPT, NEAR. Эти директивы уточняют действия компилятора и
распространяются на всю подпрограмму и только на нее, т.е. если за
подпрограммой следует другая подпрограмма, стандартная директива,
указанная за заголовком первой, не распространяется на вторую.
Например, директива FORWARD используется при опережающем
описании для сообщения компилятору, что описание подпрограммы следует
где-то дальше по тексту программы (но в пределах текущего программного
модуля).
Вызов процедуры представляет в программе самостоятельную
инструкцию:

<Имя процедуры>(<Фактический параметр 1>, <Фактический параметр


2>,…);

Типы фактических параметров должны быть такими же, что и у


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

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

Procedure SB (a : real; b : Integer: с : char);

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

Function F (а : real; b : real) : real;

можно написать проще:

Function F (a, b : real) : real;

Операторы тела подпрограммы рассматривают список формальных


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

Function Power (var a : real; b : real) : real;

Здесь параметр А – параметр-переменная, а В – параметр-значение.


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

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}

В результате прогона программы будет выведено:

Исходные: 5 7 удвоенные 10 14 результат 10 7

Как видно из примера, удвоение второго формального параметра в


процедуре INC2 не вызвало изменения фактической переменной В, так как
этот параметр описан в заголовке процедуры как параметр-значение. Этот
пример может служить еще и иллюстрацией механизма "закрывания"
глобальной переменной одноименной локальной: хотя переменная В
объявлена как глобальная (она описана в вызывающей программе перед
описанием процедуры), в теле процедуры ее «закрыла» локальная пере-
менная В, объявленная как параметр-значение.
Итак, параметры-переменные используются как средство связи ал-
горитма, реализованного в подпрограмме, с «внешним миром»: с помощью
этих параметров подпрограмма может передавать результаты своей работы
вызывающей программе. Разумеется, в распоряжении программиста всегда
есть и другой способ передачи результатов - через глобальные переменные.
Однако злоупотребление глобальными связями делает программу, как
правило, запутанной, трудной в понимании и сложной в отладке. В
соответствии с требованиями хорошего стиля программирования
рекомендуется там, где это возможно, использовать передачу результатов
через фактические параметры-переменные.
С другой стороны, описание всех формальных параметров как
параметров-переменных нежелательно по двум причинам. Во-первых, это

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}

Для вызова функции POWER мы просто указали ее в качестве параметра


при обращении к встроенной процедуре WRITELN. Параметры Х и У в
момент обращения к функции - это фактические параметры. Они
подставляются вместо формальных параметров А и В в заголовке функции и
затем над ними осуществляются нужные действия. Полученный результат
присваивается идентификатору функции - именно он и будет возвращен как

72
значение функции при выходе из нее. В программе функция POWER
вызывается дважды - сначала с параметрами Х и Y, а затем Х и -У, поэтому
будут получены два разных результата.
Механизм замены формальных параметров на фактические позволяет
нужным образом настроить алгоритм, реализованный в подпрограмме. Турбо
Паскаль следит за тем, чтобы количество и тип формальных параметров
строго соответствовали количеству и типам фактических параметров в
момент обращения к подпрограмме. Смысл используемых фактических
параметров зависит от того, в каком порядке они перечислены при вызове
подпрограммы. В примере первый по порядку фактический параметр будет
возводиться в степень, задаваемую вторым параметром, а не наоборот.
Пользователь должен сам следить за правильным порядком перечисления
фактических параметров при обращении к подпрограмме.

Тип данных String


Тип STRING (строка) в Турбо Паскале широко используется для
обработки текстов. Он во многом похож на одномерный массив символов
ARRAY [O..N] OF CHAR, однако, в отличие от последнего, количество
символов в строке-переменной может меняться от 0 до N, где N - макси-
мальное количество символов в строке. Значение N определяется объяв-
лением типа STRING[N] и может быть любой константой порядкового типа,
но не больше 255 . Турбо Паскаль разрешает не указывать N, в этом случае
длина строки принимается максимально возможной, а именно N-255 .
Строка в Турбо Паскале трактуется как цепочка символов. К любому
символу в строке можно обратиться точно так же, как к элементу одномер-
ного массива ARRAY [O..N] OF CHAR, например:

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;

Значение ORD(st[0]) , т.е. текущую длину строки, можно получить и с


помощью функции LENGTH(st), например:

while ( Iength(st)<>0) and (st[ length(st)]-' ') do


s[0] := chr(length(st)-1)

К строкам можно применять операцию «+» - сцепление, например:

st := 'а' + 'b':
st := st + 'с'; {st содержит 'abc'}

Если длина сцепленной строки превысит максимально допустимую


длину N, то «лишние» символы отбрасываются. Следующая программа,
например, напечатает символ 1:
var
st:string[1];
begin
st:='123';
writeln(st)
end.

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':

Сравнение строк:

'Turbo' < 'Turbo Pascal'


'Паскаль' > 'Turbo Pascal'

76

Оценить