Search code examples
arraysfortransubroutine

Pass Common block array size to subroutine in Fortran


I would like to pass the array dimension as a dummy variable to a subroutine. The array itself is on a common block. Here is the code:

PROGRAM test
integer i, nn
integer PARAMETER(Nt=10)
real x(Nt), y(nt), z(Nt)
Common /Bdat/ z
nn=Nt
do i=1,Nt
x(i)=i+1
z(i)=i-1
enddo
call estimate(x,y,nn)
print*, y
return
end

subroutine estimate(x,y,jj)
integer i,jj
real x(jj), y(jj), zq(jj)
COMMON /Bdat/ zq
do i=1, jj
y(i)=x(i)+zq(i)
enddo
return
end

this is the error I get from the subroutine:

real x(jj), y(jj), zq(jj)
                      1

Error: Variable 'jj' at (1) in this context must be constant

I would really appreciate it if anybody could solve the issue.


Solution

  • You have a scope problem. Read: Scope in Fortran. That is, your subroutine estimate needs access to the variable Nt which you need to pass as an additional argument, or you can move the entire subroutine inside your program using the contains statement. This will allow your program to run successfully, but I highly encourage you to abstain from using common blocks. If you cannot avoid them due to legacy codes see: Improve your FORTRAN 77 programs using some Fortran 90 features

    Try using modules instead:

        module bdat
    
          implicit none
    
          private
          public :: NT, z
    
          integer, parameter :: NT = 10
          real               :: z(NT) 
    
        end module bdat
    
        module my_sub
    
          use bdat, only: &
               zq => z ! You're free to rename the variable
    
          implicit none
          private
          public :: estimate
    
        contains
    
          subroutine estimate(x,y)
            ! calling arguments
            real, intent (in) :: x(:)
            real, intent (out) :: y(:)
    
            ! local variables
            integer :: i, jj
    
            jj = size(x)
    
            do i=1, jj
               y(i)=x(i)+zq(i)
            end do
    
          end subroutine estimate
    
        end module my_sub
    
        program test
    
          use bdat, only: &
               NT, z
    
          use my_sub, only: &
               estimate
    
          implicit none
    
          integer :: i
          real :: x(NT), y(NT)
    
          do i=1,NT
             x(i)=i+1
             z(i)=i-1
          end do
    
          call estimate(x,y)
    
          print *, y
    
        end program test