假设我正在编写一个执行模拟的一个时间步长的Fortran子例程,因此将重复调用。要完成它的工作,它需要许多临时数组,这些数组在子程序之外没有意义或有用。用户可能希望在程序执行期间执行多个不同大小的模拟,可能同时进行,但是对于特定模拟的所有时间步长,数组的尺寸将是相同的。
我该如何处理这些临时数组?我能想到的每一种方式都有一些问题。
如果我要在子程序中使用本地数组,则必须将它们放在堆栈上,这将限制它们的大小,或者它们必须在堆上分配,这将浪费时间,因为每个步骤都会分配和释放数组。
或者,调用者可以分配数组。但是,如果调用者将每个数组作为单独的参数传递给子例程,则调用者必须知道有多少个数组以及每个数组有多大。此外,如果以某种方式修改子例程以更改数组的数量,则必须修改对子例程的每次调用。
我看到的一种技术是子程序接受单个大型数组并将其视为连接在一起的几个临时数组。但是,这似乎有风险,因为算术错误可能导致很难找到的错误。
最后,我可以将所有临时数组放入派生类型,并编写一个单独的子例程来分配所有数组和另一个子例程来释放它们。这样,只有少数子程序必须知道临时数组。但是,我的理解是,至少在最近版本的Fortran之前,派生类型只能包含指向数组的指针。这会带来与使用指针相关的所有缺点(可能存在错误,别名等)。
有没有办法避免这些问题呢? (或者这些问题中的任何一个都不像我想的那么重要吗?)
答案 0 :(得分:1)
您可以在阵列上使用save属性。
subroutine step(x, t, do_allocattion)
double precision, intent(in) :: x(:)
double precision, intent(in) :: t
logical, intent(in), optional :: do_allocation
integer :: n
double precision, allocatable, save :: work1(:), work2(:)
n = size(x)
if (present(do_allocation)) then
if (do_allocation) then
allocate(work1(n))
allocate(work2(n))
end if
end if
! do work on x
end subroutine
编辑:替代解决方案,因为我已经混合了指针数组。
subroutine step(x, t)
double precision, intent(in) :: x(:)
double precision, intent(in) :: t
integer :: n
double precision, allocatable, save :: work1(:), work2(:)
n = size(x)
if (.not. allocated(work1)) then
allocate(work1(n))
end if
if (.not. allocated(work2)) then
allocate(work2(n))
end if
! do work on x
end subroutine
编辑:警告:您不能简单地检查"分配"因为当程序启动并且子程序第一次执行时它将是未定义的。您可以添加另一个可选参数来解除分配。 - >这是指针数组的情况。