如何在 Fortran 子程序中使用可分配数组?

How to use allocatable arrays in Fortran subroutines?

让我先说一下,我对 Fortran 很陌生,但熟悉 Python。然而,我的研究项目要求我使用一些预先编写的 Fortran 代码,目前无法在我的电脑上编译。我想知道为什么。

我尝试编译的实际代码很长,可能不是很有启发性,但我想我已经设法想出了一个我认为问题所在的最小示例。假设我有一个非常简单的模块和子程序,如下所示,

module arraycheck
    implicit none
    real*8, allocatable, dimension(:) :: x
    contains
    subroutine fillx
        real*8, allocatable, dimension(:) :: x
        allocate(x(5))
        x(1) = 1
        x(2) = 2
        x(3) = 3
        x(4) = 4
        x(5) = 5
        print*, x
    end subroutine fillx
end module arraycheck

我希望简单地创建一个数组 x,当调用子例程 fillx 时,它会用整数 1 到 5 填充数组。我的实际源代码包含概念上与此类似的内容。现在我还有一个main程序如下,

program main
use arraycheck
print*, x
call fillx
print*,x
end

我的想法是,在第一个 print 语句中,变量 x 仍未分配,因此 print return 什么都没有,然后在第二个print语句x已经填充,所以应该return填充数组。

然而,在两个 print 语句中都没有 returned。现在在我的原始源代码中发生了类似的事情,这导致运行时抛出一个错误,即未分配的数组作为实际参数传递到某处,而实际参数应该已经分配。看起来和我这里的小例子完全一样。

所以我的问题是,我在这里的示例中观察到的行为是否符合预期?如果是,我如何更改代码以使其按照我希望的方式工作?如果我知道这一点,我可能会更好地理解为什么实际来源不起作用。

为了以防万一,我在 ubuntu.

上使用 gfortran

谢谢!

你们的 x 太不一样了。他们没有任何共同点。一个是模块数组,一个是子例程本地数组。当您在子程序中分配本地数组时,它不会对模块中的其他数组做任何事情。

此外,您不能打印未分配的数组。那不符合标准(未定义的行为)。任何事情都可能发生。在诊断问题时,您绝对应该启用所有编译器检查。编译器应该通过这些检查来抱怨您的代码。

删除局部数组声明并避免引用未分配的变量。模块过程可以通过主机关联访问模块变量。

module arraycheck
    implicit none
    real*8, allocatable, dimension(:) :: x

  contains

    subroutine fillx

        allocate(x(5))
        x(1) = 1
        x(2) = 2
        x(3) = 3
        x(4) = 4
        x(5) = 5
        print*, x
    end subroutine fillx
end module arraycheck


program main
  use arraycheck

  call fillx
  print*,x
end

此外,real*8 不是标准的 Fortran,它是一个非标准的扩展。 Fortran 90 及更高版本改用种类系统。

以下是一些可能有用的其他内容 - 以大写形式显示。

module arraycheck
    USE ISO_C_BINDING, ONLY : C_Int32_t, C_DOUBLE
    implicit none
    PRIVATE

    real(KIND=C_DOUBLE), allocatable, dimension(:), PUBLIC :: x

    PUBLIC Creation_X, Destruction_X, FillX

  contains

    subroutine Creation_X(n)
    USE ISO_C_BINDING, ONLY : C_Int32_t
    IMPLICIT NONE
    INTEGER(KIND=C_Int32_t), INTENT(IN) :: n

    allocate(x(n))

    RETURN
    end subroutine Creation_X

    subroutine Destruction_X
    USE ISO_C_BINDING, ONLY : C_Int32_t
    IMPLICIT NONE

    IF(ALLOCATED(X)) DEALLOCATE(X)

    RETURN
    end subroutine Destruction_X

    subroutine fillx
    USE ISO_C_BINDING, ONLY : C_Int32_t
    IMPLICIT NONE
    INTEGER(KIND=C_Int32_t) :: N

    DO I= 1, SIZE(x)
      x(I) = I
    ENDDO

    RETURN
    end subroutine fillx

end module arraycheck


program main
  use arraycheck

  CALL Creation_X(5)
  call fillx
  print*,x
  CALL Destruction_X

end