在子程序之间调用

时间:2016-12-30 20:54:39

标签: fortran

我是Fortran编程的新手,我试图理解子程序之间的调用。所以我写了一个简单的程序来测试它

这是我的代码

program dummy

    real, allocatable, dimension(:)         :: zz,yy

    call test2(zz,yy)

    print *, zz, yy

contains

    subroutine test1(ar1,ar2,arsum)
        real, dimension(:)                  :: ar1,ar2
        real, allocatable, dimension(:)     :: arsum
        allocate(arsum(size(ar1)+size(ar2)))
        arsum(1:size(ar1)) = ar1
        arsum(size(ar1)+1:size(ar1)+size(ar2)) = ar2

    end subroutine test1

    subroutine test2(sg1,sg2)
        real, dimension(3)              :: g1,g3
        real, dimension(4)              :: g2,g4
        real, allocatable,dimension(:) :: sg1,sg2,dum
        g1 = 1.0
        g2 = 2.0
        g3 = 3.0
        g4 = 4.0
        call test1(g1,g3,dum)
        sg1 = 2*dum
        call test1(g2,g4,dum)
        sg2 = 3*dum
    end subroutine test2

end program dummy 

然而,这会引发以下错误

forrtl: severe (151): allocatable array is already allocated
Image              PC                Routine            Line        Source             
dummy.exe          0000000000409B1C  Unknown               Unknown  Unknown
dummy.exe          0000000000402E70  MAIN__                     26  dummy.f90
dummy.exe          0000000000402A2E  Unknown               Unknown  Unknown
libc-2.23.so       00002B3E716C7830  __libc_start_main     Unknown  Unknown
dummy.exe          0000000000402929  Unknown               Unknown  Unknown

test1子例程简单地连接任何两个给定的数组。 Test2子例程定义要连接的数组,并在输出上执行一些代数并将它们存储在新数组中。程序dummy只是打印新数组。

我在这里做错了什么?

1 个答案:

答案 0 :(得分:3)

让我们来看看这个程序的流程。这里涉及一些术语,但有希望通过其他文档探讨使用的内容。

主程序使用几个参数调用子例程test2。对于这里的问题,这些论点没有意义。相反,请查看本地(到子例程)变量dum

dum是一个可分配的数组。它在执行test2时开始,因为未分配。它是test1调用的第一个(实际)参数,后来是另一个test1调用的(实际)参数。那么,出了什么问题?

这里的论点意图至关重要。真的很关键。在继续这个答案之前,应该先阅读其他地方的意图。

所以,我们现在熟悉论证意图。

在输入子例程test1时,伪参数arsum具有与实际参数dum相同的分配状态。在test1执行期间,有一个allocate声明。

allocate语句只能尝试分配尚未分配的内容。这在第一次调用时没问题:未分配条目dum / arsum。在执行子例程arsum的过程中,这会影响test2 dum的分配状态。

现在已分配对test1 arsum的第二次调用,因为已分配实际参数dum。由于此原因,allocate语句失败,并显示错误消息。

那是问题所在;怎么修?我们需要确保未分配arsum。有两种显而易见的方法:

  • 测试arsum的分配状态并做出相应的回应(可能是deallocate);
  • dum
  • 的来电之间解除分配test1

但是可能有更合适的方式。请注意,dum仅在返回test2某些操作的值时才有用。回想一下意图:这是intent(out)表示的意思。

如果我们将子例程test1重写为

subroutine test1(ar1,ar2,arsum)
    real, dimension(:)                           :: ar1,ar2
    real, allocatable, dimension(:), intent(out) :: arsum
    allocate(arsum(size(ar1)+size(ar2)))
    arsum(1:size(ar1)) = ar1
    arsum(size(ar1)+1:size(ar1)+size(ar2)) = ar2
end subroutine test1

然后,由于intent(out),属性arsum / dum会在录入时自动解除分配。

最后(并且未显示),人们甚至可以考虑使用函数返回arsum甚至使用自动数组而不是可分配数组。或者,甚至Fortran 2003自动分配和数组构造函数:

subroutine test1(ar1,ar2,arsum)
    real, dimension(:)              :: ar1,ar2
    real, allocatable, dimension(:) :: arsum   ! Or with `intent(out)`
    arsum = [ar1,ar2]
end subroutine test1