• Aucun résultat trouvé

Manipulation de listes chaînées

Les composantes des types dérivés peuvent posséder l’attribut pointeur, ce qui permet la consti-tution de listes chaînées : les listes chaînées permettent de représenter des ensembles ordonnés d’éléments (appelés noeuds de la liste) dont non seulement le contenu, mais aussi le nombre peut évoluer en cours de l’exécution du programme. On peut en particulier insérer ou supprimer des éléments dans la liste tout en conservant l’ordre : l’allocation se fait donc élément par élément, contrairement à ce qui passe pour les tableaux où l’allocation, si elle peut être dynamique, reste globale. Mais, l’accès à un élément donné de la liste nécessite de parcourir tous les précédents alors qu’on peut accéder directement à un élément d’indice donné d’un tableau.

Dans une liste simplement chaînée, chaque élément comporte un pointeur vers l’élément suivant sauf le pointeur du dernier élément de la liste qui est nul.

données 1

pointeur

données 2

pointeur

données 3

pointeur pointeur

Figure11.1 – Liste simplement chaînée à trois éléments : le dernier élément pointe versNULL. L’exemple suivant montre une liste chaînée permettant de représenter une courbe dans le plan : le type dérivépointcomporte donc un pointeur vers une donnée de typepointpour chaîner la liste.

