
книги из ГПНТБ / Соловейчик, Р. Э. Программирование на АЛГОЛ-60 учеб. пособие
.pdf60
зе, в котором она описана, т.е. вне этого блока она не имеет смысла. Если этот блок содержит в себе другие блоки, называе мые подблоками, то по отношению к ним эта переменная называ ется глобальной. Переменная величина, описанная в подблоке некоторого блока, является неопределенной во внешнем блоке.
Два блока называются независимыми, если ни один из них не .является подблоком другого. Поясним эти термины следующи ми примером блочной структуры
begin reel |
г |
; |
|
|
|
|
|
С2: |
begin real |
а f |
|
|
|||
СЗ; |
begin reel |
t |
; |
|
|||
|
end |
03 |
} |
|
|
|
|
04 S |
|
|
begin real |
w |
• |
||
|
|
|
|||||
|
|
|
end |
04 . |
|
|
|
|
end 0? ; |
|
|
|
|
|
|
05; |
begin |
real |
x |
- |
|
|
|
|
end |
<75 |
; |
|
|
|
|
С6: |
begin |
real |
у ; |
|
|
||
|
|
|
|||||
С7: |
begin real |
z |
|
|
|
||
|
|
|
|
||||
|
end |
C7 |
; |
|
|
|
|
|
end C6 • |
|
|
|
|
|
|
end |
Cl |
|
|
приведено |
т а к о й программы, |
||
причем подчеркнем, что здесь не |
а сохранены только описание переменных и операторные скобки. Приведем сводную таблицу, которая покажет для всех наших пе ременных и для всех рассматриваемых блоков, где эти перемен ные будут локализованными (л), где глобальными (г) и где они не определены (-)
Идентифн- |
С1 |
Метки блоков |
С5 |
1 С8 |
ст |
||
каторы |
С2 |
СЗ |
С4 |
||||
— I----- |
2 |
---s ~ |
|
S |
в |
7 |
8 |
Г |
Л |
Г |
Г |
г |
г |
г |
г |
а |
- |
Л |
Г |
г |
__ 1_____ :__ |
- |
|
|
|
_____ 1_ |
|
|

