IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Fortran Discussion :

Fonction retournant tableau de taille variable


Sujet :

Fortran

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut Fonction retournant tableau de taille variable
    Bonjour,

    J'ai une question concernant la gestion des tableaux en sortie de fonction en FORTRAN90.

    Mon but (c'est un cas d'école) est d'écrire une fonction qui prend en entrée deux tableaux T1 et T2 (de même dimension) et retourne un tableau (de dimension inf. ou égale à la taille de T1) des valeurs communes placées au même endroit

    Exemple :

    T1 = (8,2,3,4,5,1)
    T2 = (8,3,2,5,5,7)

    f(T1,T2) = (8,5)


    Comment puis je créer une fonction qui renvoie un tableau sans connaitre la longueur de ce tableau à l'appel de cette fonction?

    Pourriez vous m'aider?
    Merci

  2. #2
    Membre habitué Avatar de Grame
    Profil pro
    Inscrit en
    Août 2007
    Messages
    148
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Août 2007
    Messages : 148
    Points : 192
    Points
    192
    Par défaut
    Bonjour


    Tu sais que ta fonction retourne un tableau de taille inférieure ou égale aux tableaux entrants. Donc tu le déclares commes les autres.

    Exemple simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    program f
      implicit none
      integer, dimension(6) :: t1, t2, t3
      integer :: dim
     
      data t1 / 8,2,3,4,5,1 /
      data t2 / 8,3,2,5,5,7 /
     
    ! Tu n'es pas obligé de récupérer dim, c'est toi qui voit si tu en as besoin
      call cf (t1, t2, t3, dim)
      print *, t3(1), t3(2), dim
     
    end program f
     
    subroutine cf (t1, t2, t3, dim)
      implicit none
      integer, dimension(*), intent(in) :: t1, t2
      integer, dimension(*), intent(out) :: t3
      integer, intent(out) :: dim
     
      t3(1) = 8
      t3(2) = 5
      dim = 2
     
    end subroutine cf
    C'est juste une base de travail, à toi de continuer.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Merci de ta réponse.

    Mais mes tableaux t1, t2 sont de taille variable : ils sont déclarés en

    integer, dimension(, allocatable :: t1, t2

    C'est après un calcul que je connais leur longueur j et que je fais un

    allocate(t1(1:j), t2(1:j)

    et que je remplis les tableaux.

    Et j'aimerais que le tableau t3 soit de bonne taille.

    Merci

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Comme c'est un travail de classe, je ne vais pas te donner la réponse, mais comme tu as l'honnêteté de nous le dire, voici une piste pour la solution la plus "flyée" à ce problème : Tu dois dimensionner ton tableau de sortie avec une fonction "pure" utilisant les arguments "intent in" de ta fonction principale. Pour plus d'indice : recherche Fortran + "James Van Buskirk". Il a déjà publié la solution à un problème très semblable...

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Bonjour,

    Je me suis mal exprimé par "cas d'école"! Je voulais dire que le but de ce programme était de manipuler des tableaux pour comprendre, sans vouloir dire que j'étais étudiant (j'ai malheureusement passé l'âge!)

    Je pense comprendre l'idée de dimensionner mon tableau par une nouvelle fonction mais pourriez vous m'en dire un peu plus?

    Merci à vous

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Cas général :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    pure integer function NbPareil(a,b)
       integer, intent(in) :: a(:), b(:)
       integer k
       NbPareil = 0
       do k = 1, size(a)
          if (a(k) == b(k)) NbPareil = NbPareil + 1
       enddo
       end function
     
    program Test
       implicit none
       integer T1(6)
       integer T2(6)
     
       T1 = [8,2,3,4,5,1]
       T2 = [8,3,2,5,5,7]
     
       print *, Pareil(T1,T2)
     
    contains
     
       function Pareil(U,V) result(R)
          integer, intent(in) :: U(:),V(:)
          interface
             pure integer function NbPareil(a,b)
                integer, intent(in) :: a(:), b(:)
                end function
          end interface
          integer             :: R(NbPareil(U,V))
          R = pack(U,U==V)
          end function Pareil
     
    end program
    La technique, c'est qu'une variable peut être dimensionnée par une expression faisant référence uniquement à des fonctions pures ou des fonctions informatives (size, count, ...) du langage (cette limite est relâchée en F2003). En pratique, on fait donc 2 fois le travail : une première fois pour calculer le nombre d'élément requis dans une fonction pure, et une deuxième fois pour traiter effectivement. La technique aurait été inventée par James Van Buskirk.

    Malheureusement, le compilateur que j'ai sous la main (Intel 9.1) est un peu vieux et ne supporte pas ce programme : il termine sur un ICE. Mais il n'y a pas d'erreur de syntaxe. Si quelqu'un pouvait l'essayer avec gfortran ou Intel 10, ce serait gentil.

    Une version très simplifiée, mais qui fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    program Test
       implicit none
       integer T1(6)
       integer T2(6)
     
       T1 = [8,2,3,4,5,1]
       T2 = [8,3,2,5,5,7]
     
       print *, Pareil(T1,T2)
     
    contains
     
       function Pareil(U,V) result(R)
          integer, intent(in) :: U(:),V(:)
          integer             :: R(count(U == V))
          R = pack(U,U==V)
          end function Pareil
     
    end program
    Cette version illustre cependant mal la possibilité introduite par la première méthode. Elle est possible parce qu'une fonction intrinsèque du langage permet de calculer directement le nombre d'élément requis.

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Bonjour,

    Et merci de votre réponse détaillée et très intéressante. Oui, la première méthode est la seule qui me convient car j'aurais pu généraliser ma demande

    (par exemple une fonction qui retourne les solutions d'une équation du 4e degré avec possibilité d'avoir 0 à 4 solutions et donc un tableau de 0 à 4 éléments)

    Cette méthode de James Van Buskirk est élégante mais très couteuse en temps de calcul (double du temps de traitement). N'y a t'il pas une autre solution, non pas avec une fonction mais une subroutine où je pourrais faire dans la subroutine un allocate pour dimensionner mon tableau à la taille voulue?

    Merci encore

  8. #8
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Si tu acceptes qu'une subroutine soit utilisée, il y a effectivement des solutions plus efficaces. La variable de retour doit alors être un tableau allocatable et intent (out).

    Reste que souvent, pour stoker progressivement les résultats, tu dois avoir déjà alloué la variable et que pour allouer cette variable, tu as besoin de résoudre le problème pour connaitre le nombre d'élément requis. Ça devient alors aussi inefficace que la solution de la fonction... L'autre solution est alors d'utiliser des listes liées, mais c'est beaucoup plus exigeant en terme de connaissance pour le programmeur.

    Un autre élément milite en faveur de la solution fonction : la fonction retournant un vecteur, ce résultat peut être directement intégré à une expression vectorielle. Comme le langage, les compilateurs et les processeurs s'orientent de plus en plus vers la parallélisation du traitement, peut-être qu'une solution n'ayant pas l'air très efficace maintenant pourrait le devenir éventuellement.

  9. #9
    Membre habitué Avatar de Grame
    Profil pro
    Inscrit en
    Août 2007
    Messages
    148
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Août 2007
    Messages : 148
    Points : 192
    Points
    192
    Par défaut
    Bonjour


    Malheureusement, le compilateur que j'ai sous la main (Intel 9.1) est un peu vieux et ne supporte pas ce programme : il termine sur un ICE. Mais il n'y a pas d'erreur de syntaxe. Si quelqu'un pouvait l'essayer avec gfortran ou Intel 10, ce serait gentil.
    Ca fonctionne parfaitement avec gfortran

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    ~/tmp> gfortran f.f90 
    ~/tmp> ./a.out 
               8           5

  10. #10
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Bonjour,

    Je rebondis sur ma question. J'avais tenté la chose avec une subroutine, mais même si le code se compile, j'ai une erreur à l'exécution (Access Violation). Quel est selon vous le problème?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    PROGRAM tet
      IMPLICIT NONE
      INTEGER, DIMENSION(:), ALLOCATABLE :: tab1,tab2,tab3,tab4
      INTEGER :: j,taille_tab12
     
      tab1 = (/1,2,3,4,5,6/)
      tab2 = (/1,2,3,4,6,5/)
      j=0
      taille_tab12 = SIZE(tab1)
      ALLOCATE(tab3(taille_tab12))
      CALL elem_egaux(tab1,tab2,tab3,j)
      ALLOCATE(tab4(j))
      tab4 = tab3(1:j)
     
    CONTAINS
     
      SUBROUTINE elem_egaux(tableau_in1,tableau_in2,tableau_out,size_tableau_out)
        INTEGER, DIMENSION(:),INTENT(IN) :: tableau_in1
        INTEGER, DIMENSION(:),INTENT(IN) :: tableau_in2
        INTEGER, DIMENSION(:),INTENT(IN OUT) :: tableau_out
        INTEGER, INTENT(IN OUT) :: size_tableau_out
        INTEGER :: taille,i
        taille = SIZE(tableau_in1)
        DO i=1,taille
          IF (tableau_in1(i) == tableau_in2(i)) THEN
            tableau_out(size_tableau_out) = i
            size_tableau_out = size_tableau_out + 1
          END IF
        END DO
      END SUBROUTINE elem_egaux
     
    END PROGRAM tet
    Merci

  11. #11
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Rebonjour,

    Une version corrigée de mon code qui fonctionne finalement. Je pense que ca manque d'élégance, et que cela consomme plus de mémoire mais cela permet de réaliser une seule boucle (contre 2 dans la solution générale de type fonction). Qu'en pensez vous?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    PROGRAM tet
      IMPLICIT NONE
      INTEGER, DIMENSION(:), ALLOCATABLE :: tab1,tab2,tab3,tab4
      INTEGER :: j,taille_tab12,alok
      ALLOCATE(tab1(6),tab2(6))
      tab1 = (/1,2,3,4,5,6/)
      tab2 = (/1,2,3,4,6,5/)
      j=1
      taille_tab12 = SIZE(tab1)
      ALLOCATE(tab3(taille_tab12),stat=alok)
      PRINT *, tab1
      PRINT *, alok
      CALL elem_egaux(tab1,tab2,tab3,j)
      ALLOCATE(tab4(1:j))
      tab4 = tab3(1:j)
      DEALLOCATE(tab3)
      PRINT *, tab4
    CONTAINS
     
      SUBROUTINE elem_egaux(tableau_in1,tableau_in2,tableau_out,size_tableau_out)
        INTEGER, DIMENSION(:),INTENT(IN) :: tableau_in1
        INTEGER, DIMENSION(:),INTENT(IN) :: tableau_in2
        INTEGER, DIMENSION(:),INTENT(IN OUT) :: tableau_out
        INTEGER, INTENT(IN OUT) :: size_tableau_out
        INTEGER :: taille,i
        taille = SIZE(tableau_in1)
        DO i=1,taille
          IF (tableau_in1(i) == tableau_in2(i)) THEN
            tableau_out(size_tableau_out) = i
            size_tableau_out = size_tableau_out + 1
          END IF
        END DO
        size_tableau_out = size_tableau_out-1
      END SUBROUTINE elem_egaux
     
    END PROGRAM tet

  12. #12
    Membre habitué Avatar de Grame
    Profil pro
    Inscrit en
    Août 2007
    Messages
    148
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Août 2007
    Messages : 148
    Points : 192
    Points
    192
    Par défaut
    Bonsoir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Qu'en pensez vous?
    Bah, l'essentiel est que ton code fasse ce que tu veux. Après, chacun son style
    Puisque tu nous demandes gentiment notre avis, je ferais juste quelques modifs mineures.

    Au lieu d'initialiser la taille de t3 dans le programme principal, je le ferais dans la routine. Donc supprimer la ligne
    dans le programme. De fait, tableau_out et size_tableau_out deviennent INTENT(OUT)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    . . .
        INTEGER, DIMENSION(:),INTENT(OUT) :: tableau_out
        INTEGER, INTENT(OUT) :: size_tableau_out
    . . .      
        size_tableau_out = 1

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Bonjour,

    Une nouvelle version du code qui marche mais que je ne comprends plus!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    PROGRAM tet
      IMPLICIT NONE
      INTEGER, DIMENSION(:), ALLOCATABLE :: tab1,tab2,tab3,tab4
      INTEGER :: j,taille_tab12
      ALLOCATE(tab1(6),tab2(6))
      tab1 = (/1,2,3,4,5,6/)
      tab2 = (/1,1,3,5,6,5/)
      CALL elem_egaux(tab1,tab2,tab3,j)
      PRINT *,tab3
    CONTAINS
     
      SUBROUTINE elem_egaux(tableau_in1,tableau_in2,tableau_out,size_tableau_out)
        INTEGER, DIMENSION(:),INTENT(IN) :: tableau_in1
        INTEGER, DIMENSION(:),INTENT(IN) :: tableau_in2
        INTEGER, DIMENSION(:),INTENT(IN OUT), ALLOCATABLE :: tableau_out
        INTEGER, INTENT(OUT) :: size_tableau_out
        INTEGER :: taille,i
        size_tableau_out = 1
        ALLOCATE(tab3(taille_tab12))
        taille = SIZE(tableau_in1)
        DO i=1,taille
          IF (tableau_in1(i) == tableau_in2(i)) THEN
            tableau_out(size_tableau_out) = i
            size_tableau_out = size_tableau_out + 1
          END IF
        END DO
        size_tableau_out = size_tableau_out-1
        DEALLOCATE(tableau_out);ALLOCATE(tableau_out(1:size_tableau_out))
      END SUBROUTINE elem_egaux
     
    END PROGRAM tet
    Dans mon (à la fin de la routine)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    DEALLOCATE(tableau_out);ALLOCATE(tableau_out(1:size_tableau_out))
    Que se passe-t-il en mémoire après le deallocate? Comment se fait-il que cette suite d'instruction deallocate, puis allocate suffise à redimensionner le tableau et que le tableau ne soit pas "perdu" après le deallocate?!

    Au point de vue de l'optimisation, est ce que ce code est performant? En comparaison de la méthode de la fonction, je dirais que oui (une seule boucle), mais au point de vue de la mémoire, je pense que non (obligation d'allouer un tableau de sortie très grand pour contenir potentiellement que peu de points)?

    Merci.

  14. #14
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Ton code est illégal. C'est un hasard que ça fonctionne. Pour que tu ne perdes pas les données dans le deallocate / allocate, il faut que le bloc de mémoire alloué débute exactement à la même adresse que celui déalloué. Mais que ton code se fie sur ce hasard pour fonctionner est illégal.

    De plus, la première allocation à la taille taille_tab12 est aussi illégal puisque taille_tab12 n'est pas initialisé. taille_tab12 contient fort possiblement la valeur 0. Alors tu alloues le tableau à la taille 0, et là, tu mets des valeurs aux éléments 1, 2 , 3... Si tu compilais ton programme avec tous les checks "on", il ne fonctionnerait certainement pas.

  15. #15
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Merci. Je me doutais bien qu'il y avait anguille sous roche!

    Et quid de la version proposée avant (message d'hier à 16h39)? Est ce bon, ou y-a-il encore un souci?

    Merci encore

  16. #16
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    16h39 ? Tu dois parler du message de 10h39... (les heures des messages sont convertis à l'heure local...)

    Je suis d'accord avec Grame pour j=1

    Ensuite, et là c'est vraiment une question de style : j'aurais déplacé tout le traitement des 2 vecteurs de résultats dans la fonction. Mais peut-être veux-tu laisser le "resize" du résultat optionnel à la discrétion de l'utilisateur (donc le programme principal).

  17. #17
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Oui, je parlais bien du message de 10h39/16h39!

    J'ai essayé d'intégrer les remarques de Grame et la tienne (avoir le traitement dans la subroutine m'intéresse). J'ai le code suivant qui marche

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    PROGRAM tet
      IMPLICIT NONE
      INTEGER, DIMENSION(:), ALLOCATABLE :: tab1,tab2,tab3
      INTEGER :: j,taille_tab12,alok
     
      ALLOCATE(tab1(6),tab2(6))
     
      tab1 = (/1,2,3,4,5,6/)
      tab2 = (/1,2,3,4,6,5/)
     
      PRINT *, tab1
      CALL elem_egaux(tab1,tab2,tab3)
      PRINT *, tab3
    CONTAINS
     
      SUBROUTINE elem_egaux(tableau_in1,tableau_in2,tableau_out)
        INTEGER, DIMENSION(:),INTENT(IN) :: tableau_in1
        INTEGER, DIMENSION(:),INTENT(IN) :: tableau_in2
        INTEGER, DIMENSION(:),INTENT(OUT), ALLOCATABLE :: tableau_out
        INTEGER, DIMENSION(:), ALLOCATABLE :: tableau_temp
        INTEGER :: size_tableau_out=1,taille,i
        taille = SIZE(tableau_in1)
        ALLOCATE(tableau_temp(taille))
        DO i=1,taille
          IF (tableau_in1(i) == tableau_in2(i)) THEN
            tableau_temp(size_tableau_out) = i
            size_tableau_out = size_tableau_out + 1
          END IF
        END DO
        size_tableau_out = size_tableau_out-1
        DEALLOCATE(tableau_out);ALLOCATE(tableau_out(1:j))
        tableau_out = tableau_temp(1:j)
        DEALLOCATE(tableau_temp)
      END SUBROUTINE elem_egaux
     
    END PROGRAM tet
    Mais je ne comprends pas bien deux choses:

    1°) N'est ce pas une erreur de re-déclarer en ALLOCATABLE le tableau_out dans la subroutine ?
    2°) Comment se fait-il que je puisse passer en argument à la subroutine un tableau non alloué?

    Merci

  18. #18
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Citation Envoyé par sfiliste Voir le message
    Mais je ne comprends pas bien deux choses:

    1°) N'est ce pas une erreur de re-déclarer en ALLOCATABLE le tableau_out dans la subroutine ?
    2°) Comment se fait-il que je puisse passer en argument à la subroutine un tableau non alloué?
    1. Si tu n'avais pas mis l'attribut allocatable dans la routine, le tableau n'aurait pas été allocatable dans la routine. Le fait qu'il soit allocatable dans l'appelant ne le rend pas allocatable automatiquement dans la routine. La routine aurait simplement reçu l'adresse du bloc de mémoire contenant la variable, et non l'adresse du header contenant les infos pertinentes à une variable allocatable (ce n'est pas dit comme ça dans le standard, mais c'est comme si tu recevais variable%Adresse plutôt que variable).
    2. Parce que la variable dummy est justement allocatable. Elle a donc accès au header et peut donc déterminer que la variable est ou n'est pas allouée. Si la variable dummy n'était pas allocatable et que tu passait une variable non allouée, il y aurait alors un access violation.


    Finalement, il y a une erreur très "Fortran" dans ta routine. Quand tu fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        INTEGER :: size_tableau_out=1,taille,i
    la variable size_tableau_out devient "save" et garde sa valeur d'un appel à l'autre. Ta routine ne devrait donc fonctionner qu'une fois ! L'initialisation n'est en fait effectuée que la première fois, au "load time" mettons. Tu dois plutôt faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        INTEGER :: size_tableau_out,taille,i
        ...
        size_tableau_out=1
    pour avoir le comportement désiré. L'initialisation dans la déclaration doit être réservé aux cas où on veut vraiment conserver la valeur. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    subroutine EcritMessage(Msg)
       character (*), intent(in) :: Msg
       logical PremiereFois = .true.
       if (PremiereFois) then
          ouverture du fichier...
          PremiereFois = .false.
       endif
       write(...) Msg

  19. #19
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 25
    Points : 7
    Points
    7
    Par défaut
    Bonsoir, et merci encore de ces réponses précieuses!

    Je pense que j'ai bien compris, et je prends bien en compte la subtilité "fortran" de l'initialisation de la variable: je le ferai bien de manière séparée.

    Merci!

Discussions similaires

  1. sommes des cases d'un tableau de taille variable
    Par Bubale dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 18/04/2008, 00h18
  2. Sélectionner tableau a taille variable
    Par Iloon dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 07/02/2008, 16h20
  3. [Conception] tableau de taille variable
    Par salirose dans le forum PHP & Base de données
    Réponses: 16
    Dernier message: 21/10/2006, 13h53
  4. Réponses: 1
    Dernier message: 14/09/2006, 10h53
  5. [TP] Tableau de taille variable
    Par Ripley dans le forum Turbo Pascal
    Réponses: 4
    Dernier message: 30/01/2006, 15h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo