шпаргалка

Процедуры и функции

[ Назад ]

ПРОЦЕДУРЫ И ФУНКЦИИ БЕЗ ПАРАМЕТРОВ



Процедуры и функции



В языке Turbo Pascal, как и во всех других современных языках программирования, имеется возможность разбиения программы на относительно независимые части, называемые подпрограммами. Разбивают программы на подпрограммы для того, чтобы:

1. Облегчить создание и отладку программы (маленькие независимые куски программы легче создавать и отлаживать, чем одну большую программу).

2. Сократить размер исходного текста и кода программы (в программе часто имеются повторяющиеся части, и если их вынести в подпрограммы, то размер исходного текста программы уменьшится).



В разных языках программирования существуют разные правила работы с подпрограммами. Нас с вами интересует только Turbo Pascal версии 7.0. В этом языке существует два вида подпрограмм. Первый - это процедуры, второй - функции. Процедура – это подпрограмма, в которой выполняются определенные действия. Функция – это подпрограмма, в которой также выполняются определенные действия, но, в отличие от процедуры, в функции вычисляется и возвращается значение функции. Определения процедур и функций в Turbo Pascal очень похожи. Определение функций немного сложнее, чем определение процедур, поэтому мы начнем изучать работу с подпрограммами в Turbo Pascal именно с процедур.





Простейшие процедуры



Возьмем такую задачу. Необходимо ввести массив целых чисел, удалить из него минимальный элемент, вывести получившийся массив.



Данная задача имеет следующий общий алгоритм решения:

1. Ввести массив.

2. Найти индекс минимального элемента.

3. Удалить элемент с найденным индексом.

4. Вывести массив.



Таким образом, наша программа должна будет состоять из четырех относительно независимых кусков: 1-й кусок – ввод массива, 2-й кусок – поиск минимального элемента, 3-й кусок – удаление элемента, 4-й кусок – вывод массива. Сначала реализуем эту программу без использования подпрограмм:



{ Задание: ввести массив целых чисел, удалить из него минимальный элемент, вывести получившийся массив.

Реализация программы без подпрограмм.

}



Program WithoutProcedureExample;



Const {Определение констант}

maxN = 20; {Максимально возможное количество элементов

в массиве}



Type {Определение типов}

IndexEl = 1 .. maxN; {Индексы массива лежат в интервале

от 1 до maxN}

arrInt = array[IndexEl] of integer; {Массив целых чисел,

содержащий до maxN элементов}



Var {Объявление переменных}

A : arrInt; {Массив}

N : integer; {Количество элементов в массиве}

I : IndexEl; {Переменная для сканирования массива}

IndMin : IndexEl; {Номер минимального элемента массива}



begin



{1 – ввод массива}

{1.1 - ввод количества элементов}

repeat

write('Введите n:');

readln(n);

until (n >= 1) and (n <= maxN); {Из цикла выйти возможно

только тогда, когда 1<=N<=maxN}



{1.2 - ввод элементов массива поодиночке}

for i := 1 to n do

begin

write('a[', i, ']=');

readln(a[i]);

end;



{2 – поиск индекса минимального элемента}

indMin := 1;

for i := 2 to n do

if A[i] < A[indMin] then IndMin := i;



{3 - удаление элемента массива с индексом indMin}

for i := indMin to n-1 do

A[i] := A[i+1];

dec(n);



{4 – вывод массива}

writeln;

for i := 1 to n do

write(A[i]:3);

writeln;



end. {Конец программы WithoutProcedureExample}



Теперь продемонстрируем на этой же задаче решение с использованием подпрограмм.

Напрашивается мысль, а не разбить ли нашу программу на подпрограммы таким образом: 1-я подпрограмма – ввод массива, 2-я подпрограмма – поиск минимального элемента, 3-я подпрограмма – удаление элемента, 4-я подпрограмма – вывод массива. Сделаем это, причем будем использовать в программе простейшие подпрограммы-процедуры – так называемые процедуры без параметров.



{ Задание: ввести массив целых чисел, удалить из него минимальный элемент, вывести получившийся массив.

Реализация с использованием процедур без параметров.

}

Program SimpleProcedureExample;



Const {Определение констант}

maxN = 20; {Максимально возможное количество элементов

в массиве}



Type {Определение типов}

IndexEl = 1 .. maxN; {Индексы массива лежат в интервале

от 1 до maxN}

arrInt = array[IndexEl] of integer; {Массив целых чисел,

содержащий до maxN элементов}



