Allocate and Subprograms

Unlike some other languages, an array allocated in a Fortran subprogram is automatically deallocated when the subprogram returns.

To some extent, this has the advantage of preventing memory leaks, where a programmer allocates more and more memory over time and forgets to deallocate all of it, resulting in a continual reduction in available memory. Automatically deallocating arrays does not completely eliminate memory leaks however, and some might argue that it leads to less disciplined programmers by allowing them to be less vigilant.

Automatically deallocating arrays when a subprogram returns is sometimes a disadvantage as well. There are situations where we want a subprogram to allocate memory which can later be used by the calling subprogram, or others. In Fortran, however, allocated memory is only accessible to the subprogram that allocated it, and other subprograms called by it after the allocation and before it returns. Consider the following read\_list() implementation:

! Main program body
program cant_do_this
    ! Disable implicit declarations (i-n rule)
    implicit none
    
    ! Variable defintions
    integer :: num_temps
    real(8), allocatable :: temps(:)
    
    ! Allocate an array for a list of temps and fill it from input
    ! Get back the list and the list size from read_list()
    call read_list(temps, num_temps)
    
    ! Print the list returned by read_list
    
end program

subroutine read_list(list, list_size)
    ! Disable implicit declarations (i-n rule)
    implicit none
    
    ! Dummy variables
    ! Define list_size first, since it is used to define list
    integer, intent(out) :: list_size
    real(8), intent(out), allocatable :: list(:)

    ! Local variables
    integer :: i, alloc_status
    
    read *, list_size
    allocate(list(1:list_size), stat=alloc_status)
    if ( alloc_status /= 0 ) then
        print *, 'Allocate failed.  status = ', alloc_status
        stop
    endif
    
    do i = 1, list_size
        read *, list(i)
    enddo
end subroutine

The code above will compile, but will not work, because the array allocated inside the read_list() subroutine is deallocated when the subroutine returns. Hence, the array no longer exists after coming back to the main program from read_list().

The code below shows how this task must be accomplished in Fortran. The array must be allocated before calling read_list() and passed to read_list() to receive the input. The array can exist in the main program, in read_list(), and in other subprograms called by the main program.

! Main program body
program this_one_works
    ! Disable implicit declarations (i-n rule)
    implicit none
    
    ! Variable defintions
    integer :: num_temps, alloc_status
    real(8), allocatable :: temps(:)

    read *, num_temps
    allocate(temps(1:num_temps), stat=alloc_status)
    if ( alloc_status /= 0 ) then
        print *, 'Allocate failed.  status = ', alloc_status
        stop
    endif
    
    ! Allocate an array for a list of temps and fill it from input
    ! Get back the list and the list size from read_list()
    call read_list(temps, num_temps)
    
    ! Print the list returned by read_list
    
end program

subroutine read_list(list, list_size)
    ! Disable implicit declarations (i-n rule)
    implicit none
    
    ! Dummy variables
    ! Define list_size first, since it is used to define list
    integer, intent(in) :: list_size
    real(8), intent(out) :: list(1:list_size)

    ! Local variables
    integer :: i
    
    do i = 1, list_size
        read *, list(i)
    enddo
end subroutine

In C, memory allocated by malloc() remains allocated until it is released by free(). This is part of the C philosophy of "trust the programmer". This philosophy often leads to programmers shooting themselves in the foot, but also allows programmers to easily do what they need to.