Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fortran increase dynamic array size in function

Tags:

fortran

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.

like image 494
Matthias 009 Avatar asked Sep 23 '11 01:09

Matthias 009


1 Answers

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


allocate(tmp_arr(2*size(array)))
tmp_arr(1:size(array)) = array
deallocate(array)
move_alloc(tmp_arr, array)
! tmp_arr is now deallocated
like image 70
janneb Avatar answered Sep 26 '22 08:09

janneb