16834

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

Лекция

Информатика, кибернетика и программирование

Лекция 7 1. Модульное программирование Основные понятия Принцип модульности оказывает наиболее сильное влияние на дисциплину мышления при решении задач. Он состоит в декомпозиции первоначального задания в связную систему подзадач и является основным методом в н

Русский

2013-06-26

222.5 KB

3 чел.

Лекция 7

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

Основные понятия

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

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

Используя модули, можно:

  1.  разрабатывать типовые подпрограммы для использования одним или многими программистами;
  2.  разделять большие  алгоритмы  на части  и  разрабатывать  их  программы
    разными программистами невысокой квалификации;
  3.  из программ на Паскале использовать модули, разработанные на других
    языках, например на языке ассемблера;
  4.  использовать нисходящий метод разработки программ.

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

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

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

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

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

Классификация и вызовы подпрограмм

Подпрограммы на Паскале могут быть в виде процедур и функций, внутренних, внешних или библиотечных. Внутренние располагаются внутри других модулей, в том числе в основной программе, библиотечные - в файле Паскаля Turbo.TPL и в модулях (TPU-файлах) Паскаля. В большинстве языков высокого уровня термин "модуль" определяет программу или подпрограмму. В Паскале имя "модуль" носит библиотека подпрограмм. Термин "внешний" используется для определения вложенности внутренней подпрограммы в другую, "внешнюю" по отношению к данной, программу или подпрограмму.

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

Вызов процедур производится оператором вызова процедур, а функций - по имени функций из выражений. Завершение выполнения подпрограмм может быть по концу ее текста или по вызову процедуры Exit. Вызов Exit из подпрограммы приводит к завершению выполнения подпрограммы. Вызов Exit из программы приводит к завершению ее выполнения. С помощью процедуры Halt (ExitCode : word ); можно прекратить выполнение программы из любой подпрограммы или из программы; параметр процедуры Halt необязателен. Подпрограммы на Паскале могут быть внутренние и внешние по отношению к программе или к другим подпрограммам, из которых они вызываются. Библиотечные подпрограммы всегда внешние. Схематично вложенность подпрограмм представлена на рис. 1.

Рис.1

Схема вложенности подпрограмм

В примере рис. 1 две подпрограммы (2-й уровень вложенности) вложены в основную программу (1-й уровень вложенности); в одну из них вложена еще одна подпрограмма (3-й уровень вложенности).

Если текст подпрограммы включен (вложен) в текст другой программы или подпрограммы, то она - внутренняя по отношению к своей внешней программе, в которую она вложена. Выполнение главной программы начинает ОС (если ее запуск производится, например, из системы Нортон) или среда Паскаля. Остальные подпрограммы выполняются под управлением главной, т. е. вызываются (активизируются) из главной. Подпрограмма, выполнение которой начато, но не закончено, называется активной.

Схематично вызовы подпрограмм друг другом представлены на рис. 2.

Рис.2

Вызовы подпрограмм и уровни

вложенности

 Правила вызова подпрограмм:

  1.  из любой программы или подпрограммы можно вызвать любую под про
    грамму, расположенную в библиотеке: системной (
    TPL-файл) или личной
    (
    TPU-файл);
  2.  внутренняя подпрограмма может быть вызвана:

а) из программы или подпрограммы - первой внешней по отношению к вызываемой;

б) из подпрограммы одного с нею уровня вложенности:

если текст вызываемой подпрограммы расположен до текста вызывающей
подпрограммы, без опережающего описания;

если текст вызываемой подпрограммы расположен после текста вызывающей и имеет опережающее описание, расположенное до вызывающей
подпрограммы;

3) из программы и подпрограммы нельзя вызвать подпрограмму, вложенную
в другую подпрограмму.

На рис.2 над дугами установлены номера пунктов приведенного перечня, в соответствии с которыми разрешен или нет вызов подпрограммы.

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

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

Каждое имя (объект), используемое в подпрограмме, должно быть объявлено. Область действия объявленных имен - от точки объявления до конца программы или подпрограммы, в которой они объявлены.

Переменные, используемые в подпрограммах, могут быть:

  1.  глобальные (внешние): объявленные во внешней подпрограмме или про
    грамме и не переопределенные в данной;
  2.  локальные (внутренние): определенные в данной подпрограмме и доступные и используемые только в ней и во всех вложенных в нее блоках или
    подпрограммах, в которых они не переобъявлены;
  3.  формальные, определенные в списке формальных параметров; идентификаторы формальных параметров локальны в подпрограмме.

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

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

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