Var {Объявление переменных}

A : arrInt; {Массив}

N : integer; {Количество элементов в массиве}

I : IndexEl; {Переменная для сканирования массива}

IndMin : IndexEl; {Номер минимального элемента массива}





{Определение процедур}



{==========================================}

{ReadArray - процедура ввода массива с клавиатуры}

procedure ReadArray;

begin

{1 - ввод количества элементов}

repeat

write('Введите n:');

readln(n);

until (n >= 1) and (n <= maxN);

{2 - ввод элементов массива поодиночке}

for i := 1 to n do

begin

write('a[', i, ']=');

readln(a[i]);

end;

end; {Конец процедуры ReadArray}



{==========================================}

{FindIndMin – процедура поиска индекса минимального элемента}

procedure FindIndMin;

begin

{Ищем индекс min элемента}

indMin := 1;

for i := 2 to n do

if A[i] < A[indMin] then IndMin := i;

end; {Конец процедуры FindIndMin}



{==========================================}

{DeleteMin – процедура удаления минимального элемента}

procedure DeleteMin;

begin

{ Удаляем элемент массива с индексом indMin}

for i := indMin to n-1 do

A[i] := A[i+1];

dec(n);

end; {Конец процедуры DeleteMin}



{==========================================}

{PrintArray – процедура вывода массива на экран}

procedure PrintArray;

begin

{ Выводим массив}

writeln;

for i := 1 to n do

write(A[i]:3);

writeln;

end; {Конец процедуры PrintArray}



{Основная часть программы}

begin



{1 – ввод массива}

ReadArray;



{2 – поиск индекса минимального элемента}

FindIndMin;



{3 – удаление элемента}

DeleteMin;



{4 – вывод массива}

PrintArray;



end. {Конец программы SimpleProcedureExample}



Этот пример показывает, как сделать программу с использованием процедур без параметров. Для этого необходимо задачу разбить на относительно независимые куски. Затем каждый из этих кусков оформить в виде отдельной процедуры, а из основной части программы эти процедуры необходимо вызвать. Заметим, что все используемые в процедурах переменные и типы должны быть определены и объявлены выше определения процедур.



Правила определения процедуры без параметров:

1. Из текста программы вырезается нужный кусок и переносится выше основной части программы (выше первого Begin).

2. Этот кусок текста программы заключается в операторные скобки Begin … End;.

3. Перед этим куском вставляется строка:

procedure имя_процедуры; ,

где имя_процедуры – это идентификатор.



Замечания:

1. Правила структурного программирования требуют, чтобы каждая процедура (и функция) была пояснена достаточным (ясным и полным) комментарием, который ставится перед самой процедурой.

2. Имя процедуры (и функции) должно быть смысловым. Заметим, что по отношению к процедурам (и функциям) это требование необходимо выполнять всегда (имеется в виду, что по отношению к именам переменных это требование иногда можно игнорировать, а вот по отношению к именам процедур и функций это требование игнорировать нельзя никогда).

3. Программу разбивают на подпрограммы в первую очередь для того, чтобы облегчить ее разработку и отладку. Облегчение основывается на том, что во время разработки и отладки приходится иметь дело не с “монстром” длиной в сотни и тысячи строк, а с набором независимых подпрограмм небольшого объема. Подпрограмму можно считать небольшой, если ее исходный текст не превышает 40-60 строк. В этом случае подпрограмма целиком помещается на одной странице распечатки. Еще лучше, если подпрограмма целиком помещается на экране компьютера - в этом случае ее текст не должен превышать 20 строк.

4. В тексте программы подпрограммы должны быть отделены друг от друга визуально. Обычно для этой цели между двумя подпрограммами вставляют не меньше двух пустых строк. Иногда к пустым строкам добавляют строки комментариев, подобных таким {=========================================}.





Вызов процедур



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

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

После этого выполняются операторы, составляющие тело процедуры. Когда будет выполнен последний оператор тела подпрограммы, управление возвращается в точку вызова подпрограммы - на оператор, следующий за оператором процедуры.

Пример:

{1 } program CallProcedure;

{2 } procedure HiWorld;

{3 } begin

{4 } Writeln('Привет,мир!');

{5 } Writeln('Hi World!');

{6 } end;

{7 }

{8 } begin

{9 } Writeln('Это начало');

{10 } HiWorld;

{11 } Writeln('Это конец');

{12 } end.



После запуска этой программы управление передается на строку

{8 } begin – начало программы.