61
t |
2 |
. |
Л |
3 |
6 |
7 |
в |
I |
3 |
4 |
|||||
W |
_ |
_ |
_ |
Л |
_ -_ |
|
|
X |
_ _ |
|
Л |
— — |
|||
У |
- |
_ |
— — |
- |
Л |
г |
|
7, |
- ■ |
- |
- |
- |
Л |
То, что было сказано о переменных величинах, естественным об разом распространяется на идентификаторы. Несколько .перефра зируя результаты, можно сказать, что идентификатор определен в любом блоке, для которого он является локализованным или ■ глобальным, и нигде больше. Наконец, сделаем замечание о мет ках - они всегда локализованы в том блоке, в котором они на писаны. Отсвда следует, что метки в различных блоках могут не отличаться одна от другой и что невозможно передать управ
ление из одного блока в середину другого |
(не являющегося его |
подблоком). |
' |
. Все изложенное в этом пункте весьма существенно при сос тавлении более или менее сложных программ, когда применяется так называемое блочное программирование. Попробуем пояснить, что это такое. Как известно, всякая программа должна быть блоком. Разделим ее на несколько независимых подблоков таким образом, чтобы переменные и массивы, используемые в одном блоке, не использовались ни в каком другом. При этом инфор мация, используемая во всех подблоках, должна быть описана в их внешнем блоке, а в описаниях подблоков должна быть толь
ко та информация, которая используется только в каждом конк- / ретном подблоке.
Приведем чисто учебный пример подобного процесса програм* мирования. Пусть требуется составить программу для вычисле ния по следующим формулам:
1 = |
■г |
__________ 1 |
+ |
|
а |
|
|
|
(8 * Ъ х Г 2 “ |
3 (а + Ъ х г | - |
|||||
|
|
||||||
кпа г = |
х V х 2- a2 f |
а 2 т „ / v |
ЛЛх |
2 |
~ а |
2 / |
|
---- :--------V — |
J.n / х |
|
/ ; |
||||
|
|
о |
? |
|
|
|
|
|
— 62 |
Апз 3 •VЪ1* - х |
v - |
|
причем известно, что все входящие в них величины вещественны
и в результате должны быть напечатаны величины а, ъ, |
х, |
Ansi, |
|||||||
Ans2, |
Ans3 |
. Нетрудно |
заметить, что в выражение |
а п з |
1 |
дваж |
|||
ды входит величина (в+Ъх)?- |
, поэтому естественно описать ее |
||||||||
идентификатором, например temp |
. в выражение для |
Ans 2 |
|||||||
трижды входит величина |
еЛ |
и дважды величина^/ х 2 - а 2 ' , |
|||||||
для них возьмем идентификаторы |
asg |
и r o o t |
. Аналогичное |
||||||
положение в выражении |
Ап б З |
|
куда трижды входит величина |
||||||
ь г |
и дважды в е л и ч и н а ~ |
|
; для них введем идентифика |
||||||
торы |
bsq |
и root . Очевидно, |
что |
введенные нами пять вспомо |
гательных величин нужны не одновременно, поэтому наиболее вы годной будет следующая программа:
begin r e a l |
а, |
Ъ, у , |
апз |
1 , |
аг.я |
2, |
Апг |
3 |
; |
|
|||
ВВОД |
( а , |
Ь , у.) |
• |
|
|
|
|
|
|
|
|
|
|
|
begin r e a l |
temp |
; |
|
|
(a |
t |
b v |
x ) • |
||||
|
Ans |
|
|
tempi= |
sq rt |
||||||||
|
i :з(2/ЬТ 2 ) x ( ” i/tem p |
+ a/ |
(3 |
у |
temp 4*3)) ; |
||||||||
eng |
- |
|
|
|
|
|
|
|
|
|
|
|
|
begin |
r e a l |
r o o t , |
aso |
• |
|
|
|
|
|
|
|||
|
|
a s q j |
= |
a'f |
2 |
; ’ |
|
- |
esq ) |
• |
|
|
|
|
|
r o o ti= |
s o r t |
( x t |
2 |
|
|
||||||
|
|
Ans2 :=x x r o o t /2 + |
aen/2 |
x |
In |
(abs (x * ro o t),' |
|||||||
end |
; |
|
|
|
|
|
|
|
|
|
|
|
|
b eg in r e e l |
r o o t , |
bso |
; |
|
|
|
|
|
|
||||
|
|
b s q : = b f 2 |
; |
(bsc |
- |
|
. |
; |
|
|
|||
|
r o o t : |
= |
aqrt |
x l ? ) |
|
|
|||||||
|
Ans 3 s = r o o t* b s q /r o o t |
|
|
|
|||||||||
еп* |
; |
|
|
|
|
|
|
|
|
|
|
|
|
.печать (а, ь, х, апз |
i , апя |
?, апз |
з |
) |
|
|
end
63
Собственные переменные
Отметим, что после выхода из блока, значения всех пере менных, описанных в этом блоке, утрачиваются. Однако в неко торых случаях бывает нужно вернуться в тот блок, из которого ранее мы вышли; при этом хотелось бы, чтобы некоторая пере менная сохраняла то значение, которое она имела при выходе из блока. Для этого нужно перед описанием этой переменной поставить слово own , а само описание ставить раньше дру гих описаний. При этом возникает такое затруднение: ведь на чальное значение для переменной, описанной в блоке, должно быть присвоено ей именно в этом блоке, но тогда при возврате в блок даже с сохранившимся значением переменной ей вновь будет присвоено начальное значение. Однако это затруднение можно обойти с помощью использования переключателя. Покажем это на примере программы, вычисляющей сумму ряда Фибоначчи I, I, 2, 3, 5, 8 ... , где каждый член, начиная с третьего, есть сумма двух предыдущих.
Следует отметить, что число членов ряда больше или рав но двум и что начальное значение суммы берется равным двум. Программа будет иметь следующий вид:
begin Integer вит, which, 1, n, next ;
ВВОД (n ) f
Burnt => 2.0 ; which:* 1 .0 ;
next: > 0.0 |
for it * 2 atep 1 until n do begin
sumt = num + next j go to Fibonacci ;
Fibonacci: begin own*~Integer Fib,Prey Fibj integer T?mp;
|
|
|
|
— |
64 |
|
|
|
|
|
|
switch |
$ |
j о |
f i r s t , |
th e re afte r j |
|||
|
|
go |
to |
S |
[w h io h j |
$ |
|
|
|
f i r s t |
t |
Fib |
t - |
P rer ,Plb i |
» 1 |
j |
|
||
|
|
whloh j о 2 t |
|
|
|
|
|||
th e re a fte r» |
Teep i » Fib + |
Prev |
Flh ; |
||||||
|
|
Prev Fib i я Fib ; |
|
|
|||||
|
|
next» |
ш Fib |
I a |
Temp f |
||||
and |
|
end |
; |
|
|
|
|
|
|
печать |
( en* |
) |
|
|
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
Можно пояснить, |
что |
Prev |
Fib |
и Fib |
|
- |
это идентификаторы |
предыдущего и последующего членов ряда Фибоначчи. При первом обращении к переключателю величина which имеет значение
Г, которое присвоено ей во внешнем блоке, и управление пере дается метке f i r s t . которая присваивает Prev Fib и Fib
их начальные значения, т.е. I, кроме того, переменной which присваивается значение 2. Поэтому при Последующих обращениях к переключателю приходится иметь дело с передачей управления
метке |
th e re afte r |
, оператор которой вычисляет следующий |
|||
член ряда и присваивает его |
значение |
переменной next |
, |
||
а также |
присваиваются новые |
значения |
предпоследнему и последт |
||
нему члену ряда. |
|
|
|
|
Процедуры
Материал, изложенный выше, дает довольно полное представ ление об алгоритмическом языке АЛГОЛ-60; мы получили возмож ность составлять программы с довольно сложной логической структурой. Но есть еще один способ, который позволяет опи сывать алгоритмы в более сжатой форме, а также использовать
—6 5 --
ранее накопленный опыт. Для этого применяются так называе мые процедуры. Под этим термином в АЛГОЛ-60 понимается какаялибо последовательность действий по обработке числовой или логической информации, которая рассматривается как единое целое. Такую процедуру удобно расположить где-то в программе и иметь возможность обращаться к ней по мере надобности.
Необходимо четко различать определение алгоритма, кото рый реализует процедура , и использование этой процедуры. Процедура определяется с помощью описания процедуры,- которое состоит из заголовка процедуры и тела цроцедуры. Заголовком процедуры является ее идентификатор, а также название ее па раметров. Тело процедуры обычно является блоком, но может быть оостжвнын оператором или даже просто оператором.
В качестве первого примера рассмотрим процедуру, нахо
дящую больший из вещественных корней квадратного уравнения |
|
||||
|
ах® * Ъх + о ш О , |
|
|
|
|
при этом мы предполагаем, что такой корень существует и что |
|
||||
коэффициент |
при квадрате неизвестной больше нуля. Процеду |
|
|||
ре, реализующей эту задачу, присвоим идентификатор |
го°* |
: |
|||
она выглядит |
так: |
|
|
|
|
procedure root |
(а,Ъ,с,х) j real |
a,b,c,x ; |
|
|
|
|
Х|я |
(“b+aqrt |
a * с » / ( 2 |
- a) |
|
Эта процедура приводит к реализации некоторого |
алгорит |
ма, но для его выполнения необходимо обратиться к процедуре. Это обращение осуществляется написанием ее названия и заме
ной формальных параметров- а , ъ и ° |
соответствующими фак |
||
тическими параметрами; если искомая величина |
х |
также |
|
рассматривается как формальный параметр, |
то и она должна |
быть заменена-фактическим параметром. Если например, требу ется вычислить больший вещественный корень квадратного урав
нений, в котором коэффициент |
при |
х 2 |
равен 16,9, |
коэффи |
|
циент при х |
равен &-t |
, а |
свободный член 1 |
+ 1 2 , |
причем искомая величина должна сохраняться в памяти машины
в виде |
нового значения величины answer |
, все это |
можно |
сделать |
путем написания соответствующего обращения к |
|
66
процедуре, > именно |
_ |
root (16,9, s-t, 5 + |
12, answer) ; |
В результате этого обращения тело процедуры примет вид |
|
£> |
|
answer 1э(-(s-t)+eqrt ((s-t)t2~4 |
* 16.9 ' ( W 2 ) ) / ( 2 к 16.9)? |
Если в каком-то другом месте той же программы понадобит ся вычислить аналогичный корень уравнения
х 2 - 7х *■ In (2 ♦ g) » О
й назвать этот'корень reenlt |
, то |
это можно |
сделать, напи |
сав обращение к процедуре ' |
|
|
|
root (1 .0,-7 .О, In |
(2 + g), |
result) |
} |
и, наконец, если в той же программе нам еще раз нужно найти аналогичный корень уравнения
2 х 2 t |
ах + |
Ъ « О. |
и назвать его xvalue |
, то |
это достигается следующим обра |
щением к процедуре . |
|
|
root (2 ,а,Ъ, xvalue) ;
Вэтом случае очень важно отметить,•что фактические параметры
еи ъ , стоящие в обращении к процедуре, не имеют ничего
общего с формальными параметрами а и ъ , стоящими в описа нии процедуры.
Формальные параметры представляют собой "пустые" перемен ные, т.е. такие переменные, которые нигде до этого не были
описаны; они указывают только на то, что |
должно быть |
сделано |
с фактическими параметрами, указанными в |
обращении к |
проце |
дуре. |
. |
Фактические параметры представляют собой выражения, |
ко |
торые могут содержать переменные величины, но они обязатель но должны быть уже описаны в программе, содержащей обращение к процедуре. Отметим, что в рассмотренном примере тело проце дуры было самым простым, т.е. просто оператором.
Рассмотрим теперь пример процедуру, у которой тело про-
цедуры представляет собой составной оператор. Допустим, из вестно, что квадратное уравнение
ах^ + Ьх + о » 0
имеет два вещественных корня (следовательно а / 0) и их надо
найти. Присвоим процедуре, решавдей эту задачу, идентификатор ro o t 2 . Тогда описание" этой процедуры будет сдрдувдим:
prooednre |
root 2 (e,b,o,xl ,х2 ); real |
a,b,c,xi,x2 |
j |
|||
begin x1 1 |
a (-b + eqrt |
(bf2 - 4 |
* a x |
o)) / (2 x |
a) |
\ |
x2i |
a (-b - aqrt |
(bf2 -4 |
* a * |
o)) / (2 |
x a) |
|
end |
|
« |
|
|
|
|
'~r~ |
|
|
|
|
|
По-видимому, более естественно построить вычисления та ким образом, чтобы вычислять корень из дискриминанта только один раз. Тогда написание этой процедуры будет несколько от личаться от предыдущего, а именно:
prooednre |
ro o t |
2 |
(а ,Ь ,о ,х 1 ,x 2 )j |
re a l |
а ,Ъ ,о ,х 1 ,х 2 j |
|||||
begin re a l |
temp |
j |
|
|
|
|
|
|
|
|
|
tempi |
« |
aqrt |
(b l2 - |
4 * |
a |
no) |
; |
||
|
x1i |
= |
( - b |
♦ |
temp) |
/ (2 |
* a) |
; |
||
|
x2i |
a |
( -b |
- |
temp) |
f |
(2 |
* a) |
; |
|
end. |
|
|
|
|
|
|
|
ч |
|
|
Причем на этом примере явно видна целесообразность представ
ления тела процедуры в виде блока; кроме того, эта процедура потребует для своей реализации меньше машинного времени.
(Здесь мы поступили не вполне корректно, присвоив двум раз личным процедурам одно наименование,т.е. общий для них иден тификатор root 2 ; но поскольку оба они выполняют одно и
то же, то нам казалось, что это не очень предосудительно).
68
Теперь приведем пример процедуры, у которой тело проце дуры является блоком. Допустим, что нам нужно найти наиболь ший по абсолютной величине элемент заданной строки двумерно го массива с размерами n х п . Входными данными для такой процедуры являются идентификатор массива, номер строки и чис ло строк. Выходными данными должны быть наибольший элемент и номер его столбца. Искомая процедура имеет следующий вид:-
prooadnre bigi |
(a .i.n .g ij ,.1 ) ; real |
array a, Integer i , n , j |
||||||||
begin integer |
k |
; |
|
|
|
|
real |
eij |
|
|
|
|
|
|
|
|
|
|
|||
|
|
«Ц » |
= |
a |
[i,l] |
; |
|
|
||
|
|
3 |
« = 1 |
: |
|
|
|
|
|
|
fo r |
ks |
» |
2 3tep 1 |
ont i l |
n do |
|
||||
|
if |
abe |
(a |
|4 |
,kJ |
) ^ |
a ij |
then |
||
begin |
aij |
« |
= |
a |
j^i, k^j |
; |
||||
|
|
|
j |
: |
- |
k |
|
|
|
|
|
end |
|
|
|
|
|
|
|
|
end
Смысл этой процедуры весьма прост. Он 'заключается в том, что присваивается абсолютная величина значения первого эле мента данной строки той переменной, которая в конце принима ет искомое значение. Затем она сравнивается последовательно со всеми элементами рассматриваемой строки. Всякий раз, ког да обнаруживается больший по абсолютной величине элемент, мы присваиваем его значение рассматриваемой переменной, а номер соответствующего столбца присваивается переменной, которая в конце вычислений укажет номер столбца, в котором находится искомый элемент. После выполнения этого сравнения мы получим ответ, т.е. значение искомого элемента и номер столбца, в ко тором он расположен (в данной строке). Если теперь в какомто месте той программы, в которой написана эта процедура, понадобится найти наибольший по абсолютной величине элемент
69
седьмой строки матрицы 15x15, то это можно сделать с помощью обращения к процедуре.
blgi (matrix, 7, 15, walue, column ) , |
|
|
|
|
в котором использованы идентификаторы: матрицы - |
matrix |
|
; |
|
искомого элемента - |
walue |
' |
; |
|
столбца |
- |
column |
|
|
Сделаем замечание, имеющее своей целью облегчить понима |
|
|||
ние процедур. До сих пор, когда мы писали заголовок процеду |
|
|||
ры, то в том случае, если он содержал более |
чем один формаль |
|||
ный параметр, мы отделяли эти формальные параметры друг от |
|
|
||
друга запятой. Однако можно использовать в качестве раздели |
|
|||
теля вместо запятой следующую конструкцию: |
закрывающую скоб |
|
ку, за которой следует строка букв, т.е. любой буквенный текст, служащий душ пояснения, далее следует двоеточие и, наконец, открывающая скобка. Этим способом можно пользоваться всегда, когда это будет казаться целесообразным; он не влияет на ра боту программы. Если в описании процедуры мы воспользовались этки приемом, то при обращении к рассматриваемой процедуре можно поступать по своему усмотрению, т.е. писать поясняю щий текст, но можно и не писать. Так, в приведенной выше про
цедуре. ее заголовок был |
написан следующим образом: |
||||||
procedure |
o l g i |
( |
s , i , n , c i j , j |
) |
; |
|
|
и если бы нужно было пояснить |
его, |
то |
можно |
сделать это |
|||
следующим образом: |
|
|
|
|
|
|
|
prooedure |
M g i |
(а) строке : (х) порядок, (п ) |
|||||
■элемент: |
(aij) |
столбец; |
( j |
); |
Подчеркнем, что пояснения относятся к формальным параметрам, начиная со второго. 3 случае если имеется только один фор мальный параметр, то подобный прием неприменим.
Ввиду важности понятия процедуры приведем еще несколько примеров.