Académique Documents
Professionnel Documents
Culture Documents
en Fortran
2e édition
AUX EDITIONS EYROLLES
Du 111111~ a1tlt!1tr
Programmer
en Fortran
2e édition
EYROLLES
ÉDITIONS EYROLLES
61, bd Saint-Ocm>ain
75240 Paris Cedex 05
www.edilions~rollcs.com
E111~>pl b11 iondc la loidu 11 llWS 1957. il C'.$1 intctdhdcrcprOOuirc Îl)lé.gn1lc1ncn1 ou particlk-mcn1 k: présent
'u1vn1v vrr1prl1pr <iJ'f'f'l\1'1 tpr fY' ~i l U.M l 's11111nn~11lnn1,,.. 1·f.rtil,..1rrn11t•1C'rntr-r f:'mnç11ic:1rr'ICrlr.i u1rinn
du droil de oopC. 20. rue cb: <IMds Augustins. 75006 Paris.
0 C'.mupc l~yrolk: '-. IW7. 2015. ISBN: 978-2-212-1402().0
AVANT-PROPOS
Bien qu'exio;tant depui<i de nombreuses décennies, Fo1tran a touj ow·s su évoluer pour conserver
s.a supré1natie dans le do1naine du calcul scientifique.
Après ses premières nonnalis.ations (Fortran 66 et Fortran 77). w1e. évolution radicale a eu lieu
avec la nonne Fortran 90. Elle en a fait un "vrai langage sttucturé" et elle a amélioré ses
possibilités de "progratn1nation modulaire". notamment grâce à la notion d'interface. Si cette
nonne s'était limitée à cela, Forb·at1 90 aurait déjà possédé des qualités que l'on ne retrouvait
pas simultanément dans les langages des années 1990. Mais, elle est allée beaucoup plu.<i loin
en introduisant :
des possibilités de 1nanipulation de tableaux, à la fois pui<;..c;.a ntes et concises, sans véritable
équivalent dans les autres langages•. particulièrement bien adaptées au calcul vecto1iel ou
parallèle;
la gest ion dynamique, par le biais de pointeurs ou de tableaux allouables ~
1. Fottrsn 77 élai1déjâ supérieur aux ~tul!cs lsng.sgcscn msiiérc d' cn1téc-sot1ic <k: 1sblcsux.
VI Avant·propos
Par la suite, si la nonn e For tran 95 (qui a notamment introduit l'insb·uction /oral/ s pécifique
au calcul paralJèle) n 'a 001l.'it itué qu'une évolution mineure, Fortran 2003, en revanche, a doté
le langage de réelles fo nctionnalités de Program1nation Orientée Objet . tout en en amélia·ant
ses possibilités de gest ion dynamique. en le dotant (facultativement) de mécanismes
d'interopérabilité avec le langage C. Enfi n, For tran 2008 a s w1out apporté quelques
améliorations dest inées au calcul parallèk- (co·tableaux) ou au développement de gros
programmes (sous.modules).
Cet ouvrage est dest iné à tous ceux qui souhaitent 1naitriser la programmation en Forb·an:
étudiants des di<i.Ciplines scientifiques, chercheurs ou ingénieurs, enseignants de ce langage. JI a
été conçu sou.-; forme d' w1 cow·scomplet :
c haque notion importante est illu.o;trée d'un programme d'école1 monb·ailt comment la
mettre en œuvre dai1s un contexte r éel~ celui· ci peut également se1vir :
*à w1e. prise de connai'i..sance intuitive ou à w1e. révision rapide de la notia1 en quest io n~
*à w1e. expérimentation directe dai1s votre environnement de travail~
*de point de dépa11 à une e.xpé1i mentation personnelle~
nous avons c herché à être prog re~<;..o;if et nous avons systé1natiquement évité les "références
avant", ce qui signifie que la compréhension d'un pas.sage dom1é ne fai t intervenir que ce
qui pr écède~ il est ainsi po.<;..o;ible d'étudier l'ouvrage de faço n séquentielle,
la plupart des c hapitres sont dotés d'exercices corrigés en fi n de volume. Ils vous
permettront de contrôler 1'acquisition de vo.o; connaissances.
D'une 1nanière générale, l'ouvrage s'adre~<;..o;e à w1 "lecteur type" po.<i..'iédant déjà quelques
rudiments de program1nation (éventuellement Fo1tran 77). La pré~o;e nte édition tient compte
des différentes versions du lai1gage. Néanmoins. le discours privilégie Forb·ai1 90/95 (qui reste
toujours très utili<ié). Lors.que cela s'est avéré j u.-;t ifié, les différences avec Forb·ai1 77 ou les
appo11s des nonn es 2003 et 2008sont mentionnées au fil du te.xte.
En plus de son c ai·actère didactique, nous avons conçu cet ouvrage de 1nanière à facili ter sa
001l.o;ultation lors de la recherche d'une infonnation précise :
les c hapitres sont fortement s b·ucturés ~ceci pennet une première recherche au niveau de la
table des 1natières ~
au fil du te.xte, des encadrés viennent récapituk-r la syntaxe des différentes instructions du
lai1gage ~sachez qu'ils sont toujow·s exhaustifa, quitte à mentiom1er des point-; non encore
abordésl ~
de nombreuses annexes font le point sur certains aspects, au demeurant techniques, dont la
présentation exhau.<itive dans le texte principal aw·ait nuit à la cla11é de l'exposé:
muhiplicité des fo nn es de déclarations. descriptew·s de fonnat. variantes des types de base,
typ e complex, inst1uctions obsolètes, description de 1'ensembk- des fonctions intrinsèques.
l. Cœi n•cs1 pss ooo.usdictoirc 11vcc le fui! d'éviter dc-stéfétcnccssvsn.1: ici. il ne s>sgi1Qu.'.!' de- mcmioo.ner l'cxistcnœ
de- certains poin1sdon1 ls coo.tHtisssncc n•csi nullcmcn.1 n6ccssaitc il ls comptéhcnsioo du oouts.
TABLE DES M ATIERES
Ce chapitre vous propose tout d'abord une première approche du langage Fortran 90,
basée sur un exemple commenté. Nous vous montrons, de manière pour l'instant
"informelle"', comment s'expriment :
- les instructions de base que sont les déclarations de variables, faffectatioo, la lecture
et l'écriture,
- deux des structures fondamentales : boucle avec compteur et choix.
Cela nous permettra dans les prochains chapitres d' illustrer chaque notion importante
d'exemples complets de programmes, avant que nous n'ayons réalisé une étude détaillée de
toutes les instructioos qui le constituent.
Nous dégagerons ensuite les r~es générales qui s'appliquent à l'écriture d'un programme
en Fortran 90 (identificateurs, mots clés, format des lignes ...). Vous serez ainsi en mesure,
dès le débu~ d'expérimenter les programmes propœés, de les adapter, voire d'écrire les
vôtres (ne serait-ce que ceux correspoodant aux exercices proposés!).
2 1. Généralités sur Fortran CXJ
progra11 racines_c:arrees
integer : : i . nrac • 5
real : : valeur, racine
pr int • , 'Bonjour - je vai s vous calcul er ' , nrac, ' racires carTees •
do i • 1. nrac
pr i nt • , ' Oonrez un nolbre ·'
read • , va leur
i f (va l eur >• 0) tllen
racine • sqrt (valeur)
pr int • , 'l e nolbre ' ,val eur, ' a pour rac ine: 1
, racine
else
pr int • , ' le nolfbre ' , valeur, ' ne possede pas de rac ire'
end if
end do
print • , ' Trava il ter111ire - hJ revo i r '
end
Donnez un nolfbre :
l.2Se32
le nomre l .250000Œ+32 a poor rac ine 1. 118034Œ+l 6
Donnez un rolfbre :
0.9
le nomre 0.9000000 a pour racine : 0.9486833
Donnez un rolfbre :
end
L'en-tête est facultatif. Lorsqu'il est présent, le nom de programme (ici 1"Cines_cames)
doit être écrit suivant les conventions applicables à tous les 'identificateurs• (elles seront
présentêes dans le paragraphe 2).
Entre ren:tête et l'instruction end, on trouve (comme dans la plupart des langages) des
instructions de ' déclaration' et de.~ instructions 'exécutables' . Les instructions de
déclaration doi>enL, en Fortran 90, toujours précéder les instructions exécutables. Plus
tan.I. nous '.errons qu'en outre ces déclarations doivent respecter un certain ordre.
i nteger .. i . nrac • S
real : : valeur, rac i ne
2. Rn toute rigueur, nous devrions dire un "programme principal• ; majs cette distinction ne se justinera que
bn;que notS aurœs abordél'étudedcsprootdurcs.
4 1. Généralités sur Fortran 90
sont des 'déclarations'. La première précise que les variables i et nrac sont de type integer
(entier), c'est-à-dire destinées à contenir des nombres entiers (relatifs). Nous -errons qu'il
est possible, en Fortran 90, de définir plusieurs sortes de types entiers (pour finstant, nous
utilisons, en quelque sorte, un type entier 'par défaut").
Notez que, dans cette déclaration de type, nous avons écrit nrac = 5 et non simplement
1uuc. On dit quenrac a été ~nitialisée' (ici à la valeur 5) lors de sa déclaration. Autrement
dit, lorsque notre programme ccmmencera à s'exécuter, la variable nrac contiendra la
valeur 5; bien entendu, cela n'empêche nullement que sa valeur évolue par lasuite3 (ce qui
n'est pas le cas dans le présent programme).
La seconde de ces déclaratioos précise que les variables valeur et racine soot de typerea/,
c'cst-à-cjire destinées à contenir des 'nombres flottants' (approximation de nombres réels).
Là encore, nous verrons qu'en Fortran 90 il existe plusieurs types de flottants.
Remarque Importante :
L'instruction :
'Bonjour - j e vais vous cal ru ler ' , nrac, ' racines carrees'
3. JI ne raut pas cotiondrc une telle déclaration avu: oe que J'oo nomme g6t~ralement une ~constante
symbolique·, é'csHi-dirc unsymbok dont la wdeur ne peut t \Oluerau o::>ursdu programme ; oela s'Obtiendr~ en
Fortran 90, à l'aide de l'attribut pa.rameter.
4. Notez que œtte sortie sta.ncfard peut, suivant les eu, t trc as:socih à un «ran ou à une imprimante.
Naturdlement, la manière dtcrire un programme n'est pas la mfme dans les deux cas : dans le premier, on peut
'interagir" av« l'utilisateur ; cc n'est pas le cas dans le sccood. k~ nous avoos supp>Sé que oene sortie standard
était un tcran.
1. Généralités sur Fortran 90 5
Le symbole • qui préœde la liste des informations précise qu'on souhaite les écrire suivant
un 'format par défaut". Nous Yerrons plus tard, dans le chapitre consacré aux "entrées-
sorties conYersationnelles' comment imposer nous-mêmes un format de notre choix.
Ici, nous demandons d'écrire trois informations différentes:
Remarque:
Comme nous le verrons, il existe en Fortran 90 plusieurs façons d'effectuer une répétition
(on dit aussi une "boucle). Ici :
do i • 1. nrac
demande de répéter les instructions suivantes (délimitées par rinstruction end do), en
attribuant à la variable i sucœssivement les valeurs 1, 2... nrac. li s'agit d'une classique
'boucle·avec compteur".
L'instruction suivante :
read *, val eur
lit sur l'entrée standard6, suivant un format 'par dêfaut", une valeur qu'elle affecte7 à la
variable valeur. Nous verrons plus tard ce qu'est exactement ce format par dêfaut pour les
nombreS réels (pour l'instan~ l'exemple d'exêcution vous en donne dêjà ure bonne idée!).
Remarque :
Chaque instruction print provoque, à la fin de l'affichage, un changement de ligne.
Manifestemen~ dans certains cas d'interrogation de l'utilisateur, il serait plus judicieux
d'éviter ce pMnomène de manière à ce que sa réponse apparaisse à la suite de la
question posée (ce n'était pas Je cas ici). Ceci est effectivement possible en Fortran 90;
il vous faudra toutef<is attendre le chapitre relatif aux fichiers pour ~ir comment
procéder.
Les lignes:
constituent une instruction de choix basée sur la condition valeur > = 0 (elle est vraie si la
valeur contenue dans la variable ~leiu est positive oo nulle). Si cette condition est vraie, on
exécute les instructions :
La fonction préd~nie8 sqrl fournil la valeur de la racine carrée d'une valeur flottante
qu'on lui transmet en •argument". L'instruction :
Tout d'abord, sachez que Fortran 90 accepte tout ce qui était légal en Fortran 77. Dans ces
conditions, on pourrait considérer qu'il suffit d'étudier simplement les nouveautés
apportées par Fortran 90. En fait, les choses sont un peu plus oomplel<lls dans la mesure où
Fortran 90 permet également d'exprimer différemment (géreralement mieux) certains
points.
Ainsi, en Fortran 77, les instructions devaient être écrites suivant un "format• assez
rigoureux (colonnes 1 à 5 pour les étiquettes, colonne 6 pour les lignes "de suite" •.). En
Fortran 90, il n'Clliste plus aucune contrainte de ce genre : comme vous pouvez le ~ir sur
notre el<llmple, nos instructions peuvent commencer en n'importe quel emplacement d'une
ligne.
De même, Fortran 90 a homogén~sé les dé<:larations; pour finstant cela peut apparaître
comme une contrainte lorsque l'on écrit!
alors qu'en Fortran 77, on se serait contenté de ceci (qui reste accepté par Fortran 90) :
8. On parlcsouvcntdcfonction"intrinsèque".
8 1. Généralités s ur Fortran 90
En revanche, l'initialisation de la var iabJe nrac au sein de sa déclaration n 'était pas possibJe
en Fortran 77. Il aurait fall u prévoir, en début des instructions exécutables, une instruction
d' affec tation nrac = 5 ou fai re appel à une inst tu ction da1a (devenue désuète en Fortran 90).
Enfin, l'instruction do aurait dû être écrite en faisa nt appel à une étiquette pow· repérer la
dernière inst ruction ~ par exempk- :
do 100 i = 1, nrac
100 continue
Ce par agraphe vou.'i expose un certain nombre de règJes générales intervenant dans l'écriture
d' w1 programme en Fortran 90.
Les identificateurs servent à désigner les différents "objets" 1n anipulés par le programme:
var iables, fonctions. no1n 'i de typ es.. Comme dans la plupart des langages. ils sont formés
d' w1e s uite de c aractères c hoisis parmi les lettres ou les chiffres, le premier d'entre elLx étant
néces..sairement w1e lettre.
• le caractère "souligné" (__) est considéré comme une Jettre. Il peut donc apparaitre en
début d'un identificateur. Voici quelques identificateurs corrects:
lg_lig valeur_5 _Iota/ _89
• k-s 1n aju.<icules et les min us.cules s ont autorisées mais (comme en Pascal) on n e les
dist ingue pas les unes des autres. Ainsi racine et Racine représentent le même
identifica teu r.
La longuew· d'un identificateur est limitée à 3 1 caractères9 (63 à partir de Fo1t ran 2003).
progra11 b izare
integer : : rea l • 1
real : : integer • 2.5
pri nt • . rea 1. i nteger
end
1 .0000000
b) Les séparateurs
Dans notre langue écrite, les différents mots sont séparés par un espace, un signe de
ponctuation ou une fm de ligne. Il en va presque de même en Fortran 90 : deux
identificateurs successifs entre lesquels la syntaxe n'impose aucun signe particulier (tel que
: , = • + - ()etc.) doi-ent impérativement être séparés soit par un espace, soit par un
10 1. Généralités sw· Fortran 90
changement de ligne (dans ce cas. toutefois, appar aitra en plu.<i, au moins un caractère de suite
• nou.'i y reviendrons un peu plus loin).
En revanche, dès que la S)Utaxe impose un sépar ateur quelconque, il n 'est pas nécessaire
d'introduire d'espaces suppJémentaires ~ cela est toutefois penni'i et améliore généralement
grandement la lisibilité du programme.
et non :
doi = 1, n'lal
est équivalent à:
print ', 'donnez un nombre'
read ', n
est équivalent à :
print •, 'abscisse ' .valeur. 'ordoonee ' . resultat. 'precision' . epsilon
Si l'on souhaite 'couper• une in!lruction à l'intérieur d'une chaîne, il est nécessaire de
prévoir (outre le caractère & de fin de la première ligne) que le premier caractère non
blanc de la ligne suivante soit, lui aussi, un &1 0. Par exemple, ces in!lructions:
10. E.n toute rigueur, cette contrainte pro.rient de la lbertt que vous offre fortran d'introduire une ligne
commentaire (VO)'CZ le pa.rngrnphe 2A) entre cesdeuw: lignes.
12 1. Généralités sur Fortran 90
2. 4 Les c ommentaires
Dés lors qu'un caractère ! ligure dans une ligne, tout ce qui le suit, jusqu'à la fin de la
lignes est considéré oomme un commentaire. En voici un exemple:
i f (va leur >• 0) then ! on s ' assure que 1e !'Dlbre n' est pas négati f
Naturellement, cette possibilité peut être exploitée pour écrire des lignes complètes de
commentaires (le caractère ! pouvant être placé n' importe o~ avant le te xte concerné)
comme dans :
Notez qu'il n'est pas possible d'introduire un commentaire entre deux instructions d'une
mê me ligne (puisque alors la seconde instruction fera partie du commentaire) ; par
exemple, dans :
Remarque:
le caratère & peit apparaître dans un commentaire: il n'a alors aucune signification ;
le caractère ! peut apparaître dans une chaîne: il s'agit alors d'un caractère (comme un
autre) de la chaîne.
On peut insérer une ligne commentaire (c'est-à-dire une ligne ooŒ le premier caractère
non blanc est un !} entre deux lignes différentes d'une même instruction ; nous vous
conseillons d'éviter cette possibilité qui nuit à la lisibilité des programmes_
Dans le format fixe, la notion de séparateur n'exi!le plus (il n'est plus nécessaire de séparer
deux identificateurs par un espace) et, de surcroît, l'espace est sans significationll. Ains~
n'importe laquelle de ces lignes :
doi • 1. nrac
d o i • 1. n rac
do i • 1. nrac
Remarque :
Les deux formats (libre et fixe) sont incompatibles. Il est donc nécessaire de préciser,
lors de la compilation, quel est le format utilisé. Généralement, sans information
précise de votre part, le compilateur considérera qu'il a affaire à du format libre. Notez
que, grâce aux possibilités de "compilation séparée'' offertes par Fortran, il vous sera
toujours loisible de "récupérer" des routines écrites en Fortran 77 (donc en format fixe),
sans are pour autant contraint d'utiliser ce format, manifestement désuet, pour le
logiciel que vous développerez.
11. N'oW'ez pas que Je seul intérttdece format futeest de permettre decomp~e ren Fortran 90 des programmes
écrits en Fortran 71.
Il. LES TYPES DE BASE DE FORTRAN 90
INTEGER, REAL,
DOUBLE PRECISION ET LOGICAL
Les types i111eger et re(J/ quç nous a-.ins déjà rencontrés sont souvent dits "scalaires• ou
"simples• car, à un mcment donné, une variable d'un tel type oontient une seule valeur. Ds
s'oppœent aux types dits "agrégés1' qui correspondent à des variables2 qui, à un moment
donné, contiennent plusieurs valeurs. Le cas le plus oourant de type agrégé ~ le tableau
qui est formé d'un ensemble de valeurs de même type ; nous verrons que Fortran permet
également de définir des "structures", dans lesquelles sont associées des valeurs de types
quelconques.
Ici, nous allons étudier en détail les types simples permettant de représenter des nombres
entiers (i111eger), des nombres réels (real et double precisi<m) et des valeurs logiques
(!ogicol), c'e!t-à-dire des valeurs du type "vrai/faux".
1. On parle aus:si de types strut turû, mais oc terme est plus ant>igu, dans la mesure où f un des 1ypC$ agrtgés de
Fortm.n 90 ut le type structure.
2. Attention. le terme de va.riabJc n'a pas la me.me signification daœ tous les langages.. C'est ainsi qu'en Fortran
71 . on rûervaît traditionneUement cc terme aux variables de type $Cll.1aîre (on parlait de variables indicé.es pour
des Séme:nts d'un tableau), Mais le seul type agrégé était a101S le tableau. En Fortran 90, on va disposer de
beaucoup de types ~gû et il devient utile de disposer d'un mot permettant de dtsigner n'importe quel ~Objet•
d'un type quekœque. Ici, nou.s utmserons à oet effet le mot vaiiablc i lorsqu'il sera n6oea:aire d't tre plus pr&is,
nous parlerons aJcn de variable simple., de tabJeau, de stnicturc., d'tJtment de tabJeau, dccbampdestructure_
16 il. Les types de base de Fortran 90: integer, real, double precision et logical
Notez bien que nous laisoons momentanément de côté deux types particuliers qu'on peut
considérer à la fois comme des types simples et des types structurés, à savoir le type
"complexe" et le type "chaîne de caractères". Ceux-ci seront abordés ultérieurement
1 - LA NOTION DE TYPE
La mémoire centrale est un ensemble de "positions binaires' nommées bits. Les bits sont
généralement regroupés en octets (8 bits) et chaque octet est repéré par œ qu'on nomme
son adresse.
0 100110 1
vous pouvez considérer que cela représente le nombre entier 77 (puisque le motif ci-dessus
correspond à la représentation en base 2 de ce nombre). Mais pourquoi cela
représenterait-il un nombre? En effet, toutes les informations (nombres entiers, nombres
réels, nombres complexes, caractères, instructions de programme en langage machine,
graphiques ...) devront, au bout du compte, être codées en binaire.
Dans ces conditions, les huit bits ci-dessus peuvent peut-être représenter un caractère;
dam ce c~. si nous connaissons la convention employée sur la machine concernée pour
représenter les caractères, nous çouvons lui faire correspondre un caractère donné (par
exemple M, dans le cas du code ASCU). Ds peuvent également représenter une 'partie'
d'une instruction machine ou d'un nombre entier codé sur deux octets, ou d'un nombre
réel codé sur 4 octets, ou ... autre chose.
On comprend donc qu'il n'est pas possible d'attribuer une signification à une information
b inaire tait que Pon ne coona\\ pa.< la manière dont elle a été codée. Qui plus est, en
général, il ne sera même pas possible de "traiter" cette information. Par exemple, pour
additionner deux informations, il faudra savoir quel codage a été employé afin de pouvoir
mettre en oeuvre les "bonnes' instructions3 (en langage machine).
J. l~ exemple, on ne f'ait pas awd al.O: mCJnes: cirwits: tlectroniqucs pœr additiœner deto: nombres cOOts: $0\IS
fonne •entière• et déLP: ncmbrcs cOOts: sous tonne "flottante•.
II. Les types de base de Fortran 90: integer, real, double precision et logical 17
D'une manière générale, la notion de type, tclle qu'elle existe dans les langages évolués,
sert à régler (entre autres choses) les problèmes que nous venons d'évoquer.
Pour chacun des types que nous allons étudier dans ce chapitre, nous préciserons :
2 - LE TYPE INTEGER
Le type i111eger permet de représenter des nombres entiers relatifs. Pour ce faire, on utilise
un certain nombre d'octets (ce nombre dépendant de la machine concernée). Un bit est
réservé pour représenter le signe du nombre (0 correspond à un nombre positif et 1 à un
nombre négatif). Les autres bits servent à représenter la valeur absolue du nombre4.
Les limitations inhérentes au type integu dépendent de la machine. Voici des valeurs
usuelJesS correspondant à des entiers codés sur 16 ou 32 bits :
Pour introduire une constante entière dans un programme, il vous suffit de l'écrire sous la
forme (décimale) habituelle, avec ou sans signe, comme dans :
+533 48 -2894
Il est également possible de fournir des con!lantes écrites en base 2 (binaire). 8 (octale) ou
16 (hexadécimale). Dans ce cas, on place la valeur correspondantes entre apostrophes et
on la fait précéder de l'une des lettres B (pour binaire). 0 (pour octal) ou Z (pour
hexadécimal) comme dans ces exemples:
4. Flle peut t tre représentée 'naturellement", c·'est-à-<Jire par sœ codage direct en binaire oo par oequ•on nomme
son •oomptément à dwc•, Cette dernière tedtnique a le mérite de ne demander q'1'un seul •âfQlit électronique"
pour réaliser une opération donnée (addition, par exem,:te) aussi bien S\lr des nombres pos:itifs que S\lr des
nombres négatif&. Eue a d'ailleurs tendance à se.généraliser.
S. L'amptitude des nombres négatifs peut diminuer de 1 Jonque rcn n'emptoie pas la tecbni(fJe du oomptément
A2.
18 li. Les types de base de Fortran 90 : integer, real, double precision et logical
Remarque:
Les limitations imposées par le type integer varient d'une machine à une autre, ce qui
peut nuire à la portabilité absolue des programmes. Le Fortran 90 a introduit la
possibilité de définir des tyçes entiers dont on fixe explicitement les limitations (en
nombre de chiffres décimaux). ce qui, en théorie, devrait permettre d'améliorer la
portabilité des programmes.
En fait, cette possibilité s·a~re en pratique moins séduisante qu'elle n'y paraît a priori
En effet, on n'a aucune assurance sur le fait que la machine concernée pourra
représenter effectivement des entiers de la taille demandée, de sorte qu'un programme
donné pourra être compilé correctement sur telle machine et rejeté sur telle autre!
Nous parlerons plus en détail de ces 'variantes du typeintegel' dans rannexe B.
3 - LE TYPE REAL
représente une approximation de ce nombre. La base Best généralement unique pour une
mac hine donnée {il s'agit souvent de 2 ou de 16) et elle ne figure pas explicitement dans la
représentation machine di nombre.
6. Sauf brsque Pœ dC>it faire une analyse fine des erreurs decakul.
Il. Les lyçes de te.se de Fortran 90: integer, real, double precision et logical 19
- la prédsio11 : lors du codage d'un nombre décimal quelconque dam un type flottant, il
est nécessaire de ne conserver qu'un nombre fini de bits. Or, la plupart des nombres
s'exprimant avec un nombre limité de décimales ne peuvent pas s'exprimer de façon
exacte dans un tel codage- On est donc obligé de se limiter à une représentation
approchée en faisant ce qu'on nomme une "erreur de troncature'.
- le domai11e couve11, c'est-à-dire l'ensemble des nombres représentables à l'erreur de
troncature pres.
Sur beaucoup de machines, le type rea/ est représenté sur 32 bits; suivant le codage em-
ployé, on obtient des nombres pouvant couvrir des domaines allant de (10-38, 1<>38] à (10' 78,
101:1] avec une précision relative de l'ordre de 10-6.
- décimale,
- exponentielle.
La notation décimale doit comporter obligatoirement un point (correspondant à notre
virgule). La partie entiêre ou la partie décimale peuvent être omises (mais, bien snr, pas
toutes les deux en même temps!). En voici quelques exemples corrects:
Par contre, la constante 47 serait considérée comme entière et non comme flottante. Dans
la pratique, ce fait aura peu d'importance7, compte tenu des conversions automatiques qui
seront mises en place par le compilateur (et dont nous parlerons dans le chapitre suivant).
Remarque:
Comme le type i111eger, le typereal a l'inconvénient de ne pas correspondre aux mêmes
limitations sur toutes les machine~ Ici encore, Fortran 90 a introduit la possibilité de
définir des types dans lesquels on choisit les limitations, à la fois en domaine et en
précision. Ainsi, théoriquement, vous pou..ezdéfinir un type permettant de représenter
des réels s'étendant de 10·• à 10" a..ec une précision relative de lO'P (en choi~nt
vans-même les valeurs de net de p). Mais, ici encore, cette possibilité s'avérera peu
intér=te en pratique, dans la mesure où vous n'aurez jamais l'assurance de pouvoir
disposer d'un type ainsi défini sur toutes les machines. Un programme donné pourra
donc être compilé correctement sur telle machine et rejeté sur telle autre!
Nous parlerons plus en détail de œs 'variantes du type real" dans l'annexe B.
La norrne du Fortran 90, comme celle du Fortan 77, prévoit que, dans tous les cas, il existe,
outre le type real dont nous venons de parler, un type dispœant d'une plus grande
précision (mais pas né~rement d'un domaine plus étendu) e t nommé double precision.
Beaucoup de machines représentent un tel type sur 64 bits avec une précision relati..e de
l'ordre de 10-ts.
Les constantes du type double precisio11 doivent s'écrire obligatoirement sous forrne
exponentielle en utili~t la lettre D (ou d) à la place de la le ttre E (ou e). Par exemple
O.JeO et 0.JdO représentent toutes deux une approximation de la valeur réelle 0,1 maiS la
seconde est plus précise.
Remarque :
Contrairement à ce qui se p~it pour les types i1teger e t rea4 il n'existe pas de
"variantes du type double precisio11". Cela est, de toute façon, inutile puisque de telles
variantes sont en fait contenues dans celles du typereal.
Il. Les types de base de Fortran 90: integer, real, domle prccision et logicfil 21
5 - LE TYPE LOGICAL
Ce type "logique" peut ne pas apparaître d'emblée comme aussi nécessaire et naturel
que les trois autres types scalaires que nous venons d'étudier. C'est pourquoi nous
allons l'illustrer de quatre petits exemples complets.
range • n<p
print .
i f (range) then
'croissant'
e lse
pr i nt
end i f
. 'non cro issant '
end
Cette fois, la valeur de l'expression logique n < p est affectée à la variable nommée ronge,
laquelle a été déclarée de type logicaJ. Cette variable est ensuite utilisée pour effectuer le
choix entre les deux possibilités d'affichage.
Voici un troisième exemple qui vous montre que l'on peut écrire la valeur d'une variable
logique:
Notez que la valeur faux s'écrit simplement F (abréviation de "false"). La valeur vrai
s'écrirait T (abréviation de "true"). Voici enfin un dernier exemple, un peu artificie~ qui
vous montre comment s'écrivent les deux constantes du typelogical,à savoir:
.false. .lrue.
A priori, Fortran 90, comme Fortran 77, ne rend pas obligatoire les déclarations des types
des variables. Si vous cherchez à utiliser une variable qui n'a pas été explicitement
déclarée, Fortran lui attribue "implicitement• l'un des deux types i111eger ou real, en tenant
simplement compte de la première lettre de son nom. S'il s'agit de l'une des lettres i, j, k , l,
m ou n8 , elle sera de type i111eger ; dans tous les autres cas, elle sera de type real.
D'une manière générale, une telle tolérance s'avère plus néfaste qu'utile. En effet,
considérez ce petit exemple :
8. A titre m.X:monique, notez que la suite de ces lettres est "cncad.r«• par les lettres i et n qui oonstituent d es-
mt mes les deux premières lettres du mot integer.
24 Il. Les types de base de Fortran 90: integer, rea~ double precision e t logical
i nteger : : nbre • 5,
k • nbr • l
On a écrit manifestement 1i>r au lieu de 11bre. Dans ce cas, la variable 1i>r sera considfaée
comme une autre variable (ici, de type integer) et, manifestement, elle ne sera
probablement pas définie. Malgré tout, aucune erreur de compilation ne sera détectée9.
implicil none
9. ll n'en va pas ains i dans des langa;es oomme Pascal ou C qui imposent le t~e explicite de toutes let
variables.
Ill. LES EXPRESSIONS ET L'INSTRUCTION
D'AFFECTATION
variable = expression
Nous avons déjà rencontré des exemples:
Toitefois, dans ce cas, les exµ-essions concernées étaient suffisamment simples pour qu'on
en saisisse intuitivement la signification Mais ces expressions peuvent devenir beaucoup
plus compliquées, en faisant intervenir:
l'expression n + p founÎit un résultat de type integer, tandis que x':Y fournit un résultat de
typereaJ.
1. C'est ainsi que $10nl p~vues les instructions de base de la machine. Par exemple, on trouvera, sur une machine
dœn6e. une instruction de multiplieation de deux r6els 32 bits, une instructiœ de multiplicatiœ de deux r6els
64 bits et une multiplicalion de deux entiers mais œ ne trouvera jamais de multi plication d'un Rel 32 bits par un
entier...
Ill. Les expressions et finstruction d'affectation V
Remarques:
1)D'une manière générale, fopérateur /,lorsqu'il porte sur des entiers (relatifs) net p,
fournit un résultat de valeur absolue:
lnl:l pl
où le symbole•:• représente la division entière. Le signe du résultat est celui obtenu par
la règle habituelle. Par exemple, -813 vaut -2. Notez que, dans le cas d'entiers y;sitifs, le
résultat n'est rien d'autre que le quotient entier usuel (division euclidienne) . Ce n'est
que dans les autres cas que l'on aboutit à un résultat pouvant différer d'une unité.
2) Contrairement à d'autres langages comme Pascal ou C, Fortran ne dispose pas
d'opérateur "modulo". Une "fonction prédéfinie" nommée mod permet toutefois
d'obtenir le même résultat.
Contrairement aux opérateurs précédents, rorrateur •• est a priori défmi pour toutes les
combinaisons de types de ses deux opéraides . Toutefois, certaines combinaisons imposent
des restrictions sur les valeurs mêmes des opérandes. Celles-ci sont la conséquence
immédiate de la défmition mathématique de fexponentiation. En effet, il ne faut pas
oublier que, quel que soit le type de x :
xfi - 1
Pwr rentier positif:
xr = x • x • ..... •x (r fois)
x-r = 1 / xr
Potr r réel quelconque :
'f! = er Logx six positif ou nul,
-1! n'est pas cak:ulable pour x négatif
2. Rappelon.s que matb6matiquemed, le quotiententier den pO.r peu un entier q tel que:
n=p•q+r
r <p
3. Mais rappelons que les po$$ibilit6s de oonvet$ion implicite d'un des dewi; o p6randes permettront quand m!me
à un opér&eur de porter sur des opérandes de types: différenrs.
28 III. Les expressions et l'instruction d'affectation
D'autre part, le type du résultat est entier si les deux opérandes sont entiers et réel dans
tous les autres cas•.
Ains~ une puissance entière positive ne pose aucun problème particulier. 2..3 est bien
l'entier 8; de même 25..2 sera un réel de valeur (approehée) 6,25. En revanche, 2 ..(-3)
est l'entier calculé par la formule 1/(2..3), soit 1/8, c'est-à-dire fmalement O!
De même, ( -2.)..(-3) sera le réel obtenu comme étant l'inverse (en réel) de (-2.)..3 qui
vaut -8; on trouvera donc bien, dans ce cas, la valeur (approehée) 1,25. En revanche,
l'expression ( -2)..3. (qui correspondrait au réel obtenu par la formule e3Lot:C-2l) ne sera
pas calculable.
Re ma rt}!I• :
Dans une expression telle que x.. y, il ne faut pas espérer obtenir un diagnostic de
compilation dans les cas où elle n'est pas calculable. En effet, le compilateur ne peut
pas connaître la valeur d'une variable5 qui d'ailleurs, par défmition même, est
susceptible d'évoluer au fil de l'el<l\cution du programme! Ce n'est que lorsque l'on
exécutera l'instruction "coupable" que l'on obtiendra un "message d'erreu.r•6,
génfaalement assorti d'un arrêt de l'exécution.
• I
- ( una ire)
+ -
4. En toute rigueur, le résultat sera de type doWle pree:isicn si l'un dei de1.i1C oplrancJu est de te type; oo
retrou\.era du règles oomparablu lon:que J'œ parlera <J'expressions mktes..
S. Saur, é\.Cntuellement, si l'exposant est une oonstante ou une "expressiœ constante• {oc.ne notiœ sera abord&
un peu plus loin).
6. Ce message signaJera géœraJement que l'on d1erche àcaleuler un logarithme av« un argument négatif.
1. L'anne.xe E rkapitule lu prioritû de tous lu ~rateuri.
Ill. Les expressions et l'instruction d'affectation 29
En cas de priorités identiques, les calculs s'effectueit de "gauche à droite". Une exception
a touterois lieu pour l'opérateur •• pour lequel les calculs s'effectuent de droite à gauche
(pour respecter les habitudes mathématiques).
Enfin, des parenthèses permettent d'outrepasser ces règles de priorité, en forçant le calcul
préalable de fexpression qu'elles contiennent. Notez que ces parenthèses peuvent
également être employées pour assurer une meilleure lisibilité d'une expression.
Voici quelques exemples dans lesquels fexpression de droite, où ont été introduites des
parenthèses superflues, montre dans quel ordre s'effectuent les calculs (les deux
expressions proposées conduisent donc aux mêmes résultats) :
a + b• c a+(b ' c)
a•b+c / d (a•b)+(c/d)
- c / d - Cc /d)
-a+ c/d ( - a)+(c/d)
- a/(b+c) -(a /{b+c))
a • b •• c a • (b • c)
Remarques :
1) On peut, bien sOr, contmeen mathématiques, trouver, dans une expression, un appel
d'une fonction (comme danssqrt {valeur)).
2) La norme prévoit que l'ordre exact des calculs dans une partie d'expression ne
comportant pas de parenthèses peut être modifiée par le compilateur si cela ne modifie
pas la valeur thtorique de l'expression. Par exemple, dans l'expression :
a + b + c
le calcul pelt se faire indifféremment comme (a!b)/c ou comme a/(b•c) (cela peut se
produire dans le cas d'une machine où la multiplication est plus rapide que la di~sion).
Si, mathématiquement, les expressions réellement calculées sont identiques à celles
effectivement écrites dans le progranune, il n'en reste pas moins que l'ordre des calculs
a une incidence sur le résultat numérique fina~ et ceci pour au moins deux raisons:
. la précision limitée des calculs,
30 III. Les e>:pressions et finstruction d'affectation
- les risques de dépassement de capacité qui, suivant les valeurs concernées, peuvent
apparailre dans une des formulations et pas nécessairement dans rautre.
Sachez que vous pou-ez cependant imposer un ordre précis aux calculs en faisant appel
à des parenthèses supplémentaires. Par exemple, a-cc :
(a+b)+c
Nous avons vu le rôle des quatre opérateurs binaires + , -, • et/ lorsqu'ils portent sur des
opérandes de même type. Fortran accepte que ces opérateurs portent sur deux opérandes
de types différents. Dans ce cas, simplement, le compilateur met en place des instructions
de conversion de l'un des opérandes dans le type de l'autre. De telles con-ersions, dites
•implicites•, se font toujours en respectant la •hiérarchie• :
integer - > real - > double precision
et ceci afm de ne pas (trop) dégrader les valeurs soumises à des conversions: une valeur
entière convertie en réel n'est pas modifiée de façon importante (tout au plus peut-on,
dans certains cas rares; aboutir à une erreur de représentation).
Voici quelques exemples, dans lesquels nous supposons effectuées les déclarations
suivantes:
inte~r .. n. p
rea l :: x. y
double precision : ; z
n +X
La valeur de n est con-ertie en real, avant d'être ajoutée à celle de x. Le résultat est de
type reaJ.
x•y +z
Le produit x • y est d'abord évalué en real; puis le résultat est converti en double
precision pour être ajouté à la valeur de z. Le résultat est de type double precision.
Dl. Les expressions et finstruction d'affectation 31
X+ D/p
Le quotient n/p est d'abord évalué en ùt eger; puis le résultat est converti en rea/ pour
être ajouté à x. Le résultat est de type rea/. Notez bien que, sin a pour valeur 3, p pour
valeur 5 et x pour valeur 15, le résultat vaudra (315) + 15, c'est-à-dire O+ 15, soit
(environ) 1,5. Pour obtenir 2,1 (0.6 + 1.5), il faudrait éviter la division entière : pour ce
faire, on pourrait remplacer, dans l'expression, n par une variable réelle ayant reçu la
même valeur. La démarche la plus élégante et la plus lisible consiste à utiliser une
fonction intrinsèque nommée real qui convertit un entier en réel ; dans ce cas, on
remplace l'expression précédente par rune des trois suivantes;
x + rea l(n)/p x + n/real(p) x + rea l(n)/rea l(p)
Remaniues:
1) Compte tenu des "Variantes" des types ùteger et rea/ prévues par Fortran 90, les
possibilités de conversions implicites8 sont en fait plus nombreuses. Par exemple, il
faudra considérer que le type i111eger correspond à toute une hiérarchie de types entiers
de plus en plus "grands".
2) Comme nous l'avons déjà évoqué, Fcrtran connai'l le type complex et l'assimile à un
type scalaire. Ce dernier pourra apparai"tre dans des expressions, éventuellement
mélangé avec les types numériques que nous venons d'évoquer; là encore, des
conversions implicites .,Ourra avoir lieu : leur sens sera défini en considérant que le
type ccmplex occupe la première place dans la hiérarchie.
variable = expression
la variable était d'un type (numérique) identique à celui de fexpression (même si
fexpression pouvait être mixte).
Mais Fortran accepte que la variable soit d'un type numérique différent de celui de
fexpression. Dans ce cas, le compilateur met en place une COR\ersion de la valeur de
l'expression dans le type de la variable. Cette fois, une telle conversion peut très bien se
faire sans respecter la lûérarchie dont nous avons parlé précédemment.
Toutes les conversions sont acceptées par Fortran. Mais, comme on s'en doute, dès lors
qu'elles n'ont plus lieu suivait la hiérarchie inleger- >real- >double precision, des
problèmes peu-ent apparai1re en ce qui concerne le résultat de cette conversion.
Plus pr&:isémen~ la con-ersion d'un réel (real ou double precision) x en un entier fournit
théoriquement la partie entière E(x) lorsque x est positif ou nul Cl la valeur -E(-x) si x est
négatif; ains~ 3.75 converti en entier fournit 3; de même -5.75 fournit -5 (notez que la
partie entière, au sens mathématique du terme, serait -6). Mais, si un tel entier n'est pas
représentable dans le type inleger, le résultat est (relati-ement) imprévisible.
De même, la conversion d'une valeur de type double precision en une valeur de type rea/9
fournira simplement un résultat moins pr&:is si la valeur obtenue reste représentable dans
le typereal; dans le cas contraire, le résultat sent, ici encore, imprévisible.
Exemples
integer :: n • S. p • 10. q
real :: X • O.S. y . 1.25, z
Remarque:
Comme nous Pavons déjà dit dans le paragraphe 1.4, il existe des fonctions de
conversion d'un type numérique dans un autre type numérique. Nous avons d'ailleurs
rencontré la fonction real, à laquelle nous avions fourni un "argument" de type integer.
Dune maWère générale, cette fonction peut s'appliquer à n'importe quel type
numérique: integer, double precision ou même un type entier ou réel "généralisé" ou
encore au type complcx (que nous re..:ontrerons plus tard - dans ce cas, on obtient la
partie réelle du nombre).
D'une manière comparable, il existe une fonction nommée int qui convertit en entier
une valeur de n'importe quel autre type numérique. En voici un petit exe.mple:
integer :: n • 3
real :: x • 0.3. y
9. <M encore. compce tenu des variantes, la c:awersioo d'un type réd dan:s un autre type iicl. de moins grand<
précision.
Ill. Les o:pressionset finstruction d'affectation 33
Nous a~ns déjà rencontré des exemples d'expressions logiques dans les précédents
chapitres : il s'agissait de comparaison entre expressio!l'l numériques. Nous allons ici faire
le point sur les comparaisons existames avant de vous présenter les 'opérateun logiques'
et, ou et non. Notez bien que les (nouvelles) expressions logiques que nous serons ainsi en
mesure de <;onstruire pourront intervenir aussi bien dans une affectation que dans
certaines instructioll'l structurées (telles que if).
Fortran 90, comme Fortran 77, dispœe de 6 opérateurs de comparaison. Pour chacun
d'entre eux, vous pouvez indifféremment employec soit l'ancien.ne notation Fortran 77, soit
la nouvelle, manifestement plus pratique (anention, la comparaison d'égalité s'écrit = = et
non • qui correspond à uné affectation!).
Les priorités des opérateurs de comparaison sont inférieures à celles de tous les
opérateurs arithmétiques de sorte que dans une expression telle que a +S < b"z, il n'est
pas utile d'employer des parenthèses (on peut bien sOr les utiliser pour éviter tout doute
lors de la relecture du programme, surtout si Pon est habitué à travailler avec d'autres
langages où les règles de priorité sont différentes!).
. Nous avons vu comment fabriquer des expressions logiques 'simples' à l'aide des
opérateurs de comparaison. Mais Fortran vous permet également de combiner deux
expressions logiques à l'aide des opérateurs logiques classiques e~ ou (inclusif) et ·non .
Ceux-ci se notent 12 :
Par exemple :
a <b .and . c< d prend la valeur vrai si les deux expressions a <b etc <d sont toutes vraies
et la valeur faux dans le cas contraire.
10. Noue verroos qu'ils poa:èdcnt ~gaiement une signlfication pourlcscbaînu dccaractèru. Oc pt.ISi, = = et/=
sont utilisables pour lu oomplcxes.
11. A litreindèatü, avec des Rel s représeŒ~s sur3l bi ~ cet "epdoo maehne· eu de l'ordre de 10.0.
12. Rappelons que, oomme tous les mots dis ou tous lu i:Jcntir.catwri Fortran, ils peuvent indiff'~ent être
tcri ttcn maj U9!ules ooen minuscuk&
Dl. Les expressions et lfostruction d'affectation 35
a< b .or. c < d prend la valeur vrai si l'une au moins des deux expressions a< b et c <d est
vraie et la valeur faux dans le cas contraire. Notez bien qu'il s'agit de ce que l'on nomme un
"ou inclusif': l'expression en question est vraie même si les deux expressions a< b et c < d
sont vraies.
.not. a <b prend la valeur vrai si l'expression a< b a la valeur faux et la valeur faux dans le
cas contraire. Cette expression~ équivalente à a> • b.
En cc qui concerne leurs priorités, les opérateurs logiques se classent ainsi par priorité
décroissante: .not., .and., .or. ; ils ont tous les trois une priorité inférieure à celle de tous
les opérateurs que nous avons rencontrés13. Ainsi n'avons-nous pas besoin de parenthèses
dans les exemples précédents, pas plus qu'il n'en faudrait dans :
Remarque:
integer : : nrac • 5
le compilateur rejétera toute inotruction cherchant à modifier llTOC, par exemple llTOC
nrac + 1 ou nrac • 20 ou reâd "', nrac. En revanch~ il acceptera que ces mêmes actions
soient appliquées à la variablen .
Remarques:
integer nrac
"expressfon constante•, c'est -à-dire une expressfon que le compilateur est capable de
calculer lorsqu'il traduit votre programme,
Cest ains~ que dans une expression constante peut a pparaître une con!lante symbolique
pr~alablement définie :
D'une manière générale, une expression constante peut faire intervenir non seulement des
constantes (symboliques ou non), des opérateurs logiques ou arithmétiques ( toutefois, • •
doit toujours avoir un second opérande de type entier) mais également ce que Fortran
nomme des "fonctions élémentaires14n avec toliefois une restriction importante ; ces
fonctions devront obligatoirement porter sur des entiers (ou des chaînes) et fournir un
entier (ou une chaîne). Pour fixer les idées, disons que les fonctions abs (valeur absolue) et
mod (modulo) sont dans ce cas. Voici un exemple d'instructions correctes :
D'autre part, nous n'avons en fait parlé ici que des "expressions constantes scalaires"; nous
verrons, en effet, qu'il est également possible de définir des expressions constantes de type
tableau 15.
Nous venons de voir comment utiliser une expression constante pour définir une constante
symbolique. Une expression constante peut également servir à ~nitialirer' une variable lors
de sa déclaration :
real .. x • debut
real :: ecart • (fin - debJt) / (,.its-1)
t4. Traduction de l'ar.glaît: "elementaJ fooctioos". N(Q: vcm::ns: ea etfct IJJC les fonctions intrin:sè~es (w
foœtions standardJ)se das:s:eal ea plusieursanégoriesdo..- l'unecorrespc::nd <ttuc fooctionséléme~ires.
lS. En lO~e rigueur, hormis les forv:tions élém~irea:i. il exisle 4 au&res forv:tions (repear. lrim. &ransfer et
surtout reshape)qui peuvcnl appa.rat'lredansune eiq.nss:ioo consta,_e.
38 Ill. Les expressions et l'instruction d'affectation
Remarque :
Certains distinguent les expressions qui oont "théoriquement constantes' de œ lles que
le compilateur est effectivement en mesure de calculer; on parle alors d'expression
constante dans le premier cas et d'expression d'initialisation dans le second. Cette
distinction a généralement peu d'importance, si ce n'est au niveau de l'optimisation du
temps d'exécution d'un programme: une expression théoriquement constante
apparaissant dans une boucle pourra être calculée (éventuellement lors de l'exécution)
avant l'entrée dans la boucle.
EXERCICES
integer : : n • 6, p • 10
real :: x • 1.5
double precision : : z • 5.25
a) p• x - 12
b) z + n/p
c) x + (n + 1.0) / p
d) (p - 7) •• (n-4) " (p-8)
e) ·P" (n-4)
f) p > n
g) z > x .and . p > n
h) n •• p .or . x > z
i) .not. x •• z .and . n - p
j) .not . (x - z .and . n •• p)
Ill Les expressions et l'instruction d'affectation 39
progra11 exoi i i2
i'J) lie i t none
integer : : n. p
real::x,y
logical : : ok
n • 4 ; X • 0. 9
p•n •x: print •, 'A : p
y,. n •X : print •. '8 : y
y • int (n*x) print •, ·c y
p • int (n*x) print "'· 'O
. p
ol< • n~ .and. n>3 print "'· 'E ok
ok • int (n*x) •• n· t print • , ' F ok
end
3) Ecrire un programme qu i lit une valeur réelle représentant la valeur d'un angle en
degrés décimaux et qu i afü:he la valeur correspondante en degrés sexagésimaux {degrés,
minutes, secondes). Rappelons que, par exemple:
1 ·L'INSTRUCTION IF STRUCTURE
Comme nous l'avons déjà mentionné, la même instruction 'if structuré' permet de réaliser
à la fois des alternatives usuelles {choix entre deux possibilités) et des alternatives "en
cascade''. Nous allons en examiner progressivement ces différentes possibilités avant de
récapituler la syntaxe générale de Pinstruction if !lructuré dans le paragraphe 15.
Nous avons déjà rencontré des exemples d'alternatives; ils se présentaient sous une forme
que nous pouvons schématiser comme suit:
La partie introduitre par le mot clé e/se peut ne pas exister, ce qui conduit à la forme
simplifiée:
i f (eJCPression_logique) then
! instructions exécutées quand 1'express ion logique est vraie
end if
Rappelons que Fortran 90 autorise que vous placiez sur une même ligne plusieurs
instructions séparées par des points-virgules. Dans ce cas, il ne faut pas perdre de vue que
chacune des lignes du schéma précédent doit être comptée pour une instruction. Par
exemple, if faudra écrire:
if (a<b) then print " . 'croissant '
else print •. ' oon croissant '
end if
Notamment, il ne faudra pas oublier le point-virgule qui suit le mot IMli ou celui qui sui! le
mot else. Il serait incorrect d'écrire:
if (a<b) then ; print • . 'croissant ' ; else ; print •. 'oon croissant• ; eOO if
RmJarques:
Nctez qu'en Fortran 90, contrairement à d'autres langages tels que Pascal ou C, un bloc
n'est pas toujours délimité par les mêmes mots clés (begi11 et end en Pasca~ { et } en C) 4 ;
ces derniers varient en effet avec finstruction structurée concernée: il peut s'agir par
exemple de 1he11 et else, de the11 et end if. de e/se et end if ou encore de do et end do ...
ou encore:
if (exp_log_l) then
1 exécutées si exp_log_l est vraie
if (exp_log_2) then
1 exécutées si exp_log_l et e)IJ>_log_2 sont vraies
e lse
exécutées si exp_log_l est wai et exp_ log2 est fausse
end if
end if
Ce seoond cas est moins trivial que le premier, dans la mesure oil il n'y a qu'un seul mot clé
else pour deux if Certes l'indentation des instructions suggère bien à quel if se réfère
l'unique mot cléelse ; mais cette indertation n'est pas significative pour le oompilateur qui
considère, en fai~ qu'un else se rapporte toujours au dernier if non enoore fermé. La règle
est d'ailleurs la même dans tous les langages possédant ce type de structure.
Notez bien que si l'on cherche à donner un nom à l'une ou aux deux instructions if
concernées, il n'est pas possible de modifier la règle que nous venons d'évoquer en forçant
par exemple un end if à porter sur une autre instruction. Dans ce cas, on aboutira
simplement à un diagno!lic de compilation.
46 IV. Les instructions de contrôle
if (exp_IOCJ_l) then
1 exp_log_l est vraie
else
if (exp_log_2) then
! exp_log_I est fausse et exp_log_2 est vraie
e 1se
if (exp_IOCJ_3) then
1 exp_log_l et exp_log_2 sont fausses et exp_log_3 est vraie
el se
1 exp_IOCJ_l. exp_log_2 et exp_log_3 sont fausses
end if
end if
end if
if (exp_log_l) then
! e)IJ>_log_l est vraie
else if (exp_IOCJ_2) then
! exp_log_l est fausse et exp_log_2 est vraie
else if (exp_IOCJ_3) then
1 e)IJ>_log_l et exp_log_2 sont fausses et exp_log_3 est vraie
else
1 exp_log_l. exp_IOCJ_2 et exp_log_3 sont fausses
end if
Notez bien que, de par sa nature même, l'instruction else if ne peut apparaître (en un
nombre quelconque de fois) dans une instruction if qu'avant le mot else et ce dernier ne
peut plus figurer qu'une seule fois (toute autre construction n'aurait en fait pas de sens!).
Le paragraphe suivant vous récapitulera la syntaxe complète de l'instruction if.
A titre d'exemple, voici en parallèle deux programmes réalisant la même chose, à savoir
une facruration avec remise. Ils lisent en donnée un simple prix hors taxes et ils calculent le
prix TTC correspondant (avec un taux de TVA constant de 18,6%). Ils établissent ensuite
une remise dont le tai« dépend de la valeur ainsi obtenue, à savoir:
print •, 'doonez le prix hors taxes : print •, 'domez le prix hors taxes
read ", ht· read •, ht
L'instruction if
Avec:
exp _log: expression queleonque de type logical,
nom: identificateur quelconque.
bloc: bloc d'instructions, c'est-à-dire une ou plusieura instructions quelconques
(simples ou structurées).
Nous utilisons ici des "conventions" relativement répandues pour décrire la synblxc du
langage Fortran 90, à savoir :
- les crochets ([ ... Dprécisent que leur contenu est facultatif,
IV. Les instructions de contrôle 49
- lorsque des crochets sont suivis de points de suspension (...), cela signifie que leur
contenu peut apparat1re 0, 1 ou plusieurs fois (c'est le cas de la partie introduite par
else if),
- pour faciliter la lecture, les mois clés sont écrits en majuscules (ils peuvent bien sûr
être écrits en minuscules dans votre programme). De même, nous ne mentionnons pas
la double possibilité : END IF ou ENDIF.
Notez qu'un nom peut apparaître devant le mot if ; il peut être répété après le then de
chaque else if (!orque ce dernier existe)et après lee/ses'il existe.
Remarque:
Lorsqu'une alternative ne comporte pas de "partie else" et qu'en outre la "partie then" ne
comporte qu'une seule instruction simple, on aboutit à une écriture relativement lourde
comme dans cet exemple :
if (x > inax) then
mx = x
end i f
En fait, vous pouvez(en Fo1tran 90, comme en Fortran 77) écrire tout simplement:
Notez bien qu'il riy a plus de mot clé then (l'instruction if (x> max) then max=x serait
incorrecte, malgré son apparente "lisibilité''!).
50 IV. Les instructions de contrôle
Voici la syntaxe générale de cette instruction simple (elle ne fait intervenir aucun bloc!) :
if (exp_log) inst_si""le
L'instruction if logique
Avec:
progra11 exeq>le_se1ect_case
i11p1 ic it ooœ
integer : : n
print "• 'domez ll1 oolbre ent ier '
read • . n
1. Nous verrons en effet quljl existe des "instructions simples nœ exécutables" qui ne sont pllS pour aUlant des
dtcla.rations : l'instnictie>n format.
2. N<>us mentioanonsce point dans un souci de complétude car. en fait, ~s'agit plus d\lnequestion de bon sensf
IV. Les instructions de contrôle 51
i 1 est iroyen
2
OOnnez ll1 nœbre entier
- 11
i 1 est negatif
L'essentiel du programme est constitué d'une instruction (structurée) select case s'étendant
de la ligne select case ( n) jusqu'à la ligne end select. Son rôle est de calculer la valeur de
l'expression figurant à la suite de select case (ici n) et d'exécuter:
. Pinstruclionprilt ", 'il est nul' si cette valeur est 0 (case (0)).
· l'instructionprilt ", 'il est pelil'si cette valeur est 1ou2(case(1,2)).
- Pinstructionprilt •,'il est moyen 'si cette valeur est comprise entre 3et10 (case(J:JO)),
- Pinstruction prilt *,'il est grand' si cette valeur est supérieure ou égale à 11 (case(/ 1:)),
· Pinstruction suivant case (deflJU/t) si aucune des "conditions" précédentes n'est
satisfaite.
52 IV. Les instructions de contrôle
Les indications qui figurent dans les parenthèses suivant le mot case se nomment des
"sélecteurs".
Notez bien que les lignes de la forme case(...) sont des instructions à part entière; en effet,
si l'on souhaitait les placer sur la même ligne que l'instruction suivante, il faudrait utiliser
un point-virgule:
case(O) ;
case (t.2)
Dans notre exemple, à chaque sélecteur ne correspondait qu'une seule instruction; mais il
pourrait·s'agir d'un bloc d'instructions.
Les sélecteurs peuvent faire appel à des "expressions constan tes", c'est-à-dire calculables
par le compilateur - revoyez éventuellement le paragraphe 3.2 du chapitre Ill}. ·par
exemple, avec ces déclarations:
Comme on peut s'y attendre, pour éviter toute ambiguïté, il est nécessaire que les valeurs
figurant dam les différents sélecteurs d'une même instruction select case ne se ''recoupent
pas". Ainsi, avec :
case (2) 2 appartient déjà à 1' interva lie précédent """u erreœ "'u
IV. Les instructions de contrôle 53
select case ( .. . )
case (ma l-3:ma l+3)
case (8)
end se lect
A priori, les instructions sont correctes. Mais si, par la suite, on modifie la valeur de mal
(ce qui est tout à fait normal) en l'amenant à 10, on va créer un recoupement entre 8 et
l'intervalle 10.3:10 + 3. En fait, on peut considérer que rexemple précédent est "mal
programmé'; en effet, il aurait fallu s'assurer non seulement que les sélecteurs concernés
ne se recoupaient pas pour les valeurs courantes des différents paramètres, mais, surtout,
qu'ils ne risquaient pas de se recouper quelles que soient les valeurs des paramètres
concernés. Bien entendu, iç~ pour améliorer les choses, il faudrait connaître le problème
qui a conduit à cette suite d'in!lructions; peut-être, par exemple, que 8 pourrait être
remplacé par 1wal-J2 ou 11val/2-2...
En ce qui concerne l'ordre dans lequel apparaissent les différents sélecteurs, Fortran 90
n'impose aucune restriction, y compris dailleurs sur le case (defauit) qui pourrait ne pas
être le dernier. Pour d'évidentes raisons de lisibilité, il est toutefois conseillé de placer ce
dernier à la fin et de respecter l'ordre naturel pour les autres.
3. N()JS em ~oyooi des noc.alions dont lasignlk'athn a élé dUînie dans te pa.ragra):he lS de oe cbapère.
54 IV. Les instructionsdecontrôle
Remarques :
1) Comme toutes ·les instructions structurées, select case peut comporter un "nom''
(identificateur usuel) et ce oom peut éventuellement être répété devant chaque bloc
concerné et à la fin de lfostruction. Les remarques faites à propos de l'instruction if
structuré s'appliquent bien sûr ici.
2) S'il est possible théoriquement de baser une instruction select case sur le type k>gical,
ceci n'a guère d'intérêt en pratique (une banale "alternative" fait raffaire).
3) Anticipant quelque p>u sur le chapitre relatifauxchaînes de caractères, on peut dép
dire que la possibilité d'utiliser un sélecteur de type character présente un intérêt
manifeste. Par exemple, si la variable rep est de cc type, on pourra utiliser des
constructions de ce type:
se lect cas (rep)
case ( 'oui ' )
case (defaul t)
end select
IV. Les instructions de contrôle 55
4.1 Introduction
Nous avons déjà rencontré cette instruction dans:
OO i • 1. rrac
erd do
Son rôle était alors évident: répéter le bloc correspondant en donnant successivement à la
variable iles valeurs 1, 2,. .. nrac.
do i • 1. 10, 3
end do
do i • 5, 1. -1
erd do
D'une maniêre générale, il est possible d'utiliser des expressions comme valeurs de début,
de fin ou comme incrément, comme nous allons le voir en examinant la synta.ice générale de
cctt e in!I ruction.
56 IV. Les instructions de contrôle
Remarques:
1) calculer les valeurs des expressions debut, fl11 et pas (s'il ne s'agit pas d'expressions
constantes car, dans le cas contraire, ce calcul aura déjà été réalisé à la compilation). et
affecter à var la valeur debut,
2) si pas est positif et que la valeur de var n'est pas supérieure à celle dejù1 ou que pas
est négatif et que la valeur de var n'est pas inférieure à celle de fi11, exécuter le bloc;
dans le cas contraire, mettre fin à la boucle,
3) incrémenter la variable var de la quantité pas et revenir en 2.
On voit que dans certains cas, le bloc concerné peut n'êtreexécutéaucune fois; c'est, bien
sOr le cas avec :
dol • 2, I
do i • ndeb. rma.x.
ou, même, compte tenu de ce que debut et fin peuvent être des expressions {dont la valeur
n'est connue que lors de rexécution) :
Notez que, même lorsque debut,fln ou pas sont des expressions, le nombre de tours est
parfaitement déterminé lors de l'entrée dans la boucles; si, par mégarde, vous modifiez
des valeurs de variables intervenant dans ces expressions, cela n'aura aucune incidence sur
le nombre de tours effectivement réalisés ; par exemple, avec :
p. p • 1
end do
S. D est préâsimeal donné par la fo rmule: n • max (Q, E(6n-debul + pas)/pas), B désignant ta pi.rlie entière ;
ccue fonn\jes'appfque également ai cas (~conseilé) OO tes b0rnessoo1 de type réel.
58 IV. Les instructions de contrôle
tout se passera comme si l'on avait écrit do i • J, Il, 2 ; on aura donc 6 tours de boucle (i
prenant les valeurs 1, 3, 5, •. 11) et ceci bien que la valeur de net p, donc des expressions
2"71 + J et p, évoluent au cours de la boucle.
Néanmoins, il est vivement conseillé d'éviter ce genre de choses qui nuit obligatoirement à
la lisibilité du programme.
Par ailleurs, la norme prévoit qu'à la fin de l'exécution de la boucle, la valeur de _,,, n'est
pas définie (en toute rigueur, elle vaudra souvent Jin ou fin +pas mais rien ne permet de
l'assurer). li est donc raisonnable de ne jamais chercher à exploiter la valeur de la variable
de contrôle en dehors de la boucle.
Fortran 90 a introduit une nouvelle structure de boucle, à savoir ce que l'on nomme
généralement la boucle 'tant que'. Dans la boucle avec compteur précédente, le nombre de
répétition était déterminé des l'entréedans la boucle. En revanche, la boucle 'tant que' est
ce que l'on nomme une répétition dite conditionnelle, c'est-à-dire une répétition dans
laquelle la pouruite esrrégie par une condition.
Notez toutefois que la présence de cette instruction dans Fortran 90 est assez contreversée,
certains allant jusqu'à la considérer comme "pt.rùnée' (des son apparition!). En fait, elle
posera essentiellement problème dans le cas d'emploi de 'super cakulateurs' de type
vectoriel ou parallèle ; nous verrons comment, dans ce cas, nous en passer.
program exeq,le_do_Ml i le
iq> l ic i t oone
integer :. : n 1 nœbre lu en domêe
i nteger : : so~ 1 sonae de trus les lQbres lus
IV. Les instructions de contrôle 59
""""" • 0
do whi le (so.,.. < 100)
print •. 'OOnnez lll ranbre entier'
read • . n
so111e • sanre + n
end do
print • . 'sonne obten.ie sonne
end
L'instruction:
end do
répète le bloc qu'elle contient tant que la condition mentionnée (somme < 100) est vraie.
Plus précisément, cette condition est examin6e avant la première exécution du bloc ; si elle
avait été fausse, le bloc n'aurait pas été exécuté du tout (ici, ce n'est pas le cas, compte
tenu de notre initialisation de sonvne à 0). Après chaque exécution du bloc, on examine à
nouveau la condition pour savoir s'il faut entamer une nouvclle exécution ou, au contraire,
interrompre la boucle et, donc, passer à Pinstruction suivant le end do.
Naturellement, on ne sait pas, a priori, combien de fois le bloc concerné sera exécuté.
60 IV. Les instructions de contrôle
L'instruction do while
Avec:
Remarques:
1) L'expression exp_/cg doit être définie lorsque l'on commence à exécuter cette
instruction.
2) Si exp_log est fausse lors de l'entrée dans la boucle, le bloc correspondant ne sera
exécuté aucune fois.
3) Pour qu'une telle boucle ait un intérêt, il fait manifestement que la valeur de exp_log
ait des chances d'être modifiée à l'intérieur du bloc concerné. Si tel n'est pas le cas, cela
signifie qu'on aboutira à une "boucle infinie".
4) Si l'on écrit des programmes destinés à être exécutés sur des calculateurs vectoriels
ou parallêles, on a intérêt à réserver l'emploi de cette boucle à des situations qui s'y
prêtent. Notamment, si Pon doit gérer un "compteur" à l'intérieur d'une telle boucle, il
faudra savoir qu'on court le risque que le programme obtenu ne soit pas trés optimisé
en temps; dans ce cas, contrairement à la philophie de la programmation structurée, il
sera préférable d'utiliser une boucle avec compteur, dont on prévoira une 'sortie
extraordinaire'' par exil (nous y reviendrons un peu plus loin).
5) Contrairement à ce qui passe dans d'autres langages (C, Pascal), il n'existe pas en
Fortran 90 de répétition "jusqu'à". Nous verrons comment la "simuler" à l'aide de exit
associé à une ''boucle infinie".
IV. Les instructions de contrôle 61
Certains langages tels que Pascal avaient tendance à appliquer trop strictement les
principes de la programmation structurée dont Pobjectif ttait de disposer d'un nombre
restreint de structures de base. Ains~ non seulement les structures de boucle ne
comportaient qu'une sortie mais, de surcroît, celle-ci était obligatoirement située au début
( boucle 'tant quej ou à la fin (boucle 'jusqu'à'). Or de telles contraintes peuvent
manifestement alourdir exagérément la programmation, ce qui va finalement à l'encontre
du but espéré. C'est pourquoi certains langages (C, Fortran 90.•) ont prévu des
instructions complémentaires permettant d'assouplir quelque peu les structures de boucles
existantes. En. Fortran 90, on trouve dans cet esprit les instructions exit et cycle que nous
allons étudier maintenant.
Dans la pratique, cette instruction s'avère très utile pour régler le cas où, au sein d'une
boucle, on rencontre une situation exceptionnelle qui compromet la poursuite de la boucle.
Dans ce cas, on utilisera un schéma de ce type:
62 IV. Les instructions de contrôle
cbi•l.n
if ( ... ) exit
erd do
Si, comme il est probable, on a besoin, dans la suite du programme, de savoir si la boucle
s'est déroulée entièrement ou non, on pourra faire appel à une variable de type logical (ici
ok) de cette façon:
ok • .true.
OO(•l,n
If ( ... ) then
ok • .false.
exit
end if
erd do
if (ok) then
cas où la boucle s'est dérou lée entièrement
else
1 cas <il la bouc le a êtê i nteTTQrlPJe
end if
D'une manière générale, l'instruction exil peut appanu"'tre dans n'importe quel type de
boucle : avec compteur (comme dans l'exemple précédent). tant que ou "infinie' ; cette
dernière !lructure sera présentée un peu plus loin (on verra précisément que c'est
l'instruction exit qui lui donne un intérêt).
D'autre part, lorsqu'une instruction exit apparaît dans une boucle elle-même imbriquée
dans une autre boucle, elle ne met fin, a priori, qu'à la boucle la plus interne~ voyez cet
exemple
do i • l . n
end OO
IV. Les instructionsdecontrôle 63
instruction A
if ( ... )exit sortie 2
end do
! instruction 8
end do
end do
Notez bien que si la boucle contenant exit contien~ à son tour, une autre boucle (à laquelle
exil est extérieure), cette demiêre boucle n'intervient pas dans le fonctionnement de exil.
EXIT [rom]
L'instruction exit
Avec:
11om : nom d'unestructure de boucle à l'intérieur de laquelle se trouve l'instructicn exiL
64 IV. Les instructions de contrôle
D'une maniêre générale, l'instruction cy:Je, comme l'instruction exi~ peut apparaîlre dans
n'importe quel type de boucle: avec compteur (comme dans l'exemple précédent), tant
que ou "infinie". De même, lorsqu'une instruction C)"le apparaît dans une boucle imbriquée
dans une autre, elle concerne, a priori, la boucle la plus interne. Mais, il est possible de la
faire porter sur une boucle de niveau moins élevé en ajoutant à l'instruction C)"le le nom de
la structure concernée. En voici un exemple:
Si l'instruction de bouclage anticipé cyde comptage est exécutée, elle ne se contente pas de
"sauter" les in!lructions B ; elle provoque le passage au tour suivant de la boucle nommée
comptage, c'est·à·dire en fail, l'examen de la condition de poursuite ( ici .n0Lfi1•) et si cette
condition est vraie, on exécu te les instructions A, avant d'entamer une nouvelle exécution
complète de la boucle avec compteur (on repart à i = J).
Bien entendu, il n'en serait pas allé de même si l'on s'était contenté d'une simple
instruction cyde, laquelle, dans ce cas, aurait simplement provoqué le "saut" des
instructions Il, avec passage à la valeur suivante de i (si la limite n n'était pas atteinte).
CYQE [nom]
L'instruction cycle
Avec:
7 .1 Introduction
Fortran 90 possède une structure de boucle qui peut, de prime abord, semble r curieuse, à
savoir la boucle (d 'apparence!) inf inie:
do
end do
Bien entendu, son intérêt se justifie à partir du moment oll l'on note qu'il est possible
d'introduire, à l'intérieur du bloc concerné, une ou plusieurs instructions d'arrêt prématuré
de la boucle (exit) ou, d'une façon générale, n'importe quelle in!lruction de "rupture de
séquence'' (goto, i/•.).
66 IV. Les instructions de contrôle
Nous allons voir deux exemples classiques d'utilisation de cette nouvelle structure, après
vous en avoir présenté la syntaxe-
7.2 Syntaxe
[nom : ] OO
bloc
OO OO [nom]
7 .3 Exemples
1) Il est très fréquent que l'on doive traiter une suite de données, en nombre non connu à
l'avance, une valeur particulière servant à préciser qu'il n'y a plus rien à traiter. On doit
donc répéter les deux actions :
- lire une valeur,
- traiter la valeur.
Toutefois, la valeur servant de signal de fin de données ne doit généralement pas être
traitée. La mise en oeuvre de ce traitement peut être réalisée simplement en Fortran 901,
de la façon suivante:
do
read •. x lecture d'une valeur
if ( X ••• ) exit sortie si signa 1 de fin
end do
1. La programmation semil mcins simple si l'on voulail se limi1er aux scruttures fœdluneaales de la
programmation structuRe.
IV. Les instructions de contrôle 67
Naturellement, il est facile de généraliser ce canevas au cas oil l'on lit, non pas une seule
donnée, mais tout un ensemble de données ou, même, au cas oil Pon doit programmer une
boucle conditionnelle dans laquelle la sortie ne peut se faire en début2.
2) Comme nous l'avons dit, Fortran 90 ne dispose pas de boucle "jusqu'à". Cette dernière
peut toutefois se programmer facilement à l'aide d'une boucle infinie- Ains~ la
construction suivante correspond à la répétition d'un bloc d'instruction jusqu'à ce que
l'expression logique exp_log devienne vraie :
do
if (exp_log) exit
end do
3) Comme nous Pavons déjà dit en introduction du paragraphe 5, la boucle do whùt est
déconseillée dans le cas de "super calculateurs", compte tenu des risques de dégradation
de performances qu'elle comporte- Dans ce cas, la construction:
do
if (.oot. exp_log) exit
end do
do wlli le (exp_log)
end do
qui compromet le bon déroulement d'un programme (c'~ la même notion que celle que
nous avons évoquée dans le cas d'une boucle, avec cette différence qu'ici la portée de
l'incident est le programme lui-même et non plus seulement une boucle.
Comme on peut s'y attendre, l'instruction go w provoque un 'branchement' à un
emplacement quelconque d'un programme ; plus précisément :
GO TO etiqœtœ
L'instruction go to
Avec:
étiqueite : nombre entier (sans signe) de 1 à 5 chiffrés (non nul) qui ooit figurer devant
l'instruction à laquelle on souhaite se brancher.
Remarques:
1) Bien qu'elle soit devenue désuète en Fortran 90, il existe uœ autre instruction faisant
intervenir des étiquettes; il s'agit de ee que ron nommait l'in!lruction i/ arithmétique.
Voyez éventuellement l'annexe H qui présente les instructions périmées du Fortran 90.
3) Une étiquette peut précéder une instruction structurée portant un nom, comme
dans:
100 cœptage : do "'1ile ( .not.fini)
end do
if ( .•• ) go to 9999
9999 end
car l'instruction end ne doit appa.rai'lre que comme délimiteur à la fin du programme3.
D'une manière générale, il existe une aitre instruction qui peut être utilisée n'importe oil
comme n'importe quelle instruction exécttable: il s'agit de rinstruction stop . Ainsi, peut-
on écrire:
if ( ...) stop
ou encore:
if ( •.• ) tllen
P"int *. 'Problàne insur1100tables- arrêt exécut ion•
stop
end if
Notez que le dernier slbp n'est pas indispensable; en revanche, le end l'est puisqu'il sert de
délimiteur pour le compilateur.
Remar ques :
1) ll est possible de faire suivre le mot clé stop, soit d'une chaîne de caractères, soit
d'un nombre enlier positif de 1 à 5 chiffres, comme dans :
st~ 'erreur inso lub le '
stop 123
2) En Fortran 77, rinstruction stop était obligatoire car l'instrtuction end n'était pas
exécutable (elle ne servait que de délimiteur).
3) Il existe une instruction 'vide', à savoir continue ; eUe élait surtout très ttile en
Fortran 77 pour marquer la fin d'une boucle (dans ce cas, eUe était précédée d'une
étiquette).
IV. Les instructions de contrôle 71
EX ERCICES
note
12
note 2
15.25
note 3
8.75
note 4
-1
royenne de ces 3 notes : 12.0000000
Le nombre de notes n'est pas connu a priori el Putilisateur peul en fournir autant qu~l le
désire. Pour signaler qu'il a terminé, on convient qu'il fournira une noie fictive négative,
Celle-ci ne devra naturellement pas être prise en compte dans le calcul de la moyenne,
2) Ecrire un programme qui 'détermine la éniême valeur u0 (" étant fourni en donnée) de
la 'suite de Fibonacci' définie comme suit :
ul e 1
u2 = 1
u0 = Un-1 + u0 .2 pour n>2
4) Afficher toutes les manières possibles d'obtenir un franc avec des piêces de 2 centimes,
5 centimes et 10 centimes. Dire combien de possibilités ont été ainsi trouvées.
S) Ecrire un programme qui trouve la plus grande et la plus petite valeur d'une succession
de noies (nombres entiers entre 0 et 20) fournies en données, ainsi que le nombre de fois
où ce maximum et ce minimum ont été attribués. On supposera que les noies, en nombre
non connu à Pavance, seront terminées par une valeur négative,
V. LES TABLEAUX
Comme tous les langages, Fortran permet de manipuler des "tableaux". Rappelons qu'on
nomme tableau un ensemble ordonné d'éléments de même type désigné par un
identificateur unique; chaque élément du tableau est repéré par un "indice" (nombre
entier) précisant sa position au sein de Pensemble-
- les opérations "globales', c'est-à-dire portant sur l'ensemble des éléments d'un tableau
ou de plusieurs tableaux,
- la notion de 'section de tableau', qui permet de manipuler une portion de tableau
comme un tableau, même lorsque cette portion n'est pas formée d'éléments
"consécutifs",
- Paffectation conditionnelle (instruction where ),
- les 'constructeurs' de tableaux, qui simplifient l'affectation de valeurs quelconques aux
différents éléments d'un même tableau,
- de nombreuses fonctions intrinstques
Ce sont ces différentes possiblités que nous étudierons ici. Nous les compltlerons par
quelques informations concernant la lecture ou l'écriture de tableaux.
74 V.Les tableaux
Notez que certaim points relatifs aux tableaux ne pourront être abordés que dans les
prochains chapitres. C'est le cas, notamment, des tableaux trammis en argument d'un sous-
prograrnme, des tableaux dynamiques, des pointeurs sur des tableaux. ..
doi-1.5
print •. 'domez lll e ntier relati f'
read •. t(i) ! on lit l 'elanent de rang ide t
end do
print •. ' voici les nœibres positifs q.ie vous avez donne :
doi•l.5
if (t(i) > 0) print •. t(i)
end do
e nd
La déclaration :
spécifie que t est le nom d'un tableau de 5 éléments de type entier. Chaque élément sera
repéré par sa position dans le tableau,nommée ~ndice'. Ici, la première position portera le
numéro 1 (nous verrons toutefois, qu'en Fortran 90, il est possible de demander qu'elle
porte un numéro différent). Nos indices pourront donc varier de 1 à 5. Le premier élément
du tableau sera noté t(I), le second 1(2) .• Plus généralement, une notation telle que
t(i)désigne l'élement dont la position dans le tableau test fournie par la valeur actuelle de
i.
Un élément de tableau peut être utilisé comme le serait n'importe quelle variable de son
type. Ainsi, il peut :
b) Les indices
Les indices peuvent prendre la forme de n'importe quelle expression arilhm8ique d e type
entier. Par exemple, ces notations sont correctes (n,p,j, k et/ étant de ty pe entier):
t (n-3)
t (3*p - 2*k + j/I)
76 V. Les tableaux
llOUS spécifiez que le tableau v comportera 14 éléments de typerea/; ses éléments seront :
Comme llOUS Pavez constaté dans nctre exemple de programme précédent, lorsque la
valeur initiale des indices ne figure pas dans la déclaration, elle est prise par défaut égale
à 1. Ainsi, la déclaration:
est équivalente à :
D'une manière générale, les limites d'indices mentionnées dam la déclaration d'un tableau
peuvent être non seulement des constantes comme dans tous nos précédents exemples,
mais n'importe quelles expression constantes. Cette remarque s'avère particulièrement
utile puisqu'elle permet d'utiliser des constantes symboliques, comme dans cet exemple:
- la lisibilité du programme (il est plus facile de comprendre do; = 1, n _comp que do i
= 1, JO),
Dans nos exemples, les éléments de tableau étaient de type ùteger ou real. D'une manière
générale, ils peuvent être de n'importe quel type. Il peut donc s'agir :
- d'un de ceux dont nous avons déjà parlé: ùteger (éventuellement avec variante~ real
(éventuellement avec variante).doubleprecision ou logical comme dans:
logica l , dirension (10:20) :: preinier
(le tableau premier pourrait par exemple être prévu tel que premkl(i) ait la valeur vrai
si i est premier et la valeur faux dans le cas contraire)
·mais également de types que nous rencontrerons ultérieurement : complex, structures
ou chaînes de caractères (nous verrons alors des exemples de tels tableaux).
Lorsque l'on emploie une constante comme indice, il est possible au compilateur de
détecter une valeur située en dehors des limites prévues (toutefois, tous les compilateurs
ne mentionnent pas ferreur) .
En revanche, dès lors qu'on emploie comme indice une expression (non constante), il est
clair que le compilateur n'est plus en mesure d'effectuer un tel contrôle. Dans ces
conditions, un indice mal calculé pourra se traduire, lors de l'exécution du programme, par
des anomalies plus ou moins faciles à identifia- ; la situation la plus catastrophique est cd le
où ron 'écrase' une information située en dehors du tableau, voire, dans ce.rtains cas, une
instruction de programme. L'erreur ne sera détectée (si elle l'est!) que lorsque l'on
cherchera à utiliser la donnée ou l'instruction ainsi écrasée. Ce phénomène est responsable
d'une grande partie des 'erreurs de programmation'. Il peut éventuellement être évité en
ajoutan~ au sein de son programmel, des instructions vérifJan~ avant toute utilisation d'un
indice qu'il est bien situé dans les limites autoriséesl.
1. Comme de teJJes ilstructions son1 ~nalisan1es en1emps d'cxh:u1ion. on a SOUYenl 1endance (f1ebeusemen1) à
les d6'.laigner. NUrunokls. il reste 1oujoun pô$Sible de pR:YOir des contrOJes ~vères à la inse. au pod et Ase
limiter en phase d'e.xplci1alion à des contrOles portant sur les seuls points "œvtaJgiques" (na:amrnent. les il<ices
dont la valeur di.coule de vêlleun lues en dœnUs).
2. Certains compilateurs, à voœtion p&lagogique,. introduiSUll d'ailleurs automai:iquemcnt de teJJes ilstruclions
dans Je programme exb:uui.ble.
78 V. Les tableaux
Ce que nous venons de voir pour les tableaux à 'une dimension' se généralise sans
difficultés à ce que l'on nomme des tableaux à "plusieurs dimensions' (ou encore à
plusieurs indices). Par exemple :
spécifie que le tableau Il comporte 15 (5 x3) éléments de typeinteger; chaque élément est,
cette fois, repéré par deux indices, le premier allant de 1 à 5, le second de 1 à 3, comme
dans (i, jet k étant entiers) :
lei encore, les valeurs minimales des indices peuvent être précisées. Par exemple :
spécifie que /2 ~ un tableau de 132 (12 x 11) éléments, chaque élément étant repéré par
deux indices, le premier allant de -1 à 10, le second de 0 à 10.
D'une manière générale, il est possible de définir des tableaux comportant jusqu'à 7
dimensions. Ainsi:
Le nombre de dimensions d'un tableau s'appelle son rang. Ainsi, 1 est de rang 1, Il et 12
sont de rang 2 et 13 est de rang 7.
Le nombre de valeurs possibles pour un indice pour une dimension dollllée s'appelle
l'étendue du tableau suivant cette dimension. Ainsi 1 a une étendue de 5 suivant son unique
dimension ; Il a une étendue de 5 suivant la première dimension et une étendue de 3
suivant la secœde dimension. De même, 12 a une étendue de 12 suivant la première
dimension •. Naturellement, lorsque la limite inférieure d'un indice dans une dimension
donnée est égale à 1, l'étendue suivant cette dimension est égale à la limite supérieure de
l'indice (c'est, par exemple, le cas pour les étendues de1J).
Le produit des étendues dans toutes les dimensions fournit bien sOr le nombre d'éléments
d'un tableau; c'est ce qu'on nomme aussi sa taille.
Enfm, la liste des étendues d 'un tableau constitue son profil (ou sa forme). Ainsi :
Nous \Crrons que cette notion de profil joue un rôle important en Fortran 90; notamment
deux tableaux de même profil seront •compatibles3o, c'est-à-dire qu'on pourra affecter à
l'un la valeur de fautre.
- les indices commençaient toujours à 1; il n'était donc pas possible de déclarer tels
quels les tableaux 12et13 précédems,
ou encore:
integer t1 (5, 3)
Comme nous ra~ns déjà dit et vu, il est toujours pœsible de manipuler individuellement
chacun des éléments d'un tableau ; c'est d'ailleurs ce que nous avons fait dans le
programme e>emple du paragraphe 1. Mais Fortran 90 permet sou-ent de manipuler
"globalement" l'ensemble des éléments d'un tableau, offrant ainsi des possibilités très
séduisantes pour rutilisateur scientifiques; ce sont ces possililités que nous allons étudier
ici. à savoir :
- ratrectation collective d'une même valeur à tous les éléments d'un tableau,
- les "expressions de type tableau• qui s'apparentent (sans toutefois être identiques) aux
expressions \Cetorielles ou matricielles des mathématiques.
Notez que ces possibilités se trouveront enrichies par la possililité d'emplo)er des sections
de tableau dont nous parlerons un peu plus loin.
L'instruction suivante :
4. Rappel<ns qu'un programme Fortran 77 est IWjQlrs accep~ pt.r un ccmpilateur Fortran 90 (il faudra SIWvent
toutefois: préciser que l'on emploie un llfonnat fixe").
S. Poa:ibilithqu'on ne trOwe d'ailleurS pu dans des langages tel.s que Cou Pascal.
V. Les tableaux 81
vect • 1
est acceptée par Fortran 90. Elle affecte la valeur (scalaire) 1 à tous les éléments de ""''·
Elle remplace avall[ageusement (j étant déclarée entière) :
do i • 1, 10
vect ( i ) • 1
end do
D e même, a-cc:
vous pourrez~ire:
llat • 1.5
Avec:
Remarq ues:
1) Aucune restriction ne pèse sur le type des éléments. Certes, dans nos exemples, il
s'agissait de types scalaires. Mais, comme nous le -errons par la suite, il pourra s'agir de
complexes, de structures ou de chaînes de caractères6.
2) Compte tenu de la comptabilité des types numêriques ell[re eux, vous avez tout à fait
le droit d'écrire (a-cc nos préeédell[s tableaux):
6 . 11 ne peut toutefoii pu s 'agir de tablea\11( c ar, en Fortran 90, il n'existe pu de tablea\llC de tableaud (alori que
c'ea le cas en Pucal).
82 V. Les tableaux
a) Exemples d'introduction
L'instrllctioo :
w• a + b
do i • 1. dill
w(i) • a(i) + b(i)
end do
De même:
est équivalente à:
do i • 1. di11
w( i) • a(i) • b(i) 1 attentioo, produit êlément par êléOlent et non pro<1iit scalaire
end do
Mieux:
W • a*b + S
est équivalent à :
doi • l .dill
w(i) • a(i) • b(i) + 5
end do
V. Les tableaux &3
Remarques:
b) Attention à ta correspondance
Dans des expressions tableau telles que a + b, il faut bien sOr que a et b aient te même
nombre d'6léments, c'est-à- dire le même profit. En revanche, il n'est pas nécessaire que les
84 v. Les tableaux
limites des indices soient les mêmes (ce qui était le cas dan.~ notre exemple) . La même
remarque s'applique à l'affectation de la valeur d'une expression tableau à un tableau.
Voyons cela plus précisément sur un nouvel exemple :
w • vl + v2
doi•2 , ll
w(i) • vl(i - 1) + v2(i-2)
erd do
ou encore à:
do i = o. 9
w(i•2) • vl(i•l ) • v2(i)
end do
Autrement dit, Il oorrespondance entre les 6éments des dlllérents tableaux, aussi bien
dan.~ l'évaluation d'une expression tableau que dans l'affectation, ne tient compte que du
protu des tableaux concenés. Naturellement, ceci se généralise à des expressions tableau à
plusieurs dimensions comme dans :
W• U + V
Ici, les tableaux u, vet w ont le même profil (10,20). L'affectation w = u + v est équivalente
(par exemple) à :
do i • 1, 10
do j • 1. 20
w ( i ,j) • u(i, J-1) • v(i- 3, j -9)
end do
end do
V. Les tableaux 85
une expression telle que tabl + tab2 n'aurait pas de sens puisque les deux tableaux n'ont
pas le même profil (10 pour tabl et 9 pour tab2). De même, raffectation tabl = tab2 serait
incorrecte.
Remarque :
Dans nos· précédents exemples, nous nous sommes limitts à des tableaux de type
numa-ique. Voici un exemple d'expression tableau de type logique:
logical. dimension (10) :: coq>are
integer. di11ension (10) :: vl. v2
c~are • vl < v2
Comme nous l'avons déjà é~ué, on pourra rencontrer des expressions tableau de type
character ou structure.
tn • tp + tr
tr • tp + 2.5
L'expression tp + tr est une expression tableau de réels obtenue en COn\ertissant toutes les
valeurs de tp en rée~ avant de les ajouter à celles de tr. Puis, pour effectuer l'affectation à
ln. on réalise une conversion des valeurs ainsi obtenues en entier.
86 V. Les tableaux
- il peut être appliqué à deux tableaux A et B de même profi~ fun de type II, l'autre de
type IZ. Dans ce cas A op B est le tableau de même profil que A et B dans lequel
chaque élément a la valeur et le type deA(i) op B(i) ; rexpression lp +tr du paragraphe
c en est un e>:emple ;
- il peut être appliqué à un tableau A de type tI et un élêment x de type IZ
( respecti-ement à un élêment x de type Il et un tableau A de type IZ). Dans ce cas A op
x (respectivment x op A) est le tableau de même profil que A dans lequel chaque
élément a la valeur et le type de A(i) op x (respectivement x op A(i)) ; rexpression
tp + Z.5 du paragraphe cen est un exemple.
Notez bien que ces règles sont assez fastidieuses à ênoncer de façon précise. Il n'en reste
pas moins qu'elles correspondent à l'intuition qu'on peut en avoir.
Remarque:
Ces règles s'appliquent à tous les opérateurs définis par le langage (nommés sou-ent
"opérateurs intrinsèquesî. Mais nous verrons qu'il est possible, en Fortran 90, de
définir soi-même de nou-eaux opérateurs (qui ne seront donc plus "intrinsèquesî : ces
derniers ne jouiront plus des propriétés que nous \CDOns d'ênoncer7.
7. Saur si vous le pm<:iyez explickement. en exploiu1n1 des: poa:ibilitU de •s:urdU'initiOd' d'op&.teurs dent nous
p.rlcrœs plus tard.
V. Les tableaux irl
Uaffectation rac = sqrt (1•al) fai t intenenir une no1Nelle forme d'expression tableau : sqrt
(val). Celle-ci n'est rien d'autre que le tableau de réels obtenus en appliquant la fonction
sqrt à chacun des éléments du tableau va/.
D'une manière générale, toutes les fonctions élémentaires8 peuvent être appliquées à un
tableau de profil quelconque ; elles fournissent en résultat un tableau de même profil. Ce
dernier peut éventuellement intervenir, à son tour, dans une expression tableau plus
complète comme dans:
Voici un autre e>emple faisant appel à deux fonctions élémentaires que nous n'avons pas
encore rencontrées mais dont le rôle est évident (notez bien que a, b et omega sont des
scalaires, tandis que t et valeurs sont des tableaux) :
8. Enfaît, pardérinitiOI\ une fonction élémentaire (en anglais elemental)est une fonctîonqu 'onpeut appliquer à
tou$ les éléments d'un tableau.
88 V. Les tableaux
Les fonctions élémentaires dont oous \Cnons de parler ont la particularité de pou\/Oir
porter indifféremment sur des scalaires9 ou sur des tableaux. En dehors de cela, il existe
également des fonctions spécifiques aux tableaux, c'est-à-dire ne comportant plus
d'équivalent pour des scalaires. L'exemple le plus usuel est probablement la fonction sum
qui fournit en résultat la somme des valeurs d'un tableau qu'on lui fournit en argument:
De façon comparable, il existe les fonctions maxval (valeur maximale d'un tableau), mimai
(valeur minimale d'un tableau) etproduct (produit des valeurs d'un tableau).
Fortran 90 offre une notation particulière dite "constructeur' permettant de regrouper les
valeurs des différents éléments d'un tableau.
9. Ou, tn toute reueur, sur deS ccmplexes (qui son1 pre""e deS SCllaires) ou des diaines de carac~res. typeS
dont nws ptrlttœs ull6'iememen1.
V. Les tableaux 89
a) Introduction
(! 3, 5, 1. 8, 12 Il
représente un tableau formé des 5 nombres entiers: 3, 5, 1, 8 et 12. 0 n peut dire qu'il s'agit
d'une expression tableau d'entiers de profil (5).
Cette expression peut être utilisée classiquement dans une affectation, comme dans:
t • (! 3, 5, 1. 8, 12 Il
ou, même dansll :
t • 2 • (/ 3, 5, 1. 8, 12 Il +5
Dans un constructeur de tableau, on peut en fait mentionner, non pas seulement des
constantes, mais n'importe quelles expressions, à condition toutefois qu'elles soient toutes
de même type. Par exemple, sin etp sont des variables entières, on pourra écrire (1 étant le
même tableau que ci-Oessus) :
En fait, dans un oonstructeur de tableau, on doit prévoir une liste de valeurs. Or,
Fortran 90 possède une notation spéciale pour décrire une liste de valeurs, lorsque celles-
ci peu-ent se déduire d'une expression unique dans laquelle on se contente de faire varier
une variable entière. Par exemple, la notation :
( 3' i + 1, i • 1, 6. 2)
représente la llsle des différentes valeurs que prend l'expression J'i + 1 quand la variable
i prend successi-ement les valeurs 1, 3 et 5 (de 1à6 par pas de 2, comme dans une boucle
do, en quelque sorte12!). Cette notation remplace donc la liste :
4, 10, 16
Une telle notation porte le nom de liste à boude lmpllclte, ou encore de ' liste implicite'
(nous emploierons souvent ce terme, par souci de briè-eté) ou, parfois de 'boucle
implicite•.
En plaçant une telle notation dans un constructeur de tableau (de la forme ( / liste de
-..aleur.r /),on obtient (n'oubliez pas les parenthèses qui encadrent la liste implicite):
(/ ( 3' i + 1. i • 1. 6, 2) /)
Naturellement, une liste implicite peut apparaître n'importe où dans une liste de valeurs et,
donc, éventuellement, être accompagnée d'autres valeurs (ou même d'autres listes
implicites), comme dans cette affectation:
Voici un dernier exemple qui montre que la boucle implicite peut porter sur une
expression ; l'instruction :
t . (! (i, 2• 1, i . 1. 5) !)
Remarque importante:
La ou les variables apparaissant dans une liste implicite sont de 'vraies" variables. Nous
voulons dire par là qu'elles doivent être déclarées au même titre que les autres et
l'exécution de finstruction correspondante entraîne obligatoirement une modification
de ces variables. Ainsi, il faudra éviter d'incorporer rexemple précédent à l'intérieur
d'une boucle dans laquelle i serait une variable de contrôle d'une boucle do. JI s'agit
d'ailleurs là d'une source d'erreur fréquente (beaucoup de compteurs, d'indices.•
s'appellent ~ j ...!).
(/ 1i ste_d_ê l !lnents /)
Le constructeur de tableau
A-cc:
élément:
- expression quelconque,
- liste implicite de la forme :
( liste_d_éléments, variable_entMr<! = dfbui,fin (,pas))
A-cc: débu~ fin et pas: expressions de type entier.
Toutes les expressions figurant dans le constructeur doivent être de même type (entier,
réel, comple>e, variantes comprises) et non seulement d'un type comptible.
Remarques :
1) Rien n'interdit d'écrire une liste implicite dans laquelle la liste d'éléments est réduite
à la variable entière, comme dans :
(i, i•l.5)
(/ (i. 1•1.5) /)
2) Notez bien qu'il n'est pas permis de mélanger les types dans un constructeur; ainsi,
ceci est incorrect :
(f 3. 4.5. 2.5 /) 1 Incorrect
3) Comme ~us pouvez le constater, la définition d'une liste implicite est "récursive" ;
plus précisément, la liste_d_éléments peut elle-même être une liste implicite, comme
dans cet exemple de constructeur :
(/ ( (1 +2•j . j • 1. 3) • i • 1. 2) /)
Il est équivalent à :
(/-(1+2• j. j • 1. 3). (2+2•j , j • 1. 3) /)
4) La variable peut ne pas apparaiûe dans la liste d'éléments. Par exemple, avec:
(/ 100, I• 1, D /)
D'une manière générale, comme on peut s'en douter, on peut utiliser dans le constructeur
une liste de valeurs obtenues par des expressions constantes (calculables par le
compilateur) :
Mais, il est également permis de faire apparaîtres des boucles implicites, pour peu que les
expressions qu'elles renferment (hormis la ou les variables *compteur*) soient elles-mêmes
des expressions constantes. En voici un exemple :
Notez qu'alors la ou les variables *compteur* doivent absolument avoir été déclarées
auparavant
Par ailleurs, il est tout à fait possible de définir des oonstantes symboliques (parometer) qui
soient des tableaux Il suffit simplement d'utiliser l'instruction parameter et des *expressions
tableau constantes*, c'est-à-dire dont les éléments sont eux-mêmes des expressions
constantes. En \Oici un premier e>emple :
Notez bien que si lim n'était pas une constante, la dernière déclaration serait incorrecte.
94 V. Les tableaux
curieusement, Fortran 90 n'a pas prévu de oonstructeur pour des tableaux à plus d'une
dimension. En revanche, il existe une fonction qui permet de fabriquer un tableau de profil
donné, à partir d'un tableau à une dimension. ns'agit de la fonction reshape.
L'expre.ssion :
reshal>' ( tl, (/ 3, 2 /) )
est un tableau à 2 dimensions obtenu en répartissant les valeurs du premier argument Il,
suivant le profil indiqué en second argument, lequel doit être un tableau d'entiers
fournissant le profil voulu. La répartition des valeurs se fait suivant un ordre qui n'est pas
nécessairement celui auquel on s'attend: en effet, il s'agit de celui obtenu en faisant varier
plus rapidement le premier indicel3 ; autrement dit :
l'élément de rang 1, 1 sera U (1),
l'élément de rang 2, lsera U (2),
l'élément de rang3, lsera t1 (3),
l'élément de rang 1, 2 sera t1 (4),
l'élément de rang2, 2 sera t1 (5),
l'élément de rang3, 2 sera t1 (6).
L'expression tableau fournie par la fonction reshape peut apparaître:
- mais aussi dans une expression constante(car l'emploi de la fonction res!tape, entre
autres, y est autorisé) ; par e>emple nous pourrions ainsi initialiser notre tableau t2, lors
desa déclaration:
integer , diœns ion (3, 2) :: t2 • reshal>' ( tl, (/ 3, 2 /) )
13. Q.d corrcspcnd à l'ordre dans lequel les 616nenis d'un tablU u à dewc dimensions sont nui~ en m6noire.
V. Les tableaux 95
Remarques:
1) Dans l'e.Jaemple précédent, il serait judicieux de placer les dimensions de 12 en
•constantes symboliques• (parameter), afin de diminuer les risques d'erreur (de
programmation) et, le cas échéant, faciliter leur modification. Par e.Jaemple, on pourrait
écrire :
integer. paraœter : : nl • 3. ne • 3
integer : : i
integer, di11ension (nl•ne) .. tl • (/ (i , i•l,nl•ne) /)
integer, dirension (ni , ne) . . 12 • reshape (tl. (/ ni , ne /) )
2) Le second argument de reshape n'est rien d'autre qu'un tableau d'entiers de rang 1.
On peut écrire par exemple,
integer , dirension (2) :: profil • (/ ni, ne /)
3) Ce que nous avons dit à propos des tableaux constants à une dimension s'applique
également aux tableaux oonstants à plusieurs dimensions. A simple titre indicatif, ~ici
comment nous pourrions appliquer cela au tableau /2 de la remarque 1:
integer , paraœter : : n 1 • 3, oc • 3
integer : : i
integer , ditension (ni• ne) , paraœter :: t1 • (/ (i, i•l , nJ•nc) /)
integer, dirension (ni. ne) , par..,.ter : : 12 • reshape (tl , (/ni , ne/))
Notez bien que nous avons dO faire également de Il w tableau constant (sinon
rexpression reshape n'aurait pas été une expression constante).
Nous avons déjà vu comment créer des expressions tableau et affecter le résultat à un
tableau de même profil mais supposez que nous disposions des deux tableaux v et w définis
ainsi:
integer. dimension (10) ;; v
integer , diœnsion (S) : : w
Si ~us souhaitez recopier les 5 premiers éléments de v dans les 5 éléments de w, vous ne
pouvez plus utiliser les facilités que nous a~ns déjà renoontrées. Dans ces conditions, il
semble qu'il faille revenir à une notation développ6e telle que:
doi • l,5
w(i) • v(i)
end do
w • v(l :S)
La notation v(1:5) est une expression tableau représentant le tableau de 5 éléments formés
des valeurs de v(J), v(2J.- v(5).
D•ns cet exemple, v(J:5) était employé comme une expression. Mais (et cela est moins
naturel!) Fortran 90 accepte qu'une telle notation soit employ6e à gauche d'une
affectation, c'est-à-dire comme une variable14. Par e>emple, a-cc:
v(l :S) • {/ 3, 7, 1, 8. 0 /)
v(2:4) • w(5:7)
14. Rappelons que le 1ermede v.uiable désigne toute tiftrenceà quelque Chœe susœptibled'ttre modifié.
V. Us tableaux 97
Remar<,ie:
Dans une section continue, on peut omettre une des bornes ou les deux. Lorsqu'une
borne est omise, on utitise celle du tableau complet. Ainsi:
v(:4) est équivalent à v(1:4),
v(3:) est équivalent à v(3:10),
v(:) est équivalent à '(1:10) ou encore à v.
La dernière remarque montre qu'on peut toujours faire suivre un identificateur de
tableau de (:), ce qui peut permettre, comme nous l'avons déjà évoqué, de mieux
distinguer, dans un programme, les tableaux des scalaires.
b) En cas de •recoupement"
Comme vous pouvez vous en douter, un problème apparaît dès lors que des sections de
tableau ayant des parties communes apparaissent à la fois à gauche et à droite d'une
affectation. Considérez par exemple:
Ici, 1>(2) se voit affecter une valeur dépendant de v( 1) et v(3). Mais, v(3) reçoit lui-même
une valeur dépendant de v(2) et v(4) . De quel v(2) s'agit-il? De l"'ancien• ou du •nou-eau"?
En fait, la règle adoptée par Fortran 90 est la suivante:
lS. En fait, cette RgJe, introduite dans le cas de &eUions oontinu« de ttbleau, est Yllable p0ur tout« I«
exp:egsiœsde type tableau.
98 V. Les tableaux
Aios~ dans notre exemple, on remplace chacune des composantes de v, excepté les
extrêmes, par la valeur moyenne des deux composantes voisines. S'il fallait écrire la même
chose sans utiliser de section de tableau, il faudrait surtout éviter de procéder ainsi:
do i • 2, 9
v(i) • ( v(i-1) + v(i+l ) ) / 2 t résu ltat différent de ce lui escoq>té
erd do
do i· · 1, 10
v l (i) . v(i)
end do
doi•2 , 9
v(i) • (vl (i ·l) • vl (i+l )) / 2
end do
Ici encore, une telle expression (section de tableau) peut ê tre utilisée comme une variable
comme dans:
w(l :9:2) • 1
w(2:10:2) • 2
La première place la valeur 1 dans les éléments de rang impair de w ; la seconde place la
valeur 2 dans les éléments de rang pair de w.
16. IJ existe des solutions sans tableau intermédiaire, ma.is elles sont peu tisibles.
V. Les tableaux 99
w{ l :9:2) • V
w(2: 10:2) • V
On obtient finalement les valeurs 1, 1, 2, 2, 3, 3... 5, 5 daŒ les 10 éléments de w. Bien sOr,
ici il serait plus simple d'écrire :
w . (/ { i . ; , i . 1, 5) /)
A-ec :
début, fin et pas: expressions entières quelconques; quand une telle expression est
omise, elle est prise par défaut égale à:
- la valeur du premier indiœ du tableau pour début,
- la valeur du dernier indiœ du tableau pour [m,
- un pour pas .
Remarques:
Dès lors que la valeur de début est supérieure à celle de fur (avec un pas positif, ou
l'inverse avec un pas négatif), la section correspondante ne comportera aucun élément.
Ceci est parfaitement accepté par Fortran 90 (et se révélera fort pratique dans certains
problèmes d'analyse numérique). La valeur de fexpression (de type tableau, rappelons-le!)
est un tableau de rang 1 et de dimension O. Comme il est possible d'affe<.ter un scalaire à
un tableau, l'instruction :
v( ! :n) • 1
aura toujours un sens, quelle que soit la valeur den ; simplement, si n est négatif, elle ne
fera ... rien.
Nous reviendrons sur ces •sections vides• dans le cas de sections de tableaux à plusieurs
dimensions.
V ( 2: 5) • W ( (/ !, 3, 7, 10 /))
ou encore à:
w ( {/ 1. 3 . 7, 10/)) •100
w ( {/ 1 , 3, 7. 10 /) ) • v(3 :6)
Le tableau d'entiers (ici constant) (1 1; 3, 7, JO/} se nomme ici un "vecteur d'indice". D'une
manière générale, on peut utiliser un tableau d'entiers quelconque. Par eJ<emple, si ron
déclare:
w ( ind) . 100
w ( ind) • v(3 :6)
la notation w(i11d) joue le mê me rôle que w ( / I, 3, 7, JO/) (avec toutefois cette différence
qu'avec cette nou-elle notation, il devient possible de faire évoluer le contenu de l11d)
102 V. Les tableaux
Voici, à titre d'exemple d'application, comment effectuer une permutation circulaire des
éléments du tableau w précédent (mais on peut faire la même chose en utilisant la fonction
prédéfinie cshijl!) :
D'une manière générale, quand une section de tableau appanu"t Agauche d'une affectation,
elle ne doit pas faire intervenir deux fois le même élémeit. Certes, une telle anomalie est
facile à déceler lorsque le vecteur d'indice est un tableau de constantes et elle est alors
généralement délectée en compilation. En revanche, les choses sont moins évidentes dans
le cas de tableaux variables (constructeur contenant des expressions variables ou tout
simplement identificateur de tableau) ; ferreur ne peut alors être décelée que lois de
l'exécution (quand elle l'est!).
Avec un vecteur d'indice constant, on ne risque pas d'aboutir à une section vide. En
revanche, cela peut se produire dans des situations telles que v( (/ (~ i = n, p, q /)) . Suivant
les valeurs relatives de n p & q, on pourra n'obtenir aucun élément. Rappelons que la
section vide reste un tableau de rang 1 el d'étendue O.
V. Les tableaux 103
la notation 1( 1:2, 1:3) correspond à un tableau de 6 éléments de profil (2, 3), qu'on pourrait
schématiser ainsi :
la notation 1(1:4:2, 1:6) correspond à un tableau de 12 éléments de profil (2, 6); elle est
équivalente à 1( 1:4:2, :) et elle pourrait se schématiser ainsi:
Mais, et c'est là une nouveauté par rapport aux sections de tableaux à une dimension, on
peut aussi spécifier une section pour certaines dimensions et la valeur d'un indice pour
d'autres. Par exemple 1(2, 1:3) est u n tableau de rang 1 formé des trois premiers éléments
de la deuxiême ligne 17 de1. Notez bien que, contrairement à la précédente, lasectionl(2:2,
1:3) serait de rang 2 et de profil (1, 3); autrement di~ elle aurait la même taille que la
précédente, mais son profil serait différent.
Cette remarque prend toute son importante si l'on pense que l'affectation de tableaux n'est
possible que si les profils soŒ identiques! Elle prend encore plus d'importance dans le cas
d'une expression de la forme 1(11:p, 1:3) qui sera toujours de rang 2, quelles que soient les
valeurs den et de p. Ains~ lorsque n ~p. elle est de profil (1, 3); avec n >p, elle est de
profil (0,3) : il s'agit d'une nouvelle forme de section vide.
17. On util.isc souven1 les tennes lignes et cOlonnesdans le cas de tabk:aux à deux dinensions par analogie avec les
lignes el les <Olonnes d'\lllc matrice.
104 V. Les tableaux
A1'CC:
sped/; : une des trois p0$Sibilités suivantes ;
·indice (expression entière quelconque).
• indication de section régulière, de la forme; (deb):(fin)(:pas)
·vecteur d'indice (tableau d'entiers à une dimension)
Le rang de cette section (dAfini à la compilation) est au nombre de spécifications fournies
sous forme de ooction regulière ou de vecteur d'indice.
5.5 Exemples
œt • o.o 0 0
do i • 1, ne 0
œt(l: i , i ) • 1.0 1 1
end do
do i • 1. ne
mat(!: i, i) • 1.0
œt ( i+l :œ , i ) • 0.0
end do
Dans ce cas, la seconde section m(Jl(i + J:ne, i) (de rang 1 et de profil variable) devient, au
dernier tour de boucle (i = M) une 'section vide'; finstruction correspondante ne fait
alors ... rien.
Soient deux matrices a et b On cherche à constituer une nou-elle matrice (nommée m(Jl)
formée ainsi (a et b désignant des blocs de taille quelconque et 0 un bloc de taille
queconque ne contenant que des zéros) :
a O
0 b
œt • O
mat (l:nll, 1 : ne!) • a
œt (nll +l : n i , ne!+! : ne) • b
Remarque:
6 - L'INSTRUCTION WHERE
6 .1 Introduction
Nous avons déjà vu oomment simplifier la programmation de certains traitements en
utilisant les expressions de type tableau. Lfostruction where va nous permettre d'appliquer
ces possibilités dans le cas oil l'on ne souhaite traiter que les éléments vérifiant une
certaine ccndition.
Par exemple, si a et b sont deux tableaux réels de même profil, nous savons affecter à
chaque élément de b, la valeur de la racine carrée de rélément oorrespondant de a en
écrivam::
b • sqrt (a)
En pratique, toutefois, on souhaitera traiter correctement le cas oil a contient des valeurs
négali..es en convenant (par exemple) qu'on se contente alors d'affecter la valeur 0 à
l'élément correspondant deb. Dans ce cas, on peut penser qu'il est nécessaire de 'revenir"
à une formulation élément par élément de la forme (ic~ on suppose que nos tableaux sont
de rang 1 et de taille n) :
doi • l ,n
if ( a(i) "' 0 .0) then
b(i) • sQrt (a(i))
e 1se
b(i). o.o
end if
end do
where (a "' 0)
b = sqrt (a)
e lsewhere
b • o.o
end lfhere
V. Les tableaux 107
EllO WHERE
Avec:
blocl et bloc2 : Instructions d'affectation dans lesquelles le tableau figurant à gauche
du signe • est du même profil que le résultat fourni par rexpression logique de type
tableau figurant dans la ligne where.
Notez que, bien que ce soit rare en pratique, il est possible d'introduire plusieurs
instructions d'affectation; naturellement, ces dernières doivent concerner obligatoirement
des tableaux de même profil (dans le cas contraire, d'ailleurs, on ne ~it guère la
signification que pourrait posséder notre instruction).
Lorsque bloc2 est absent et que bloc/ ne comporte qu'une seule instruction d'affectation,
on peut utiliser une forme simplifiée :
6 .3 Quelques·comm entalres
1) L'expression logique sezvant de "filtre" au traitement réalisé par finstruction whue peut
être un tableau de type logique. Par exemple, avec ces déclarations :
integer, paraœter : : n • 20
logica1. di11ension (n) :: inverse
integer. dimension (n) : : a, b, c
2) Les expressions figurant dans les expressions peuvent être quelconques, pour peu que
leur résultat soit du profil voulu. Considfaez alors ces instructions (a étant un tableau de
dimension n) :
Que représente alors sum(a)? En fai~ dans notre premier exemple la fonction sqn était
une "fonction élémentaire"; ce n'est pas le cas de swn (elle ne s'applique qu'à un tableau,
pas à chacun de ces éléments). Dans ce cas, la règle est que cette fonction est calculée
comme elle le serait en dehors d'une instruction where. Elle porte donc sur tous les
éléments dea (négatifs compris).
On notera que, dans :
sqlf ~ élémentaire, tandis que sum ne l'est pas. Ici, la règle est qœ les fonctions
élémentaires apparaissant en argument d'Une fonction non élémentaire ne soient pas
soumises au fdtre. Autrement di~ l'expression sum (sqlf(a)) porte toujours sur tous les
éléments de a. On aboutira donc à une erreur d'exécution dés lors que a contient une
valeur négative.
V. Les tableaux 109
3) La nonne prévoit que l'exécution d 'une jnstruction w/Jere commence par évaluer
complttement la valeur du filtre (c'e st-à-dire toutes les valeurs du tableau logique
correspondant) avant d'exécuter les différentes affectatiœs. En pratique, cela signifie que
si les affectations placées dans l'instruction wilere modifient la valeur du filtre, cela n'aura
aucune incidence sur son déroulement (qui restera celui prévu lors de l'entrée dans
l'instruction18).
7- ENTREES-SORTIES DE TABLEAUX
Bien entendu, un élément de tableau peut apparai'"tre dans une liste d 'entrée-sortie, comme
dans:
read •. t(2)
print '. mat (2. 1)
Mais on peut également employer le nom du tableau. Dans ce cas, il est ~ulvalent à la
Bste de tous ses éléments. Pour un tableau de rang 1, fordre est naturel ; ainsi, t est
équivalent à t(J ), t(2), t(3), t(4), t( 5), t(6).
18. Un peul l'bnage de ce qui se p0S'Sle poor ooe lns.roedon do œn.s laquelle on modlie la valeur desbomes.
110 V. Les tableaux
print • , t( (/ 1. 5, 4, 2 /) )
~ équivalent à :
De même:
est équivalent à :
Mai~ dans le cas d'une lecture, il faut é>I ~r q ue, dans u ne meme section, le memeélément
ne soit cité deux fols. On retrouve ici la même règle que pour faffectation à une section de
tableau (ce qui est logique puisqu'une lecture implique une affectation implicite!). Ainsi:
read • . t ( (/ 2, 4, 2 /) ) 1 incorrect
Remarque:
Notez bien que finterdiction d'amtiguïté ne concerne que les sections de tableau
utilisées comme des variables. Ains~ une lecture telle que :
read • . t(2), t(4), t(2) 1 correct 11a is stupide
reste autorisée même si elle est stupide; en effet, ic~ aucuœ ambiguïté n'existe dans
chacune des variables citées dans la liste.
D'une manière générale, dans une liste apparaissant dans une instruction de lecture, vous
ne pouvez faire intervenir que des "variables19" Qes sections sans ambiguïté étant bien des
variables). Dans les instructions d'écriture, vous pouvez introduire en revanche n'importe
19. Auseœgénâa1dece1erme.
V. Les tableaux 111
quelle expression. En voici des exemples (on suppœe que a et b sont des tableaux de rang
1):
print • . a+b
print •. a(2:5) • b(l:4)
print • . 2 • (/ 3, 1. 5 /) + 1 1 êqutvalent A print 11
• 7. 3 , 11
Dans une liste d'entrée-sortie, on peut utiliser un mécanisme analogue à celui que nous
avons décrit dans le cas des constructeurs de tableaux.
Par exemple :
print •, ( t(i) , i • 1, 5, 2)
est équivalente à :
De même:
est équivalente à:
cette dernière écrivant effectivement les mêmes éléments, mais dans un ordre différent
Voici une manière d'écrire les éléments d'un tableau de rang deux (de dimensions net p)
suivant l'ordre naturel (et non plus suivant l'ordre d'arrangement de ses éléments en
mémoire) :
Dans les exemples précédents, les expressions concernées étaient des éléments20 de
tableau. Mais, il peut s'a gir également d'expressions de type tableau.
Dans le cas d'écriture, ces expressions peuvent être absolument quelconques comme dans :
Naturellemen~ dans le cas de lectures, il faut que chaque expression ainsi générée par la
liste implicite soit une variable, ce qui revient à dire qu~l peut s'agir d'une section de
tableau,.à condition qu'elle ne présente pas d'ambiguïté. Ainsi :
EXERCICES
20. Ici S1Ca.airts. Plus loi>:. nous venons que oes tl6ntnts peuveni: ttre du structures ou duchatnudecaraccères..
V. Les tableaux lll
• - 5
b - •
c • a +b
c• a +b
a • b
a • b + cl II
a • 2' b • 5 III
a(2:nel)•cl l lV
a(l:nel- l)•Cl IV
b(::2)•cl(::2) I VI
program construction_tableau
iq:>licit none
integer. paraœter :: net • 10
integer .. i , n
integer. ditension (net): : t • (/ (i, i• l. ne1) /) 1 constructeur a l'initialisation
Jusqu'ic~ nous avons utilisé de façon relativement intuitive les instructions de lecture sur
("entrée standard' et d'écriture sur la 'sortie standard' avec ce que l'on nomme le fermai
libre (désigné en fait par le symbole• dans les instructions correspondantes).
Ici, nous allons commencer par apporter quelques précisions sur ce format libre dont on
verra qu'on peut Ir~ souvent se contenter pour la lecture. Nous verrons ensuite comment
imposer nous-mêmes un format précis (gabari~ précision des nombres, espaces...), et ceci
aussi bien pour les informations que nous écrivons pour celles que nous lisons (en toute
rigueur, vous serez plus souvent amené à utiliser un tel format en lecture qu'en écr~ure).
Notez que, dans le chapitre consacré aux fichiers, nous étudierons une nouvelle syntaxe des
instructions d'entrées-sorties qui pourra également s'appliquer aux entrées-sorties
standards; nous verrons qu'elle offre alors d'autres possibilités que celles que nous
abordons ic~ notamment au niveau du contrôle du changement de ligne et de la gestion des
erreurs.
116 VI. Les entrées-sorties standards
Jusqu'ici, nous n'avons exploité que quelques possibilités du format libre (séparation des
informations par un ou plusieurs espaces ou fin de ligne). Voyons ce qu'est ce format libre'
d'une manière générale, en nous limitant toutefois ici aux types de base connus (entier, réel
et logique2).
Lorsque vous lisez en format libre une variable de type entier, vous pouvez exprimer sa
valeur sous la fttme de n'importe quelle constante entière avec ou sans signe comme, par
exemple:
+345 78 -3456
Pour une variable de type réel (real ou dodile predslon), vous disposez d'une grande
liberté. En effet, vous pouvez l'introduire indifféremmeit sous forme d'une constante
entière ou sous forme d'une constante réelle en notation flouante ou exponeitielle (dans
ce cas, l'exposant peut être indirféremmeit E, e, D ou d), par exemple:
Quant aux variables de type loglcal, vous pouvez les introduire indifféremment sous la
forme:
Lorsque vous founûssez une information ne correspondant pis à l'une des formes
autorisées (par exemple 125 pour un entier, 255A2 pour un réel...), vous obtenez un
"message d'erreur' accompagné d'un arrêt de rexécution. Ce comportement (que l'on
retrouve dans la plupart de langages) peut s'avérer peu satisfaisant et, comme nous le
verrons dans le chapitre consacré aux fichiers, il existe des techniques permettant de
prendre en charge l'analyse de la réponse fournie par un utilisateur el, en cas d'erreur, lui
demander d'en fournir une nouvelle.
l Au lieu d'entr6ewortiesenforma1libre, on parle aussi d'•entr6cs...soa1iesdirigées par li.s1e• (par eppOSiticn aux
en~œ-Wrti« dirig6es par ronn•).
2 Pour les autrtt typeS,vous trouverez les informationsntoeuairesdans lescbaptb'CS corrcspœdan1&
VI. Les entrées-sorties standards 117
Nous avons déjà vu que les différentes informations peuvent être séparées par un ou
plusieurs espaces. On peut également utiliser une virgule (précédée ou suivie d'éventuels
espaces). La fin de ligne est elle-même un séparateur, ce qui revient à dire que, si l'on n'a
pas trouvé suffisamment d'informations sur une ligne donnée, on en lit tout simplement
une autre ...
integer : : n. p
read • . n. ·p
Chaque nouvelle lnstrucllon de lectw-e entratne toojoors la lectw-e d'une noovele Il~,
même si certaines informations de la ligne précédente n'ont pis été prises en compte.
Ainsi, avec ces instructions :
integer : : n. p
read • , n
read • . p
10 20 30@
40@
l. N0\5 verrœs twtef'oi5 que la 5CCOnde forme de5 entrée5-50rtb (pré&entéc dans le cbap 1rc n:JJtif aux f.chiers)
permettr.1 de môdifier oe oomportement.
118 VI. Les entrées-sorties !tandards
D'une manière générale, quand aucure information ne figure entre deux virgules4, la
valeur de la variable correspondante reste Inchangée. De même, un caractère / en fin
d\me ligne revient à considérer que toutes les valeurs suivantes sont absentes.
Ces deux possibilités peuvent paraître séduisantes, notamment lorsqu'il s'agit de fournir
des informations par l'intermédiaire du clavier; en efftt, il devient possible à l'utilisateur
de ne fournir que certaines données, les autres recevant en quelque sorte des valeurs par
4, Ceue règk. ne pe .. pas s'apptiq\IC.r a1,1 cas des es~oes car un ootrbn:. quetcCllque d'~ces jO\le le .rae d'un
SC\ll ~~ratwr.
VI. Les entrées·sorties standards 119
défauts. Il n'en reste pas moins que cela complique quelque peu la programmation, dans la
mesure où l'on doit alors s'assurer que toute variable recevant une valeur par une
instruction de lecture a été convenablement initialisée.
voici quelques exemples des valeurs obtenues dam t, net p avec les réponses indiquées à
gauche:
7'8 t(l)·8 t(2)·8 t{3)·8 t(4 )· 8 t(S)-8 n-8 p•8
3•7. 2*3. 2•0 t(l )· 7 t(2)·7 t( 3)• 7 t(4)·3 t( 5) ·3 n•O p-0
2' 6 .. 8/ t(l)•6 t(2) · 6 t{3)•3 t(4)-8 t(5)·5 n•lO p-20
4'. 10. 1. 0 t(l )•l t(2)-2 t{3)•3 t(4)o4 t(5)•10 n-1 p•O
Remarque:
Les possibilités d'omission d'infOrmation et de mise en facteur que procure le fOrmat
libre ne se retrouveront pas dans le cas de lecture avec un format Aussi, l'utilisateur
d'un programme, s'il n'est pas prévenu explicitemen~ ne peut pas savoir s'il a
effectivement le droit d'en (ab)user.
Comme nous l'avons déjà vu, les instructions d'écriture en format libre fournissent les
informations suivant une représentation adaptée à leur type. Suivant leurs valeurs, les
nombres réels peuvent être écrits en notation flottante ou en notation exponentielle, ce qui,
manifestemen~ ne facilite pas l'affichage de grands tableaux de valeurs.
s. Q1,1'il serak tO\lteloi.s boa, dans un cas r«.I, de faire comaître à f\ltiis:ato.ar, ce qui n'ttail pu le cas dan.s notre
120 V L Les entrées-sorties standards
D'une manière générale, le comportement exact du format libre n'est pas défini par la
nonne du langage; il dépend donc de la machine. Dans œs conditions, le fOnnat libre en
écriture est généralement réservé à l'écriture de petites quantités dfofonnations ou, le cas
échéant, à des informations que l'on se contente d'afficher pendant la phase de mise au
point d'un prognunme6.
Comme nous l'avons laissé entendre dans les deux paragraphes précédents, les mctivations
pour imposer un format ne sont pas les mêmes suivant qu'il s'agit d'instructions d 'écriture
ou de lecture. Dans le premier cas, il s'agit probablement de maîtriser la présentation de
ses résultats; dans le second cas, il peut s'agir d'une adaptation à des données existantes
non adaptées à un fOrmat libre (naturellement, cela signifie que les données en que!tion
ont déjà été créées, autrement dit que l'on travaille en 'mode différé' et non pas en 'mode
conversationnel).
Néanmoins, le 'formalisme' est le même dans les deux cas Qecture ou écriture) ; nous
allons le décrire dans ce paragraphe.
Tout d'abord un format se présente toujours comme une liste de descripteurs, placée
entre parenthèses, comme dans cet exemple qui peut être utilisé pour lire ou écrire deux
entiers (nous verrons plus tard la signification exacte de ces descripteurs) :
( 13. 14)
Pour spécifier un format dans une instruction d'entré~rtie. vous disposez de deux
possibilités7 :
- introduire ce format sous forme d'une chaîne de caractères (à la place du caractère •
qui représente le format 'libre'1 ce qui conduit às :
read ' (13, i4)'. n, p wrlte '(13, 14)', n, p
prce,ramme o::einple.
6. Cette runarque ne S'applique p.sdu 1o.i1 au ronnat libreen lecture.
7. La seconde est toutelok ronàdtrte comme •<iûvite" mai.s ns'agissait de la tonne usuelle en A>rtran 77.
S. Ri ppe.Jons que let chaînes de cana:~res peuvent ttre indifûtrnrnent Umittes par des apoctrOphet (')ou par
desguin emeu('}
Vl Les entrées-sorties standards 121
- faire figurer ce format dans une instruction indépendante de mot clé format ,
possédant une étiquette9 et mentionner cette étiquette dans l~nstruction (toujours à la
place du caractère •) :
read 1025. n, p wrlte 1025. n, p
Cette 'instruction format' peut être placée n~mporte où, parmi les instructions
exécutables.
La seconde possibilité est considérée comme "périmée" en Fortran 90. On pourrait
objecter qu'elle a favantage de n'écrire qu'une seule fOis un format qu'on peut utiliser dans
différentes instructions : en fait, nous verrons que la notion de variable de type caractère
(sous-entendû de type chaîne de caractères) permettra d'obtenir la même souplesse en
utilis.ant la première forme (on y mentionnera le nom d'une chaîne au lieu de fournir une
chaîne constante).
Nous allons &udier ici les descripteurs les plus usités dans un format d'écriture. Les autres
descripteurs sont décrits dans l'annexe O. Pour chaque descripteur Qes symboles w, p et d
l'accompagnant représentent toujours des constantes entières s.ans signe), nous fournisrons
les résultats fournis par une instruction d'écriture pour différentes valeurs pœsibles des
variables correspondantes Qe symbole représente un espace). Nous supposons que n et
A
p sont des variables entières,x et y des variables réelles et ok une variable logique.
Notez que toute lettre appara.iss.ant dans un descripteur peul indifféremment être écrite en
majuscule ou en minuscule(comme dans les mots clés).
5 23 -5-23
- 12 45 - 12-45
-23 4521 -234521
9. La nocion d't:liquette, peu \ltih 6e en Fortran 90, a c\:16 pn!sent«. en mtme temps que l'instNClion go to:
rappek:>ns qu'il S'agil d'une consunte endttt. sans signe de 1à S c~ruditrtremede O.
122 VI. Les entrées-sorties standards
-247 28
Le descripteur i3 affiche la valeur correspondante (qui doit être entière'°} sur 3 caractères,
cadrée à droite, Si le "gabaril" (ici 3) est insuffisan, il y a écrilure d'étoiles(•); c'est ce qui
se produil dans le dernier cas. NOlez que, contrairement à ce qui passai! avec le format
libre, on peut très bien, lorsqu'on impose soi-même un forma~ ne plus avoir d'espaces
entre plusieurs valeurs: c'est ce quise passe dans le troisième cas.
2.5
-47 .678
100000.
Le descripteur f8.2 écril la valeur correspondante (qui doit être réelle11) avec la notation
OOltante, sur 8 caractères, avec 2 chiffres (il y a arrondi au plus proche) après le point
décimal (lequel compte pour un emplacement dans les 8 prévus). Là encore, si le gabarit
est insuffisan~ il y a écrilure d'étoiles: c'est ce qui se produit dans le dernier cas
2.5 "0.2500E+01
-47 .678 " -0.4768E+02
Le descripteur El2.4 écril la valeur correspondante avec la nOlation exponentielle avec une
manti~ "normalisée", c'est-à-dire comprise dans l'intervalle [0,1;1r 2 avec un gabarit total
de 12 caractères, 4 d'entre eux étant réservés aux chiffres significatifs de la mantisse,
Remarques:
Comme le montrent ces exemples, un descripteur de format peut être constitué d'une
chaîne de caractères constante telle que "11or>Wre: •.Son rôle est alors simplement d'écrire
le texte correspondant On note que, cette fois, un tel descripteur ne correspond plus à un
élément de la liste; il se suffit en quelque sorte à lui-même. On parlera dans ce cas de
descripteur passlr (on parle aussi de descripteur de contrôle); dans le cas où un
descripteur correspond à un élément de liste (comme par exemple/, F ou E), on parlera
de descripteur actlr (ou descripteur d'édition).
Notez bien que les espaces obtenus dans les résultats proviennen~ pour les uns de ceux
figurant dans le descripteur de forma~ pour les autres, d'espaces ajoutés à gauche pour
compléter le "gabarit".
Remarques:
1) Dans notre exemple, nous avons délimité la chaîne correspondant au format par des
apostrophes, tandis que nous avons délimité chaque descripteur par des guillemets.
Nous aurions pu faire l'inverse. En revanche, nous n'aurions pas pu écrire, par
exemple:
print '('norrbre : ' , i3, •va leur : '. i4)', n, p ! incorrrect
En eff~ la deuxième apostrophe aurait été considérée comme mettant fin au format et
une erreur de syntaxe n'aurait pas manqué d'appanu"tre. Nous reviendrons plus en
détail sur ces problèmes d'introduction d'un caractère délimiteur dans une chaîne dans
le chapitre VIII consacré aux chaînes de caractères.
124 VI. Les entrées-sorties !tandards
print • . 'bonjour'
qui écrit ... rien (la liste est vide) suivant le fttmat ("bonjour'), lequel comporte un
descripteur passif demandant d'écrire le libdlébonjatr.
2.5 8 .25
Le descripteur (passif) .lr demande simplement d'écrire 3 espaces. JI e!t, en fait, équivalent
au descripteur ..................
. true .
. false.
13. Note2 que legabll.rit w figure îd devant lasp!cl îcation e t non derrière.
VL Les entrées-sorties standards 125
Le descripteur 110 est un descripteur passif (ou "de contrôle") qui demande de •se placer"
sur le dixième caractère de la ligne, Nous aurions pu obtenir le même résultat avec le
descripteur x, mais il nous aurait fallu compter "manuellement• les gabarits des différentes
informations écrites:
print '(9x. "n••. i4. 6X. "p•". i3) '. n. p
5 23
Cette fois, pour bien comprendre Je rôle du descripteur 1, il est nécessaire de savoir qu'en
Fortran finformation à écrire est transmise à funité de sortie, non pas progressivemen~
mais "ligne par ligne" (dans tous nos exemples, nous n'écrivions qu'une seule ligne, mais
nous verrons bientôt des cas où l'on en écrit plusieurs) . Autrement di~ on commence par
préparer dans un emplacement mémoire (nommé "tampon14") une "image" de la ligne
qu'on souhaite écrire. Tant que cette derniêre n'a pas été transmise à funité de sortie, il est
donc possible d'en modifier le contenu. C'est précisément ce qui se passe dans notre
exemple où, grâce à ce descripteur 1, il devient possible de se "positionner" n'importe où
dans ce tampon donc, en quelque sorte "d'avance!" ou de "reculer" à son gré.
Naturellemen~ un tel résultat serait impossible à obtenir si finformation était effeaivement
transmise à l'unité de sortie, au fur et à mesure de sa constitution.
Naturellemen~ un tel mécanisme a ses revers puisqu'il permet (généralement par
mégarde) d'écraser (éventuellement partiellement) dans le tampon une information qui y a
déjà été placée, En voici deux exemples significatifs :
5 23 -ps""23'5
t25 476 ""p-""47625
25 145 nombre 25
'la leur 145
En fait, notre instruction d'écriture est rigoureu sement équivalente aux deux instructions
s uivantes:
print ' •" nombre , i4) '
print ' •" 'laleur , i4) '
25 145 nombre 25
Ren1arques
1) Il n'est p a.~ nécessaire de sépar er Je descripteu r I des autres à l' aide d'une virgule. Le
fai re ne constitue cependant pas une erreur ~ l'inst ruction de notre premier e.x emple aurait
pu également s'écrire:
print ' •"nombre " , i4, / , " 'laleur ", i4) '
2) Nous verrons (dans Je paragraphe 4 . J 0) que certaines impri1n antes attribuent une
signification particulière au premier c ar actère de c haque ligne ~ dans ce cas, les résultats
imprimés par les exemples précédents poutTont se présenter légèrement différemment.
VI. Les entrées-sorties standar ds J 27
Ce n 'est que lors de l'exécution que l'on obtiendra un mess.age, accompagné d' w1 arrêt du
programme.
Autrefois, certain." pé1i phériques d'impression n 'impri1naient pas le premier car actère de
chaque ligne car ils l'utilisaient pow· "contrôler" l'avancement du papier (on par lait souvent,
dans ce cas, de "car actère de contrôle" de l'impri1nante). Voici les significations des
car actères tels qu'ils étaient définis par Fortran 90, sachant qu'après l'impression d' w1e ligne,
l'impritnante restait positionnée sw· cette dernière (de sorte qu'il était éventuellement possible
de la surchager lors de l'impression d'w1e nouvelle ligne):
blanc avancer d'une ligne avant d'imprimer (cas usuel): si toutes les lignes sont imprimées
ainsi, on obtient bien des lignes consécutives,
+ ne pas avancer avant d'imprimer : on imprime donc sur la ligne précédente,
0 avancer de deu.x lignes avant d'imprimer (ce qui laisse une ligne blanche entre la ligne
que l'on va imprimer et la précédente).
passer au début d'une nouvelle page avant d'imprimer,
Autre Tout autre caractère a le même effet que l'espace (mai"· attention, il ne sera pas
imprimé!).
Même lorsqu'un programme se contentait d'atfteher des infonnations à l'écran, il était
prudent de prévoir de commencer chaque ligne par un espace. De cette façon, on ne
rencontrait aucun problème s'il fallait modifier Je programme pour qu'il envoie ses
info nnations sw· un pé1i phérique utilisant un "car actère de contrôle".
C'est pour cette raison que les écritures avec fonnat libre ajoutent systé1natiquement w1 espace
en début de c haque ligne. Ceci reste vrai pour Fortran 2003 ou 2008 alors que, théoriquement,
la notion de car actère de contrôle n 'est plus pri~ en compte dan." ces versions.
15. o ·uillrurs, cdo sera totolemcnt impœsiblc lorsque Io d ite chaîne sera placée dans une "\'nri:iblc" dont, p.u
définition, le contenu n' est plus défini il Io compilation.
128 VI. Les entrées-sorties standards
Rappelons qu'en général les lectures en format libre seront suffisantes dans la plupart des
cas et qu'il faudra donc résener remploi d'un format en lecture à des situations
exceptionnelles.
C-Omme nous fa\Ons fait pour les instructions d'écriture, nous allons maintenant examiner
(un peu plus succintement toutefois) les principaux descriptems de format que l'on peut
utiliser dans une instruction de lecture (il s'agit des mêmes que pour une lecture mais,
parfois, leur signification doit être nuanœet6). U encore, vous en trouverez la liste
complète en anneJ<e O. Dans tous nos exemples, nous indiquons l'information fournie en
réponse à finstruction de lecture et, à sa droite, les valeurs attribuées aux variables
correspondantes.
• 42-15 42 15
'124547 12 4547
' - 3-- 456 -3 -4
lei, comme \Ous pouvez le constater, la notion de séparateur n'existe plus. Le giibarit
mentionné dans le spécificateur définit exactement le nombre de caractères qui sera pris
en compte dans finformation lue. Ainsi, ici, la valeur de n est formée avec les 3 premiers
caractères e t celle de p avec les 4 caractères suivants.
Si l'on fournit plus d 'information que l'instruction rien exploite (c'est le cas du dernier
eJ<emple), l'information excédentaire sera pmement et simplement ignorée; en effet, il ne
faut pas oublier que la lecture suivante prendra en compte une nouvelle ligne
d'information (il est possible de modifier ce 'comportement par défaut• ; nous n'en
parlerons que dans le chapitre consacré aux fichiers).
Bien entendu, la notion de 'donnée absente", dont nous avons parlé à propos du format
libre, n'a plus de signification ici (\Oyez le troisième e>emple). On peut toutefois
s'interroger sur ce qui se produirait si l'on fournissait moins de caractères que prévu (ici,
16. Tout simplement parce que, pOrtant sur une Cptration difîtrente, les«>ntnûntessont parfois dfTt~tes.
VI. Les eitrées-sorties standards 129
moins de 7 (4 de i4 + 3 de iJ). Nous verrons que, même dans ce cas, il y aura toujours
'quelque chose•.
read '(f8.2)'. x X
D'une manière générale, à l'intérieur du gabarit spécifié, on peut trou-er un nombre écrit
en notation exponentielle (avec e, E, d ou D) ou flottante ; dans ce cas, la valeur de d n'est
pas utilisée: c'est ce qui se produit dans nos trois premiers exemples. En oltre, il est
permis d'utiliser la notation exponentielle, sans la lettre indiquant fexposant, à condition
que ce dernier soit précédé d'un signe + ou _17 : c'est le cas dans notre quatrième
e>emple.
Remarques:
1) Lorsque nous disons, par e>emple, que la variable x prend la valeur 3.452, il faut
sous-entendre qu'il s'agit d'une valeur approchée, compte tenu d'une probable erreur
de représentation.
•t2-·238 12 238
123456789 123 67~
1234567890 234 90
En voici un second, dans lequel on se permet d'explorer plusieurs fois une partie des
informations lues :
Notez bien que s'il est possible de se passer du descripteur t dans le premier cas, il n'en va
plus de même dans le second cas (à moins de demander à fu tilisateur de fournir deux fois
la même information!) .
Le descripteur/ prO•O)Que la lecture d'une nouvelle ligne dans le tampon; bien entendu,
les informations de la ligne précédente ne seront plus exploitables. Voici un exemple:
1234"47
21 123 21
•4·2-i-·57g 42 15
Il correspond au comportement par défaut du Fortran 90. On voit que les espaces figurant
dans les données sont purement e t simplement ignor~ (toutefois, quand un gabarit ne
contient que des espaces, la valeur correspondante est ûro). ~la peut paraître •naturel" ;
toutefois, il fau t sa•o:>ir que les •ersions antweures de Fortran (y compris Fortran 77)
interprétaient de tels espaces comme des ûrosl9.
Si cela est absolument nécessaire, sachez que •o:>us pouvez imposer que ces espaces soient
interprét~ comme des zéros en utilisant un descripteur approprié BZ dont nous parlons
dans l'annexe D.
- d'une part, il existe des entrées-sorties non formatées (utilisables uniquement avec des
périphériques d'archivage de l'information - typiquement le disque),
- d'autre part, il existe une deuxième forme des instructions d'entrée-sortie formatées.
Par ailleurs, dans le chapitre précédent, nous avons déjà présenté la notion de "boucle
implicite" dans une liste d'entrée-sortie. Cette notion a été intégrée dans la synta>e ci-
aprés, de sorte que celle-ci est exhausti-e.
20. Dans le cas de lecture dans des riehiers;o on awa. le mtmecomp0rtement mais on p0urra alors le môdifüer en
utlli$1l.nl le paramètre po.d = <Jans l'instruction q:ien (il n'existe pas <f«)uivalent pOur let lecturesstan<Jar<Js).
VI. Les entrées-sorties standards 133
4 i5
est équivalent à :
i S, iS, iS, iS
D'autre part, il est également possible d'appliquer un tel facteur de répétition à un groupe
de descripteurs (actifs ou passifs) placé entre parenthèses. Par exemple:
est équivalent à :
2x, i3, Sx, 18.2, 2x. i3, Sx. 18.2. 2x. i3, Sx, 18.2
Les répétiti-Ons "imbriquées" sont autorisées, de sorte que cette construction est correcte :
n • 5
print "(l x, i2, 'etœ ' / t4, 'cas' , f!0.3, " -")', n
écrit (en supposant que le premier caractère de chaque ligne est effectivement écrit) :
VI. Les entrées-sorties standards 135
Notez que les descripteurs /, t4 et 'cas' ont été traités. Le descripteur '-' ne l'a pas été,
puisqu'il est précédé d'un descripteur actif non utilisé.
Ri!marques:
on obtient bien :
bonjoll'
De même, avec:
n • 5
print *( lx, i3, 'eire va leur')*
on obtient bien :
-"Seme valeur
2.4.Nous parlons ici de •changement de ligne•, dans la mesure où notre propos s'applique au.'I: entréts:-sortics
standards:. Lorsque nous généra tiserons ces p:>SSiblités à des 6chiers, nous parlerons plutôt de "changement
d 1cnrcgistrcmcnt'". De plus, la dgledevrattrequeque peu •nuancée' pour tenir compte des p:>SS.ibilitcs que vous
aurez de ne pas changer S)Stématîquement d'enregistrement à chaque nouvelle opération (en utilisant Je
paramètre advance= 'no1).
136 VI. Les entré.es-sorties standards
chaque réexploration (c'est-à-dire en faisant 'comme si" une nouvelle instruction d'entrée-
sortie avait été demandée).
Si le format ne contient qu'Une seule paire de parentMses (c'est-à-dire s'il n'y a aucun
facteur de répétitioo de groupe), on explore à nouveau tous les descripteurs depuis le
début.
On change de ligne
S'il s'agit d'une lecture, on lit une nou\dle ligne, avant de poursuivre l'exploration du
format.
S'il s'agit d'une écriture, on écrit la ligne en cours de compœition et on prépare une
nou-elle; notez que si elle est destiree à une imprimante qui • mange le premier caractère',
il faudra bien faire en sorte que cette nou-elle ligne dispose à son tour de son 'caractère de
contrôle~.
Exemple 1
:Z.S. Il s'a&it d'aiDeurs là d'un oubli fréquent qui se traduit souvent par une "OliPIW'C d'aJj~ement • entre la
premièreUgneet laou Jes suivantes.
VI. Les entrées~rties standards 137
Exemple2
reo I , dimension (1 5, 5) :: a
m 1 • 1. 15
print • (lx. Sel6.8)", a(i,:) 1 on prévoit un *caractère œ contrO le*
"1d do
Si l'on souhaite ' numéroter" les lignes, on pourra s'y prendre ainsi:
m i • 1. 15
print • (lx, 13, 5el6.8)" , i, a(i,:)
end m
ou ainsi:
EXERCICES
program esl
impHcit rone
integer :: n•lO. pa5
real : : x-2.5. y-3.5
read • , n, p, x, y
print •(lx, il, 2x. i2. 2(18.2. 2x))•, n, p, x, y
elll
a) 1·8·12·25
b) 1.8.. 25
c) 2'. 2'5
proçram es2
inplicit nore
integer : : ""12l. p-4567
real : : X•l 2.l65, y-l.256e5
print •(lx, i4. i5}". n, p
print •(lx, il, i4}", n, p
prlnt •(lx, il, 2x, i2)", n, p
print "(lx, 2fl0.l)". x, y
print •(lx, i2, 16.l. 2x. i4, f7.0)•, n, x, p, y
print "(lx, 1valeur œ n :'/lx. 14 //lx, 'valeur de p :' /lx. t4)*, n, p
print •(t8. il. t 2. i4, t6 •• : ')•' n, p
pr int •(1x. '•• '. 18 .l. t 7, il)•, x, n
elll
VI. Les entrées-sorties standards 139
A 8
ligne 1 a( 1.1 ) a(l ,2) a( 1. 3) b( l.l ) b( l. 2)
ligne 2 a(2.l) a(2.2) a(2.3) b(2.l) b(2.2)
...............
...............
ligne 5 a(S, l ) a(S.2) a(S.3) b(S, l ) b(S,2)
VII. LES SOUS-PROGRAMMES
ET LES FONCTIONS
Comme tous les langages, Fortran permet de découper un programme en plusieurs parties
nommées souvent "procédures1•. li s'agit là d'un des aspects de la programmation
structurée (on la nomme aussi programmation modulaire) qui se justifie pour plusieurs
raisons:
- Un programme écrit d'un seul tenant devient difficile à comprendre dès qu'il dépasse
une ou deux pages de texte. Un découpage en procédures permet de le scinder en
plusieurs parties et de regrouper dans le "programme principal" les instructions en
décrivant les enchaînements. Chacune de ces parties peut d'ailleurs, si néœssaire, être
décomposée à son tour en parties plus &mentaires; ce processus de décomposition
pouvant être répété autant de fois que nécessaire comme le préconisent les méthodes
de 'programmation structurée".
- La décomposition en procédures permet d'éviter des séquences d' instructions
répétiti.es, et cela d'autant plus que la notion "d'argument" permet de "paramétrer" les
procédures en question.
- La programmation par procédures permet le partage d'outils communs qu'il suffit
d'a~ir écrits et mis au point une seule fois.
1. On parte aussi de "module•, INLÎS oc terme pOatdera une signification particulière en Fortran.
142 VII. Les sous-programmes et les fonctions
Comme la plupart des autres langages. Fortran dispose de deux sortes de procédures:
En Fortran 77, les procédures ~ent toujours des "unités de compilation" distinctes.
Plus précisément, chaque procédure était compilée comme un tout, indépendamment de
toutes les autres et du programme principal susceptible de l'utiliser (ou des programmes
principaux ou des autres procédures). Ceci restait vrai quand plusieurs procédures
myaient leurs instructions regroupées dans un même 'fichier source'.
En Fortran 90, on consel"e bien s(lr la possibilité de créer des procédures séparées: on
parle alors de "procédures externes'. Mais, de plus, chaque procédure, ainsi que le
programme principal, peut définir ce que l'on nomme des "procédures internes' . Ces
denlières s'appellent exactement de la même manière que les procédures externes mais
elles ~ont compilées en même temps que la procédure ' hôte" (c'est-à-dire celle qui les
contient); on -erra que œtte nuance autorise le partage d'informations, non plus
seulement par argument, mais également par "variables globaJes4".
2. Dans certllins langages. œ dit qu'il existe deux sortes de modules : les proœdW"ts et les fonctiœs. lei, le mot
sous.prognunme conupond à procédure, tandk le mot procédure oonupond à mOdule; QUMt au mot mOdule,
nous ~rrœs qu'il pc:aède en Fortran 90 une signification pré.dse...
l. En f.'lit, en Fortrm 90, cc:mme dans la plupart des htn#l#S, la fonctiœ peut qUMd mlme rtaHser une action,
bien que oe ne soit pas là sa vocation.
VU. Les sous-programmes et les fonctions 143
mtrée (in), sortie (out) et entrée/sOi'de (inout)S. Fortran 77 ne faisait pas de telles
distinctions et nous verrons d'ailleurs qu'il restera possible d'Utiliser sa façon de faire,
laquelle, au demeurant, ne correspond pleinement à aucun des trois modes précédents.
Ce chapitre va commencer par wus présenter sur des exemples les notions de sous-
prograrnme externe et interne, ce qui, dans le second cas, nous amènera à vous présenter
la notion de variable globale. Nous examinerons ensuite les différents •modes• de
transmission des arguments. Puis nous aborderons l'importante notion d'interface
(introduite elle-aussi par Fortran 90) et la manière dont elle vous permet de •fiabiliser' les
appels de procédures; plus tard, nous verrons qu'elle est également indispensable pour
exploiter les pœsibilités de création de modules, de surdéfinition des opérateurs, de
procédures génériques_.
Nous ferons ensuite le point sur tout ce concerne la transmission de tableaux en argument.
Nous -errons notamment comment la notion de profil implicite introduite par Fortran 90
facilite énormément les choses. Nous parlerons ensuite des variables automatiques
(variables définies dans une procédure) et nous verrons comment Fortran 90 vous permet
de définir des tableaux automatiques dont la taille ne peut être définie que lors de
l'exécution. Nous découvrirons qu'une fonction peut fournir un résultat qui soit un tableau
(et non plus seulement un scalaire). Nous étudierons la façon de définir des arguments
optionnels, d'appeler une procédure en lui transmettant des arguments par mot clé. Nous
terminerons par les procédures transmises en argument et les procédures récursives.
4 . A ttention, oette notiœ n'a guère de lien a\C.C ks: ~roMMON" du A>rtran T1. Cœnaîssews! Patientez jusqu'au
(hapitre XI où vous verrez (Œlmt.nt m.ieuxprog.ntmmeren Fortran 90,(ette possibiUtédésorma.is "dtsuttc•.
S. Attenti>n, oeci ne préjuge en rien de la manière dOnt l'iNormaitiœ est récUemcnt ttanszrise (pm valeur ou par
adresse....).
144 VII. Les sous-programmes et les fonctions
program exple_sous_progranme
impl icit none
inte~r :: n • 2
print • , 'appel optimist (n)'
ca 11 optimist (n)
print •, "'appel optimist (2*n+l)'
call optimist (2*ntl )
erxl
Remarques:
6. Mtme, nippelons-te. br&quc le prognimrne princ4>il1 et b prooéduru externes figurent dans un mEmc fChicr
wuroe.
VII. Les sous-programmes et les fonctions 147
program exple_sous...,Progrèlflle
tnplicit none
integer :: n • 2
print • . ' appel opttmist (n)'
call optimist (n)
print • ;'appel optimist (2*n+l )'
call optimist (2 *n•l )
contatns
slbroutine optimist (n_fois)
integer, intent (in) .. n_fois déclaration del ' argument n_fo is
tnteger :: i déclaration d'llle variable "locale"
OO i • 1. n_fo ts
print *, 1 il fait beau 1
end do
end si.brout ire opt imist
end
Cette fois, il n'y a plus qu'une seule "unité de programme" commençant par ren-tête
prOtp'Uln et terminée par l'unique instruction tJJd. La définition du sous-programme
optimist est restée la même mais elle est placée entre la fin du programme principal et une
nouvelle instruction contains, laquelle précise que notre unité de programme (ici le
programme principal) "contient" des procédures internes dont la définition vient à la suite.
La procédure interne est donc définie en même temps que le programme (ou la
procédure) qui l'utilise qu'on appelle son "laôle". Contrairement à une procédure externe
qui était accessible à qui souhaitait l'utiliser, la procédure interne n'est accessible qu'à son
hôte7 .
7 . Ap:ès cc:mpilation d'une p:O<idure externe, il reste, dans le mOdule Objet, une traoe de son nom (on a affaire à
ccqu'œ nomme un nom externe). Oms le cas d'une procidure interne, il ne reste aucune trace desœ nom, pas
plus qu'il ne reste une trace des noms des dftérentes variables locales à la procédure.
148 VII. Les sous-programmes et les fonctions
Dans le cas des procédures externes, on est en présence de domaines indépendants qui ne
peu-ent communiquer que par le biais des arguments. En revanche, dans le cas des
procédures internes, il en va différemment puisque: la procéd ure interne a accès à toutes
les variables définies par son hôte (on parle alors dans œ cas de variable globale). Elle
peut aussi bien en utiliser la valeur que la modifier.
Si nou.~ voulions écrire trinome sous fonn e de s ou.~· programme ext erne, il fa udrait absolument
faire de a, b et c des ar gument~.
D'une manière générale, les procédures internes sont généralement réservées à des procédures
relativement courtes, n 'ayant d'intérêt que pow· w1e. application donnée, c'est .à.dire n 'ayant
que peu de c hance de pouvoir êt re utilisées en dehors du contexte da n.~ lequel elles ont été
définies3.
Quant à la notion de variable globale, il fa ut considérer qu'elle n 'est que le "sous· produit" de
la notion de procédure inte1u e. Elle ne doit êt re utilisée qu'avec parcimonie, dans la mesure
où elle est génératrice de ce qu 'on nomme des risques d'effets de bord, c'est ·à · dire de
modification non désirée de var iables.
Voici, à titre d'exemple de ce qu 'il vaut mieu x evrte1 de fai re, delLx autres versions du
précédent programme. Dans la première, nous avons remplacé la transmission par argument
(nJoi.r) par w1e variable globale (de même nom, ici):
subroutine optimist
inte9er i ! déclaration d ' une '!aria.ble "locale"
do i = 1, n_fois
print ', ' il fait beau'
end do
end subroutine optimist
end
8. Cc qui n'exclut nulle-ment que k-ur procédure hôte soit, q uant it d ie-, d ïntérêt !,>énéml.
150 VII. Les sous-programmes et les fonctions
Dans la seconde, nous avons fait du compteur de boucle i (initialement local à optimist),
une variable globale (imagingez les risques d'erreur encourrus dans le cas où le
programme principal utiliserait, lui auss~ la variable i!) :
program test
inte~r : : n, p, q
call sp (p)
conta ins
subrout ine sp (n)
real q
end subroutine sp
end program test
remarque s'appliquerait à une variable locale; par ei<emple, ici, dans sp, q désignera
toujours la variable locale et la variable globale q sera masquée.
Remarques:
1) Les étiquettes ne sont pas soumises aux même règles de portée que les variables;
plus précisément, la portée d'une étiquette est toujours limitée à la procédure (même si
elle est interne) dans laquelle elle est définie. En particulier, l'usage des étiquettes en
Fortran devrait être très limité.
2) En revanche, la portée d'une instruction de déclaration telle que implicit reste bien
l'uruté de compilation. Ainsi, dans notre exemple du paragraphe 2.2, elle s'applique
aussi bien au programme principal qu'à la procédure interne binome.
3) Aucun des problèmes de portée que nous \'Cnons d'évoquer ne se posait dans le cas
de procédures externes (puisqu'il y a totale indépendance...).
4) Ce que nous avons dit à propos des sous-programmes s'applique naturellement aux
fonctions; ainsi, une fonction pourra être externe ou interne et, dans ce dernier cas,
utiliser éventuellement des variables globales.
Jusqu'ici, dans nos exemples, nous avons déclaré nos arguments avec fattribut intent (i11)
sans trop nous préoccuper de sa signification exacte. En Fortran 77, on ne faisait aucune
distinction entre les différents arguments. En Fortran 90, on peut continuer à ne faire
aucune distinction (nous y reviendrons un peu plus loin). Mais, il est possible de préciser le
genre? d'un argument ; certes, en soi, cela n'apporte pas de possibilités nouvelles mais le
compilateur peut faire des vérifications supplémentaires et, partant, vous éviter certaines
erreurs de programmation.
a) lntent (ln)
Cet attribut signifie que l'argument correspondant est un "argument d'entrée', c'est-à-dire
que sa valeur ne doit pas être modifiée par la proredure correspondante. Par ei<emple,
a\'CC:
9. Le tenne genre n'at pas uni-..crse.I ;on peut parler de type (mais 1 y a contusion avec le 1ype œune ~ri.able), de
mOde (mais on peut alors songer à un mode de transmission, oe qui, comme nws le venons, ne recouvre pas
(.'(actemement ta memecbose).... LesAngJa.is,quantà eux, conservent le terme intcnt
152 Vil. Les sou,,. programmes et les fonctions
n • 5 interdit
b) lntent (out)
lnterd it
c) lntent (lnout)
Cet attribut signifie que rargument ccnespondant est à la fois un argument d'entrée et un
argument de sortie. La procédure peut utiliser sa valeur et elle doit lui en attribuer une
nouvelle. Voici, par e>emple, un sous-programme qui échange les valeu~ de deux
variables:
Rl'!Darques :
1) Pour l'instant, nous a~ns vu l'incidence du choix du genre d'un argument dans la
dêfinition de la procédure correspoodante. Nous verrons que cela a également une
incidence sur la manière dont on pourra l'appeler. Toutefois, dans ce cas, pour que le
compilateur puisse effectuer une queJcooque vérification de rappel, il faudra qu'il
Vil. Les sous-programmes et les fonctions 153
4 - LES INTERFACES
aucun diagnostic ne vous sera fourni lors de la compilation. Lors de rextcution, le sous-
prograrnme recevra le "motif binaire' correspondant au codage de 5.25 dans le type réel et
il l'interprétera comme un entier, ce qui reviendra à considérer une valeur francbement
différente. li n'y aura toutefois pas de détection d'erreur d'exécution à proprement parler.
10. Nous verrons plus pr6::is6ment oe que doit t trecette oom:spondanoede type dans )e paragraphe 11.
154 VII. Les sous-programmes et les fonctions
interface
subroutiœ optimist (n_fois)
· integer, intent (in) :: n_fois
eOO subroutine optimist
end interface
Notez bien que notre déclaration se présente sous la forme de ce qu'on nomme un ,,toc
d'interface• (il commence par interface et il se termine par errt inteiface). A l'intérieur de
ce bloc, on trouve une ou plusieurs (ici une seule) "déclarations d'interface• (on dira
souvent 'interfaces• tout court) ; chaque déclaration est formée de l'en-tête de la
procédure concernée et des déclarations relatives aux arguments.
Ici, nous n'avions qu'une seule interface de procédure à l'intérieur de notre bloc
d'interface; nous pourrions en avoir plusieurs comme dans cet ellemple :
interface
subroutine spl (n, x)
integer, intent (in) :: n
real, intent (out) :~ x
end subroutine spl
subroutine sp2 (z)
real, intent (in) :: z
end subroutine sp2
end interface
Notez qu'il serait également possible d'écrire deux blocs d'interface différents, l'un pour
spl, l'autre pour sp2. En général, cela n'a guère d'intérêt.
11. Par souci de simpli.ficaticm, nous parlons de programme, sachant qu'en fait il peut s'agit aussi bien d'un
programme principal (c'est lasituatiœ que nous avons renoontr« juSC.JU'ici)qued'une pro::é.dure.
VII. Les sous-pr<~rammes et les fonctions 155
Lorsque le compilateur rencontre une interface, il ne connait pas les noms utilisés
effecti\'Cment pour les arguments muets correspondants (compte tenu de la compilation
séparée). Dans ces conditions, on comprend qu'il soit a utorisé (mais guère conseillé)
d'utiliser, dans une interface, des noms d'arguments différents des noms des arguments
muets de la prOctdure concernée.
Nous a\'Ons introduit l'interface comme outil de contrôle du type des arguments; à ce titre,
son usage était en quelque sorte "facultatif" (mais vivement conseillé!). Mais nous
rencontrerons, dans la suite de ce chapitre, des situations où l'interface est indispensable :
tableaux de taille quelconque transmis en argument, procédures transmises en argumem,
fonction fournissant un résultat non scalaire, arguments à mots clés ou optionnels. .. Par
ailleurs, nous découvrirons par la suite que la notion d'interface re\'ilt un aspect plus
général : utlisations de "modules", surdéfinition de fonctions, fonctions génériques...
Remarque:
Pour l'instant, il semble qu'il faille répéter la déclaration d'une interface dans chaque
programme utilisant une prO<édure donnée, ce qui peut para.ùe fastidieux et, de
surcroit, sujet à l'erreur. En fait, nous \errons qu'il existe des solutions évitant cene
"recopie d'information". La première consiste à faire appel à finstruction include qui
perrnet d'incorporer dans un programme (source) des instructions figurant dans un
fichier12; la seconde (et, de loin, la meilleure!) réside dans la notion de "module" que
nous étudierons plus loin.
5 - LES FONCTIONS
La notion de fonction en Fortran \'Ous est en fait déjà familière; en effet, nous avons déjà
utilisé des "fonctions intrinsèques", c'est-à-dire des fonctions fournies a\'Cc le langage lui-
mêmel 3. Comme nous l'avons dit en introduaion, vous pouvez définir vos propres
12. En fait, bien qu'inlr0dui1e par Fortran 90œ11e instruction es1oonsictéréc oommedésuê.1e.
11 Bn toute rigueur, il cxîstcdœ5ous--programme5 intrînsèquc5 maî5 nous n'en avon5 pa5 encore rcnoontré.
156 Vil. Les sous-programmes et les fonctions
fonctions d'une manière vo.sme de celle dont \O'.lus définissez des sous-programes.
Notamment, une fonction pourra être interne ou externe, de sorte que nous nous
contenterons d'en présenter remploi dans le cas de fonction externe. D'autre part, tout ce
que nous avons dit concernant les variables locales, les variables globales et les arguments
restera valable.
Par ailleurs, le nom même de la fonction (ici trinome) sert, au sein de sa définition, à
désigner le résultat qu'on souhaite qu'elle fournisse. C'est ce qui justifie:
- la déclaration de type d'une variable de même nom que la fonction; elle permet donc
de préciser le type de la valeur que fournira la fonction (on parle souvent plus
brièvement du •type de la fonction").
- l'affectation d'une valeur à cette variable.
Remarques:
1) Ici, nous a\O'.lns utilisé le nom même de la fonction pour désigner le résultat qu'elle
produit. Cette démarche, déjà utilisable en Fortran 77, nous semble la plus naturelle.
En Fortran 90, il est cependant possible de donner au résultat un nom différent de celui
Vil. Les sous-programmes el les fonctions 157
y • trirome (a. b, c. x)
Mais il est alors nécessaire que le compilateur coonaisse le type de la rooctJon (c'est-à-dire
le type du résultat qu'elle fournit). Pour ce faire, \Ous disposez de deux solutions:
- placer dans \Oire programme une déclaration précisant quel est le type de la fonction,
à savoir ici :
rea 1 : : tr inone
- utiliser une interface; celle-ci fournira alors non seulement le type de la fonction, mais
aussi le type de ses arguments, ce qui signifie qu'elle permettra en outre un contrôle de
type des arguments :
fuoction trinone (a, b, c, x)
real, intent (in) :: a, b, c, x 1 argunents
14. De plus, rappebn& que, par souci de oompatibili1~ ai.u Fortran 77, vous pouvez aussi ne pas pr6:iscr le genre
d'un argument; dans ce cas, le même risque existera (canme nous le verrons u.o peu plus loin).
158 Vil. Les sous-programmes et les fonctions
A titre indicatif, \O'.lici un exemple complet de programme utilisait notre fonction trinome,
dans lequel la déclaration de la fonction a été faite sous forme d'une interface:
Remarque:
Son utilisation aurait alors été moins aisée que celle d'une (Onction puisque nous n'aurions
pos pu faire directement figurer son nom dans une expression. Certes, une affectation de la
forme y = trinome (a. b, c, x) serait devenue simplement:
En revanche, une affectation telle quez g 2 • ( trinome (a. b, c, x) + trinome (a + 1., b, 2•c,
x + 0.5)) aurait dO s'écrire:
call trinCJne (a, b, c, x, resl)
call trinane (a+!., b, 2*c, x<0.5, res2)
z • 2 * (res l + res2)
Un tableau peut apparaître en argument d'une procédure. Mais, dans ce cas, on voit que se
pose le problème de la façon dont on va pouvoir en connat'lre le profil au sein de la
procédure. Il faut en fait envisager deux situations fort différentes:
a) Le profil du tableau en question est connu (il est donc "fixe") lorsque l'on écrit la
procédure ; dans ce cas la déclaration du tableau (argument muet) ne posera aucun
problème particulier.
b) Le profil du tableau en question n'est pas connu lorsque l'oo écrit la proeédure!S ;
dans ce cas (nous parlerons de •tableau ajustable'). il existe deux manières très
différentes de traiter le problème:
- déclarer (en argument muet) un tableau de profil implicite (on dit aussi variable
ou ajustable): son profil sera automatiquement transmis lors de l'appel, sans qu'il
ne soit nécessaire des' en préoccuper,
15. On p0umùt penser que oc cai se subdivise en deux : profil nœ oonnu mù fire d'une part. prol'il sua:eptible
de varier dVn appel à l1autre d'autre part ; en fa.ît, oomme nous le Yerron~ les deux cas se traitent de la même
manitie.
160 VU. Les sous-programmes et les fonctions
- transmettre en argument, non seulement le tableau, mais (tout ou partie de) ses
étendues.
La première démarche est de loin la plus pratique et la plus fiable. Toutefois, Fortran 77
ne disposait que de la seconde; il vous faut donc la connax"tre si vous devez utiliser ou
adapter des programmesécrits avec cette ..ersion.
Cette situation peut quasiment être traitée avec œ que nous avons déjà vu sur les
procé<lures. Voici par exemple une procédure affichant les valeurs d'un tableau d'entiers
de profil (5,8) :
On pourra rappeler pour n'importe quel tableau ayant le profil (5,8) comme dans cet
exemple de programme principal:
li est très important de noter que la correspondance entre tableau effectif et tableau muet
est uniquement bash sur le p...m. Les bornes exactes des indices n'ont aucune incidence
sur le déroulement des opérations; on rctrou..e là exactement le même phénomène que
dans les expressions de type tableau.
Ains~ dans affiche, si nous faisions appel à 1(1,J). il s'agirait de tJ(J,0) pour le premier
appe~ alors qu'il s'agirait det2(5,J 1) pour le second appel.
VII. Les sous-programmes et les fonctions 161
Notez également que, dans la déclaration de c dans affiche, nous aurions pu spécifier les
bornes des indices (ici, on emploie 1 pour la borne inférieure). Néanmoins, il fllut bien \Oir
que ceci n'aurait d'incidence que sur la manière décrire les instructions de la procédure
elle-même; la corrrespondance entre tableau effectif et tableau muet resterait to~ours
basée uniquement sur le profil.
Remarque:
Que se produit-il si ron appelle affiche en lui transmettant en argument un tableau de
profil différent de celui attendu?
- si finterface de affiche est disponible lors de la compilation de cet appel16 , on
obtiendra un diagnostic de compilation,
- dans le cas contraire, aucun diagnœtic de compilation ne pourra être espéré. Lors de
fexécution, la procédure travaillera avec des éléments du tableau non situés à
l'emplacement \Oulu ; suivant les cas, on pourra n'utiliser qu'une partie des éléments du
tableau ou, au contraire, utiliser des éléments situés à feJ<térieur. Dans ce dernier cas,
les consêquences seront nettement différentes suivant que l'on a affaire à un tableau
transmis dans le mode in (le seul risque étant alors d'utiliser de mauvaises valeurs) ou
dans fun des modes in ou out (puisque alors on pourra écrire des valeurs 'en dehors"
du tableau effectif aYCc les ' conséquences habituelles" inhérentes au débordement
d'indice) ...
On voit donc, une fois de plus, que l'emploi systématique d'interfllces améliore la
fiabilité des programmes.
16. c.e qui revient à dire que soit afffohe est une procédure interne, soit l'interface de affiche est "explicitW pa.r
un blcx d'interface app-oprit.
17. Dans le but, essentiellement, devou.s pennettrede ··u~ d'anciens programmes.
162 Vil. Les sous-programmes et les fonctions
Reprenons rexemple précédent (affli:he) en supposant, cette fois, que le profil de notre
tableau n'est pas connu. Nous pou\O'.lns le déclarer ainsi au sein de affiche:
L'indication dimension (:,:) précise simplement que t est de rang 2 et que son prolll est
implicite, c'est-à-dire qu'il sera effectivement fourni à ajflf:he lors de l'appel. Notez bien
que nous n'a\O'.lns pas à nous préoccuper de la manière dont cette information concernant
le profil sera effectivement transmise (contrairement, par exemple, à ce qu'il fallait faire en
Fortran 77, comme nous le -errons ci-aprês).
En ce qui concerne les instructions à introduire dans notre procédure ajflf:he, une petite
difficulté "technique" apparai"t; en effet, il est maintenant possible que toutes les valeurs
d'une ligne de notre tableau ne puissent plus être écrites sur une seule ligne; dans ces
conditions, le plus sage consiste à écire un nombre maximal de valeurs (par exemple, 16)
par ligne en prévoyant de changer de ligne pour chaque nouvelle ligne du tableau. D ans
ces conditions, on ne peut plus se contenter d'une écriture globale de t ; il faut répéter une
instruction d'écriture de chaque ligne. li faut donc connai"tre le nombre de lignes de t.
Or, précisément, il existe, en Fortran 90, une fonction nommée size qui fournit l'étendue
d'un tableau suivant une dimension donnée. Ainsi:
Pour utiliser notre procédure ajflf:he ainsi réalisée, il nous suffit d'écrire un appel tel que :
Pour udllser une procédure recevant en argment un tableau de prolll Implicite, son
interface doit être connue.
18. En l'absenoe d'une telle connaissanoe, rien ne distingue cet appel a\ee celui que nous aviœs rencontrt dans le
cas d'un tableau de profil f ixe.
vn. Les sous-programmes et les fonctions 163
program affichage_tableau
implicit oone
integer, dimension (1:4, 0:9) .. tl
integer, dimension (9, 10:14) " t2
interface interface obi igatoire ici
subroutine affiche (t) (sinon..,. erreur execution)
integer, intent (in), dirrension (:, :) ..
end subrout ine affiche
erd interface
tl• I
t2=2
ca Il affiche ( tl )
call a ffiche (t2)
end program affichage_tableau
Remarques:
1) Dans le cas de tableau de profil fixe, l'interface est simplement conseillée: son
absenc.e n'a d'incidenc:e qu'en cas d'erreur; ici, en revanche. son absence conduira à
une erreur d'exéeutioo (aucun diagnostic n'est possible en compilation). Là encore, si
vous vous astreignez à l'emploi systématique d'inferfaœs, les choses seront beaucoup
plus agréables.
Z) Ici encore, dans la déclaration de nct.re tableau implicite, nous aurions pu indiquer
des limites inférieures des indices si cela avait pu faciliter la rédactioo de notre
procédure (ce qui n'était d'ailleurs pas le cas ici) ; ceci n'aurait eu aucune incidence sur
son utilisation (puisque seul le profil est transmis!). Notez cependant qu'il serait
164 Vil Lessou.<i-programmeset les fonctions
inco1Tect de préciser à la fois une borne infé1ieure et une borne s upé1ieure (l'w1e des deux
étant déduite auto1n atiquement de l'autre et de la connaissance du protiO. Signalons que
les fonctioll.'i lbound et ubound permettent de connaitre ces bo111es.
Ren1arq ues :
1) On peut touj ours prévoir en argument non seulement les étendues, 1n ais également Jes
bo111es des indices~ généralement, cela aura peu d'intérêt .
2) Compte tenu de la 1n anière dont les éléments d'un tabJeau s ont arrangés en mémoire
(revoyez éventuellement le par agraphe 4.3 du c hapitre consacré aux tableaux). il n 'est en
fai t pas utiJe de connaitre la dernière étendue. Ce qui signifie que vous pouvez ne pas
prévoir d'ar gument pour cette dernière en écrivant par exemple:
subroutine affiche •t, n)
implicit none
inte9êr, intent Hn)
inte9êr, intent Hn), dimension •n, ') ; ; t
Vil. Les sous-programmes et les fonctions 165
Toutefois, lorsque l'argument en question est du genre out ou inout, il faut que la section
ne soit pas ambiguê, c'est-à-Oire qu'il s'agisse d'une vraie variable (comme doit fêtre tout
argument du genre 0111 ou in out - nous y reviendrons dans le paragraphe 11).
Nous a~ns déjà vu ce qu'était une variable locale à une procédure. Nous allons toutefois
apporter ici quelques précisions sur :
- la manière dont sont "gérés' les emplacements mémoire correspondants,
- la façon dont on peut initialiser une telle variable.
Lorsque vous défmissez une variable scalaire dans un programme principal, le compilateur
lui attribue un emplacement en mémoire. Cette remarque s'applique également aux
166 VII. Les sous-programmes et les fonctions
tableaux, du moins tels que nous avons appris à les défmir jusqu'ici 19 : leurs dimensions
sont des expressions constantes, elles sont donc calculables par le compilateur qui peut
ainsi réserver la taille exacte nécessaire au tableau.
De telles variables dont les emplacements sont parfaitement définis une fois pour toutes
par le compilateur sont dites statiques.
En revanche, les variables locales à une procédure sont gérées différemment. En effet,
compte tenu de ce qu'elle n'ont d'intérêt que pendant fexécution de la procédure, Fortran
90 a prévu:
slbroutine ...
On peut dire que, dans ce cas, la variable locale devient statique20 (et non plus
automatique).
19. EIJe ne s'appHquera plus aux tableaux dynamiques <Jont nous parlerons dans le éhapitre comacré aux
pointeurs.
20. On parte parfois dans ce cas <Je "vaiiables rémanentes".
VU. Les sous-programmes et les fonctions 167
Cela revient donc à dire qbe dès lors qu'on initialise une variable locale, tout se passe
comme si on l'avait déclarée avec fattribut save ; ce dernier devient donc facultatif dans ce
cas.
Il est frequent que l'on doive réalisa- une procédure qui nécessite certaines opérations
d'initialisation nécessaires à son bon fonctionnement ultérieur. On peut toujours prévoir un
argument particulier, de type logique, pour commander cette initialisation, laquelle devient
alors dépendante du bon vouloir de l'utilisateur de la procédure (qui peut alors tout
bonnement oublier de procéder à cette initialisation). Dans ce cas, il est préférable de faire
en sorte que la procédure s'auto-initialise lors de son premier appel. On peut, par exemple,
utiliser ce canevas :
if (prein_fois) then
1 traitanent effectue au pre11ier appel
pre11_fois • .false .
eOOif
1 tra itanent usue 1
21. Il s'agi td'uo choix relatM.meot a.d>itra.i.re; oo aurait. eo effet, tgalemeot pu admettrequ'uoevariable lœale
pouvait t treioüialis6e a\oC.C w e e.xpreaio o quelc:cmque, bleotuellemeot difT6reote d'uo appel au suMtnt (c'est ce
qW se passe parexempleeo C).
168 VII. Les sous-programmes et les fonctions
Awe 1 n..-nero 1
Awe 1 n1A11ero 2
Appe l m... ro 3
Awe 1 n..-nero 4
Appe l m..,ro 5
Comme les autres variables automatiques (variables locales non initialisées~ les tableaux
automatiques voient leurs emplacements alloués à chaque appel Fortran 90 tire parti de
cette remarque, en acceptant que les profds de ces tableaux puissent varie. d'un appel à
l'autre-
Voici un exemple de sous-programme nommé echange permettant d'échanger les valeurs
de deux tableaux d'entiers de rang un et de même profil, ce dernier étant implicite
(revoyez éventuellement le paragraphe 6.2.a} :
ta • tb
lb • 1...,
end subrout ine echange
L'utilisation du sous-programme est alors classique; il est seulement nktssalrt que son
Interface soit explicite (soit il s'agit d'un sous-programme interne, soit son interface est
déclarée dans un bloc d'interface22), et ceci pour que le compilateur puisse prévoir de
transmettre correctement les informations nécessaires. En voici un exemple :
Fortran 90 1.0us autorise donc à fournir les dimensions d'un tableau automatique sous
forme d'expressions; bien entendu, on peut utiliser ici autre chœe que des expressions
constantes (c'est ce qui fait tout l'intérêt de la chose!). Toutefois, n'importe quelle
expression n'est pas pour autant légale; par exemple, comme on peut s'en douter, il faut au
moins que cette expression soit calculable au moment de rentrée dans la procédure; cela
signifie:
- qu'elle peut faire intervenir des arguments de la procédure mais, en aucun cas, des
variables locales,
- que les arguments qui y sont mentionnés doi-ent dêjà avoir é{ê dêclarés auparavant ;
ains~ dans notre fonction echange, nous n'aurions pas pu inverser l'ordre des deux
dêclarations de type en êcrivant :
integer. dimension (s ize(ta)) : : teq> 1 •••E~ElR •" ta n'est pas (encore) déclaré
integer . dimension(:):: ta. tb
D'une manière gênêrale, vous pourrez utiliser œ que l'on nomme des expressions de
sp~dfication ; la dêfinition exacte de œ terme vous sera fournie dans l'amexe F .
Dans beaucoup de langages, une fonction ne peut fournir qu'un résultat scalaire. Mais
fortran 90 acœpte qu'une fonction fournisse un résultat de type quelconque et, donc, en
particulier, un tabteau23.
Voyons, par ei<emple, comment êcrire une fonction qui fournit comme résultat une matriœ
carrée identitê (diagonale principale à 1); elle reœvra en unique argument un entier
prêcisant la dimension de la matriœ.
23. Nous renoontreroœ d~u tres lypes non sCILlaires. à savoir les structures.
VU. Les sous-programmes et les fonctions 171
Cette fonction /dent peut alors être utilisée dans n'importe quelle expression de type
tableau, à condition :
Remarques:
1) Si nous n'avions pas voulu utiliser de fonction fournissant un résultat de type tableau,
nous aurions dO faire de ident un sous-programme ; dans ces conditions, il aurait fallu
prévoir, dans le programme appelant, la réservation d'un tableau destiné à aeeueillir la
matrice identité. Ici, cela n'a pas été nécessaire: la matrice identité a été fabriquée
temporairement par la fonction (son emplacement a été alloué lors de l'appel et libéré
à la sortie). Dans certains cas, on pelll aboutir à des économies substantielles de
mémoire.
Par exemple, si vous déclarez finterfare suivante (comme à l'accoutumée, en cas de sous-
programme interne, une telle déclaration n'est plus néœssaire):
VII. Les sous-programmes et les fonctions 173
interface
s!J>routi ne ~ (valeur, resu ltat. qte)
rea l, intent (in) :: valeur
rea l . intent (out) ·.: resultat
integer. i ntent (i n) :: qte
end subrouti ne sp
end i nterface
Comme vous le constatez, à partir du moment oil ron 'nomme' les paramètres, il n'est plus
nécessaire d'en respecter l'ordre. Ceci peut éviter de fâcheuses erreurs d'étourderie! De
plus, comme le montre le dernier exemple, vous pou-ez mixer les deux pœsibilités
(classique par position et par mot clé) ; bien entendu, dans ce cas, les paramètres sans mot
clé, donc repérés par leur position, doi-ent obligatoirement être les premiers de rappel.
Remarque:
En toute rigueur, il faudrait dire que les paramètres à mot clé sont repérés par le nom
tel qu'il figure dans l'interface, et non par le nom de l'argument muet qui figure dans la
définition de la procédure correspondante. Une telle remarque ne se justifie bien sOr
que lorsque ces noms sont différents, situation que nous vous déconseillons vivement.
Voyons tout d'abord un exemple d'école2S d'une fonction qui calcule la somme des
éléments de rang n à p d'un tableau d'entiers; le tableau sera toujours fourni en argument
(obligatoire) tandis que les valeurs de n Cl p pourront ou non être précisées; on
conviendra que, sin est absent, on commence au premier élément du tableau; de même si
p est absent, on va jusqu'à la fin du tableau.
Vous y notez tout d'abord que les arguments deb etfin ont été déclarés avec un nouvel
attribut optiona/ qui précise qu~ls pourront ne pas être fournis lors de l'appel Par ailleurs,
la fonction JN"Se111 appliquée à un argument permet de savoir s'il a été ou non fourni lors
de l'appel. Ici, nous déterminons dans les variables locales debl et fini les éléments sur
lesquels doit porter la somme. Par exemple, si fargumcnt deb est présent, la somme
commence au rang deb ; s'il est absent, la somme commence à 1...
Notre fonction ainsi réalisée, il devient possible de l'appeler en ne fournissant que certains
arguments. On peut également faire intervenir des arguments à mot clé. Voici un petit
exemple:
progra11 exeq>le_arg....ents_~tionnels
i11pl icit oone
integer : : i
integer, dimension (10) . . tl • (/ (i, i •l. 10) /)
2.S. Q. calcul poumtit en fajt être réa.Usé, saiis fonction, à J'aided'unesec:tion approprié.e.
VII. Les sous-programmes et les fonctions 175
interface J iOOispensable
flllction saane (t, deb, fin)
integer. dilnension (:). intent (in) :: t
integer. intent (in). optional !: deb. fin 1 argJlllE!llts optiomels
integer :: soiwne
eOO funct ion soime
eOO inter# ace
print '. 'de 2 a 5 sanne (tl, 2, 5)
print • , ' de 3 a la fin : saane (tl, 3)
print •, 'tout sanne (tl)
print '. 'clJ debut a 7 : ', sonme (tl. fin• 7) ! IK>t cle iOOispensable ici
end progra11 exeq>le_argullellts_~tionnels
Naturellement, l'interface de notre fonction doit être connue, d'oll la présence d'un bloc
d'interface. Notez que, dans certains environnements, on peut ottenir des résultats
corrects tant qu'on n'appelle pas la fonction avec certains arguments ab6ents; ceci n'est
nullement garanti et il vaut mieux p:évoir systématiquement une interface.
Remarques:
1) A priori, remploi des variables debl et fi11J semtte superflu. On pourrait penser à
écrire, par exemple :
if (.not.(present(deb)) deb • 1 ! incorrect car deb declare intent (in)
Ce n'est pas possible ici car deb el.fin sont des arguments d'entrée.
3) Dans un appel, il n'est pas possible d'omettre un argument en cours de liste, comme
dans:
""""" (tl. • 4) J interdit
Notez qu'on pelt toujours oontourner la difficulté avec des arguments à mot clé:
soome (tl, fino4) 1 correct
176 Vll. Les sous-programmes et les fonctions
4) Dans notre exemple, les arguments optionnels recevaient des valeurs par ~faut dans
la procédure. C'est là l'utilisation la plus fréquente &, dans cc cas, il est fortement
conseillé de prévoir que de tels arguments soient des arguments d'entrée (dans le cas
oon1raire, cela n'aurait d'ajlleurs guère de signification). En revanche, on peut
éventuellement prévoir qu'une procédure, sans chercher à donner une valeur par défaut
à des arguments optionnels, se contente d'utilirer ou de ne pas iiiliser un argumen~
suivaŒ qu'il a ou non été fourni lors de l'appel ; dans ce cas, on peut en~er que
certains de ces arguments op1ionnels ooient des argumenlS de oortie...
5) Une procédure à argumeŒ optionnel peut, à son tour, appeler une aiire procédure
en lui transm&tant (en argument dfectif, celte fois), le dit argument. Ce serait par
exemple le cas si, dans notre fonction somme précédente, nous trouvions un appel de la
fonne:
ca 11 truc (deb)
Dans ces conditions, il est nécessaire que celte seconde procédure (ici tnu:) ait prévu
également un argument oplionnel à ce niveau (ici pour son seul argument). De plus, si
l'argument en question était absent dans le premier appel, il sera également absent
pour le second. Ainsi, si nous appelons somme sans préciser de valeur pour le second
argument, tout se passera comme si troc avait été appelé sans argument. En revanche, si
nous appelons somme avec la valeur 3 comme second argument, c'est effectivement
œue valeur qui sera 1ransmise à tnu:.
Pour ceux d'entre vous qui ne sont pas familiarisés avec la notion •d'argument procédure' ,
nous allons l'introduire sur un exemple simple. Nous verrons ensuite comment la
programmer en Fortran 90 Cl nous fournirons un exemple classique de procédure
d'intégration numérique d'une fonction quelconque.
Or, si nous ne faisons rien de plus, il est clair que le compilateur ne saura pas que /c
désigne une fooctioIL Si nous avons pris la précaution dfotroduire une déclaration implicit
11ol'le, nous obtiendrons probablement un diagnostic de compilation lié au fait que le
symbole /c n'aura pas été déclaré- Dans le cas contraire, le complateur attribuera
simplement un empacemeit pour une variable nommée fc (de type par défaut, ici rea/).
De toute façon, il est nécessaire de fairesavoir au compilateur que/c est effectivement une
procédure. Pour ce faire, ilexistedeux démarches:
Notez qu'ici nous avons déclaré l'interface de la fonction ( muene) fa. Cela n'est pas plus
obligatoire que ne l'était la déclaration d'une interface d'une procédure utili:ste par un
programme quelconque.
Voici un exemple de programme utilisant integ pour calculer deux intégrales de deux
fonctions/J etf2 Qeur définition est fournie en même temps). Notez bien que nous y avons
systématiquement déclaré les interfaces de toutes les procédures concernées alors que
seules les interfaces de / J et f2 fétaient (encore pourraient-elles être remplacées par la
déclaration : exrema/ fl, f2.
program proœWre_en_arcpœnt
iq>licit none
rea 1 : : res 1. res2
interface debut interface procedure integ
subroutine integ (xd. xf. n, fct, res) 1
rea 1, intent ( in) :: xd, xf
integer, intent (in) : : n
rea 1, intent (out) :: res
Vil Les sous-programmes et les fonctions 179
fonction fi (x)
real , intent (in) : : x
real " fi
fi • X * X +
eOO function fl
Notez bien la manière dont il faut "imbriquer" un bloc d'interface dans un autre lorsque
l'on déclare l'interface d'une procédure (ici integ) comportant un argument procédure dont
on souhaite également fournir rinterface.
En revanche, lors de rappel d'une procédure, un argument effectif pourra certes toujours
se présenter sous fonne d'une variable; mais, dans certains cas, on pourra y emplo)Cr une
constante ou une expression. Par exemple, si nous considérons le sous-programme tJuc
ayant cette interface :
il est tout à fait possible de rappeler de l'une de ces façons (1 étant un tableau d 'entiers, n
une variable entière) :
En revanche, si rargument n avait été de genreo111, on comprend que le dernier appel ait
toujours un sens puisque alors la procédure pourra modifier la valeur det(3); en revanche,
les deux premiers appels ne seraient plus corrects.
- s'il est argument d 'entrée (in). il peut s'agir de n'importe quelle expression,
- s'il est argument de sortie (out) ou d'entrée-sortie (inout). il ne peut s' agir que d 'une
variable au sens large; ains~ pour un scalaire, on pourra trouver un identificateur
VII. Les sous-programmes et les fonctions 181
Nous avons déjà dit, sans trop entrer dans les détails, qu'il était nécessaire que le type d'un
argument effectif corresponde à celui de l'argument muet correspondant. Précisons ce que
doit être cette "correspondance".
Tout d'abord, dans le cas de variables d'un type de base (entier, réel, logique). il doit s'agir
exactement du même type, en tenant comp1e d'éventuelles variantes (la valeur du
paramètre kind doit être la même).
Dans le cas de tableaux:
- leurs éléments doivent être exactement de même type (variante comprise) et de même
rang,
-en ce qui concerne leur profil, nous avons vu que:
• aucune contrainte n'existe dans le cas des tableaux de profil implicite,
• dans tous les autres cas, le profil de l'argument effectif doit correspondre à celui
de l'argument muet avec, toutefois, une excep1ion pour la dernière dimension.
Remarque ùnportante:
Dans certaines circonstances, on peut avoir besoin de réaliser des procédures récursives.
Ceci peut prendre deux aspects :
- récursivité directe: une procédure comporte, dans sa définition, au moins un appel à
elle-même,
182 VII. Les soos-programmes et les fonctions
- récursivité croisée : une pro<tdure appelle une autre procédure qui, à son tour,
appelle la première (le "C)'Cle" pouvant é11Cntuellement faire intervenir plus de deux
procédures).
Pour qu'une telle récursivité des appels soit possible, il est nécessaire qu'un mécanisme
approprié soit mis en oeuvre; sans entrer dans les détails, on peut dire, notamment, qu'il
est nécessaire d'empiler convenablement les différents appels, en conservant pour chacun
d'entre eux l'état des différentes variables locales.
En Fortran 90, on peut demander qu'une procédure puisse être utilisée de façœ récursive
(directe ou croisée) en faisant précéder son en-tête du mot clé 1'0cursi..,, comme dans ces
deux exemples :
Pour utiliser une telle procédure, ilest alors nécessaire que son interface soit explicite.
Voici un exemple fort classique (au demeurant inefficace sur le plan du temps d'exécution)
d'une fonction calculant une factorielle de manière récursi..e :
recursive fuoction fac (n) result (res) 1 result obligatoire puisque f s'appelle
integer, intent (in) :: n
integer : : res
if (n<• l) then
res • 1
e lse
res • fac (n· l) .. n
end if
eOO flllction fac
Vous y notez une nouveauté: l'utilisation du mot clé result qui précise le nom sous lequel
on souhaite désigner le résultat de la fonction dans sa définition. Il s'agit en fait d'une
possibilité utilisable pour n'importe quelle fonction (pas forcément récursive) : jusqu'ici,
nous nous étions contenté d'emplo)'er le nom même de la fonction pour désigner le
résultat.
Dans le cas d'une fonction récursive directe telle que/ac, l'écriture suivante:
Vil Les sous-programmes et les fonctions 183
EXERCICES
1) Ecrire une fonction externe fournissant en résultat le volume d'ure sphère dont le rayon
{de type real) lui est fourni en argument. Ecrire un petit programme l'utilisant pour
calculer 3 volumes correspondant à trois rayons fournis en donnée.
2) Même question que précédemment, en utilisant une fonction interue.
3) Même question qu'en 1, en utilisant un sous-programme au lieu d'une fonction_
4) Ecrire un sous-programme permettant de trier par ordre croissant les valeurs entières
d'un tableau de rang un, d'(:tendue quelconque:
a) en prévoyant un tableau de profil ajustable {étendue transmise en argument),
b) en prévoyant un tableau de profil implicite.
Dans les deux cas, le tri se fera par réarrangement des valeurs au sein du tableau lui-même-
5) Transformer le sous-programme précédent en une fonction recevant en argument un
tableau de rang 1 et de profil implicite et renvoyant en résuhat un tableau de même profil
(cette fois, on ne modifiera plus le tableau initial).
6) Ecrire une fonction recevant en argumeŒ deux tableaux de rang 1, de taille implicite el
fournissant en résultat une matrice définie ainsi:
rij ~ ai • bj
(r désignant la matrice résultat, a el b les tableaux fournis en argument).
On voit que la première étendue de r sera celle de a et que sa seconde étendue sera celle
de b.
184 vn. Les sous-programmes el les fonctions
Nous aborderons ensuite les différentes opérations qu'il est possible de réaliser sur des
chaînes:
- concaténation de chaînes; au passage, nous verrons qu'en Fortran la notion de chaîne
souffre d'une limitation importante, à savoir qu'a priori une variable de cype chaîne
possède une taille bien définie (la longueur de la chaîne qui y est placée ne peut pas
évoluer au cours de l'exécution comme c'est le cas, par exemple, en Basic!). Nous
verrons toutefois qu'une fonction particulière (ien_trim) fournit une solution partielle à
ce problème
- localisation d'une sous-chaîne à l'intérieur d'une chaîœ.
Un peu à l'image de ce que nous avons fait pour les tableaux, nous verrons la souplesse
qu'offre Fortran 90 en matière de transmission d'une chaîne en argument d'une procédure
puis nous aborderons le cas des chaînes automatiques et des fonctions fournissant une
chaîne comme résultat
1 - EXEMPLE D'INTRODUCTION
Ce programme lit deux motsl et les réafüche suivant l'ordre alphabétique. Comme on peut
s'y attendre, la déclaration :
réserve des emplacements pour trois variables nommées moll, mo/2 et mot, destinées à
contenir des chaînes de caractères. Notez qu'on en fixe précisément la longueur; ici, ces
variables comporteront toujours (exactement) 20 caractères.
1. En fai t, oe terme de "mot• est un peu abus:if', dan.s la mesure où, comme nous le verrons, oe programme pourra
e n fait lire n'importequeDe suite de caractères (mais des p-oblèmes de d61imiteursse poseront alors!) .
VID. Les chaînes de caractères 187
Vous constatez qu'une instruction rœd 'classique' (avec format litre) nous permet de lire
des informations de ce type. le~ l'utilisateur a fourni une première réponse ne contenant
que 6 caractères, ce qui pourrait laisser supposer que Pon a pu introduire une chaihe de
longueur inférieure à 20 dans mal. En fait, comme nous le verrons plus loin, il n'en est
rien car l'information ainsi lue a tout bonnement été complétée par des espaces à
concurrence de 20 caractères La même remarque s'applique bien sûr à mot2.
Notez l'expression logique mo:J>mot2 qui montre qu'on peut comparer des chaînes. Elle
conditionne l'échange éveŒuelle des contenus de nos deux variables motl et mot2.
Remarques:
1) Nous verrons plus loin qu'il est possible de définir des tableaux de chaînes On
prendra alors bien ooin de distinguer une chaîne de longeur 20:
character ( len • 20) : : mt
Certes, dans les deux cas, on disposera bien de 20 caractères, mais on n'y accédera pas
de la même façon.
2) En Fortran 77, les variables de type chaîne devaient être déclarées suivant d'autres
syntaxes (toujours acceptées du Fortran 90); la plus classique était:
character'*20 : n>tl. 100t2. mt
'bonjour'
Comme on peut s'y attendre, la longueur d'une constante chaîne est le nombre de
caractères qu'elle comporte. Par exemple, nos deux chaînes précédentes (ce sont les
mêmes) sont de longueur 7.
On peut toujours introduire un guillemet dans une chaîne délimitée par des apostrophes.
Par exemple, la notation 'il dir 'vive FOlfron 90" représent la chaîne Il dit "vive Fortra11 917'.
De la même manière, on peut toujours introduire une apostrophe dans une chaihe
délimitée par des guillemets; par exemple, la notation ' fordin(]feul' représente la chaihe
l'ordiJiateur.
De plus, dans une chaîne délimitée par des apostrophes, deux apostrophes consécutives
sont interprécées comme une seule apostrophe (et non comme un délimiteur) . La même
remarque s'applique aux guillemets. Par exemple, la notation 'l"ordiJi(]feur' représente la
chaîne l'ordinâJeur.
VIII. Les chaînes de caractères 189
Lorsqu'on souhaite écrire une constante chaîne sur plusieurs lignes, on procède comme
pour les instructions. Toutefois, dans ce cas, les espaces sont "significatifs'; ainsi, avec
cette notation :
•c.eci est lll exeq>le de longue chaine CJJe l 'on a ecrit &
sur deu:it lignes•
On obtient quatre espaces (un 'enaŒ de la première ligne el trois de la seconde) entre le
mot ecrit el le mot siu. SoU\eŒ, on souhaitera conserver certaines indentations de
présentation; dans ces conditions, il est toujours possible de spécifier oil commence
effecti,ement la ligne de continuation à l'aide d'un (autre) caractère & comme dans :
IOOt • 'alexandrine'
mt • 'alex'
190 VIU. Les chaûies de caractères
on obtiendra dans la variable mot uoe chaîne de 10 caractères formée des 4 caractères
a/ex complétés par 6 espaces.
Or les réponses à toutes ces questions dépendent de la machine sur laquelle vous
travaillez. Plus précisément, elles dépendent du 'code' que cette machine utilise pour
représenter les différents caractères. Toutefcis, dans tous les cas, on peut assurer que :
En revanche, les majuscules peuvent aussi bien arriver avant ou après les minuscules, les
chiffres avant ou après les minuscules, avant ou après les majuscules. ..
3. P\Jisque, da15 Je dictionoairc.o n ne distingue pas les maju:sculcs des minu:scufcs ni les caractères acoenrués des
caractèressanS acc:enl(ni c; de c).
VUI. Les chaînesdecaractères 191
chl • i>on• : ch2 • "boo" J chl - ch2 (bien q.ae de longueur differente
chl • i>on : ch2 • •bon• 1 chi - ch2
chl • i>on• : ch2 • i>onus• 1 chl < ch2
chl • •paris2• : ch2 • •paris12• l chl > ch2 (attention au piegel)
Remarques:
1) Les caractères utilisables dans les chaînes dépendent, eux aussi, de la machine
utilisée. Dans certains cas, on pourra disposer des caractères nationaux (accentués el
ç).
2) Les codes les plus répandus sont le code EBCDIC (Exteoded Binary Coded
Decimal lntercbange Code} el le code ASCil (American Standard Code for
Information lnterchange).
3) La norme prévoit que, si le code employé par défaut n'est pas le code ASCII, il soit
possible (moyennant l'utilisation d'une 'variante' appropriée du type charadtr} d'y faire
appel (voyez fanoeJ<e B). De plus, les fonctions intrinsèques iachar el achar permelteit
de manipuler de tels caractères (voyez fanoeJ<e consacrée aux fonctions intrinsèques) .
2 .5 Chaînes et Initialisations
Comme toutes les variables en Fortran 90, une chaihe peut être initialisée lors de sa
déclaration à l'aide d'me oonstante comme dam:
La longueur de la constante n'a pas besoin d'être identique à celle de la chaîne; sa valeur
sera simplement tronquée ou complétée par des espaces comme dans le cas d'une
affectation.
Par ailleurs, il est possible de déclarer une constante symbolique de type chaîne à raide du
mot clé paromettr:
De plus, dans ce dernier cas (con!tante symbolique de type chaîne), on peut laisser le
compilateur déduire la longueur de la chaîne de celle de la constante qu'on lui fournit; il
suffit pour cela de mèntioooer le caractère• à la place de la longueur. Ainsi :
3 ·ENTREES-SORTIES DE CHAINES
Examinons successivement ce que sont ces possibilités, en format libre d'une part, avec un
format d'autre part.
· encadrer les informations par des apostrophes ou des guillemets, comme on le fait
pour les constantes de type chaîne (le caractère n'apparaissant pas dans ladite
information, à moins d'être doublé); dam ce cas, il est possible d'y faire apparaître
n'importe quel caractère, en particulier des séparateurs habituels tels que respace, la
virgule ou le caractère/; ces derniers seront bien pris en compte.
- ne pas encadrer les informations; dans ce cas, le premier caractère séparateur
(espace, virgule ou/) déterminera la fin de l'information.
Par ailleurs, si finformation fournie comporte un nombre de caractères inférieur à la
longueur de la variable chaîne, elle sera complétée (classiquement) par des espaces. S~ en
revanche, Pinformation fournie comporte trop de caractères, seuls les caractères de droite
(attention, on s'attend à l'inverse) seront comidérés.
Par exemple, voici ce que nous obtiendrons avec ces instructions:
4. Cette postibilhé ( laisser le canpiJateur compter â \Otre place!) oe pourra pU s'appliquer à des tableaux
symbol(lues (parameter) de chaînes.
Vlll Les chaînes de caractères 193
chi ch2
"bonj:>ur"'--"""1oonsieur boojour" 1K>ns ieur
he llo, boy he llo· ~ boy""""•
'bonj:>ur cher n>ns ieur ' .dupoot boojour" wpont
"1 'exunen blanc•. 'le "lfDi" et le •sunooi"' l 'examen le "mi"
En écriture, o.n écrit dans le gabarit voulu; dans le cas de Aw, si w est supérieur à la
longueur del a chaîne, on fait précéder son écriture par des espaces à gauche (comme pour
les nombres, ce qui ne correspond pas à l'usage : en généra~ on aligne bien les nombres à
droite, mais les libellés le sont à gauche). Si w est inférieur à la longueur de la chaîne, seuls
les w premiers caractères sont écrits.
at>c••11efgh
mot (2·6) représente une chaîne de longueur 4 formée des caractères de mot de rang 2 à 6,
mot (3:3) représente une chaîne de longueur 1 formée du caractère de rang3 de mot.
Une telle notation de sous-chaîne peut inter\eoir aussi bien dans une expression de type
chaîne (à droited'uneaffectation, dans une liste d'écriture) mais également à gauche d'une
affectation ou dans une instruction de lecture. Une sous-chaîne est donc (comme l'était
une section de tableau non ambiguë) une variable à part entière. Ainsi, ces instructions
sont valides :
mt • •bonjcur•
print •. 11ot (2:6) 1 affiche onjou
llOt (2:2) - •• •
print •. 11ot (1:5) 1 affiche banjo
Notez qu'une notation telle que mot (5:3) n'a pas de sens mais elle est aoceptée par
Fortran. Plus précisément, si me telle notation apparaît dans une expression de type
chaîne, elle correspond simplement à une chaîne vide; par exemple (ch étant supposée de
type chaîne) l'instruction di =mot (5:2) est simplement équivalente à di= ".
Sous-chaîne
Avec:
A priori, la notation d'une sous-chaîne n'a aucun sens si debut>[111. En fait, une telle
situation est acceptée par Fortran (n'oubliez pas que les limites de sous-chaîne peuvent
être des variables!). Il faut alors di!linguer les deux modes d'utilisation d'une telle sous-
chaîne:
- au sein d'une expression, la sous-chaîne correspondante est simplement considérée
comme une chaîne vide Par exemple (ch et mot étant des variables de type chaîne) :
dl • mot(5:2)
est équivalent à :
ch s '"'
4 .3 En cas de recoupement
Comme avec les rections de tableau, on risque avec les sous-chaînes de rencontrer des
situations telles que:
196 VIII. Les chaînes de caractères
Dans ce cas, Fortran applique la règle que nous avons déjà rencontrée, à savoir que la
valeur d'une expttssion est entièrement évaluée avant d'être affectée.
4.4 Exemples
a) Ces instructions permettent de supprimer la première lettre d'un mot contenu dans la
variable mot (de longueur /mot):
b) Ces instructions affichent, de façon comécutive, une lettre sur deux de la chaîne
contenuedansch:
i nte~r .para111eter : : lg • 20
int e~r :: i
character ( len•lg) : : ch
doi • l.l
print •. ch(i : i)
end do
Notez bien qu'on affiche toujours 10 caractères, même si les derniers sont des espaces. On
ne tient pas réellement compte du contenu effectif de ch. Nous verrons un peu plus loin
comment la fonction len_trim permet d'améliorer lasiluatioo.
Alors, la notation chiffres (i + l:i + I} fournit une chaîne de longeur 1 contenant le caractère
correspondant au chiffrei; par exemple,chiffees (3:3) est la chaîne 'Z'. Notez que l'on a un
'décalage' d'une unité, pu~ue le premier chiffre est O. Certes, on n'aurait plus ce
problème avec chiffres = '123456789' mais, il ne serait alors plus possible d'obtenir le
caractère O.
program concatenation
iq> lie it none
character ( 1en• l2) : : chl • •bonjour•
character (len-10) :: ch2 • 1 1JOnsieur'
character ( len-18) : : ch
198 VIII. Les chaînes de caractères
ch • chi Il ch2
print •. 'A : ' . ch 1 on aurait p.i ecrire print *. chl // ch2
ch • trim (chi) Il ch2
print •. '8 : ' . ch
ch • trim (chi) Il ' ' Il ch2
print •. 'C : •. ch
end pro::.Jram coocatena tion
A : bonjoor 100nsie
8 : bonjoor1JDns ieur
C : bonjoor n>nsieur
Un tel exemple semble montrer que la (Onction /en e!t dénuéed'inté~, dans la mesure oil
elle fournit une infOrmalion déjà connue par ailleurs. En fait, nous verrons qu'elle se
révélera précieuse dans le cas de chaînes transmises en argument ou dans le cas de chaînes
automatiques.
Par ailleurs, la fonction Jen_trim permet de conruu'"tre le nombre de caractères d'une chaîne
lorsque l'on ne tient pas compte des espaces de fin. Ainsi, Jen _trim (met) est en fait
équivalent à/en (trim(mot)).
Voici, à titre d'exemple, m programme qui lit une chaîœ et qui l'affiche verticalement, en
évitant d'afficher des lignes blanches intempestives pour les éventuels espaces de fin
(comme le faisait l'exemple c du paragraphe 4.3).
progra111rot_vertical
ilrplicit ooœ
integer. parameter : : lCJJK>t ... 20
integer : : i
Vlll Les chaînes de caractères 19'.I
progra11 recherche_sous_chaine
iq> 1ici t none
integer. parameter : : kj • 20
integer pos
character ( len••). parameter :: cherche • 'er'
character ( len•lg) : : mot
print *• 'doonez un n>t '
read •. mot
pos • index (mot, 'e')
if (pos / • 0) print •. ' le premier e est en position : '. pos
pos • index (mot, cherche)
if (pos / • 0) print •. 'la chaine er apparait en position : 1 , pos
eOO progra11 recherche_soos_chaine
slbroutine sp (ch)
character ( len• IO), intent ( ... ) :: ch
- avec des arguments effectifs de même longueur (ce qui e~ la moindre des choses!),
- avec des arguments effectifs de longueur supérieure; dans ce cas, en effet, la
procédure travaillera avec une partie de la chaîne qu'on lui aura transmise-
VIII. Les chaînes de caractères 201
La deuxième situation est en fait d'un intérêt limité car la procédure ne connaîtra pas la
.tritable longueur de la chaîne qu'on lui aura transmise; ains~ avec les précédentes
déclarations, le!(ch) vaut toujours 10 quel que soit rappel de sp. D'autre part, un risque
important existe d'appeler la procédure avec une chaîne trop courte; dans ce cas, on
aboutira au mieux à un message approprié aecompagné d'un arrêt de l'exécution, au pire à
des écrasements d'emplacements mémoire {dans le cas d'arguments de sortie) ...
Notez qu'ici, contrairement à ce qui se passait pour les tableaux, il n'est pas nécessaire au
compilateur de connaître l'interface de la procédure pour en compiler l'appel. Elle n'en
reste pas moins conseillée.
Voici un petit exemple illustrant celte possibilité:
Remarque:
Il ne faut plS confondre les chaînes de caractères avec les tableaux à une dimension
(éventuellement des tableaux de chaînes de longueur 1). En effet, tout se passe en
Fortran 90 comme si 1foformation de longueur d'une chaine ~tait transmise
auiomatiquement en même temps que la chatne elle-même. Au contraire, l'étendue
d'un tableau de rang 1 n'est transmise que si on l'a prévu explicitement (soit en
argument supplémentaire, soit par un tableau implicite el, dans ce cas, naturellement,
l'interface de la procédure était obligatoire).
Nous avons déjà eu l'occasion de parler de l'aspect automatique des variables locales ; en
particulier, nous avons vu que les tableaux locaux pouvaient voir leurs dimensions définies
seulement au moment de l'appel par une expression de spécification. Celte remarque
s'applique également à la longueur d'un argument de type chaîne. Sa longueur peut, die
aussi, être fournie sous forme de n'importe quelle expression de spécification ; celte
dernière peut faire intervenir, notarnmentS :
progra11 per1J1Jte_chaines
iq> lie it none
character ( len• IO) :: chi • "bonjour•
character ( len• lS) :: ch2 • •cher tronsieur•
print •.'avant:•. 1 : 1 • chl. 1 : 1 , ch2. 1 : 1
ca 11 peroute (chi. ch2)
pr int • . 'apres: ' , ' : ', chl. ' :' , ch2, ':'
eOO progra11 per1J1Jte_chaines
Remarque:
li ne serait pas possible ici de fournir une chaîne débarrassée de tous les espaces, y
compris de ceux de fin ; en effet, dans ce cas, la longueur de la chaîne résultat ne serait
pas connue lors de l'entrée dans la fonction compaa, ce qui est contraire à la notion
d'expression de spécification (qui doit être calculable à l'entrée dans la procédure).
Cette situation ne doit pas être confondue avec celle que vous rencontrerez par
exemple dans l'exercice 5.
Vlll. Les chaînes de caractères 205
9 • TABLEAUX DE CHAIN ES
déclare un tabJeau nommétabch dont chacun des 10 éléments est une chaîne de longueur
20.
Notez bien que, de par ta nature même d'une telle déclaration, toutes les chaînes d'un
même tableau ont obligatoirement ta même longueur.
La notation tabch (i) représente ta chaîne de rang ide tabch . La notation tabch (i) (2:5)
représente ta sous-chaîne formée des caractères 2 à 5 de la chaîne de rang i de tabch.
Quant à tabch (i) (j:j), elle représente te caractère (en toute rigueur, chaîne de longueur 1)
derangj de ta chaîne de rang i de1abd1.
Notez que, de même que tes éléments figurant dans un constructeur de tableau numérique
devaient être de même type, les expressions de type chaine figurant dans un constructeur
de tableau de chaines doivent être de même longueur. Ainsi, ce constructeur rerait
incorrect:
Un tel constructeur peut &re utilisé soit dans une expression, auquel cas ses éléments
peuvent &re constitués de n'importe quelles expressions de type chaîne (de même
longueur!). Il peut également intervenir dans une initialisation, auquel cas il ne peut faire
intervenir que des expressions constantes (en général, on se contentera de simples
constantes comme dans rexemple ci-dessus7).
Enfm, commme pour les tableaux numériques, il est possible de défmir un tableau
symbolique de chaînes (parame1er), à condition, là encore, de se limiter à des expressions
constantes (de même longueur). Voici un exemple correct:
character ( le ,...14 dimension (4) : : message •
(/ • •••erreur-• •. ·---so lutim---·. -OK .
&
/)
Remarques :
1) Lorsque nous disons que la longueur des chaînes est variable, elle peut effectivement
être différente d'Un appel à un autre; en revanche, elle reste la même pour tous les
éléments d'un même tableau.
2) li ne serait pas possible de défirur, au sein d'une procédure telle ·que ecriture, une
chaine automatique ayant une longueur égale à celle des chaînes du tableau 1 ; en elfe~
il faudrait utiliser comme longueur une expression telle que /en (1(1)), laquelle n'est pas
une expression de spécifications. Si un tel beroin apparaissait, la seule solution serait de
prévoir de transmettre cette longueur en argument de la procédure.
EXERCICES
8. Et oeci, bien que cette cxprusl>n liOil théoriquement calc ulable Ion de l'entrée dans la proctdun:. En dtet,
ccmme l'indique l'annexe D, la norme a ittroduil certaines oon1nin1cs dcatintcs à facllier le travail du
oompiJateur: l'une de Cle$ oontninta préti.se que la fonctions é lémentairu cmployUl dans une exprusiœ de
spécl kalion doivem posséder dei argwncntteŒiers.
208 vm. Les chaînes de caractères
progran test
iq> l icit none
character ( len-6) :: chi. ch2
read • (aS, a8) chi. ch2
print • (2 c·-·.
a6)" chi, ch2
em ·progran test
a) 'abcdefghijk l
b) ' he llo', "bol'
c) """""""/
4) Ecrire un programme qui supprime toutes les lettres e (minuscules) d 'un texte d 'au plus
ro caractères fourni en données. Le texte ainsi modifié sera créé (en mémoire) à la place
de l'ancien.
5) Ecrire une fonction qui reçoit deux chaînes en argument et qui fourni t en résultat une
chaîne obtenue en concaténant la première chaîne débarrassée de ses espaces de fin avec
la seconde, en prévoyant un espace supplémentaire entre les deux chaînes. La longueur de
cette chaîne résultat devra être la plus faible possible.
6) Ecrire un sous-programme de tri par ordre croissant d'un tableau de chaînes (le tableau
sera de rang 1 et de profil implicite, les chaînes de longueur variable). Le tri se fera par
réarrangement du tableau à l'intérieur de lui-même.
IX. LES STRUCTURES
(OU TYPES DERIVES)
Nous avons déjà vu comment le tableau permettait de désigner sous un seul nom un
ensemble de valeurs de même type, chacune d'entre elles étant repérée par un indice.
La structure (ou 'type dérivé'), quant à elle, va nous permettre de désigner sous un seul
nom un ensemble de valeurs pouvant êtrede types différents. L'acœs à chaque élément de
la structure (nommé 'champ') se fera, cette fois, non plus par une indication de position,
mais par son nom au sein de la structure.
Nous allons tout d'abord apprendre à déclarer et utiliser des variables de type structure.
Puis nous verrons commen~ à fimage de ce que avons fait pour les tableaux, employer un
constructeur de structure; ce dernier pourra servir à initialiser des variables ou à définir
des constantes symboliques (paramettr). Nous examinerons ensuite les situations
d~mbrication de structures; nous terminerons par la transmission d'une structure en
argument d'une procédure ou en valeur de retour d'une fonction.
Notez que le chapitre XI vous montrera l'intérêt que présentent les structures lorsque l'on
cherche à créer des 'types abstraits' ou des 'objets' réalisant ce que l'on nomme
l'encapsulation des données.
210 1X. Les structures
Ici, an I et art2 sont donc deux "var iables' " (au sell.'i lar ge) du typ e structure nommé
enreg. Chacw1e de ces delLx variables disposera donc des troi'i c hamps numero, quana1e et
prix.
Ren1arque :
Depuis Fortran 95, les champs d'une st tucture peuvent être initiali'iés lors de lew·
déclaration, ce qui fou rnit une "valeur par défaut".
2- UTILISATION DE STRUCTURES
Voyons 1naintenant l'usage que nou.'i pouvons fai re de telles variables.
En Fo1t ran 90, il est possible d' utiliser w1e.st ructure de deux 1nanières:
· en travaillant individuellement sw· chacw1 de ses c hamps.
· en travaillant de manière globale s w· l'ensemble de la structure.
1. Il nous a mi\'cra WU\'C:nl, lorsque uucunc a mbiguïté ne sera possible; de parler simplement de structures pour
d6dgncr ~ \'ari obl ~ d·un type structure.
IX. us st ructures 2 11
Chaque cham p d' w1e structure peut être m anipulé com me n 'importe quelle var iable du type
001Tespondant. La désignation d'un champ se note en faisa nt s uivre le nom de la variable (du
type structure) du s ytnbok- % s uivi du nom de champ tel qu 'il a été défini dans la déclar ation
du type structure. Voici quelques exemples utilisant les variables an / et art2 du typ e enreg
défini précédem ment.
ar t1% nunlero = 15
affecte la vak-u r 15 au c hamp n umero de la variable an 1,
print *, a rtl % prix
écrit s ur ('unité st andar d la valew· du c ham p pâx de la variable an1,
read *, art2% quantite
lit, sur l'unité st andar d, une valew· réelle et l'affecte au c hamp q uanau.> de la var iable an2,
ar t1% nunlero = ar tl% nun1ero + 1
auginente de w1 la valeur du champ n umero de la var iabk- art 1.
Il est possible d'affecter à une variable de typ e structure, le contenu d' w1e. autre var iable de
même type. Par exemple, avec :
a r tl = a r t2
nou.~ recopions les valeurs de tou.~ les champs de art2 dans les c hamps correspondants de art 1.
De m êm e, il est possible de m entionner le nom d' w1e variable de type structure dans une
inst ruction d'entrée.sortie. Cela revient à m entionner s uccessivement chacw1 de ses c hamps.
Par exempk-, avec:
read *, ar tl
on lira trois valeurs (deu.x de type entier, une de typ e réel) que l' on affectera respectivement
au.x c hamps n umero, quamUe et prix de la var iable art/ . Le même résultat pomTait s'obtenir
avec:
re.ad ~, artltnumero, artl \ quantite, artl\prix
212 IX. Les structures
Voie~ à titre d'exemple, un programme complet reprenant les différentes possiblités que
nous venons d'évoquer :
3 · CONSTRUCTION ET INITIALISATION DE
STRUCTURES
représente une structure de type enrtg, dans laquelle le premier champ (ici numero) a la
valeur 3, le second champ (ici quanti te) a la valeur 25 et le troisième champ (ici prix) a la
valeur 5.25.
Notez bien qu'un tel constructeur fait référence au type de la structure concernée, sans
toutefois mentionner les noms de champ correspondants (c'est l'ordre d'apparition des
informations qui permet de s'y retrouver).
Un tel constructeur peut faire intervenir des expressions quelconques, pour peu qu'elles
soient d'un type compatible2 avec celui figurant dans la définition du type structure. Par
exemple (moyennant les déclarations appropriées),ces instructions sont correctes:
end do
Un constructeur de structure peut également apparaître pour initialiser une variable (de
type structure) lors de sa déclaration, comme dans:
Dans ce cas, comme dans le cas des tableaux, les différentes expressions figurant dans le
constructeur doivent être des expressions constantes.
Enfin, comme pour les tableaux et les chaînes, il est possible de définir des constantes
symboliques de type structure. Par exemple:
Remarque
Nous verrons plus tard que Fortran 90 vous permet de définir des opérateurs portant
sur un type structure, ce qui vous amènera à écrire des "expressions de type structure',
comme vous écrivez des expressions de type tableau. Pour l'instant, nous pouvons
toutefois mentionner que le constructeur de structure est un cas particulier
d'expression de type structure. Le cas des fonctions fournissant un résultat de type
structure (que nous aborderons un peu plus loin dans ce chapitre) en constituent un
autre cas particulier.
2. Ce qui revient à dire qu'il doit ttre d'un type qui senût attei;té par une afttttation à une variable du type du
champcom:sponditnt. En pratique., cclasignifie notamment qu'on peut utiliser n'imPorte qucls types numériques
(complexa oomprii}, mc>)ennant la mise en place automa tique de oonveBioœ.
214 IX Les structures
4 - IMBRICATION DE STRUCTURES
Dans nos exemples d'introduction, nous nous sommes limité à une structure simple ne
comportant que trois champs d'un type de base. Mais, chacun des champs d'une structure
peut être d'un type absolument quelconque: pointeur3, tableau, chaine de caractères,
structure ... De même, un tableau peut être constitué d'éléments qui sont eux-mêmes des
structures. Voyons ici quelques situations classiques.
type pers
character ( len-8) : : 0011
integer, d imens ion (3) :: qtes
en:t type pers
type (pers) : : e111>lo)<! , courant
Elles définissent deux variables employe et courtillt, du type structure nommé pers, formé
d'une chaîne de caractères (de longueur 8) et d'un tableau de trois entiers.
employe'llnom (1:3)
désigne la sous-chaîne formée des trois premiers caractères du champ nom de la variable
emplaye.
De même:
emplo:ie%qœs (2)
représente le second élément du tableau qtes de la variable employe.
Quant à la notation :
employe%qtes
elle désigne le tableau de trois entiers qtes de la variable employe.
ou encore à:
pr int •. cptrant%nan, oourant%qtes(l). ootrant%qtes(2). cotrant%qtes(3)
type po i nt
character (len• l) nom
integer : : x, y
end type po i nt
type ( poi nt). diœns ion(50) •• courbe
La structure point pourrait, par ei<emple, seIVir à représenter un point d'un plan, point qui
serait défini par son nom (chaîne de caractères de longeur 1) et ses deux coordonnées.
Notez bien que poini est un nom de type structure, tandis que courbe représente
effecti.ement une variable de type 'tableau de 50 éléments du type point4".
4. En pratique. on aura i:ntédt à distilguer les ncms de type des noms de variables , par e.c.mple en "préfo:ant•
les premiers pardescaraclères oonventiormelsccmme danS l,J>Oint ou t_enreg.
21' IX. Les structures
courbe%nom(i)
n'aurait pas de sens.
De même, la notation :
cour be(l)'10x
désÎglle la valeur du champ xde l'élément de rang i du tableau courbe.
Par ailleurs:
courbe(4)
représerue la variable de type point correspondant au quatrième élément du tableau
coudle .
L'instruction :
pr 1nt •. courbe
est équivalent à:
elle-même équivalente à :
5 -STRUClURES ET PROCEDURES
5. NaturcDement, cette remarque ne s'applique ptl aux procédures internes puisqui; dans ce CitS, les types: dérinîs
Clans la proc6clure ~hôte~ soot connus des procédures intc mes.
6. Comme nous Je verrons., les modules ont un rOle beaucoup plus général que œlui qui oons:iste à rendre ui»que
lit déclaration d'une struaurc.
218 IX. Les structures
progra11 arguirent_structure
itpl ic i t none
type enreg
sequence 1 theor iqu11ent i OO i spensab le
i nteger l'IJEl"O
i nteger qJant i te
real i:rix
ero type enreg
interface
subrout ine aff iche (a)
type (enreg), intent ( in) :: a
·end stbroutine affi dle
e nd interface
type (enreg) :: art!• enreg (5 , 12, 2.25), &
art2 • enreg (3, 25, 5.30)
call affi che (art!) ; call aff i che (art2)
ero
subroutine affi dle (a)
i11p 1i c i t none
type erreg
sequenoe
integer ntaro
i nteger qant ite
rea 1 pri x
end type enreg
type (enreg), intent ( in ) :: a
print 1 ( •n y a • , i 3 , •arti cl es de n ~ro • , i 3. •val ant • , f8.2, •f•) 1 , &
a%qant ite , a%nuEro. a%pri x
end subrout ine aff iche
A partir du moment où 1m même type structure doit être employé dans deux unités de
programme différentes, la nonne prévoit qu'il est nécessaire que ses deux déclarations
mmpnrtent le mnt clé .tlV[UR.11CP.. C:e dernier ~·emploie t'..nmme une in~tn1ctinn et il ttnit
IX Les structures 219
apparaître aprês le mot erveg et avant la première déclaration de type7 . Notez que nous
aurions pu écrire :
ou encore:
7 . Dans k cas de s tructures privé.es (que nous t tudierœs ditœ le chapitre XI), scquenoe peut apparaître avant o u
après prîw.tc..
220 IX. Les structures
slbrrutine sp (t)
type enreg ; sequence
mar acter ( l e,..8) : : nan
integer. d imens ion (3) :: qtes
end type enreg
i nteger :: i
type (enreg). dimension(:) :: t
print •, 'tabl eau de ' . size(t). ' structures'
do i • 1. s ize (t)
pr int • . t( i)
end do
end slbrouti ne sp
tableau de 4 structures
dubois 2 5 3
dunoyer 6 9 0
duchene 3 0 0
dutronc 0 7 2
Remarque:
Il n'est pas possible de transmettre en argument une structure dont un champ serait un
tableau de profil implicite ou même variable.
type point
dlaracter ( l en• l) .. rom
integer : : x. y
end type poi nt
Remarques:
1) Dans tout programme utilisant la fonction symetrique, il est nécessaire d'en connaîlre
l'interface.
2) JI n'y a pas de •conflit" entre le symbole llôm correspondant à un champ de la
structure peint et rargument muet nom de notre sous-programme. En effet, le premier
ne peut jamais être employé seul (il doit être précédé d'un nom de structure). tandis
que le second peut l'être. JI n'y a donc aucune ambiguilé.
EXERCICES
a) lit en données des informations dans un tableau (de rang 1) de structures du type
peint défini ainsi:
type point
character ( l en• l) .. ro11
rea l:: x,y
end type point
222 rx. Les structures
2) Réaliser la même chose que dans rexercice précédent, mais en prévoyant, cette fois, un
sous-programme pour la lecture des informations et un sous-programme pour leur
écriture.
3) &rire une fonction permettant de calculer la somme de deux vecteurs définis comme
étant des structures du type :
type vecteur
rea l : : x
...,. 1:: y
rea l : : z
end type vecteur
Nous a~ns déjà eu rocccasion de distinguer les variables statiques des variables
automatiques. Les premières (variables du programme principal ou variables locales aux
procédures ayant reçu l'attribut sa"") voient leurs emplacements définis, une fois pour
toutes, lors de la compilation. Les deuxièmes (variables locales aux procédures n'ayant pas
reçu fattribut sa..,), en revanche, se voient attribuer un emplacement (sur la "pile") à
chaque appel de procédure ; cet emplacement est libéré lors de la sortie de la procédure.
Les variables automatiques permettent déjà une certaine forme de la •gestion dynamique•
de la mémoire, dans la mesure où une même partie de la mémoire (ici de la pile) peut être
utilisée à des instants différents par des variables différentes. Toutefois, cette gestion se
déroule •automatiquementh, c'est-à-dire sans intervention aucune du programmeur.
En Fortran 90, il est possible également d'allouer ou de libérer de la mémoire pour des
variables de votre choix, et ceci "à la demande", à raide d'instructions appropriées. En
général, ceci se fera par le biais de "pointeurs', c'est-à-dire en première approche, par des
variables précisant l'emplacement effectif d'autres variables en mémoire. Toutefois :
- d'une part, les pointeurs peu,ent intervenir en Fortran 90, indépendamment de toute
gestion dynamique; en effet, comme nous le -errons, un pointeur pourra être associé,
non seulement à une variable dynamique, mais également à une variable statique ou
automatique ;
- d'autre part, il est possible de gérer dynamiquement des tableaux (et uniquement des
tableaux), sans utiliser explicitement de pointeur ; on parle souvent, dans ce cas, de
tableaux d)'llamiques2.
Compte tenu de ce que certains utilisateurs scientifiques de Fortran 90 risquent, au moins
dans un premier temps, de s'intéresser essentiellement aux tableaux dynamiques, en
laissant de côté tout ce qui touche aux pointeurs, nous commencerons par traiter ce point
dans le premier paragraphe. Néanmoins, si vous étudiez le reste du chapitre, wus y
déoouvrirez que cette manière de gérer d)'llamiquement des tableaux n'est en fait qu'un cas
particulier de la gestion d)'llamique à l'aide de pointeurs. Quoi qu'il en soit, sachez que
l'étude du reste du chapitre peut, le cas échéant, être différée, sans que cela ne nuise en
aucune façon à l'étude des chapitres suivants.
Ensuite, et comme nous l'awns fait pour chaque nouveau type rencontré au fil de
l'ouvrage, nous verrons comment les pointeurs peuvent intervenir en argument d'une
procédure.
Nous terminerons par un exemple classique d'utilisation de pointeurs: la constitution
d'une "liste chaînée".
1.1 Introduction
Il arrive fréquemment que l'on ait à manipuler des tableaux dont les étendues ne sont pas
connues lors de l'écriture du programme. On peut également awir besoin de tableaux dont
les étendues varient d'une exécution à une autre. Qui plus est, il arrive fréquemment qu'un
tableau ne soit utile que pendant une partie de l'exécution d'un programme. Avec les
2. En toute rigueur, les tabh:au:x. doot l'emplaoement est alloué par Je biais d'un pointeur sont tOJt au:s:si
dynamiques.
X. La gestion dynamique et les pointeurs 225
Avec Fortran 90, nous avons déjà llU qu'il était possible de faire appel à des tableaux
automatiques; ces derniers permement déjà de régler une partie des problèmes évoqués.
Mais, il est également possible d'utiliser des 'tableaux dynamiques' , c'est-à-dire des
tableaux dont remplacement est alloué à la demande explicite du programme, au cours de
son exécution.
Les tableaux dynamiques vont vous permettre de mieux gérer la mémoire, en n'utilisant
que ce dout vous avez besoin à un moment donné. Notamment, rien ne vous empêchera de
'récupérer' un emplacement devenu inutile ' en 'libérant remplacement correspondant'.
program tableau_ctYnamique
i rp l ic i t none
integer, d imens ion(:.:). a llocatab le :: mat 1 decl arat ion tab dyna11ique de rang 2
integtr : : nl. ne. i. j
La déclaration :
précise que le tableau mal est de rang 2 (notez qu'on ne fournit aucun profil à ce niveau) ;
le qualificatif a/Jocatable indique qu'il s'agit d'un tableau dynamique (dont l'emplacement
peut être "alloué').
qui demande d'allouer un emplacement au tableau mal, en précisant quelles sont les
étendues souhaitées. Le tableau mal peut alors être utili~ d'une manière tout à fait
classique
L'attribut de dimension ne doit jamais mentionner les étendues du tableau mais seulement
son rang ; il est donc obligatoirement de la forme:
Ol lŒNSION ( [. : ) ... )
[ debUJ: /fin
Ici, toutefois, debUJ et fin peuvent être n'importe quelle expression entière4 • Lorsque debut
est omis (comme dans notre précédent exemple), il est pris par défaut égal à 1.
On peut allouer plusieurs des emplacements pour différents tableaux dans une seule
instruction oJ/ocOle comme dans :
i nteger : : ok
4. Alors que. p0urun tableau stati}ue, il s'agissait d'une expression construrteet p0ur \Dl tableau autcmatique ou
argument, d'une expression de spûification.
5. Notez qu'un tel phénomène ne peut pas apparaître dans Je C<ll des \Wiables statJ&ues puisque Jeurs
emplacements sont définis av.i.nt me.me qu'on ne ccmmenoe à exécuter k progr.unme. En rev.i.nche, il pouvait
déjà se manifester dans le cas des variables automatiques, dès lors que l'emplaoc.ment attribué initialement à la
p i.le éttît "satu~·.
228 X. La gestion dynamique et les pointeurs
Voici un petit exemple de programme qui alloue des emplacements de plus en plus grands,
en les libérant à chaque fois, jusqu'à ce que cela ne soit plus possible. On obtient ainsi une
estimation de la taille disponible pour la gestion dynamique:
e) La fonction allocated
Elle permet de savoir si un tableau dynamique dont on fournit le nom en argument s'est vu
ou non allouer un emplacement mémoire. Nous en verrons ci-Oessous un exemple
d'utilisation.
X. La gest ion dynainique et les pointeurs 229
Cela signifie que les tableaux d)uamiques devront obligatoirement être alloués et libérés dans
la même w1ité de programme. En revanche, il rest e possible de transmettre un tableau
dynamique à w1e. procédure. Il suffrt simplement de prévoir, au niveau de l'ar gument muet
co1Tespondant, un tableau de profil implicite (l'interface de la procédure doit être connue).
En voici w1 exemple d'école dans lequel nous avons également introduit des app el~ (ici
relativement artificiels) de la fonc tion al/oca1ed:
pro9ram table.au_dynamiqœ
implicit none
inte9er nl, ne, i, J
inte9er, dimension •: , : ), allocatable mat ! tableau dynamique
interface
subroutine afficha9e •t)
inte9êr, dimension C, : ), intent •in)
end subroutine afficha9ê
end interface
if • . not .allocated •mat)) print ', 'a'lant creation, matrice non encore allouee '
print ', ' nombre de li9nes et nombre de colonnes '
read ', nl, ne
allocate •mat •nl, nt))
if •aUocated •mat)) print ', 'apres creation, matrice allouee '
doi=l,nl
d:>J=l,nc
mat U, J ) = i ' J
end do
end do
eau afficha9e •mat)
deallocate •mat)
if • . not .allocated •mat)) print ', 'apres destruction, matrice non aUouee '
end
230 X. La gest ion dynamique et les pointeurs
10
12 15
apres destruction, matrice non allouee
Comme nous l'avons dit en introduction, nous allons commenœr par vous présenter la
notion de pointeur, de manière indépendante de la gestion dynamique à laquelle elle est
souvent associée. Ce paragraphe commence par le cas des pointeurs sur des variables d'un
type simple; les paragraphes suivants aborderont les pointeurs sur des chaînes, des
structures et des tableaux.
n • 10 ; p • 20
adint ->- n 1 adint p:>inte Slr n
print • , ' n : ', n, 'adint : ' , adint
adint •> p 1 maintenant adint pointe sur p
print • , 1 p : • , p, 'adint : ' , adint
adint • 25 ! l ' entier pointe par adint (dooc p) preOO la valeur 25
print • , 'p : ' . p, ' adint : 1 , adint
adint • adint + l ! on increnente de 1 l'entier pointe par adint
p-int • , 1 p : ', p, ' adint : 1 , adint
end
n : 10 adint : 10
p : 20 adint : 20
p : 25 adint 25
p : 26 adint : 26
La déclaration ;
précise queadinl est un pointeur sur un entier. Cela signifie qu'il pourra être associé (nous
verrons comment) à un entier. Notez bien que adint n'est pas un entier. D'autre part, la
r~ervation de adinln'entraîne pas de r~ervatlon pour un quelconque entier...
Dans la déclaration:
integer, target : : n, p
nous précisons que les variables n et p sont de type entier et que, de plus, e lles sont
"cibles", c'est-à-dire susœptibles d'être associées à un pointeur, sans préciser lequel.
L'instruction eio\cutable :
adint •> n
associe le pointeur adint à la variable entière n. Cela signifie que, dorénavant, lorsque, dans
une instruction, nous parlerons de adint, tout se passera comme si nous parlions den. C'est
c.e que montre effectivement le résultat de rinstructionprint •, 'n: ', n, 'adint: ~ adint.
Avec l'instruction;
adint s> p
L,instruction :
adint = 25
signifie que l'entier associé au pointeur adint (icip) reçoit la valeur 25. Notez bien qu'il ne
s'agit pas, comme on pourrait le crcire a priori, d'Une affectation à la variable pointeur
adint (d'ailleurs de telles affectations se font à l'aide de l'instruction = >); comme dans
n'importe autre instruction (telle que, par exemple, les précédentes instruction print),
lorsqu'on parle de adint, tout se passe comme si on parlait de l'entier associé. Autrement
dit, cette instruction a le même effet ici que:
p. 25
Malgré tout, on ne peut pas dire que ces deux instructions sont équivalentes puisque l'effet
de la première dépend de la variable effectivement associée à adint.
X. La gestion dynamique et les pointeurs 233
adint • ad int + l
pro~am exemple_yointeurs_2
iq> I icit none
inte~r. pointer :: ad intl, ad int2
integer, target : : n-10, polO
ad intl a> n ; ad int2 • > p 1 adintl pointe sur net adint2 sur p
print • . 'n : ', n, adintl : adintl
ad intl • ad int2 1 equiva lent a n • p
print • , ' n : ', n, p : '. p
n • 10 : p • 20 pour retrower les valeurs initia les
adintl • > ad int2 adintl pointe ma intenant sur p
print •, ' n : '. n, ' p p, ' adintl : ', ad intl. ' adint2 : ', adint2
end
n 10 ad inti : 10
n 20 p 20
n 10 p : 20 adi ntl 20 ad int2 20
Cette fois, nous avons déclaré deux variables tulintl et adùrt2, de type "pointeur sur des
entiers". L'instruction :
s'interprète comme nous avons déjà appris à le faire précédemment : rentier associé à
tulinll reçoit la valeur de l'entier associé àadint2. Quant à l'instruction:
nous ne l'a~ns pas encore employée sous cette forme (dans l'exemple précédent, on voyait
apparaître à droite de = > un nom de variable). Ici, elle signifie que le pointeur adinll
devient associé à la variable associée au pointeur adint2.
Par la suite, nous dirons sou-ent que cette instruction réalise faffectation d'une "valeur" à
un pointeur (le terme de "valeur" étant pour l'instant quelque peu flou - il se précisera
progressivement dans la suite de ce chapitre).
Remarques:
1) On peut être surpris que Fortran impose une correspondance stricte des types des
cibles en cas d'affectation d'une valeur à un pointeur. En fait, l'explication réside dans
le fait que le compilateur doit obligatoirement connai"tre le type exact d'Un objet cible
pour prévoir les instructions appropriées (ne serait-ce, par exemple, qu'une simple
addition); vooloir que ce type puisse é~luer au coors de l'el<écution poserait les
mêmes problèmes que vouloir que le type d'une variable puisse changer pendant
l'el<écution7 .
6. Saut dans le cas de procédures dans JesquelJes un argument muet a été dé.<:laré ccmme pointe-ur. Nous en
reparlerons un peu plus Join.
7. Toutet"ois., dans oertains langages de •progr.unmation orientée d>jet", il est possible de définir des pointeur$
susceptibles d'être assodû.. au cous de rexé.cution, à des "objets- de types différents ; on parle aJors dans ce CllS
de 'typa,ge dynamique•; les langages •c1as:siques", quant à e1.0:. se cœtentant d'un •typa.gt. statique".
X. La gestion dynamique et les pointeurs 235
Le principe reste le même que pour les pointeurs sur des variables de type simple. Voici
un exemple de programme illustrant la plupart des situations possibles.
program pointeurs_chaires
i mplicit rone
integer. parameter : : lgl • 20. lg2• 5
character (len•lgl) , target : : chl • "bonjour ", ch2 • *Kmsieur"
character (len• lg2), target : : ch3 • "hello"
character (len• lgl), pointer:: adchl. adch2 1 pointeurs Slr chaines de long 20
character (len• lg2) , pointer : : adch3 1 pointeur sur chaine de long 5
La déclaration :
character (len• lgl) , pointer : : adchl. adch2
236 X. La gestion dynamique et les pointeurs
précise que adchl et adch2 sont des pointeurs qui pourront être associés à des chaînes de
longueur 20. Elle montre qu'un pointeur sur une chaîne est caractérisé par la longueur de
la chaîne qui pourra lui être associée. On ne pourra donc associer à un pointeur sur une
chaine qu'une cible de m&ne longueur. C'e!t effectivement ce qui se passe dans les
affectations telles queadchl = > chl, adcl12 ~ > ch2 ou 1Ulcl13 = > c113.
En revanche, rien n'empêche d'affecter à une cible la valeur d'une chaîne de longueur
différente (comme nous pouvions affecter directement à une variable de type chaîne une
chaîne de longueur différente8}. C'est précisément ce qui se passe dans l'affectationadchl
= adch2 qui recopie le contenu de la chaîne associée à adcl.Z dans la chaîne associée à
adchl.
De plus, l'instruction adch3 = > ch2 (4:8) montre qu'on peut associer à un pointeur une
sous-chaîne à condition qu'il s'agisse d'une sous-chaîne d'une chaîne déclarée comme cible
(tœger) et qu'elle posstde la bonne longueur9 . Nous verrons que cette notion d'association
d'Un pointeur à une "variable au sens large' se généralise au cas des champs des structures
ou des sections de tableaux10.
program ordonner_deux_chaiœs_bis
inpl icit none
character ( l en•30). target :: chl. ch2
character ( l en•30). pointer : : illl. ad2. ad
pr int •, 'donnez deux chaines de 10ins de l> caracteres '
read • . chl. ch2
adl -> chl : ad2 -> ch2
Voyez oot e>emple qui montre comment les principes précédents s'appliquent aux
structures.
pro~am pointeurs_structures
i ~ licit none
type point ; character { l en•l) :: nom : integer x, y ; end type point
type {point), target : : pl • point {"A". 3, S), p2 • point {"C", 0, 2)
type {point) , pointer : : adpl. adp2
integer, pointer : : adint
a"'l ., pl ; adp2 • > p2
print •, adpl 1 affiche A 3 S
adplb • 8 : print *, pl 1 affiche A 8 S
adpl • adp2 ; print • , pl 1 affiche C O 2
adpl • point {"X", 9, 9) ; print • ,pl 1 affiche X 9 9
adint • > plb l correct car pl%x est un champ d 'une structure cible
print •, adint 1 affiche 3
end
Seule l'instruction adint s > pl%r a un caractère nou\'Cau: elle montre qu'on peut
aff<l!'ter à un pointeur (de type approprié - ici entier) un champ d'une structure, pour peu
que cette dernière ait été dtclarte comme cible. D s'agit en fait de la géntralisation aux
struc:tures de ce que nous avions vu pour les cbaûies. D'une manière générale, nous verrons
en fait que Fortran 90 accepte qu'on associe à un pointeur tout •sous-0bjct1:b> (sous-cliaîne,
cbamp, section de tableau non ambiguë) de type approprié d'un objet dtclaré cible.
5.1 Exemple
VO)CZ ce programme:
12. Ici, on ne peut plut se oontenterde dire qu'on peut usocier un pointeur à n'importe quelle variable di.d.ade
t ible.. Bn revanehe, on poumût parler de •tou$-\Wiable:" d\tne variable d&:lade cble (mais oe tenne n'est gu~re
répenOu).
X. La gestion dynamique et les pointeurs Z39
1 11111
1 1 1
112222
22
La déclaration :
précise que adl et ad2 sont des pointeurs qui pourront être associés à des tableaux
d'entiers de rang 2. Notez bien qu'ici aucune êtendue n'est précisée.
montre qu'on peut associer à un pointeur sur un tableau une section de tableau, pour peu
que celle-ci soit du rang voulu et qu'il s'agisse d'une section (non ambiguë) d'un tableau
déclaré comme cible (target). Ici, on voit clairement que l'information contenu dans adl va
bien plus loin qu'une simple adresse puisqu'elle doit permettre de repérer, au sein du
tableau cible qu'est Il, les éléments appartenant à la section de tableau en question.
Notez bien que, dans le précédent programme, une affectation telle que:
240 X. La gestion dynamique et les pointeurs
serait parfaitement légale ; elle modifierait simplement le tableau associé à adl (son
adresse et ses dimensions!). En revanche, une affectation telle que :
serait incorrecte puisqu'elle reviendrait à affecter au tableau associé par adl les valeurs du
tableau associê à ad2, leq ue~ dans le cas prêsent, est de profil différentB
De même, et de façon similaire à ee que nous avons dit dans le cas de pointeurs sur des
variables simples, avec ees déclarations :
En revanche, ees affectations seront correctes (elles feront inter.enir des conversions
numériques!) :
b) Lorsqu'on associe une section de tableau à un pointeur, il peut s'agir d'une section dont
les bornes som des expressions comme dans (ietj étant supposées entières):
adl-> tl(i :, j : j)
dans ee cas, il fau t bien voir q ue si les valeurs dei et j évoluent apr~ cette affectation, cela
ne modifiera en rien la section associée à adl. Pour qu'il en soit ainsi, il faudra, après
modification dei etj, exécuter à nouveau l'affectation précédeme.
Il n'est pas possible d'associer un pointeur sur un tableau à une section de tableau
olJt.enue par un ve<:teur d'indice. On peut raisoonableroent penser que la norme a introduit
13. Nous avons toutefois rencontré un oompiJatew qui acceptait une teJJe atfectation (sans toutefois éauer des
emplacementssitu6s en dehotS du tableau ooncemé_).
X. La gestion dynamique et les pointeurs 241
une telle restriction, afin de ne pas rendre trop complexe finformation contenue dans un
pointeur.
ptrl 0
>0> ptr2 ptr -> var
proç,ram ptr_gestion_cbtn
implicit nore
real, pointer :: adi pointeur sur un reel
character (len• IOO), pointer :: adc pointell' sur ure dla ine
integer, diœnsion (:),pointer :: adt pointelr sur un tab d'entiers de rarg 1
integer :: i, n
- commence par allouer un emplacement mémoire pour un entier (ce type est déduit de
la déclaration de adi),
- puis associe cet emplacement au pointeur adi.
X. La gestion dynamique et les pointeurs 243
D'autre part, lorsqu'on alloue un emplacement pour un tableau, on précise les étendues
désirées, exactement comme on ra fait dans le eas des tableaux dynamiques (déclarés avec
l'attribut allocalable). La seule différence entre les deux eas est qu'on a affaire ici à un
pointeur sur un tableau à la place d'Un nom de tableau.
Notez bien qu'à partir du moment où ron alloue dynamiquement un emplacement pour un
"objet", on ne peut y "aecéder" que par l'intermédiaire d'un pointeur (celui qu'on a précisé
à allocate); il n'en allait pas de même dans les préœdents paragraphes (objet statique ou
automatique associé à un pointeur) car, alors, l'objet lui-même possédait un nom : on
pouvait donc y accéder indifféremment par son nom ou par un pointeur14 .
Supposez qu'au sein d'Un programme, on dispose de deux chaînes déclarées ainsi:
Supposez qu'on souhaite permuter é\entuellement les deux chaûies contenues dans chi et
ch2, de manière à ce qu'elles soient ordomées suivant rordre "alphabétique•. Voici
comment nous pourrions procéder :
Nous ajoutons une déclaration supplémentaire pour un pointeur adch sur des chaînes de
80 caractères. S'il est néœssaire de procéder à l'échange du contenu des deux chaûies (et
uruquement dans ce eas), nous allouons dynamiquement un emplacement pour une telle
chaûie, lequel nous sert à effectuer la permutation voulue ; ensuite de quoi, nous libérons
l'emplacement correspondant, devenu inutile, en faisant appel à l'instruction deaUocate
(elle s'emploie exactement comme pour les tableaux dynamique).
14. C'est pré.cisément pour cette raiS'On que les pdnteurs sont peu utilisés pour des objets statiques ou
automatiques.
244 X. La gestion dynamique et les pointeurs
L'instruction allocate
L'instruction deallocate
Aoec:
Mais, pour les utiliser à bon escient, il faut voir que, comme n'importe quelle autre
variable, un pointeur qui n'a pas encore reçu de valeur en possède quand même une mais
qu'elle est imprévisible: on dit que le pointeur en question est dans un état indéfini. Si on
X. La gestion dynamique et les pointeurs 245
cherche à l'utiliser dans cet état, les rtsultats sont imprévisibles : on peut utiliser une
mauvaise valeur, écraser un emplacement mémoire quelconque ou, au mieux, obtenir une
erreur d'exécution (liée au fait que l'adresse trouvée n'est pas acceptable).
Notez toutefois que, si mus tentez ensuite d'utiliser adr sans prendre de précaution
particulière (comme nous le verrons ci-<lessous), vous courrez toujours les mêmes risques
que ceux évoqués précédemment.
li est possible de savoir si un pointeur a été associé à une cible en utilisant l'une des formes
de la forme de la fonction associated. Plus précisément, avec la déclaration précédente de
adr, fexpression assoclated (adr) aura la valeur vrai si une etble a été associée à adr (que
cette association ait eu lieu par affectation de la forme a > ou par l'instruction al/ocale) et
la valeur faux dans le cas contraire.
Toutefois, si le pointeur adr n'a été associé à aucune cible, c'est-à-Oire s'il est dans un état
indéfini, le résultat de associaled est, lui-auss~ imprévisible (soit vrai, soit faux!). En
revanche, si le pointeur a reçu une "valeur nulle" (par nul/ify), il sera bien considéré comme
non associé.
Le même risque e.iste après qu'on a libéré un emplacement par deal/oca1e : la norme
n'impose pas que cette instruction mette à zéro le pointeur correspondant (mais on peut
toujours le faire avecnul/ify).
On voit donc que, pour être sOr des résultats fournis par la fonction associated, il faut
absolument éviter d'avoir des pointeurs dans un état indéfini (donc soit les initialiser
explicitement, soit leur donner une 'Valeur nulle" par m/lify).
Voici un petit programme d' illustration:
program test_assoc
i mplicit oone
integer, pointer : : ptr
print • . associated (ptr) 1 affiche Tou F (indefini)
rullify (ptr) : print •, associated (ptr) 1 affiche F (faux)
allocate (ptr) : print • , associated (ptr) 1 affiche T (vrai)
deallocate (ptr) : p-int • , associated (ptr) 1 affiche Tou F (irdefini)
ru Il ify (ptr) : print •, as soc iated (ptr) 1 affiche F (faux)
end
L'expression associated (adl, n) a la valeur vrai si le pointeur adl est associé à la cible net
la valeur faux dans le cas contraire (y compris si adl a une valeur nulle). De même
l'expression associated (adl. ad2) prend la valeur vrai si adl e t ad2 sont associés à la même
cible et la valeur faux dans le cas contraire (y compris si l'un au moins des deux pointeurs a
une valeur nulle). Là encore, la valeur fournie par la fonction assodated est indéterminée
&s lors qu'un des pcinteurs transmis en argument possède une valeur indéfinie.
8 · POINTEURS ET PROCEDURES
li est bien sûr possible d'appeler une procédure en lui fournissant un pointeur en argument
effectif. Mais il faut distinguer deux situations totalement différentes suivant que, dans la
définition de la procédure, rargument muet correspondant est ou n'est pas un pointeur.
X. La gestion dynamique et les pointeurs W
En effet, un pointeur apparaissant en argument effectif est (par dêfaut) traité comme s'il
s'agissait de l'objet associé. Notez d'ailleurs que c'est bien ee comportement que nous
avons rencontré jusqu'ici (excepté lorsqu'un nom de pointeur apparaissait à gauche de
rinstruetion = > ).
En ee qui coneernel'interfaee de la procédure copie, elle n'est pas ici indispensable. D'une
manière générale, le fait d'avoir un pointeur en argument effectif ne change rien au besoin
qu'a le compilateur de connaître ou non son interface.
Dans ee cas, la situation est totalement différente. En effet, Fortran coosidère que
l'information correspondant à eet argument est effectivement l'information contenue dans
le pointeur lui-même (adresse, dimensions ..) et non l'information associée à ee pointeur.
Généralement, on utilisera eette facilité lorsque la procédure devra être en mesure de
modifier le pointeur lui-même.
248 X. La gest ion dynamique et les pointeurs
En voici un exemple dans lequel la procédure ordre pennet d'échanger éventuellement les
valeurs de delLx pointeurs. afin que les chaines associées soient effectivement convenablement
ordonnées. Notez qu'alors les contenus des chaines en quest ion ne sont nullement modifiés.
pro9ram ordre_chaines
implicit none
interface ! indispensable ici
subroutine ordre •pl , p2) ; character Hen=80), pointer pl, p2
end subroutine ordre
end interface
character Uen=80), tar9et chl="pascal" , ch2=" fortran"
character Uen=80), pointer adl, ad2
adl => chi ; ad2 => ch2
call ordre •adl , ad2) ! sans interface, trans . des chaines et non des pointeurs
print ', "chaines initiales " print ', chi, ch2
print ', "chaines ordonnees " ; print ', adl, ad2
end
D'une 1nanière générale, on voit que, si une procédure a prévu un pointeur en argun1ent
n1uet, rappel devra con1porter obligatoiren1ent un pointeur en argunlent effectif (du
même type !). Bien entendu, le compilatew· ne powTa s'en assurer que s'il dispose de
l'interface de la pr océdur e~ dans le cas contraire, il se contentera de transmettre en argument
effectif, l'objet associé au pointeur (puisque c'est là le compo11ement par défaut !) et les
co1t.'i.équenœs apparaitront (p lus ou moins clairement) au moment de l'exécution !
Par aiUeurs, jusqu' à Fortran 2003, il n ' était pas possible de préciser, avec ;n1en1, le genre d'w1
pointeur reçu en argument muet~ la principale just ification résidait dans l'ambiguïté de ce
qualificatif: devait·il po11er sur Je. pointew· lui· même ou sur l'objet pointé? A partir de
Fortran 2003, il a été convenu que ce qualificatif por terait sur le pointeur lui-n1ênle.
X La gestion dynamique et les pointeurs 249
L'utilisateur du langage Fortran est gént\ralement peu habitué à utiliser des "listes
chamoos", dans la mesure où leur programmation était, jusqu'au Fortran 77, relatioement
délicate.
Toutefois, les listes chamées peuvent s'avérer pratiques dans certains types de problèmes
que l'on a souvent trop tendance à résoudre par l'utilisation d'un tableau (éventuellement
d'un tableau de structures). Bien entendu, le choix doit se faire, à partir des diverses
opérations qu.e l'on doit appliquer aux différents éléments concernés. En particulier, s'il est
nt\cessaire de conserver une liste ordonnée (suivant un critère quelconque) d'éléments et
qu'il faut fréquemment introduire un nouvel élément à sa place dans la liste, alors la liste
chaînoo est manifestement plus approprioo que le tableau. De même, la liste chamoo
permet de n'Utiliser à un instant donné qœ la place nécessaire, tandis que le tableau
nécessite de connailre le nombre d'éléments (ou une borne supérieure).
Ici, nous ..ous présentons un exemple simple (pour ne pas dire simpliste) de liste chamoo
dont le principal objectif est de vous montrer les techniques à employer en Fortran.
Supposons donc que nous ayons à conserver en mémoire des éléments du type point défini
ainsi:
t ype poi nt
i nteger : : rum 1 m.n ro i dent if i ant un poi nt
f loat x, y l ooordonnees
end type point
Pour pou..oir établir une liste chamoo d'éléments de ce type, il est nécessaire que chaque
élément comporte un pointeur sur félérnent suivant. li fau t donc adapter en conséquence
la structure précédente, ce qui nous conduit à quelque chose de ce genre (nous a..ons
gardé le même nom de type) :
type poi nt
i nteger :: num 1 m.mero i dent if i ant un poi nt
tloat x, y 1 coordonnees
t,We (poi nt). pointer ;: s uivant ! poi nteur sur elenent sui vant
e rd type poi nt
250 X. La gestion dynamique et les pointeurs
Notez qu'il est nécessaire, dans la définitiœ même du type poin~ de déclarer un champ de
type "pointeur sur un élément de type poitt" ; il y a là une sorte de récursivité des
déclarations qui est autorisée en Fortran.
Ici, nous allons supposer que nous constituons notre liste chaînée, à partir d'informations
fournies en données dans le "bon ordre". Deux possibilités s'offrent alors à nous :
Notez que le dernier élément de la liste (donc, dans notre cas, le premier lu) ne pointera
sur rien. Or, lorsque nous chercherons ensuite à utiliser notre liste, il nous faudra être en
mesure de savoir Oil tilt s'anêtt. Certes, nous pourrions, à eet effet, consener l'adresse de
son dernier élément. Mais il est plus simple d'attribuer au champ suivant de ee dernier une
valeur dont on sait qu'elle ne peut appara.t"tre nulle part ailleurs; la valeur "nulle" (fournie
par la fonction rullify) fait tres bien l'affaire.
Ici, nous a\Ons décidé de faire effectuer la création de la liste par un sous-programme. Le
programme principal se contente de réserver remplacement d'un pointeur destiné à
désigner le premier élément de la liste. Sa valeur efl'ecti.e sera fournie par le sous-
programme crtatioo.
Bien entendu, la constitution d'llne telle liste n'est SOU\'Cnt que le préalable à un traitement
plus sophistiqu6. En particulier, dans un cas r6el, on pourrait être amen6 à réaliser des
op6rations telles que :
EXERCICES
- lit un nombre n,
- alloue un emplaœment pour une matriœ carr6e n x n, en s'assurant que l'op6ration
s'est bien d6roulée,
- appelle un sous-programme qui attribue des valeurs {de votre choix) à œtte matriœ,
- appelle un sous-programme qui affiche les valeurs de la matrice,
- libère femplaœment correspondant.
program essai
i nplici t none
rea l, poi nter : : pl. p2
real ::x • 2.5,y • l. O
pl -> x : print • . 'A : 2•p1
p2 • > y ; pr int •. '8 : pl + x + 2*p2
pl • > p2 ; print • , ' C : pl , p2
pl • X ; pr int •, '0 : pl , p2, X, y
pl • > X ; p2 • > y
pl • p2 • y ; print •. 'O : '. x
er<I
X. La gestion dynamique et les pointeurs 2S3
Au cours des précédents chapitres, il nous est arrivé de dire que les modules permettraient
d'améliorer la fiabilité des programmes en évitant la duplication de déclarations
identiques, en particulier au niveau des interfaces de procédures externes et des types
structure (ou types déri\Oés) utilisés par plusieurs unités de programme.
Comme nous allons le voir dans ce chapitre, la notion de module va bien au-delà de ces
quelques caractéristiques. En effet, d'une manière générale, un module peut être considéré
comme une unité de compilation autonome comportant à la fois des déclarations de
variables, de types, des interfaces de procédures ainsi que des définitions de procédures;
celle unité peut être utilisée au sein de n'importe quelle autre, comme si l'on avait explicité
son contenu.
Par ailleurs, Fortran 90 offre des possibilités traditionnellement réser\Oées aux langages
orientés objet, à savoir :
En fait, nous verrons que les deux dernières possibilités sont, symaxiquement parlant, un
cas particulier de la première.
A prior~ ces "extensions objet" sont indépendantes de la notion de module et il serait tout à
fait envisageable de les étudier en elles-mêmes (nous le ferons succinctement d'ailleurs
pour la généricité). Néanmoins, elles sont d'un emploi beaucoup plus aisé lorsqu'elles sont
associées à la notion de module; c'est ce qui justifie leur place dans ce cbapitre.
1 - NOTION DE MODULE
Pour vous familiariser avec la création et l'utilisation d'un module, nous allons commencer
par un eJ<emple trés simple de module contenant une seule déclaration de type, à savoir le
type point déjà rencontré :
type point
i nt~r num
real x. y
end type poi nt
module essai
i mpl i ci t none
type poi nt
i nt~er m.111
real x, y
end type poi nt
en:I module essa i
On note remploi du mot clé module à la place du mot clé program ; d'autre part, vous
constatez que, contrairement à un programme ou une procédure, un module peut ne
c.ontenir aucune instruction exécutable.
XI. Les modules et la généricité 2S7
Pour utiliser ce module, au sein d'une autre unité de compilation (programme principal ou
procédure), il nous suffit de mentionner son nom dans une instruction use (ici : use essai).
En voici un exemple, au sein d'un programme principal :
program exetrple_rrodule
use essai
impl i c it oone
type (poi nt) :: a • poi nt (3, 2.0. 3.5)
print *.a
end
3 2. 0000000 3. 5000000
Tout se passe alors comme si les instructions contenues dans essai avaient été introduites
dans le programme exemple_module. Nous pou\O'.lns ainsi déclarer une variable a de type
poi11t, sans avoir à redéfinir ce dernier.
Remarques:
module essai
i mpl i ci t none
type poi nt ; i ntf?9er rum ; real x, y ; en:I type point
conta ins
funct ion S>"10tr ique (p, n)
type (point), i ntent ( i n) :: p
type (poi nt) : : S>"l'tr ique
i nt~r. intent ( in) :: n
S>"10tri que • point (n, - p%x, - p%y)
en:I funct i on S)flletr ique
end nodule essa i
program exemple_module
i mpl ic i t none
use essa i
type (point) :: a • poi nt (3, 2.0, 3.5) . b
b • s)lnetr ique (a, 10)
pr int •. a. b
erd
Nous y trou\O'.lns cette fois, outre la définition de type précédente, une fonctioo ; celle-ci est
définie exactement de la même manière que le serait une fonction interne à une unité de
compilation : mot clé contains, accès, dans la fonction, aux 'objets' définis globalement (ici,
le typepoùtt qu'il n'est donc pas besoin de redéfinir).
L'utilisation de ce nouveau module se fait exactement comme précédemment Cette fois,
outre l'utilisation du type point, nous pou\O'.lns faire appel à la fonction s;metrique, sans
avoir à en fournir l'interface (comme s'il s'agissait d'une fonction interne). Notez que cette
interface serait indispensable dans le cas d'une fonction externe puisque rargument de la
fonction et soo résultat sont de type non s tandard.
XI. Les modules et la généricité 259
nxlule essai
imp li ci t oone
integer. parameter : : nbre_param • 10
integer. di mensi on (rt>re_param). save : : coeff
end nxlule essa i
progr;,wn exEIRf)le_mdule
impl i ci t oone
use essa i
i nteger : : 1
coeff • (/ ( 1. 1• 1, ntre_param) /)
ca Il sp
end
s ubrout i ne sp
ilrp 1ic i t none
use essai
pri nt •. coeff
end subrout i ne sp
1 2 3 4 5 6 7 8 9 10
Ici, notre module comporte simplement la déclaration d'un tableau nommé coejf. Certes,
nous pouvons ainsi faire appel à un tel tableau, sam a\Oir à Je déclarer, dans toute unité de
programme utilisant le module, mais cela n'est pas d'un grand intérêt En revanche, il
devient possible à plusieurs unités de programmes de "partager" ce tableau. l'lus
précisémen~ Je programme principal y place ici des valeurs qui sont reprises par une
procédure externe nommée sp.
Pour que ce partage soit possible, il est bien sOr nécessaire que les unités concernées
fassent appel au module en question mais, de surcroll, il faut que les variables concernées
2(i() XI. Les modules et la généricité
aient été déclarées avec l'attribut save (c'était bien le cas de coe/f). Si l'on omet cet attribut,
aucune erreur de compilation n'apparaîtra mais rien ne vous assurera que les tableaux
coejf du programme principal et de la proOOduresp seront les mêmes; on retrou\C un peu
le même p~nomène que pour les variables locales à une procédure: avec l'attribut staûc,
leur emplacement est défini une fois pour toutes.
Un module, comme n'importe quelle autre unité de programme, peut très bien faire appel
à son tour à un autre module. A titre d'exemple, nous a\l'.lns repris le programme du
paragraphe 2.1, en faisant de la fonction symetrique une fonction externe indépendante et
en prévoyant deux module distincts: l'un pour les déclarations de types (ici le seul type
poi111); rautre pour les interfaces (ici desymetrique) :
module pro~tl_interfac.es
tmplic it oone
use projetl_types
i nterface
function s.)'l'letrique (p. n)
type (point), intent (in) : : p
type (point) :: S)Oletrique
integer. intent (in) : : n
end function S.)'lletrique
en:I interface
end modul e projetl_interfac.es
program exeople_moclule
i npl ic i t none
use projet!_types
use projet!_ interfaces
twe (point) :: a • point (3, 2.0, 3.5), b
b • Sl"Otr ique (a. 10)
pr int *. a. b
end
D'une manière générale, le seul type de dépendance qui soit interdit est celui où un
module s'appelle lui-même (soit directement, soit indirectement: A utiliserait B, qui
utiliserait C ... qui lui-même utiliserait A).
Nous a\O'.lns vu que les procédures définies dans un module ont accès aux 'objets' définis
globalement. De la même manière, la ' portée' de la déclaration implidt none placée en
début du modràe s'étend aux procédures définies dans ce module de sorte qu'il n'est pas
nécessaire d'y répéter cette déclaration {le faire ne constitœrait toutefois pas une erreur).
Bien entendu, dans ce cas, les différentes entités de la procédure hôte sont accessibles à
ses procédures internes; celles-ci, en revancbe, ne sont pas accessibles à d'autres
procédures de modules autres que leur hôte ni, a fortiori, à une unité utilisatrice du
module.
262 XI. Les modules et la généricité
Lorsqu'on utilise un module, on peut se trouver gêné par les noms des différentes
ressourœs (types, variables, procédures...) qu'il nous propose. Cela peut par exemple
arriver dans un contexte de projet important dans lequel sont impliquées plusieurs
personnes; nous pou\O'.lnS également a\O'.lir à utiliser deux modules différents qui
comportent des noms communs; nous pouvons aussi souhaiter disposer, dans notre unité
de compilation de noms qui nous paraissent plus appropriés à notre problème ...
Dans œ cas, il est possible, dans l'instruction use, de "renommer" tout ou partie des
ressour.œs du module. Par exemple, en appelant ainsi notre module essai du paragraphe
1.2:
Le type point sera dorénavant connu sous le nom couple {le nom point ne sera plus
utilisable) et la fonction symttriqut sous le nom S)m.
On peut bien sOr ne renommer qu'une partie des ressourœs, les autres gardant leur nom
d'origine.
Remarques:
1) Lorsqu'on utilise deux modules ayant des noms de ressources en commun, aucun
problème ne se pose tant que l'on ne cherche pas à utiliser rune des ressources en
question. Dans le cas contraire, il apparait une arnbiguité qui ne peut se résoudre qu'en
les renommant.
2) Un nom défini dans une unité de compilation cache automatiquement une ressourœ
de même nom dans un module. Pour accéder à œtte ressource, il est nécessaire de la
renommer.
Dans le cas de modules .conséquents, il arrive fréquemment que l'on ait pas besoin de
toutes les ressources y figurant. Dans ce cas, BOUr d'évidentes raisons de sécurité, on peut
avoir intérêt à limiter \O'.llontairement faccès aux ressourœs qui nous intéressent On
emploie alors le mot clé on/y pour mentionner les ressources en question Par exemple, si
un module truc se présente ainsi:
XI. Les modules et la généricité 263
rodule t ruc
type t1 . . . . . . .. : end type t1
type t2 . . . . . . . . ; end type t2
i ntO<JOr, di ..,ns ion (10) :: param
oontains
s ubrout i ne sp . .. . . end subrouti ne sp
furcti on fc end fuocti on fc
en:I IOdule truc
~ nom_JOOdule
USE rom_100dule, l iste_de_nx:li f i cat i ons_de_noms
USE roo_lllldule, Olt.Y : [ l iste_de_spécificat ions ]
L'instruction use
Avec:
liste_de_modifications_dt_noms: liste d'indications de la forme ancien_nom = >
nouveau_nom.
liste_dt_spécifications: liste d'indications de l'une des formes nom ou (]Jlcien_nom = >
nouveau_nom.
dans ces conditions, pour d'évidentes raisons de sécurité, on a tout intérêt à ne pas laisser
l'utilisateur risquer de modifier (accidentellement) ces données. Nous .errons plus loin
d'autres situations oil la privatisation de ressources s'impose (pour assurer fencapsulation
des données dans un type abstrait).
Les ressources accessibles à tout utilisateur d'un module sont dites "publiques• ; les autres
sont dites "privées". Par défaut, toutes les ressources d'un module sont publiques. On peut
rendre pri.t un type ou une variable (cette démarche ne s'applique pas aux procédures) en
ajoutant rattribut priWJte dans sa déclaration, comme dans! :
On peut également utiliser une instruction private dans laquelle on énumère les différents
ncms de ressources (type, variable ou procédure) qu'on souhaite privatiser comme dans
cet exemple :
rodule truc
type point ..... : end type point
i nt~r::n,p
rea l , dhœns lon (10) :: tl, t2
pr ivate : : poi nt, n. t2
Ici, les variables net t2, ainsi que Je type point sont privés.
JI est également possible d'utiliser les instructions priWJte ou public pour imposer 'un état
par défaut" ; vo)Cz cet exemple :
mxlule truc
integer : : n n est publ ic par defaut
pr i vate pr i ve devi ent l'etat par defaut
real::x.y x et y sont donc pr ives
integer. public .. q q est public
integer : : r r est pr ive
1. Attention, ici., les <Jel.&X points deviennent obligatoirts. alorsqu'ilsttaitent (acultatif$ <Jans Jes auttts eu.
XI. Les modules e t la généricité 265
De plus, les types structure peuvent être 'semi-publics', c'est-à-dire que fon peut laisser
public le type lui-même, tout en privatisant ses différents champs. Dans ce cas, il suffit de
faire précéder la déclaration de ces champs d'une instruction private comme dans :
type (poi nt )
pr i vat e
i nteger : : x. y
er<I type poi nt
Seules les différentes procédures du module où le type poilll a é té défini pourront accéder
aux composantes x e t y d'un point. En revanche, les utilisateurs du module pourront
déclarer des variables de type point mais ils ne pourront pas accéder directement à leurs
composantes. Nous reviendrons sur l'intêrêt de cette possibilité dans le paragraphe 5.2
2.1 Le principe
Si fon consi&re une fonction prédéfmie telle que abs, on constate qu'elle peut reœ\Oir
(entre autres) indifféremment un argument de type i111eger ou un argument de type real {le
résultat fourni ayant le type de l'argument). Or, avec ce que nous connaissons des
procédures, il ne semble pas possible d'écrire nous-mêmes une procédure dans laquelle le
type d'un ou plusieurs arguments ne soit pas rigoureusement imposé.
En réalité, une fonction telle que abs est dite 'générique', en ce sens que, à un nom unique
correspoodent en fait plusieurs fonctions (une pour le type integer, une pour le type rea/...),
chacune portant un nom et une interface spécifiques. Là où nous écrivons abs, le
compilateur va en fait appeler une fonction précise dont le nom sera déduit du type de
l'argument d'appel.
Cette possibilité de regrouper sous un seul nom toute une famille de procédures (en
laissant le compilateur décider de la boone procédure à appeler en fonction du type des
arguments) peut également s'appliquer à des procédures que nous définissons nous-
mêmes. Il nous suffit pour cela d'emplo)er la technique que nous allons décrire
maintenant :
Fréquemment cette technique sera mise en oeuvre par fintermédiaire d'un module; ce
n'est toutefois pas une obligation et nous commenœrous par vous la présenter en tant que
telle, sans utiliser de module.
Pour en faire une procédure générique, il nous faut alors créer un "bloc d'interface•
approprié:
i nterface affiche les proce<lures qu'on appelera sous le nan gener i que affiche
s ubrouti ne aff int (n) ; integer : : n; end s ub"o utine affi nt
slt>routine affr (r) : real :: r ; end sulrouti ne affr
s ubrout ine afft i ntl (t) ; int~er. dimerf:i i on (:)nt ; end sulrouti ne afft intl
en:I i nter face
interface affi che 1les proc:edures qu'on appelera sous le nan gener i que affi che
subrout ine affi nt (n) : i nt~er :: n ; end s ubrout i ne affi nt
subrout ine affr (r) ; real :: r ; end s ubrout i ne affr
s ubrout ine afft i ntl (t) ; i nteger, dimens ion(:) :: t ; end subrout ine afft i ntl
en:I interface
integer : : n • 25
rea I :: x • 5 .25
i nteger, dimens i on (5) :: tabl • (/ 3, 5, 2, 9, 12 /)
i nteger : : i
i nteger, di mensi on (15) :: tab2 • (/ (25*i, i • l. 15) /)
call affi che (n) ; call affi che (x) ; call affi che (tabl) ; call aff iche (tab2)
end
A la rencontre d'un appel tel que calf affiche(...) , le compilateur se sert du bloe d'interface
correspondant à la procédure générique affiche pour déterminer quel est le sous-
programme (affin~ ajfr ou affiintl) à appeler effectivement.
- créer un module contenant simplement le bloc d'interface de affiche (tel qu'il a été
indt roduit dans le programme principal), en gardant des sous-programmes externes
pour affin4 a/fr et ajfintl; cela ne présente donc ici aucune difficuhé puisqu'il suffirait
de créer ce petit module:
module irt-e r _affiche
interface affiche les proœdures qu ' on appelera sous le nom generique
1 affiche
s ubroutine affint (n) irt-e ger : : n : en:I s ubroutine affint
s ubroutine affr ( r) real :: r: en:I s ubroutine affr
subroutine afftintl (t) i nteger, dimension ( : ) , . end subrout ine afft intl
end interface
e nd nodule inter _affiche
· créer un module contenant les définitions des sous-programmes afllnl, offr et offintl ;
dans ce cas, une petite no1Neauté apparat"\: en effet, ces sous-programmes vont figure r
dans le module en question, en compagnie du bloc d'interface re latif à a/ficlie ; il n'est
alors plus nécessaire d'y fournir la description complète des sous-programmes (nom et
types des arguments) : seul leur nom suffit; ceci conduit à une nou-elle instruction de
déclaration ; module procedure, suivie du nom des procédures en question (elle précise
les procédures faisant partie de la ''famille•, tout en mentionnant que leur définition
figure dans le module lui-même). Voici ce à quoi nous aboutissons en programmant
aiŒi notre préoédent exemp le :
nodule gene
interface affiche 1 les procedures qu 'on appelera sous le nom generique affiche
module procedure affint, affr , afftintl
en:I irt-e r face
contains
s ubroutine affirt (n) : integer : : n
print '(lx,·-- entier --·. il2)'. n
en:I s ubroutine affint
s ubroutine affr ( r) ; real : : r
print 1 (lx, " --- reel ........ el2 .4) ' . r
end s ubroutine affr
s ubrout ine afftintl (t) ; integer, dinension (:) :: t
print •. 1 - - - tableau d"entiers de profil ('. size(t ). ')
print ' (lx, 12i6)', t
end s ubroutine afftintl
end module gene
XI. Les modules et la généricité 2@
program essa i
use gene
impl i c it none
i nt~r :: n • 25. i
rea 1 : : x • 5 .25
i nteger, dimens i on (5) : : tabl • (/ 3, 5, 2, 9, 12 /)
i nteger, dimens i on (15) :: tab2 • (/ (25*i , i• l. 15) /)
call affi che (n) ; call aff iche (x) ; call aff iche (tabl) call affi che (tab2)
end
interface f ambigui te
f uncti on fi (n, x) 1 enti er. ree l
i nt~er :: n
real :: x
rea l :: f1
en:I funct i on fl
function f2 (x, n) ree l , ent i er
r·eal : : x
i nt~er :: n
real :: f2
en:I functi on f2
end i nterface
2. N>oubUez pas que les variantes des types numtriquesoorrespondent Ades types difUrentsles uns des autres et
que des tableauxde rangdiIUrentscorrespondent ~galement Ades typeSdifUrents.
2JO XI. Lesmoduleset lagénfocité
Le mal vient de ce que ron a emplo)t les mêmes noms d'arguments pour les deux
fonctions, de sorte qu'il n'est plus possible au compilateur de trancher dans le cas d'un
appel par mot clé tel que:
call f (n• ... , x• ... )
3.1 Le principe
Dans u11e expression arithm~tique telle que a +b, le même symbole o~ratoire + peut
d~igner, suivant le type de a et b des o~rations différentes: addition de deux entiers,
addition de deux réels...
- donner une signification à tout symbole o~ratoire existant ( +, -, •, /, <, >, ..and. ,
etc.) lorsqu'il porte sur des types différents de ceux pour lesquels il est déjà défini (on
ne pourra pas modifier la signification de l'addition de deux entiers!),
- créer de nou-eaux o~rateurs (de la forme .op. où op désigne une suite quelconque
de caractères).
Dans les deux cas, on utilise le même mûanisme, à sa\Oir qu'on définit une fonction
générique de nom optrator (op) , op d~ignant l'o~rateur concerné( + ,•, .and., .plus.,
.appartient., ...) comportant :
- deux arguments (de genreintent(in)), s'il s'agit d'un o~rateur à deux opérandes,
- un argument (de genre intent(in)) s'il s'agit d'un opérateur à un o~rande (tel que -
dans -a ou .not.)
32 Exemples
Généralement, cette technique est utilisée pour doter d'o~rateurs simples des types
déri\Oés (structures), afin d'en simplifier la manipulation. Voici, par exemple, comment
nous pou\Ons définir (ici, au sein d'un module) l'o~rateur + pour qu'il ait une
signification lorsqu'il est appliqué à deux valeurs de type point : ici, il fournit un point dont
les coordonnées sont obtenues en faisant la somme des coordonnées des deux o~randes.
XI. Les modules et la généricité 271
mdule type_poi nt
i mpl i ci t none
type poi nt
integer : : x, y
end type point
i nterface operator { • )
nodule procedure poi nt_plus_poi nt
end i nterface
contai ns
f urct ion point_plus _poi nt (pl. p2)
type (poi nt), i ntent ( i n) : : pl. p2
type (i>oi nt) :: point_pl us _poi nt
poi nt_plus_poi nt • point (pl"" • p2""· p1%y • p2%y)
end f un;;t ion point_plus_point
end nodule type_poi nt
progr;,wn essai
use type_point
i npl ic i t none
type (poi nt) :: a • point (3, 2), b • poi nt (5, 2), c
c • a • b
pri nt • . c ! aff iche 8 4
end progr;,wn essai
Ici, bien que nous ayons procédé comme pour définir une fonction générique nommée
operator ( +), il ne correspondait qu'une seule fonction effecthe (poùtt_plus_poùtt) à œ
nom générique. Voici, cependant un autre exemple, basé sur le même type poùtt dans
lequel nous dAf'm.issons trois opérateurs + , le précédent (pour additionner deux points).
Paddition d'un point et d'un entier (on considère alors que le résultat est le point d'origine
dont l'abscisse a été augmentée de rentier en question) et faddition d'un entier et d' un
point (même chose).
m XI. Les modules et la généricité
mdule twe_poi nt
type poi nt ; i nteger : : x, y ; erd type poi nt
interface operator ( • )
module proce<lure poi nt_plus_poi nt. point_plus_ent i er. ent i er_plus_poi nt
end i nterface
conta ins
funct i on poi nt_plus_poi nt (pl. p2)
type (point), intent ( i n) :: pl, p2
type (point) : : poi nt_plus_poi nt
point_plus _point • poi nt (pl%>< •p2%x. p1%y • p2%y)
en:I funct i on poi nt_plus_poi nt
funct i on poi nt_plus_enti er (p. n)
type (point), i ntent ( i n) : : p
i nteger. intent ( i n) : : n
type (poi nt) : : point_plus_enti er
poi nt_plus_ent i er • poi nt (p%x • n, p%y)
end f unct ion point_plus_enti er
fonct ion ent i er_plus_poi nt (n, p)
type (poi nt). i ntent ( in) : : p
i nteger, i ntent ( i n) :: n
twe (poi nt) : : ent ier_plus_poi nt
ent i er _plus_poi nt • point (n • p%x, p%y)
end fun::t i on enti er_plus_point
end mdu le twe_point
program essa i
use type_poi nt
i rrpl ici t none
twe (point) : : a • point (3. 2). b • poi nt (5, 2). c
c • a • b pri nt • . 'a•b'. c
c • a • 3 ; pri nt •. ' a •3' . c
c • 5 • a : pr int *. 1 5•a ' . c
en:I program essa i
a•b 8 4
a•3 6 2
S.a 8 2
Remarque:
4 - SURDEFINITION DE L'AFFECTATION
Lorque Pon est amené à défmir de nouveaux types dérivés {structures). on est limité dans
le fait que faffectation n'a de sens qu'entre deux éléments du même type. Par exemple,
avec le type point préœdent, on ne peut qu'affecter un point à un point, alors qu'on
pourrait vouloir affecter un entier à un point (en convenant qu'alors on affecte cet entier à
l'abscisse du point et la valeur O à son ordonnée). Ceci est possible en surdéfinissant
l'opérateur d'affectation dans ce cas.
La démarche est, là encore, la même que pour la réalisation d'une fonction générique
nommée (cette fois) assignmtnt ( = ) . Voici un exemple dans lequel nous avons défini
l'affectation d'un entier à un point ainsi que raffectation d'un point à un entier (dans ce
cas, on obtient l'abscisse du point).
1:14 XI. Les modules et la généricité
module tweJ>Oi nt
type poi nt ; i nteger : : x, y ; end type poi nt
interface ass lgnment ( • )
module proœdure point_egal _ent i er, enti er_egal_ poi nt
end interfaœ
conta i rrs
s ubrout ine point_egal _ent ier (p, n)
type (point), i ntent (out) : : p
i nteger, i ntent ( in):: n
p • poi nt (n, 0)
en:I sub"out i ne poi nt_egal _enti er
s ubrouti ne ent i er_e<jal_J>Oi nt (n, p)
i nteger , i ntent (out) :: n
type (point), intent ( i n) : : p
n • p%x
en:I sub"outi ne ent i er _egal_poi nt
end module twe_J>Oint
program essa i
use type_poi nt
i rrpl ic i t none
twe (point) :: a
i nteger : : n• l2
a • n : pr i nt •. a 1 affi che 12 0
a • poi nt (5. 2) : n • a : pri nt • , n 1 affi che 5
en:I progr;,wn essa i
Remarque:
Bien entendu, un minimum d'organisation est alors nécessaire lorsque ron doit gérer ainsi
un grand nombre de procédures; notamment, il faut choisir comenablement le contenu
des différents modules en s'assurant qu'aucun module ne sera amené à s'appeler lui-même
(même indirectement).
3. Ellessontdûritesdansl'anne.xeH.
276 XI. Les modules et la généricité
de l'édition de liens alors que. dans l'autre cas, cette incorporation découle généraJement de
l'appel du module).
Le terme type abstrait possède plu.<iieurs significations. Ici, il s'agira de c réer w1 type
oompo11ant ses propres "opérateurs". Nous en avo1l.'i d'ailleurs rencontré un exemple
(simplist e) dans le type /JO;n1 du par agraphe 3.
D'une manière générale, en Fortran 90, on réali~ r a w1 tel type à l'aide d'une sttucture. On le
dotera d'opérateurs appropriés en utilisant les possibilités de surdéfinition d'opérateurs telles
que nous les avons étudiées précédemment.
Les deux déclar ations sont équivalentes. Notez que pr;vau.> doit obligatoirement être placé
avant la déclar ation du premier c hamp de la structure (si sequenœ appar ait égak-ment, il peut
se situer indifféremment avant ou après pr;va1e).
JI n 'est possible d' aœéder au.x c hamps x et y d' w1e. var iable de type /JO;n1 que dans I' w1ité de
compilation (donc dans notre cas le module) qui contient la déclaration du type po;n1. En
revanche, dans toute unité de compilation utilisant ce module, on pow·ra ce11es déclar er des
variables de typ e /JOin1 (puisque ce type est bien public). 1nais on ne pomTa pas accéder
directement aux c hamps x et y .
4. Ceci n·n d ïntérêt qu·nu sein d·un module puisque priw1te nïntentit pa..; r ncc6> nux champs de Io structure,
depuis !"unité Œ programme dans laquelle Io structure est déclarée.
XI. Les modules et la généricité 277
Le type abstrait est tout indiqué pour ce genre de choses. Une structure comportant deux
champs entiers permettra de représenter un rationnel. On surdéfinira les opératew·s indiqués
pow· qu'ils aient w1e. signification lors.qu'ils sont appliqués à deux rationnels. voire à un
rationnel et w1 entier.
Par souci de brièveté, nous vous fournirons ici un exem ple partiel d'un module pennettant de
mettre en œuvre ce t)'p e abs trait. Nous nous sommes lim ité à l'opération d'addi tion~ il
faud rait donc le compléter avec les autres opérations. ainsi qu'avec les comparaisons. en
prévoyant, à chaque fois que l'un des opérandes puisse également être de type entier. En toute
riguew·. il faud rait également prévoir de surdéfinir l'opérateur "unaire" - lorsqu'il porte s w·
w1 rationnel (il fou rnit l'opposé).
module rationnels
type rationnel
inte9êr nun, den
end type rationnel
interface operator •t)
module procedure rat_plus_rat, rat_plus_ent, ent_plus_rat
end interface
conc:1 lns
funct Ion rat.J>lus_rat (ri. r2)
tYl>t (ratlome 1), intent ( in) : : ri, r2
tYl>t (ratlon...,l ) :: rat_plus_rat, res
res • ratlomel ( rltm.a • r2tden • rl~en * r2""-. rl~en • r2'den)
ca ll s l1111lifie (res)
rat_plus_rat • res
end functlon ratylus_rat
progra• test_ratlomels
use rat 1onne 1s
twe (rat ionnel) :: fi• rat ion"'l (3, 5), f2 •rationnel (2, 7), f
call affiche (fi) ; call affi che (f 2)
f • fi + 12 ; call aff i dle ( f )
XI. us modules et la généricité 279
Exemple (p a11iel) d'utilisation d' w1 module pour créer un "type abstrait". ici le type
rationnel
Notez bien que Je détail de la structurera1ionnel n 'a pas été rendu privé ici car il n 'aurait pas
été possible de "construire" un rationnel en fo urnissant les deux valew·s entières
001Tespondantes (c'est ce qui se passe dans l'initialisation de// et f2)!>. Il serait donc possible,
par exemple, au sein du programme principal, d'accéder au.x champs// r df.um.
Si la procédure simplifie n 'était utili~e que par une seule procédure, on powTait en fai re une
procédure interne à cette procédure (il ne serait p lu.~ nécessaire de la déclarer privée pui<i.que
alors elle serait inaccessible à l'ext érieur du m odule).
Ren1arque:
Lorsque nous étudieroll.~ les possibilités orientées objet de Fortran 2003, nous ve1Tons que
la notion d'objet (implémentée par w1e. généralisation du type st ructure) est beaucoup plus
générale que celle de typ e absb·ait présentée ici. Notamment, les objets disposeront, non
seulement d'opérateurs, ma i~ égalem ent de méthodes (procédures). La gest ion de
l'encapsulation sera p lu.~ fi ne. De plus, on disposera de l'héritage et du polyinorphisme.
Par aillew·s. nous verrons que le terme type abstrait correspondra à un autre concept que
celui que nous avons exam iné.
5. A partir de fortran 2003, cc «constructeur » ne sera plus utilisable d irecte-ment. Nous \'Cn'ons comment
procécr dans l'annexe H consacrée il la « programmation o rientée obj et ».
XII. LES FICHIERS
J usqu'ici, nous avons appris à travailler avec les 'entréeHorties standards" qui
correspondent à ce que l'on nomme souvent les 'périphériques de communication' (ils
vous servent à échanger de l'information avec la machine). Mais, bien entendu, Fortran
permet également de stocker et de consulter de l'information sur des 'périphériques de
stockage' (disques, disquettes et, plus rarement, bandes), par l'intermédiaire de ce que l'on
nomme des fichiers.
1 - GENERALITES
Avant de voir précisément comment utiliser des fichiers en Fortran, il est bœ d'introduire
un certain nombre de ootiom, à savoir :
- la notion d'enregistremeo~
- ladistinctiooentreaccêsséquentielet acœs di~
- les deux possibilités qui vous soit offertes de stocker l'infa:matioo: sous forme
"formatée" ou sous forme "non formatée".
ailleurs, le mode d'acœs (séquentiel ou direct) est géoéralemeot2, lui auss~ iotriosêque au
fichier, ce qui s~oifie qu'il ne sera pas possible de relire en acœs direct un fichier créé
séqueotiellement .
00000001001011 01
Si Poo écrit o sous forme non formatée; on se coitentera de reproduire telle quclle cette
information qui occupera donc 2 octets {16 bits) dans le fichier. Si, en revanche, on l'écrit
avec le format i5 (donc sous forme formatée), on occupera 5 caractères (soit généralement
5 octets) contenant respecti,emeot les codes des 5 caractères suivants :
espace esçace 3 0 1
Les fichiers non formatées sont parfOis qualifiés de 'binaires"', tandis que les fichiers
formatés sont parfois nommés ' fichiers texte' ou ' fichiers de type lexie' ou encore, par
abus de langage ' fichiers ASCII' (on cite alors dans ce cas le code utilisé pour y
représenter les caractères).
Dès lors qu'elles portent sur des informations numlriques, les entrées-sorties non
formatées sont beaucoup plus rapides que les entrées-sorties formatées : les premières
n'impliquent qu'un échange brut d'informations, tandis que les secondes nécessitent des
opérations de codage. Dans le cas d'informations de type chaîne, la différence de vitesse
est peu sensible.
Un fichier non formaté contenant des informations numériques, créé sur une machine d'un
type donné, n'est pas accessible à une machine d'un autre type, dans la mesure oü le
codage de l'infôrmation numérique (en mémoire) est généraleirent différent5. En
revanche, un fichier formaté créé sur une machine donnée pou.rra être relu sur n'importe
quelle machine qui utilise le mêire code pour représenter les caractères (actuelleirent, le
code ASOI tend à s' imposer).
Par ailleurs, un fichier formaté peut facileirent être "consulté" à l'aide de certains
"prograrnires utilitaires" : éditeurs, traiteirent de te~e ... Il n'en va bien entendu pas de
mêire pour les fichiers non formatés (mêire lorsqu' on pou.rra les consuker, leur contenu
n'apparaitra plus "en clair", excepté pour les variables de type charocter).
On notera que les entrées-sorties standards sont toujours formatées. Aux conversions dont
nous avons parlé s'ajotte une opération telle que :
Comme dans la plupart des langages, un fichier se manipule en Fortran, non pas
directement par son nom (tel qu'il est conllll du systèire), mais par ce que l'on nomire un
numéro d'unité (ou numéro d'unité logique). Plus préciséirent, on établit tout d'abord une
connexion entre un numéro (de son choix) et un nom de fichier; par la suite, on se
S. Ce qui n'exclut pos totalement du possîbîUtés: d'échange d'informations non formatées dans certains cns
po rticuHers: par ocemple, échange de noni>rcsentiertentredeux macbincsdiffércn tucodant toutes lu deuw: lu
nombresentierSsur 32 bitssuhoant la ttêbnique du oomplément i deux. Bnoore faudra.-t-H~trt en mesure de
prendre en oompte la manière dœt lu deux environnements coooernés: gèrent le découpage du fich ier en
enregistrements.
6. Lorsque l'on travaîJJe en mode "diO'ére, c'est-à-dire lorsque lu dOnnéct oot été préalablement enregistrées:
dans un fichier ou que les rûuluitssont st()(:kÛ temp0r.1frement dan,ç un fiéhier, il n'existe phaG aucune distinétion
entre entrée-soniestandard e t entrée.01tie forma tée dans un '"vrai" fich.ier.
xn. Les fichiers 285
Comme nous l'avons dit, l'utilisation des fichiers passe par l'utilisation de nou-elles
instructions d'entrées-sorties. Nous -errom que ce sont les mêmes instructions qui
permettent à la fois de gérer l'accès séquentiel et l'accès direct et de travailler sous forme
formatée ou non formatée ; simplement, e lles seront assorties de 'paramètres' différents
dans chaque cas.
Pour conserver une certaine progressivité à notre CJ<posé, nous commençom dans ce
paragraphe par introduire ces instructions dans le cas d'entrées-sorties séquentielles
formatées. Les paragraphes suivants CJ<amineront les autres possibilités e t ce n'est
qu'ensuite que nous vous fournirons un récapitulatif complet de la syntaxe de ces
instructions.
Voici un programme qui crée un fichier séquentiel non formaté dans lequel chaque
enregistrement contient :
286 xn. Les fichiers
progra11 cr_fich_seq_oon_for11
iq>l icit oone
integer. paraœter . . rurf ich• l
character (len-12) .. noorfich
character ( len-20) .. OOOI, prenOOI
integer : : annee
print •, ·-- rai du f ichier a creer•
read •, ne.if ich
open (unit-nlm!fich, fi le•l'Dlfich, forms'unformatted', status•'new')
print •, 1 0011, prenœi, annee naissance (nœi v ide poor finir) '
do
read •, rai, prenœi, annee
if (rom - ")exit
write (nlmlfich) nœi, prel'DI, annee
end do
print •, ' - - fin creation fichier'
close (lllOlfich)
end
No~ avons suppœé ici que notre programme s'exécutait de façon "conversationneUe", les
informations nécessaires étant lues au cla~er.
XII. Les fichiers 1131
Nous avons déclaré une chaîne de 12 caractères nommée nornjid1 destinée à contenir le
nom du fichier à ccéer ; ce dernier (ici repert) est fourni par futilisateur7.
L'instruction:
est ce que l'on nomme une iostructico d" ouverture' de fichier. Elle sert nttamment à
établir une connexion entre un numéro d'unité et un nom de fichier. Ici, clle comporte 4
paramètres repérés par un mot clé (comme les arguments de procédures).
Le second de ces piramè tres file=nomficli précise le nom du fichier concerné. NotC2. que
nous aurions pu indiquer directement le nom du fichier en écrivant par exemple file =
"reperl" mais ceci aurait moins souple puisque notre prcgramme aurait été condamné à
ccéer toujours le même fichier8.
Le premier piramètreunir = numfich (ce qui revient en fuit àunil = l , comp1e tenu de la
déclaration de numfich en constante symbolique -parameter) précise le numéro d'unité (ici
1) que l'on a choisi d'utiliser pour repérer le fichier en question.
Le troisième paramètre f0tm = 'unformaaed' précise que le fichier en question sera non
formaté.
Enfin, le quatrième paramètre status = 'new' précise que le fichier en question est
"nouveau". Autrement dit, cette iostructico va ccéer un fichier de ce nom (pour l'instant
vide). NotC2.qu'aucuo fichier de ce nom ne doit exister: si tel était le cas, il s'agirait d'une
erreur, laquelle conduirait, ici, à un arrêt de fexécution (nous 'errons qu'il est toutefois
possible d'éviter cela en gérant soi-même la situation d'erreur, à faide de l'un des
paramè tres wstal ou e" de riostruction open).
Le remplissage du fichier est réalisé ici par la répétition de l'instruction (notez le nouveau
mot clé write et non print):
Nous aurions pu écrire également (ce qui aurait été plus homcgène avec fiostruction
d'ouverture)?:
1. Gtnéralement, vous p0unez fournir, nm seulement un nom de fit.hier mais, également, une extension et un
''chemin•, sous une fonne dépendant toutefois de J'envirœnement.
8. Bn mOde différé, en revanéhe, le problème serait moins crucial dans la mesure où l'on p0umût ne pas ptéwir
d'instructiœ open en taisant établir la oonnexi0n voulue, pdalablement à fC);Ûutiœ, à 11.ude de commandes
appropriées de l'envirœnement.
9. La syntaxe oomplttc d'open est fournie dans Je p.ragr.i.phe 8 e teelle de write dans le paragraphe 7.
288 xn. Les fichiers
Enfin, l'instruction:
c lose (rulllfich)
Rm>arques:
10. Tou tefoi~ mem.e a\U une in.struction élOSC. le ri:que exSte devoir Je prcgr.unme se •planter• avant que cette
derniCre ne soit C)Ûu\Û.
xn. Les fichiers 289
3) Notre programme peut poser un problème lors de sa mise au point. En effet, dès lors
que le fichier concerné a été créé, même s'il ne contient aucune information, il n'est
plus possible d'exécu ter à nouveau le programme tel quel puisqu'il va alors chercher à
créer à nouveau le même fichier (du moins si Putilisateur fournit le même nom de
fichier que la fois précédente) ; dans ces conditions, une erreur se produira lors de
fexécution de Pinstruction open. Nous verrons plus loin qu'il existe plusieurs remèdes à
oette situation :
- utiliser une autre valeur du paramètre status dans l'instruction open,
• prévoir de gérer soi-même les "erreurs d'ouverture", en utilisant un paramètre
supplémentaire (iostat ou err) dans l'instruction open,
• faire appel à l'instruction inquire pour savoir si le fichier concerné existe déjà et.
dans oc.cas. l'ouvrir comme un fichier existant et non plus comme un fichier à créer.
Là encore, nous supposons que nous avons affaire à une exécution conversationnelle. Le
nom de fichier, fourni par futilisateur, est conservé dans la variable nomfich.
L'instruction d'ouverture de fichier est voisine de celle du programme de création :
open (unit•JU1fich. fi 1e-oollfich. forma'unfor11atted 1 • status •'old')
Seule la valeur du paramètre stalus est différente. Ici o/d signifie que le fiehier doit déjà
exister. Si tel n'était pas le cas, nous obtiendrions un message d'erreur assorti d'un arrêt de
fexécution. Là encore, nous verrons qu'il est possible d'éviter eela en gérant soi-même la
situation d'erreur {à l'aide de l'un des pararnètresiostal ou etr de l'instruction open).
La lecture de chacun des enregistrements du fichier se fait par finstruction :
read (unit•rullfich. efKl•999) nœi. prenœi. anœe
Comme l'instruction d'écriture, elle précise le numéro d'unité associé au fichier (nous
aurions pu aussi omettre le mot clé unit et écrireread (numfich, end = 999)...) et la liste des
variables concernées. Toutefois, une nouveauté apparat"! dans le paramètre:
erd • 999
Sa présence se justifie par le fait que nous avons supposé que nous ne connaissions pas le
nombre d'enregistrements du fichier (c'est généralement la démarche la plus raisonnable).
Dans ces conditions, il faut ce!Ur de traiter les enregistrements du fichier lorsque la fin de
fichier a été atteinte.
Plus précisément, notre instruction read telle qu'elle est ici écrite, examine si la fin du
fichier a été ou non atteinte. Si ce n'est pas le cas, elle lit (normalement) un enregistrement
et place les informations correspondantes dans les variables indiquées par la liste. En
XII. Les fichiers 291
Nous verrons qu'il existe une autre manière de gérer la fin de fichier, en faisant appel à un
paramètre supplémentaire (iostat) dans finstruction de lecture ; moins portable que
remploi du paramètre end, elle présentera toutefois ravantage de ne plus faire appel à une
étiquette et, partant, de permettre d'écrire des programmes mieux structurés.
Remarques:
2) Ici, nous a~ns crée ce que l'on nomme parfois un "fichier homogène", c'est-à-<lire un
fichier dans lequel tous les enregistrements ont la même taille (ici, ils sont de plus créés
par la même instruction d'écriture). Mais il ne s'agit pas la d'une obligation même si,
comme nous le verrons dans le paragraphe suivant, cela facilite rexploitation du fichier
correspondant. A titre indicatif, voici deux circonstances dans lesquelles on peut être
amené à créer un "fichier hétérogène" :
- un premier enregistrement nommé •en-tête• fournit des informations relati.es à
fensernble du fichier lui-même; dans ce cas, le fichier pri\'é de son en-tête est un
fichier homogène,
· chaque enregistrement contient un nombre variable de valeurs, ce nombre figurant
comme première information de fenregistrement. Cela signifie que chaque
enregistrement pourra être écrit par une instruction de la forme :
wr ite (n...tich) n, ( t( i). i• 1, n )
Ce que nous venons de "'ir à propos des entrées-sorties séquentielles non formatées se
généralise assez facilement aux entrées-sorties séquentielles avec format : en gros, il suffit
d'ajouter un format aux instructions d'écriture et de lecture. Mais, de surcroit, il est
possible dans ce cas d'éviter le changement systématique d'enregistrement à chaque
exécution d'une nouvelle instruction d'entrée-sortie.
program cr_fich_seq_fon11
i..,Hcit oone
inte~r. parameter : : ru11fich• l
character ( len• l2) :: 0011fl ch
character ( len-20) : : OOll, preoo•
integer : : amee
print *, · - - oom du fichier a c.reer•
read •, nmfich
open (unit •ru11fich, fil e •oolllfich, to nna ' f ormatted' . status • ' new')
print •, 'oom, prenm, annee naissance (nœ vide pour finir)'
do
read * , rem, prenan, annee
if (nœ •• ' ') exit
write (ll.lllfi ch, ' (2a20.i4) ' ) oom. prellOOI, amee
end do
Xll. Les fichiers 293
Comme on peut s'en douter, il serait facile d'adapter de façon semblable le programme de
lecture du paragraphe 2.2 pour qu'il puisse lire un tel fichier; il suffirait de remplacer
l'instruction open par:
Remarques:
1) Comme dans les entrées-sorties standards que nous connaissons, le format figurant
dans une instruction d'entrée-sortie séquentielle formatée peut être fourni
indifféremment sous rune des formes suivantes:
- chaîne constante de caractères (c'était le cas ici),
- nom d'une variable de type dl(JTOCler contenant un format (dans ce cas, ne pas
oublier les parenthèses),
- étiquette d'une instruction fom1111 (nous en avons parlé dans le paragraphe 3 du
chapitre consacré aux entrées-sorties standards; rappelons qu'une instruction
format peut être placée n'importe où parmi les instructions exécutables et qu' il s'agit
d'une possibilité considérée comme périmée).
294 XJI. Les fichiers
2) Avec des fichiers non formatés, il suffit de connaître le type des informations figurant
dans un enregistrement. A'ec des fichiers formatés, il faut, en plus, connaître le format
avec lequel elles ont été écrites.
3) Tout ce qui a été dit pour les entrées-sorties s'applique ici, à condition simplement
de remplacer le terme de' ligne' par celui d'enregistrement. Notamment :
• Le descripteur / permet de changer d'enregistrement ; en lecture, on peut ainsi
ignorer la fin d'un enregistrement, voire sauter un ou plusieurs enregistrements,
moyennant l'emploi de plusieurs descripteurs/.
• Il est tout à fait possible d'utiliser un format libre; en pratique, on le fait
rarement, notamment en écriture, dans la mesure oil la taille des emegistrements
dépend alors des valeurs des informations qu'on y introduit (par exemple, un entier
n écrit en format libre occupera 3 caractères s'il contient la valeur 25 mais il en
occupera 6 s'il contient la valeur -1234 (dans les deux cas, on a un espace qui
précède la valeur).
4) Contrairement à ce qui se passe avec les lectures non formatées, le cas oil un
enregistrement ne contient pas suffisamment d'informations pour satisfaire la liste ne
conduit plus à une erreur d'exécution ; tout se passe, en effet, dans ce cas, comme si des
espaces supplémentaires avaient été ajoutés à l'enregistrement en question. Ce
comportement n'est pas toujours acceptable; nous verrons qu'on peut le modifier en
agissant sur le paramètre pad lors de l'ouverture du fichier et retrouver le
comportement des entrées non formatées (notamment possibilité de gestion de cette
situation à faide de l'un des paramètres iostat ou err).
5) Les remarques faites à propos des erreurs d'ouverture restent valables ici.
6) Qu'il s'agisse d'entrées-sorties formatées ou non, nous avons présenté d'une part un
programme de création de fichier, d'autre part un programme de lecture de ce même
fichier. A priori, rien ne \'OUS interdit théoriquement de mélanger au sein d'un même
programme des opérations de lecture et d'écriture et, partant, réaliser une certaine
mise à jour d'un fichier. Toutefois, on notera alors que:
- la modification d'un enregistrement existant présente le risque d'écrire un nouvel
enregistrement de taille différente de fancien ; ce risque est particulièrement
évident dans le cas de fichier hétérogène. De plus, cette opération peut s'avérer
dangereuse, voire impossible, dans le cas de fichiers sur bande magnétique.
- on ne peut jamais supprimer un enregistrement; tout au plus peut-On en modifier
le contenu (avec les risques évoqués précédemment).
Xll. Les fichiers 295
Dans la pratiqœ, on lim~e les possibilités de mise à jour d'un fichier séquentiel à
l'extension, c'est-à-dire à fintroduction de nouveaux enregistrements en fin de fichier
(on utilise dans ce cas le para~re position = 'append' de l'instruction open). Si fon
do~ absolument réaliser une mise à jour générale, on procMe par lecture de l'ancien
fichier et création d'un nouveau fichier. D'une manière générale, l'accès direct s'avère
bien mieux adapté et beaucoup plus rapide, dès lors que ces mises à jour sont
fréquentes.
Lorsque l'on emploie pour les entrées-sorties standards la forme simplifiée que nous avons
utilisée jusqu'ici, ce numéro n'appanu"t pas explicitement. Mais la nouvelle syntaxe des
instructions d'entrées-sorties destinées aux fichiers que nous avons commencé à étudier
dans ce chapitre peut s'appliquer aux entrées-sorties standards.
De même, s i la sortie standard porte le numéro 6, ces instructions sont équivalentes (on
suppose que out contient 6) :
a) Le principe
advance = 'no*
Dans ce cas:
- en lecture: à la fin de l'instruction, le pointeur de tampon reste positionné sur le
premier caractère non encore utilisé; l'information correspondante sera exploitée lors
d"une prochaine lecture concernant le même fichier;
- en écriture: contrairement à ce qui passe d"habitude, l'enregistrement n"est pas
encore considéré comme terminé; il viendra s'y ajouter féventuelle information écrite
par une prochaine instruction d'écriture concernant le même fichier.
On notera bien que l'effet de ce paramètre ne concerne que l'instruction dans laquelle il
figure. Il est tout à fait possible de l'emplo}er par e>emple pour certaines lectures et pas
pour d'autres.
Voici, tout d'abord, deux exemples d~école' (le paragraphe ci-après fournit un e>emple
plus réaliste). Avec:
123456789
123
b) Exemple d'applcation
11. C"est toujourslecas pour un 6cbier s.iquentie.I tormat6, maison ne l'expk>itc pas toujours comme une suite de
cantct!res.
298 xn. Les fichiers
do
read (nUlllfich, '(a l)'. advanœ•' oo'. eor•888, end•99'}) c
write (*, '(a l)', advance• 'oo ' ) c
cycle
888 wr ite (•. *) ! pour forcer le changement de ligne
cyc le
99'} exit
end do
write (*, ' (// "-·fin fi chier")' )
end
Avec:
write ( •, ' (• rmi d.J fichier texte a lister:•)•, advance •'no ')
il n'y aura pas de changement de ligne aprês l'affichage de la question, de sorte que le nom
de fichier fOurni par Putilisateur apparai"tra bien à la suite. Dans :
on lit un seul caractère (c), sans changer d'enregistrement Le paramètre eor=888 (eor est
fabréviation de "end of record") permet un branchement à fétiquette 888 lorsque la
lecture n'a pas pu être satisfaite dans l'enregistrement courant
Notez que nous affichons chaque caractère en évitant de changer de ligne. Ce n'est que
lorsqu'une fin d'enregistrement a été détectée que nous changeons de li.gne (par une
instruction n'éaivant rien!).
Remarques:
1) li n'est pas possible d'utiliser le format libre (•) dans une instruction d'entrée-sortie
dans laquelle on a spécifié advance ='no'.
2) Rappelons que l'emploi de ia.UJI offrira une oolution plus structuiée que rusage de
end eteor.
3) Le cas où un enregistrement ne coŒ.ient pas suffisamment d'information est traité de
la même façon que le paramètre advance soit présent ou non (revoyez é-entuellement
la remarque 4 du paragraphe 3.1). La seule nouveauté (avec advancd='ho' est qu'on
peut "tester" la fin d'enregistrement avec eor (ou iostat).
XII. Les fichiers 299
4-L'ACCES DIRECT
Nous venons de voir comment créer et exploiter un fichier séquentiel sous forme formatée
ou non formatée. Des possibilités comparables existent pour les fichiers en accès direct.
Elles impœent toutefois une contrainte importante, à savoir que tous leurs
enregistrements doivent être de même taille (c'est ce qui permet au "s)'Slème• de localiser
un enregistrement de numéro donné).
L'instruction d'ouverture:
q>en (unit• ruif ich. f i le•raif ich, acœss• 'direct ' . recl• 1ge, &
fo1"W1• 1 unfoniatted', status• 'new')
- le paramèlre access = 'direct' qui sert à préciser qu'il s' agit d'un fichier à accès direc~
- le paramèlre red=lge (ce qui correspond ici à red=44); il précise la 'taille' de
chacun des enregistrements. Notez que :
• cette information est nécessaire puisqu'elle sert au système à déterminer
l'emplacement (dans le fichier) où il devra écrire un enregistrement,
• elle s'exprime soit en nombre de caratères dans le cas des fichiers formatés, soit
dans une unité qui dépend de renvironnement dans le cas des fichiers non
formatés: dans noire cas, cette unité était l'octet (un enregislrement nécessitant ici
20 octets pour le nom, 20 pour le prénom et 4 pour l'année de naissance). Nous
verrons tottefois qu'il existe une manière portable de définir cette taille en faisant
appel à une forrne particulière de l'instruction inquire (ici: inquire (icle~h = lge)
nom, prencm, annee).
Notez que si nous avions défini une taille d'enregistrement trop grande, les
conséquences se seraient limitées à un fichier occupant plus de place que nécessaire.
En revanche, avec une taille trop petite, l'instruction d'écriture dans le fichier aurait
conduit à une erreur (qu'on peut gérer avec err ou iostal~
En ce qui concerne l'écriture dans le fichier, elle est réalisée par Pinstruction:
Remarques:
1) Dans la pratique, il est rare que ron se contente d'un tel programme pour créer un
fichier à accès direct En effet, rien ne nous assure que l'utilisateur fournira
effectivement (dans un ordre quelconque) tous les enregistrements du fichier. Que fait
alors le système pour les enregistrements n'ayant pas été écrits? Certains systèmes, dès
que "'us écrivez le énième enregistrement d'un fichier, réservent automatiquement (si
ce n'est pas déjà fait) les emplacements pour tous les enregislrements précédents, avec
un contenu aléatoire. D'aitres peuveit se contenter de n'en réserver qu'une partie.
xn. Les fichiers 301
Dans tous les cas, une incertitude existe; elle est d'autant plus gênante qu'à la
rtlecturt, rien ne vous permettra de distinguer les enregistrements rttllement krlts de
œux ayalà une valeur al&tolrt. Dans ces conditions, il faudra prévoir que le
programme soit en mesure de repérer ces "trous' ; plusieurs techniques existent à cet
effet ; citons-en deux :
• avant toute chose, 'initialiser" tous les enregistrements du fichier à une valeur
spéciale, dont on sait qu'elle ne pourra pas apparaître comme valeur effective,
• gérer une 'table' des enregistrements inexistants ; cette table était, de préférence,
conservée dans le fichier lui-même.
Naturellement, aucun problème de cette sorte ne se posera si vous vous contentez de
créer le fichier en écrivant ces enregistrements suivant leur ordre naturel Notez bien
que, dans ce cas, on devra quand même créer un fichier à accès direct (le paramètrerec
prenant al.ors successivement les valeurs 1, 2 ..) si l'on souhaite pouvoir ensuite
l'exploiter comme teJ 12 .
2) li est permis d'écrire des enregistrements de taille inférieure à celle déclarée lors de
l'ouverture du fichier. Simplement, dans ce cas, le reste de l'enregistrement contiendra:
• des informations indéfmies s'il s'agit d'un fichier non formaté,
• des caractères espace s'il s'agit d'un fichier formaté,
En revanche, toute tentative d'écriture d'un enregistrement trop grand conduira à une
erreur d'exécution (qu'on peut gérer avec le paramètre eJT ou iostat).
3) li est tres facile d'adapter ce qui vient d'être dit à un fichier formaté il suffit
d'adapter en conséquence le paramètre frm de l'instruction open et d'ajouter un format
(chaîne constante ou variable ou étiquette) à la suite du numéro d'unité dans
l'instruction 11rire.
peut très bien écrire plusieurs enregistrements consécutifs, à partir de celui de rang
mun . En pratique, cette facilité sera peu utilisée, ne serait-ce que pour son manque de
lisibilité,
read •, 00111
if (0<111. .0) exit
read (unit •rumf ich, rec8fu.m) nœi, prenc.i, amee
print '(lx,2a20, i4} ' , OO!I, preOO!I, annee
end do
print • , ' ··fin traitement'
end
Remarques:
D'une manière générale, Fortran 90 vous offre deux possib~és (redondantes) de gérer les
erreur, à saYOir:
- le paramètre icstat,
- les paramètres err, eor et end.
Nous avons d'ailleurs déjà parlé partiellement des secondes.
304 XJI. Les fichiers
do
read (oollfich, ... . . , iostat• err) . ...
if (err •• fin_fich) exit
1 traitement d'un enregistrement
end do
Comme nous l'avons déjà vu, ces paramè.tres permettent de préciser une étiquette à
laquelle on se branche lorsque l'événement correspondant se produit. Leur emploi conduit
à des programmes portables mais moins structurés que ceux obtenus en utilisant ios1a1.
XII. Les fichiers 305
progra.11 list_fich_seq_noo_fol"WI
iq>licit nme
integer. para11eter : ~ nlm!fich-1
integer, paraœter :: fin_fich--1 1 attention deperKI de 1'environne11e11t
character ( leno12) : : n001fich
character ( leno20) n 0001. pren001
integer : : amee. eTT
306 XJI. Les fichiers
do
print • • l"OI d.J fichier a lister"
read *. raifich
open (unit• rullfich. file-nœifich. form- 1 oofoniatted', &
status • 'old'. iostat• eTT)
if (err - 0) e><it
print •. • ...... fi chier oon trouve•
end do
Liste d'un fichier séquentiel non formaté avec prise en compte des erreurs
Remarque:
do
print • . rai dJ fichier a consul ter•
read • , oollf i ch
q>en (unit-nlSlfich, file-nœifich, access •'direct', rec l•1ge, &
for1P 1 unfo1"W1atted 1 , status• 'o ld', io.stataerr)
if (err .. 0) exit
print • , 1 - - fichier non troove'
end do
do
write ( • , • ('nlSlero de l' 'enregistrement cherche (0 poor finir)')-, &
advan::e•' 00 1 )
read • , ru11
if c-~o) exit
read (lllit•m.•fich, rec•n.si, iostat•etT) nœi, preJDI, annee
if (err •• O) then
print ' (lx,2a20, i4)', !'Dl, preoo11, amee
e l se
print • , ' - -erreur nllflero ' , err
efKI if
end do
print • • fin traitement'
end
Consultation d'un fichier non fonnat~ en accès direct avec prise en compte des erreurs
308 Xll. Les fichiers
Lorsqu'un programme lit une information au clavier et que l'utilisateur fournit une réponse
incorrecte, le programme s'interrompl de façon généralement peu satisfaisante. Avec la
nouvelle syntaxe de fiostruction de lecture, appliquée à la lecture au clavier, il est possible
de détecter l'anomalie et de demander à rutilisateur de foomir une autre réponse. Voici
une adap1ation dans ce sens du programme de cak:ul de racines carrées présenté dans le
chapitre 1.
progra11 racines_carrees
iq>licit oone
integer err
rea l valeur. racine
tl. Ne pus cœfondre ce ta.mpœ comenan1 un selA enregistrement avec le ta.m.pœ (dont nous avœs par16 à
propœ de l'instruction dose) qui sert aux &:hanp avec le 6dlier ; oc dernier oontien1 g6n6ralemen1 plusieurs
enregistrements. Bn tOlAe rigueur, d'ail eurs, le tampOn d'enregistrement n'est souvem rien d'autre qu'une partie
du tampOn de fidlier.
14, En tolAc rigueur ,iJ S'agit d'un &ba.ngeemre la.mpâl d'enregistremem et ta.mpœ de fichier (dans certains cas,
cet &:hange peUI se réduire à.. rien -voyez la remarque pr6:6dente) ; le tampâl de fit.hier ~a.nt reoopi6 dans k
fie:hier ou aliment6i partir du tichierque lorsque oelaest n6cessaire.
310 xn. Les fichiers
6 .2 Exemples
Par exemple, avec :
on va prélever les 3 premiers caractères de texte (ici U3) et les convertir en un nombre
entier qu'on rangera dans n (qui prendra donc ici la valeur 123). De même, on va utiliser
les 6 caractères suivants (456789) et les oonvertir en un réel qu'on rangera dans x (qui
prendra donc ici la valeur approchée 4567.89).
De même, avec :
wr ite (tab. 1
( •quantite : •. i3. • valeur f8.3)') n, X
li est possible d'utiliser une zone mémoire qui soit un tableau de chaînes ; dans ce cas,
chaque élément du tableau est considéré comme un •enregistrement" (du fichier interne).
Des descripteurs/ peuvent alors être utilisés pour 'changer d'enregistrement".
xn. Les fichiers 311
Chaque instruction d'entrée-sortie utilise toujours la zone mémoire depuis son début,
même si plusieurs instructions successives concernent la même zone et même si cette zone
est un tableau.
- lorsqu'il est nécessaire de décrire une même information suivant plusieurs formats
différents,
- lorsqu'il est nécessaire de lire une information suivant un format qui ne peut être
défini que lors de l'exécution, en fonction d'informations figurant dans le même
enregistrement (ou la même ligre),
- pour effectuer des conversions numérique - > chaîne ou chaîne - > numérique.
WRITE ( [UNIT • ) runéro_unité, [flll• ) format [,REC• nuonéro) [,IOSTAT • indic) &
[. ERR • êt iquette) &
) liste
Avec:
talméro, nwnéro_uniJé, taille : expressions entières,
indic: nom d'une variable de typeinteger(sans variante).
fomt'1l : chaîne de caractères (constante ou variable sans variantes) ou étiquette d'une
instructionfon'nlll,
liste: telle que défmie dans le chapitre relatif aux entrées-oorties standards_
Remarques :
1)En toute rigueur, le paramètre advance est de la forme advance = chaine où chaine
désigne une chaîne (constante ou variable de type charat:ter sans variante) pouvant
prendre l'une des valeurs 'yes' ou 'no'.
2) Il est possible d'utiliser pour les entrées-sorties séquentielles formatées une forme
particulière qui fournit, à l'aide du paramètre nml (abréviation de 'namelist"), la
"référence" à la liste des variables concernées Pour plus de détails, voyez l'annexe H
qui décrit les instructions désuètes_
De plus, bien que ce soit d'un usage peu fréquen~ Fortran 90 vous autorise à exécuter à
nouveau une instruction open pour un fichier déjà connecté à un numt.ro d'unitt 1S, ceci
dans le seul but de modifier les valeurs de certains paramètres, à savoir :
blank, ddim, pad : si seulement certains d'entre eux sont modifiés, on continuera, pour
les au tres, à utiliser leurs anciennes valeurs,
en et iostat : si certains d'entre eux ne oont pas spécifiés, on considérera qu'on souhaite
revenir au comportement standard (on utilisera les valeurs par défaut et non plus les
anciennes valeurs) .
Notez que, dans ce cas, le nom de fichier ne doil pas être spécifié (on se limite au numéro
d'unité).
Les val~urs soulignées correspondent aux valeurs par défaut Rappelons que ces valeurs
peuvent toujours être fournies sous forme d'une expression de type cliaracter (sans
variante).
L'instruction open
Avec:
15. En toute rigueur, o n peut regretter que Fortran n'ait pas prtvu une instruction difrtrentc dans oc cas (par
exemple, «Open).
XII. Les fichiers 315
Voici la liste et la signification de tous les paramètres qui peuvent intervenir dans ceue
instruction.
iostat : la variable indiquée recevra une valeur positive en cas d'erreur et nulle sinon.
status :
blank (utilisable seulement pour les fichier formatés; dans ce cas, ne concerne que les
lectures de valeurs numériques) :
read; seule la consultation est autorisée ; les instructions write et endfile 16 sont
interdites,
write ; seule l'écriture est autorisée; finstruction read est interdite; dans certains
environnements, l'instruction backspacel1, ainsi que le paramètre position = 'append'
peuvent être interdits,
readwrite : aucune restriction .
delim : (utilisable seu lement pour les fichiers formatés; n'intervient que dans les écritures
de chaînes en format libre (dirigées par li!le) ou avec le paramètre nml, associé à
l'instruction namelis118:
apostrophe ; les chaînes sont délimitées par des apostrophes (une apostrophe
apparaissant dans une chaîre est doublée),
quote ; les chaînes sont délimitées par des guillemets (un guillement apparaissant dans
ure chaîne est doublé),
none : les chaînes sont écrites "telles quelles'.
pad : (utilisable seulement pour les fichiers formatés; n'intervient que dans les lectures);
sert à préciser le comportement voulu en cas d'enregistrement de taille insuffisante par
rapport à la li!le :
yes; l'enregistrement est complété par des espaces en nombre suffisant (attention, œci
ne concerne que le type charocter !landard ; dans le cas des variantes, il y a toujours
remplissage mais le caractère utilisé dépend de l'implémentation),
no; l'enregistrement n'est pas complété; on aboutit alors à une erreur (qui peut être
éventuellement gérée classiquement par icstlJI, err ou, le cas échéant, eor).
L'instruction dose permet, elle-aussi de gérer les éveiruelles erreurs à raide des
paramèlresiostlJI et""· De plus, un pararnètrestat11s permet de préciser ce que deviendra
le fichier après fermeture :
· keep précise qu'on le conserve (c'est le cas le plus fréquent ; cette valeur ne peut
naturellement pas être attribuée à un fichier ouvert avec le statut 'scratch'),
delete précise qu'il ne sera pas conservé; cet te possibilité peut s'avérer utile dans le cas
où le programme ne s'est pas déroulé comme prévu pour éviter de conserver un fichier
sans intérêt.
L fostruction close
9 - L'INSTRUCTION INQUIRE
Comme nous l'avons déjà dit, la connexion d'un fichier peut être établie soit pendant
l'exécution d'un programme (avec l'instruction open). soit avant l'exécution à l'aide de
commandes propres à l'environnement, lesquelles précisent les différentes valeurs des
paramètres nécessaires (formaté ou non, séquentiel ou direct, opérations autorisées...).
Dans ce cas, il peut arriver que le bon déroulement du programme nécessite la
connaissance de certaines de ces valeurs (fixées de façon indépendante des instructions du
programme). L'instruction inquire offre une réponse à ce besoin.
L'instruction inquire peut être appliquée:
- si l'on applique inquire à un nom de fichier Qe para.mètre FILE= sera alors présent,
mais pas UNrT=), elle signifiera: " le fichier en question est connecté à une
(quelconque) unité".
lll)UffiE &
( [ [UMIT• ]r111néro_unitê ) & 1 paralnètre interdit si FILE est présent
[ FILE...,m_fichier) & 1 paranêtre interdit si UNIT est présent
[, IOSTAT• integer] &
[. ERR•êti<Jlette] &
[, EXIST• logical] & 1 vrai si fichier connecté
[. OPEMEO-logical] & l vrai si fichier conœctê et ouvert
[. MUHBER• integer] & 1 runéro de l'unité si connecté, -1 sioon*
[. IWEO-logical] & vrai si fichier connecté et s'il a un oom**
[, IWE•character) & no11 du fichier si cc:.nnecté, indéfini sioon
[. ACŒSS-character) & 'seqJential'/'direct' si fichier connecté
'undefined' si fichier non connecté
[. OffiECT•character] & 'yes'/'no' si fichier connecté
ou 'unkoown' si fichier ncn connecté
[. FC!lll-character) & 'for111atted'/'1.11fonnatted' si fich connecté
'undefined' si fichier non ccrmecté
[. REQ.• integer) & si fich connecté : taille*- enreg si aa:ês
direct, taille l la.X•- si accês sequentiel
si f ich ncn connecté : i ndêf i ni
[, MEXTREC• integer) & si fich connecté : 1111néro du prochain enregis-
trement à l ire ou écrire : i lllêf in i s inm
[. ll.AllC•character) & 'null'/'zero' si fichier connecté et forlllaté.
'mdefined' sinon
[. POSITIOM•character] & 'rewind'/'a"1end'/'asis' si fich comectê
en séquentiel, 'ulllefined' sinon
[, ACTIOM-character) & 'read'/'write'/'readwrite' si fich comecté
'mdefined' sinon
[. REAo-character) & 'yes'/'no' si fich cmnecté, 'urllefined' sinon
[. WRITE•character] & 'yes'/'no' si fich connecté, 'undefined' sinon
[. REAOOUTE-character] & 'yes' /'no' si fich cmnecté, 'undefined' sinon
[. OELIH- character) & 'apostrq:ihe'/'qoote'/'none' si fichier cmnectê
en formtê : 'urllefined' sinon
[. PAD-character) & 'yes'/'no' si fich cmnectê, 'tnlefined' simn
)
L'instruction inquire
Xll. Les fichiers 319
•Ce pt~trc n'a pas dfotértt dans une interrogatiœ par numéro d'unité.
• • Le fichier peut ne pas avoir de n<m lorsqu'ils'agit <fun fichier temporaire. 0:. ~tre n'a pasd'intérttdans
une intern~gation par nom.
L'unité de mesure est le caractère pour lu fichiers formatés:; eue dépend de fenvironnement pour les
fichiers non formatés.
Remarque:
Il exi!te une troisième forme de finstruction in~ire, dite interrogation par liste. Elle
permet d'obtenir la longueur de l'enregistrement que fournirait (en non formaté) une
liste donnée- En voici un exemple:
inquire ( io length•long) x, ( t( i), i-1,5), p
A priori, un fichier séquentiel est créé ou lu suivant l'ordre naturel de ses enregistrements.
Il est cependant possible d'agir sur ce point en utilisant les in!tructions :
BACKSPAŒ 1111néro_mitê
L'instruction backspace
REWlllJ nllnéro_unitê
L1nstruction rewind
ENIJfllE nllnéro_unitê
L'instruction endfile
ANNEXE A:
LES PROCEDURES INTRINSEQUES DE
FORTRAN 90
- les proa!dures élémentaires : elles !Ont définies à la fois pour des aigumenlS scalaires
(numériques y compris complexes, chaînes) mais elles s'appliquent également à des
tableaux. Dans ce cas, elles fournissent le même résultat que si elles avaient été
appliquées individuellement à chacun des éléments du tableau,
- les fonctions d'interrogation : elles fournissent un résultat qui ne dépend que du type
de leurs arguments, et en aucun cas de leurs valeurs Qes arguments correspondant
pouvant d'ailleurs ne pas être définis),
- les fonctions de transformation : ce sont les fonctions que ne rentrent dans aucune
des deux catégories précédentes,
- les sous-programmes non élémentaires : il s'agit des sous-programmes qui ne rentrent
pas dans la première catégorie-
Tous les arguments de ces procédures peuven~ le cas échéant, être spécifiés par mot clé
(c'est celui que nous précisons systématiquement dans l'en-tête corrrespondant). Par
ailleurs, certaines procédures comportent des arguments optionnels: nous les menlio11Mm
"'italiques gras dorul'en-tlte.
322 Annexe A: les procédures intrinsèques de Fortran 90
Quand target est présent: fournit la valeur vrai lorsque le pointeur pointer est
associé à la cibletaiget. Quand target est a bren~ fournit la valeur vra lorsque
le pointeur pointer est associé à une cible quelconque.
KI ND kind (x)
ABS abs(a)
Fourni~ dans le typereal de variantekind (ou celle dea si kind est ab6ent~ la
•troncature• dea (partie entière E(a) pour a> 0 et -E(-a) pour a <0).
Fourni~ dam le type real de variaite kind (ou celle de a si kind e!t ab6ent~
l'arrondi de a à l'entier le plus proche-
a, c'est-à-dire airt (a)) ou compexe (le résultat est alors égal à la troncature
de la partie entière de a).
Fournit l'entier de variante kind (ou l'entier standard si kind n'est pas
précisé) le plus proche du réel a.
Fournit max (x-y, 0); x et y doivent être tous deux entiers ou tous deux réels.
Fournit la valeur minimale des valeuis reçues en arguments (qui doivent être
toutes de type entier ou toutes de type réel).
Fournit la valeur dea-inl(a/p)•p; a etp doivent être tous deux entieis ou tous
deux réels. Sip est nu~ le résultat dépend de la machine.
Note géné rale : toutes ces fonctions fournissent un résultat ayant le même type et la même
variante que leur premier argument.
AS IN asin (x)
cœ cos (x)
LOG log(x)
Notes g~nirales:
1) le premier argument (x) de toutes œs fonctions est d'un type reel quelconque.
2) Rappelons qu'un nombre réel est representé de façon approchée à l'aide d'une
'mantisse' M et d'un 'exposant" E. Si B est la base de numération utitisée sur la
machine concernée, la quantité:
mBE
represente une valeur approchée du réel en question.
Fournit la valeur (réel de même variante que x) ayant la même mantisse que
x, mais l'exposant i, c'est-à-dire la quantitéx B >E.
Fournit ce que fon appelle l"'epsilon machine' (plus grand nombre e tel que
1 + e soit égal à e) du type correspondant au réel x. Le résultat possêde la
même variante que x.
Fournit la plus petite valeur (entier standard) possible pour un exposant dans
le type (réel) dex.
l . Attention, dies ne sont pus p<>ur autant 6J6mentaires car, dans tous les cas, e lles fournissent un ~ Jt.at
scatain:.
330 Annexe A : les procédures intri~ues de Fortran 90
Fournit la base (entier standard) utilisée pour représenter les valeurs du cype
dex (entier ou réel). En général, il s'agit de 2 ou de 16.
Fournit la plus petite valeur représentable dans le cype dex. Le résubt est
du même type (variante comprise) quex qui peut être entier ou réel
!CHAR lcbar c)
Fournit la valeur vrai si la chaîne string_a apparai't après string_b ou lui est
égale.
332 Annexe A: les procédures intrinsèques de Fortran 90
Fournit la valeur vrai si la chaîne string_a appanu"t avant string_b ou lui est
égale.
Fournil un entier (de type integer standard) valart 0 si tous les caractères de
la chaîne string figurent dans la chaîne set ou la position du premier caractère
de string qui ne figure pas dans set dans le cas contraire- Si back (de type
lcgical) n'est pas ffécisé ou s'il a la valeur faux, l'exploration se fait depuis le
début de la chaîne; si back a la valeur vra~ cette recherche se fait depuis la
fin de la chaîne-
Note gm~rale: dans tous les cas, les bits sont numérotés 'à partir de la droite', c'est-à-dire
plus précisément en partant des bits de poids faibles ; le bit le plus à droite portant le
numéro O.
Fournit rentier obtenu en effectuant une opération 'et' sur chacun des bits
de même rang de i et j (1 et 1 donne 1 et toutes les autres combinaisons
donnent 0). Le résuhat est un entier de même variante que i et j qui doivent
être, tous deux, de même variante.
Fournit rentier obtenu en effectuant une opération 'ou exclusif' sur chacun
des bits de même rang dei et j (1 et 1 donne 0, 1 et 0 ou 0 et 1 donnent 1, 0 et
0 donne 0). Le résultat est un entier de même variante que i et j qui doivent
être, tous deux, de même variante.
336 Annexe A : les procédures intrinreques de Fortran 90
IOR lor(IJ)
Fournit l'entier obtenu en effectuant une opération 'ou inclusif' sur chacun
des bits de même rang de i et j (0 et 0 donne 0, toutes les autres
combinaisons donnent 1). Le résultat est un entier de même variante que i et
j qui doivent être, tous deux, de même variante.
NOT not(I)
Les arguments sont donc des tableaux de rang un ou deux qui doivent être
soit tous deux de type numérique (mais pas nécessairement le même~ soit
tous deux de type logique.
338 Annexe A: les procédures intrinsèques de Fortran 90
Si les deux arguments sont de rang 2, le premier étant de profil (n, p), le
second doit avoir un profil de la forme (p, q) ; le résultat est de rang 2 et de
profil (n, q) et il correspond au produit des deux matrices, c'est-à-<lire qu'un
élément de rangi,j a pour valeur :sum (molrix_a (4 :) * matrix_b (.·, j));
D'autre part, elles peuvent toutes comporter un argument optionnel nommé dim et, de
plus, certaines d'entre elles peuvent recevoir un argument optionnel servant de 'masque'.
Ici, nous décrivons d'abord le rôle de toutes ces fonctions, dans le cas usuel où elles ne
possèdent qu'un seul argument Il sera alors plus facile d'en expliquer le rôle dans les cas
plus généraux.
Annexe A: les procédures intrinsèques de Fortran 90 339
Fournit la valeur vrai si tous les éléments du tableau logique mask ont la
valeur v!lli (ou simask est de taille zéro).
Fournit la plus grande valeur du tableau anay. Le résultat est du même type
que les éléments de01n1y qui peuvent are de type entier ou réel. Si le tableau
arary est de taille nulle, le résu ltat est égal à la valeur la plus petite
représentable dans le type concerné.
Fournit la plus petite valeur du tableau 01n1y. Le résultat est du même type
que les éléments de amzy qui peuvent être de type entier ou réel Si le tableau
arary est de taille nulle, le résultat est égal à la plus grande valeur
représentable dans le type concerné.
Fournit le produit des valeurs des éléments du tableau 01n1y. Le résultat est
du même type que les éléments dearray qui peuvent être de type entier, réel
ou complexe. Si le tableau~roy est de taille nulle, le résultat vaut 1.
Fournit la somme des valeurs des éléments du tableau army. Le résultat est
du même type que les éléments de 11ray qui peuvent être de type entier, réel
ou complexe. Si le tableau 01n1y est de taille nulle, le résultat vaut O.
340 Annexe A : les procédures intrin.sêques de Fortran 90
l'expression sum (lob, dim =2) est un tableau de rang 3, de profil (3, 9, 4) (il
se déduit de celui delab, en supprimant la deuxième étendue); un élément
de rang i, 1 k ayant pour valeur : sum (lob (i, :, j, k)).
Fournit la valeur vrai si le tableau /1TTay (déclaré avec l'attribut al/oc/lie) est
a lloué et la valeur faux dans le cas contraire.
Les arguments tsource et [source peuvent être d'un type quelconque, pourvu
qu'il s'agisse du même (variante comprise). L'argument mask doit être de
type logical. Les trois arguments doivent être soit tous les trois des scalaires,
soit des tableaux de même profil
L'argument aray peut être d'un type quelconque; mask doit être un tableau
de type logica4 de même profil que arroy.
Si vector est absent, cette fonction fourni t un tableau de rang 1 contenant les
é~ments de aray pour lesquels l'é~ment correspondant demask a la valeur
vrai; lorsque aray est de rang supérieur à 1, ses é~ments sont considérés
suivant l'ordre dans lequel ils sont rangés en mémoire (le premier indice
variant donc le plus rapidement) .
Le résultat fournit est un tableau de même profil que mask et de même type
(variante comprise) que vector. Ses éléments sont remplis suivant l'ordre
naturel en considérant l'élément correspondant de mask ; s'il est vrai, il s'agit
d'une valeur provenant de vector (attention, ic~ il n'y a plus de
correspondance d'indice; on se contente de prélever la valeur suivante à
chaque fois qu'on en a besoin) ; s'il e!I faux, il s'agit de la valeur
Annexe A : les procédures intrin.stques de Fortran 90 343
Si pad est présent, il doit s'agir d'un tableau de même type (variante
comprise) que source. Ses valeurs sont utilisées (dans leur ordre naturel) et,
si nécessaire, plusieurs fois, pour compléter le résuhat, si sa taille (définie par
shape) dépasse celle de source.
Si outer est présent, il doit s'agir d'un tableau d'entiers de rang 1, de même
taille que shape ; dans ce cas, les éléments du résultat, pris dans l'ordre
indiqué par les indices figurant dans order sont ceux de source pris dans
l'ordre usuel des indices ; là encore, si pad est présent, ses valeurs seront
utilisées éventuellement plusieurs fois) pour compléter le résultat si sa taille
dépasse celle de source.
Lorsque shift est un scalaire, le résultat fournit par cette fonction est le
tableau obtenu en décalant circulairement shift fois chaque section de rang 1
s'étendant suivant la dimension indiquée par dim (le décalage se fait dans le
sens des indices croissants si shift est positif, dans le sens des indices
décroissants si shift est négatif).
Lorsqueshift est un tableau, il doit être de même profil que array privé de sa
dimension dim ; il fournit les décalages à appliquer à chacune des sections de
rang 1 définies précédemmenL
- soit par celles précisées par boundary qui doit alors être de même type
(variante comprise) que les éléments de 01Tay; s'il s'agit d'un scalaire, sa
valeur est attribuée à toutes les valeurs manquantes ; s'il s'agit d'un tableau, il
doit avoir le même profil que shift (c'est-à-dire cdui de trray privé de sa
dimension dim) et il foumit les valeurs remplaçantes pour chaque décalage,
Si mask n'est pas précisé, on obtient les indices relatifs à la plus grande
valeur de max/oc (si e lle appa.rai"t plusieurs fois, c'est la position du premier,
au sens de l'arrangement en mémoire, qui est fournie).
Si mask est précisé, il doit s'agir d'un tableau de typelogical de même profil
que (JJT(Jy et qui est appliqué comme filtre à la recherche (seuls les éléments
de array pour lesquels l'élément correspondant de mask est vrai sont
considérés).
Si mask n'est pas précisé, on obtient les indices relatifs à la plus petite valeur
de max/oc (si elleapparai"t plusieurs fois, c'est la position du premier, au sens
de l'arrangement en mémoire, qui est fournie).
Si mask est précisé, il doit s'agir d'un tableau de type logical de mtme profil
que aray et qui est appliqué comme fikre à la recherche (seuls les éléments
de (JJT(Jy pour lesquels l'élément correspondant de mask est vrai sont
considérés).
7 • PROCEDURES DIVERSES
E lle fournit un résultat formé du 'motif binaire' contenu dans source mais
ayant le type indiqué par mold (dont la valeur n'intervient pas). Le résultat
est ooit un scalaire (du type de mold) si le paramètre siu est absent et que
mold est scalaire, soit un tableau de rang 1 (de taille siu si ce paramètre est
spécifé ou de la taille de source si size n'est pas spécifié) d'éléments du type
de mold. S'il n'y a pas suffisamment de valeurs dans source pour remptir le
résultat, les valeurs abrentes sont indéterminées ; s'il y en a lrop, en revanche,
seules les premières valeurs de source sont utilisées.
346 Annexe A: les procédures intrinseques de Fortran 90
Fournit dans les différents arguments (de sortie) dont le type est précisé ci-
dessous les valeurs suivantes Qorsqu'elles ne sont pas disponibles, on obtient
un espace pour les arguments de typecharocter et la valeur -huge(O),c'est-à-
dire le plus petit entier ntgatif, pour les arguments de type numérique).
date (characrer) : date sous la forme aaaammij (4 caractères pour fan née, 2
pour le numéro de mois, 2 pour le numéro de jour).
values (tableau de rang 1de8 entiers) : il fournit, sous forme numérique les
différentes informations précédentes; ses éléments correspondent dans
l'ordre à : année, numéro de mois, numéro de jour, différence en minutes
avec le temps universe~ heure, minutes, secondes et millièmes de seconde.
Fournit dans les trois arguments de sortie, de type irteger, les informations
suivantes:
b) Nombres aléatoires
slze (integer de genre out) : taille du tableau d'entiers utilisé comme ' graines'
pour la génération des nombres aléatoires,
put (integer de genre in) : tableau d'entiers de rang 1 (de taille au moins égale
à la valeur fournie dans size) qui correspond aux valeurs qui seront utilisées
comme graines pour la génération des nombres aléatoires,
get (integer de genre oui): tableau d 'e ntiers de rang 1 (de taille égale à la
valeur fournie dans size) qui correspond aux valeurs utilisées pour la
génération des nombres aléatoires.
1 . Généraltés
Les types de base irteger, rea/, logica/, canptex et chilracter possêdent des caractéristiques
(encombrement mémoire, domaine couvert, précision, codage) qui dépendent de la
machine utilisée.
Fortran 90 vous permet d'imposer des caractéristiques précises à un type. Cela se fait en
choisissant ce qu'il nomme un numéro de variante (nombre entier positif) à l'aide d'un
paramètre supplémentaire (kind = ). Cette possibilité présente toutefois quelques
difficultés :
- le numéro correspondant à des caractéristiques données dépend de la machine,
- on ne peut avoir rassurance que des caractéristiques données existent sur une
machine donnée.
Comme ce numéro de variante dépend de la machine, on a souvent besoin de conna.t"tre le
numéro correspondant à des caractéristiques données. Pour cela, il existe deux solutions:
- consulter la documentation Fortran 90 de la machine; si Pon souhaite pouvoir adap1er
son programme à une autre machine, on introduira de préférence le nombre voulu sous
forme d'une constante symbolique (parameter1
350 Annexe B : les variantes des types de base
Comme nous l'avons dit, il sera généralement plus judicieux d'utiliser des constantes
symboliques pour les numéros de variante.
Les constantes de type charaaer font exception à cette regle: le numéro de variante
préctde la constante.
Annexe B: les variantes des types de base 351
selected_lnt_klnd_ (r)
fournit l'entier (standard) correspondant au numéro de variante du type integer susceptible
de représenter les nombres entiers s'étendant de 10"' à 1o+r ; s'il en existe plusieurs, on
obtient celui qui correspond au domaine le moins étendu (s'il y en a encore plusieurs, on
obtient le plus petit numéro de variante); s'il n'en existe aucun, on obtient la valeur -1.
Exemple:
-
grand oomrel • 9876543210 k!O
- 1 coostante a 10 chiffres rarenmt représentab le
J dans le type integer standard
selected_real_klnd ( p, r)
fournit rentier (standard) correspondant au numéro de variante du type reaJ susceptible de
représenter des nombres réels avec une précision (au sens que lui donne la fonction
precisicn) au moins égale àp et une étendue (au sens que lui donne la fonction range) au
moins égale à r. L'un au moins des deux arguments entiers p ou r doit être présent. Si
plusieurs numéros de variantes conviennen~ on obtient celui qui correspond à la précision
la moins grande (s'il y en a encore plusieurs, on obtient le plus petit numéro de variante).
S'il n'en existe aucune, on obtient: -1 si la précision demandée n'est pas disponible, -2 si
l'étendue demandée n'est pas disponible et -3 si ni la précision ni l'étendue ne sont
disponibles.
La nonne impose qu'il existe au moins deux variantes distinctes du type reaJ sur une
machine donnée- Le type double precisicn correspond d'ailleurs toujours à une variante
352 Annexe B : les variantes des types de base
Une variable de type complex n'est rien d'autre qu'un couple de deux réels (voyez
éventuellement l'annexe C). On peut lui attribuer un numéro de variante qui sera alors
interprété comme la variante du typereal utilisé pour chacun de ces deux réels
Dans une constante complexe, en revanche, vous pouvez introduire deux constantes de
variante différente comme dans:
( 3.5_4, 4.55_6)
Comme on peut s'y attendre, une variable de type complex est représentée en mémoire
sous la forme de deux nombres de typereal, avec les limitations inMrentes à ce type.
2. Entrées-sorties de complexes
Dans une écriture en format libre, un complexe apparaît sous la Conne de deux nombres
réels ~parés par une virgule et placés entre parenthèses (comme une constante complexe
à l'inttrieur d 'un programme). Lorsqu'on utilise un format, un complexe utilise deux
descripteurs d'tdition, tventuellement non identiques (chacun correspondant à un réel);
ces deux descripteurs peuvent être ~parés par un descripteur passif (c'est ce qui permet
d'tcrire un complexe sous la forme a + ib dans l'exemple du paragraphe 8).
La leeture d 'un complexe en format libre ntcessite une prtsentation analogue à celle des
constantes dans un programme- Lorsqu'on utilise un format, un complexe utilise deux
descripteurs d 'tdition, tventuellement non identiques (chacun correspondant à un réel) ;
là encore, ils peuvent être stparés par un descripteur passif.
3. Les opérateurs
Les cinq optrateurs arithmttiques usuels (- unaire, +, -, •,/binaires sort utilisables.
L'optrateur " est tgalement utilisable. Dans ce cas, Zl .,z.2 fou mit la 'valeur principale'
de ziû, c 'e st-à-dire:
exp (z2 Qog 1Zl1 + i aig zl)) (avec -pi < argzl < = pi)
Parmi les optrateurs de comparaison, seuls = = et / = permettent de comparer deux
valeurs complexes.
Lorsqu'on affecte une valeur de type complex à une variable de type rtel, on en obtient
simplement la partie réelle- Lorsqu'on affecte une valeur de type complex à une variable de
typeinte&"T, on obtient le résultat de la conversion en entier de sa partie rtelle.
Annexe C : le type complex 355
8. Exemple récapnulatif
Voici un exemple de programme illustrant les possibilités les plus classiques offertes par
Fortran 90.
program ex~les_cœiplexes
iq>licit oone
C001plex :: zl • (1, 2), z2 • (1.5, 5.25). z
rea l :: r. x, y
integer : : n
end
zl • (1.0000000, 2 .0000000)
zl + z2 • ( 2 .5000000, 7 .2500000)
zl • z2 • ( -9 .0000000, 8 .2500000)
zl " 3 • ( ·11 .0000000, -2.0000000)
zl " z2 • ( 9 .2169866E-03, -3.8717822E -03)
donnez un nœibre cœip lexe
(2 .5, 3 . 75)
part ie re lie : 2.5000000 part ie illilg ina ire 3 .7500000
Z • 2.503. 75
z • 2.50 + 3.750i
valeur der : 2.5000000
va leur de n : 2
domez deux valeurs ree lles
7 .5 9
0011> lexe correspondant : ( 7. 5000000, 9 .0000000)
ANNEXE D:
LES DESCRIPTEURS DE FORMAT
- les descripteurs actifs (dits également descripteurs d'édition) : ils sont obligatoirement
associés à un élément de la liste; ils peuvent être précédés d'un "facteur de répétition" ;
- les descripteurs ~ifs (dits égalemeit descripteurs de contrôle) : il ne sont associés à
aucun élément de la liste ; ils ne peuvent jamais être précédés d'un "facteur de
répétition'.
Nous utiliserons toujours les notations suivantes:
w : gabarit de l'information,
d : nombre de décimales aprês le point décimal,
m: nombre minimal de chifres à écrire(n'intervient pas dans une lecture).
e : nombre de chiffres d'un exposant
Ces quantités sont toujours des constantes entières 'littérales' sans signe (telles que 14,
8 ...). c'est-à-dire qu'il ne peut pas s'agir d'expressions constantes, ni même de constantes
symboliques (telles quenmax). De plus, w et e ne peuvent pas être nulles.
358 Annexe D : les descripteurs de format
Lorsque cela est permis, si un point décimal est présent dans la donnée, on ne tient pas
compte de la valeur du paramètre d du descripteur.
En lecwre, tous ces descripteurs sont ~uivalents : l'information peut &re présentée sous
n'importe quelle des formes : entier signé (la valeur de d sert alors à préciser la position du
point), réel en notation flottante ou exponentielle (avec un exposant repéré par E, e, D ou
d).
Annexe 0 : les descripteurs de format 359
La valeur de e Qorsqu 'elle est présente) n'est utilisée qu'en écriture; elle précise le
nombre de chiffres qu'occupera fexposant En absence de e, on utilise deux chiffres pour
l'exposant ; pour des exposants compris entre 100 et 99'), Fortran 'récupère' l'emplacement
de la lettre E ou O qui disparaît alors. La présence de e est indispensable pour des
exposants supèrieurs à 99'J.
Ils ne sont ud llsables qu'en fo·l ture. Us régissent la présence ou fabsence d'un signe plus
lors de l'écriture de nombres positifs Un tel descripteur s'applique uniquement à
l'instruction concemte, et uniquement à partir du moment où il a tté rencontré dans la
liste des descripteurs. Son efftt peut tventuellement être annult par la présence d'un autre
descripteur de ce type.
Exemples:
lnteger n • 4, p • 25, q • 5
affichera 4 ou +4 pour n (suivant l'ordinateur utilisé) et toujours +25 pour pet +5 pour
q.
Avec les mêmes déclarations, l'instruction :
affichera toujours + 4, 25 et + 5
360 Annexe D : les descripteurs de format
·en lecture, la valeur obtenue est celle de la donnée, divisée par lOP.
· en écriture, lorsqu'un exposant est présen~ la mantisse est multipliée par loP, tandis
que Pexpœant est diminué de p.
Un tel descripteur s'applique uniquement à Pinstruction concernée et uniquement à partir
du mOll)enl où il a élé rencontré- Le facteur d'échelle peut être modi(ié par l'application
d'un nouveau facteur d'échelle ou annulé par la spécification OP.
Exemple:
Par défau~ les espaces sont ignorés dans une donnée lue. Ce comportement peul toutefois
être modifié :
Annexe D : les descripteurs de fccmat 361
- en utilisant le paramètre blank lors de l'ouverture d'un fichier; pour toutes les
opérations de lecture relatives au fichier en question, les espaces sont alors (par défaut)
soit ignorés (blank = 'mdl?, soit interprétés comme des zéros (blank = wo?. Notez
que cette possibilitt ne peut pas s'appliquer à l'entrte standard (on ne peut lui
appliquer d'instruction d'ouverture!).
- en utilisant les descripteurs bn et bz, lesquels modifient le comportement de la seule
instruction de lecture à laquelle ils sont associés- Notez qu'il est possible, avec ces
descripteurs, d'outrepasser un comportement •gtntral' dtfini lors de fouverture du
fichier.
Exemple:
1@23@4@56@7
Lw logique
Gw idem Lw
En lecture, on peut trouver, dans le gabarit spécifit un nombre quelconque d'espaces suivis
tventuellement d'un point, de fune des lettres T, t, Fou f puis de... n'importe quoi.
En tcriture, on obtient rune des deux lettres T ou F, cadrte à droite dans le gabarit
indiqué.
En écriture, on écrit dans le gabarit voulu ; dans le cas de Aw, si w est supérieur à la
longueur de la chaîne, on fait précéder faffichage par des espaces à gauche (comme pour
les nombres, ce qui ne correspond pas à l'usage). Si w est inférieur à la longueur de la
chaîne, seuls les w premiers caractères sont écrits.
En lecture, on lit le nombre de caractères correspondant au gabarit voulu Dans le cas de
Aw, si w est supérieur à la longueur de la chaîne, seuls les w derniers caractères seront pris
en compte; si w est inférieur à la longueur de la chaîne, cette dernière sera complétée par
des espaces.
A priori, lorsque la liste d'une entrée-60rtie est épuisée, les descripteurs pa$ifs suivams
sont exploités. La présence d'un descripteur':' interrompt, dans un td cas, l'exploitation
du format
Exemple:
iq>l icit ooœ
integer : : i
integer, dirension (8) :: t • (/ (i, i• l. 8) /)
Annexe D : les descripteurs de format 363
print •, 1
sans : 1 : print 1 ( 8(i3, • -- •) ) 1 , t
print •, •avec :' : print '( 8(i3, :, • •• ") )'. t
end
sans
1 ..2 ·- 3 -- 4 .. 5 -· 6 ·- 7 -- 8 --
avec :
1 -- --
2 3 -- 4 -- 5 -- 6 -- 7 -- 8
TABLEAU RECAPITULATIF
Voici la liste de tous les opérateurs du Fortran 90, classés par ordre de priorité
décroissante. Les opérateurs figurant sur une même ligne ont même priorité.
Il
.EQ.. NE. .LT. LE..GT..GE. /= < < = > > =
.NOT .
. AND.
.OR .
.EQV.. NEQV.
Opérateur binaire défini par l'utilisateur
ANNEXE F :
LES INSTRUCTIONS DE DECLARATION
- son type,
- des "attributs• tels que parameter,pointer, target, aUocatable, save,privote,public ...
- des bornes dfodices dans le cas de tableaux,
- une valeur éventuelle.
Comme nous l'avons vu, en Fortran 90, ces différents éléments peuvent être regroupés au
sein d'une seule instruction de déclaration dans laquelle le premier mot (mot clé) est alors
le nom du type de la variable.
En Fortran 77, on ne disposait pas de cette possbilité et il fallait alors souvent faire appel à
plusieurs instructions de déclaration, par exemple, une pour préciser un type, une autre
pour préciser que fon a affaire à une constante symbolique (parameter). Par ailleurs, il
existait d'autres manières de déclarer des tableaux ou des chaînes de caractères.
D'une manière génfaale, quand vous écrivez un nouveau programme en Fortran, il est
vivement conseillé d'utiliser systématiquement la nouvelle forme des déclarations dont
nous allons fournir ici un récapitulatif complet Toutefois, pour vous permettre de
comprendre ou d'adapter des programmes écrits dans des versions antérieures de Fortran,
nous vous fournirons ensuite des indications sur les différentes formes de déclaration que
vous risquez de rencontrer.
366 Annexe F : les instructions de déclaration
Avec:
1. Rappelons que la n0tation ( ~.. signifie que le contenu des crochets peul appani.krt. 0, 1 ou plu.sieurc fois.
2. Notez. que lon:que aucun a1tribu1 n'est p«cisit, les : SOnl facultatifs; œ retrowe la forme fi>rtnn 77 des
d6cla.rations de l)pe.
3. Bn gtntral, il s'agi1 d'un identitiœ1eur de variatje mais, en th6orie, iJ peul s'agir d'un iden1l icateur de
fonction; en Portnn ~ il est toutefois oonse.ilt d'utiliser une interface dansoe cas.
4. Altention, pas de variante possjble ici.
Annexe F : les instructions de déclaration 'Y>7
genre: IN/OUT/INOUT
liste_d_érendues : liste de spécifications de rune des deux Connes suivantes:
a) (début : ) fin
Avec début et fm : expressions constantes pour des tableaux statiques,
expressions de spécification pour des arguments muets ou des tableaux
atomatiques,
b) : [: )
pour les tableaux allouables ou pour les pointeurs sur des tableaux
Rappels
Une expttsslon constante doit être 'théoriquement constante' (c'est-à-dire définie par le
texte du programme et non lors de l'exécution) et, de plus, satisfaire à certaines contraintes
(imposées pour ne pas trop compliquer la tâche du compilateur):
- les fonctions élémentaires doivent avoir des arguments et des résu ltats de type entier,
· En dehors des fonctions élémentaires, il fau t se limiter à :
• repeat, trin~ tronsfer et reshape avec des arguments de type entier ou chaîne,
• seleaed_itt_kind etseleaed_reaJ_kind,
• des fonctions d'interrogation différentes de present, assodaled ou a/located.
On peut toujours écrire une déclaration de la forme générale présentée dans le paragraphe
l et la "compléter" par des déclarations spécifiques à un ou plusieurs attributs particuliers
(qui n'auront alors pas été précisés dans la première déclaration). En voici des exemples :
integer : : n. p 1 ou integer n. p
real :: x, y, tl, t2 1 ou rea l x, y, tl, t2
save : : n. x 1 ou save n. x
di11ension :: tl (50) 1 ou di11ens Ion tl (50)
pointer : : y 1 y sera donc un pointeur sur des rêels
target : : n. x. t2
a llocatable :: t2 (:,:)
parameter : : p • 20
Les dimensions des tableaux peuvent figurer sam l'attribut dimension dans une déclaration
de type telle que :
Notez bien qu'alors les"::' ne peuvent plus apparaître (il ne s'agit ici que d'assurer la
compatibilité de Fortran 90 avec Fortran 77).
mais awi oous rune des formes (les"::" sont facultatifs ; en les suppriman~ on retrouve les
formes connues du Fortran 77) :
character : : mt• 10
character : : mt " (10)
character * 10 :: IK>t
character • (IO) : : mt
Ces possibilités peuvent se combiner avec celles concernant les déclarations de dimension,
ce qui peut conduire à une multitude de formulations équivalentes. Par exemple, voici
différentes façons de déclarer un lableau de 100 chaînes de longueur 10 Qà encore, les"::"
sont facukatifs) :
Comme nous l'avons déjà signalé, en l'absence de spécification de type (et si l'on n'a pas
prévu d'instruction implicit none) une variable se voit attribuer un type basé sur la première
lettre de son nom, à savoir :
le~ les noms commençant par l'une des lettres d, e, ~ g. h, x, y ou z restent soumis aux
règles "habituelles', c'est-à-dire que:
- si aucune déclaration implicit none n'a été prévue, ils correspondront au type real,
- si une déclaration implicit none a été prévœ (elle devra alors apparaîlre avant toutes
les déclarations précédeites), ils conduiront à une erreur de compilation_
Voici la syntaxe générale de l'instructionimplicil:
Typage implicite
Avec:
S. Compte tenu de la place in posée aux instr\.lctions implicit, la dllinl:icn du type. vecteur ne pown. se faire que
dans un modulcqu•œ utli&era parur.e.
Annexe F : les instructions de déclaration 371
Remarque
cl • ...
c2 • •.•
contains
slt>routine sp
iqi licit integer (a - c)
integer : : cl
efKI subroutine sp
el'KI progra.11 bizare
ANNEXE G:
ORDRE DES INSTRUCTIONS
USE
lMPllCIT f«JNE
PAAAMETER lMPllCIT
CONTAINS
Ef«l
ANNEXEH:
LA PROGRAMMATION ORIENTEE OBJET AVEC
FORTRAN 2003
Depui<i Fortran 2003 , il est possible de mettre en œuvre la plupart des concept<; proposés par
ce que l'on nomme la « program1nation orientée objet », ou POO. Celle-ci possède de
nombr eu.~s vertu.<; universellement reconnues. Sans renier la program1nation st ructurée (elJe
se fonde sur elle), elle contribue à la fia bilité des logiciels et elle facilite la réutilisation de
code existant. Elle introduit de nouvealLx concepts dont les principalLx sont ceux d'objet.
d'encapsulation, de classe, d'héritage et de polytnorphi-;me. Nous vous proposons dans ce
chapitre d'étudier comment ces concept<; s'expriment en Fortran 2003 .
1.1 Introduction
Le concept d'objet consist e à regrouper dan.<; une même entité des données qu'on nomme des
attributs (ou des champs) et des procédures qu'on nomme souvent des méthodes. Lorsque l'on
réali...e ce que l'on nomme l'encapsulation des données, seules les méthodes sont habilitées à
1nanipuJer ces données, qu'il s'agis.....e de les modifier ou simpJement d'en utiliser la valeur.
Par ailleurs. la notion de clas.....e généralise la notion de type aux objets: un objet n 'est rien
d'autre qu' w1e. description (w1ique) pouvant dom1er naio;.sance à ditîérento;. objeto;. disposant de
la même structure de données et des mêmes méthodes.
En Fo1t ran 90, on dispose déjà de la notion de type dérivé (ou structure) qui va fo urnir Je.
suppo11 à la notion de clas.....e. Depuis Fo1t ran 2003, w1 t)'p e dé1ivé peut se voir «attacher• »
w1e ou plu.<iiew·s procédures jouant le rôle de méthodes.
1
Bind en angl ois
374 Annexe H: La program1nation orientée objet avec Fortran 2003
Nous allon.'i définir une classe2 nommée poin1, dest inée à 1nanipuler les points d'un plan,
représentés par deux coordonnées de typ e entier, disposant de trois méthodes: inilia/ise pow·
attribuer des valeurs aux coordonnées d'un point, deplace pour les modifier et affiche pour les
atfteher.
Pour écrire les procédures 001Tespondantes, il fa ut tenir compte de ce que lorsqu'une méthode
est appelée, elle l'est pow· un objet préci'i dont elle reçoit auto1natiquement l'adresse. Dans de
t10mbrelLx langages, ce mécani'ime est géré de façon implicite. En Fo1t ran, il en ira de même
pour l'appel de la métl10de (comme nous le verrons plus loin) 1nais, dans sa définition, il
faud ra mentionner cet objet comme premier ar gument. Par exemple, la procédure inilia/ise
s'écrira aitl.'ii (p désignant l'objet l'ayant appelé):
subroutine initialise •p, x, y)
cl.ass •point) , intent •out) p
inte9êr, intent •in) x, y
p\x : X ; p\ y : y ! notation usuelle des champs :< et y de p
end subroutine initialise
On notera que Fortran impose la règle suivante: un argun1ent n1uet correspondant à un
objet doit être déclaré avec le n1ot-clé class et non avec 1ype. Nous reviendrons sw· ce point
lorsque nous parlerons du polyinorphisme. Pour l'instant, disons qu'un tel argument est
su.<i.Ceptible de désigner, non seulement un poin1, 1nais n 'importe quel objet d' w1e clas..<i.e
descendante de /JOin1. Le mot-clé c/ass correspond à un type su.<i.Ceptible de var ier, tandis que
l)'pe correspond à un typ e figé".
Voici en définitive la définition de notre t)'p epoin1, placée ici dans un module.
module point_simple
type point
int1:9er, pr i'late x, y ! composantes pri'lees
contains
procedure initialise, affiche, deplace
end type point
contains
subroutine initialise •p, x, y)
class •point) , intent Unout) p
int1:9er, intent Un) x,
p\x : X ; p\ y : y
end subroutine initialise
subroutine affiche •Pl
class •point) , intent Un) p
print ~, "Je suis un point de coordonnees , p\ x, " , pt.y
end subroutine affiche
subroutine deplace •p, d x, dy)
class •point) , intent Unout) p
int1:9er, intent •in) d x, dy
pt x = pt x t d x ; pt y = pt y t dy
end subroutine deplace
end module point_simple
Pour utiliser ce typ e dans w1 programme, on effectuera classiquement des déclar ations de
variables de ce t)p e (objets), comme:
type(point) p
On appellera une méthode d'w1 objet en la nommant de la même manière qu'un c hamp d'une
structure, c'est· à...dire de cette 1nanière:
call p\ initialise •2, 5)
pro9ram testPoint
use point_simple
typelpoint) p
call pt initialise •2, 5)
call pt affiche• )
call pt deplace •6, - 1)
call pt affiche• )
end pro9ram testPoint
4) Ici, les procédures attachées étaient des SOU.<i· programmes, mai'i il pourrait s'agir de
fonctions. d'opérateurs ou de procédures génériques comme tlOU.'i le verrons plu.<i loin.
Annexe H: La program1nation orientée objet avec Fortran 2003 377
5) On peut définir classiquement des procédures sans les attacher au type, en lew·
prévoyant éventuellement un ou plusieurs ar gument'i de type classe. rvt ais, contrairement
aux procédures attachées au type, elles n' auront plus accès alLx membres privés du type.
Naturellement, on ne pourra plu.<i utili<i.er d'appel<i du type (sp désignant un tel sous-
programme) :
call point\:sp ! incorrect si sp est un sous- pr09ramme indépendant
En toute riguew·. il est possible de définir une fonction portant le même nom que le type qu'on
poura utiliser pour initiali<i.er w1 objet, sans toutefoi'i pouvoir l'employer comme initialiseur. Il
suffit de c réer une fonction géné1ique portant le nom du type et de l'associer à une ou
plusieurs fonctions effectuant l'initialisation. Cette dé1narche comporte l'avantage de pouvoir
fou rnir plusieurs fonctions de construction de même nom, avec des arguments de typ es
différents, à l'inst ar de ce qui se produit pow· une procédure générique (voir c hapitre XI) .
Voici comment nou.'i pomTions adapter dans ce sens notre clas..<i.e poin1 en la dotant de deux
co1l.'it ructew·s: un clas..'iique à deux arguments, un à un seul ar gument re pré~<i.entant l' abscis..<i.e
d' w1 point (dont l'ordonnée sera alors 0). Notez qu'on dispo.<i.e implicitement d' w1
co1l.'itructew· sans argument, compte tenu de ce que nou.'i avons initialisé (ici à 0). les champs
de /JOin1. Nous n 'avons pa.<i reproduit intégralement les méthodes affiche et deplace qui sont
celles du paragraphe 1.2.
module point_simple_const
type point
int1:9er, pr i'late x=O, r=O
contains
procedure affiche, depl.ace
end type point
interface point
module procedure initl , init2
end interface
378 Annexe H : La program1nation orientée objet avec Fortran 2003
contains
function initl •x)
type •point) initl
int~er , intent Un)
initltx = :<; initl i y
end function initl
function init2 •x, y)
type •point) init2
int~er , intent Un) x,
init2t:< = :< ; init2i y
end function init2
! !! ! subroutines affiche et depl.ace du module point_simple du para9raphe 1. 2
end module point_simple_const
pro9ram testPoint
use point_simple_const
type•point) p ! On ne peut pas faire type•point)
p = point •2, 5)
call pt affiche• )
p = point •3) ! meme role que p = point •3, 0)
call pt affiche•
p = point O
call pt affiche•
end pro9ram testPoint
et ;nu2 de notre exemple ne sont p lu.~ des méthodes attachées au type poin1. Il s'agit de
fonctions appartenant au module poin1_simple_cons1. ma i~ indépendante du type point
3) Dans les fonctions ini1 I et ;ni12. on ne pourait pas déclar er le type de la valeur de retow·
avec c /ass au lieu de l)'p<.>:
class (point) initl ! erreur
En effet , ces méthodes fou111issent toujours en ret ow· un objet de type /JO;n1 . Elles ne sont
nullement concernées par d'éventuelles classes descendantes de /JOin1 .
La fo nction doit donc recevoir le second point en argument (en plu.~ du premier transmis
implicitement). Elle poutTait se présenter ainsi:
l~ical function coincide (p, q)
class (point) , intent Un) p, q
coincide = (pt x . eq . qtx) . and . (pt y . eq . q \ y)
end fonction coincide
On voit que cette méthode coincide, appeJée pour un objet p. est autorisée à accéder aux
champs privés d'un autre objet q de la même classe. On traduit cela en disant que. en Fortran.
comme dans la plupart des langages objet, l' unité d'encap.sulation est la classe (et non
l'objet). Nous avons déjà dit que seules les méthodes d' w1e classe pouvaient accéder aux
champs privés de cette classe. Nous voyo11.~ plus précisément ici que cette autorisation
conce111e bien tous les objets de la classe et non l'objet cow·ant seulement.
Voici un exemple complet utilisant cette fonction coincide avec w1e. classe poin1 réduite au
sb·ict minimum :
module point_simple
type point
intE09er, pr i'late x=O, r=O
contains
procedure initialise, coincide
end type point
380 Annexe H: La program1nation orientée objet avec Fortran 2003
contains
subroutine initialise (p, x, y)
class (point), intent Unout) p
int~er, intent Un) x,
p\x : X ; p\ y : y
end subroutine initialise
lo9ical function coincide (p, q )
class (point), intent Un) p, q
coincide = (p\ x . eq . qtx) . and . (p\ y . eq . q %:y)
end fonction coincide
end module point_simple
pro9ram tstcoincide
use point_simple
implicit nor.oe
type (point) a, b, c
c.all a\ initialise U, 3)
c.all b\ initialise (2, 5)
c.all c\ initialise U, 3)
print ', a %:coincide(b), b \coincide(a), c \ coincide(a)
end pro9ram tstcoincide
F FT
contains
procedure, pass (p) sub ! p sera l'argument transmis implicitement
end type T ! pour représenter l' ob)et appelant la procédure
subroutine sub (a, b, p, c )
Annexe H: La program1nation orientée objet avec Fortran 2003 381
contains
procedure sp, fct ! sous- pro9rammes ou fonctions
end type T
Cette association peut également porter sur des méthodes géné1iques, en utilisant ce schéma :
type T
contains
procedure spi, sp2 ! on pourrait decl.arer spi et sp2 pri'les
9eneric sp => spl , sp2 ! en conser'lant seulement sp public
end type T ! pour e'liter un appel direct de spl ou sp2
Ici, l'appel de la méthode sp sera converti en w1 appel de l'une des méthodes spi ou sp2.
suivant l'interface de la méthode appelante.
Enfi n, cette association peut également porter sur des définitions ou surdéfinitions
d'opérateurs, suivant ce sché1na :
type T
contains
procedure Tplusl , TplusT, IplusT ! pour Ttint~er, TtT, int~ertT
9eneric operator•t) => Tplus!, TplusT, IplusT ! qui pourraient etre pri'les
end type T ! en 9ardant operator•t) public
382 Annexe H: La program1nation orientée objet avec Fortran 2003
Voici un exemple dans lequel nou.~ dotons un typepoin1 d'un opérateur + utilisable pow· :
· ajouter deux p oint~ (le résultat est le point obtenu en ajoutant leurs coordom1ées) ~
· un point et w1 entier (le résultat est obtenu par ajout de l'entier à l'ab scisse)~
· un entier et un point (même chose).
module point_simple
type point
int1:9er, pr i'late x=O, r=O
contains
procedure initialise, affiche, TplusI, TplusT
procedure, pass {p) IplusT ! noter pass ici
9êneric operator{t) => Tplus!, TplusT, IplusT
end type point
contains
subroutine initialise {p, x, y)
class {point), intent {inout) p
int1:9er, intent {in) x,
p\x : X ; p\ y : y
end subroutine initialise
subroutine affiche {p)
class {point), intent {in) p
print ', "Je suis un point de coordonnees , pt x, " , pt y
end subroutine affiche
function Tplus! {p, i)
class {point), intent {in) p
type {point) TplusI ! attention, type ici et non class
int1:9er, intent{ in)
TplusI\x = p\ x t i ; Tplusl t y = pt y
end function Tplus!
function TplusT {p, q)
class {point), intent{in) p, q
type {point) TplusT ! attention, type ici et non class
TplusT\x = p\x t qtx ; TplusT\ y = p\ y t q t y
end function TplusT
function IplusT {i, p)
type {point) IplusT ! attention, type ici et non class
class {point), intent {in) p
int1:9er, intent{ in)
IplusT\ x = p\ x t i ; IplusTt y = pt y
end function IplusT
end module point_simple
Annexe H: La program1nation orientée objet avec Fortran 2003 383
pro9ram tstPlus
use point_simple
implicit none
type (point) p, q, s
call p\ initialise (3, 5) c.all q\ initialise (2, 8)
s = ptq ; call stafficheO
s = pt3 ; c.all stafficheO
s = 3tp ; call stafflcheO
end pro9ram tstPlus
2 - L'HERITAGE
Le concept d' héritage const itue l' w1 des fondements de la program1nation orientée objet. En
effet , il permet de définir une nouvelle clas..~. dite classe dérivéeJ (ou aussi éœndue, fille,
descendame ou sous-classe). à pa11ir d'une clas..~ exi'it ante dite classe de base (ou au.'i..'ii
paren1e ou ascendan1e). Cette nouvelle clas..~ hérite d'embJée des fonctionnalités de la clas..~
de b a.~ (champs et méthodes) qu'elle powTa modifier ou compléter à volonté, sans qu'il soit
nécessaire de remettre en quest ion la clas..~ de base.
Cette technique permet donc de développer de nouveaux outil<i en se fondant sur un certain
acquis, ce qui just ifie le terme d'hé1i tage. Comme on peut s'y attendre, il sera possible de
développer à partir d'w1e clas..~ de base, autant de sous-cla.'i..~s qu'on le désire. De même, une
sous-clas..~ poutTa à son tow· servir de clas..~ de base pow· une nouvelle ext ension.
s Attention, furttan parle plutôt de typ~déri\'é~ pour dési gner ~« ty~déri\'é~ ~ ty~de base», types que
r on nomma aussi structures. li emploie le terme de« types é tendus » dans le cas de l'hérilnh"C:.
384 Annexe H: La program1nation orientée objet avec Fortran 2003
Nous commenceroll.'i. par vous présenter la mise en œuvre de l héritage et nous verrons alors
ce que deviennent les droits d'accès alLx c hamps et méthodes d'une classe descendante. Puis,
110u.o;. ferons le point s w· la construction et l'initialisation des objets co1Tespondanto;.. Nou.o;.
montrerons ensuite comment w1e. classe descendante peut redéfinir w1e. métl10de d'une clas..<i.e
de ba.<i.e, avant d'énoncer quelques règles générales.
2.1 Le mécanisme
Supposez que nous disposions d'une clas..<i.e po;n1 (p ar exem ple, celle du par agraphe 1. 2) et
que nous souhaitions disposer d' w1e clas..<i.e po;n1eol, destinée à 1nanipuler des pointo;. colorés
d' w1 plan. Une telle clas..<i.e peut 1nanifest ement disposer des mêmes fonctionnalités que la
clas..<i.e po;n1. alLxquelles on powTait adjoindre, par exemple, une méthode nommée colore,
char gée de définir la couJeur. Dans ces conditions. nous pouvons c hercher à définir poin1col
comme clas..<i.e descendante depo;n1. Si nou.o;. y prévo)'t>ns, outre la méthode colore, un membre
110mmé couleur, de typ e in1eger, dest iné à représenter la couk-ur d'un point. voici comment
pourrait se présenter la déclar ation de la clas..<i.e po;n1col:
type, extends (point) pointcol ! pointcol hérite œ point (ou étend point)
int1:9er, pri'late cout = 0
contains
procedure colore
end type pointcol
Disposant de cette clas..<i.e, nous pouvons déclar er des objets de ryp e po;n1col:
type (pointcol) pc
Un objet de type /JO;n1ol peut bien sûr fai re appel aux méthodes publiques de /JOin1col (ici,
colore) m aio;. au.o;.si aux méthodes publiques de poin1 telles que iniaa/ise, deplace et affiche.
call pe%:initiatise (3, 5) ! donne les 'laleurs 3 et Saux champs x et y de pc
call pekolore (3) ! donne la 'laleur 3 au champ cout de pc
call pctafflch!! O
D'une 1nanière générale, un objet d'une classe descendante accède aux nien1bres (chan1ps
et n1éthodes) publics de sa classe de base, exactement comme s'ils étaient définis dans la
clas..<i.e descendante elle.même. Si cela s'avère nécessaire, il est possibJe d'accéder à la
globalité des données de l'objet hé1i té. Par e.xempJe, p c'XfJ0in1 désigne la « composante»
/JOin1 de l'objet pc de type po;n1col. Le dernier appel précédent pow·rait aussi s'écrire cal/
pc'X{Join f'/,;iffiche()".
En revanche, une n1éthode d'une classe descendante n'a pas accès aux n1en1bes privés de
sa classe de base. En l'ab.<i.e1lCe de cettre règle restrictive. il suffirait de c réer une cla.'i...<i.e
descendante pour violer Je pri1lCipe d'encapsulation.
t. Attention, les deux écritu ~ ne seraient pa..; équi \'alent~ si la méthode q{fiche était redéfinie dans pointool.
Annexe H: La program1nation orientée objet avec Fortran 2003 385
Ainsi, si l'on considère notre classepointcol, elle ne dispose pour l'instant que d' w1e méthode
affiche, héritée de point qui, bien entendu, ne fow·n it pas la couleur. On peut c hercher à la
doter d'une nouvelle méthode nommée, par exem ple, affichec , fou nio;.s.ant à la fois les
coordonnées du point coloré et sa coulew·. rvt aio;., il n 'est pas possible de procéder ain.'ii
(p uisque x et y sont privés pour les méthodes depoin1col):
subroutine affiche_c (p)
class (pointcol) , intent Un) p
print ', ...Je suis un point colore de coord:>nnees " , p\ x, pt.y ! non x et y prh-es
print ', " et de couleur " , p%:coul
end subroutir.oe affiche_c
Mais nou.o;. pouvon.o;. nous appuyer sur la méthode affiche de point en procédant ainsi :
call p%:point%afficheO
print ', " et de couleur " , p%:coul
En fai t, ici, nous avons appelé la méthode affiche pour la« com posante» point de l' objet p c.
En définitive, voici w1 exemple complet reprenant cette nouvelle classe pointco/ que nous
avons également dotée d'une méthode inilia/ise_c pennettant de définir à la fois les
composantes et la couleur d'un point coloré (là encore, nous nou.o;. appuyons. s.w· la méthode
initia/ire de point). Nou.o;. n 'avons. pas reproduit les procédures inilia/ise, affiche et deplace qui
sont celles du paragraphe 1.2.
module point_simple
type point ; inte9er, pri'late x=O, y=O
contains ; procedure initialise, affiche, deplace
end type point
contains
! ! ! ! procedures initialise, deplace, affiche du module point_simple - section 1. 2
end module point_simple
module point_colore
use point_simple
type, extends (point) pointcol
intE09er, pr i'late cout = 0
contains
procedure initialise_c, affiche_c, colore
end type pointcol
contains
subroutine initialise_c (p, x, y, c)
class (pointcol) , intent Unout) p
intE09er x, y, c
call p%:initialise ( x, y) call p\colore (c)
end subroutine initialise_c
386 Annexe H : La program1nation orientée objet avec Fortran 2003
pro9ram testPoint
use point_simple ; use point_colore
type {pointcol) pcl, pc2
call pcl\ initialise {3, 5) ; c.all pcl t colore {3)
call pcltaffiche O ! attention, ici affiche
call pcltaffiche_c O ! et ici affiche_c
call pc2\ initialise_c {5, 8, 2) ; c.all pc2taffiche_c O
call pc2t deplace {l, -3) ; c.all pc2taffiche_c O
end pro9ram testPoint
Considé roll.~ l'exemple du par agraphe précédent. Nous avons vu que l'appel cal/
pc/ 'YfPjficheO fou rni'i..sait tout naturellement les coordonnées de l'objet p cl, mais pas sa
coulew·. C 'est pour cette raison que 110u.~ avions introduit dans poin1co/ une méthode affichec
affichant à la fois les coordonnées et la couleur d' w1 objet de type /JOin1co/.
Or, manifest ement, les méthodes affiche et affichec font un travail semblable: ellles affichent
les valeurs des données d'un objet de lew· classe. Dans ces conditions. il parait logique de
chercher à lew· attribuer le même nom. Cette po.<i..<iibilité qui exi'it e dans la plupart des
langages objet peut être mise en œuvre en Fo1tran. Toutefois, il n'est pa.~ pennis de définir
directement une nouvelle méthode affiche da11.~ /JOin1co/. rvt ais il est po.<i..<iible dans la
déclar ation d'association de la procédure affichec de1JOin1co/ de lui fou rnir un nom synonytne
(ici, affiche) en procédant ainsi:
procedure affiche => affiche_c
Cela signifie que, au sein du module où est défini le typ e poin1co/, on définira la procédure
comme auparavant sous le nom afficlte_c. En revanche, on l'utilisera dep uis un programme
sous le nom affiche. Toutefois, dans la définition de affiche_c. il n 'est p lu.~ quest ion d'utiliser
w1 appel tel que :
c.all ptafficheO ! pro'loquerait un appel récursif de affiche
qui, cette fois, appelerait la méthode affiche de poinico/ (donc son synonyme afflche_c),
provoquant une récw·sivité non souhaitée. JI nous fau t absolument recow·ir à la méthode
afficlte de la compo.sante poin1 de p. en écrivant :
call pt pointtafficheO
Voici un exemple complet de programme illustrant cette po.<i..<iibilité de redéfinition. Nous
utili<i0 1l.~ toujours le type /JOin1 défini au par agraphe 1. 2 et nous avons défini une classe
descdendante1JOin1co/ simplifiée.
module point_simple
type point
intE09er, pr i'late x=O, r=O
contains
procedure initialise, affiche, deplace
end type point
contains
! ! ! ! procedures initialise, deplace, affiche du module point_simple - section 1. 2
end module point_simple
388 Annexe H: La program1nation orientée objet avec Fortran 2003
module point_colore
use point_simple
type, extends {point) pointcol
int1:9er, pr i'late coul = 0
contains
procedure initialise_c , affiche => affiche_c
end type pointcol
contains
subroutine initialise_c {p, :<, y, c)
class {pointcol) , intent {inout) p
int1:9er, intent{in) :<, y, c
c.all p\ initialise { :<, y) ! ou c.all p\ point\ initialise { :<, y)
p\ coul = c
end subroutine initialise_c
subroutine affiche_c {p)
class {pointcol) , intent {in) p
c.all p\ point\ afficheO ! call p\ afficheO =>appel recursif de affiche
print ', " et de couleur " , p\ coul
end subroutine affiche_c
end module point_colore
pro9ram testRedefinition
use point_simple
use point_colore
type {point) p
type {pointcol) pc
call p%:initialise {4 , 8)
call p%:afficheO ! appel œ affiche œ point
call pe%:i nitialise_c {3, S, 3)
call petafflche O
call pe%:deplace U , - 3)
call petaffiche 0 ! appel œ affiche œ pointcol
end pro9ram testRedefinition
On notera que les méthodes génériques sont traitées de façon par ticulière en ce qui concerne
la redéfinition. Si, par exemple, on a défini dans une classer. les méthodes fini, /double
regroupées sous le syi1onyine/gen et que l'on définit, toujours comme syi1onyine defgen dans
w1e. classer· descendante de r. les méthodes ftn12 el /char. elles ne 1nasqueront pas celle de
T, mai'i elles les complèteront. Bien entendu, l'ensemble des quatre méthodes devra alors
respecter les règles habituelles relatives aux fonctio1l.'i génériques.
Enfin, on peut interdire qu' w1e méthode d' w1e classe pui'i..<i.e être redéfinie dans les classes
descendantes, en la déclar ant dans l'instruction d'association avec l'attribut non_overridable
comme dans:
procedure, non_overridable sp ! sp ne pourra pas être redéfinie dans les
! classes descendantes
3 - LE POLYMORPHISME
Nous avons déjà vu que grâce à la redéfinition des méthodes, on pouvait appliquer le même
traitement (comme affiche) à des objets de types différents (comme poinl et poin1col). rvt ais.
jusqu 'ici, le typ e de l' objet était connu à la compilation. Le polyinorphi<ime pennet de définir
des var iables contenant des références à des objel'i dont le typ e peut varier au fil de
l'exécution. En Fortran (comme en C++). cela pas..<i.e par le biais de pointeurs.
Elles déclarent des objets p. de typ e /JOin1 et p c de typ e /JOin1co/ qui pow·ront être utili~s
comme cible d' w1 pointew·. Considé roll.~ alors:
class (point), pointer adp
Cette insb·uction déclare un pointeur sw· des obje l~ de type /JOin1 . Notez bien l'utilisation du
mot-clé c/ass (et non type). lequel signifie que la cible du pointeur pomTa êt re de type /JOin1 ou
d' w1 typ e descendant.
Bien entendu, on pourra affecter à adp la référence d'un objet de ty pepoin1, mais aussi celle
d' w1 objet de tyJlepoin1co/ (attention, l'affectation inverse serait iUégale):
adp => p ! usœl
adp => adpc ! correct car pc est d'un type descendant de point
! et adp est déclaré class(point) et non type(point)
Voici un programme qui illustre ce mécanisme, en utilisant la classe /JOin1 du par agraphe 1. 2
et la classe poin1co/ du par agraphe 2. 1 (sans la méthode colore, inutile ici) :
module point_simple
type point
int1:9er, pr i'late x=O, r=O
contains
procedure initialise, affiche, deplace
end type point
contains
! ! ! ! subroutines initialise, affiche et deplace du para9raphe 1. 2
end module point_simple
module point_colore
use point_simple
type, extends (point) pointcol
int1:9er, pr i'late coul = 0
contains
procedure initialise_c
procedure affiche => affiche_c
end type pointcol
contains
!! ! ! subroutines intialise_c et affiche_c du para9raphe 2.
end module point_colore
Annexe H: La program1nation orientée objet avec Fortran 2003 391
pro9ram testPoly
use point_simple
use point_colore
type (point) , tar~t p
type (pointcol) , tar~t pc
class (point) , pointer adp
class (pointcol) , pointer adpc ! ici, type(pointcol) pourrait com-enir
eau p\ initialise (3, 5) ; adp => p
caU pc\initialise_c (3, 8, 2) ; adpc => pc ! adpc => adp serait reJete
eau adp\ affiche 0 eau adpc\ affiche 0 ;
adp => adpc ! serait iUe9!le av-ac type(pointcol) , pointer adpc
eau adptaffiche 0 eau adpc\ affiche 0 ;
end
Exemple de polyinorphisme
1 On parle auss~ parfois, de« ligature dynamique» pour traduire le fo it que le lien entre objet et procédure est
réalisé lors de r exécution et non plus lors de b compilation.
1 Nous a\'OOS déjil rencontré I~ tableaux d)11amiq~ qui existent depuis F'orttan 90. fo rtran 2003 a é largi cctte
possibilité aux autr~ types (sca bir~, cha i ~ de caractêr~, déri \'é~ comme b structu~ ou I ~ da..;scs), comme
nous le \'errons dans r anae sui\'antc.
392 Annexe H : La program1nation orientée objet avec Fortran 2003
On peut dire que le polytnorphi<ime permet d'obtenir un comportement adapté à chaque type
d'objet, sans avoir besoin de tester sa nature, de quelque façon que ce soit. La richesse de cette
possibilité amène parfoio;. à dire que l'insb·uction if est à la POO ce que l'insb·uction go10 est à
la program1nation sttucturée. Autrement dit, Je. bon usage du polytnorphisme permet par fois
d'éviter des instructions de test, de même que le bon usage de la programmation structurée
permettait d'éviter l'instruction go10.
On notera bien que si l'on considère w1e. variable telle que p déclarée :
type •point) p
il ne s'agit pas d' w1e var iable polytnoq>hique puisqu'on ne peut affecter à p que des objets de
type poin1 (et il n'est pas possibJe d' utili<i.er ici le mot-clé c/ass à la place de IJJJt>). Sans entrer
dans Jes détails, on peut dire que cette restriction est liée à la façon dont Fo1t ran gère Jes
objets (et Jes autres structures). à savoir « par valeur » et non « par référence». Dans Jes
langages comme Java qui gèrent Jes objets par référence, les 1101no;. d'objet deviennent eux
au.o;.si polytnoq>hiques. En C++, en revanche, les objets sont égak-ment gérés par valeur et il
faut recowTir à des pointeurs pour pouvoir dispo.<i.er du polytnorphisme.
Ren1arque :
Il ne fau t pas confondre la redéfinition des métl10des où les appelo;. correspondants sont
parfaitement définis à la compilation avec le polytnorphisme où les appelo;. correspondants
ne sont définio;. qu'à l'exécution, même si, en définitive, le polytnoq>hisme exploite la
redéfinition.
· affiche les coordonnées (action commune à toutes les clas..<i.es desce ndantes)~
• fas..<i.e appel à une autre méthode (nommée, par exemple, iden1ifie). ayant pour vocation
d' atfrcher les info nnations spécifiques à chaque objet. Bien entendu. ce faisan t, nou.o;.
supposons que chaque descendante de poin1 redéfinira iden1ifie de façon appropriée (1nais el Je
n'aw·a plu.o;. à prendre en char ge l'affichage des coordonnées).
Cette dé1narche nous conduit à introduire dans la clas..<i.e /JOin1 la méthode iden1ifie et à
modifier la méthode affiche :
9 Cert~, l'c-njc-u c-st tr6' limité ici. Mais, il pourrait être- import.nnt dans un programme- réc-1.
Annexe H: La program1nation orientée objet avec Fortran 2003 393
module point_simple
type point
intE09er, pr i'late x=O, r=O
contains
procedure initialise, affiche, deplace, identifie
end type point
contains
subroutine affiche (p)
class (point) , intent Un) p
call p\ identifieO
print ~, "Mes coordonnees sont , pt x, pt y
end subroutine affiche
394 Annexe H: La program1nation orientée objet avec Fortran 2003
pro9ram testPoly3
use point_simple
use point_colore
type (point) , p
type (pointcol) , pc
class (point) , adp
class (pointcol) , pointer adpc
eau p\ initialise (3, 5) ; adp => p
eau pc\initialise_c (3, 8, 2) ; adpc => pc !
eau adp\ affiche 0 eau adpc\ affiche 0
adp => adpc
eau adp\ affiche 0 eau adpc\ affiche 0
end pro9ram testPoly3
Enfi n, Fortran 2003 propose un polyinorphi<ime universel (ou polyinorphisme illimité). Ainsi,
on peut déclarer :
cl.ass ( ~ ) , pointer ptr_uni'I
Le pointeur ptr_un;v peut alors désigner n 'importe quelle c ible:
inte9êr, tar~t
type(point) , taf9et p
ptr_uni'I => n ! OK
ptr_uni'I => p ! OK
396 Annexe H : La program1nation orientée objet avec Fortran 2003
On notera toutefois que l'intérêt de cette possibilité rest e limité dès lors que les obj ets
conce111és ne dispose nt pas des mêmes méthodes (ce qui sera nécessa irement le cas pour Jes
typ es de base !). E n effet, on ne peut alors plu.<i bénéficier du mécanisme du polytnoq>hisme.
T out au plu.<i powTa·t-<>n se fonder s ur une inst ruction se/ec1 IYJJI! (prés.entée ci. après) pow·
effectuer w1 traitement dépendant du type.
pro9ram testSelect
use point_simple
use point_colore
type (point), tar(Jet p
type (pointcol), tar(Jet pc
class (point), pointer adp
class (pointcol), pointer adpc
call p%:initialise (3, 5) ; adp => p
call pe%:i nitialise_c (3, 5, 9) ; adpc => pc
select type (adp) select 1
class is (point) ; print ' ' select class point '
'
class is (pointcol) ; print ' ' select class pointcol '
'
type is (point) ; print ' ' select type point'
'
type is (pointcol) print ' ' select type pointcol'
'
end select
adp => adpc
select type !adp) select 2
class is (point) print ' ' select adpclass point '
'
class is (pointcol) ; print ' ' select class pointcol '
'
type is (point) ; print ' ' select type point'
'
type is (pointcol) print ' ' select type pointcol'
'
end select
select type (adp) select 3
class is (point) print ' ' select class point '
'
type is (point) print ' ' select type point'
'
end select
end
Annexe H: La program1nation orientée objet avec Fortran 2003 397
La clau....e de sélection se/ec1 l)'pe doit mentionner une var iable polyinorphique se1vant de
« sélectew· » . Les différentes possibilités sont des blocs d'instructions introduito;. par des
expressions de l'une des fo nnes suivantes:
type ;s (nom_de_l)'pe) : la condition est satisfaite si le typ e du sélecteur est exactement
nom_de_~ype ~
c /ass ;s (nom_de_~ype) : la condition est satisfaite si le typ e du sélecteur est nom_de_1ype
ou un type descendant.
Par ailleurs, on n 'exécute qu'un seul bloc au maximum. sachant que les conditions IY/Je sont
prioritaires sw· les conditions c /ass. De plu.o;., si plusieurs conditions c /ass conviennent, on
choisit celle qui est «la plus proche » du sélecteur. c'est·à...dire dont le typ e est w1 type
descendant des autres. On notera que les situations d'ambiguïté sont détectées par le
compilateur.
JI est possible de prévoir un bloc introduit par c /ass defaufl qui se trouvera exécuté si aucun
autre ne convient.
précise que la clas.....e affichable est « abstraite», ce qui signifie qu'il sera impossible de
déclar er directement des objets de ce typ e:
type •affichable) aff ! interdit affichable est abstraite
398 Annexe H : La program1nation orientée objet avec Fortran 2003
Une telle classe abstraite peut contenir des c hamps et des méthodes 1nais, surtout, elle peut
contenir des« méthodes retardées10 ». Il s'agit de méthodes dont on ne fou111it que l'interface
qui devront obligatoirement être définies dans toute classe descendante pow· que cette de111ière
permette la déclaration d'objets.
Voici w1 exemple de classe abstraite, nommée affichable, comportant une seule méthode
retardée nommée affiche dont nous fournissons l'interface à l'aide d'une interface abstraite
(présentée précédemment) .
module classes_affichables
type, abstract affichable
contains
procedure Unterface_affiche) , deferred affiche
end type affichable
abstract interface
subroutine interface_affiche •obJ)
import affichable ! necessaire car type affichable non 'lisible ici
class •affichable) , intent Un) oh)
end subroutine interface_affiche
end interface
end module classes_affichables
On notera l' utilisation d'une nouvelle inst ruction ;mpon. introduite par Fortran 2003 pow·
permettre à une inte1face d'accéder à son environnement.
On peut alors créer une classe descendante nommée ici enaer, de façon classique. en
prévoyant bien de définir la métllode affiche:
module classe_entier
use classes_affichables
type, extends •affichable) entier
int1:9er, pr i'late
contains
procedure init => initi, affiche
end type entier
contains
subroutine initi •ob), n)
cl.ass •entier) , intent Unout) obJ
inte~r , intent Hn)
obj t n = n
end subroutine initi
subroutine affiche •obJ)
cl.ass •entier) , intent Un) Ob)
print ', " entier de 'laleur , ObJ\ n
end subroutine affiche
end module cl.asse_entier
Notez que nous avons défini la méthode ini1i comme synonytne de ini1. Cela n' était pas
obligatoire à ce niveau mai'i, dès que l'on est amené à utili~r en même temps. plu.<iieurs
descendantes de affiche, le problème de confli t de nom se po..~ .
Voici w1e. autre clas..~ descendante nommée ree/ (avec inUr comme syt10nytne de ini1):
module classe_reel
use cl.asses_affichables
type, extends •affichable) reel
real, pri'late
contains
procedure init => initr, affiche
end type reel
contains
subroutine initr •ob), x)
class •reel) , intent Unout) obJ
real, intent Hn)
Ob)\ X : X
end subroutine initr
subroutine affiche •obJ)
class •reel) , intent Un) obJ
pr int ', " reel de 'la leur " , ObJ\ x
end subroutine affiche
end module cl.asse_reel
S'il n 'est pas penn is de déclarer des objel'i à pa11ir d'une classe abstraite, il est en revanche
possible de définir des variables pol)'1norphiques de ce typ e. Voici un exemple de programme
utilisant les classes que nous venons de définir. Nou.'i y définissons une variable
polymorphique de type affichable:
cl.ass •affichable) , pointer ad
que nou.'i faisons pointer successivement sw· un objet de type enlier, puis de typeree/. L'appel
cal/ ad'Y<PfficheO entraine bien l'appel de la méthodeoo1Tespondant au type pointé par ad.
pro9ram Test.Abstraite
use classes_affichables ; use cl.asse_entier ; use classe_reel
cl.ass •affichable) , pointer ad
type •entier) , taf9et en ! attention type ici
type •reel) , taf9et cr ! et ici
call cnt init • 12)
call crt init •2. 5)
ad => en
call adt affiche O
ad => cr
call adt affiche O
end
entier de 'laleur 12
reel de 'laleur 2 .50000000
Le recow·s aux classes abstraites et aux méthodes ret ar dées facilite lar gement la conception
des logiciels. En effet, on peut placer dans w1e. classe abstraite toutes les « fo nctionnalités»
dont on souhaite di<iposer pow· toutes ses descendantes :
· soit sous forme de méthodes retar dées dont on est alors certain qu'elles exi'iteront dans toute
descendante.
C 'est cette certitude de la présence de ce11aines méthodes qui permet d'exp loiter le
polyinorphisme, et ce dès la conception de la classe abstraite, alors même qu'aucw1e. classe
descendante n 'a peut..ètre encore été c réée.
ANNEXEI:
FORTRAN 95, 2003 et 2008
Certaines amélior a t ioll.~ des nonnes Forb·an 95, 2003 et 2008 ont déjà été présentées dans
l'ouvrage. C 'est notamment le cas des possibilités de POO présentées dans l'annexe
précédente. Nous exp osons ici les plus importantes des autres possibilités. Certaines d'entre
elles, souvent d'implémentation facuha tive, oonce111ent des aspects plus techniques sortant
1nanifest ement du cadre de cet ouvrage d'apprentissage du langage. Nou.~ nous contenterons
alors de les citer.
1
Id, contraire-ment il cc qui se passe U\'CC do, la portée de i~t limitée il l 'instruction.
402 Annexe 1 : Fo1tran 95, 2003 et 2008
Dans le premier cas (do), les affectations sont obligatoirement réalisées dans l' ordre imposé.
Dans Je second cac;, l'évaluation peut se fai re dans n · impo11e quel ordre ~ il est donc préférable
qu'il n 'y ait pas de dépendances entre les différentes évaluations. ce qui serait le cas avec:
forall U=l : l9) th)= tht1) ' 2 ! résultat imprevisible
D'une 1nanière générale, cette inst ruction ne peut porter que sur des affectations de valew·s à
des tableaux. Les instructions suivantes (som étant une var iable entière), si eUes étaient
acceptées par le compilatew·. conduiraient à des résuhats incorrecte;:
S<xn =0
forall U=l : 10) som = s<xn t t Ul ! resultat probablement faux
end do
end do
2 - AMELIORATION DE LA GESTION
DYNAMIQUE
----------------------------------------------------
pro9ram TabOynAf9
implicit none
inte9er, dimension : ), allocatable tl
inte9er, dimension : ), allocatable t2
allocate •tt•2: 5))
print ', Premier appel sp ' call sp •tt )
print ', '-- Oeu:<ieme appel sp ' c.11 sp!t2)
contains
subroutine sp •t)
inte9er, dimension • : ), allocatable, intent Unout)
if •allocated•t)) then
print ', ' table.au de)a alloue -
el se
allocate •tM ))
print ', ' table.au alloœ dans sp - bornes lbound• t), ubound• t)
end if
end subroutine sp
end pro9ram TabOynAr9
-- Premier appel sp
table.au de)a alloue - bornes
-- Oeuxieme appel sp
table.au alloœ dans sp - bornes
Notez bien qu 'ici, l'argument muet I a été déclar é avec l 'attribut ino111. D 'une 1n an1ere
générale, lorsqu' w1 tableau allouable figu re en ar gument muet, il ne peut pas posséder
l'attribut in, ce qui est logique. En revanche, s 'il possède l'attribut 0 111, le tableau
correspondant est dés.alloué dès l 'entrée dans la procédure et ceci, même s 'il avait été alloué
dans la procédure appelante.
Ainsi, en décarant / avec l 'attribut 0 111 dans le programme précédent, 110u.~ obtiendrions ces
résultat~:
-- Premier appel sp
tableau alloue dans sp - bornes
-- Oeuxieme appel sp
tableau alloue dans sp - bornes
a) Présentation
En Fortran 90195, seul~ les tablealLx pouvaient êt re gérés dynamiquement sans reoow·ir à des
pointeurs. Avec Fo1t ran 2003, n 'im porte quelle var iable, y compr i~ Jes c hamps d 'un typ e
dérivé (st ructures ou classes) peut se voir déclar er avec l 'attribut al/oca1ab/e. On pourra alors
lui attribuer un emplacement avec l ' inst ruction al/oca1e et le dés.allouer. le cas échéant, avec
l 'inst tu ction deal/oca1e :
type (point), allocatable pa
Ces possiblités seront également intéressantes pow· les c haînes de car actères dont la longueur
(1n aximale) pou1Ta êt re définie lors de l'exécution et , éventellement varier pendant le
déroulement du programme1 :
lnt~er nb = 30
character ( :) , allocatable ch ! ch= chaine dynamique de lon9œur differee (: )
! on la desalloœ ici
allocate (char acter (nbt20) : :ch) ! pour l'allouer ici a'!ec une taille nbt20
2 Ne confôndez pas la notation * qui correspond il une longurur fôu mie en a r1,rumcnt U\'CC b notation : qui
correspond il wie longueur d ite « d iftëréc )).
Annexe J: Fortran 95, 2003, 2008 405
pro9ram testChaineOyn
implicit none
character 02) chi
character •: ), allocatable ch2
inte9er
chi = " bOnJOU!" print '' "chair.oe fixe " chi , len•chl)
'
ch2 = " bOnJOU!" print '' "chair.oe 'lariable " ch2, lenlch2)
'
chi = " salut" print '' "chair.oe fixe " chi , len•chl)
'
ch2 = " salut" ; print '' "chaine 'la ri.able " ch2, lenlch2)
'
deallocate •ch2)
allocate •character •20) ch2)
do i = 1, 20
ch2H i) = ' x'
end do
print ', "chaine 'laria.ble , ch2, len•ch2)
end
Voici un autre exemple compo11ant une transmission d 'une chaîne dynamique en argument :
pro9ram ChainesOynArgument
implicit none
character •: ), allocatable chi
character •: ), allocatable ch2
inte9er, allocata.ble
allocate •n)
if •allocated(n)) print ~, n est alloue"
ch i = "bonJOUr"
call sp tchl) print ~, ch i
call sp tch2) pr int ~, ch2
contains
subroutine sp (ch)
character( : ), allocatable, intent Hnout) ch
if (allocated (ch)) then
print ~, "-- deJa alloue - on r.oe modifie pas
el se
print ~, pas encore alloue - on c ree une nou'lelle chaine"
ch = "au re•;oir et merci"
end if
end subroutine sp
end
-- n est alloue
-- de)a alloœ - on ne modifie pas
bOnJOU!
Ren1arques :
En théorie, la longuew· de la chaîne allouée par al/ocau.> peut être, non seuJement une
const ante comme dans notre exemple, maio;. au.o;.si une var iabk- (dont la vak-ur est alors
définie lors de l 'exécution). Cela autorise des schémas de ce genre où la longeur de la
chaîne est lue en donnée :
print ', " lon9eur maxi"
read ', 19max
allocate tcharacter U9max) ch2)
read ', ch2
Annexe J: Fortran 95, 2003, 2008 407
c) Transfert d'allocation
Il exist e une subroutine move_alloc qui permet de déplacer le contenu d'un objet dynamique
vers w1 autre objet de même type, tout en Je dés.allouant préalablement. Voici w1 exemple où
l'on déplace w1 tableau d'entiers nommé b dans un autre tableau nommé a.
pro9ram tstMoveAlloc
inte9er, allocata.ble al : ), hl :)
inte9er
allocate •aUO: 15))
do i = lhound•a, 1) , ubouncHa, 1) ; a Ul = i ; end d:>
pr int ', ' a = ' , a
allocate (bU :3)) ! b alloue a 3 elements
do i = lhound(b, l) , ubouncHb, l) ; bU) = 2 ' i ; end d:>
print ', ' b = ' , b
eau mov·e_alloc (a, b) ! ou call mov•~ _alloc Hrom = a , to = b)
print ', ' b= ' , b
print ', ' a alloue? ' , allocated(a) ! maintenant, a est desalloue
end
a = 10 li 12 13 14 15
b : 2 4 6
b : 10 li 12 13 14 15
a alloue ?
T ransfert d'allocation
• b doit être de même ty pe (ou de type descendant si a et b sont des var iables pol)'1norphiques)
et même rang que a~ s'il a été reçu en ar gument, il doit avoir Wl in1en1(ou1).
408 Annexe 1 : Fo1tran 95, 2003 et 2008
a) Exemple d'introduction
Fortran 2003 a introduit la notion de pointeur sur w1e. procédure (fonction ou sous-
programme), c'est -à-dire w1e. var iable destinée à contenir l'adres..<i.e d'w1e procédure. La
déclar ation de telles var iables se présente ainsi :
procedure Hl, pointer pf
Il semble qu'on déclare un pointeur sw· la procédure/ seulement. En réalité, il s'agit d'w1
pointeur sur w1e. procédure ayant la même interface que f On peut ensuite affecter à pf
l'adresse d' w1e. fonc tion «convenable» :
pf =>
L'appel de la procédure correspondante se fera classiquement en utilisant pf en lieu et place
du nom de la procédure :
call pf !. ... . l
pro9ram testPtrsProcedures
implicit none
procedure Uois2), pointer pf
! pf est un pointeur sur une procedure ayant meme interface que fois2
pf => fois2
print ~, pf •3)
pf =>carre
print ~, pf •3)
contains
inte9er function fois2 •n)
int~er, intent Un)
fois2 = 2 ~ n
end function fois2
inte9er function carre •n)
int~er, intent Un)
carre=n ~n
b) Interface abstraite
Dans notre précédent exemple, la déclar ation de pf fai t intervenir une fonction donnée, alors
que pf pow·ra désigner n 'importe quelle fo nction de même interface. Pour rendre les choses
plus li<iibles (ou pour pouvoir écrire le code lors.que l'on ne connait pas encore de fonction
cible), on peut utiliser une interface pa11iculière dite « abstraite» ( mot· clé abs1rac t) qui sert à
déclar er un modèle d'interface. Voici comment adapter dan.'i ce sens l'exemple précédent. On
y déclare une inte1face abstraite /cal qu'on utilise ensuite en lieu et place de fo;s2 pow·
déclar er notre pointeur de fonctions.
----------------------------------------------------
module c.a leu l
abstract interface
int~er function fcal (n) ! interface abstraite des fonctions de calcul
inte9êr, intent (in)
end function fc.al
end interface
contains
int~er function fois2 (n)
inte9êr, intent (in)
fois2 = 2 ' n
end function fois2
int~er function carre (n)
inte9êr, intent (in)
carre = n ' n
end function carre
end module calcul
pro9ram testPtrsProcedures
use calcul
procedure Ucal) , pointer ptr
! ptr est un pointeur sur une procedure ayant l ' interface (abstraite) fcal
ptr => fois2
pr int ', ptr (3)
ptr =>carre
print ', ptr(3)
end pro9ram testPtrsProcedures
410 Annexe J: Foitran 95, 2003 et 2008
Par défaut, un pointeur de procédure n 'est pas initialisé. On peut recourir à la fonction nullO
lors des.a déclar ation.
En théorie, il est possible d'utiliser des pointeurs de procédure, sans expliciter d'interface,
comme dans:
procedure O , pointeur pp ! pp est un pointeur sur une procedure quelconque
Cette possibilité est peu reoom1nandée, dans la mesure où le compilateur ne peut plus vérifier
la compatibilité des interfaces et les problèmes sont rejetés à l'exécution.
Une structure (ou une classe) peut disposer d'un c hamp de type pointeur de procédure:
type T
procedure •traite) , pointer pp ! pp est un pointeur sur une procedure
! ayant meme interface que traite
! ou d' interface abstraite traite
end type T
Dans ce ca.c;, lorsqu'on appellera la procédure pointée par pp. eUe recevra l' adresse de l' objet
conce111é en premier argument, sauf si l'on a utilisé le paramètre pass pour en modifier la
position ou si l'on en a supprimé la b·ansmission par nopass comme dans:
procedure •traite) , pass •obJ) , pointer pp
procedure •traite) , nopass, pointer pp
Par ailleurs, il exist e w1 par amètre LEA' utilisable pour les c haînes (il peut se combiner avec
KJND) qui n 'est pas discriminant pour la généricité. De pui~ Forb·an 2003, ce par amètre ne
peut être défini que lors de l'exécution.
Avec Fortran 2003, ces possibilités de paramétrage se généralisent aux types dé1ivés
(st1uctures, classes) comme dans cet exemple où l'on définit un vecteur dont le type et le
nombre des éJéments sont par amétrables:
type 'lecteur •'lariante, nb)
inte9êr, kind 'lariante ! parametre de type kind
inte9êr, len nb ! parametre de type len
re.al •'lariante) elem •nb)
end type •,-acteur
Les valeurs des par amètres seront alors fou rnies lors de la déclar ation de variables du typ e :
'I ! S elements du type de la constante O. 0
Pour les var iables dynamiques (al/oca1able ou poin1er). la valeur des paramètres de type peut
être différée et précisée lors de l'allocation :
type •'lecteur •kind•0. 0), :)), allocatable 'li
Lors.qu 'un type par amétré appar ait en ar gument muet d'une procédure, les par amètres de type
/en sont défini'i avec la valew· *(signifiant vaJeur définie par ailleurs):
subroutine truc h)
type •'lecteur •kind•O . O, ' )
Il est également possible de foun1ir des valew·s par défaut de ces paramètres dans la définition
du type :
type 'lecteur •'lariante, nb)
inte9êr, kind 'la riante = kind •O. 0)
inte9êr, len nb = 30
re.al •'lariante) elem •nb)
end type •,--ecteur
cependant prendre des précautions avec la 1nanière dont sont représentées les fi ns de ligne des
fic hiers fonnatés (cert aill.~ syst èmes ut ili~ nt un seul car actère, d'autres deux ... ).
• w1 mode de codage des flottants, dans lequel on dispose de motifa particuliers comme +o • .0,
+inf, -inf et NaN (no/ a number) pow· les opérations dont le résultat est indéfini (0/0 par
exemple)~
·différents modes d'arrondis (au plus proche, vers 0, vers l'infi ni, vers moins l'in fi n i)~
block
inte9êr
! ici i est connu
end block
! ici, il ne l ' est plus
7.3 Co-tableaux
Fortran 2008 offre des outil<i permettant de facili ter la program1nation parrallèle, qu'il
s'agi'i..<i.e d'architecture à mémoire di<itribuée ou à mémoire partagée.
7.4 Sous-modules
Fortran 2008 a introduit cette notion pour le développement de programmes de grande taille.
Il est alors possibJe de di<i..'i.Ocier Jes interfaces des procédures (qui restent définies dans un
module) de lew· corps qui se trouvent défini'i dans w1e. unité séparée nommé sous.module.
ANNEXEJ:
LES INSTRUCTIONS OBSOLETES
Nous décrivons ici les instructions de Fortran 77 qui, bien qu'acœptées par les versions
suivantes, sont à déconseiller.
Jes sytnboles x et z désignent tous les delLx des variables réelles situées à la même adres..~.
Avec:
re.al, dimension (8)
re.al, dimension •S) u
equi'lalence ( tM), u•2) )
on préci~ que 1(4) et u(2) ont la même adresse, ce qu'on peut illustrer par ce sché1na:
tll) tl2) tl3) tl4) tl5) tl6) tlîl tl8)
_____ 1___ 1___ 1____ 1____ 1____ 1___ 1___ 1
représenter les objelli du type en quest ion. Par exemple, suivant les cali, un entier pourra
001Tespondre à 2 ou 4 caractères, un réel à un ou delLx entiers...
On notera que le bon sens interdit de donner delLx adresses différentes à w1 même objet. Ainsi,
cette suite d'instructions sera rejet ée par le compilatew· :
equi'lalence • tH) , u•2) )
equi'lalence • t•S) , uU) )
Pour les mêmes raisons. il n 'est pas possibk- de fai re coïncider deux objelli définis dans des
w1ités de compilation différentes, notamment w1 objet d'un module avec un objet d'une
procédure utilisant ce module.
2 - L 'INSTRUCTION COMMON
Nous avons vu comment différentes w1ités de programmes pouvaient pa11ager des données à
l'aide d' w1 module approprié. Avec Fo1tran 77, ceci n'était pas possible et il fallai t alors
recourir alLx «zones communes». Cette méthode consist e à définir une ou plusieurs zones (de
mémoire) utilisées parallèlement par différentes unités de programme.
Pour ce fai re, on donne un nom à chacune des zones que l'on souhaite pa11ager ~on décrit cette
zone, dans c haque w1ité de programme, avec des nottLli de variables locales. La correspondance
se trouve alors réali'iée par la place occupée par chaque élément dans la zone concernée.
Par exemple, en plaçant dans un programme principal:
re.al a , z, x
c<xnmon /parta9/ a , z, x
et dans w1e. procédure :
re.al x, y, t
c<xnmon /parta9/ x, y,
Jes var iabk-s nommées x. y et / dans le programme principal auront Jes mêmes adres..<ies que
celk-s nommées respectivement a. z et x dan.li la procédure.
De même, si une première procédure comporte:
re.al, dimension •3)
real
c<xnmon /cml / x, y
et si w1e.seconde procédure comporte:
re.al, dimension •2)
re.al a, b
c<xnmon /cm!/ a , b, t
Annexe J: Jes instructions obsoJètes 41 7
3 - L 'INSTRUCTION DATA
Nous avons vu comment initialiser une variable lors de sa déclaraticn . Tou tefoi~. cette
possibilité n'existait pas en Fortran 77 et il fallai t alors recourir à l 'i tl.~ttuction da1a. En voici w1
premier exempJe :
datak/5/
Cette insttuction attribue la valew· initiale 5 à la variable k (éventuellement déclarée
préalablement).
Voici un autre exemple, dan.~ Jequel x est w1 tabk-au de réels de dimension 3:
data x / 1. 0, 2.5, 3. 2 /
On peut y mettre des valeurs «en fac teur » comme dans cet exemple où / est un tableau de
5 entiers:
data t / 1, l"5, 8 /
Ou initialiser w1iquement ce11ains éléments:
data t•2) , tH) / 3, 8 / ! ou encore data t•2) /3/, t•4) /8/
évalue la valeur de l'expression (entière). Suivant la valew· ainsi obtenue, il y a branchem ent :
· à elique11e1 si cette valew· est 1 ~
• à elique11e1 si cette valew· est 2 ~
· etc.
Si la valew· de l'e.xpres..'iion est infé rieure à 1 ou supérieure au nombre d'étiquettes
mentiom1ées, l'exécution se poursuit en séquence.
Généralement, une telle instruction était utilisée pour réaliser w1 «choix multiple»~ dans ce
cas, l 'inst tuction case est beaucoup plu.li appropriée.
Annexe J : Jes instructions obsoJètes 41 9
----------------------------------------------------
MAX/MOI M.~XO/M!llO inte~r int~er
}Z4AX1/}M!nl real re.al
OM.~Xl/aHm double double
'1~AXD0Mlll0 inte~r real
!{~Xl/MllH real int~er
420 Annexe J: Les itl.'it tuctions obsolètes
7 - LA DIRECTIVE INCLUDE
Dans w1 prograinme source, il est possible de de1nander au compilatew· d'incorporer des
instructions provenant d'w1 autre fichier. à l'aide d'une ligne particulière :
inelude ncm_fichier
Notez qu'il ne s'agit pas d'une instruction Fortran à proprement parl er ~ cette ligne ne peut pas
compo11er autre c hose, exception fai te d'éventuels commentaires.
Tout se passe comme si les inst ructions du fichier conce1u é fig w·aient effectivement à la place
de cette ligne. JI est tout à fai t possible que ce fic hier contienne à son tow· w1e ou plusiew·s
lignes include.
Bien qu'introduite par Fo1tran 90, cette possibilité est généralement 001t.<iidérée comme périmée
dans la mesure où l'emploi de modules (avec l'insb·uction use) est de loin préférable.
Elle évalue lexpression indiquée (elle doit être de t)'p e numérique différent de complex) et elle
provoque w1 branchement à l' w1e.des trois étiquettes indiquées, à savoir :
• eliqueue I si le résuhat est n égatif~
• e1ique11e2 si Je. résuhat est nul ~
• e1ique11e3 si Je résuhat est positif.
inte~r et
assi90 125 to et
assi90 200 to et
90 to et
Annexe J: Jes instructions obsoJètes 421
L'insttuction assign 12 5 to e1 place l'étiquette 125 1 dans la var iable entière e1. L'instruction go
to e1 effectue w1 branchement à l'étiquette contenue dans et
D'une 1nanière générale, l'instruction go 10 assigné peut préciser la liste des différentes
étiquettes su.<i.Ceptibles d'avoir été attribuées à la variable correspondante. Dans notre précédent
exemple, nous pomTions écrire:
90 to et U 25, 200)
Une var iabk- entière peut également recevoir la vak-w· d'une étiquette d'une instruction format
et, dans ce cac;, intervenir dans une i1t.c;t ruction d'entrée·so11ie comme dans cet exempJe:
int~er etf
1
En toute rigueur, un «code» correspondant il cette é tiquette.
CORRECTION DES EXERCICES
Chapitre 3
Exercice 3.1
a) real: 3
b) double precision : 5,25
c) real: 2,2
d) integer : 81
~) ioteger: -100
f) logical : T
g) logieal : T
h) logical : F
l) logieal: F
j) logieal : T
Exercice 3.2
A: 3
B : 3. 5999999
c: 3. 0000000
0 : 3
E : T
f : T
Correction des exercices
Exercice 3.3
Chapitre 4
Exercice 4.1
so11-0;m..a•
do
pr int *. ' note ru11
read * , not e
if ( note < O) exit
nu11•nu11+l
scm .. so11 + note
end do
n ..-i • n ..-i .. 1 ! car la derniere rote ne doit pas etre oons ideree
Correction des exercices
Exercice 4.2
progra11 f ibonacc i
iqil ic i t none
integer :: ul. u2 , u3. & poor parcoor ir la suite
n. & rang du terme demande
j Cc»!pt.eur
Exercice 4.3
do i • 1. nt
so11 • scm + 1.0/i 1 ou encore so11 • scm + l/f loat ( i }
attention so11 • scm + l/i ne conviendrait pas
end do
pri nt *, 'sonne des 1
, nt, 1
prelliers ter1es : 1
• scm
end
Exercice 4.4
program 1Bx_11i n
i1pl icit none
i·nteger : : note. & note courante
11axi . & note llëlXi
11i ni . & note lli ni
roltJre de fois ou note maxi trouvee
""""'· &
1111i n ooltJre de fois ou note 11in i troovee
11axi • -1 car toutes notes >• 0
11i ni • 21 car . tootes notes <• 20
do
print •. 'donnez une note {<O pour fi nir)'
read * , note
if (note < 0) exit
If ( note •• maxi) noex • nmax + 1
if ( note> mx i ) then
11axi • note
nmax • 1
end if
if ( oote •• 11ini) nmin • r111in + t
if ( oote < lli ni ) then
11i ni • note
1111i n •
end if
end do
i f (maxi >• O) then 1 si oon auo.me note four ni e
print *. 'note 1Bx i11a le
', maxi, attribuee &
nmax, ' fois '
print•. 'note11ini11a le '. 11i ni , attribuee &
nmi n, 'fois'
end if
elll
Cotteeûoo des cxetciccs
Exercice 4.5
P"<9"•• p1eœs_de_monreie
'""' tctt none
integer :: rtlf, & COOlllew w notlbre de facons de fa tre 1 F
nlO, & no.tJre de pieœs de 10 c
nS, & nollt>re de pi eoes de 5 c
n2 1 nolbre de pieoes de 2 c
nbf • 0
do nlO • o. 10
do nS • o. 20
do n2 • 0, 50
If ( 2"n2 • 5*r6 + lO*nlO - 100) then
nbf • nbf + 1
prtnt • . 1 1F· 1 .n2. 1 X2c•1. I
nS. ' X Sc • 1 • nlO. 1
X lOc'
end If
end do
end do
end do
prtnt •, 'En tout, 11 y a • . nbf. • faoons de fatre l f'
end
Chapitre 5
Exercice 5.1
Le tableau te CSI de rang 2, de pcofil (9, 3) et de taille 'Z1 (9JC3).
Exercice 5.2
EUcs plaoent la valeur 5 dans les 200 élémeits de a puis de b et la valeur 10 (5+ 5) dans les
200 éléments de c.
Correction des exercices
Exercice 5.3
Pour l'instant, les tableaux a, b etc ont bien le même profil (10, 20). Aucune erreur de
compilatioo ne sera signalée. Néanmoins, si, par la suite, on modifie les valeurs des
param~es nl ou 112, on risque fort que cette condition (profils identiques de a, b etc) ne
soit plus vérifiée, ce qui conduira à la détection d'une erreur de compilation dans
l'instruction d'affectation c = a + b.
Exercice 5.4
Exercice 5.5
a) mt (i , :) 1 1igne de raBJ i
b) mt (:, j) 1 coloMe de rang j
c) mt (2:10:2, :) 1 toutes les l ignes pa ires
d) mt (1:10:2, 1:20:2) 1 élélleflts de rarç iq>air en l igne et en colonne
e) mt (10:1:- 1, :) ! 1ignes inversées
f) mat( :, 20: 1: - 1) 1 co loooes i nversêes
g) mt (10:1: -1, 20: 1: - 1) 1 lignes et coloMes inversées
Exercice 5.6
Dans les deux cas, il est néeessaire d'avoir déclaré préalablement une variable i de type
integer.
Correction des eJ<ercices 429
Exercice 5. 7
Dans les deux cas, il est nécessaire d'avoir déclaré préalablement une variable i de type
iJiteger.
Exercice 5.8
integer : : i, j
inœger, dimension (nel, nel) :: t •
& reshape ( (/ ( ( i "j , j • 1, nel). 1 • 1, nel) /}, (/ nel , nel /} )
Exercice 5.9
Chapitre 6
Exercice 6.1
a) ···1·-a..· 12.00-··-zs.oo
b) ···1·-a-·-z. so--·-zs.oo
c) " 10--s····s.oo--·-s.oo
Correction des e>ercices
Exercice 6.2
123 4567
1234567
123 **
12 .365325500. 000
"1 2.365 4567325500.
valeur de n :
123
valeur de p
4567
4567: 123
n• 112365
Exercice 6.3
Chapitre 7
Exercice 7 .1
i nterface
fu nct ioo YO lume ( r) s i 11 interface n'est pas presente
real , intent (i n) : : r il faut au n> ins l a decl arat ion :
rea 1 : : vol ume rea l : : volume
e OO funct ion YO lume puisque aucun type n' est iq:iHcite
end interfaœ (a cause de iq :dicit none)
doi • l.3
pri nt *, "ra)<ln ?
read *, rayon
print *, "voh111e • • , Y0h111e ( ra)<ln)
end do
end progr am vo lume_si:flere
Exercice 7 .2
progra• vo l1.111e_sphere
i q:il icit none
integer : : i
rea 1 : : rayon
J i nterfaœ de YO luœ il'IJtile puisque fonct ion interne
do i• l.3
pr i nt *, -ra)<ln ?
read • , rayon
pri nt * , -Vo luœ • • , YO l uœ (ra)<ln)
end do
conta ins
fu nctioo YO lulllO (r)
real , intent ( in) :: r
reat :: vo l uœ
real : : pi • 3.141 5926
voluœ • 4.0/3.0*pi *r**3
erd funct ion VO lume
end program vo l me_sphere
Exercice 7.3
subrouti ne vol uœ (r, v)
iq:i 1 icit none
rea l , i ntent (i n) :: r
real, intent (out) : : v
real :: pi • 3.1415926
V • 4 .0/3 .0"!>i *r**3
end
Correction des exercices
progr• .ol-_Sphere
1111> lie lt rone
lnt'91!r : : 1
real : : rayon, vol
Interface
s ubroutlne voh... (r, v)
rea l, lntent(in) ::r interface
rea l, lntent (out) : : v facu l tative
end slbroutlne vo l.-.. llllls
end Interface oonseil lee
dol•l,3
pr tnt •. •rayon ? •
read •, ra.von
cati .ol- (r~n. vol)
prlnt •, -Voh~ • •. vol
end do
end progo'H .Ol-_sphere
Exercice 7.4
a)
b)
s ubroutire tr i (t)
impl icit oone
integer, d i œnsi on (:), i ntent ( inout) :: t
integer : : temp 1 pour l 1 echange de deux elements du tableau
i nteger : : i . j
do i • 1. s ize (t) - 1 ! ou s i ze(t,1)- 1
do j • i+l. s i ze (t)
i f (t( i ) > t(j)) then ; te111> • t( i ) ; t( i ) • t(j) t(j) • temp ; end i f
erd do
erd do
end s u.brout i ne t ri
Exercice 7 .5
Exercice 7.6
furet ion prod (a, b)
impl i cit none
real, dhnension (:), intent (in) :: a, b J profils implicites
O>rrec:tion des exc.-cices
Exercice 7.7
sulrout lne "*"te ()
lnteger :: - l s • 0 1 stati(Jle cor lnltl1llsee (save facultatif)
lnteger : : ll•lœ • 1 1 statique cor lnltlillsee (Hve facultatif)
- l s • nappels • 1
If {nappels >- l t.lœ) then
print • . . ... appel •. ll•tte, ' foh · -·
li11ite • 1i11ite • 10
erd if
erd subroutlne coinpte
program test
isip l icit rone
integer. paraneter .. nfois • 10000
integer :: i
do i • l. nfo i s
ca 11 OOlllPt• ()
end do
end program test
Exercice 7 .8
recursive fonction acker (11, n) result (res)
integer, \ ntent (i n) : : 111, n
i nteger : : res
If ( (11<0) .aro. (n<O) ) tllen
res • 0
e lseif (11 - 0) then
res • n • 1
e l se if ( n •• 0) then
res • acker (11· l. 1)
e l se
res • acker (11- 1. acker (11. n- 1) )
end if
end fonction acker
Chapitre 8
Exercice 8.1
:bonjour lllO: bonjo:
Exercice 8.2
• ab cd -ghi jd
-' he ll · ."boy"
I
Correction des exerciœs
Exercice 8.3
program canptage
i mpt ic i t none
integer . par aœter : : lgmt • 26
character (len-•), par aœter : : lettre • ' e'
i nteger : : nbl • 0, i
character (len-l !JOOt) : : IOOt
print • , 'donnez un not'
read •. JOOt
do i • 1. len_tri m (IOOt)
if ( rot( i:i ) "" lettre) nbl • nbl + 1
end do
pri nt *, 1 votre IOOt 0091POr te • , nb l, 1 fo i s la lettre lettre
end prcgr a11 0091Ptage
Exercice 8.4
progra11 suwressi on_de_ lettres
i 11Pl i c i t none
integer , paraœter :: lgtexte • 80
integer pos
character ( len• l). paraœter : : lettre • 'e'
character ( len• lgtexte) : : texte
Exercice 8.5
progra11 concatenati on_intel l i gente
impl i c i t none
i nterface
foncti on concat (chi. ch2)
character (len• •) : : chl. ch2
dlaracter (1en- 1en_triln(dll)+len_tr im(ch2)•1) .. concat
en:I funct i on concat
end i nterface
Exercice 8.6
program tri _cha ines
i apl ic i t none
i nteger, paraœter : : lgch • 10
char acter (len• lgch). di mens ion (4) :: tab • &
(/ •fortran 90". •pascal •. "langage C •. *bas i c • /)
! attent ion, toutes les constantes do i vent avoir la 111e111e longueur
i nterface
subroutine tri (t. lg)
integer, i ntent ( i n) : : lg
character (le,,. lg). d imeŒ ion (:). intent ( inout) ..
end s ubrout i ne tri
end i nterface
Chapitre 9
Exercice 9.1
progra• tableau_s tr·uctures
ilnpf iclt none
i nteger, paraoneter : : nef • 4
integer :: 1
type point
char acter ( fer>-1 ) :: nan
ree l : : x. y
end type poi nt
twe (point). dlonens lon (nef ) : : t s
dol • l ,nef
prlnt • , .,... (1 caractere) et ooordoone.. (2 reels)"
r11d •, ts (1)
end do
prlnt • • • uste des points foomïs•
prlnt • . ts
end
Exercice 9.2
progra11 tabl eau_struc tures
lmplf cl t none
l nteger . paraonet er :: nef • 4
Correction des e>erciœs
su.brout i ne lecture ( t)
imp li c i t oone
type P<li nt ; se~ence 1 on redec lare le type point
character ( len·l) : : nom 1 faute de m1wx
real :: x. y 1 (N is1 1 i deal sera d 'utili ser
erd type poi nt 1 un IOOdule
type (point ), diœnsion ( : ), intent (out ) : : t
int~r :: i
do i • 1. size (t)
pr int • , •nom (1 caractere) et ooordonnees (2 reels)•
read •, t ( i )
erd do
end su.brout i ne lecture
Exercice 9 .3
progr• sone_vecteœs
i11>1iclt nore
type -.iecteur : seq.1ence
re•I :: x : real :: y : real n
end twe vectetr
interface
functlon s . - (•, b)
t1P0 (vecteur), ln1en1 (ln) :: a, b
t1P0 (vecteur) : : s.-
eOO funct ion some
end lnterhœ
type (vecteur) : : vl • wecttir(I. 3. 5), v2 • vecteur(5, 3, 1), w
w - ·~ (vl. "2)
print • . 'vl •, vl
prlnt • • 'v2 •• "2
print •, 'sOllle : • , w
end
Chapitre 10
Exercice 10.1
pr~. . tab_~
iop llclt none
real, dt.enslon (:,:), 1lloc1t1ble :: •t
lnteger :: n, ollolt
Correction des exercices
interface
subroutine i nit (a); real. diaensi on ( :.: ) , intent (out) :: a
end su.broutine i ni t
subrout ine affiche (a) real. diaension (:,:). i ntent (in):: a
erx:I subroutine affiche
end i nterfaoe
print •, 'donnez la taille : ' ; read •. n
allocate ( mat(n,n). stat • allok)
if (a llok > 0) then
print •, 'allocat ion i mpossi ble '
stop
end i f
ca ll init (mat)
call aff idle (mat)
dea llocate (mat)
end
Exercice 10.2
A 5.0000000
B 7 .0000000
c 1.0000000 1.0000000
0 2. 5000000 2. 5000000 2 .5000000 2. 5000000
0 5 .0000000
Correction des eJCercices
Exercice 10.3
program proc:edure_gestion_chaine
ilnpl icit none
char acter ( len-60). pointer : : ad ch
i nterface ! seule la premiere i nterface est indispensable ici
subroutine alloc (ad) char acter ( len-60), P<li nter : : ad ; end si.brout ine a lloc
subroutine lit (ch) ; char acter ( l en• 60). i ntent (out) :: ch
end subrout i ne 1i t
subroutine ecr i t (ch) : char acter (len-60). i ntent ( i n) :: ch
end s ubro ut i ne ecrit
end interface
nullify (adch)
ca 11 alloc (adch)
cal l l it (adch)
call ecrit (adch)
end
élëmen1airc. 87 identifica1Cur. 8
in1rinsèquc. 1SS idin1 (fonction). 378:419
prédéfinie. 29 IEE (>l•ndard). 413
rcltui\'c aux tibleaux. 88 ioor (fonc1ion). 33S
iypc. 1 S7 if(insiruc1ion). 6;42;48;SO
u1iliso1ion. 1S7 ifari1hmé1iquc (insiruction), 379;420
form (poramèirc). 287;292;3 14;318 ifix (fonclion). 378;4 19
forma1. 133: 134 imbrication
cor1·cspondanccs. 134 de choix. 45
dans une cntré<.:-son ie, 120 de S1111c1urcs. 2 14
dcscrip1cur. 120: 121; 133 im1>lici1 (instruction), 370
é1iquc11c. 121 im1>lid1 none (instruction), 24
fixe. 13 im1llici1c ( lypc). 23
inS1rue1ion. 121:293 in (gairc). 1SI
libre. S:9: 116:119: 192:294:298 includc (directive). 3 79:420
frac1ion (fonction). 328 index (fonc1ion). 199:332
indice (d'un tableau). 7S
G ini1hdi531ion
G (dcscrip1cur). 3S8;361 de chaines. 191
générique (procédure). 26S de >INCIUr13. 212
genre (d13 nrgurncnis). 1SI; 153 de 1nblcaux. 93:94
gesiion dynomiquc. 24 1;249 de lnblc:iux de chnines, 205
globillc (vnrioblc). 148 de variables. 167
go 10 (ins1ruc1ion). 67 inou1 (!,•"ire). IS2
goto a.~signé (instructton), 380;420 inquirc (inslruction), 317
go10 calculé (ill<ll'uclion), 377;41 8 Ïl\'ill'UCI ÎOll
GT (01>era1cur). 33 allocaic. 227:242;244
assign. 3 80:420
H backspacc. 319
héri1agc. 384 block dalll. 376:418
hétérogène (fichier). 291 call 14S
homogène (fichier). 291 close. 288:316
bêle (procêwrc). 147:148 common. 374:416
hugc (fonc1ion). 329 cycle. 61 :64:6S
dn10. 417
1 d'nffccllllion. 2S:80:81: 107
1(dcscrip1cur). 122: l 28;3S8 d'ècri1urc. 132; 133:3 11
iochar (fonction). 331 d'cnirèe-soriic. 3 11
iond (fonciion). 33S da10. 376
ibclr (fonciion). 33S de branchement. 42
ibiis (fonelion). 33S de choix. 4 1
ibsc1 (fonclion). 33S de conirolc. 4 1
ichar (fonciion). 33 1 de lcciurc. 132; 133 ;3 1 1
450 Index
ê1<nduc, 78 logical. 21
expr""5ion. 82:83:85: 112 nocion de. 16
fonc1ions, 88 rcol. 18
fonc1ion.s élémentaires. 87 scalaire, 1S
implici1<, 206 simple. 1S
indice, 75 structure, 209
initialisation. 93;94;205 varit1ntcs. 349
lœturc, 109: 11 0
01>érntcurs. 86 u
opérations globales, 80 ubound (lbnction), 34 1
11ointcur. 238 unairc (opérateur), 26
1irofil. 78:84 unit (paramètre),
profil ajuslllblc. 161 287:311:312:314:317;31 g
1>rofil implici1c. 162 uni1êdccompilation, 146;151
rang. 78 uni1ê >Umdard. 295
rêsuhai d'w1c fonction. 170 unpack (fonction). 342
section. 95: 103:10U 10 use (ins1ruc1ion). 257:262:263
1aiDc, 78
1>illc (d'lln 1ablcou). 78
iampon. 125: 130 "
\'atiablc
auioma1ique. 165:223
ian (fonclion), 327
ianh (fonc1ion), 327 de coniràlc. 56
glooole. 148
iargct (ottribul), 232
initialisation. 167
thcn, 43
tiny (fonction), 330 locale, 144; 165; 167;202
slilliquc. 165
transfcr (fonction), 345
vul'Îantc. 349
tl'ansposc (fonction), 344
n·im (fonction), 334 vecteur d'indK:cs. 100
vectoriel (cuicui). 60
truc (constante), 23
vcrify (fonc1ion). 333
ty)>c
abmait. 2 76 w
chaine. 186 w(dcscrip1cur). 130
chan1c1cr, 186 whcrc (ins1ruc1ion). 106: 107
complcx. 353 wri1c (ins1ruc1ion). 287:293:300
dêclantlion. 3 wri1c (para~irc). 318
dêri\'ê, 210
domoinc, 19 X
double prccision. 20 X (dc5Crip1cur). 124:362
entier, 17
flottan t. 18 z
im1>licitc, 23 Z (descripteur). 358
instruction. 2 10 zone étiqucuc, 13
intcgcr, 17 zone instruction, 13