Процедуры

Процедура имеет описание (текст) и вызов. Описание процедуры содержит заголовок процедуры и блок. Причем блок (тело процедуры) имеет такое же строение, как и блок программы. Заголовок процедуры:

PROCEDURE имя-процедуры [(список-формальных-параметров)];

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

Список формальных параметров в заголовке процедуры необязателен; он может отсутствовать, если используются только глобальные и локальные объекты. Более детально список формальных параметров рассмотрен в данном разделе.

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

Форма оператора вызова процедуры:

Имя-процедуры [(список-фактических-параметров)];

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

Пример вызова процедуры без параметров: PRINT;.

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

Листинг 1. Процедура для выбора минимального и максимального значений.

PROGRAM PR;

CONST N=20;

TYPE VECT=ARRAY[1..N] OF REAL;

. . . {Описание процедуры MNMX:}

PROCEDURE MNMX(A:VECT;M:INTEGER;VAR MN,MX:REAL);

    VAR I:INTEGER;
BEGIN MN:=A[1]; MX:=A[1];
     FOR I:=2 TO M DO

  IF A[I]<MN  THEN MN:=A[I]

    ELSE IF A[I]>MX

      THEN MX:=A[I]; END;

BEGIN ... MNMX(D,N,MIN,MAX);{ Вызовы  процедуры MNMX }

  MNMX(E,20,MINI,MAX1);

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

Функции

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

FUNCTIONимя-функции[(список-формальных-параметров)]:тип-результата;

где     имя-функции - идентификатор (имя-входа), определяет имя, по которому функция вызывается;

тип-результата - тип возвращаемого значения.

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

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

имя-функции   :=  выражение;

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

Листинг 2. Функция аля вычисления значения N!.

FUNCTION FACT(N:INTEGER):INTEGER ;

VAR F,I:INTEGER; {тип  результата}
BEGIN F:=1;

FOR  I:=2 TO N DO F:= F*I;

FACT :=F; { - определение результата FACT }
END;

BEGIN  ...          { Примеры вызова функции FACT:}

A := FACT(20);  В:=FACT(M+1);
END.

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

В листинге 3 приведена программа VST, использующая функцию VS -возведения в степень значений типа Real:XY.

Листинг 3. Функция возведения в степень вещественных значении.

PROGRAM VST;

VAR  X, Y : REAL;

{ Функция  VS - возведения в степень--}

FUNCTION  VS(X, Y : REAL): REAL; VAR I, N : INTEGER;

P : REAL;

BEGIN

IF X = 0  THEN

IF Y < 0  THEN       { X = 0, Y < 0,  VS = 1 / 0 !! }

BEGIN WRITELN ('ОШИБКА : X = 0, Y < 0 ');

HALT(1)   { Останов программы }

END

ELSE { X = 0, Y >= 0,  VS = 0 ** Y }

VS := 0
ELSE { X <> 0  }

IF FRAC(Y) = 0 THEN { Y целое }

BEGIN

N:=ABS(ROUND(Y)); P:=1; {Результат ROUND - целое} FOR I := 1 TO  N DO P := P * X;

IF Y > 0  THEN  VS := P { Y > 0 }

ELSE  VS := 1/P { Y < 0 }

END

ELSE  { X <> 0, Y не целое }

IF X > 0 THEN

VS := EXP (Y * LN (X)) { VS = X ** Y }

ELSE { VS = - ( |X|** Y) }

VS := - EXP ( Y * LN (ABS (X))) END;

{   Основная программа   }

BEGIN

REPEAT    READLN (X, Y) ;

WRITELN (VS(X, Y) :12:10, VS (X, -Y) :15:10); UNTIL EOF

END.

где  ** - в комментариях - возведение в степень.

В примере листинга 3 используются следующие правила:

  1.  возведение нуля в степень меньше 0 является ошибкой;
  2.  возведение значения X в степень Y, где Y - целое число, производится перемножением X (возводимого значения) 'Y' раз;
  3.  возведение X в степень Y, не являющуюся целым числом, производится
    с помощью встроенной функции ЕХР в соответствии с формулой

R := ЕХР ( У * Ln (X) ) ;.

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