Pour simplifier, la courbe initialement créée est la deuxième bissectrice des axes. Les procédures d’impressionimprime_chaine(ligne10, p.112) et de libérationlibere_chaine(ligne26, p.113) de la liste sont ici implémentées sous forme récursive. Pour libérer la mémoire, il est nécessaire de commencer par la fin de la liste afin d’éviter de perdre l’accès aux éléments suivants. En revanche, l’impression de la liste se fait dans l’ordre si on imprime avant l’appel récursif (en « descendant » la récurrence) ou dans l’ordre inverse (procédureimprime_chaine_inverse(ligne18, p.112) si on imprime après (en « remontant » la récurrence). Enfin, les opérations d’insertion, insere_point (ligne 57, p. 113) ou de suppression, supprime_point (ligne 35, p. 113) d’un point intérieur se font dans une boucle qui parcourt l’ensemble de la liste jusqu’au pointeur nul signifiant l’accès au dernier point.

1 MODULE m_chaine

2 IMPLICIT NONE

3 TYPE point

4 ! définition du type dérivé point avec un pointeur vers le suivant

5 REAL :: x

6 REAL :: y

7 TYPE(point), POINTER :: next => null() ! f95 seulement (par prudence)

8 END TYPE point

9 CONTAINS

10 RECURSIVE SUBROUTINE imprime_chaine(courant) !

11 TYPE(point), POINTER :: courant

12 ! affichage en commençant par le début : imprimer avant la récursion

13 WRITE(*,*) courant%x, courant%y

14 IF(ASSOCIATED(courant%next)) THEN

15 CALL imprime_chaine(courant%next)

16 END IF

17 END SUBROUTINE imprime_chaine

18 RECURSIVE SUBROUTINE imprime_chaine_inverse(courant) !

19 TYPE(point), POINTER :: courant

20 ! affichage en commençant par la fin : dérouler la récursion avant

21 IF(ASSOCIATED(courant%next)) THEN

11.4. MANIPULATION DE LISTES CHAÎNÉES 113

28 ! attention libérer en commençant par la fin

29 IF(ASSOCIATED(courant%next)) THEN

30 CALL libere_chaine(courant%next)

31 END IF

32 WRITE(*,*) "libération du point de coordonnées", courant%x, courant%y

33 DEALLOCATE(courant)

34 END SUBROUTINE libere_chaine

35 SUBROUTINE supprime_point(debut) !

36 ! suppression d’un point (intérieur seulement)

37 TYPE(point), POINTER :: debut

38 TYPE(point), POINTER :: courant=>null(), suivant=>null()

39 TYPE(point), POINTER :: precedent=>null()

45 WRITE(*,*) courant%x, courant%y, "supprimer ? 1 si oui"

46 READ(*,*) suppr

47 IF (suppr == 1) THEN

48 precedent%next => courant%next ! court-circuiter le point courant

49 DEALLOCATE(courant) ! libération du point courant

50 ELSE

58 ! ajout d’un point (intérieur seulement)

59 TYPE(point), POINTER :: debut

60 TYPE(point), POINTER :: nouveau=>null(), suivant=>null()

61 TYPE(point), POINTER :: precedent=>null()

67 WRITE(*,*) precedent%x, precedent%y, "insérer ? 1 si oui"

68 READ(*,*) ajout

69 IF(ajout == 1) THEN

70 ALLOCATE(nouveau)

71 nouveau%next => precedent%next

72 precedent%next => nouveau

73 WRITE(*,*) "entrer x et y"

74 READ(*,*) x, y

75 nouveau%x = x

76 nouveau%y = y

77 ENDIF

78 precedent => suivant

79 IF (.NOT.ASSOCIATED(suivant%next)) EXIT

80 END DO

81 END SUBROUTINE insere_point

82 END MODULE m_chaine

84 PROGRAM linked_list

85 USE m_chaine

86 INTEGER :: i, n

87 TYPE(point), POINTER :: courant => null(), suivant=>null()

88 TYPE(point), POINTER :: debut => null()

89 ! construction d’une liste chaînée de n points

90 WRITE(*,*) ’entrer le nb de points’

91 READ(*,* ) n

92 ! premier point qui permettra l’accès à toute la chaîne

93 ALLOCATE(debut)

94 courant => debut

95 DO i = 1, n-1

96 courant%x = REAL(i)

97 courant%y = -REAL(i)

98 ALLOCATE(suivant)

99 courant%next => suivant

100 courant => suivant

101 END DO

102 ! dernier point sans successeur

103 courant%x = REAL(n)

104 courant%y = -REAL(n)

105 courant%next => null() ! fin de la liste

106 WRITE(*,*) "impression dans le sens direct"

107 CALL imprime_chaine(debut) ! impression dans le sens direct

108 WRITE(*,*) "impression dans le sens inverse"

109 CALL imprime_chaine_inverse(debut) ! impression en sens inverse

110 WRITE(*,*) "suppression de points"

111 CALL supprime_point(debut) ! suppression de points intérieurs

112 WRITE(*,*) "impression dans le sens direct"

113 CALL imprime_chaine(debut) ! impression dans le sens direct

114 WRITE(*,*) "insertion de points"

115 CALL insere_point(debut) ! insertion de points intérieurs

116 WRITE(*,*) "impression dans le sens direct"

117 CALL imprime_chaine(debut) ! impression dans le sens direct

118 WRITE(*,*) "libération de la chaîne"

119 CALL libere_chaine(debut) ! libération de la chaîne

120 END PROGRAM linked_list

données 1

pointeur

données 3

pointeur pointeur

données 2

pointeur

Figure11.2 – Suppression d’un élément intérieur d’une liste simplement chaînée à trois éléments

Chapitre 12

Inter-opérabilité avec le C

La standardisation de l’interfaçage entre les langages C et fortran est intervenue seulement avec la norme fortran 2003. Elle permet de rendre portables les appels de fonctions en C depuis le fortran et réciproquement. Elle s’appuie sur la définition en fortran d’entités (types, variables et procédures) dites inter-opérables car équivalentes à celles du langage C.

La construction d’un exécutable à partir de code C et de code fortran nécessite une compilation séparée avec des compilateurs C et fortran compatibles, puis une édition de lien qui fournisse toutes les bibliothèques nécessaires. En particulier dans le cas où le programme principal est en C, il faut spécifier explicitement la bibliothèque du fortran

lors de l’édition de lien si elle est lancée par le compilateur C1. Une autre solution consiste à confier l’édition de lien au compilateur fortran associé, quitte à lui indiquer par une option2 que le programme principal n’est pas en fortran.