1

I'm learning the basics of Fortran. I created a simple subroutine initializing a matrix:

program test
   integer, parameter :: n = 1024
   real :: a(n, n)
   call init(a)
   write (*, *) a(1, 1)
end program

subroutine init(a)
   real :: a(n, n)
   a(:, :) = 3.0
end subroutine

Then the output is 0.0 instead of expected 3.0. Apart from that, valgrind says that:

==7006== Conditional jump or move depends on uninitialised value(s)
==7006==    at 0x400754: init_ (in /home/marcin/proj/mimuw/fortran/test)
==7006==    by 0x4007A4: MAIN__ (in /home/marcin/proj/mimuw/fortran/test)
==7006==    by 0x40083B: main (in /home/marcin/proj/mimuw/fortran/test)

Why? The n parameter is correctly recognized by the compiler and should be a global one.

I compiled the program with gfortran 6.3.1

marmistrz
  • 5,974
  • 10
  • 42
  • 94
  • Perhaps you are thinking of an internal procedure. – tim18 Feb 03 '17 at 12:59
  • 2
    `n` isn't a global object. If you add `implicit none` in the subroutine you will see an error. – francescalus Feb 03 '17 at 13:11
  • Oh, so I need `implicit none` in the subroutines too! Did not know about it. When testing I tried using that in `program` but not in the `subroutine`. Is it possible to use `implicit none` globally? – marmistrz Feb 03 '17 at 13:40
  • Because of the independent compilation nature of various program units (as touched on by Vladimir F), there's no such thing really as "globally" for scoping. You can find detail about implicit typing rules in [this question](https://stackoverflow.com/q/24337413). – francescalus Feb 03 '17 at 14:25

2 Answers2

6

n is not a global variable, it is a local variable of the main program.

The subroutine is a completely independent compilation unit from the main program and they do not share any information.

A subroutine can "see" other variables of the parent module, if it is a module procedure, or variables of a parent (host) procedure or program if it is an internal procedure.

Be sure to read about the structure of Fortran programs and use modules as much as possible. Prefer modules over internal procedures. You will see how to put the subroutine into a module or how to make it internal to the main program in the link.

I did not mention common blocks, just don't use them, they are obsolete. And rember to use implicit none in every compilation unit.

Graham
  • 7,431
  • 18
  • 59
  • 84
  • So `n` was just implicitly declared when I used it in the subroutine? – marmistrz Feb 03 '17 at 13:40
  • 1
    @marmistrz yes, with implicit typing everything that starts with i,n and some other letters(don't even remember which ones) are declared as integers. Generally you should not use implicit typing since this may lead to undesired behavior sometimes. I can suggest reading Modern Fortran Explained by Michael Metcalf - this can help you with onboarding process. – Chaosit Feb 03 '17 at 14:14
2

Assuming that you want it everywhere, then one uses a COMMON block in the f77 era, and a MODULE now.

I CAPITALISED most of the changes. And if there is no error gives a few ways to consider understanding N in the SUBROUTINE, and an ELEMENTAL FUNCTION would likely be worthwhile to try here too.

MODULE MyMODULE
  integer, parameter :: n = 1024
END MODULE MyMODULE

!%%%%%%%%%% 
program test
USE MyModule
IMPLICIT NONE
! done up in ˆmoduleˆ...!  integer, parameter :: n = 1024
REAL, DIMENSION(n,n) :: A

CALL Alternative_Init(A, 3.3)
WRITE (*,*) a(1, 1)

CALL Alternative2_Init(A, n, 1.23)
WRITE (*,*) a(1, 1)

call init(a)
write (*, *) a(1, 1)
END PROGRAM TEST

!%%%%%%%%%% 
subroutine init(a)
USE MyModule
IMPLICIT NONE

real :: a(n, n)
a(:, :) = 3.0

RETURN
END SUBROUTINE init


!%%%%%%%%%% 
SUBROUTINE Alternative_Init(a, Val4A)
USE MyModule
IMPLICIT NONE

REAL, DIMENSION(:,:) , INTENT(INOUT) :: a
REAL                 , INTENT(IN  )  :: Val4A

a(:, :) = Val4A
! or just... A = Val4A ! which does them all too.

RETURN
END SUBROUTINE Alternative_Init

!%%%%%%%%%% 
SUBROUTINE Alternative2_Init(a, n, Val4A)
!!!!  USE MyModule
IMPLICIT NONE

INTEGER              , INTENT(IN   ) :: n
REAL, DIMENSION(n,n) , INTENT(  OUT) :: a
REAL                 , INTENT(IN   ) :: Val4A

A = Val4A

RETURN
END SUBROUTINE Alternative2_Init
Holmz
  • 714
  • 7
  • 14