Списки формальных параметров

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

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

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

Примеры заголовков процедур и функций и формальных параметров:

PROCEDURE MNMX(А:REAL;М:INTEGER;VAR MN,MX:REAL);

FUNCTION FACT (В:MYTYPE;N:INTEGER):INTEGER;

где    MNMX, FACT - имена подпрограмм;

А, В, М, N - параметры-значения,

MN, MX - параметры-переменные;

MYTYPE - тип параметра, определенный пользователем.

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

Форма секции формальных параметров:

[VAR] список-имен:имя-типа;

где     VAR определяет секцию с параметрами-переменными; секция без VAR определяет параметры-значения.

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

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

Между формальными и фактическими параметрами должно быть взаимнооднозначное соответствие, а именно:

  1.  количество формальных и фактических параметров должно быть одинаково;

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

типы фактических параметров и соответствующих им формальных параметров должны совпадать или должны быть согласованы.

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

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

Параметры-значения

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

Если формальный параметр определен как параметр-значение, то перед вызовом подпрограммы вычисляется значение выражения фактического параметра, а затем полученный результат помещается в ОП, выделенную в стеке соответствующему формальному параметру на время активации подпрограммы. Тип результата выражения фактического параметра должен быть совместим с типом формального параметра. Значение переменной - формального параметра можно изменять при выполнении подпрограммы, но при этом значение соответствующего фактического параметра не меняется, так как формальный и фактический параметры занимают разные области ОП. Это происходит потому, что в оперативную память вызываемой подпрограммы передается (копируется) значение параметра, а не адрес его размещения в вызывающей программе. Поэтому параметр-значение не может быть результатом выполнения подпрограммы. С другой стороны, если формальный параметр не должен быть результатом выполнения подпрограммы, его можно определить как параметр-значение. Например:

PROCEDURE TREUG (А,В,С:REAL;VAR S:REAL);

В списке параметров переменные А, В, С - параметры-значения, S - параметр-переменная.

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

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

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

Формальные параметры-переменные обычно используют для передачи результатов выполнения процедуры в вызвавшую программу. Ключевое слово VAR в начале секции параметров означает, что следующий за ним список имен представляет параметры-переменные. Например:

PROCEDURE Р(F:CHAR;VAR А,В,С:REAL);

где    А, В, С - параметры-переменные; F - параметр-значение.

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

Пример программы, возвращающей в качестве результата значения суммы и произведения двух значений типа REAL, дан в листинге 4. Программа примера содержит процедуру МА, которая вычисляет MUL - произведение двух параметров-значений (A и B) и ADD - их сумму. Результаты выполнения программы возвращаются с помощью двух параметров-переменных: ADD и MUL. В тексте программы приведено 2 вызова этой процедуры; в первом случае фактическими параметрами являются имена переменных А и В, во втором -выражения (А + 2 = 4) и (В - 3 = 2). В результате первого обращения возвращаемые значения AD = 7., ML = 10.; во втором - AD = 6., ML = 8.

Листинг 4. Процедура, возвращающая 2 вещественных значения.

PROGRAM MULADD;

VAR  А, В, ML, AD : REAL;

PROCEDURE MA (С, D : REAL; VAR ADD, MUL : REAL );

BEGIN    ADD := С + D; MUL := С * D   END;

BEGIN

A := 2; В := 5; { Результаты:       }

MA ( А, В, AD, ML ); ...         { AD = 7.; ML = 10. }

MA ( A + 2, В - 3, AD, ML );   ... { AD = 6.; ML = 8.  }

END.

В листинге 5 приведен пример использования в процедуре PRINT: X -параметра-значения и Y - параметра-переменной. Обе переменные изменяют свое значение в процедуре PRINT. Но изменяется в вызывающей программе только значение В - параметра-переменной.

Листинг 5. Изменения параметра-переменной.

PROGRAM  PARM;

VAR А,   В,   С    :    INTEGER;

{   Изменение и вывод значений параметров - --}

PROCEDURE PRINT (X : INTEGER; VAR Y : INTEGER ) ;

BEGIN X:=X+2;Y:=Y+3;

WRITELN( 'Вывод из PRINT: X = ', X, '  Y = ' , Y) ;

END;

{  Основная программа   }

BEGIN   ASSIGN (OUTPUT, 'prpar.rez');  REWRITE (OUTPUT);

