Pointers 指向第0个索引的指针有问题
对于上面的代码,我得到以下输出:Pointers 指向第0个索引的指针有问题,pointers,fortran,Pointers,Fortran,对于上面的代码,我得到以下输出: module shared !derived type target here integer, parameter :: nblock = 2 integer, parameter :: xdim = 2 TYPE block_info INTEGER :: il=10,jl=20,kl=30 REAL, ALLOCATABLE :: x(
module shared
!derived type target here
integer, parameter :: nblock = 2
integer, parameter :: xdim = 2
TYPE block_info
INTEGER :: il=10,jl=20,kl=30
REAL, ALLOCATABLE :: x(:)
END TYPE block_info
TYPE(block_info), TARGET :: block(nblock)
end module shared
module point_to
!point to subroutine here
use shared
REAL, POINTER :: x(:)
integer :: il,jl,kl
contains
subroutine set_current(n)
nullify(x)
il = block(n)%il
jl = block(n)%jl
kl = block(n)%kl
x => block(n)%x(0:xdim)
end subroutine set_current
end module point_to
program main
use shared
use point_to
!Iam allocating derived type target and initialize
do i = 1, nblock
allocate(block(i)%x(0:xdim))
do j = 0, xdim
block(i)%x(j) = dble(i)*dble(j)
enddo
enddo
!Iam pointing using set_current subroutine and print
do i = 1, nblock
call set_current(i)
do j = 0, xdim
write(*,*) "i= ",i, "j= ",j, block(i)%x(j), x(j)
enddo
enddo
end program main
我已经应用了从1开始的x向量到xdim,没有得到任何错误。当第一个索引被选择为0时,问题就开始了。在上述输出中,最后两个值必须相等。那么问题出在哪里呢?首先,当您遇到问题时,使用编译器的所有调试功能,仅仅查看代码是不够的 例如:
i= 1 j= 0 0.00000000 0.00000000
i= 1 j= 1 1.00000000 0.00000000
i= 1 j= 2 2.00000000 1.00000000
i= 2 j= 0 0.00000000 0.00000000
i= 2 j= 1 2.00000000 0.00000000
i= 2 j= 2 4.00000000 2.00000000
编译器直接告诉您错误在哪里。数组x从元素1开始,您试图访问元素0,因此超出了边界。它发生在第52行,这是
> gfortran -g -fbacktrace -fcheck=all -Wall zeroptr.f90
zeroptr.f90:44.24:
block(i)%x(j) = dble(i)*dble(j)
1
Warning: Possible change of value in conversion from REAL(8) to REAL(4) at (1)
> ./a.out
At line 52 of file zeroptr.f90
Fortran runtime error: Index '0' of dimension 1 of array 'x' below lower bound of 1
Error termination. Backtrace:
#0 0x7fa2d4af3607 in ???
#1 0x7fa2d4af4115 in ???
#2 0x7fa2d4af44ba in ???
#3 0x4014dc in MAIN__
at /home/lada/f/testy/stackoverflow/zeroptr.f90:52
#4 0x401640 in main
at /home/lada/f/testy/stackoverflow/zeroptr.f90:37
为什么会这样?因为
write(*,*) "i= ",i, "j= ",j, block(i)%x(j), x(j)
使x指向块n%x0:xdim,但x将从1开始
在Fortran 2003中,可以进行以下指针重新映射:
x => block(n)%x(0:xdim)
x => block(n)%x ! x has lower bound 0
x => block(n)%x(0:xdim) ! x has lower bound 1
它的工作原理与预期一样,但最好使用blockn%x。解释了问题的根源。然而,这个细节在这里的问题中经常出现,所以值得强调几点
数组部分,即使它匹配数组的所有元素,也与整个数组不同。blockn%x是一个完整的数组;blockn%x0:xdim是数组部分,即使该数组组件的边界为0和xdim
为什么这种差异很重要?让我们看看指针赋值的规则。指针赋值语句
x(0:xdim) => block(n)%x(0:xdim)
是数据指针赋值的一种。正如另一个答案所提到的,有一件事叫做边界重新映射。也可以给出边界规范
这两种情况在这里都没有发生,稍后我将进一步讨论,因此我们将看到Fortran 2008,7.2.2.3
如果出现边界规范列表,则指定下限;否则,每个维度的下限是应用于指针目标对应维度的内在函数LBOUND 13.7.90的结果
LBOUND的结果是,整个数组/数组部分的区别非常重要,Fortran 2008,13.7.90:
如果数组是整个数组。。。LBOUND ARRAY,DIM的值等于数组的下标DIM的下限。否则,结果值为1
这意味着在这种情况下,LBOUNDblockn%x的结果为0,但LBOUNDblockn%x0:xdim的结果始终为1
这意味着
x => block(n)%x(0:xdim)
现在,Vladimir F提到边界重新映射:
x => block(n)%x(0:xdim)
x => block(n)%x ! x has lower bound 0
x => block(n)%x(0:xdim) ! x has lower bound 1
这表示x具有所请求的上限和下限。这是很合理的,但也有几个警告:
一个人必须小心地重复界限;左侧大小的元素数必须最多与右侧大小的元素数相同,如果较少,则为较小的数组。
右侧必须是秩1或简单相邻。
所有这些条件都成立,但这使得推广需要谨慎
最后,还有一个边界规范:
x(0:xdim) => block(n)%x(0:xdim)
这仍然指定下限,但指针和目标始终具有相同的大小,并且对秩/邻接性没有限制
总结:对于这个问题的简单情况,使用x=>blockn%x 你用了标签。Fortran问题始终使用tag。您可以添加另一个标记来区分版本。但是,您的代码不是Fortran 90。原始Fortran 95甚至不允许将可分配组件分配给派生类型,这是Fortran 2003的一项功能。所以您的代码是Fortran 2003。设置x0:xdim=>blockn%x0:xdim解决了我的问题。非常感谢。顺便说一下,我正在使用GNU Fortran Ubuntu 4.8.4-2ubuntu1~14.04.3 4.8.4版本,但是调试选项没有如您所说的那样工作,没有给出错误。这是如何发生的?再次感谢你。我的版本是4.8.5,所以它应该像我所展示的那样工作。运行为调试而编译的代码时会显示错误!这么好的解释谢谢你,先生,现在一切都清楚了