Языки и технология программирования 2

–PAGE_BREAK–ЛИНЕЙНЫЕ АЛГОРИТМЫ
Алгоритмические действия над исходными данными и рабочими объектами языка, необходимые для решения поставленной задачи описываются при помощи операторов Турбо Паскаля. Операторы разделяются точкой с запятой, их последовательность и составляет тело программы. Наиболее простой случай представляют собой линейные алгоритмы. При выполнении линейных участков алгоритма операторы выполняются последовательно друг за другом в том порядке, в котором они перечислены в программе. При этом могут использоваться операторы присваивания, операции ввода и вывода.
ПУСТОЙ И СОСТАВНОЙ ОПЕРАТОРЫ
В программе может применяться пустой оператор, не выполняющий никакого действия. Он представляет собой точку с запятой.
Составным оператором считается последовательность произвольных операторов, заключенная в операторные скобки — зарезервированные слова begin… end. Допускается произвольная глубина вложенности составных операторов. Составной оператор применяется там, где по синтаксическим правилам языка может стоять только один оператор, а нам надо выполнить несколько действий. В этом случае набор необходимых команд должен быть оформлен как составной оператор. По сути, все тело программы представляет собой один составной оператор.
ОПЕРАТОР ПРИСВАИВАНИЯ
Оператор присваивания используется для задания значения переменных и имеет следующий синтаксис:
имя_переменной := выражение;
Вычисляется выражение, стоящее в правой части оператора, после чего его значение записывается в переменную, имя которой стоит слева. Тип выражения и тип переменной должны быть совместимы, т.е. множество допустимых значений для типа выражения содержится во множестве допустимых значений для типа переменной.