A := 0; В := 10;

WRITELN( 'Вывод до вызова PRINT:  A = ', A, 'В = ' , В);

PRINT (А, В );      { - вызов PRINT }

WRITELN('Вывод после вызова PRINT: A=',A,'В =',В); CLOSE (OUTPUT);

END.

Результаты выполнения программы:

Вывод до вызова PRINT:    А = 0  В = 10
Вывод из
PRINT:          X = 2  Y = 13

Вывод после вызова PRINT: А = 0  В = 13

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

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

В дополнение к параметрам-значениям и параметрам-переменным  добавлены параметры-константы. Изменение этих параметров запрещено в подпрограммах. Для объявления параметров-констант используется ключевое слово const. Например:

Procedure Р(const Par:word);

Если в теле процедуры появится оператор:

р := <выражение>;

то это вызовет диагностическое сообщение:

Invalid variable reference  -  Неверная ссылка  на  переменную.

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

Type  ta = array [ 1..5 ] of byte;

  tb = string [10];

Const a : ta = (1,2,3,4,5);

Var b : tb;  с : byte;

Procedure P(const a:ta;const b:tb;const с:byte); Begin

Writeln ('a[2]= ', a[2],'b = ', b,'с=', с)

End;

Begin b := 'Привет!'; с:=7;  P(a, b, c); End.

Бестиповые параметры

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

Function Equal (var Paraml, Param2; Len : Word );

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

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

Function Max(Var Mas; N : Byte) : integer; Type TArray = array[1..200] of integer; Var Ma: integer;  i: byte; Begin  Ma := TArray(Mas)[1];

   For i := 2 to N do

 If Ma <  TArray(Mas)[i] then

    Ma := TArray(Mas)[i];

Max := Ma

End;

Параметры - массивы и строки открытого типа

Одно из наиболее существенных расширений языка Паскаль 7.0 - открытые параметры-переменные подпрограмм: массивы и строки. Открытые массивы - это параметры-массивы подпрограмм, размер которых не указывается в списке формальных параметров заголовка подпрограммы. Пример формы объявления открытого одномерного массива:

Function Sum ( Var A : array of byte ) : byte;

Ключевое слово Var в объявлении параметра открытого типа обязательно.

Фактическим параметром открытого массива может быть массив любого размера. Тип элементов фактического массива должен совпадать с типом массива - формального параметра. В качестве открытых массивов могут использоваться только одномерные массивы. Внутри подпрограмм границы переданного массива могут определяться с помощью функций Low и High. При этом результат вызова функции Low всегда даст 0. А результат вызова функции High - верхнее значение индекса при нумерации его элементов от нуля. Программа с использованием открытого массива приведена в листинге 6.

Листинг 6. Процедура с открытым параметром.

Program OtkrPar;

Type  TA1 = array[ 1 .. 5 ] of byte;

TA2 = array[ 0 .. 2  ] of byte;

ТАЗ = array[-2 .. 2] of byte; Const A1 : TA1 = ( 1, 2, 3, 4, 5);

A2 : TA2 = ( 7, 8, 9);

A3 : ТА3 =(1,2,3,4,5); 

Procedure P ( var A : array of byte ); Var i, s : word;

Begin   s := 0;

For i := Low(A) to High(A) do begin

s := s + A[i]; Write ( ' ', i, '  ', a[i]);

end;

Writeln ( ' s = ' , s); End;

Begin

P(A1); P(A2); P(A3); { - вызовы процедуры } End.

Открытые строки аналогичны открытым массивам. Для их использования надо включить директиву {$Р+}. Формальные параметры объявляются в виде string. В качестве фактического параметра при этом можно использовать строки любой длины. При этом внутри подпрограммы строка-параметр всегда трактуется по максимуму, т. е. как строка на 255 символов. Пример процедуры с открытым параметром-строкой дан в листинге 7.

Листинг 7. Процедура с открытым строковым параметром.

Program OtkrStr; {$P+}

Var  SI:string;

S2 : string[10];

Procedure P(Var  S : string);

Begin Writeln ('S = ',Sizeof(S),'L =',Length(S));
End; {   
Будет  выведено:   }

Begin S1 :='ABC'; P(S1); { S = 256  L = 3 }

S2:= XXXXXXX'; P(S2); {S = 256  L = 7 }

END.