Затем выполняется оператор процедуры

{9 } Writeln('Это начало'); - выводится строка ‘Это начало!’

Затем выполняется оператор процедуры

{10 } HiWorld; - управление передается в процедуру HiWorld на строку

{3 } begin – начало процедуры HiWorld.

Затем выполняется оператор процедуры

{4 } Writeln('Привет,мир!'); - выводится строка ‘Привет, мир!’

Затем выполняется оператор процедуры

{5 } Writeln('Hi World!'); - выводится строка ‘Hi, World!’

Следующая строка

{6 } end; - возвращает управление из процедуры HiWorld.

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

{11 } Writeln('Это конец'); - выводится строка ‘Это конец!’

Следующая строка

{12 } end. – возвращает управление из программы – программа завершает свою работу.





Глобальные и локальные переменные



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

Локальные переменные объявляются, инициализируются и используются только в пределах одной процедуры или функции.

Рассмотрим ранее приведенный пример. В нем используется 4 глобальные переменные:

Var {Объявление глобальных переменных}

A : arrInt; {Массив}

N : integer; {Количество элементов в массиве}

I : IndexEl; {Переменная для сканирования массива}

IndMin : IndexEl; {Номер минимального элемента массива}

В программе определено 4 процедуры:

{1 – ввод массива}

ReadArray;

{2 – поиск индекса минимального элемента}

FindIndMin;

{3 – удаление элемента}

DeleteMin;

{4 – вывод массива}

PrintArray;



Рассмотрим использование всех глобальных переменных.

Переменная A – массив. Элементы массива вводятся в процедуре ReadArray, массив используется в процедурах FindIndMin и PrintArray и изменяется в процедуре DeleteMin. То есть можно сказать, что значение массива A передается из процедуры ReadArray в процедуру FindIndMin, затем в DeleteMin, где он изменяется, и измененное значение передается в PrintArray. Следовательно, переменную A сделать локальной нельзя – она должна быть глобальной.

Переменная N – количество элементов в массиве. Значение переменной вводится в процедуре ReadArray, используется в процедурах FindIndMin и PrintArray и изменяется в процедуре DeleteMin. Следовательно, переменную N, так же, как и массив A, сделать локальной нельзя – она должна быть глобальной.

Переменная I – переменная для сканирования массива. Эта переменная инициализируется, изменяется и используется в каждой из четырех процедур. Между процедурами значение этой переменной не передается. Следовательно, переменную N можно сделать локальной.

Переменная IndMin – индекс минимального элемента массива. Эта переменная получает значение в процедуре FindIndMin и используется в процедуре DeleteMin. Следовательно, ее нельзя сделать локальной – она должна быть глобальной.

Таким образом, из четырех переменных одну можно (и нужно) сделать локальной.





Объявление глобальных и локальных переменных



Глобальные переменные объявляются, вне какой либо процедуры, в разделе VAR. После объявления глобальная переменная доступна (то есть может быть использована) во всех процедурах, описанных ниже.

В нашем примере все четыре переменные объявлены как глобальные, они доступны во всех четырех процедурах.



Локальные переменные объявляются внутри процедуры (или функции), в разделе VAR.

Замечание: если в подпрограмме объявлена локальная переменная, имя которой совпадает с именем глобальной переменной, то внутри этой подпрограммы глобальная переменная будет недоступна. Говорят, что локальная переменная перекрывает одноименную глобальную переменную.



Для примера объявим переменную I как локальную переменную внутри процедуры PrintArray:

{PrintArray – процедура вывода массива на экран}

procedure PrintArray;

Var {Объявление локальных переменных}

I : IndexEl; {Счетчик цикла – локальная переменная}

begin

{ Выводим массив}

writeln;

for i := 1 to n do

write(A[i]:3);

writeln;

end; {Конец процедуры PrintArray}





Функции без параметров



Как говорилось ранее, в Turbo Pascal существует два вида подпрограмм – процедуры и функции. Функции отличаются от процедур тем, что в них вычисляется и возвращается значение. Процедуру можно превратить в функцию, если в ней вычисляется какое-то (желательно одно единственное) значение. При этом превращении сокращается количество глобальных переменных, через которые передаются данные из процедуры (и это очень хорошо).

Проанализируем ранее рассмотренную задачу. В ней имеется 4 процедуры:

{1 – ввод массива}

ReadArray;

{2 – поиск индекса минимального элемента}

FindIndMin;

{3 – удаление элемента}

DeleteMin;

