Maxim Moloshenko
Maxim Moloshenko

Reputation: 366

Segmentation fault, when passing functions with array arguments to subroutine in Fortran

I am working on a project (which is due tomorrow :/) and encountered a problem when I tried to use a simplex algorithm on a function I wrote myself. It didn't work, and after now 5 hours of searching and experimenting, I found out the following:

When I pass a function to a subroutine, this function can't have any array arguments. Is this true? Because in the code that I am supposed to use it evidently SHOULD work.

I am using the ifort compiler. See below for a minimum example, which I basicaly took from http://malayamaarutham.blogspot.de/2006/02/passing-function-names-as-arguments-in.html

  ! Author : Kamaraju S Kusumanchi
  ! Email  : [email protected]
  ! Last edited : Sun Feb  5 2006
  !
  ! Sample program demonstrating the use of external attribute.        This program
  ! shows how to pass function names as arguments in Fortran 90       programs.
  !
  ! Compilation and execution steps
  ! $gfortran passing_functions.f90 -o passing_functions
  ! $./passing_functions
  !  beta =    5.500000
  !  beta =    1.500000
  !
  ! I would appreciate any comments, feedback, criticism,       mistakes, errors etc.,
  !   (however minor they are)
  !
  module dummy
    implicit none
  contains
  !------------------------------------------------------------------------------
  function func1(a)
    implicit none
    real :: a
    real :: func1

    func1 = a+5
  end function func1
  !------------------------------------------------------------------------------
  function func2(b)
    implicit none
    real :: b(:)
    real :: func2

    func2 = b(1)
  end function func2
  !------------------------------------------------------------------------------
  function func3(dyn_func, c)
    implicit none
    real :: c
    real, external :: dyn_func
    real :: func3

    func3 = dyn_func(c)
  end function func3
  !------------------------------------------------------------------------------
  function func4(dyn_func, c)
    implicit none
    real :: c(*)
    real, external :: dyn_func
    real :: func4

    func4 = dyn_func(c)
  end function func4
  end module dummy
  !------------------------------------------------------------------------------

  program passing_functions
    use dummy
    implicit none

    real :: alpha=0.5, beta
    real :: gamma(2) = (/10,20/)

    beta = func3(func1, alpha)
    write(*,*) 'beta = ', beta
    beta = func4(func2, gamma)
    write(*,*) 'beta = ', beta
  end program passing_functions

This is the output:

zeus$ passing.out
 beta =    5.500000    
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image              PC                Routine            Line        Source             
passing.out        0000000000402D44  Unknown               Unknown  Unknown
passing.out        0000000000402C7C  Unknown               Unknown  Unknown
libc.so.6          00002AFF7915D23D  Unknown               Unknown  Unknown
passing.out        0000000000402B79  Unknown               Unknown  Unknown
zeus$ 

Upvotes: 1

Views: 3016

Answers (1)

M. S. B.
M. S. B.

Reputation: 29391

The other answer could be used to solve your problem, but there are simpler ways without using pointers.

There is almost never a reason to use external in modern Fortran. In Fortran questions that I see on Stackoverflow it almost always leads people to a wrong approach. Unless you are really sure, don't use external.

What you want to do is declare (i.e., describe) the function arguments in functions func3 and func4 with interface blocks. Here is how to do it for func4 ... you should be able to figure out func3:

 function func4(dyn_func, c)
    implicit none
    real, dimension (:) :: c
    interface
       function dyn_func (x)
          real :: dyn_func
          real, dimension (:) :: x
       end function dyn_func
    end interface
    real :: func4

    func4 = dyn_func(c)
  end function func4

Upvotes: 5

Related Questions