|
| |||||||||||||||||
Паскаль для новичков (часть 13)Процедуры и функции. Блочная структура программыАвтор: Владислав Демьянишин
В начале было слово Begin.
В конце было слово End.
А между ними было еще много слов,
Смысл которых был известен ему одному…
Вот и пришло время ознакомить Вас, мои дорогие читатели, с тем таинством, которое хранит в себе магия таких странных и непонятных на первый взгляд сгустков программного кода, именуемых процедурами и функциями.
Например, есть некоторая задача, состоящая в выводе текста на экран. Если пренебречь всеми хорошими советами и все-таки составить программу в виде одного блока Begin…End. (найдутся и такие умельцы ;O), то малейшая переделка уже имеющихся функциональных возможностей этой программы или добавление новых возможностей станет серьезной проблемой перед ее разработчиком.
Но если с самого начала подойти к разработке такой программы более дальновидно, то все может оказаться не так страшно.
Если программист в самом начале работы над своей программой и предположить не может, что еще может понадобиться в его программе, то хотя бы просто перестраховаться и составлять свою программу так, чтобы потом не было мучительно больно ее совершенствовать ;O)
Т.е. составить некоторые обособленные фрагменты кода, например, две процедуры. Одна для вывода строки текста на экран в заданной позиции и заданной длины, чтобы длинная строка урезалась до ширины экрана. А другая процедура для вывода определенного количества строк, в пределах окна начиная с некоторой строки.
Таким образом, если в дальнейшем понадобиться выводить текст каким-то особым способом, например, выделять отдельные символы цветом, шрифтом, курсивом, подчеркиванием, то придется переделать лишь процедуру вывода строки, а вторая процедура может остаться не тронутой.
Всегда легче решать локальные задачи, а потом составлять решение глобальной задачи по кирпичикам из уже имеющихся решений локальных задач.
Таким образом, при составлении программы, выполняющей некоторую задачу, программист должен позаботиться о такой структуре ее кода, чтобы разбить выполнение сложной задачи на менее сложные. При этом, для решения каждой упрощенной задачи составляется код, обособленный от всего остального кода программы, работающий с собственными (локальными) параметрами и операндами. Такой локальный код оформляется в виде подпрограммы, и как правило, имеет свой интерфейс.
Такой подход в программировании позволяет создавать хорошо читабельные (прозрачные) и гибко модифицируемые программы.
Так что же такое подпрограмма?
Подпрограмма – это самостоятельная часть программы, оформленная в виде отдельного блока, имеющая собственное имя, собственный перечень описаний типов, констант, переменных и меток. Все локальные переменные создаются в стеке перед началом выполнения подпрограммы и уничтожаются по ее завершении. Локальные объекты предназначены для операций внутри подпрограммы и являются видимыми только в пределах ее блока.
К тому же подпрограмма может иметь (или не иметь) входные и выходные параметры.
Но описать подпрограмму, это еще не все. Чтобы подпрограмма выполнялась, ее следует вызывать посредством указания в программе ее имени и списка параметров в скобках, при условии, что интерфейс данной подпрограммы предусматривает наличие входных параметров. Подпрограмма может быть вызвана из любой точки блока, в котором она описана. Т.е. подпрограмма может быть описана либо в глобальном блоке программы, и тогда она может вызываться из любой ее точки и из других подпрограмм, либо может быть описана в блоке другой подпрограммы, и тогда она будет известна в пределах объемлющего блока.
Используя такую гибкость языка, программист может разработать целый ряд собственных процедур и функций, на все случаи жизни, и потом использовать их с такой же легкостью, как и стандартные функции языка Pascal. При этом, используя интерфейс входных параметров можно настраивать работу подпрограммы необходимым образом. А используя интерфейс выходных параметров, можно получать результат работы по завершении подпрограммы.
Общая структура подпрограммИз выше сказанного уже наверно стало понятно, что структура подпрограммы строится так же, как и вся программа.
Составляя подпрограмму, следует указать следующие составляющие:
1) входной и выходной интерфейсы подпрограммы, обеспечивающие ее нормальный вызов;
2) описания локальных объектов;
3) составной оператор Begin..End, содержащий все необходимые действия.
Существуют два вида подпрограмм.
Процедуры – могут иметь (или не иметь) входные параметры, и предназначены для выполнения некоторой задачи.
Функции – помимо того, что могут иметь входные параметры, обязаны обеспечивать возврат выходного параметра (результата) в точку вызова, т.е. предназначены для выполнения некоторой задачи, но при этом по завершении должны возвращать результат в виде значения предопределенного типа. Таким образом, функции могут участвовать в любом выражении, где допустимо применение значения типа результата этой функции.
Итак, описания процедур и функций очень похожи. Для процедур, описание начинается со служебного слова procedure, а для функций со служебного слова function. Далее следует указать имя описываемой подпрограммы, а вслед за ним в скобках указать список входных параметров. Для функций, за списком параметров следует указать тип возвращаемого результата, которым может быть простой, строчный или ссылочный тип. Примеры:
procedure Init;
procedure MyWrite ( X, Y : word; Color : TColor; s : string );
function LowCase ( s : string ): string;
Тело подпрограммы. Области действия именТелом процедуры и функции является блок с описанием локальных констант, типов, переменных, меток, и вложенных подпрограмм. Т.е. любая процедура или функция может в свою очередь содержать ряд вложенных процедур и функций.
Будем рассматривать возможную структуру программы на следующем примере, который, для удобства, буду называть Рис. 1:
Programm A;
{ блок A }
Procedure B;
{ блок B }
Procedure C;
{ блок C }
Begin
…
End; { конец блока C }
Function D : byte;
{ блок D }
Begin
…
End; { конец блока D }
Begin
…
End; { конец блока B }
Procedure E;
{ блок E }
Begin
…
End; { конец блока E }
Begin
…
End. { конец блока A }
На рис. 1 буквой A – обозначен самый внешний (главный) блок программы. B и E – блоки подпрограмм, описанных во внешнем блоке A. C и D – блоки, вложенные в подпрограмму B (т.е. описанные в ней).
Организация структуры блоков требует определенной дисциплины для доступа к объектам:
1) Объекты, описанные в некотором блоке, считаются известными в пределах этого блока, а также во всех вложенных блоках;
2) Идентификаторы объектов, описанных в блоке, не должны повторяться в пределах данного блока, но могут совпадать с именами из других блоков;
3) Если в некотором вложенном блоке описан локальный объект, имя которого совпадает с именем объекта, описанного в объемлющем (внешнем) блоке, то во вложенном блоке это имя будет ассоциироваться с одноименным локальным объектом. Т.е. одноименный объект из внешнего блока будет перекрыт локальным одноименным объектом.
Подпрограмма B будет известна (видна) не только в блоке A, но и в блоке E. Подпрограмма C будет известна не только в блоке B, но и в блоке D. Таким образом, вложенные подпрограммы будут видеть все объекты, описанные во внешних блоках. Т.е. в блоке C и D будут известны все объекты, описанные в блоках B и A. В блоке E будут известны объекты из блока A.
Исходя из выше указанных правил, следует, что при составлении процедур и функций можно пользоваться именами для локальных объектов, независимо от того, встречаются ли эти имена в других блоках. Теперь о значении слова обособленный должны были догадаться даже те, кто раньше не встречал это слово.
Вот пример программы с вложенными процедурами. Пусть необходимо вычислить сумму положительных и сумму отрицательных целых чисел, записанных в некотором массиве, и вывести результат с количеством тех и других чисел на экран:
const MaxItem = 100;
type TItems = array [1..MaxItem] of integer;
var Items : TItems;
PCount, NCount : word;
Psum, Nsum : longint;
procedure PrepareItems( count : word; max : integer );
var j, mmax : word;
sign : integer;
begin
mmax := abs (max);
for j := 1 to count do begin
sign := random(2);
if sign = 0 then sign := 1
else sign := -1;
Items[j] := random(mmax)*sign;
end;
PCount := 0;
NCount := 0;
Psum := 0;
Nsum := 0;
end;
procedure Calculation( count : word );
var j : word;
{вложенные процедуры}
{подсчет положительных чисел}
procedure CalcPos( Item : integer );
begin
Psum := Psum + Item;
inc(PCount);
end;
{подсчет отрицательных чисел}
procedure CalcNeg( Item : integer );
begin
Nsum := Nsum + Item;
inc(NCount);
end;
begin { Calculation }
j:=1;
repeat
if Items[j] >= 0 then CalcPos(Items[j])
else CalcNeg(Items[j]);
inc(j);
until j > count;
end; { Calculation }
procedure Report;
begin
writeln( 'Сумма = ', PCount, ' положительных чисел = ', Psum );
writeln( 'Сумма = ', NCount, ' отрицательных чисел = ', Nsum );
end;
begin
PrepareItems(MaxItem,10);
Calculation(MaxItem);
Report;
end.
Программа содержит три процедуры, каждая из которых решает частную подзадачу:
PrepareItems(count : word; max : integer) – заполняет Count элементов массива Items целыми числами в диапазоне –Max..Max и инициализирует глобальные переменные;
Calculation( count : word ) – вычисляет суммы чисел;
Report – выводит результат на экран.
Процедура Calculation содержит две вложенные подпрограммы. Эта процедура управляет вложенными процедурами в соответствии со знаком очередного числа.
Блок процедуры PrepareItems имеет свой список описаний параметров и переменных, которые можно использовать только в блоке этой процедуры. Переменные-параметры Count и Max считаются локальными переменными, и видны только в блоке процедуры PrepareItems.
Блок процедуры Report не имеет описания локальных переменных, так как эта процедура работает с глобальными переменными.
Следует также объяснить значение Random(range:word):word – стандартная функция Turbo Pascal, которая формирует случайное положительное число X в диапазоне 0 < X < range. Следует учитывать, что результат X никогда не будет равен range, т.е. возможные значения результата будут лежать в диапазоне 0 < X < (range - 1) включительно.
Таким образом, в процедуре PrepareItems в теле цикла стоят строки
sign := random(2);
if sign = 0 then sign := 1
else sign := -1;
целью которых является получить случайное число, которое всегда будет 0 или 1 и в соответствии с этим установить значение переменной sign в 1 или в –1, чтобы потом в строке
Items[j] := random(mmax)*sign;
сформировать случайное положительное число в пределах Max, умножить его на переменную sign, что может привести к изменению знака формируемого числа для инициализации очередного элемента массива Items. В итоге получим массив, заполненный положительными и отрицательными случайными числами.
Еще следует упомянуть о стандартной процедуре
Inc( var x ; n : longint ), которая увеличивает целочисленный параметр X на целую величину N, а если последняя опущена (это допустимо), то приращение происходит на единицу. Т.е. эта процедура производит инкремент аргумента.
Раз уж я рассказал о процедуре Inc, то нужно рассказать и о ее сестренке ;O), процедуре Dec( var x ; n : longint ), которая делает все тоже с точностью да наоборот, т. е. эта процедура производит уменьшение аргумента X на величину N, а если последняя опущена, то просто производит декремент аргумента (уменьшение на единицу).
Продолжение следует…
© Владислав Демьянишин
На нашем сайте можно не только бесплатно скачать игры, но и документацию и книги по программированию на MIDLetPascal, Turbo Pascal 6, Turbo Pascal 7, Borland Pascal, по программированию устройств Sound Blaster, Adlib, VESA BIOS, справочник Norton Guide и много другой полезной информации для программистов, включая примеры решения реальных задач по созданию резидентных программ. Журнал > Программирование > Паскаль для новичков (Turbo Pascal, Assembler) > Паскаль для новичков (часть 13): Процедуры и функции. Блочная структура программы
| ||||||||||||||||||
|
||||||||||||||||||