- •Алфавит, лексемы, ключевые слова языка Фортран. Метки. Комментарии.
- •Структура программы. Внешние подпрограммы. Внутренние подпрограммы. Модули.
- •Переменные. Переменная – это величина, которая может в программе принимать различные значения.
- •Условный оператор if... Then...End if.
- •12.Неявное определение типа.
- •13. Синтаксис определения производных типов
- •14. Атрибут parameter. Именованные константы и константные выражения
- •15. Атрибуты dimension и allocatable. Описание массивов.
- •16. Атрибут intent. Описание формальных параметров.
- •17. Определенные и неопределенные переменные. Выражения с массивами и присваивание массивов.
- •24,Внешние подпрограммы.
- •30.Оператор use
- •31.Основные сведения о массивах
- •32.Массивы. Динамические массивы.
- •33.Операторы allocate, deallocate.
- •34.Форматирование ввода-вывода. Оператор format.
- •35.Соединение файла с логическим устройством
- •Алфавит, лексемы, ключевые слова языка Фортран. Метки. Комментарии.
- •15. Атрибуты dimension и allocatable. Описание массивов.
- •18. Скалярные числовые выражения и скалярное числовое присваивание.
- •27. Модули. Области общей памяти.
24,Внешние подпрограммы.
Внешние подпрограммы обычно служат для выполнения отдельных задач в рамках общей задачи программы в целом. Внешние подпрограммы вызываются из главной программы или из других подпрограмм и при завершении возвращают управление вызывающему компоненту. Структура внешней подпрограммы похожа на структуру главной программы, за исключением заголовка:
Заголовок_подпрограммы
[операторы_описания]
[исполняемые_операторы]
[CONTAINS
внутренние_подпрограммы]
END [спецификатор_подпрограммы [ имя__подпрограммы] ]
Здесь Заголовок_подпрограммы имеет вид:
{префикс__спецификатора] спецификатор_подлрограммы имя_подпрограммы
[(список_формальных_параметров)]
где спецификатор_подпрограммы — один из операторов: subroutine или
function; имя_подпрограммы — уникальное имя, удовлетворяющее правилам
фортрана, за которым может следовать необязательный список_формальных_
параметров, заключенный в круглые скобки. Спецификатор подпрограммы
указывает, является ли подпрограмма процедурой или функцией. Процедура
не имеет возвращаемого значения: результаты ее работы передаются либо
через формальные параметры, либо через глобальные переменные. Функция
же возвращает значение заданного типа, которое может быть присвоено пе-
ременной или подставлено в выражение. Поэтому префикс_спецификатора
для функций содержит тип возвращаемого значения. Обращение к процедуре осуществляется оператором call, имеющим вид:
CALL имя_подпрограммы [(список_фактических_параметров)],
например,
CALL BIGSUB
Вызов функции не требует никакого специального оператора:
REAL A, X
REAL, EXTERNAL :: MYFUNC
А = MYFUNC (X)
Оператор end подпрограммы возвращает управление тому программному компоненту, из которого подпрограмма была вызвана. Есть способ сделать это, не дожидаясь конца подпрограммы — оператор return прекратит выполнение подпрограммы в любом ее месте и передаст управление в место вызова. Как и оператор stop, он может иметь метку и быть частью условного оператора. Оператор return не может появляться в главной программе и в подпрограммах-функциях. Если в операторе end указано имя подпрограммы или функции, оно должно совпадать с именем, указанным в заголовке. Пример главной программы с внешней подпрограммой: Пример главной программы с внешней подпрограммой
PROGRAM main
IMPLICIT NONE
REAL X, Y, S
DATA X, Y /0.755545, 6.873452/
CALL outer_sub(X, Y, S)
158 Глава 7
WRITE(*, *) 'Result of outer_sub S =', S
END PROGRAM main
SUBROUTINE outer_sub(A, В, С)
REAL А, В, С
С = SQRT(A**2 + B**2)
END SUBROUTINE outer_sub
1)Внешнии подпрграммы:
program swapab
Integer::a,b
a=5
b=1
call swap(A,b)
print*,'A=',a,'B=',b
end program
subroutine swap(c,d)
Integer::d,c,tmp
tmp=d
d=c
c=tmp
end subroutine
Внутренние подпрограммы
Внутренние подпрограммы, в отличие от внешних, не могут содержать собственных внутренних подпрограмм и имеют вид:
Заголовок_подпрограммы
[операторы_описания]
[исполняемые_операторы]
END [спецификатор_подпрограммы [имя_подпрограммы]]
Внутренняя подпрограмма автоматически получает доступ ко всем объектам своего носителя, в том числе, к другим внутренним подпрограммам Все обращения к внутренним подпрограммам могут производиться только из компонента-носителя Пример внутренней подпрограммы в главной программе:
Пример главной программы с внутренней подпрограммой:
PROGRAM main
IMPLICIT NONE
REAL X, Y, S
DATA X, Y /0.755545, 6.873452/
CALL inner_sub(X, Y, S)
WRITE(*, *) 'Result of inner_sub S =', S
CONTAINS
SUBROUTINE inner_Sub(A, В, С)
REAL А, В, С
С = SQRT(A**2 + B**2)
END SUBROUTINE inner_sub
END PROGRAM inam
Программа, состоящая из двух компонент с внутренними подпрограммами, имена которых совпадают. Тем не менее, каждый компонент уверенно вызывает только свою подпрограмму
Внутренние подпрограммы:
PROGRAM main
IMPLICIT NONE
REAL X, Y, S
DATA X, Y /0 755545, 6.873452/
CALL inner_sub(X, Y, S)
WRITE(*, *) 'Result of main1's inner_sub S =', S
CALL outer_sub(X, Y, S)
WRITE(*, *) 'Result of outer_sub S =', S
CONTAINS
SUBROUTINE inner_sub(A, В, С)
REAL, PARAMETER :: R = 5.,RR = SQRTE / 2.0)
REAL А, В, С
С = SQRT(A**2 + B**2)
IF (C > R) THEN
IF (A > RR) A = RR
IF(B > RR) В = RR
END IF
END SUBROUTINE inner_sub
END PROGRAM main
SUBROUTINE outer_sub(A, В, С)
REAL А, В, С
REAL S
CALL inner_sub(A, B, S)
WRITE(*, *) 'Result of outer1's inner_sub S =', S
С = SQRT(A**2 + B**2)
CONTAINS
SUBROUTINE inner_sub(A, В, С)
REAL А, В, С
С = SQRT(ABS(A**2 - B**2))
END SUBROUTINE inner_sub
END SUBROUTINE outer_sub
Внутренние подпрограммы:
program swapab
Integer::a,b
a=5
b=1
call swap(A,b)
print*,'A=',a,'B=',b
contains
subroutine swap(c,d)
Integer::d,c,tmp
tmp=d
d=c
c=tmp
end subroutine
end program
МОДУЛИ:
MODULE имя_модуля
[операторы_описания]
[CONTAINS
модуль ные_подпрограммы ]
END [MODULE [имя_модуля]]
MODULE ARRAY
REAL, DIMENSIONB0) :: A
CONTAINS
….
END MODULE ARRAY,
Интерфейсы
Для организации вызова любой подпрограммы необходимо и достаточно
знать ее интерфейс: заголовок, список формальных параметров и их описа-
ния. Интерфейс внутренней подпрограммы всегда известен в области ее
использования: компонент-носитель знает все о параметрах внутренней
подпрограммы; другим же программным компонентам внутренние подпро-
граммы недоступны. Интерфейс внутренней подпрограммы представляет
образец явного интерфейса: проверить корректность обращения к ней можно
еще на стадии компиляции. Другим примером явного интерфейса являются
модульные подпрограммы и встроенные функции.
Внешняя подпрограмма и формальная процедура, как правило, не обладают явным интерфейсом. У компилятора нет сведений о параметрах внешних и формальных
процедур, т. е. их интерфейс является неявным. Поэтому на этапе компиля-
ции невозможно, например, выполнить проверку на соответствие межд>
фактическими и формальными параметрами.
Сделать неявный интерфейс явным можно, описав его в интерфейсном блоке
INTERFACE
заголовок_лодпрограммы
описание_формальных_параметров
[описание_локаль ных_переменных]
оператор_Е№Э_подпро граммы
END INTERFACE
В интерфейсный блок нельзя включать операторы data и format Имена
формальных параметров и порядок операторов описания можно, а в некото-
рых случаях, и нужно, менять. В интерфейсном блоке можно поместить
описание интерфейса программы, написанной на другом языке программи-
рования, например, на языке ассемблера или на языке С.
Интерфейсный блок размещается среди операторов описания; после этого
интерфейс подпрограммы, содержащейся в нем, становится явным.
В листинге 1. интерфейс внешней подпрограммы сделан явным посредст-
вом включения интерфейсного блока в главную программу.
Листинг 1. Интерфейсный блок
PROGRAM main
IMPLICIT NONE
REAL X, Y, S
INTERFACE
SUBROUTINE outer_sub(A, В, С)
REAL А, В, С
END SUBROUTINE OUter_sub
END INTERFACE
DATA X, Y /0.755545, 6.873452/
CALL inner_sub(X, Y, S)
WRITE(*, *) 'Result of main''s inner_sub S =', S
CALL outer_sub(X, Y, S)
WRITE(*, *) 'Result of outer_sub S =', S
CONTAINS
SUBROUTINE inner_sub(A, В, С)
REAL, PARAMETER :: R = 5., RR = SQRTE. / 2.0)
REAL А, В, С
REAL, INTENT(OUT) :: С
С = SQRT(A**2 + B**2)
IF (C > R) THEN
IF (A > RR) A = RR
IF(B > RR) В = RR
END IF
END SUBROUTINE mner_sub
END PROGRAM main
25. Параметры подпрограмм
Все подпрограммы — и процедуры, и функции, — должны иметь возмож-
ность обмениваться данными с теми компонентами программы, из которых
они были вызваны. Подпрограммы получают входные данные от вызываю-
щего компонента и передают ему выходные данные — результаты своей
работы. Обмен информацией с подпрограммами может происходить через
параметры подпрограмм и/или через глобальные данные. Глобальные дан-
ные — это переменные, доступные в равной степени и подпрограмме, и вы-
зывающему компоненту. Организация глобальных данных будет рассмотрена
в разделе "Модули" настоящей главы. Другой способ обмена информаци-
ей — передача данных через параметры подпрограмм. В этом случае в описа-
нии подпрограммы указывается список_формальных_параметров — перечень
переменных (среди них могут быть и имена функций), которые так или
иначе будут использоваться в ходе выполнения подпрограммы. Формальные
параметры должны быть (явно или неявно) описаны в операторах описания
подпрограммы. При вызове подпрограммы происходит подстановка факти-
ческих параметров на место формальных (листинг 1).
Листинг 1. Формальные и фактические параметры
SUBROUTINE sub(A, В, С) 'А, В, С - формальные параметры
REAL А, В, С
С = SQRT(A**2 + В**2)
END SUBROUTINE sub
PROGRAM main
IMPLICIT NONE
REAL X, Y, S
DATA X, Y /0.755545, 6.873452/
CALL sub(X, Y, S) ' X, Y, S - фактические параметры
WRITE(*, *) 'Result of sub S =', S
END PROGRAM mam
Ограничения, накладываемые
на фактические параметры .
Фактические параметры обязаны согласовываться с соответствующими
формальными параметрами по типу, параметрам типа и по форме. Совпаде-
ния имен параметров не требуется. Более того, на место формального пара-
метра может быть подставлено выражение, тип и разновидность типа кото-
рого совпадают с типом и разновидностью формального параметра
Предполагается, что формальные параметры являются отдельными объекта-
ми, не совпадающими ни с какими другими объектами подпрограммы
Компилятор может скопировать входной параметр во внутреннюю перемен-
ную при входе в подпрограмму с тем, чтобы на выходе из нее вернуть со-
храненное значение фактическому параметру Поэтому на фактические па-
раметры накладываются следующие ограничения:
- любые действия, влияющие на фактический параметр в обход формаль-
ного параметра, запрещены;
- если хотя бы часть фактического параметра получает значение через
формальный параметр, то ссылаться на этот фактический параметр мож-
но только через формальный параметр.
То есть если в подпрограмме введен формальный параметр а, то в рамках
подпрограммы он будет доступен только как а, независимо от того, какой
фактический параметр подставляется на его место Возможность доступа
к фактическому параметру в обход формального появляется, например, то-
гда, когда фактическим параметром становится глобальная переменная из
присоединенного модуля или переменная, доступная через соммоы-блок.
26. Параметры подпрограмм
Все подпрограммы — и процедуры, и функции, — должны иметь возможность обмениваться данными с теми компонентами программы, из которых они были вызваны. Подпрограммы получают входные данные от вызывающего компонента и передают ему выходные данные — результаты своей
работы. Обмен информацией с подпрограммами может происходить через параметры подпрограмм и/или через глобальные данные. Глобальные данные — это переменные, доступные в равной степени и подпрограмме, и вы-
зывающему компоненту. Организация глобальных данных будет рассмотрена в разделе "Модули" настоящей главы. Другой способ обмена информацией — передача данных через параметры подпрограмм. В этом случае в описа-
нии подпрограммы указывается список_формальных_параметров — перечень переменных (среди них могут быть и имена функций), которые так или
иначе будут использоваться в ходе выполнения подпрограммы. Формальные
параметры должны быть (явно или неявно) описаны в операторах описания
подпрограммы. При вызове подпрограммы происходит подстановка факти-
ческих параметров на место формальных (листинг 1).
Листинг 1. Формальные и фактические параметры
SUBROUTINE sub(A, В, С) 'А, В, С - формальные параметры
REAL А, В, С
С = SQRT(A**2 + В**2)
END SUBROUTINE sub
PROGRAM main
IMPLICIT NONE
REAL X, Y, S
DATA X, Y /0.755545, 6.873452/
CALL sub(X, Y, S) ' X, Y, S - фактические параметры
WRITE(*, *) 'Result of sub S =', S
END PROGRAM mam
При работе с подпрограммами важными являются понятия формальных и фактических параметров. Формальные параметры — это идентификаторы входных данных для подпрограммы. Если формальные параметры получают конкретные значения, то они называются фактическими. Формальные параметры могут получить конкретные значения только в той программе, где производится обращение к данному модулю-подпрограмме. Тип и порядок записи фактических параметров должны быть такими же, как и формальных параметров. В противном случае результат работы программы будет непредсказуемым. Из этого следует, что фактические параметры используются при обращении к подпрограмме из основной, а формальные параметры — только в самом модуле.
Категории формальных параметров
Параметры-значения (в списке формальных параметров не имеют атрибута). Передаются ПП через стек, как копии, и не изменяются ею.
Параметры-переменные (в списке формальных параметров имеют атрибут var). Передаются ПП через адреса, и могут изменяться ею. Используются для возврата результатов в вызывающую программу.
Выходные параметры-переменные (в списке формальных параметров имеют атрибут out). Подобны параметрам-переменным, но передаются только из ПП в программу.
Параметры-константы (в списке формальных параметров имеют атрибут const). Передаются ПП через адреса, но не могут изменяться ею. Применяются вместо параметров-значений, когда стек может переполняться.
Процедуры или функции. Это параметры процедурного типа. Задаются именами.
Параметры без типа. За правильность использования отвечает программист.
Умалчиваемые параметры. Их в списке фактических параметров можно пропускать. В списке формальных параметров для них нужно задать тип и значение.
27. Модули
Если целью внутренних и внешних подпрограмм является выполнение действий, определяемых подзадачей в рамках всей программы (внешние подпро-
граммы) или данного программного компонента (внутренние подпрограммы),
то задачей модуля является аккумуляция данных.
Структура модуля такова:
MODULE имя_модуля
[операторы_описания]
[CONTAINS
модуль ные_подпрограммы ]
END [MODULE [имя_модуля]]
Модуль включается в другие программные компоненты оператором use. Все объекты модуля, не имеющие атрибута private, могут использоваться во
включающих компонентах.
Оператор use имеет возможность ограничить доступ к частям модуля или переименовать объекты, доступ к которым разрешен. (Подробнее об опера-
торе use будет рассказано в одном из следующих разделов.) Если ограничений не установлено, все объекты модуля доступны, модульныеподпрограммы
имеют структуру внешних подпрограмм, за исключением того, что оператор end, завершающий их описание, обязан содержать слово subroutine или
function в соответствии с видом подпрограммы. Все объекты модуля автоматически доступны для модульных подпрограмм.
Модули можно вкладывать друг в друга, используя все тот же оператор use,при этом модуль не должен ссылаться сам на себя ни прямо, ни косвенно —
через цепочку модулей.
Самый простой пример использования модуля — это помещение в него описаний данных. Описываем модуль array и помещаем в него описание некоторого массива:
MODULE ARRAY
REAL, DIMENSIONB0) :: A
END MODULE ARRAY,
и затем включаем этот модуль в набор подпрограмм subi, sub2 и sub3:
SUBROUTINE SUBI
USE ARRAY
END SUBROUTINE SUB1
и так далее Массив а будет доступен для всех трех подпрограмм:
PROGRAM SUBS
CALL SUB1
CALL SUB2
CALL SUB3
END PROGRAM SUBS
Модуль является идеальным местом для размещения определений производных типов и операций с ними, интерфейсных блоков и списков
NAMELIST.
Области общей памяти
Необходимо отметить, что в Фортране существует еще одно средство глобализации данных — это области общей памяти, называемые coMMON-блоками.
coMMON-блоки могут быть именованными и неименованными. Можно описать только один неименованный соммодг-блок для всей программы, именованных блоков можно описать множество. Область общей памяти описывается оператором common, полный синтаксис которого имеет вид:
COMMON [/имя_общего_блока/] список [, /имя_общего_блока/] список .,где имя_общего_блока — необязательное имя comoN-блока, а список — спи-
сок переменных, размещаемых в указанной области общей памяти. Приведем примеры именованного и безымянного блоков:
COMMON /BASE/ X, Y, Z, INDEXA0)
COMMON / / RESULTB00)
Сommon-блок представляет собой отрезок памяти, куда последовательно записываются включенные в него объекты. Общая область доступна для всех программных компонентов, объявивших ее. При этом имена переменных именованного соммоы-блока в различных программных компонентах вовсе не должны совпадать — должно совпадать полное число единиц памяти, отведенных под него. Например,
coMMON-блок /base/ в другой подпрограмме может выглядеть так:
COMMON /BASE/ AC), I, J, К(8)
Данные соммоы-блока становятся неопределенными после выхода из подпрограммы, описывающей его, если только другие подпрограммы или главная программа не используют его.
28. Рекурсивные процедуры и функции
Процедуры и функции могут вызывать сами себя, то есть обладать свойством рекурсивности.
Предполагается, что подпрограммы не содержат обращений к себе* по умол-
чанию рекурсия подпрограмм запрещена. Подпрограмму можно объявить
рекурсивной, для этого нужно внести в ее заголовок декларацию recursive:
RECURSIVE SUBROUTINE FACTORIAL(N, NF)
тогда обращения из подпрограммы к самой себе будут разрешены. При соз-
дании рекурсивной подпрограммы необходимо построить ее алгоритм так,
чтобы выход из нее гарантировался. Рассмотрим простейшую рекурсивную
подпрограмму вычисления факториала целого числа n (листинг 7.9)'
Листинг 7.9. Пример рекурсивной процедуры
RECURSIVE SUBROUTINE FACTORIAL(N, NF)
INTEGER, INTENT(IN) :: N
INTEGER, INTENT(INOUT) :: NF
DATA NF /1/
IF(N .GT. 1) THEN
NF = NF * N
CALL FACTORIAL(N - 1, NF)
END IF
END
При каждом вызове рекурсивной подпрограммы создается новый набор ло-
кальных объектов подпрограммы. Исключением являются объекты, имею-
щие атрибут save, и объекты, начальное значение которых задается опера-
тором data. Объекты, инициализируемые в подпрограммах, получают
атрибут save автоматически, а оператор data при рекурсивном вызове вы-
полняется только один раз.
Рекурсивные функции несколько отличаются от рекурсивных процедур* ес-
ли рекурсивная функция вызывает сама себя, результат ее должен иметь
другое имя. Описанная здесь подпрограмма factorial является процедурой;
сделаем из нее рекурсивную функцию (листинг 7.10).
Листинг 7.10. Пример рекурсивной функции
INTEGER RECURSIVE FUNCTION FACTORIAL(N) RESULT(NF)
INTEGER N, NF
DATA NF /1/
IF(N .GT. 1) NF = N * FACTORIAL(N - 1)
END
Директива result помещает результат рекурсивной функции в указанную
переменную, решая проблему сохранения результата предыдущей итерации.
29. Области видимости имен и меток
Для именованных объектов и меток существует пространство, в рамках которого они доступны по своему идентификатору. Это пространство называется областью видимости. Для каждой подпрограммы определен свой набор меток; даже внутренние подпрограммы имеют свой, независимый от компонента-носителя набор. То есть метки компонента-носителя и внутренней подпрограммы могут быть одинаковыми, они не будут смешиваться.
К именованным объектам относятся переменные, именованные константы, подпрограммы (внутренние и внешние), производные типы и списки NAMELIST.
Каждая подпрограмма определяет свое пространство имен, состоящее из всех объектов, описанных в ней Это локальные объекты. Кроме локальных объектов, внутри подпрограммы могут использоваться ассоциированные (присоединенные) и глобальные объекты. Ассоциирование может происходить
через носитель (подпрограмма является внутренней подпрограммой) или через включение в компонент модуля (vse-ассоциированиё) Глобальные объекты — к ним относятся имена программных компонентов и внешние подпрограммы — не требуют объявления и автоматически доступны в любом месте программы.
Локальные именованные объекты доступны для всех операторов того программного компонента, в котором они определены, за вычетом интерфейсов. Блоки определения производных типов и внутренних подпрограмм имеют доступ к ассоциированным объектам через носитель, если только в них не объявлен локальный объект с тем же именем — локальные объекты
имеют приоритет перед объектами, ассоциированными через носитель Для носителя локальные объекты блоков определения производных типов, внутренних подпрограмм и интерфейсов недоступны. Например, в программе inside, переменная а доступна ассоциированием через подпрограмму- носитель outside, а переменная в носителя недоступна, так как в inside объявлена локальная переменная с тем же именем:
SUBROUTINE OUTSIDE
REAL А, В
CONTAINS
SUBROUTINE INSIDE
REAL В, Y
У = А + В
END SUBROUTINE INSIDE
END SUBROUTINE OUTSIDE
Имена use-ассоциированных объектов использовать в описаниях локальных объектов, вообще говоря, нельзя. Оператор:
USE имя_модуля
рассматривается как повторное описание всех объектов модуля внутри программного компонента с сохранением своих имен и свойств. Другое дело, что возможности оператора use позволяют обойти нежелательное совпадение имен объектов модуля и программы, использующей его
Имя каждого именованного объекта внутри блока видимости должно быть уникальным Например, определение внутренней подпрограммы с именем sin сделает недоступной одноименную встроенную процедуру.
