Fortran 在函数中增加动态数组大小
我需要 Fortran 中的可变大小数组。在 C++ 中我会使用向量。所以我有一个这样的函数,
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 从 array(i) 和 array(j) 中获取地址,将后者发送到函数append,然后当访问 array(j) 的地址并写入 array(i) 的地址时,地址空间已被释放。
我想要的是,将 array(j) 的值放在堆栈上(而不是地址),然后在函数中使用,在函数完成后,查找 array(i) 的最新地址并得出结果该函数已保存到其中。
我很确定 gcc 会按照我想要的方式做,为什么 gfortran 如此卑鄙?
Fortran 有什么方法可以使一个健壮(意味着 array(j) = ... 示例有效) 函数或数据类型具有类似 C++ stl 向量的行为?
结论:
我最终引入了临时变量
integer tmp_val
tmp_val = value
...
array(n) = tmp_val
,因此至少可以调用该方法
pos = append(n, array, array(j))
array(i) = pos
,并希望项目中的其他/未来开发人员不会尝试“优化”这两行以消除“pos”的必要性。
感谢您的回答和评论。
I need a variable size array in Fortran. In C++ I would use vector. So I have a function like
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
that works fine if I use it the way
integer pos, val
pos = append(n, array, val)
However, if I would like to use it the way
integer i,j,n ! i,j<n
array(i) = append(n, array, array(j))
with gfortran this does not work. It compiles, but segfaults. The problem seems to be that gfortran makes addresses out of array(i) and array(j), sends the latter to the function append, and then when the address of array(j) is accessed and the one of array(i) written, the address space has been deallocated.
What I would like is that the value of array(j) is put on the stack (not the address) and then used in the function and after the function has finished the uptodate address of array(i) is looked up and the result of the function saved to it.
I am pretty sure gcc would do it the way I want, why is gfortran so mean?
Is there any way in Fortran to make a robust (meaning the array(j) = ... example works)
function or data type to have a c++ stl vector like behaviour?
Conclusion:
I eventually introduced temporary variables
integer tmp_val
tmp_val = value
...
array(n) = tmp_val
so at least the method can be called as
pos = append(n, array, array(j))
array(i) = pos
and hope that other/future developers on the project won't try to 'optimize' the two lines to eliminate the necessity of 'pos'.
Thanks for the answers and comments.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
IRO-bot 的答案是 Fortran 90 的正确方法。如果您可以将自己限制为支持 Fortran 2003 MOVE_ALLOC 内在函数(自 4.2 版本起包含在 gfortran 中),您可以避免其中一个副本。也就是说,将数组的大小增加 2 倍可以写为
The answer by IRO-bot is the correct approach for Fortran 90. If you can limit yourself to compilers that support the Fortran 2003 MOVE_ALLOC intrinsic (included in gfortran since the 4.2 release), you can avoid one of the copies. That is, increasing the size of an array by a factor of 2 can be written as
好的,问题是您无法取消分配并重新分配要为其分配函数值的数组。您对问题原因的理解是正确的(参数通过引用传递,而不是像 C 中那样通过值传递)。由于您在函数体内释放了数组,因此对该数组的赋值变得无效,从而导致段错误。这不是 gfortran 问题,用 ifort 和 pgf90 尝试过,它们都报告了相同的问题。这对我有用:
OK, the problem is that you cannot deallocate and re-allocate the array that you are assigning a function value to. You are correct about the cause of your problem (arguments passed by reference and not by value as it is in C). Since you deallocate the array inside the function body, the assignment to that array becomes invalid, leading to segfault. This is not a gfortran issue, tried it with ifort and pgf90, all of them report the same problem. This works for me:
非常感谢您janneb。您的评论非常有帮助。
我只做了一些更改,就是省略
deallocate(array)
。在我的代码中省略这一行没有任何错误。如果您需要将其放入循环中并且在循环之前没有分配
array
,则此更改特别有用。我的具体情况如下(注意我没有在循环之前或循环中分配 x_all ):Thank you a lot janneb.It was very helpful your comment.
Only a few change I have made was to omit the
deallocate(array)
. There was'nt any erro omitting this line in my code.This change is specially helpful if you need to put it into a loop and you don't allocated
array
before the loop. My specific case follows below (look that I don't allocatex_all
before or into the loop):