我有一个问题与几年前在Intel Developer Forum关于数组就地重塑的问题有关。
简而言之,答案是可以分配某个等级的数组,并创建一个指向相同内存位置(即就地)的指针,但具有不同的等级,例如:
use, intrinsic :: ISO_C_BINDING
integer, allocatable, target :: rank1_array(:)
integer, pointer :: rank3_array(:,:,:)
integer :: i
! Allocate rank1_array
allocate(rank1_array(24))
! Created rank3_pointer to rank1_array
call C_F_POINTER (C_LOC(rank1_array), rank3_array, [3,2,4])
! Now rank3_array is the same data as rank1_array, but a 3-dimension array with bounds (3,2,4)
我现在的问题是,如果我deallocate
原始数组rank1_array
,为什么指针rank3_array
仍然关联,并且可以毫无问题地使用(貌似)。因此,如果我从上面附加代码段:
! initialise the allocated array
rank1_array = [(i, i=1,24)]
! then deallocate it
deallocate(rank1_array)
! now do stuff with the pointer
print *, associated(rank3_array)
rank3_array(2,2,1) = 99
print *, rank3_array
编译并运行此程序会为我提供输出
gfortran -Wall my_reshape.f90 -o my_reshape
./my_reshape
T
1 2 3 4 99 6 7 ... 23 24
如果rank1_array
的内存已被释放,为什么rank3_array
仍然有效,除非它是原件的副本?最初的重塑是否就位?如果有人能向我解释这种行为,我将非常感激。
我正在使用感兴趣的gfortran 6.1.0。
修改/更新
正如@francescalus所接受的答案所指出的,这里真正的问题是我(错误!)如何处理指针,而不是特别是C_F_POINTER
的就地重塑。我看到的奇怪行为只是由于我编写的不合规的fortran代码导致的未定义行为。基于@francescalus的回答和评论,我做了更多的在线阅读,并认为给一个Fortran Reference Manual的相关部分的链接可能是有用的,它可以非常清楚地解释如何处理指针和可分配的数组。
答案 0 :(得分:4)
使用c_f_pointer
代替"正常"指针赋值与问题无关,也不会改变形状。
在调用c_f_pointer
之后,指针rank3_array
是与目标rank1_array
关联的指针。没有副本。
在声明
中取消分配rank1_array
时
deallocate(rank1_array)
这会对以rank1_array
为目标的指针产生影响。特别是,rank3_array
的指针关联状态变为未定义。 (每当指针的目标被释放,除非通过指针,指针的关联状态变为未定义。)
指定未定义关联状态的指针
print *, associated(rank3_array)
是不允许的。此时程序不是符合Fortran标准的程序(并且编译器无法检测到该程序),如果需要,处理器可以在此处打印.TRUE.
。
同样,
rank3_array(2,2,1) = 99
print *, rank3_array
rank3_array
本身未定义,也不允许这些引用。同样,编译器可以使用任何效果。
现在,就像在another answer中关于类似主题的那样:只是因为rank1_array
已被解除分配,并不意味着内存被清除。可能发生的一切是第一个数组的某个数组描述符的状态发生了变化。编译器的责任不是对所有相关的指针/描述符执行相同的操作。 (所以指针的描述符可能仍然会说"关联"。)