如何在Fortran中将可分配数组传递给子程序

21
以下代码返回了一个分段错误,因为我尝试传递的可分配数组未被正确识别(大小应为3,但返回1)。在这个页面(http://www.eng-tips.com/viewthread.cfm?qid=170599)中,类似的示例似乎表明它应该在F95中正常工作;我的代码文件扩展名为.F90,但我尝试将其更改为F95,并使用gfortran进行编译。
我猜问题应该在我传递可分配数组到子程序的方式上;我做错了什么?
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
 PROGRAM test
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
 IMPLICIT NONE
 DOUBLE PRECISION,ALLOCATABLE :: Array(:,:)
 INTEGER                      :: iii,jjj

 ALLOCATE(Array(3,3))
 DO iii=1,3
 DO jjj=1,3
    Array(iii,jjj)=iii+jjj
    PRINT*,Array(iii,jjj)
 ENDDO
 ENDDO
 CALL Subtest(Array)

 END PROGRAM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
 SUBROUTINE Subtest(Array)
 DOUBLE PRECISION,ALLOCATABLE,INTENT(IN) :: Array(:,:)
 INTEGER                                 :: iii,jjj

 PRINT*,SIZE(Array,1),SIZE(Array,2)
 DO iii=1,SIZE(Array,1)
 DO jjj=1,SIZE(Array,2)
    PRINT*,Array(iii,jjj)
 ENDDO
 ENDDO

 END SUBROUTINE
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!

1
请注意,可分配的虚拟参数实际上是Fortran 2003的一个功能(包括gfortran在内的许多编译器已经支持了几年)。 - IanH
3个回答

33
如果一个过程有一个作为可分配对象的虚拟参数,则在任何调用范围内都需要显式接口。(有许多事情需要显式接口,可分配的虚拟参数只是其中之一。)您可以通过在主程序中放置子例程的接口块来提供该显式接口。一种替代且更好的选择是将子例程放入模块中,然后在主程序中使用该模块-这样显式接口就会被自动创建。您提供一个链接到 eng-tips 网站的示例,其中包含 xwb 的帖子。请注意,仅当您要执行与其分配状态相关的操作时,虚拟参数具有可分配属性才有意义-查询其状态、重新分配它、取消分配等。

谢谢,这正是我的问题。我知道一些功能(不记得它们的名称了,但我认为它们是改变输入参数的那些功能)需要明确的接口,但我不知道分配也是一样的。是的,该代码是为调试我的真实代码而编写的。 - Nordico

9
请注意,您的可分配虚拟参数 array 声明为 intent(in),这意味着它的分配状态将与相关实际参数相同(并且在过程期间可能不会更改)。传递给子程序的实际参数可能未分配,因此即使使用显式接口也无法引用它,这是非法的。编译器不会知道这一点,在这种情况下,像 size 这样的查询行为是未定义的。
因此,在引用其内容之前,您首先必须使用 allocated(array) 检查 array 的分配状态。我还建议使用 lboundubound 在整个数组上实现循环,因为通常无法确定 array 的边界:
subroutine subtest(array)
  double precision, allocatable, intent(in) :: array(:,:)
  integer                                   :: iii, jjj

  if(allocated(array)) then
    print*, size(array, 1), size(array, 2)
    do iii = lbound(array, 1), ubound(array, 1)
      do jjj = lbound(array, 2), ubound(array, 2)
        print*, array(iii,jjj)
      enddo
    enddo
  endif  
end subroutine

注意:我将此作为一个新答案添加,因为我还不能在其他人的答案下评论。这是对IanH答案的一个补充,我认为这个细微差别也被xwb在eng-tips.com的帖子中忽略了。我不想用一个大的编辑来打扰你们,但你可以自由地将其合并为一个答案。 - sigma
ubound似乎具有与Size相同的效果; 有什么区别?而lbound的使用是为了防止数组从高于1的索引开始?这种情况可能发生吗? - Nordico
3
size 函数可以返回一个数组的总元素个数(没有维度参数)或沿着某个维度的元素个数(有维度参数)。你可以为边界为 (-2:0, -2:0) 的数组分配空间,但每个维度上大小仍然是 3,但是 array(1:3, 1:3) 没有定义。这与具有假设形状的不可分配虚拟数组不同,后者如果未指定,则确实假定下限为 1。 - sigma

3

这是一个使用可分配虚拟参数与模块的简单示例。

module arrayMod   
  real,dimension(:,:),allocatable :: theArray    
end module arrayMod

program test
   use arrayMod
   implicit none

   interface
      subroutine arraySub
      end subroutine arraySub
   end interface

   write(*,*) allocated(theArray)
   call arraySub
   write(*,*) allocated(theArray) 
end program test

subroutine arraySub
   use arrayMod

   write(*,*) 'Inside arraySub()'
   allocate(theArray(3,2))
end subroutine arraySub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接