{4 – вывод массива}

PrintArray;

В функцию можно (и нужно) переделать процедуру FindIndMin – единственным действием в этой процедуре является вычисление индекса минимального элемента массива.

После превращения процедуры в функцию эта подпрограмма примет такой вид:

{FindIndMin –функция поиска индекса минимального элемента}

{Возвращаемое значение – индекс минимального элемента}

Function FindIndMin:IndexEl;

Var

Ind : IndexEl; {Локальная переменная, в которой хранится

индекс минимального элемента массива

до возвращения из функции}

I : IndexEl; {Локальная переменная, счетчик цикла}

begin

{Ищем индекс минимального элемента}

Ind := 1;

for i := 2 to n do

if A[i] < A[ind] then Ind := i;

FindIndMin := Ind; {Функция возвращает

найденный индекс}

end; {Конец функции FindIndMin}

Правила определения функций без параметров (из процедуры без параметров):

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

2. Слово Procedure заменяется словом Function.

3. После имени функции вставляется двоеточие и тип возвращаемого значения.

4. В конце тела функции необходимо присвоить имени функции значение локальной переменной, хранящей вычисленный параметр (смотри пункт 1).





Вызов функции



Для того чтобы функция выполнила определенные в ней действия, ее нужно вызвать. Для вызова функции используется оператор процедуры, в тексте программы пишется имя этой функции.

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

Пример:

Выведем индекс минимального элемента массива. Для этого воспользуемся определенной выше функцией FindIndMin.



Var

IndexMinEl : IndexEl; {Локальная переменная, в которую

занесем возвращенное из функции FindIndMin значение}



begin



{Ищем индекс минимального элемента}

IndexMinEl := FindIndMin;

{Выводим на экран индекс минимального элемента массива}

Writeln(‘Минимальный элемент массива имеет индекс = ’,

IndexMinEl);



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



begin



{Ищем индекс минимального элемента и выводим его на экран}

Writeln(‘Минимальный элемент массива имеет индекс = ’,

FindMinEl);





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

Пример: Вычислим значение тангенса по введенному значению угла в градусах.



{1 } program CallFunction;

{2 } var

{3 } x : real; {Значение введенного угла в градусах}

{4 }

{5 } function tg:real;

{6 } var

{7 } xRad : Real; {Значение угла в радианах}

{8 } begin

{9 } xRad := x * Pi / 180.0; {Перевод градусов в радианы}

{10 } tg := sin(xRad) / cos(xRad);

{11 } end;

{12 }

{13 } var

{14 } y : real;

{15 } begin

{16 } Write('Введите x = ');

{17 } Read(x);

{18 } y := tg;

{19 } Writeln( 'tg(', x:0:2, ')=', y:0:4);

{20 } end.



Эта программа начинает свою работу со строки

{15 } begin

Затем выполняется

{16 } Write('Введите x = ');

и

{17 } Read(x);

Затем в строке

{18 } y := tg; - вызывается функция tg, в результате чего управление передается на строку

{8 } begin

Затем выполняется

{9 } xRad := x * Pi / 180.0; {Перевод градусов в радианы}

Затем в строке

{10 } tg := sin(xRad) / cos(xRad); - вычисляется значение тангенса, которое в строке

{11 } end; - возвращается в точку вызова функции tg – в строку

{18 } y:=tg; -где переменной Y присваивается возвращаемое из функции значение тангенса.

Следующей строкой выполняется

{19 } Writeln( 'tg(', x:0:2, ')=', y:0:4);

И, наконец, в строке

{20 } end. - управление из программы возвращается операционной системе – программа завершает свою работу.





Пример использования процедур и функций без параметров



Мы рассмотрели правила оформления и использования подпрограмм (т.е. процедур и функций) без параметров. Теперь используем выше полученные знания для решения следующей задачи.

Необходимо посчитать, сколько разных элементов хранится в массиве.

Пример: массив 1 4 3 2 4 3 1 3 5

разные элементы 1 4 3 2 5

всего их 5



Вот текст программы:

{Подсчитать, сколько разных элементов хранится в массиве.

Одномерный массив целых чисел. Количество элементов от 1 до 20.

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

До минимума постараться сократить использование глобальных переменных.

}

Program SimpleFunctionExample;



Const

maxNumEl = 20; {Максимально возможное количество

элементов в массиве}



Type

IndexElement = 1 .. maxNumEl; {Индексы массива}

ArrayInteger = array[IndexElement] of integer; {Массив

целых чисел}



