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.