Имеется специальный строковый тип openstring для объявления формального параметра. При этом независимо от директивы Р+ этот параметр будет открытой строкой. Например:

Procedure  P(Var S:openstring);

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

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

Для объявления процедурного типа применяется заголовок подпрограммы, в котором опускается ее имя. Например:

TYPE

PROC1 = PROCEDURE ( А, В, С : REAL;  VAR D : REAL );

PROC2 = PROCEDURE ( VAR  А, В : REAL );

PROC3 = PROCEDURE ;       { Процедура без параметров }

FUNC1 = FUNCTION  ( S : STRING ) : REAL ;

FUNC2 = FUNCTION : STRING ;  {Функция без параметров }

В примере PROC1, PROC2, PROC3, FUNGI, FUNC2 - имена типов процедурных параметров, идентификаторы.

При объявлении процедурных типов параметров списки их формальных параметров должны быть согласованы (совпадать) со списками формальных параметров подпрограмм - фактических параметров. Использование подпрограмм, в которых в качестве формальных параметров применяются процедурные типы и в качестве фактических - имена подпрограмм, требует директивы компилятора {$F+} или опции компилятора Options/Compile/Force far calls - дальний вызов подпрограмм.

Пример. Вычислить и вывести на экран таблицу значений двух функций:

SIN1(X)   =   (  SIN(X)  +  1)   *   ЕХР(-Х)  И

COS1(X)   =   (COS(X)  +  1)   *   ЕХР(-Х).

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

Программа примера приведена в листинге 8. Результаты выполнения программы выводятся в 2 столбца: значения Sinl выводятся с 1-й позиции, а Cosl - с 40-й позиции.

Листинг 8. Процедура с процедурным типом параметра для вычисления и вывода на экран таблицы из двух столбцов.

PROGRAM PROCTYPE;
{$
F+}              { Дальний  вызов  подпрограмм }

Uses CRT;

TYPE { Func - }

Func=Function (X:real):real; {процедурный тип}
{
Текст  функции  Sin1 }

FUNCTION  Sin1(x:real):real;

BEGIN Sin1:=(sin(x)+1)*exp(-x)

END;
{ Текст функции
Cos1 }

FUNCTION  Cos1(x:real):real;

BEGIN     Cos1:=(cos(x)+1)*exp(-x)

END;

{ Текст процедуры вывода }

PROCEDURE PrintFunc (M:byte;F:Func); {F - параметр}
Const { процедурного типа Func }

n = 20; { - количество точек )

VAR x : real;

i : integer;

  BEGIN

For i := 1 to n do

begin  x:=i*2*PI/n;

GotoXY (M,WhereY ); { Курсор - в М-позицию }

{ той же строки }

Writeln (х:5:3,F(x):18:5)   { Вызов F }

end

END;      { PrintFunc }

{ Начало основной программы --  }

BEGIN

ClrScr; { Очистить экран }

PrintFunc (1,Sinl); {Sinl - фактический параметр

                                   процедурного типа }

GotoXY (1, 1); { Курсор в левый верхний угол }

PrintFunc (40,Cos1) { Cos1 - фактический параметр процедурного типа }

END.

Пример функции вычисления интеграла методом прямоугольников дан в листинге 9. В примере функция INTEGRAL вычисляет значение интеграла методом прямоугольников. Функция имеет процедурный параметр F, с помощью которого в нее передается имя функции, вычисляющей значение подынтегрального выражения. Вызов функции INTEGRAL производится из списка фактических параметров процедуры WRITELN.

В примере листинга 9 используются функции:

INTEGRAL - для вычисления интеграла методом прямоугольников;

FN - для вычисления подынтегрального выражения.

Формальными параметрами функции INTEGRAL являются:

XN, ХК - начальное и конечное значения аргумента для вычисления интеграла;

N - количество интервалов разбиения аргумента;

F - имя функции для вычисления подынтегрального выражения.

Функция F - формальный параметр - определена в списке формальных параметров с типом FUNC. При различных вызовах функции INTEGRAL имена функций - фактических параметров могут быть разными. Но они так же, как и FN, должны иметь один формальный параметр типа REAL и возвращаемый результат типа REAL.

Листинг 9. Вычисление интеграла методом прямоугольников с помошью функции с процедурным параметром.

PROGRAM   INTEGR; {$F+}

TYPE

FUNC=FUNCTION (X:REAL):REAL; {- процедурный тип}

