Search code examples
fortranfortran90

Why can't we define the array size by a variable?


I found that the array size can be defined by parameters but not variables. An example is given below to explain what I am saying.

1st Example - Not working:

integer :: narr=100
integer, dimension(narr) :: Total

2nd Example - Working:

integer, parameter :: narr=100
integer, dimension(narr) :: Total

In the 1st example, I expect the dimension can use the variable narr as narr is defined FIRST. But I realized that this may not be true as the creation of variable may not follow the order of my code lines. Maybe this is only what a person with Python background only would think so.

In the 2nd example, things work perfectly.

I speculate that the difference is related to WHEN the variable and constant are created. Can someone explain the mystery inside it?


Solution

  • In your examples, since integer, dimension(narr) :: Total does not have an allocatable or pointer attribute, it is either a static array or an automatic array, depending on the context (I'm leaving out assumed shape array because the question is specifically about defining arrays). In either case, its size must be a compile time constant or a dummy argument. In the first example, narr is neither which makes it invalid Fortran. In order to use narr as a non-constant variable to specify the size, you would need to declare Total as a dynamic array by including the allocatable or pointer attribute. This might have a performance penalty depending on the situation, but it allows more flexibility in how and where the array bound is defined.

    Here are some of the common ways to define static and dynamic arrays in Fortran:

      ! Static
      call test_fixed_size()
      call test_size_parameter()
    
      ! Dynamic
      call test_allocatable()
      call test_pointer()
      call test_automatic(10)
    
    contains
      subroutine test_fixed_size()
        integer :: array(10)
        array = 1
      end subroutine test_fixed_size
    
      subroutine test_size_parameter()
        integer, parameter :: size = 10
        integer :: array(size)
        array = 1
      end subroutine test_size_parameter
    
      subroutine test_allocatable()
        integer, allocatable :: array(:)
        integer :: narr = 100
        allocate(array(narr))
        array = 1
      end subroutine test_allocatable
    
      subroutine test_pointer()
        integer, pointer :: array(:) => null()
        integer :: narr = 100
        allocate(array(narr))
        array = 1
        deallocate(array)
      end subroutine test_pointer
    
      subroutine test_automatic(size)
        integer, intent(in) :: size
        integer :: array(size)
        array = 1
      end subroutine test_automatic
    end program
    

    (I'm leaving out more modern features here such as automatic allocation on assignment.)