Fortran function returning allocatable array

Let me consider a function returning an allocatable array. Should the array variable holding the result (outside the function) be allocated before an assignment?

Consider, e.g., the following program

program mem
  implicit none

  interface
     function get_matrix() result(res)
       real(kind=kind(0.d0)), allocatable :: res(:,:)
     end function get_matrix
  end interface

  real(kind=kind(0.d0)), allocatable :: w(:,:)

  allocate(w(2,2)) ! Is this necessary?
  w=get_matrix()
  deallocate(w)

end program mem

function get_matrix() result(res)
  real(kind=kind(0.d0)), allocatable :: res(:,:)

  allocate(res(2,2))
  res = 0.d0
  res(1, 1) = 1.d0
  res(2, 2) = 1.d0
end function get_matrix

According to this, and this, the array res allocated for the resul of get_matrix is deallocated as soon as it goes out of scope.

Would an assignment to a non-allocated variable w in the main program prolong the scope of the result of get_matrix? In other words, if I omit allocate(w(2,2)) in the main program, do I get an undefined behavior?

Omitting allocate(w(2,2)) and compiling with gfortran 9.2.0 and options -Wall -std=f2008 gives following warnings

mem.f90:13:0:

   13 |   w=get_matrix()
      | 
Warning: ‘w.offset’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].lbound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ is used uninitialized in this function [-Wuninitialized]
mem.f90:13:0:

   13 |   w=get_matrix()
      | 
Warning: ‘w.dim[0].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[0].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].ubound’ may be used uninitialized in this function [-Wmaybe-uninitialized]
mem.f90:13:0: Warning: ‘w.dim[1].lbound’ may be used uninitialized in this function [-Wmaybe-uninitialized]

However, running the program with valgrind, as well as compiling with -fbounds-check, -fsanitize=address, or -fsanitize=leak does not give any error. Furthermore, the instruction deallocate(w) at the end does not crash the program, suggesting that w contains the memory allocated by get_matrix and, hence, one does not need to allocate w in the main program.

At the same time, including allocate(w(2,2)) in the code suppresses the compiler warning. Despite having the impression that the same memory is allocated twice, valgrind does not report a memory leak and, in fact, reports exactly the same memory usage.

What is the correct way to store an allocatable array as result of a function? Is it necessary to allocate w before storing in it the result of get_matrix?

The answers by ja72 and Vladimir F are correct. However, for completeness I'll address another point. In the statement

var = function_ref()

where the right-hand side is a reference to a function with an allocatable result, there's actually nothing special about this in regards to the allocatable nature. That expression is not an allocatable entity.

So, our assignment is much like any other

var = expr

with the right-hand side an expression. That is, there is no special consideration required for assigning from a function with allocatable result. (The function result must, of course, be allocated, but that's a different point.)

In the case of the question, the usual intrinsic assignment rules apply. In particular, we don't need to allocate w before the assignment.


On

Furthermore, the instruction deallocate(w) at the end does not crash the program, suggesting that w contains the memory allocated by get_matrix and, hence, one does not need to allocate w in the main program.

There are again other things to say. The function result of get_matrix is itself deallocated after being used in the assignment. w is a separate entity from the function result and the intrinsic assignment causes the allocation of w.

So, no you do not "prolong the scope of the result": you've have copied it, to a newly allocated variable, and then deallocated once it is finished with. Consider instead an expression like

var = function_ref() + 1

Again, we have an expression to assign, but would we expect the function result to "persist"?

Consider also this related question.

Returning array from function � Issue #114 � fortran-lang/stdlib � GitHub, e.g. 1D result is already allocated, function allocates its own result, on return those results are copied to pre-allocated array. real(sp), allocatable ::� The bounds (and shape) of an allocatable array are determined when it is allocated. Subsequent redefinition or undefinition of any entities in the bound expressions does not affect the array specification. If the lower bound is greater than the upper bound, that dimension has an extent of zero, and the array has a size of zero.

No need to pre-allocate, or deallocate. The compiler will take care of this. The following code works as expected with Intel fortran.

program Console1
implicit none
! Variables
real(8), allocatable :: A(:,:)
integer :: i, j

! Body of Console1

A = get_matrix(6,4)

do i=1, size(A,1)
    print '(*(g9.4),1x)', A(i,:)
end do    

contains

function get_matrix(n,m) result(res)
integer, intent(in) :: n,m
real(8), allocatable :: res(:,:)
integer :: i

    allocate(res(n,m))
    res = 0d0
    forall(i=1:min(n,m)) res(i,i)=1d0

end function

end program Console1

Output:

1.000    0.000    0.000    0.000
0.000    1.000    0.000    0.000
0.000    0.000    1.000    0.000
0.000    0.000    0.000    1.000
0.000    0.000    0.000    0.000
0.000    0.000    0.000    0.000

PS. Put functions inside the program declaration using a contains keyword. That way they are not external functions and no interface declaration is required.

function returning allocatable array, you could confirm it (g95 and gfortran accept the code). Best regards, Marco Restelli. Fortran 90 functions can return array-valued results. number of intrinsic functions always return array values and most intrinsic functions can return array values. In addition, user-written functions may be array valued. Array-valued functions provide two (related) tremendous

There are many similar bugs in the GCC bugzilla and are considered a problem with your compiler, not with your code. Some are already fixed, some are not 67679 66459 88455 and more (many duplicates).

Try the most recent version of the compiler, but it may still persist.

As a workaround I use-Wno-maybe-uninitialized.

Dynamic Arrays, Therefore, you can return an ALLOCATABLE arrays, by using a function that returns a POINTER variable. Example: returning a dynamically allocated array� Array-valued functions: functions that return arrays Functions in Fortran 90 can even return arrays (or matrices) ! Furthermore, the size of the array (or matrix) returned by the function can be defined using values that are derived from the input parameters

fortran, How can I return an allocatable array?, Dear all,. I've been convinced to write my own tridiagonal matrix solver. I'll be better for it. :) But I hit a snag. Here's what I have: FUNCTION tridiagonal_solve(a, b� Arrays and Parallel programming in Fortran 90/95 Allocatable Arrays. In the old days, the maximum size arrays had to be declared when the code was written. This was a great disadvantage, as it resulted in wasted RAM (arrays size had to be the maximum possible) or in frequent recompilations. Fortran90 allows for "allocatable" arrays.

NAG Fortran Compiler, Release 6.2: ALLOCATABLE extensions, The result of a function can be declared to be an allocatable array, e.g.. FUNCTION af() It must be allocated before returning from the function. For example: The rank of the array, i.e., the dimensions has to be mentioned however, to allocate memory to such an array, you use the allocate function. allocate (darray(s1,s2)) After the array is used, in the program, the memory created should be freed using the deallocate function

Fortran Best Practices — Fortran90 1.0 documentation, returning an array from a function; interfacing with C code or legacy Fortran (like When using allocatable arrays (as opposed to pointers), Fortran manages the� John, Fortran 2003 added the. John, Fortran 2003 added the ability to declare an allocatable dummy argument, function return value or derived type component. As you say, the only reason to declare a dummy argument to be allocatable is if you're going to change its allocation status in the routine.

Comments
  • I'd argue that the original kind=kind(0.d0) is better than your 8. It is at least portable, if a bit long.
  • @VladimirF - Yes, but I choose brevity here,