Глава 1: Опасности неявной типизации
Первое, что я настоятельно рекомендую вам сделать, это включить строку
implicit none
после строки program
. Это подавит неявную типизацию, а возникающие в результате ошибки дадут вам некоторую полезную информацию о том, что происходит.
Если бы вы это сделали, вы бы получили сообщение об ошибке:
$ gfortran -o binsearch binsearch.f90
binsearch.f90:23:12:
read*, a
1
Error: Symbol ‘a’ at (1) has no IMPLICIT type
binsearch.f90:27:25:
print*,binarySearch_R
1
Error: Symbol ‘binarysearch_r’ at (1) has no IMPLICIT type
binsearch.f90:24:16:
read*, value
1
Error: Symbol ‘value’ at (1) has no IMPLICIT type
It не имеет значения, что a
, value
и binarySearch_R
были определены в функции. Поскольку функция не является частью блока program
, программа не знает, что это такое.
При активном неявном типировании она просто предполагала, что все три являются простыми real
переменными. (Тип зависит от первой буквы имени переменной, от i до n это integer
, все остальное - real
)
Поскольку эта неявная типизация может так легко скрыть ошибки кодирования, это сильно, настоятельно рекомендуется всегда выключать его.
Это также означает, что мы должны объявить переменные a
и value
в программе:
program hji
implicit none
real :: a(6), value
...
end program hji
Глава 2 : Как ввести функцию в программу?
Так как программа получает доступ к функции? Есть четыре способа:
Лучший способ: использовать модуль
module mod_binsearch
implicit none
contains
recursive function binarySearch_R (a, value) result (bsresult)
...
end function binarySearch_R
end module mod_binsearch
program hji
use mod_binsearch
implicit none
real :: a(6), value
...
end program hji
Обратите внимание, что оператор use
должен стоять перед implicit none
. Этот метод оставляет функцию отдельной, но вызываемой. Он автоматически проверяет правильность параметров (это то, к чему мы скоро вернемся).
Имеет функцию, содержащуюся в программе.
Между последняя строка кода программы и оператор end program
, добавьте ключевое слово contains
, за которым следует код функции (все от recursive function ...
до end function ...
).
Это быстрый и -грязный метод. Вы должны быть осторожны с этим методом, так как функция автоматически получит доступ к программным переменным, если внутри функции не объявлена новая переменная с таким именем.
Сложный способ: Интерфейсы
Создайте блок интерфейса в разделе объявления исходного кода вашей программы и повторите там информацию об интерфейсе.
Это по-прежнему позволяет компилятору проверять, правильно ли вызывается функция, но она работает вам, чтобы убедиться, что этот интерфейсный блок правильный и соответствует фактической реализации.
Действительно, действительно уродливый способ: объявить его как переменную, вызвать ее как функция.
Пожалуйста, не делайте этого.
Глава 3: Вызов функции
Когда вы вызываете функцию, вы должны использовать круглые скобки и дайте ему все ожидаемые параметры. В вашем случае вам нужно ввести
print *, binarySearch_r(a, value)
Глава 4: Dynami c массивы в качестве фиктивных параметров
При последовательных рекурсивных вызовах функции массив становится все меньше и меньше. Но фиктивный параметр всегда одного размера (6). Это не только помешает вашему алгоритму, но также может привести к опасно неопределенному доступу к памяти.
К счастью, специально для intent(in)
фиктивных параметров вы можете использовать динамические c массивы:
recursive function binarySearch_R(a, value)
real, intent(in) :: a(:), value
Единственное двоеточие сообщает компилятору, что следует ожидать одномерный массив, но не его длину. Поскольку вы уже используете size(a)
, он должен работать автоматически.