Arrays 指向由映射定义的子数组的指针
我想定义一个指向子数组的指针。对于一个简单的范围,这可以通过Arrays 指向由映射定义的子数组的指针,arrays,pointers,fortran,Arrays,Pointers,Fortran,我想定义一个指向子数组的指针。对于一个简单的范围,这可以通过pointer=>array(i:j)轻松实现,但对于k=[k1,k2,k3]这样的映射,我不知道如何实现这一点。如果我要定义另一个数组,我可以使用一个循环,比如array2=[(array1(k(j)),j=1,size(k,1))]。但不可能以类似的方式分配指针(pointer=>[(array1(k(j)),j=1,size(k,1))]),因为表达式的r.h.s.似乎定义了另一个变量,而该变量甚至没有target属性。对于简单的
pointer=>array(i:j)
轻松实现,但对于k=[k1,k2,k3]
这样的映射,我不知道如何实现这一点。如果我要定义另一个数组,我可以使用一个循环,比如array2=[(array1(k(j)),j=1,size(k,1))]
。但不可能以类似的方式分配指针(pointer=>[(array1(k(j)),j=1,size(k,1))]
),因为表达式的r.h.s.似乎定义了另一个变量,而该变量甚至没有target属性。对于简单的任务,一个技巧是首先指定一个指向总数组的指针,以使用读出上的映射。但就我而言,这似乎是不可能的
我将附上一些例子:第一个例子展示了我上面描述的内容。第二个是一个更复杂的例子,这个技巧不再有效了。此外,还需要一张二维地图
最简单的例子:
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
编辑:
为了记录在案,我现在通过使用包括指针在内的派生类型数组并稍微更改调用子例程解决了这个问题。指针关联(例如
pointer1=>array1(vector_下标)
。Fortran 2008标准第7.2.2节不允许这样做:
R733指针分配stmt是数据指针对象[(边界规范列表)]=>数据目标
还有两种其他形式,但它们与您的使用不匹配,也不会改变结果。进一步阅读:
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
这将产生(包装在示例程序中):
这将p
分配为适当的大小,然后从a
分配一个向量下标。这绕过了将p
与a
映射直接关联的问题。此代码段假定变量是根据示例代码声明和初始化的。这表明可以分配一个向量subsc指向指针的数组,但仅指向已关联的指针,而不是在关联期间
正如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
您也可以通过添加步幅来关联指针,例如
p=>a(4:8:2)
,然后p
将指向数组a
的8
部分,步幅为2
。当然,你的地图必须有规律地步幅。地图是任意的,在输入时定义的。谢谢你的回答。但是p
只是一个规则数组,而不是指针,因此不是指针“知道”它的目标。@PeMa这是真的。除非你有一个均匀的步幅并且做p=>a(1:2:10)
你将无法用任意的地图完成你想要的。+1,但是对于答案的第二部分(没有得到第一部分与之相关的东西)。对于任意贴图,只需像您已经在做的那样使用索引数组,然后您可以将其与数据一起传递以进行打印,或者创建一个类似于此答案的副本(尽管我建议不要使用指针)@steabert第一部分只是解释为什么他不能使用映射将数组中的任意元素分配给指针。我喜欢包括标准的相关部分,而不是说“你不能这样做,因为它不在标准中。”“@casey:看来我只需要重读问题的第一部分。OP说你不能做array2=[(array1(k(j)),j=1,size(k,1))]
有一个指针,但这是不正确的,只要指针是关联的,你就完全可以做到。但现在我明白了,他是说你不能做array2=>…
这就是你对他的问题的理解。所以,在我看来,答案很奇怪,因为它证实了他所说的。你答案中的第一句应该是be:你不能做array2=>…
,因为在我看来“this”似乎指的是array2=…
。我希望这是有意义的?:)
% ./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