指向由地图定义的子阵列的指针

时间:2014-06-19 15:31:44

标签: arrays pointers fortran

我想定义一个指向子数组的指针。对于一个简单的范围,这可以通过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

编辑: 仅仅为了记录,我现在通过使用派生类型数组(包括指针)和稍微更改调用子例程来解决问题。

1 个答案:

答案 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分配一个向量下标。这解决了将pa地图直接关联的问题。此代码段假定根据示例代码声明和初始化变量。这表明您可以将数组的向量下标分配给指针,但只能指定已关联的指针,而不是在关联期间。


如您对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"知道"大约aa中的元素地图可以在调用者中计算。而不是将{=>p关联为a的地图(无法完成),pa相关联,并且地图与它

此代码生成输出:

% ./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