passing pointer arguments in fortran

2020-04-17 06:59发布

问题:

I am wondering what is the proper way to write the following code?

PROGRAM foo

  INTEGER :: x
  REAL(KIND=8), TARGET, DIMENSION(0: 10) :: array
  REAL(KIND=8), POINTER, DIMENSION(:) :: ptr

  ptr => array

  CALL bar(ptr)

END PROGRAM foo

SUBROUTINE bar (ptr)

  REAL(KIND=8), POINTER, DIMENSION(:) :: ptr                                                                                                                                                                                                                  
  INTEGER x
  DO x =0, 10
    ptr(x) = 2 // seg faults
  ENDDO

END SUBROUTINE bar

It works if I declare ptr in bar as REAL(KIND=8), DIMENSION(0:10). But in general I might not know the size of the passed-in array, so is there a way to declare ptr to be a pointer to some array? I am compiling this with gfortran

回答1:

If a procedure has a dummy argument that is a pointer, then an explicit interface is required in any calling scope.

(There are numerous things that require an explicit interface, a pointer dummy is but one.)

You can provide that explicit interface yourself by putting an interface block for your subroutine inside the main program. An alternative and far, far, far better option is to put the subroutine inside a module and then USE that module in the main program. A third alternative is to make the subroutine an internal procedure of the calling scope.

As of Fortran 2003, you should only use pointers if you intend to point the pointer at different things. If you are just using the pointer for something that really just behaves like a value, then you should use allocatables instead.



回答2:

It depends what you mean with "proper" way. As IanH already pointed out, you need an explicit interface (best done via packing things in a module) and using allocatables instead of pointers, if possible.

I'd further add, that if you do not want to change the allocation status of your array within your subroutine, but only want to manipulate its elements, then use a simple assumed shape array within your subroutine. Below you find a working example for it. A few more things to note:

  • Do not use real(kind=8) as not all compilers use the number of bytes as kind for the real numbers. If you want double precision accuracy, ask for it explicitely as below.

  • If you just want to fill up an array with a constant value, do it the simple way: array(:) = 2.0_dp

And here the example:

module accuracy
  implicit none

  integer, parameter :: dp = kind(1.0d0)

end module accuracy


module barmodule
  use accuracy
  implicit none

contains

  subroutine  bar(array)
    real(dp), intent(inout) :: array(:)

    integer :: ii

    do ii = 1, size(array)
      array(ii) = ii
    end do

  end subroutine bar

end module barmodule


program foo
  use accuracy
  use barmodule
  implicit none

  real(dp), dimension(0:10) :: array
  call bar(array)

end program foo