我是Fortran新手。我正在尝试编写一个子程序,它将从主程序中获取四个参数,然后向主程序输出一个涉及最初传入的四个参数的数组。这样做的好/聪明方法是什么? / p>
例如,在我的测试程序中,我在主程序中创建了四个实变量(a
,b
,c
和d
)。然后我将这些实变量传递给一个名为mysub
的子程序。我希望mysub
能够接收a
,b
,c
和d
,使用它们填充2 x 2阵列调用o
,然后将o
发送到主程序以显示(和可能的修改)。所以,我尝试了以下内容:
SUBROUTINE mysub(w,x,y,z)
IMPLICIT NONE
REAL, INTENT(IN) :: w, x, y, z
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o
ALLOCATE(o(2,2))
o(1,1)=w
o(1,2)=x
o(2,1)=y
o(2,2)=z
END SUBROUTINE mysub
END MODULE testsubs
PROGRAM test
USE testsubs
IMPLICIT NONE
REAL :: a=1.1, b=2.2, c=3.3, d=4.4
CALL mysub(a, b, c, d)
PRINT *, o(1,1), o(1,2)
PRINT *, o(2,1), o(2,2)
END PROGRAM test
但是,我收到以下错误:
test.f90:10.53:
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o
1
Error: Symbol at (1) is not a DUMMY variable
我将其解释为,编译器不知道o
是什么,因为o
不在子例程头中的参数列表中:SUBROUTINE mysub(w,x,y,z)
。所以我可能需要在该标题中包含o
。所以,我接下来尝试以下内容(我使用!...
表示更改或添加):
SUBROUTINE mysub(w,x,y,z,o) !...
IMPLICIT NONE
REAL, INTENT(IN) :: w, x, y, z
REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: o
ALLOCATE(o(2,2))
o(1,1)=w
o(1,2)=x
o(2,1)=y
o(2,2)=z
END SUBROUTINE mysub
END MODULE testsubs
PROGRAM test
USE testsubs
IMPLICIT NONE
REAL :: a=1.1, b=2.2, c=3.3, d=4.4
REAL, DIMENSION(:,:), ALLOCATABLE :: o !...
CALL mysub(a, b, c, d, o) !...
PRINT *, o(1,1), o(1,2)
PRINT *, o(2,1), o(2,2)
DEALLOCATE(o) !...
END PROGRAM test
这似乎工作正常,我得到了正确的输出:
1.1000000 2.2000000
3.3000000 4.4000001
但是,我的问题是,这是一个很好的方法吗?在这个工作示例中,我在主程序的子例程和中声明了数组o
两者。这似乎有点令人困惑,因为我认为这意味着我需要注意 子程序或主程序分配o
(但我认为,不是,以避免错误消息)。有没有更聪明的方法 - 从子程序发送数组到主程序?谢谢你的时间。
答案 0 :(得分:3)
你的解决方案,使“o”成为一个意图(out)论证就好了。如果没有“o”作为参数,则子程序中的变量“o”与主程序中的变量“o”之间没有关联,因此主程序中没有声明或分配。另一个解决方案(除了@ ja72提供的解决方案之外)将改变你的方法:使“o”成为子程序的一个intent(inout)参数并将其分配给主程序。可能的优点:分配和解除分配在代码中更加紧密,并且配对。可能的缺点:取决于程序逻辑和设计,子程序可能最熟悉数组维度。
P.S。如果在主程序中分配数组,并且实际上不在子例程中使用数组的可分配属性(即,您不分配或取消分配它),那么您不必使用allocatable属性声明它在子程序中 - 一个有用的简化。在这种情况下,“意图(外出)”可能是合适的。但是如果你在主程序中分配数组并希望将该状态传递给子程序,那么参数状态不能是“intent(out)”。 “intent(out)”在进入程序时自动解除参数。
答案 1 :(得分:1)
如果你想返回一个数组,你可以a)将它添加到INTENT(OUT)
的参数,就像你的例子#2一样,在sub中分配,或者b)创建一个函数并在外部分配数组:
FUNCTION myfun(w,x,y,z,n,m)
IMPLICIT NONE
INTEGER, INTENT(IN) :: n,m
REAL, DIMENSION(n,m) :: myfun
REAL, INTENT(IN) :: w,x,y,z
myfun(1,1)=w
myfun(1,2)=x
myfun(2,1)=y
myfun(2,2)=z
END FUNCTION
END MODULE testsubs
PROGRAM test
USE testsubs
IMPLICIT NONE
REAL :: a=1.1, b=2.2, c=3.3, d=4.4
REAL, DIMENSION(:,:), ALLOCATABLE :: o !...
ALLOCATE(o(2,2))
o = myfun(a,b,c,d,2,2)
PRINT *, o(1,1), o(1,2)
PRINT *, o(2,1), o(2,2)
DEALLOCATE(o) !...
END PROGRAM test
实际上我认为你的解决方案更清洁。
答案 2 :(得分:1)
从您的问题中不清楚您是否事先知道数组的大小,但如果您这样做,通常在同一个地方分配和释放数组通常是一个好习惯,或者更好的是让编译器在可能的情况下分配内存。
我该怎么做:
如果在编译时已知大小:
在主程序中声明您的数组,在子例程中使用intent(out)
。
如果仅在运行时知道大小:
在主程序中分配,在子程序中使用intent(out)
并在主程序中取消分配。
功能最适合小输出,因为需要复制输出。