FUNCTION FN(X:REAL):REAL; {Функция для вычисления   }

BEGIN FN:=2*X+1 END;{ подынтегрального  выражения   }

{   Функция  для  вычисления  интеграла методом прямоугольников     }

FUNCTION INTEGRAL(XN,ХК:REAL;N:INTEGER;F:FUNC):REAL;

VAR X, DX, S : REAL; I : INTEGER; BEGIN

IF XN>=XK THEN BEGIN WRITELN('Аргументы ошибочны'); Exit END;

{ Вычисление DX - шага интегрирования: }

DX := ( XK - XN ) / N; X := XN; S := 0;

FOR I:=1 TO N DO BEGIN {-перебор точек интегрирования}
X:=X+DX; { -
определение текущего значения X }
S := S + F (X) END; { -
вызов функции F }

INTEGRAL:=S*DX {- формирование возвращаемого

                                  значения }

END;

BEGIN ADSSIGN (OUTPUT, 'INT.REZ'); REWRITE (OUTPUT); WRITELN ('XN=',0.:12,'XK=',1.:12,'N=',10,#10#13, 'ИНТЕГРАЛ = ', INTEGRAL(0., 1., 10, FN ) : 12);

CLOSE (OUTPUT);

END.

Результаты выполнения программы:

XN=0.00000E+00  XK=1.00000E+00  N=10 ИНТЕГРАЛ =2.10000Е+00

Рекурсия и опережающее описание

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

Например, вычислить N!. При N = 0 или N = 1 решение тривиально (результат равен l) и используется для начала обратного хода рекурсивных вычислений. Текст программы, использующей рекурсивную функцию N!, дан в листинге 10. В ней с клавиатуры вводится целое число, факториал которого надо вычислить. Затем вызывается функция Fас, результат которой выводится на экран. Для завершения выполнения программы надо ввести команду Ctrl+z (признак конца файла).

Листинг 10. Рекурсивная функция Рас для вычисления значения N!.

PROGRAM  Factorial;

{$N+,E+}   {  N+  -  подключение  сопроцессора   }

{Е+ - создание программы для работы с cопроцессором}

VAR    N   :   integer;

FUNCTION  Fac (N:integer):longint; BEGIN

IF N<0 THEN BEGIN WRITELN ('N ошибочно');EXIT   END;

IF (N=0)OR(N=1) THEN Fac:=1

ELSE  Fac:=N*Fac(N-l)  { Рекурсия ! } END;    { Fac }

BEGIN    REPEAT  READLN ( N );

WRITELN( N, '! = ', Fac( N ));

UNTIL  EOF

END.    { - программы }

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

PROCEDURE A ( k : byte ); BEGIN . . .

B(k) ; { Вызов процедуры В }

. . .

END;

PROCEDURE В ( N : byte ) ;

BEGIN ... { Косвенная рекурсия: }

A(N); { вызов процедуры А }

END;

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

PROCEDURE В (N:byte );  { - опережающее описание  В: } FORWARD; { заголовок функции с параметрами, но нет текста процедуры В }

PROCEDURE A ( k : byte );

BEGIN . . .

B(k); { - вызов процедуры В }

. . .

END;

PROCEDURE В; { - нет формальных параметров В }

BEGIN ... { - текст - описание процедуры В }

  A(N); {- вызов процедуры А - косвенная рекурсия } END;

Таким образом, опережающее (FORWARD) и определяющее (с текстом подпрограммы) описания представляют собой полное описание процедуры. Опережающее описание обеспечивает взаимную рекурсию подпрограмм: ранее описанная подпрограмма может вызвать другую подпрограмму с опережающим описанием, текст которой расположен после вызывающей подпрограммы. Опережающие описания не допускаются в интерфейсной части модуля (unit).

2. Модули

Объем программы в Паскале должен быть не более 64 Кбайт. Но если текст программы должен быть более 64 Кбайт, надо разбить программу на ряд модулей: основную программу и один или более модулей (unit). Текст каждого из них должен быть не более 64 Кбайт.

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

Модули могут быть в виде PAS-файлов с исходными текстами и в виде объектных модулей (TPU-файлов). Компилятор Паскаля размещает объектные модули в отдельном сегменте памяти: в файлах с расширением .TPU (Turbo Pascal Uses). Максимальная длина сегмента модуля может быть не более 64 Кбайт. Но количество используемых модулей ограничивается только доступной внешней памятью.

Структура модулей

Структура модулей Паскаля:

UNIT имя-модуля ; { - заголовок модуля   }

INTERFACE

{ Интерфейсная часть: uses и глобальные объекты модуля. Заголовки процедур и функций модуля ( с параметрами ).}

IMPLEMENTATION

{ Секция реализации:

локальные объекты модуля и тексты процедур и функций}

[ BEGIN  инициирующая часть ]        { Секция инициализации: }

END. { в ней обязателен только END }

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

Например, если заголовок модуля имеет вид Unit MODUL;, то имя файла с исходным текстом модуля должно быть MODUL.PAS. После компиляции имя файла с объектным модулем будет MODUL.TPU. Имя модуля используется для его связи с другими модулями и с программой, к которой он присоединен с помощью оператора Uses (использование).

Форма оператора:

Uses список-модулей ;

где     список-модулей - это список имен модулей, с которыми устанавливается связь при компиляции программы, использующей подпрограммы этих модулей. Например: Uses  MODUL,   Crt,   Printer;.

Модуль может использовать подпрограммы других модулей. Оператор Uses в вызывающей программе должен быть после оператора PROGRAM, а в модуле - после ключевого слова INTERFACE.

Например, в программе может быть:

PROGRAM KR;

Uses  MODUL, Printer;

или - в модуле:

Unit MODUL;

 INTERFACE

  Uses Crt;

Модуль System (со стандартными процедурами и функциями) подключается всегда автоматически. Все модули, названные в операторе Uses, компилятор Паскаля ищет в файле Turbo.TPL (системмных библиотеках), в файлах типа .TPU (библиотеках пользователя) или в файлах типа .PAS. Поиск файлов ведется сначала в текущем каталоге, затем в каталогах, заданных в списке каталогов, файлов, определенных в меню Options\Directories\Unit directories (Параметры\Каталоги\Каталоги модулей).

Интерфейсная часть модуля

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

Структура интерфейсной секции:

INTERFACE

Uses

LABEL ...

CONST ...

type   ...        Глобальные объекты

VAR  ...

Заголовки процедур и функций модуля (с параметрами).

Глобальные объекты и оператор Uses необязательны. Правила описания констант, типов и переменных идентичны правилам их описания в программах и подпрограммах. Все константы и переменные, объявленные в интерфейсной части модуля, как и глобальные переменные вызывающей программы, помещаются в один общий сегмент данных (длиною не более 65521 байт).

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

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

Unit MODUL; Interface

Var  A-, В : REAL; { А и В - глобальны }

Procedure ADD (А,В: REAL; VAR  REZ : REAL); Function  MUL (А,В: REAL; RS:REAL ):REAL;

Если в вызывающей программе написать Uses MODUL, то в ней будут доступны переменные А, В, процедура ADD и функция MUL.

Исполняемая часть модуля

Исполняемая часть модуля начинается словом IMPLEMENTATION и содержит объявление локальных объектов модуля и тела (тексты) всех процедур и функций: заголовки, которые даны в интерфейсной части и заголовки, которых нет в ней.Тексты заголовков подпрограмм, заголовки которых даны в интерфейсной части, могут быть без параметров. После слова Implementation могут быть объявлены объекты, локальные в модуле: типы, константы, переменные, метки.

Структура исполняемой части модуля:

IMPLEMENTATION

Локальные  объекты модуля

Заголовок подпрограммы              Для каждой подпрограммы

Блок подпрограммы.

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

Пример модуля с процедурой ISWAP и функцией IMAX дан в листинге 11. Подключить модуль к программе можно с помощью USES MODUL. После подключения модуля можно использовать его процедуру и функцию.

Листинг 11. Модуль с процедурой и функиией.

Unit  MODUL;

Interface { - начало интерфейсной части }

Procedure  ISWAP ( Var  i,j : integer );
Function   IMAX( i,j : integer) : integer;

Implementation { - начало исполняемой части }

Procedure  ISWAP; { - заголовок без параметров }
Var T : integer;

Begin   T := I;   I := J;  J := T;

End; { - конец процедуры ISWAP }

Function  IMAX; { - заголовок без параметров }

Begin    IF  I  >  J THEN  IMAX := I

      ELSE  IMAX := J

End; { - конец функции IMAX }

END. { - конец модуля MODUL }

Инициирующая часть модуля

Инициирующая часть завершает модуль. В ней может быть блок с операторами, содержащими некоторый фрагмент программы. Эти операторы выполняются до начала вызывающей программы и обычно используются для подготовки работы вызывающей программы. Например, в ней могут инициироваться (получать начальные значения) переменные, открываться требуемые файлы и т. д. Если этого не требуется, в инициирующей части обязателен только последний оператор END. Пример модуля с инициирующей частью дан в листинге 12.

Листинг 12. Модуль с инициирующей частью.

Unit FileText;

Interface             { - начало интерфейсной части }

Procedure Print (S : string );

Implementation           { - начало исполняемой части }

Var F : TEXT;        { Локальны в модуле: F и NAME }

   Const NAME='D:\REZ.TXT'; {Определение константы NAME}

{  Процедура вывода значения S  в файл F - --}

Procedure Print;

Begin WRITE (F,S);

  End;                 { - конец исполняемой части }

BEGIN                 { - начало инициирующей части }

Assign (F, NAME); { - назначение переменной F файла }

{   из константы NAME }

Rewrite ( F ) ;  { - открытие файла F для создания }

END.                       { - конец инициирующей части }


 

А также другие работы, которые могут Вас заинтересовать

84762. Коммуникационный протокол IPv4 640.04 KB
  Длина заголовка 4 бита задает значение длины заголовка пакета измеренной в 32 битовых 4 байтовых словах. Тип сервиса Туре of Service ToS 8 битовое поле предназначенное для оптимизации транспортной службы содержащее: 3 битовое поле Приоритет принимает 8 значений: от 0 нормальный приоритет...
84763. Транспортные протоколы стека TCP/IP 237.33 KB
  Транспортные протоколы ТСР и UDP стека протоколов TCP IP обеспечивают передачу данных между любой парой прикладных процессов выполняющихся в сети и предоставляют интерфейс для протокола IP путем демультиплексирования нескольких процессов использующих в качестве адресов транспортного уровня порты.
84764. Общие принципы организации сетей. Основные понятия и определения 672.2 KB
  Средства вычислительной техники (СВТ) реализуют обработку данных и представляют собой совокупность ЭВМ, вычислительных комплексов и вычислительных систем различных классов. ЭВМ (электронная вычислительная машина, компьютер) совокупность технических средств, предназначенных для организации ввода...
84765. Требования к организации компьютерных сетей 439.39 KB
  Открытость возможность добавления в сеть новых компонентов узлов и каналов связи средств обработки данных без изменения существующих технических и программных средств; 2 гибкость сохранение работоспособности при изменении структуры сети в результате сбоев и отказов отдельных...
84766. Сетевые топологии 697.36 KB
  Следует различать физическую и логическую топологию сети. Физическая структурная топология отображает структурную взаимосвязь узлов сети. Логическая функциональная топология определяется функциональной взаимосвязью узлов сети то есть отображает последовательность передачи данных между узлами сети.
84767. Маршрутизация 495.88 KB
  Маршрутизация одна из основных функций компьютерной сети определяющая эффективность передачи данных. Проблема маршрутизации в компьютерных сетях аналогична проблеме организации автомобильного движения по улицам города и состоит в выборе в каждом узле сети направления передачи данных выходного...
84768. СРЕДСТВА ТЕЛЕКОММУНИКАЦИЙ 599.62 KB
  Для передачи электрических и оптических сигналов применяются электрические ЭЛС и волоконно-оптические ВОЛС линии связи соответственно. Передача электромагнитных сигналов осуществляется через радиолинии РЛС и спутниковые линии связи СЛС.
84769. Модуляция и кодирование данных 654.93 KB
  На основе непрерывного аналогового высокочастотного синусоидального сигнала называемого несущей аналоговая модуляция; на основе дискретного цифрового сигнала в виде импульсов импульсная или цифровая модуляция. Процесс преобразования дискретных данных представляемых дискретными первичными сигналами...
84770. Кабельные линии связи. Классификация кабельных линий связи 692.46 KB
  Классификация кабельных линий связи При организации компьютерных сетей широко используются кабельные линии связи. Кабельная линия связи КЛС линия связи состоящая из кабеля кабельной арматуры и кабельных сооружений туннели колодцы распределительные шкафы кабельные столбы.