如何在 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
让我先说一下,我对 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