web-dev-qa-db-fra.com

Comment passer des tableaux attribuables à des sous-programmes à Fortran

Le code suivant renvoie un défaut de segmentation car le tableau allouable que j'essaie de transmettre n'est pas correctement reconnu (la taille renvoie 1, alors qu'elle devrait être 3). Dans cette page (http://www.eng-tips.com/viewthread.cfm?qid=170599) un exemple similaire semble indiquer qu'il devrait fonctionner correctement dans F95; mon fichier de code a une extension .F90, mais j'ai essayé de le changer en F95, et j'utilise gfortran pour compiler.

Je suppose que le problème devrait être dans la façon dont je passe le tableau allouable au sous-programme; Qu'est-ce que je fais mal?

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
 PROGRAM test
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
 IMPLICIT NONE
 DOUBLE PRECISION,ALLOCATABLE :: Array(:,:)
 INTEGER                      :: iii,jjj

 ALLOCATE(Array(3,3))
 DO iii=1,3
 DO jjj=1,3
    Array(iii,jjj)=iii+jjj
    PRINT*,Array(iii,jjj)
 ENDDO
 ENDDO
 CALL Subtest(Array)

 END PROGRAM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
 SUBROUTINE Subtest(Array)
 DOUBLE PRECISION,ALLOCATABLE,INTENT(IN) :: Array(:,:)
 INTEGER                                 :: iii,jjj

 PRINT*,SIZE(Array,1),SIZE(Array,2)
 DO iii=1,SIZE(Array,1)
 DO jjj=1,SIZE(Array,2)
    PRINT*,Array(iii,jjj)
 ENDDO
 ENDDO

 END SUBROUTINE
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
17
Nordico

Si une procédure a un argument factice qui peut être alloué, une interface explicite est requise dans toute étendue appelante.

(Il existe de nombreuses choses qui nécessitent une interface explicite, un mannequin attribuable n'en est qu'un.)

Vous pouvez fournir cette interface explicite vous-même en plaçant un bloc d'interface pour votre sous-programme dans le programme principal. Une alternative et beaucoup, beaucoup, beaucoup mieux est de mettre le sous-programme à l'intérieur d'un module puis d'utiliser ce module dans le programme principal - l'interface explicite est alors automatiquement créée. Il y a un exemple de cela sur le site eng-tips auquel vous avez fourni un lien - voir le message de xwb.

Notez qu'il est logique qu'un argument factice ait l'attribut allocatable si vous allez faire quelque chose en rapport avec son statut d'allocation - interroger son statut, le réallouer, le désallouer, etc.

31
IanH

Veuillez également noter que votre argument factice affectable array est déclaré avec intent(in), ce qui signifie que son statut d'allocation sera celui de l'argument réel associé (et il ne peut pas être modifié pendant la procédure). L'argument réel transmis à votre sous-routine peut être non alloué et donc illégal à référencer, même avec une interface explicite. Le compilateur ne le saura pas et le comportement des requêtes comme size n'est pas défini dans de tels cas.

Par conséquent, vous devez d'abord vérifier l'état d'allocation de array avec allocated(array) avant de référencer son contenu. Je suggérerais en outre d'implémenter des boucles sur le tableau complet avec lbound et ubound, car en général, vous ne pouvez pas être sûr des limites de array:

subroutine subtest(array)
  double precision, allocatable, intent(in) :: array(:,:)
  integer                                   :: iii, jjj

  if(allocated(array)) then
    print*, size(array, 1), size(array, 2)
    do iii = lbound(array, 1), ubound(array, 1)
      do jjj = lbound(array, 2), ubound(array, 2)
        print*, array(iii,jjj)
      enddo
    enddo
  endif  
end subroutine
7
sigma

Il s'agit d'un exemple simple qui utilise des arguments factices allouables avec un module.

module arrayMod   
  real,dimension(:,:),allocatable :: theArray    
end module arrayMod

program test
   use arrayMod
   implicit none

   interface
      subroutine arraySub
      end subroutine arraySub
   end interface

   write(*,*) allocated(theArray)
   call arraySub
   write(*,*) allocated(theArray) 
end program test

subroutine arraySub
   use arrayMod

   write(*,*) 'Inside arraySub()'
   allocate(theArray(3,2))
end subroutine arraySub
1
GPSmaster