4. Подпрограммы.

Подпрограммы

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

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

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

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

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

inc(i); writeln(a, b, c);   { вызовы процедур }
y := sin(x) + 1;            { вызов функции }
  

Внутри подпрограмм можно описывать другие подпрограммы. Они доступны только из той подпрограммы, в которой они описаны. Рассмотрим правила описания подпрограмм.

Процедуры

Структура процедуры аналогична структуре основной программы:

procedure имя [(список параметров)];      { заголовок }
   разделы описаний
begin
   раздел операторов
end;
  
Пример 1

Найти разность средних арифметических значений двух вещественных массивов из 10 элементов.

Как видно из условия, для двух массивов требуется найти одну и ту же величину — среднее арифметическое. Следовательно, логичным будет оформить его нахождение в виде подпрограммы, которая сможет работать с разными массивами.

program dif_average;
const n = 10;
type mas = array[1 .. n] of real;
var  a, b : mas;
     i : integer;
     dif, av_a, av_b : real;

procedure average(x : mas; var av : real);       {1}
     var i : integer;
     begin
        av := 0;
        for i := 1 to n do av := av + x[i];
            av := av / n;
        end;                                     {2}

begin
    for i := 1 to n do read(a[i]);
    for i := 1 to n do read(b[i]);
    average(a, av_a);                            {3}
    average(b, av_b);                            {4}
    dif := av_a - av_b;
    writeln('Разность значений ', dif:6:2)
end.

         

Описание процедуры average расположено в строках с {1} по {2}. В строках, помеченных цифрами {3} и {4}, эта процедура вызывается сначала для обработки массива а, затем — массива b. Эти массивы передаются а качестве аргументов. Результат вычисления среднего арифметического возвращается в главную программу через второй параметр процедуры.

Функции

Описание функции отличается от описания процедуры незначительно:

function имя [(список параметров)] : тип; { заголовок }
   разделы описаний
begin
   раздел операторов
   имя := выражение;
end;
   

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

Пример 2

Найти разность средних арифметических значений двух вещественных массивов из 10 элементов.

program dif_average1;
const n = 3;
type mas = array[1 .. n] of real;
var
   a, b : mas;
   i    : integer;
   dif  : real;

function average(x : mas) : real;                         {1}
   var i  : integer;                                      {2}
       av : real;
   begin
       av := 0;
       for i := 1 to n do av := av + x[i];
       average := av / n;                                 {3}
   end;

begin
   for i := 1 to n do read(a[i]);
   for i := 1 to n do read(b[i]);
   dif := average(a) - average(b);                        {4}
   writeln('Разность значений ', dif:6:2)
end.
         

Оператор, помеченный комментарием {1}, представляет собой заголовок функции. Тип функции определен как вещественный, потому что такой тип имеет среднее арифметическое элементов вещественного массива. Оператор {3} присваивает вычисленное значение имени функции. В операторе {4} функция вызывается дважды: сначала для одного массива, затем для другого.

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

В IBM PC-совместимых компьютерах память условно разделена на так называемые сегменты. Адрес каждого байта составляется из номера сегмента и смещения относительно его начала.

Длина адресов сегмента и смещения — 16 бит, поэтому размер сегмента не может превышать 216 байт (64K). При вычислении адреса байта в оперативной памяти адрес сегмента сдвигается на 4 двоичных разряда влево, и к нему прибавляется смещение (рис. 1). Таким образом, длина адреса составляет 20 бит, и с помощью него можно адресовать память объемом 220 байт (1 мегабайт).

Рис. 1

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

Рис. 2

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

Внутри подпрограмм описываются локальные переменные. Они располагаются в сегменте стека, причем распределение памяти происходит в момент вызова подпрограммы, а ее освобождение — по завершении подпрограммы. Значения локальных переменных между двумя вызовами одной и той же подпрограммы не сохраняются и эти переменные предварительно не обнуляются. Локальные переменные могут использоваться только в подпрограмме, в которой они описаны, и всех вложенных в нее.

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

 

ВНИМАНИЕ Подпрограмму надо писать таким образом, чтобы вся необходимая для ее использования информация содержалась в ее заголовке.

Обсудить у себя 0
Комментарии (0)
Чтобы комментировать надо зарегистрироваться или если вы уже регистрировались войти в свой аккаунт.

Войти через социальные сети:

Ксюша Г.
Ксюша Г.
Было на сайте никогда
21 год (02.01.1997)
Читателей: 4 Опыт: 0 Карма: 1
все 1 Мои друзья