我想定义一个指向子数组的指针。对于一个简单的范围,这可以通过pointer => array(i:j)
轻松完成,但我无法弄清楚如何为k=[k1,k2,k3]
这样的地图执行此操作。如果我要定义另一个数组,我可以使用像array2=[(array1(k(j)),j=1,size(k,1))]
这样的循环。但是由于r.h.s.不可能以类似的方式(pointer => [(array1(k(j)),j=1,size(k,1))]
)分配指针。表达式似乎定义了另一个变量,然后甚至没有目标属性。对于简单的任务,围绕这个的一个技巧是首先分配一个指向总数组的指针,以便在读数上使用地图。但就我而言,这似乎是不可能的。
我将附上示例:第一个显示我上面描述的内容。第二个是一个更复杂的例子,其中诀窍不再起作用。此外,还需要二维地图。
最小例子:
program test
integer, parameter :: n=10,n_k=3
real,target :: a(1:n)
real :: b(1:n_k)
integer :: k(1:n_k)
integer :: j
real,pointer :: p(:)
! fill array a and define map k:
a=[(real(j),j=1,n)]
k=[((j+1)*2,j=1,n_k)]
! can be used to print the arrays:
!write(*,*) a
!write(*,*) k
! can be used to write only the part of a defined by k:
!write(*,*) (a(k(j)),j=1,n_k)
! this an similar things didn't work:
!p(1:n_k) => [(a(k(j)),j=1,n_k)]
! works, but not generally:
p => a
write(*,*) (p(k(j)),j=1,n_k)
! works, only for arrays:
b=(/(a(k(j)),j=1,n_k)/)
write(*,*) b
end program
更复杂(但也有点微不足道)的例子,显示(希望)我真正拥有的问题。为了便于理解,一些解释会引导它。有很多写命令可以打印数组。我很欣赏代码的数量,但我真的不知道如何制作一个更简短易懂的工作示例:
module mod1
type base
real :: a
end type
type,extends(base) :: type1
end type
type,extends(base) :: type2
type(type1),allocatable :: b(:)
end type
type(type2),allocatable,target :: c(:)
contains
subroutine printer(z)
class(*),pointer,dimension(:) :: z
integer :: j,a_z,n_z
character(len=40) :: f,ff='(F10.2,1x))',form_z
! define format for printing:
a_z=lbound(z,1)
n_z=ubound(z,1)
write(f,'(I0)') (n_z-a_z+1)
form_z="("//trim(adjustl(f))//ff
! writing:
select type(z)
class is (base)
write(*,form_z) (z(j)%a,j=a_z,n_z)
end select
end subroutine
end module
program test
use mod1
integer,parameter :: n_b=8,n_c=6,n_js=3,n_ls=2
integer :: js(1:n_js),ls(1:n_ls)
integer :: j,l
class(*),pointer :: p(:)
character(len=40) :: f,ff='(F10.2,1x))',form_c,form_b
! define format for printing:
write(f,'(I0)') n_b
form_b="("//trim(adjustl(f))//ff
write(f,'(I0)') n_c
form_c="("//trim(adjustl(f))//ff
! creating and filling the arrays:
allocate(c(n_c))
c%a=[(2d0*real(j),j=1,n_c)]
do j=1,n_c
allocate(c(j)%b(n_b))
c(j)%b%a=[(real(l)*1d1**(j-1),l=1,n_b)]
end do
! write arrays to compare later:
write(*,form_c) c%a
write(*,*)
write(*,form_b) (c(j)%b%a,j=1,n_c)
write(*,*)
! denfining two maps (size and entries will be input in the final program):
js=[1,4,6]
ls=[2,7]
! using the maps to print only the desired entries:
write(*,*) (c(js(j))%a,j=1,n_js)
write(*,*)
write(*,*) ((c(js(j))%b(ls(l))%a,j=1,n_js),l=1,n_ls)
write(*,*)
! !!! here I want to use the maps as well, but so far I only know how to use ranges:
p => c(1:4)
call printer(p)
write(*,*)
p => c(2)%b(3:6)
call printer(p)
write(*,*)
end program
编辑: 仅仅为了记录,我现在通过使用派生类型数组(包括指针)和稍微更改调用子例程来解决问题。
答案 0 :(得分:1)
您无法通过指针关联(例如pointer1 => array1(vector_subscript)
执行此操作。禁止此操作的Fortran 2008标准的第7.2.2.2节是:
R733 pointer-assignment-stmt 数据指针对象 [( bounds-spec-list )] => 数据对象
还有另外两种形式,但它们与您的使用不符,也不会改变结果。进一步阅读:
R737 数据目标 变量
C724(R737)变量应具有TARGET或POINTER属性,并且不应是带有向量下标的数组部分。
这就是为什么你不能执行你正在尝试的指针关联。但是,您可以使用指针分配来解决此问题。看到这段代码:
n_k = 3
k = [((j+1)*2,j=1,n_k)] ! a vector subscript
p => a(k) ! NOT OK. Violates C724
allocate(p(n_k)) ! Associate your pointer this way
p = a(k) ! This is OK.
write(*,*) p
哪个收益率(包含在您的示例程序中):
% ./ptrtest
4.00000000 6.00000000 8.00000000
这会将p
分配为适当的大小,然后从a
分配一个向量下标。这解决了将p
与a
地图直接关联的问题。此代码段假定根据示例代码声明和初始化变量。这表明您可以将数组的向量下标分配给指针,但只能指定已关联的指针,而不是在关联期间。
如您对Q的评论所述,如果您有一个常规步幅,您可以直接进行指针关联。对于您的第一个测试用例,这将是等效的并且有效:
p => a(4:2:8) ! Allocation to a strided array is allowed
但是,如果你有一个不规则的向量下标,那么这个答案中的方法将是你需要用来完成指针关联的方法。
您可以使用的另一种解决方法是将指针和地图传递给过程。请考虑以下代码:
program test
implicit none
integer, parameter :: nx = 10, nx_m = 3
integer,dimension(nx_m) :: x_map
integer :: i
real, dimension(nx),target :: a
real, dimension(:), pointer :: p
! initialize array
a = [(real(i*2),i=1,10)]
write (*,'(10(f5.1 x))') a
!define a map
x_map = [1, 9, 4]
! associate pointer
p => a
call print_map(p, x_map)
contains
subroutine print_map(apointer, map)
implicit none
real, dimension(:), pointer :: apointer
integer, dimension(:) :: map
write (*,*) apointer(map)
end subroutine print_map
end program test
在这种情况下,p
"知道"大约a
,a
中的元素地图可以在调用者中计算。而不是将{=>
)p
关联为a
的地图(无法完成),p
与a
相关联,并且地图与它
此代码生成输出:
% ./ptrtest3
2.0 4.0 6.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0
2.00000000 18.0000000 8.00000000