问题
I have a few array variables in a module that are dynamic, and later allocated in one of two subroutines outside of the module. However, in one subroutine I want the array to be 1D, in the other subroutine I want it to be 2D.
In principle I would want something like this in the module, but I don't believe this is possible in the declaration area?:
if (option1) then
real (kind=8), allocatable :: arr1(:)
else
real (kind=8), allocatable :: arr1(:,:)
endif
Is there a way in the allocatable declarations to have the dimension be dynamic?
Edit1: The reason I'm doing this is I'm adding a new subroutine to an existing codebase, but I want to be backwards compatible. arr1 is only used by the two separate subroutines, the main program doesn't use it at all. Here is some more complete code showing the idea:
program myprog
use inputs
call read_inputs
if (option1) then
call do1
else
call do2
endif
contains
subroutine read_inputs
use inputs
use mymod
!!!read from file .logical. option1, integers N1, N2
!allocate arrays
if (option1) then
else
endif
end subroutine read_inputs
subroutine do1
use inputs
use mymod
allocate(arr1(N1))
!do stuff with arr1
end subroutine do1
subroutine do2
use inputs
use mymod
allocate(arr1(N1,N2))
!do stuff with arr1
end subroutine do2
end program
module inputs
logical :: option1
integer :: N1, N2
end module inputs
module mymod
use inputs
!!!!can I do something here to make the rank of arr1 dynamic? I don't think the following will work
if (option1)
real (kind=8), allocatable :: arr1(:)
else
real (kind=8), allocatable :: arr1(:,:)
endif
end module mymod
I may just have two separate variable in mymod, arr1 and arr1_new. I was just hoping to avoid that.
回答1:
I think the 'olden' ways to do something like this is to pass the first element instead of the whole array and the size of the array separately:
program dyn_array
implicit none
integer :: a(2, 3)
integer :: i
call set1d(a(1,1), size(a))
do i = 1, 3
write(*, '(2I4)') a(:,i)
end do
contains
subroutine set1d(array, s)
implicit none
integer, intent(in) :: s
integer, intent(out) :: array(s)
integer :: i
do i = 1, s
array(i) = 3 * i
end do
end subroutine set1d
end program dyn_array
回答2:
"Can you pass a 2D array into a subroutine that expects a 1D array and get the right size?"
You can use reshape, but if you code is relying on the compiler to help then a 2D into a 1D is dicey. You could use RESHAPE before and after... Or you can have 2 routines, which we can call set1d and set2d. Then in the module you can have it choose what one you want to use. You could have integer(s), float(s), complex(s), byte.
You would CALL Array$Set(Array,s)
MODULE Stuff
PUBLIC :: Array$Set
PRIVATE
INTERFACE Array$Set
MODULE PROCEDURE Set1d_Float, Set1D_Double, set2D_Float, Set2D_Double
END INTERFACE Array$Set
CONTAINS
SUBROUTINE Set1D_Float(Array,S)...
!$DIR ATRIBUTES ASUUME_ALIGND:64 :: Array
REAL, DIMENSION(:,:), CONTIGUOUS, INTENT(INOUT) :: Array
REAL, DIMENSION(:,:), INTENT(IN ) :: S
REAL, DIMENSION(2) :: Shapez
...
Shapez = Shape(Array)
DO I = 1, Shapez(1)
DO J = 1, Shapez(2)
...
END SUBROUTINE Set1D_Float
END MODULE Stuff
For your example: if (option1) then real (kind=8), allocatable :: arr1(:) else real (kind=8), allocatable :: arr1(:,:) endif
I would suggest this:
!DIR ATTRIBUTES ALIGN:64 :: Arr1
REAL, DIMENSION(:), ALLOCATABLE :: Arr1
...
if (option1) then
ALLOCATE(Arr1(<#>))
else
ALLOCATE(Arr1(<#>*<#2>))
RESHAPE(Arr1, SHAPE=/(#1,#2)) !Check the syntax
endif
CALL Array$Set(Arr1,s) !It'll find the right one...
!... at the bottom ...
IF(ALLOCATED(Arr1)) DEALLOCATE(Arr1)
END PROGRAM
来源:https://stackoverflow.com/questions/38387460/dynamic-array-rank