我需要在Fortran中使用可变大小的数组。在C ++中我会使用vector。所以我有一个像
这样的功能integer function append(n, array, value)
integer, pointer, dimension(:) :: array
integer, pointer, dimension(:) :: tmp_arr
integer n
if (size(array) .eq. n) then
allocate(tmp_arr(2*size(array)))
tmp_arr(1:size(array)) = array
deallocate(array)
array => tmp_arr
end if
n = n + 1
array(n) = value
append = n
end function
如果按照
的方式使用它,它可以正常工作integer pos, val
pos = append(n, array, val)
但是,如果我想以这种方式使用它
integer i,j,n ! i,j<n
array(i) = append(n, array, array(j))
与gfortran这不起作用。它编译,但段错误。问题似乎是gfortran从数组(i)和数组(j)中产生地址,将后者发送到函数append,然后当访问数组(j)的地址并且写入数组(i)时,地址空间已被解除分配。
我想要的是将数组(j)的值放在堆栈(而不是地址)上,然后在函数中使用,在函数完成后,查找数组(i)的uptodate地址,函数的结果保存到它。
我很确定gcc会按照我想要的方式来做,为什么gfortran如此吝啬?
Fortran中是否有任何方法可以构建一个健壮的(意思是数组(j)= ...示例有效) 函数或数据类型有一个像行为一样的c ++ stl向量吗?
结论:
我最终引入了临时变量
integer tmp_val
tmp_val = value
...
array(n) = tmp_val
所以至少可以将该方法称为
pos = append(n, array, array(j))
array(i) = pos
并希望该项目的其他/未来开发人员不会试图'优化'这两行,以消除'pos'的必要性。
感谢您的回答和评论。
答案 0 :(得分:12)
IRO-bot的答案是Fortran 90的正确方法。如果你能限制自己支持Fortran 2003 MOVE_ALLOC内在的编译器(自4.2版本以来包含在gfortran中),你可以避免副本。也就是说,将数组的大小增加2倍可以写为
allocate(tmp_arr(2*size(array)))
tmp_arr(1:size(array)) = array
deallocate(array)
move_alloc(tmp_arr, array)
! tmp_arr is now deallocated
答案 1 :(得分:9)
好的,问题是您无法释放并重新分配要为其分配函数值的数组。你对问题的原因是正确的(参考传递的参数而不是C中的值)。由于您在函数体内释放数组,因此对该数组的赋值变为无效,从而导致段错误。这不是一个gfortran问题,尝试使用ifort和pgf90,所有这些都报告了同样的问题。这对我有用:
PROGRAM dynamic_size
INTEGER,DIMENSION(:),ALLOCATABLE :: array
ALLOCATE(array(10))
array=(/1,2,5,7,4,3,6,5,6,7/)
WRITE(*,*)SIZE(array)
CALL resize_array
WRITE(*,*)size(array)
CONTAINS
SUBROUTINE resize_array
INTEGER,DIMENSION(:),ALLOCATABLE :: tmp_arr
ALLOCATE(tmp_arr(2*SIZE(array)))
tmp_arr(1:SIZE(array))=array
DEALLOCATE(array)
ALLOCATE(array(size(tmp_arr)))
array=tmp_arr
ENDSUBROUTINE resize_array
ENDPROGRAM dynamic_size
答案 2 :(得分:2)
非常感谢janneb。您的评论非常有用。
我所做的只有一些改变是省略 deallocate(array)
。在我的代码中没有任何错误省略这一行。
如果您需要将其置于循环中并且在循环之前未分配array
,则此更改特别有用。我的具体情况如下(看看我没有在循环之前或循环中分配x_all
):
begin program test
integer,allocatable::x_all(:),tmp_arr(:)
integer,allocatable::x_tmp(:)
integer::N
allocate(x_tmp(2*N))
(...)
i=1
do while(logical test)
...
x_tmp(i)=some calculus
i=i+1
...
end do
i=i-1
allocate( tmp_arr( 1:(i+size(x_all) ) ) )
tmp_arr(1:size(x_all))=x_all
tmp_arr(size(x_all)+1:)=xtemp
call MOVE_ALLOC(tmp_arr,x_all)
...
end program