Var {*** Объявление глобальных переменных ***}

Arr : ArrayInteger; {Обрабатываемый массив}

NumEl : integer; {Количество элементов в обрабатываемом

массиве}





{*** Определение процедур и функций: ***}





{==========================================}

{ReadArray - процедура ввода массива с клавиатуры}

{Данные вводятся в массив Arr. В переменную NumEl заносится количество элементов в массиве Arr}

procedure ReadArray;

var

i : IndexElement; {*Счетчик цикла*}

begin

writeln;

{*Ввод количества элементов*}

repeat

write('Введите количество элементов в массиве:');

readln(NumEl);

until (NumEl >= 1) and (NumEl <= maxNumEl);

{*Ввод элементов массива*}

write('Введите элементы массива : ');

for i := 1 to NumEl do

read(Arr[i]);

end; {*Конец процедуры ReadArray*}



{==========================================}

{PrintArray - процедура вывода массива на экран}

{Данные берутся из массива Arr. В переменной NumEl хранится количество элементов в массиве Arr}

procedure PrintArray;

var

i : IndexElement; {*Счетчик цикла*}

begin

writeln;

write('Массив : ');

for i := 1 to NumEl do

write(Arr[i]:3);

writeln;

end; {*Конец процедур PrintArray*}





{==========================================}

{NumberOfDifferentElements - функция, вычисляющая количество различных элементов в массиве.}

{Данные берутся из массива Arr. В переменной NumEl хранится количество элементов в массиве Arr}

Function NumberOfDifferentElements:integer;

var

i, j : IndexElement; {*Счетчики циклов*}

num : integer; {Количество разных элементов}

isDifferent : boolean; {Элемент является отличным

от все предыдущих}

begin

{Для подсчета количества разных элементов массива используется

следующий алгоритм:

- количество различных элементов обнуляем;

- начиная с первого элемента, по очереди берем все элементы

и сравниваем их со всеми предшествующими. Если взятый

элемент равен хотя бы одному из предшествующих, то этот

элемент не является новым - мы такой уже учли;

- если же он ни одному из предшествующих не равен, то

увеличиваем количество РАЗЛИЧНЫХ элементов на 1.}

num := 0;

for i := 1 to NumEl do

begin

isDifferent := true; {i-ый элемент является отличным

от предыдущих}

for j := i - 1 downto 1 do

if Arr[i] = Arr[j] then

begin

isDifferent := false; {i-ый элемент совпадает}

break; {с одним из предыдущих}

end;

if isDifferent then num := num + 1;

end;



NumberOfDifferentElements := num; {*Возвращаем

вычисленное количество разных элементов*}

end; {*Конец функции NumberOfDifferentElements*}



{*Тело программы*}

begin

{*Вводим массив Arr*}

ReadArray;

{*Выводим массив Arr*}

PrintArray;

{*Вычисление и вывод количества различных элементов массива*}

Write('В введенном массиве различных элементов : ');

writeln(NumberOfDifferentElements);

end. {*Конец программы *}



В данном примере показан более-менее “правильный” стиль оформления исходного текста программы и его комментирования.

Комментарии, помеченные символами *** ***, в реальной программе не пишутся. Здесь они вставлены по причине того, что этот текст - учебный пример.

Комментарии, помеченные символами * * , в реальной программе могут писаться или не писаться, в зависимости от требований к качеству и количеству комментариев.

Комментарии, не помеченные никакими значками, писать нужно ОБЯЗАТЕЛЬНО, если этот исходный текст программы в дальнейшем (спустя какое-то время) кто-то будет читать.



КАТЕГОРИИ:

Network | английский | архитектура эвм | астрономия | аудит | биология | вычислительная математика | география | Гражданское право | демография | дискретная математика | законодательство | история | квантовая физика | компиляторы | КСЕ - Концепция современного естествознания | культурология | линейная алгебра | литература | математическая статистика | математический анализ | Международный стандарт финансовой отчетности МСФО | менеджмент | метрология | механика | немецкий | неорганическая химия | ОБЖ | общая физика | операционные системы | оптимизация в сапр | органическая химия | педагогика | политология | правоведение | прочие дисциплины | психология (методы) | радиоэлектроника | религия | русский | сертификация | сопромат | социология | теория вероятностей | управление в технических системах | физкультура | философия | фотография | французский | школьная математика | экология | экономика | экономика (словарь) | язык Assembler | язык Basic, VB | язык Pascal | язык Си, Си++ |