Программирование на языке высокого уровня Паскаль

Модульное программирование

Разбить на страницы
Показывать лекцию целиком

Презентацию к данной работе Вы можете скачать здесь.

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

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

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

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

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

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

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

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

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

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

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

Процедуры

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

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

Квадратные скобки в данном случае не являются элементом синтаксиса, а означают, что список параметров может отсутствовать. Рассмотрим простой пример.

Пример. Найти разность средних арифметических значений двух вещественных массивов из 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;

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

).

program dif_average1;
const n = 10;
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} функция вызывается дважды: сначала для одного массива, затем для другого.

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

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

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

ПРИМЕЧАНИЕ Если переменная внутри подпрограммы определена в разделе описания констант, - начальное значение ей присваивается один раз до начала работы программы. Время жизни такой переменной — вся программа, то есть значение этой переменной сохраняется между вызовами подпрограммы. Область действия переменной — подпрограмма, в которой она описана.

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

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

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

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

Виды параметров подпрограмм

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

В заголовке подпрограммы нельзя вводить описание нового типа — там должны использоваться либо имена стандартных типов, либо имена типов, описанных программистом ранее в разделе type.

В Паскале существует четыре вида параметров: значения, переменные, константы и нетипизированные параметры.

Кроме того, по другим критериям можно выделить особые виды параметров:

  • открытые массивы и строки;
  • процедурные и функциональные параметры;
  • объекты.
  • Параметры-значения

    Параметр-значение описывается в заголовке подпрограммы следующим образом:

    имя : тип;

    Например, передача величины целого типа в процедуру Р записывается так:

    procedure P(x : integer);

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

    Механизм передачи следующий: из ячейки памяти, в которой хранится переменная, передаваемая в подпрограмму, берется ее значение и копируется в область сегмента стека, называемую областью параметров. Подпрограмма работает с этой копией, следовательно, доступа к ячейке, где хранится сама переменная, не имеет. По завершении работы подпрограммы стек освобождается. Такой способ называется передачей по значению. Ясно, что им можно пользоваться только для величин, которые не должны измениться после выполнения подпрограммы, то есть для ее исходных данных.

    При вызове подпрограммы на месте параметра, передаваемого по значению, может находиться выражение (а также, конечно, его частные случаи — переменная или константа). Тип выражения должен быть совместим по присваиванию с типом параметра.

    Например, если в вызывающей программе описаны переменные

    var x : integer; c : byte; y : longint;

    то следующие вызовы подпрограммы Р, заголовок которой описан выше, будут синтаксически правильными:

    P(x); P(c); P(y); P(200); P(x div 4 + 1);

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

    Параметры-переменные

    Признаком параметра-переменной является ключевое слово var перед описанием параметра:

    var имя : тип;

    Например, параметр-переменная целого типа в процедуре Р записывается так:

    procedure P(var x : integer);

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

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

    Проиллюстрируем передачу параметров-значений и параметров-переменных на примере ().

    var a, b, c, d, e : word;
    procedure X(a, b, c : word; var d : word);
        var e : word;
    begin  
        c := a + b; d := c; e := c;
        writeln ('Значения переменных в подпрограмме:');
        writeln ('c = ', c, ' d = ', d, ' e = ', e);
    end;
    begin  
        a := 3; b := 5; 
        x(a, b, c, d);
        writeln ('Значения переменных в главной программе:');
        writeln ('c = ', c, ' d = ', d, ' e = ', e);
    end.

    Результаты работы этой программы приведены ниже.

    Значения переменных в подпрограмме:
    c = 8 d = 8 e = 8
    Значения переменных в главной программе:
    c = 0 d = 8 e = 0

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

    Параметры-константы

    Параметр-константу можно узнать по ключевому слову const перед описанием параметра. Оно говорит о том, что в пределах подпрограммы данный параметр изменить невозможно:

    const имя : тип;

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

    Например, параметр-константа целого типа в процедуре Р записывается так:

    procedure P(const x : integer);

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

    Параметры составных типов (массивы, записи, строки) предпочтительнее передавать как константы, потому что при этом не расходуется время на копирование и место в стеке (размер стека не может превышать 64 Кбайт, а по умолчанию устанавливается равным 16 Кбайт).

    Результаты работы процедуры следует передавать через параметры-переменные, результат функции — через ее имя.

    СОВЕТ В списке параметров записывайте сначала все входные параметры, затем — все выходные. Давайте параметрам имена, по которым можно получить представление об их назначении.

    Открытые массивы и строки

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

    procedure P(a : array of real);

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

    Его элементы нумеруются с нуля. Номер максимального элемента в массиве можно определить с помощью функции ).

    function max_el(const mas : array of integer) : integer;
    var i, max : integer;
    begin
        max := mas[0];
        for i := 0 to High(mas) do
            if mas[i] > max then max := mas[i];
        max_el := max;
    end;

    Для передачи в подпрограмму по адресу строк любой длины используется либо специальный тип OpenString, называемый открытой строкой, либо тип string при включенном режиме {$P+} (по умолчанию этот режим выключен).

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

    Пример передачи строк в подпрограмму:

    type s20 = string[20];
    var s1 : string[40]; 
        s2 : string[10];
    procedure P(const x : s20; y : string; var z : openstring);
    ...
    begin
        ...     P(s2, s1, s1); ...
    end.

    Параметры процедурного типа

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

    Описание параметра подпрограммы в большинстве случаев состоит из имени и типа. Имя функции является константой процедурного ( функционального ) типа, который требуется описать в разделе type, например:

    type fun  = function(x : real) : real;    
         pr   = procedure;
         proc = procedure(a, b : word; var c : word);

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

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

    $$q=\frac{2x}{\sqrt{1-sin\:2x}}\qquad\gamma=cos\:x-0,2x $$

    ).

    program integrals;
    type fun = function(x : real) : real;            { 1 }
    var a, b : real;
        n    : integer;
    {$F+}
    function Q(x : real) : real;
        begin
            Q := 2 * x / sqrt(1 – sin(2 * x));
        end;
    function R(x : real) : real;
        begin
            R := cos(x) – 0.2 * x;
        end;
    {$F–}
    function integr(f : fun; a, b : real; n : integer) : real;
        var sum, x, h : real;
                    i : integer;
        begin
            h := (b – a) / n; sum := 0; x := a;
            for i := 1 to n do begin
                sum := sum + f(x); x := x + h;
            end;
            integr := sum * h;
        end;
    begin
        writeLn('Введите интервал и количество шагов');
        readln(a, b, n);
        writeln('Интеграл для первой функции: ', integr(Q, a, b, n):8:3);
        writeln(' Интеграл для второй функции: ', integr(R, a, b, n):8:3);
    end.

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

    Итак, чтобы передать имя функции или процедуры в подпрограмму, необходимо:

  • Определить соответствующий процедурный тип.
  • Задать для функций и процедур, предназначенных для передачи в подпрограмму, ключ компилятора {$F +}, определяющий дальнюю адресацию. При этом компилятор формирует полный адрес, состоящий из сегмента и смещения. Альтернативный способ — указать в заголовке каждой функции директиву far:
  • function Q(x : real) : real; far;

    Рекурсивные подпрограммы

    Рекурсивной называется подпрограмма, в которой содержится обращение к самой себе. Такая рекурсия называется прямой. Есть также косвенная рекурсия, когда две или более подпрограмм вызывают друг друга.

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

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

    Простой пример рекурсивной функции — вычисление факториала (это не означает, что факториал следует вычислять именно так). Чтобы получить факториал числа n, требуется умножить на n факториал ( n – 1)!. Известно также, что 0! = 1 и 1! = 1.

    function fact(n : byte) : longint;
    begin
        if (n = 0) or (n = 1) then fact := 1    
        else fact := n * fact(n – 1);    
    end;

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

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

    Модули

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

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

    Модули можно разделить на стандартные, которые входят в состав системы программирования, и пользовательские, то есть создаваемые программистом. Чтобы подключить модуль к программе, его требуется предварительно скомпилировать. Результат компиляции каждого модуля хранится на диске в отдельном файле с расширением .tpu.

    Описание модулей

    Исходный текст каждого модуля хранится в отдельном файле с расширением .pas. Модуль состоит из секций (разделов). Общая структура модуля:

    unit имя;                                                    { заголовок модуля }
    interface                            { ------------- интерфейсная секция модуля }
                             { описание глобальных элементов модуля (видимых извне) }
    implementation                       { --------------- секция реализации модуля }
                                 { описание локальных (внутренних) элементов модуля }
    begin                                { ------------------- секция инициализации }
                                                              { может отсутствовать }
    end.
    ВНИМАНИЕ Имя файла, в котором хранится модуль, должно совпадать с именем, заданным после ключевого слова unit.

    Модуль может использовать другие модули, для этого их надо перечислить в операторе uses, который может находиться только непосредственно после ключевых слов interface или implementation. Если модули подключаются к интерфейсной части, все константы и типы данных, описанные в интерфейсной секции этих модулей, могут использоваться в любом описании в интерфейсной части данного модуля. Если модули подключаются к части реализации, все описания из этих модулей могут использоваться только в секции реализации.

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

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

    Кроме того, в этой секции можно определять константы, типы данных, переменные и внутренние подпрограммы. Они используются внешними элементами модуля и видны только в секции реализации.

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

    В оболочках Borland Pascal и Turbo Pascal результат компиляции по умолчанию размещается в оперативной памяти и на диск не записывается. Поэтому для сохранения скомпилированного модуля на диске требуется установить значение пункта Compile ( Destination в значение Disk. Компилятор создаст файл с расширением .tpu, который надо переместить в специальный каталог, путь к которому указан в пункте меню Options ( Directories в поле Unit Directories.

    В качестве примера оформим в виде модуля подпрограмму вычисления среднего арифметического значения элементов массива из ().

    unit Average;
    interface
        const n = 10;
        type mas = array[1 .. n] of real;
        procedure average(x : mas; var av : real);
    implementation
        procedure average(x : mas; var av : real);
            var i : integer;
        begin
            av := 0;
            for i := 1 to n do av := av + x[i];
            av := av / n;
     end;
    end.

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

    Использование модулей

    Чтобы использовать в программе величины, описанные в интерфейсной части модуля, имя модуля следует указать в разделе uses. Можно записать несколько имен модулей через запятую, например:

    program example;
    uses Average, Graph, Crt;

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

    Если в программе описана величина с тем же именем, что и в модуле, для обращения к величине из модуля требуется перед ее именем указать через точку имя модуля.

    ПРИМЕЧАНИЕ К любой программе автоматически подключается стандартный модуль System, который содержит библиотеку исполняющей системы Паскаля.

    Пример использования модуля из приведен в . Программа находит разность средних арифметических значений двух вещественных массивов.

    program dif_average;
    uses Average;
    var a, b : mas;
        i : integer;
        dif, av_a, av_b : real;
    begin
        for i := 1 to n do read(a[i]);
        for i := 1 to n do read(b[i]);
        average(a, av_a);
        average(b, av_b);
        dif := av_a – av_b;
        writeln('Разность значений ', dif:6:2);
    end.

    Стандартные модули Паскаля

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

    Модуль System

    Модуль System содержит базовые средства языка, которые поддерживают ввод-вывод, работу со строками, операции с плавающей точкой и динамическое распределение памяти. Этот модуль автоматически используется во всех программах, его не требуется указывать в операторе uses. Он содержит все стандартные и встроенные процедуры, функции, константы и переменные Паскаля.

    Модуль Crt

    Модуль Crt предназначен для организации эффективной работы с экраном, клавиатурой и встроенным динамиком. При подключении модуля выводимая информация посылается в базовую систему ввода-вывода (ВIОS) или непосредственно в видеопамять. При этом ввод-вывод выполняется быстрее, кроме того, появляется возможность управлять цветом и размещением на экране.

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

    Модуль Crt позволяет:

  • выполнять вывод в заданное место экрана заданным цветом символа и фона;
  • открывать на экране окна прямоугольной формы и выполнять вывод в пределах этих окон;
  • очищать экран, окно, строку и ее часть;
  • обрабатывать ввод с клавиатуры;
  • управлять встроенным динамиком.
  • ).

    program luck;
    uses crt;
    const max = 10;
    var i, k, n : integer;
    begin
        clrscr;                                        { очистить экран }
        randomize;
        i := random(max);                              { загадать число }
        window(20, 5, 60, 20);                        { определить окно }
        TextBackGround(Blue);                       { цвет фона – синий }
        clrscr;                                     { залить окно фоном }
        TextColor(LightGray);                   { цвет символов – серый }
        k := –1;                                      { счетчик попыток }
        GotoXY(12, 5); writeln(' Введите число : ');
        repeat                                      { цикл ввода ответа }
            GotoXY(20, 9);                          { установить курсор }
            readln(n);                                   { ввести число }
            inc(k);
        until i = n;
        window(20, 22, 60, 24);            { определить окно результата }
        TextAttr := 2 shl 4 + 14;      { желтые символы за зеленом фоне }
        clrscr;                                     { залить окно фоном }
        GotoXY(6, 2);                               { установить курсор }
        writeln(' Коэффициент невезучести : ', k / max :5:1);
        readkey;                          { ждать нажатия любой клавиши }
        TextAttr := 15;                  { белые символы на черном фоне }
        clrscr;                             { очистить после себя экран }
    end.

    Генератор случайных чисел формирует число, находящееся в диапазоне от нуля до max – 1. Пользователь вводит числа в одну и ту же позицию на экране до тех пор, пока не угадает это число. При угадывании с первого раза коэффициент невезучести равен нулю.

    Модули Dos и WinDos

    Модули Dos и WinDos содержат подпрограммы, реализующие возможности операционной системы MS-DOS, такие как переименование, поиск и удаление файлов, получение и установка системного времени, выполнение программных прерываний и т. д. Эти подпрограммы в стандартном Паскале не определены. Для поддержки подпрограмм в модулях определены константы и типы данных.

    Модуль Dos использует строки Паскаля, а WinDos — строки с завершающим нулем.

    Модуль Graph

    Модуль обеспечивает работу с экраном в графическом режиме.

    Экран в графическом режиме представляется в виде совокупности точек — пикселов (pixel, сокращение от picture element ). Цвет каждого пиксела можно задавать отдельно. Начало координат находится в левом верхнем углу экрана и имеет координаты (0, 0). Количество точек по горизонтали и вертикали ( разрешение экрана ) и количество доступных цветов зависят от графического режима. Графический режим устанавливается с помощью служебной программы — графического драйвера.

    В состав оболочки входят несколько драйверов, каждый из которых может работать в нескольких режимах. Режим устанавливается при инициализации графики либо автоматически, либо программистом. Самый "мощный" режим, поддерживаемый модулем Graph, — 640 480 точек, 16 цветов. Модуль Graph обеспечивает:

  • вывод линий и геометрических фигур заданным цветом и стилем;
  • закрашивание областей заданным цветом и шаблоном;
  • вывод текста различным шрифтом, заданного размера и направления;
  • определение окон и отсечение по их границе;
  • использование графических спрайтов и работу с графическими страницами.
  • Модуль Strings

    Модуль Strings предназначен для работы со строками, заканчивающимися нуль-символом, то есть символом с кодом 0 (их часто называют ASCIIZ-строки). Этот вид строк введен в Паскаль специально для работы с длинными строками и программирования под Windows. Модуль Strings содержит функции копирования, сравнения, слияния строк, преобразования их в строки типа string, поиска подстрок и символов.

    Страницы:

    Презентацию к данной работе Вы можете скачать здесь.

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

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

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

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

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

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

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

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

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

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

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

    Процедуры

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

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

    Квадратные скобки в данном случае не являются элементом синтаксиса, а означают, что список параметров может отсутствовать. Рассмотрим простой пример.

    Пример. Найти разность средних арифметических значений двух вещественных массивов из 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;

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

    ).

    program dif_average1;
    const n = 10;
    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} функция вызывается дважды: сначала для одного массива, затем для другого.

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

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

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

    ПРИМЕЧАНИЕ Если переменная внутри подпрограммы определена в разделе описания констант, - начальное значение ей присваивается один раз до начала работы программы. Время жизни такой переменной — вся программа, то есть значение этой переменной сохраняется между вызовами подпрограммы. Область действия переменной — подпрограмма, в которой она описана.

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

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

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

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

    Виды параметров подпрограмм

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

    В заголовке подпрограммы нельзя вводить описание нового типа — там должны использоваться либо имена стандартных типов, либо имена типов, описанных программистом ранее в разделе type.

    В Паскале существует четыре вида параметров: значения, переменные, константы и нетипизированные параметры.

    Кроме того, по другим критериям можно выделить особые виды параметров:

  • открытые массивы и строки;
  • процедурные и функциональные параметры;
  • объекты.
  • Параметры-значения

    Параметр-значение описывается в заголовке подпрограммы следующим образом:

    имя : тип;

    Например, передача величины целого типа в процедуру Р записывается так:

    procedure P(x : integer);

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

    Механизм передачи следующий: из ячейки памяти, в которой хранится переменная, передаваемая в подпрограмму, берется ее значение и копируется в область сегмента стека, называемую областью параметров. Подпрограмма работает с этой копией, следовательно, доступа к ячейке, где хранится сама переменная, не имеет. По завершении работы подпрограммы стек освобождается. Такой способ называется передачей по значению. Ясно, что им можно пользоваться только для величин, которые не должны измениться после выполнения подпрограммы, то есть для ее исходных данных.

    При вызове подпрограммы на месте параметра, передаваемого по значению, может находиться выражение (а также, конечно, его частные случаи — переменная или константа). Тип выражения должен быть совместим по присваиванию с типом параметра.

    Например, если в вызывающей программе описаны переменные

    var x : integer; c : byte; y : longint;

    то следующие вызовы подпрограммы Р, заголовок которой описан выше, будут синтаксически правильными:

    P(x); P(c); P(y); P(200); P(x div 4 + 1);

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

    Параметры-переменные

    Признаком параметра-переменной является ключевое слово var перед описанием параметра:

    var имя : тип;

    Например, параметр-переменная целого типа в процедуре Р записывается так:

    procedure P(var x : integer);

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

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

    Проиллюстрируем передачу параметров-значений и параметров-переменных на примере ().

    var a, b, c, d, e : word;
    procedure X(a, b, c : word; var d : word);
        var e : word;
    begin  
        c := a + b; d := c; e := c;
        writeln ('Значения переменных в подпрограмме:');
        writeln ('c = ', c, ' d = ', d, ' e = ', e);
    end;
    begin  
        a := 3; b := 5; 
        x(a, b, c, d);
        writeln ('Значения переменных в главной программе:');
        writeln ('c = ', c, ' d = ', d, ' e = ', e);
    end.

    Результаты работы этой программы приведены ниже.

    Значения переменных в подпрограмме:
    c = 8 d = 8 e = 8
    Значения переменных в главной программе:
    c = 0 d = 8 e = 0

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

    Параметры-константы

    Параметр-константу можно узнать по ключевому слову const перед описанием параметра. Оно говорит о том, что в пределах подпрограммы данный параметр изменить невозможно:

    const имя : тип;

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

    Например, параметр-константа целого типа в процедуре Р записывается так:

    procedure P(const x : integer);

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

    Параметры составных типов (массивы, записи, строки) предпочтительнее передавать как константы, потому что при этом не расходуется время на копирование и место в стеке (размер стека не может превышать 64 Кбайт, а по умолчанию устанавливается равным 16 Кбайт).

    Результаты работы процедуры следует передавать через параметры-переменные, результат функции — через ее имя.

    СОВЕТ В списке параметров записывайте сначала все входные параметры, затем — все выходные. Давайте параметрам имена, по которым можно получить представление об их назначении.

    Открытые массивы и строки

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

    procedure P(a : array of real);

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

    Его элементы нумеруются с нуля. Номер максимального элемента в массиве можно определить с помощью функции ).

    function max_el(const mas : array of integer) : integer;
    var i, max : integer;
    begin
        max := mas[0];
        for i := 0 to High(mas) do
            if mas[i] > max then max := mas[i];
        max_el := max;
    end;

    Для передачи в подпрограмму по адресу строк любой длины используется либо специальный тип OpenString, называемый открытой строкой, либо тип string при включенном режиме {$P+} (по умолчанию этот режим выключен).

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

    Пример передачи строк в подпрограмму:

    type s20 = string[20];
    var s1 : string[40]; 
        s2 : string[10];
    procedure P(const x : s20; y : string; var z : openstring);
    ...
    begin
        ...     P(s2, s1, s1); ...
    end.

    Параметры процедурного типа

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

    Описание параметра подпрограммы в большинстве случаев состоит из имени и типа. Имя функции является константой процедурного ( функционального ) типа, который требуется описать в разделе type, например:

    type fun  = function(x : real) : real;    
         pr   = procedure;
         proc = procedure(a, b : word; var c : word);

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

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

    $$q=\frac{2x}{\sqrt{1-sin\:2x}}\qquad\gamma=cos\:x-0,2x $$

    ).

    program integrals;
    type fun = function(x : real) : real;            { 1 }
    var a, b : real;
        n    : integer;
    {$F+}
    function Q(x : real) : real;
        begin
            Q := 2 * x / sqrt(1 – sin(2 * x));
        end;
    function R(x : real) : real;
        begin
            R := cos(x) – 0.2 * x;
        end;
    {$F–}
    function integr(f : fun; a, b : real; n : integer) : real;
        var sum, x, h : real;
                    i : integer;
        begin
            h := (b – a) / n; sum := 0; x := a;
            for i := 1 to n do begin
                sum := sum + f(x); x := x + h;
            end;
            integr := sum * h;
        end;
    begin
        writeLn('Введите интервал и количество шагов');
        readln(a, b, n);
        writeln('Интеграл для первой функции: ', integr(Q, a, b, n):8:3);
        writeln(' Интеграл для второй функции: ', integr(R, a, b, n):8:3);
    end.

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

    Итак, чтобы передать имя функции или процедуры в подпрограмму, необходимо:

  • Определить соответствующий процедурный тип.
  • Задать для функций и процедур, предназначенных для передачи в подпрограмму, ключ компилятора {$F +}, определяющий дальнюю адресацию. При этом компилятор формирует полный адрес, состоящий из сегмента и смещения. Альтернативный способ — указать в заголовке каждой функции директиву far:
  • function Q(x : real) : real; far;

    Рекурсивные подпрограммы

    Рекурсивной называется подпрограмма, в которой содержится обращение к самой себе. Такая рекурсия называется прямой. Есть также косвенная рекурсия, когда две или более подпрограмм вызывают друг друга.

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

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

    Простой пример рекурсивной функции — вычисление факториала (это не означает, что факториал следует вычислять именно так). Чтобы получить факториал числа n, требуется умножить на n факториал ( n – 1)!. Известно также, что 0! = 1 и 1! = 1.

    function fact(n : byte) : longint;
    begin
        if (n = 0) or (n = 1) then fact := 1    
        else fact := n * fact(n – 1);    
    end;

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

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

    Модули

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

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

    Модули можно разделить на стандартные, которые входят в состав системы программирования, и пользовательские, то есть создаваемые программистом. Чтобы подключить модуль к программе, его требуется предварительно скомпилировать. Результат компиляции каждого модуля хранится на диске в отдельном файле с расширением .tpu.

    Описание модулей

    Исходный текст каждого модуля хранится в отдельном файле с расширением .pas. Модуль состоит из секций (разделов). Общая структура модуля:

    unit имя;                                                    { заголовок модуля }
    interface                            { ------------- интерфейсная секция модуля }
                             { описание глобальных элементов модуля (видимых извне) }
    implementation                       { --------------- секция реализации модуля }
                                 { описание локальных (внутренних) элементов модуля }
    begin                                { ------------------- секция инициализации }
                                                              { может отсутствовать }
    end.
    ВНИМАНИЕ Имя файла, в котором хранится модуль, должно совпадать с именем, заданным после ключевого слова unit.

    Модуль может использовать другие модули, для этого их надо перечислить в операторе uses, который может находиться только непосредственно после ключевых слов interface или implementation. Если модули подключаются к интерфейсной части, все константы и типы данных, описанные в интерфейсной секции этих модулей, могут использоваться в любом описании в интерфейсной части данного модуля. Если модули подключаются к части реализации, все описания из этих модулей могут использоваться только в секции реализации.

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

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

    Кроме того, в этой секции можно определять константы, типы данных, переменные и внутренние подпрограммы. Они используются внешними элементами модуля и видны только в секции реализации.

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

    В оболочках Borland Pascal и Turbo Pascal результат компиляции по умолчанию размещается в оперативной памяти и на диск не записывается. Поэтому для сохранения скомпилированного модуля на диске требуется установить значение пункта Compile ( Destination в значение Disk. Компилятор создаст файл с расширением .tpu, который надо переместить в специальный каталог, путь к которому указан в пункте меню Options ( Directories в поле Unit Directories.

    В качестве примера оформим в виде модуля подпрограмму вычисления среднего арифметического значения элементов массива из ().

    unit Average;
    interface
        const n = 10;
        type mas = array[1 .. n] of real;
        procedure average(x : mas; var av : real);
    implementation
        procedure average(x : mas; var av : real);
            var i : integer;
        begin
            av := 0;
            for i := 1 to n do av := av + x[i];
            av := av / n;
     end;
    end.

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

    Использование модулей

    Чтобы использовать в программе величины, описанные в интерфейсной части модуля, имя модуля следует указать в разделе uses. Можно записать несколько имен модулей через запятую, например:

    program example;
    uses Average, Graph, Crt;

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

    Если в программе описана величина с тем же именем, что и в модуле, для обращения к величине из модуля требуется перед ее именем указать через точку имя модуля.

    ПРИМЕЧАНИЕ К любой программе автоматически подключается стандартный модуль System, который содержит библиотеку исполняющей системы Паскаля.

    Пример использования модуля из приведен в . Программа находит разность средних арифметических значений двух вещественных массивов.

    program dif_average;
    uses Average;
    var a, b : mas;
        i : integer;
        dif, av_a, av_b : real;
    begin
        for i := 1 to n do read(a[i]);
        for i := 1 to n do read(b[i]);
        average(a, av_a);
        average(b, av_b);
        dif := av_a – av_b;
        writeln('Разность значений ', dif:6:2);
    end.

    Стандартные модули Паскаля

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

    Модуль System

    Модуль System содержит базовые средства языка, которые поддерживают ввод-вывод, работу со строками, операции с плавающей точкой и динамическое распределение памяти. Этот модуль автоматически используется во всех программах, его не требуется указывать в операторе uses. Он содержит все стандартные и встроенные процедуры, функции, константы и переменные Паскаля.

    Модуль Crt

    Модуль Crt предназначен для организации эффективной работы с экраном, клавиатурой и встроенным динамиком. При подключении модуля выводимая информация посылается в базовую систему ввода-вывода (ВIОS) или непосредственно в видеопамять. При этом ввод-вывод выполняется быстрее, кроме того, появляется возможность управлять цветом и размещением на экране.

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

    Модуль Crt позволяет:

  • выполнять вывод в заданное место экрана заданным цветом символа и фона;
  • открывать на экране окна прямоугольной формы и выполнять вывод в пределах этих окон;
  • очищать экран, окно, строку и ее часть;
  • обрабатывать ввод с клавиатуры;
  • управлять встроенным динамиком.
  • ).

    program luck;
    uses crt;
    const max = 10;
    var i, k, n : integer;
    begin
        clrscr;                                        { очистить экран }
        randomize;
        i := random(max);                              { загадать число }
        window(20, 5, 60, 20);                        { определить окно }
        TextBackGround(Blue);                       { цвет фона – синий }
        clrscr;                                     { залить окно фоном }
        TextColor(LightGray);                   { цвет символов – серый }
        k := –1;                                      { счетчик попыток }
        GotoXY(12, 5); writeln(' Введите число : ');
        repeat                                      { цикл ввода ответа }
            GotoXY(20, 9);                          { установить курсор }
            readln(n);                                   { ввести число }
            inc(k);
        until i = n;
        window(20, 22, 60, 24);            { определить окно результата }
        TextAttr := 2 shl 4 + 14;      { желтые символы за зеленом фоне }
        clrscr;                                     { залить окно фоном }
        GotoXY(6, 2);                               { установить курсор }
        writeln(' Коэффициент невезучести : ', k / max :5:1);
        readkey;                          { ждать нажатия любой клавиши }
        TextAttr := 15;                  { белые символы на черном фоне }
        clrscr;                             { очистить после себя экран }
    end.

    Генератор случайных чисел формирует число, находящееся в диапазоне от нуля до max – 1. Пользователь вводит числа в одну и ту же позицию на экране до тех пор, пока не угадает это число. При угадывании с первого раза коэффициент невезучести равен нулю.

    Модули Dos и WinDos

    Модули Dos и WinDos содержат подпрограммы, реализующие возможности операционной системы MS-DOS, такие как переименование, поиск и удаление файлов, получение и установка системного времени, выполнение программных прерываний и т. д. Эти подпрограммы в стандартном Паскале не определены. Для поддержки подпрограмм в модулях определены константы и типы данных.

    Модуль Dos использует строки Паскаля, а WinDos — строки с завершающим нулем.

    Модуль Graph

    Модуль обеспечивает работу с экраном в графическом режиме.

    Экран в графическом режиме представляется в виде совокупности точек — пикселов (pixel, сокращение от picture element ). Цвет каждого пиксела можно задавать отдельно. Начало координат находится в левом верхнем углу экрана и имеет координаты (0, 0). Количество точек по горизонтали и вертикали ( разрешение экрана ) и количество доступных цветов зависят от графического режима. Графический режим устанавливается с помощью служебной программы — графического драйвера.

    В состав оболочки входят несколько драйверов, каждый из которых может работать в нескольких режимах. Режим устанавливается при инициализации графики либо автоматически, либо программистом. Самый "мощный" режим, поддерживаемый модулем Graph, — 640 480 точек, 16 цветов. Модуль Graph обеспечивает:

  • вывод линий и геометрических фигур заданным цветом и стилем;
  • закрашивание областей заданным цветом и шаблоном;
  • вывод текста различным шрифтом, заданного размера и направления;
  • определение окон и отсечение по их границе;
  • использование графических спрайтов и работу с графическими страницами.
  • Модуль Strings

    Модуль Strings предназначен для работы со строками, заканчивающимися нуль-символом, то есть символом с кодом 0 (их часто называют ASCIIZ-строки). Этот вид строк введен в Паскаль специально для работы с длинными строками и программирования под Windows. Модуль Strings содержит функции копирования, сравнения, слияния строк, преобразования их в строки типа string, поиска подстрок и символов.

    Вернуться к учебному плану