ПРОСТЕЙШИЙ ВВОД И ВЫВОД
Рассмотрим простейшие процедуры ввода и вывода. По умолчанию ввод осуществляется с клавиатуры, а вывод на экран. К операторам ввода относятся:
Read();
Readln();
Readln;
Второй отличается от первого тем, что после ввода переводит курсор на новую строку, точнее, в конце своей работы считывает с клавиатуры код клавиши Enter>. Третий оператор используется для организации паузы — выполнение программы продолжится, как правило, только после нажатия на клавиатуре клавиши Enter>. К операторам вывода относятся:
Write();
Writeln();
Writeln;
В списке вывода кроме имен переменных можно писать строковые константы (последовательность символов в апострофах) и даже выражения (выводятся их значения). Второй оператор отличается от первого тем, что после вывода переводит курсор на новую строку. Третий оператор просто переводит курсор на новую строку.
Существует так называемый форматированный вывод. Можно задать количество позиций, отводимых под число. Для целых — после выражения или переменной через двоеточие указывается меньше какого количества позиций не может быть выделено значению. Для вещественных — дополнительно через двоеточие можно указать количество цифр в дробной части. При этом происходит округление в ближнюю сторону.
ПРИМЕР:Простые вычисления.
program vvod_vyvod;
const n=1.5;
var y1,y2:real; x:byte;
begin
writeln(‘Введите натуральное число
readln(x);
y1:=cos(n); y2:=cos(x);
write(‘Зачем-то посчитали: ‘);
writeln(‘n=’,n,’ y1=’,y1:7:4, cos(Pi/2):8:4);
{напечатается
Зачем-то посчитали: n= 1.50000000000000E+0000
y1= 0.0707 1.0000}
writeln(‘x=’,x:3,’ y2=’,y2:7:4);
end.
РАЗВЕТВЛЯЮЩИЕСЯ АЛГОРИТМЫ
В Турбо Паскале имеется возможность нелинейного хода программы, т.е. выполнения операторов не в том порядке, в котором они записаны. Такую возможность нам предоставляют разветвляющиеся алгоритмы. Они могут быть реализованы одним из трех способов: с использованием операторов перехода, условного оператора или оператора выбора.
ОПЕРАТОР ПЕРЕХОДА
Оператор перехода имеет вид
GOTO .
Он позволяет передать управление непосредственно на нужный оператор программы. Перед этим оператором должна располагаться метка отделенная от него двоеточием. В Турбо Паскале в качестве меток выступают либо целые числа от 0 до 9999, либо идентификаторы. Все метки должны быть описаны в разделе объявления меток следующим образом:
label ;
Каждой меткой в программе может быть помечен только один оператор. Операторов перехода с одной и той же меткой можно писать любое количество. Необходимо, чтобы раздел описания метки, сама метка и оператор перехода с ее использованием располагались в пределах одного блока программы (см. тему процедуры и функции). Кроме того, нельзя передавать управление внутрь структурированных операторов (например, if, for, while, repeat и др.).
УСЛОВНЫЙ ОПЕРАТОР
Условный оператор IF позволяет изменить порядок выполнения команд в зависимости от некоторого логического условия, т.е. он осуществляет ветвление вычислительного процесса. Условный оператор имеет вид:
IF THEN [ELSE ];
В случае истинности логического выражения, стоящего в условии, выполняется , а пропускается. При ложном значении логического выражения пропускается и выполняется .
Оператор IF может быть полным (присутствуют обе ветви) или неполным (Else-ветви нет, при ложном условии ничего не делается). По правилам каждая из ветвей может содержать либо один выполняемый оператор, либо несколько, объединенных в составной. Точка с запятой перед Else считается ошибкой.
ПРИМЕР: Ввести целое число. Вывести соответствующий ему символ ASCII-таблицы, либо сообщить, что такого символа нет (0-31 — управляющие коды, затем до 256 — печатаемые символы).
program ascii_symbol;
var i:word;
begin
write(‘Введите целое число: ‘); readln(i);
if (i>31) and (ithen
writeln(‘Соответствующий символ — ‘, Chr(i))
else writeln(‘Такого символа нет’);
readln
end.
ОПЕРАТОР ВЫБОРА
Если у вас не два возможных варианта выполнения программы, а больше, то может использоваться оператор выбора CASE. Структура этого оператора в Турбо Паскале:
CASE OF
C1: ;
C2: ;
CN: ;
[ELSE ;]
END;
Здесь — это выражение порядкового типа, в зависимости от значения которого принимается решение; C1,…,CN — значения, с которыми сравнивается значение ; ,…, — оператор (возможно составные), из которых выполняется тот, с константой которого происходит первое совпадение значения , выполнится, если значение ключа не совпадает ни с одной из констант C1,…,CN.
Ветвь Else не обязательна, и в отличие от оператора if, перед ней можно ставить точку с запятой. Если для нескольких значений действия совпадают, то эти константы можно перечислить через запятую перед двоеточием или даже задать диапазон значений (нижняя граница… верхняя граница).
ПРИМЕР: Вводится целое число, если это цифра, то определить четная она или нет, а если число, то определить попадает ли оно в диапазон от 10 до 100, если нет, то выдать соответствующее сообщение.
program chislo;
var i:integer;
begin
write(‘Введите целое число: ‘);
readln(i);
case i of
0,2,4,6,8: writeln(‘Четная цифра’);
1,3,5,7,9: writeln(‘Нечетная цифра’);
10…100,200: writeln(‘Число от 10 до 100 или 200’);
else writeln(‘Число либо отрицательное, либо > 100, но не 200’);
end;
readln
end.
ЦИКЛИЧЕСКИЕ АЛГОРИТМЫ
Турбо Паскаль позволяет использовать три различных оператора для организации повторяющихся последовательностей действий, которые называют циклами.
ЦИКЛЫ С ПАРАМЕТРОМ
Оператор цикла For организует выполнение одного оператора заранее определенное число раз. Его еще называют цикл со счетчиком. Существует две формы оператора:
FOR := TO DO ;
FOR := DOWNTO DO ;
Здесь параметр цикла (счетчик) представляет собой переменную порядкового (ординального) типа; и — выражения, определяющие начальное и конечное значение счетчика; — один (возможно составной) оператор, который называют телом цикла, повторяемый определенное число раз.
На первом шаге цикла параметр принимает значение nz. В этот же момент происходит вычисление kz — значения параметра на последнем шаге цикла. После каждого выполнения тела цикла, если параметр цикла не равен kz, происходит изменение параметра на следующее большее или меньшее значение в зависимости от формы оператора for, т.е. неявно происходит выполнение одного из двух операторов:
:= Succ();
:= Pred();
В случае nz > kz в первой форме оператора или nz
РЕКОМЕНДАЦИИ: Использовать цикл for при заранее известном количестве повторений. Не изменять параметр в теле цикла. При использовании кратных (вложенных) циклов применять разные переменные в качестве параметров. Определять до цикла значения всех используемых в нем переменных. Не ставить точку с запятой после do.
ПРИМЕР: Вводятся 10 чисел, посчитать среди них количество положительных.
program cycle_for1;
var i,kn:byte; x:real;
begin
kn:=0;
for i:=1 to 10 do
begin
writeln(‘Введите ‘,i,’ число: ‘);
readln(x);
if x>0 then kn:=kn+1 {увеличиваем количество на 1}
end;
writeln(‘Вы ввели ‘,kn,’ положительных чисел.’);
readln
end.
ПРИМЕР: Напечатать буквы от ‘Z’ до ‘A’.
program cycle_for2;
var c:char;
begin
for c:=’Z’ downto ‘A’ do write(c);
readln
end
ПРИМЕР: Вычислить N-е число Фиббоначчи. Числа Фиббоначчи строятся следующим образом: F(0)=F(1)=1; F(i+1)=F(i)+F(i-1); для i>=1. Это пример вычислений по рекуррентным формулам.
program Fib;
var a,b,c:word; i,n:byte;
begin
write(‘введите номер числа Фиббоначчи ‘);
readln(N);
a:=1; {a=F(0), a соответствует F(i-2)}
b:=1; {b=F(1), b соответствует F(i-1)}
for i:=2 to N do
begin
c:=a+b; {c соответствует F(i)}
a:=b; b:=c; {в качестве a и b берется следующая пара чисел}
end;
writeln(N,’-е число Фиббоначчи =’,b); {для N>=2 b=c}
readln
end.
ЦИКЛЫ С УСЛОВИЕМ
Если заранее неизвестно число повторений цикла, то используются циклы с условием. В паскале имеется два типа таких циклов. Циклы While называют циклами с предусловием. Они имеют вид
WHILE DO ;
Цикл While организует выполнение одного (возможно составного) оператора пока истинно логическое выражение, стоящее в заголовке цикла. Поскольку значение логического выражения проверяется в начале каждой итерации, то тело цикла может не выполниться ни разу. Таким образом, в этом цикле логическое выражение — это условие продолжения работы в цикле.
Другой вариант циклов с условием — это циклы Repeat. Их называют циклами с постусловием. Они имеют вид
REPEAT

UNTIL
Оператор Repeat организует повторяющееся выполнение нескольких операторов до тех пор пока не станет истинным условие, стоящее в Until-части. Тело цикла обязательно выполняется хотя бы один раз. Таким образом, в этом цикле логическое выражение — это условие выхода из цикла.
При создании циклических алгоритмов Турбо Паскаль позволяет использовать процедуры Continue и Break. Процедура Continue досрочно завершает очередной шаг цикла, передает управление на заголовок. Процедура Break реализует немедленный выход из цикла.
РЕКОМЕНДАЦИИ: Для того, чтобы избежать зацикливания программы необходимо обеспечить изменение на каждом шаге цикла значения хотя бы одной переменной, входящей в условие цикла. После выхода из цикла со сложным условием (с использованием операций and, or, xor) как правило необходима проверка того, по какому условию цикл завершен.
ПРИМЕР: Пары неотрицательных вещественных чисел вводятся с клавиатуры. Посчитать произведение для каждой пары и сумму всех чисел.
program cycle_while;
var x,y,sum:real; otv:char;
begin
sum:=0;
otv=’Д’;
while (otv=’Д’) or (otv=’д’) do
begin
write(‘Введите числа x,y > 0 ‘);
readln(x,y);
writeln(‘Их произведение = ‘,x*y:8:3);
sum:=sum+x+y;
write(‘Завершить программу (Д/Н)? ‘);
readln(otv);
end;
writeln(‘Общая сумма = ‘,sum:8:3);
readln
end.
ПРИМЕР: В той же задаче можно использовать другой цикл с условием:
program cycle_repeat;
var x,y,sum:real; otv:char;
begin
sum:=0;
repeat
write(‘Введите числа x,y > 0 ‘);
readln(x,y);
writeln(‘Их произведение = ‘,x*y:8:3);
sum:=sum+x+y;
write(‘Завершить программу (Д/Н)? ‘);
readln(otv);
until (otv=’Д’) or (otv=’д’);
writeln(‘Общая сумма = ‘,sum:8:3);
readln
end.
ПРИМЕР: Нахождение наибольшего общего делителя двух целых чисел с помощью Алгоритма Эвклида.
program Evklid;
var a,b,c:integer;
begin
write(‘введите два целых числа: ‘);
readln(a,b);
while b0 do
begin
c:=a mod b;
a:=b;
b:=c;
end;
writeln(‘наибольший общий делитель = ‘,a);
readln
end.

ПОЛЬЗОВАТЕЛЬСКИЕ ТИПЫ ДАННЫХ
В Турбо Паскале предусмотрен механизм создания новых типов, которые принято называть пользовательскими или конструируемыми. Их можно создавать на основе стандартных и ранее созданных типов. Описание новых типов происходит в разделе TYPE. После этого можно в разделе Var создавать переменные этих типов. Также, можно сразу описывать новый тип при создании переменной в разделе Var. В этой главе мы рассмотрим следующие пользовательские типы:
перечисляемый тип,
тип-диапазон,
массивы,
записи.
ПЕРЕЧИСЛЯЕМЫЙ ТИП
Перечисляемый тип задается перечислением тех значений, которые он может получать. Каждое значение должно являться идентификатором (смотри главу Алфавит языка) и располагаться в круглых скобках через запятую. Количество элементов в перечислении не более 65536. Вводить и выводить переменные перечисляемого типа запрещено. Перечислимый тип является порядковым (смотри главу Типы данных), поэтому к переменным такого типа можно применять функции Ord, Pred, Succ. Функция Ord возвращает порядковый номер значения начиная с нуля.
ПРИМЕР: Объявление перечисляемых типов.
Type Colors = (Red,Green,Blue);
Numbers = (Zero,One,Two,Three,Four,Five);
var c:Colors; n:Numbers;
begin
c:=Red; write(Ord(c)); {0}
n:=Four; write(Ord(n)); {4}
c:=Succ(c); {c=Green}
for n:=One to Five do write(Ord(n)); {12345}
end.
Следует отметить, что стандартные типы byte, word, char и boolean также можно считать вариантами перечислимого типа.
ТИП-ДИАПАЗОН
Тип-диапазон также называют ограниченным или интервальным типом. Он является подмножеством своего базового типа, в качестве которого может выступать любой порядковый тип кроме типа-диапазона. Тип-диапазон наследует все свойства своего базового типа. Имеются две стандартные функции, работающие с этим типом: High(x)- возвращает максимальное значение типа-диапазона, к которому принадлежит переменная x; Low(x) — возвращает минимальное значение.
ПРИМЕР: Объявление типа-диапазон.
type Numbers = (Zero,One,Two,Three,Four,Five);
Num = Two… Four; {диапазон на базе типа Numbers}
Abc = ‘A’… ‘z’; {все английские буквы: диапазон на базе типа Char}
Digits = 0… 9; {цифры}
var n:Num; c,d:Abc; x:integer;
begin
n:=Four; writeln(Ord(n)); {4 как в базовом типе}
n:=Succ(n); { ОШИБКА (следующее значение вне диапазона)}
read(c,d);
if c=d then write(‘одинаковые буквы’);
writeln(Low(c),’… ‘,High(c)); { A… z }
writeln(Low(x),’… ‘,High(x)); { -32768… 32767 }
end.
В тексте программы на Турбо Паскале могут встречаться директивы компилятору, которые также называют опциями. Опции {$R+} и {$R-} позволяют включать и отключать проверку соблюдения границ при работе с диапазонами. Когда проверка включена, при нарушении границ диапазонов происходит аварийное завершение работы программы. В другом случае ответственность за возможные ошибки лежит на программисте.
МАССИВЫ
Массив — это упорядоченная структура однотипных данных, хранящая их последовательно. Доступ к элементу массива осуществляется через его индекс. Массивы описываются следующим образом:
    продолжение
–PAGE_BREAK–Имя типа = ARRAY [ диапазоны индексов ] OF тип элемента массива;
В качестве типа для элементов массива можно использовать любые типы Турбо Паскаля кроме файловых. Диапазоны индексов представляют собой один или несколько диапазонов, перечисленные через запятую. В качестве диапазонов индексов нельзя использовать диапазоны с базовым типом Longint.
ПРИМЕР: Три способа описания одного и того же типа массива:
type {1} M1 = array [0..5] of integer;
M2 = array [char] of M1;
M3 = array [-2..2] of M2;
{2} M3 = array [-2..2] of array [char] of array [0..5] of integer;
{3} M3 = array [-2..2,char,0..5] of integer;
var A:M3;
{Обращаться к элементам массива можно следующим образом:}
begin
read(A[-1,’a’,3]);
read(A[1][‘x’][0]);
A[1][‘c’,1]:=100;
end.
Глубина вложенности, т.е. количество индексов, при определении массивов не ограничена. Играет роль только суммарный объем данных в программе. В стандартном режиме работы Турбо Паскаля этот объем ограничен размерами сегмента, т.е. 64 килобайта. Целиком над массивами допускается применение только операции присваивания массивов (подмассивов) одинаковых типов. Остальные операции должны выполняться поэлементно.
ПРИМЕР: Вычисление значения многочлена степени N, коэффициенты которого находятся в массиве A в точке X по схеме Горнера.
Pn(x) = A[0]*X^n + A[1]*X^(n-1) +… + A[n-1]*X + A[n] =
= (…((A[0]*X + A[1])*X + A[2])*X +… + A[n-1])*X + A[n].
program Scheme_Gorner;
type Mas = array[0..100] of integer;
var A:Mas; i,j,n:integer; x,p:real;
begin
write(‘степень многочлена = ‘); read(n);
writeln(‘введите целые коэффициенты: ‘);
for i:=0 to n do read(A[i]);
write(‘значение X = ‘); read(x);
p:=0;
for i:=0 to n do p:=p*x+A[i];
writeln(‘Pn(X) = ‘,p);
end.
ЗАПИСИ
Запись — это стpуктуpа данных, которая может содержать информацию разных типов, объединенную под одним названием. Компоненты записи называются полями. Их фиксиpованное число. Описание записей имеет следующую стpуктуpу:
Имя типа = RECORD
список полей 1: тип 1;
— — —
список полей N: тип N;
CASE поле выбора: тип OF
значение 1: (полей 1: тип 1)
END;
Типы полей записи могут быть любыми. В свою очередь, тип запись может использоваться для создания массивов и новых записей. Степень вложенности не ограничена.
Список полей может состоять из двух разделов: постоянной и вариантной части. В постоянной части идет перечисление полей записи (идентификаторов) с указанием их типов. Синтаксис такой же, как в разделе var.
ПРИМЕР: Пример объявления типа запись.
type Men = Record
FIO,Adress: string;
Year: byte;
End;
var A,B: Men;
Для обращения к полям записи указывается имя переменной типа запись, точка, имя поля, напpимеp:
begin
A.FIO:=’Иванов И.И.’;
A.Adress:=’пp. Ленина, д. 40, кв. 10′;
A.Year:=1981;
end.
После описания постоянных полей может следовать вариантная часть, которая может быть только одна и имеет вид
CASE поле выбора: тип OF
значение 1: (список полей 1);
— — —
значение N: (список полей N);
Поле выбора может отсутствовать. Если оно есть, то его воспринимают как постоянное поле записи. Если его нет, указывается только тип, который должен быть порядковым, но он не влияет ни на количество перечисленных ниже значений, ни на типы этих значений.
Все варианты располагаются в одном и том же месте памяти, которой выделяется столько, сколько требуется для максимального по pазмеpу варианта. Это приводит к тому, что изменение одного вариантного поля оказывает влияние на все остальные. Это увеличивает возможности пpеобpазования типов, ПРИМЕР: Запись с вариантами.
var R = Record
rem: string;
Case byte of
3: (n:integer);
5: (x,y,z:char);
‘a’: (i,j:byte);
end;
begin
R.rem:=’запись с вариантами’;
R.n:=25000;
write(R.i,R.x,R.j,R.y); {168и97a}
{ord(‘и’)=168, ord(‘a’)=97, 168+97*256=25000}
end.
Значения выбора могут повторяться. Имена полей записи не являются переменными и, следовательно, могут повторяться, но только на разных уровнях, напpимеp:
var Rec:Record
x: real;
Sr: Record a: real; x,y: integer; end;
I: byte;
end;
Для удобства обращения к полям записей может использоваться опеpатоp присоединения
WITH переменная DO опеpатоp;
Здесь переменная — это запись, за которой может следовать список вложенных полей, напpимеp следующие три опеpатоpа эквивалентны:
With Rec,Sr Do a := x / y;
With Rec.Sr Do a := x / y;
Rec.Sr.a := Rec.Sr.x / Rec.Sr.y;
РАБОТА СО СТРОКАМИ
Тип String (строка) в Турбо Паскале широко используется для обработки текстов. Этот тип является стандартным и во многом похож на одномерный массив символов Array [0..N] of Char. Значение N соответствует количеству символов в строке и может меняться от 0 до 255. Символы, входящие в строку, занимают позиции с 1 до N. Начальный байт строки с индексом 0 содержит информацию о ее длине, т.е. это символ с кодом, равным длине строки.
Можно, также описывать переменные типа String[K], где K — целое число не больше 255. Так определяются строки с длиной не больше K. Этот тип уже не является стандартным. С символами строки можно работать как с элементами массива из символов, но в отличие от массивов, строки можно вводить целиком, сравнивать друг с другом и сцеплять операцией “+”.
ПРИМЕР: Работа со строками.
var s,x,y,z:string;
begin
x:=’turbo’;
y:=’pascal’;
z:=x+’ ‘+y; { z=’turbo pascal’ }
s:=”; { пустая строка }
for c:=’a’ to ‘z’ do s:=s+c; { s=’abcd..xyz’ }
writeln(s);
end.
Сравнение строк выполняется посимвольно в соответствии с их кодами до первого несовпадения. Если одна из строк закончилась до первого несовпадения, то она считается меньшей. Пустая строка меньше любой строки.
ПРИМЕР: Сравнение строк.
‘abcd’ > ‘abcD’ { ‘d’>’D’ }
‘abcd’ > ‘abc’ { ‘d’>” }
‘abc’
‘abcd’ = ‘abcd’
Существует ряд стандартных функций и процедур для работы со строками.
Функция Length(s) выдает длину строки s.
Функция Concat(s1,s2,..,sn) возвращает строку s1+s2+..+sn.
Функция Copy(s,p,k) возвращает фрагмент строки s, который начинается в позиции p и имеет длину k.
Функция Pos(s1,s) ищет первое вхождение подстроки s1 в строку s и возвращает номер первого символа s1 в строке s или 0 если не нашли.
Процедура Delete(s,p,k) удаляет из строки s фрагмент, который начинается в позиции p и имеет длину k.
Процедура Insert(s,s1,p) вставляет в строку s подстроку s1, начиная с заданной позиции p.
Турбо паскаль позволяет производить преобразования числовых значений в строковые и наоборот. Для этого используются процедуры Str(X:n:d,S) и Val(S,X,e). Первая получает их числа X строку S с изображением этого числа, в которой не менее n символов и из них d знаков после запятой. Параметры n и d необязательные. Вторая процедура получает из строки S число X. При успешном результате e=0.
ПРОЦЕДУРЫ И ФУНКЦИИ
Турбо Паскаль позволяет выделять фрагменты программы во вспомогательные алгоритмы (ВА). Это позволяет писать хорошо структурированные программы. Языки программирования, в которых предусмотрены ВА, называются процедурно-ориентированными. Структурированные программы обычно проще в понимании и отладке.
Наличие ВА в языке программирования позволяет применять более совершенные методы при разработке и проектировании сложных программных комплексов. Известны два наиболее широко применяемых подхода. Первый называется методом нисходящего программирования или разработкой программ “сверху — вниз”. При этом сначала создается главная программа, предполагая наличие некоторых ВА, решающих определенные задачи. Затем переходят к детальной разработке упомянутых выше необходимых ВА.
Другим подходом в разработке программ является метод восходящего программирования или проектированием “снизу — вверх”. В этом случае все начинается с создания небольших ВА, из которых затем создаются более сложные ВА и, наконец, основная программа.
В Турбо Паскале ВА оформляются в виде процедур или функций. Каждый ВА имеет собственное имя. Вызов процедуры на выполнение осуществляется отдельным оператором с помощью ее имени. Вызов функции может быть составной частью любого выражения при условии согласованности типов. Описание процедур и функций должно предшествовать их вызову и располагается перед началом основной программы. Нельзя вызывать на выполнение те ВА, которые содержатся внутри других процедур и функций. Описание процедуры имеет следующую структуру.
Procedure Имя (Список формальных параметров);
label
const Описание локальных меток,
type констант, типов и переменных
var
procedure Описание внутренних процедур
function и функций
begin
Операторы
end;
Описание функции имеет следующую структуру.
Function Имя (Список формальных параметров): Тип результата;
label
const Описание локальных меток,
type констант, типов и переменных
var
procedure Описание внутренних процедур
function и функций
begin
Операторы, среди которых хотя бы один, который
присваивает имени функции значение результата
end.
Типом результата в функциях может быть любой из стандартных типов Турбо Паскаля кроме файловых типов. Использование конструируемых типов здесь недопустимо.
Существуют понятия локальных и глобальных меток, констант, типов и переменных. Поясним эти понятия на примере переменных. Переменные, описанные в основной программе, являются глобальными по отношению к процедурам и функциям, которые описаны позже этих переменных. Аналогично, переменные, описанные в процедурах и функциях, являются глобальными по отношению к внутренним процедурам и функциям, которые описаны позже. Остальные переменные называются локальными. Их область действия локализована, т.е. ограничена, тем ВА, где они описаны.
Исходные данные для работы ВА можно передавать через глобальные переменные, а также через параметры. Параметры при вызове ВА называются фактическими, а параметры в заголовке ВА называются формальными.
Формальные параметры ВА также относятся к его локальным переменным. Локальные данные создаются, т.е. им выделяется память, при вызове ВА, а освобождение этой памяти происходит при завершении работы ВА. В том случае, когда локальная переменная имеет тот же идентификатор, что и глобальная, алгоритм работает с локальной. При этом, значение глобальной переменной сохраняется в специальной области памяти, которая называется стек.
По способу передачи параметры в Турбо Паскале делятся на три типа:
параметры-значения,
параметры-переменные,
параметры-константы.

Параметры-значения
При вызове процедур и функций формальным параметрам-значениям выделяется новое место в памяти и присваиваются значения фактических параметров. При этом на месте фактических параметров могут стоять выражения. Совместимость типов определяется возможностями присваивания. После выполнения подпрограммы место формальных параметров освобождается. Изменение формальных параметров не сказывается на значении фактических. Заголовок процедуры с параметрами-значениями имеет вид:
Procedure MyProc1(par1,par2: type1; par3,par4: type2);
Параметры-переменные
При вызове процедур и функций формальные параметры-переменные занимают то же самое место в памяти, что и соответствующие им фактические параметры. Таким образом, дополнительное место в памяти не выделяется и изменения формального параметра приводят к изменениям фактического. Параметры-переменные, как правило, используются для передачи результатов из процедур в вызывающий алгоритм.
Такой механизм передачи данных требует, чтобы фактические параметры были переменными, причем в точности того же типа, что и формальные параметры. При описании ВА перед параметрами-переменными должно присутствовать слово var. Заголовок процедуры с параметрами-переменными имеет вид:
Procedure MyProc2(var par1,par2: type1; var par3,par4: type2);
Параметры-константы
Работа с формальными параметрами-константами внутри ВА ведется как с обычными локальными константами. Только эти константы принимают значения выражений, которые находятся в фактических параметрах. Им не выделяется новая память как локальным переменным. Запрещается изменять их значения во время выполнения подпрограммы и контроль за этим осуществляется на уровне компилятора, как для обычных констант.
Использовать параметры-константы рекомендуется при передаче данных большого объема с гарантией сохранения их значений. Заголовок процедуры с параметрами-константами имеет вид:
Procedure MyProc3(const par1,par2: type1; const par3,par4: type2);
ОТКРЫТЫЕ ПАРАМЕТРЫ-МАССИВЫ
Открытые параметры-массивы могут быть параметрами-значениями, параметрами-переменными и параметрами-константами. Они используются для передачи массивов произвольной размерности. Заголовок процедуры с открытыми параметрами-массивами имеет вид:
Procedure OpenArray(Vector: array of MyType);
Формальный параметр при этом является массивом элементов некоторого типа MyType с нулевой базой, т.е. Array [0..N-1] of MyType; где N — количество элементов массива, которое можно определить с помощью стандартной функции High.
ПРИМЕР: Увеличение вдвое всех элементов массива.
program DoubleProgram;
const n=10; m=20;
type T1 = array[1..n] of integer;
T2 = array[-m..m] of integer;
var A: T1; B: T2; k: integer;
Procedure Double(var X: array of integer);
var i: byte;
begin
for i:=0 to High(X)-1 do X[i]:=X[i]*2;
end;
begin
for k:=1 to n do read(A[k]);
for k:=-m to m do read(B[k]);
Double(A); {увеличение в 2 раза элементов массива A}
Double(B); {увеличение в 2 раза элементов массива B}
Double(k); {то же самое, что и присваивание k:=k*2}
writeln(‘k=’,k); {напечатается: k=40 }
for k:=1 to n do write(A[k],’ ‘);
writeln;
for k:=-m to m do write(B[k],’ ‘);
end.
БЕСТИПОВЫЕ ПАРАМЕТРЫ
В Турбо Паскале существует возможность создания процедур и функций с параметрами, не имеющими типа. Бестиповые параметры могут быть параметрами-переменными и параметрами-константами, так как передаются только по адресу. Заголовок процедуры с параметрами, не имеющими типа может выглядеть таким образом:
Procedure MyProc(var par1,par2; const par3,par4);
Перед использованием формальных параметров необходимо выполнить их приведение к какому-либо типу. Использование бестиповых параметров дает большую гибкость программе, но ответственность за их корректное применение возлагается на программиста.
ПРИМЕР: Сложение первых N байт, начиная с того же места, что и X.
program without_type;
var N:word; s:string;
{$R-} (* отключение контроля за границами диапазонов *)
function Sum(var X; N:byte):word;
type A=array[1..1] of byte;
var i:byte; s:word;
begin
s:=0;
for i:=1 to n do S:=S+A(X)[i];
Sum:=s;
end;
begin
readln(s);
writeln(Sum(s,1)); {длина строки s}
writeln(Sum(s[1],1)); {код первого символа строки s}
writeln(Sum(s[1],length(s)));
{сумма кодов всех символов строки s}
read(N);
writeln(Sum(N,2));
{сумма двух байт, из которых состоит N типа word}
end.
ПРОЦЕДУРНЫЕ ТИПЫ
В Турбо Паскале существует два процедурных типа: тип-процедура и тип-функция. Для объявления процедурного типа используется заголовок процедуры или функции без имени.
ПРИМЕР:
type Proc1 = Procedure (a,b,c: integer; x:real);
Proc2 = Procedure (var a,b);
Proc3 = Procedure;
Func1 = Function: real;
Func2 = Function (n:integer): boolean;
Можно описывать переменные этих типов, например: var p1,p2:Proc1; f1,f2:Func2; Переменным процедурных типов можно присваивать в качестве значений имена соответствующих ВА. При этом нельзя использовать стандартные процедуры и функции. После такого присваивания имя переменной становится синонимом имени ВА. Переменные процедурного типа можно, также передавать в подпрограммы в виде параметров. Благодаря этому, имеется возможность создания более гибких вспомогательных алгоритмов.
РЕКУРСИЯ
Рекурсия — это способ организации вычислительного процесса, при котором подпрограмма в ходе выполнения обращается сама к себе. С идейной точки зрения рекурсия аналогична методу математической индукции. Базе индукции соответствует база рекурсии. Предположению индукции соответствует предположение о том, что нужный ВА уже написан. Наконец, шагу индукции соответствует вызов создаваемого рекурсивного ВА. В любой рекурсии необходимо предусмотреть условие завершения процесса, т.е. когда вызова больше не происходит.
ПРИМЕР: Вычислить N-е число Фиббоначчи. (Смотри тему Циклы)
program Fib;
var n:byte;
    продолжение
–PAGE_BREAK–