Jean-Yves Février
Algorithmique et langages
Cours
La place de la programmation
Dans le référentiel
Le cours que vous êtes en train de lire concerne la programmation en 2e année de BTS, option
administrateur de réseaux locaux d’entreprise.
C’est un cours essentiel pour votre carrière d’informaticien. Certes, vous ne serez normalement pas
amené à développer des programmes comme vos collègues de l’autre option. Cela dit, la démar-
che algorithmique sera toujours présente dans votre métier. L’exemple le plus classique, ce sont
les scripts (shells) qui vous permettront d’automatiser considérablement votre travail... si vous êtes
capable de les écrire. Pour cela, la maîtrise des boucles et des tests est indispensable.
Dans le référentiel de la formation, ce cours est inclus dans le savoir S3 DAIGL (développement
d’applications informatiques et génie logiciel) avec l’analyse. Plus précisément, nous traiterons
ici le savoir S35 du référentiel intitulé conception et développement d’applications à l’aide d’un
langage de programmation procédural.
Je vous avoue que vous avez étudié le plus gros en première année puisque le tronc commun en
programmation correspond à ce que vous, administrateurs réseaux, devez savoir.
3
8 3987 TG PA 00
Ce cours vous apportera quelques compléments mais sera pour l’essentiel l’occasion de réviser et
de mettre en œuvre les notions étudiées en première année.
Si vous aviez des difficultés l’année dernière en programmation, donnez-vous une chance : le
recul, l’approche différente puisque les exigences ne sont plus les mêmes... Tout cela peut vous
permettre, non pas d’adorer la programmation, mais au moins d’en assimiler les bases sans trop
de difficulté. À l’examen (épreuve d’étude de cas), vous aurez de l’algorithmique relativement
simple... si vous n’êtes pas totalement allergique à la discipline.
Dans la formation
En formation initiale (en lycée), la seconde année s’étend sur 29 semaines (hors stage), le volume
horaire hebdomadaire de la programmation étant pour votre option d’environ une heure de
cours et une heure de travaux dirigés. Cela représente 60 heures.
Faut-il donc passer 60 heures sur ce support ? Non, sans doute pas, car bien qu’apportant les
mêmes connaissances qu’un cours en lycée (vous n’êtes pas volé), il est présenté de façon plus
concise et l’apprentissage autonome est plus rapide. Néanmoins, il ne faut pas espérer maîtriser
la programmation en lisant d’une traite ce fascicule. Vous devez apprendre à passer du temps sur
les concepts présentés.
Chacun de vous a un rythme de travail différent. La question ne doit donc pas être « combien de
temps passer sur un cours ? », mais « ai-je compris et retenu les concepts présentés ? ». Si la réponse
à cette seconde question est oui, vous pouvez passer à la séquence suivante. Si c’est non, il faut
reprendre la séquence courante un peu plus tard.
En effet, il y a une grande différence entre « comprendre plus ou moins le principe » et « parfaite-
ment assimiler un concept ». Dans le premier cas, le savoir n’est pas assimilé et cela vous bloquera
dans la suite du cours ; dans le second cas, tout ira bien.
Pour chacun des concepts que nous verrons, il faudra d’une part apprendre parfaitement sa défini-
tion (travail de mémoire) et d’autre part identifier ce que cela signifie (travail de compréhension).
4
8 3987 TG PA 00
Organisation
Le fascicule de cours contient différentes choses :
• trois séquences de cours correspondant aux savoirs de S35 ; à la fin de chaque séquence, vous
trouverez une fiche synthèse vous rappelant les choses essentielles (à apprendre !) ;
• des exercices intégrés aux séquences de cours. Vous devez faire ces exercices quand vous arri-
vez dessus puis aller consulter la correction. Attention, ces exercices permettent de vérifier
votre assimilation du cours. Leur corrigé, très détaillé, ne doit pas être négligé : j’y présente
des situations, des techniques, des idées et des raisonnements qui ne sont pas anecdotiques
et font partie intégrante du cours. S’ils ne sont pas physiquement dans le fascicule de cours,
c’est uniquement pour conserver une certaine lisibilité au document ;
• trois séries d’exercices jouant le rôle de travaux dirigés. Elles sont placées à la fin du cours.
Le fascicule d’autocorrection comprend :
• la correction des exercices intégrés aux séquences ;
• la correction des TD.
• la correction du devoir « autocorrectif ».
En plus de vous donner la solution des exercices, j’ai essayé de détailler ces corrections pour envi-
sager les différentes solutions possibles, les erreurs à éviter... Plus que des corrections, ce sont de
véritables éléments de cours. Il ne faut donc pas les prendre à la légère !
Contenu
Les trois séquences abordent les points suivants :
• variables, types et instructions de contrôle dans la 1re séquence ;
• les sous-programmes et les paramètres dans la 2e ;
• les tableaux et les types structurés dans la 3e.
Les séquences ont été définies pour vous aider à établir votre progression. Elles représentent donc
approximativement un volume de travail identique. Le découpage n’est néanmoins pas arbitraire :
les différents concepts ont été répartis au mieux pour que chaque séquence reste cohérente.
Notations
Pour vous aider à identifier les différents constituants du cours, j’ai utilisé les représentations
suivantes :
• tout ce qui est mis en vert doit être appris par cœur. Cela correspond aux définitions ou
explications qu’il est absolument nécessaire de connaître pour s’en sortir en programmation.
Quand je dis apprendre, ce n’est pas retenir pour l’heure qui suit afin d’épater les convives
au prochain repas. Il s’agit d’une vraie leçon, dont vous devez vous souvenir tout au long de
votre vie d’informaticien, ou, plus prosaïquement, au moins jusqu’à l’examen. Ces informa-
tions sont reprises à la fin de chaque séquence dans la fiche synthèse ;
• les exercices intégrés dans les séquences et destinés à vérifier votre compréhension doivent
être faits au fur et à mesure de la lecture du cours. Leur correction se trouve dans le fascicule
correction des exercices. Ils sont présentés sur un fond vert .
5
8 3987 TG PA 00
Quelques conseils
Le seul conseil utile que je puisse vous donner est de garder à l’esprit la fable de La Fontaine
Le lièvre et la tortue : il ne sert à rien de travailler comme un fou en juin ; travaillez plutôt dès
maintenant quelques heures par semaine ré-gu-li-è-re-ment (j’aurais pu écrire régulièrement ou
RÉGULIÈREMENT, mon but étant juste d’insister sur le mot).
La difficulté de l’enseignement par correspondance réside dans le fait que, par définition, vous
êtes seul face au cours, personne n’est là pour vous guider, insister sur l’essentiel ou établir la
progression du cours.
Pour vous aider à suivre un rythme correct, disons que chaque séquence correspond à un travail
d’environ 4 à 6 heures.
Attention à l’environ ! Vous avez sans doute le souvenir de vos études où, pour obtenir un même
résultat, certains travaillaient toute la soirée et d’autres se contentaient d’être présents en cours. Il
en est de même ici. Les 5 heures ne sont qu’un ordre de grandeur signifiant juste que 15 minutes,
ce n’est pas assez, mais 25 heures, c’est trop.
Retenez qu’il vaut mieux passer 8 heures sur une séquence et la comprendre parfaitement, que
faire exactement 300 minutes (5 heures) en passant à côté de l’essentiel.
De plus, le cours contient des dizaines de petits exercices à faire au fur et à mesure. Plus vous
passerez du temps dessus (et c’est conseillé), plus vous risquez de dépasser les 5 heures.
Sommaire
Séquence 1 : Variables et instructions 7
Séquence 2 : Procédures et fonctions 35
Séquence 3 : Tableaux, structures et types 53
Travaux dirigés 1 81
Travaux dirigés 2 89
Travaux dirigés 3 93
Devoir « autocorrectif » à ne pas envoyer à la correction 95
6
8 3987 TG PA 00
Séquence 1
Variables et instructions
Durée indicative : 5 heures
Dans cette séquence, nous allons reprendre les éléments clés de la première année.
Capacités attendues
• Se souvenir du cours de l’année dernière
• Avec le recul, maîtriser ces concepts
Contenu
1. Introduction .............................................................................................. 8
2. Le programme ......................................................................................... 8
2A. Syntaxe générale.......................................................................................... 8
2B. Commentaire ................................................................................................ 9
4. L’alternative ............................................................................................ 21
5. Les boucles (répétitives) .................................................................... 23
5A. Tant que… faire .......................................................................................... 23
5B. Répéter… jusqu’à ....................................................................................... 25
5C. Pour ............................................................................................................. 26
5D. Conclusion sur les boucles ......................................................................... 29
6. Application .............................................................................................. 30
Synthèse
7
8 3987 TG PA 00
Séquence 1
1. Introduction
Ma grande idée est que l’informatique n’a rien inventé : elle copie tous ses concepts de
ce qui l’entoure.
Autrement dit, les concepts que les informaticiens manipulent ne sont que des métapho-
res des choses de la vie réelle. De plus, rien n’est jamais inutile ni incohérent en informa-
tique. C’est ce qui en fait l’élégance. Lorsque quelque chose ne nous semble pas logique,
c’est généralement parce qu’il nous manque des éléments théoriques.
Nous allons travailler de la façon suivante : je vais vous demander de définir précisément
chaque concept étudié en première année. L’objectif est de vous plonger dans vos souve-
nirs et de vérifier si vous maîtrisez réellement ces différentes notions. Il faut donc jouer le
jeu et répondre sérieusement. Ne vous contentez pas de répondre oralement voire dans
votre tête ! Prenez le temps de réfléchir et de rédiger votre réponse.
Je vous proposerai ensuite ma définition puis quelques exemples.
2. Le programme
Exercice 1
Commençons simplement : qu’est-ce qu’un programme ? Comment l’écrit-on ? Comment s’exé-
cute-t-il ? Quelle est la différence entre programme et algorithme ?
8
8 3987 TG PA 00
Variables et instructions
Il est important de se souvenir qu’une instruction peut en contenir d’autres. Ainsi, exé-
cuter une alternative ou une boucle peut conduire à exécuter dix instructions (nous y
reviendrons).
La syntaxe générale d’un algorithme (sans sous-programme pour l’instant) est :
var
déclaration des variables
début
instructions
fin
2B. Commentaire
2B1. Rôle du commentaire
Il est nécessaire de placer des commentaires dans un programme. Ils ne sont destinés
qu’au développeur et sont totalement ignorés par le compilateur.
Vous mettrez des commentaires pour expliquer le déroulement de vos algorithmes :
• pour identifier les différentes étapes ;
• pour expliquer des instructions complexes ou des indices de boucle malaisés à com-
prendreå.
Le commentaire est utile à tous :
• faire l’effort de rédiger une explication vous oblige à formaliser les choses beaucoup
plus que lors de la simple écriture du code. Cela peut vous permettre de détecter
une erreur ;
• si vous devez intervenir sur votre programme quelques jours ou semaines plus tard,
vous ne comprendrez plus les parties complexes de vos algorithmes. Un commen-
taire vous rafraîchira la mémoire. À défaut, vous devrez recommencer le processus
intellectuel vous ayant amené à ce code. Et ça, c’est assez humiliantç ;
• dans le cas d’un développement professionnel en entreprise, vous interviendrez
constamment sur du code qu’un autre aura rédigé, soit parce que vous travaillerez
à plusieurs, soit tout bonnement parce qu’il faut toujours maintenir les anciennes
applications. Or, chacun possède sa propre logique et ses tics de programmation.
Du coup, lire un code sans commentaire peut se révéler très complexe. Et face à une
instruction bizarre, il faudra beaucoup réfléchir pour déterminer si c’est un bug (à
corriger) ou une astuce de programmation ;
å Par exemple, si une boucle va de l’indice i à i+j+2, il est sans doute intéressant d’expliquer
pourquoi la valeur finale contient « +2 » et pas « +1 » ou n’est pas simplement i+j. En effet, c’est
typiquement sur ce genre de choses que le développeur produit des bugs.
ç Je vous assure que voir un bout de code que l’on a écrit et ne plus réussir à comprendre ce qu’il
signifie, c’est vraiment humiliant. Et après, plein de questions malsaines viennent à l’esprit, du
genre « est-ce que je serais encore capable d’écrire un code aussi efficace ? ».
9
8 3987 TG PA 00
Séquence 1
La paraphrase
Réservez le commentaire pour les parties compliquées du code et ne faites pas de tra-
duction en français des instructions.
Par exemple, envisageons ce bout de code :
Exercice 2
Concernant ce code, que pensez-vous du commentaire suivant :
« On prend la case i+1 de table2 pour la mettre dans la case i+3 de table1 pour toutes les
valeurs de i allant de 22 à LongueurTab+3. » ?
å Lorsque vous intervenez sur un petit morceau de code, vous n’êtes pas au fait de l’ensemble de
l’application.
10
8 3987 TG PA 00
Variables et instructions
Le verbiage
Un commentaire doit être écrit :
• dans un français irréprochable pour lever toute ambiguïté. L’objet d’un commen-
taire, c’est d’expliquer. S’il n’est pas compréhensible, il ne sert à rien ;
• de façon concise. Plus vos commentaires sont brefs et tranchants, plus ils seront
exploités.
3A. Définition
Exercice 3
Définissez variable et type en précisant bien le lien entre les deux. Expliquez ce
qu’est la déclaration de variable et à quoi elle sert.
var
âge : entier
Je viens de déclarer la variable entière âge. Plus précisément, je viens de réserver un
emplacement mémoire (où dans la mémoire ? ce n’est pas mon problème) de taille suffi-
sante pour y stocker une valeur entière. Cet emplacement mémoire est nommé âge.
11
8 3987 TG PA 00
Séquence 1
3B2. Exemple
Nous allons prendre l’exemple de mes deux octets. Sous Delphi, les deux octets
01100010 11001001 sont la représentation en mémoire de choses très diversesé :
• la chaîne de caractères «bÉ». Étant constituée de deux caractères, elle occupe deux
octets en mémoire. Notez que rien n’est simple : peut-être qu’en vrai, mon pro-
gramme a stocké une chaîne de 5 caractères (par exemple «XbÉTy») en mémoire et
que, en prenant mes 16 bits au hasard, j’ai extrait ceux codant les 2e et 3e caractères
de cette chaîne ;
• les deux caractères b et É (donc deux valeurs indépendantes mais stockées dans des
zones mémoire contiguës) ;
• le tableau de deux octetsè [98,201] ;
• les deux octets 98 et 201 (donc deux variables indépendantes) ;
å Enfin, certains langages ne demandent pas de type (PHP) ou peuvent s’en passer (VB). Le com-
pilateur se débrouille alors pour déterminer tout seul le type de la variable (si vous écrivez une
instruction i := 1, il déterminera que i est un entier) ou il utilise un type générique (variant)
permettant, au prix d’un gros gâchis de ressources et d’une nette dégradation des performances,
de stocker n’importe quel type de donnée de base. Tout cela pour vous dire qu’il faut typer
ses variables dès que le langage l’y autorise.
ç Attention aux homonymes ! Le bit informatique est un nom masculin et sans e. C’est vraiment
une coquille à éviter, à l’oral comme à l’écrit.
é Ce qui suit est exact car j’ai exploité la documentation de Delphi pour connaître les modes de
codage. Je ne vous les explique pas, il faut me faire confiance.
è L’octet (type Byte sous Delphi) est un entier allant de 0 à 255 codé sur 8 bits (un octet).
12
8 3987 TG PA 00
Variables et instructions
• le motå 51554 ;
• l’instruction assembleur bound ecx, ecxç ;
• l’entier courté –13982 ;
• deux valeurs booléennes vrai et vrai (ou le tableau de deux booléens [vrai, vrai]) ;
• …
Mes deux octets peuvent donc être interprétés de multiples façons et, sans plus de préci-
sion, je n’ai aucun moyen de savoir quelle valeur retenir puisque toutes sont valides. Pour
trancher, je dois impérativement connaître le type de la valeur stockée. Vous remarque-
rez en passant que rien ne distingue deux valeurs indépendantes d’un tableau de deux
valeurs. Nous reviendrons dessus dans la séquence 3, paragraphe 2.
Quand j’accède à la mémoire, je dois donc savoir quoi y chercher. Par exemple, si je sais
que mes deux octets stockent la valeur :
• d’un mot, je n’ai qu’à appliquer les règles de codage des mots : un mot m compris
entre 0 et 65 535 sera codé sur deux octets successifs x et y tels que m = x + y*256.
Ici, x et y valent respectivement 98 et 201 donc m = 98 + 201*256 = 51 554 ;
• de deux caractères (qu’ils soient dans un tableau ou indépendants ne change rien),
j’applique les règles de codage des caractères : chacun est représenté par son code
ASCII. Or, les caractères de code 98 et 201 sont respectivement b et É ;
•…
å Le mot (Word) est un entier entre 0 et 65 535 codé sur 16 bits (deux octets).
ç Que fait cette instruction ? Je n’en sais rien et cela n’a aucune importance.
é L’entier court (SmallInt) est un entier entre –32 768 et 32 767 codé sur 16 bits.
13
8 3987 TG PA 00
Séquence 1
3D. Exemple
3D1. Début de programme
Nous sommes au début du programme, aucune variable n’est définie et la mémoire est
vide. Mais que veut dire vide ? En fait, il y a toujours quelque chose, par exemple les
données du programme que vous venez de quitter ou des valeurs aléatoires dépendant
de l’état électrique de la mémoire. Les octets correspondants sont néanmoins réputés
libres, dans la mesure où ce qu’ils contiennent n’a pas de signification pour nouså. C’est
pour cette raison que vous devez initialiser vos variables avant usage : pour éviter de
récupérer des données stockées par d’anciens programmes.
å Un policier venant arrêter quelqu’un et ne le trouvant pas chez lui dira à son supérieur
« L’appartement était vide. » Le déménageur, une fois avoir enlevé toutes vos affaires, dira « l’ap-
partement est vide ». Vous êtes d’accord que ce ne sont pas les deux mêmes vides ?
14
8 3987 TG PA 00
Variables et instructions
var
Taille : mot
Nom : chaîne[7] // chaîne de 7 caractères
L’application va alors réserver quelque part là où il y a de la place (pour le moment,
partout) deux octets pour le mot et sept pour la chaîne puis mettre à jour le tableau des
variables.
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
Taille mot D2 1 22 2 246 235 222 109 20 170 225 55
Nom chaîne[7] B4 2 24 240 41 108 85 45 230 15 145 55
3 73 213 65 214 206 56 245 41 92 96
4 224 73 221 153 180 124 122 119 8 211
Notez qu’il ne s’est rien passé en mémoire de A1 à J4. Seul le tableau des variables a
été modifié. Cela dit, dès ce moment, les cellules D2, E2 et B4 à H4 contiennent quelque
chose pour le programme (la valeur de ses variables), raison pour laquelle elles sont
encadrées et écrites en noir. Si vous accédez à la variable :
• Taille, l’application ira chercher ce qui se trouve en D2 et E2 et l’interprétera comme
un entier de type mot ;
• Nom, l’application interprétera le contenu de B4 à H4 comme les codes ASCII des
différents caractères constituant la chaîne.
Afficher (Taille)
Afficher (Nom)
15
8 3987 TG PA 00
Séquence 1
Taille := 51554
Nom := «février»
Que fait l’application ? Elle cherche dans le tableau des variables à quel endroit de la
mémoire se trouve Taille (elle commence à l’octet D2 et comme c’est un mot, elle se con-
tinue sur E2). Elle y stocke le nombre 51 554 codé, nous l’avons vu, par les deux octets
98 et 201ç.
Ensuite, c’est le tour de Nom. Nous avons vu précédemment que pour stocker une chaîne,
on stockait successivement les codes ASCII de chaque caractère. Au final, on obtient :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
Taille mot D2 1 22 2 246 235 222 109 20 170 225 55
Nom chaîne [7] B4 2 24 240 41 98 201 45 230 15 145 55
3 73 213 65 214 206 56 245 41 92 96
4 224 102 233 118 114 105 101 114 8 211
(Ici et dans les tableaux suivants, les changements dans l’état de la mémoire sont en gras.)
16
8 3987 TG PA 00
Variables et instructions
Modification de Nom
J’appelle alors la fonction Majuscule pour mettre en majuscule la première lettre du
nom. Comme ma chaîne est en fait un tableau de caractères, il me suffit de modifier le
premier caractère de ce tableau. Cela donne le code suivant :
Nom[1] := Majuscule(Nom[1])
Que fait l’application ? Il y a trois étapes :
1. on recherche dans le tableau des variables la position du premier caractère de Nom.
C’est évidemment la position de Nom lui-même, soit B4 ;
2. on récupère la valeur en B4 et on lui retranche 32å. On passe donc du code ASCII 102
(caractère f) au code 70 (caractère F) ;
3. on stocke le résultat (soit 70) dans la zone mémoire du premier caractère de Nom,
soit B4.
Cela nous donne l’état de la mémoire suivant :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
Taille mot D2 1 22 2 246 235 222 109 20 170 225 55
Nom chaîne [7] B4 2 24 240 41 100 201 45 230 15 145 55
3 73 213 65 214 206 56 245 41 92 96
4 224 70 233 118 114 105 101 114 8 211
3D6. Simplification
Maintenant que nous avons vu le fonctionnement précis de l’allocation mémoire, nous
allons nous empresser de tout simplifier. En effet, à notre niveau, il est inutile de gérer
le codage des données. Nous allons donc estimer que les cases D2 et E2 contiennent
directement la valeur de Taille et que les cases B4 à H4 contiennent directement celle de
Nom. Cela donne la représentation suivante :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
Taille mot D2 1 22 2 246 235 222 109 20 170 225 55
Nom chaîne [7] B4 2 24 240 41 51556 45 230 15 145 55
3 73 213 65 214 206 56 245 41 92 96
4 224 Février 8 211
Les zones mémoire qui ne sont pas liées à notre programme ne changent pas puisque
leurs valeurs n’ont pas de sens pour nous.
Du coup, supposons que j’exécute ces deux instructions divisant par deux Taille et met-
tant tout Nom en majuscules :
Taille := Taille/2
Nom := Majuscule(Nom)
å Car le code ASCII de chaque lettre majuscule est égal au code de sa minuscule moins 32.
17
8 3987 TG PA 00
Séquence 1
18
8 3987 TG PA 00
Variables et instructions
Affectation
La syntaxe est :
variable := expression
Lorsque cette instruction est exécutée, que se passe-t-il ? Quelque chose qu’il faut
apprendre :
1. L’expression est évaluée (calculée).
2. Le résultat est affecté à la variable (l’ancienne valeur de la variable est perdue car
remplacée par la nouvelle). L’expression et la variable doivent être de même typeç.
å Enfin, la théorie le voudrait : affecter une chaîne de caractères à un booléen n’a pas de sens.
Néanmoins, les affectations cohérentes sont admises : on peut affecter un entier à un réel (les
valeurs entières faisant partie des réels, tout entier peut être converti en réel), un entier court à un
entier long…
ç Avec les mêmes tolérances que pour la saisie. On dispose de plus de fonctions permettant de
changer le type d’une valeur (qui peut s’en trouver modifiée). La plus connue est int, convertissant
par troncature un réel en un entier. Ainsi, i étant un entier, i := 3.5 est incorrect. En revanche, i :=
int (3.5) est valide puisque int (3.5) est égal à la valeur entière 3. On affecte donc bien un entier
à une variable entière.
19
8 3987 TG PA 00
Séquence 1
3F2. En lecture
On récupère la valeur de la variable pour l’afficher ou pour s’en servir. Exemple :
Afficher "Boujour"
Afficher "à tous !"
produira au choix l’un des deux résultats suivants :
20
8 3987 TG PA 00
Variables et instructions
4. L’alternative
On parle d’instruction de contrôle car l’alternative ne réalise rien par elle-même : pas
d’affichage, pas de modification de variable… Son objet est de déterminer en fonction
d’une condition quelles instructions – qui elles, feront quelque chose – seront exécutées.
L’alternative contrôle (dirige) l’exécution du programme.
Exercice 4
Allez, sans lire la suite, donnez-moi la syntaxe de l’alternative (l’instruction si) et expliquez
son fonctionnement.
L’alternative a pour syntaxe générale si alors sinon, la branche sinon étant facultative (ce
qui donne si alors). La syntaxe associe une expression booléenne et des suites d’instruc-
tions (dans le alors et dans le sinon) :
si booléen si booléen
alors alors
instructions_oui instructions_oui
sinon fin si
instructions_non
fin si
S’il n’y a aucune instruction dans le sinon, on ne met pas le mot sinon et on obtient le
si alors.
Lorsque l’exécution arrive à l’instruction si, voici ce qui se passe :
1. Le booléen est évalué (calculé).
2. En fonction de la valeur obtenue :
2.1. si elle vaut vrai, les instructions de la branche alors sont exécutées puis l’exécu-
tion passe à l’instruction suivant le si (l’éventuelle branche sinon est ignorée) ;
2.2. si elle vaut faux, les instructions de la branche sinon sont exécutées (s’il y en a)
puis l’exécution passe à l’instruction suivant le si (la branche alors est ignorée).
En paraphrasant l’instruction, on peut dire que :
Si le booléen est vrai, alors on exécute les instructions du alors et sinon on exécute
celles du sinon.
21
8 3987 TG PA 00
Séquence 1
L’illustration suivante montre les instructions exécutées selon la valeur du booléen. Ce qui est
en couleur est réalisé par l’application de façon automatique. (C’est la traduction du si.)
ALGORITHME TRACE DE L’EXÉCUTION
instr_1 instr_1
instr_2 instr_2
instr_3 instr_3
si booléen évaluation booléen
alors booléen booléen
instr_o_1 vrai faux
instr_o_2
instr_o_3 instr_o_1 instr_n_1
sinon instr_o_2 instr_n_2
instr_n_1 instr_o_3
instr_n_2
fin si
instr_4 instr_4
instr_5 instr_5
Exercice 5
Pour s’entraîner un peu, écrivez un programme permettant de déterminer si un nombre est
pair ou impair. Une petite aide : le nombre n est pair si n mod 2 vaut 0 (l’opérateur mod ren-
voie le reste de la division entière).
Je vous rappelle l’existence de l’instruction selon cas. Je ne la reprends pas ici car c’est une
autre forme du si. Il ne faut pas pour autant l’oublier !
Je vous disais que l’informatique n’a rien inventé. Et bien, dans le langage courant, voici
exactement une instruction si :
si j’ai le bts
alors
je paye le champagne puis je cherche du travail
sinon
je redouble
å C’est un euphémisme : cela n’augmente pas la lisibilité mais rend le code lisible. Dit autrement,
un code non indenté est illisible.
22
8 3987 TG PA 00
Variables et instructions
Si j’inverse le test :
Exercice 6
Donnez-moi les trois boucles (syntaxe et fonctionnement).
23
8 3987 TG PA 00
Séquence 1
instr_1
instr_2 instr_1
instr_3 instr_2
instr_3
tant que booléen faire
évaluation booléen
instr_tq_1
instr_tq_2 booléen booléen
vrai faux
instr_tq_3
fin tant que instr_tq_1
instr_4 instr_tq_2
instr_5 instr_tq_3
instr_4
instr_5
Exercice 7
Vous pensez avoir compris ? Oui, bien sûr, puisque vous utilisez cette instruction depuis un
an maintenant. Bien. Dites-moi alors ce que ces quatre blocs d’instructions vont afficher (en
expliquant évidemment). Faites attention, il y a de nombreux pièges.
1er bloc 2e bloc
3e bloc 4e bloc
24
8 3987 TG PA 00
Variables et instructions
répéter
instructions
jusqu’à booléen
instr_1
instr_1
instr_2
instr_2
répéter
instr_rjq_1 instr_rjq_1
instr_rjq_2 instr_rjq_2
instr_rjq_3 instr_rjq_3
jusqu’à booléen évaluation booléen
instr_3 booléen booléen
vrai faux
instr_3
Exercice 8
Vous pensez avoir compris ? Dites-moi alors ce que ces deux blocs d’instructions vont afficher
(en expliquant évidemment).
répéter répéter
saisir "Entrez l’âge : ", âge x := x/0
jusqu’à (âge > 0) et (âge < 120) jusqu’à x = x
25
8 3987 TG PA 00
Séquence 1
5C. Pour
Syntaxe
Les deux boucles précédentes réalisaient un nombre d’itérations variable. La boucle pour
est utile dès que l’on connaît le nombre d’itérations à réaliser. Voici la syntaxe :
å Dans la précédente version de ce cours, je ne présentais pas cette règle de validation, les com-
mentaires des exercices 7 et 8 me semblant suffisant. Mais après avoir retrouvé cette erreur très
fréquemment dans vos copies, j’ai compris que je devais la formaliser dans le cours. Et la voilà.
26
8 3987 TG PA 00
Variables et instructions
Lorsque entier3 vaut 1 (c’est le cas général), on peut omettre la clause pas. Le principe
général est le suivant :
Variable est une variable entière appelée l’indice de la boucle. L’idée est que l’indice
va aller de entier1 à entier2 en ajoutant entier3 à chaque fois. À chaque étape (itéra-
tion), le corps de la boucle sera exécuté.
La progression de l’indice
å J’ai un ami qui a essayé d’aller de 10 à 13 en ajoutant –1. Eh bien, il essaye toujours. (Sa sœur
a voulu prendre le problème dans l’autre sens et a tenté d’aller de 13 à 10 en ajoutant 1. Et bien,
elle tente toujours.) Je ne les fréquente plus, ils sont trop occupés à essayer pour l’un et à tenter
pour l’autre.
27
8 3987 TG PA 00
Séquence 1
instr_4
instr_5
Exercice 9
Vous pensez avoir compris ? Dites-moi alors ce que vont afficher à l’écran ces deux blocs d’ins-
tructions (en expliquant évidemment).
1er bloc 2e bloc
Exercice 10
pour i de 1 à 5
afficher i
i := i-1
fin pour
Ainsi :
L’optimisation du code n’est pas un argument magique autorisant à faire n’importe quoi.
Exercice 11
Transformez la boucle suivante en boucle répéter puis en boucle tant que :
pour i de 1 à 10
afficher i
fin pour
29
8 3987 TG PA 00
Séquence 1
Exercice 12
Exercice 13
Supposons que j’aie donné cet algorithme en début de paragraphe 5 et non à la fin. Donnez
alors son code pour qu’il ait exactement le même sens que celui de l’exercice 12.
Attention, c’est un vrai exercice, ce n’est pas une ânerie. Le code ne sera plus le même.
Exercice 14
Et si je vous disais que, quel que soit votre degré de compréhension, il faut lire le paragraphe
5 cinq fois pour bien s’en imprégner, quel algorithme obtiendriez-vous ?
Exercice 15
« En fait, la vie n’est pas simple. Travailler raisonnablement, c’est faire preuve de sérieux mais
pas d’acharnement. Nous dirons donc que vous devez lire le paragraphe 5 au maximum 5 fois.
Dès que vous l’avez compris, vous passez à la suite du cours et si, au bout de 5 lectures, ce
n’est toujours pas clair, vous devez quand même passer à la suite. »
Si ce conseil vous est donné en fin de paragraphe 5, quel est l’algorithme correspondant ?
[Passez du temps sur cet exercice.]
6. Application
Nous allons mettre tout ce savoir (boucles, alternative et variables) en pratique.
Exercice 16
Je vous demande d’écrire un algorithme affichant les heures et minutes de 00:00 (minuit) à
23:59. Je veux donc : 00:00, 00:01, 00:02… 23:58, 23:59.
Attention, il y a une petite difficulté pas évidente à voir !
30
8 3987 TG PA 00
Synthèse
Les variables
Quelques définitions
Type
Le type d’une variable décrit sa nature, ce qu’elle contient (entier, booléen,
réel, caractère…).
Variable
C’est un espace mémoire contenant une valeur d’un type donné.
Déclaration
La déclaration d’une variable contient un nom de variable explicite (qui a un
sens pour le développeur) et un type. Elle entraîne la réservation d’un espace
mémoire de taille suffisante (fonction du type) pour y stocker la valeur. Le
nom de la variable est associé à l’espace mémoire.
Manipulation
Saisie
Fonctionnement
1. La chaîne de caractères chaîne est affichée à l’écran.
2. L’application attend que l’utilisateur rentre (saisisse au clavier) quelque chose.
3. La valeur saisie est affectée à la variable (valeur et variable doivent être de
même type).
31
8 3987 TG PA 00
Affectation
variable := expression
Fonctionnement
1. L’expression est évaluée (calculée).
2. Le résultat est affecté à la variable (l’ancienne valeur de la variable est per-
due car remplacée par la nouvelle). L’expression et la variable doivent être
de même type.
Affichage
Alternative
si booléen si booléen
alors alors
instructions_oui instructions_oui
sinon fin si
instructions_non
fin si
Le fonctionnement de cette instruction est le suivant :
1. Le booléen est évalué (calculé).
2. En fonction de la valeur obtenue :
2.1. Si elle vaut vrai, les instructions de la branche alors sont exécutées puis
l’exécution passe à l’instruction suivant le si (l’éventuelle branche sinon
est ignorée).
2.2. Si elle vaut faux, les instructions de la branche sinon sont exécutées
(s’il y en a) puis l’exécution passe à l’instruction suivant le si (la branche
alors est ignorée).
Si le booléen est vrai, alors on exécute les instructions du alors et sinon on
exécute celles du sinon.
Boucles
Tant que
32
8 3987 TG PA 00
Tant que le booléen est vrai, on exécute les instructions dans la boucle.
Répéter
répéter
instructions
jusqu’à booléen
Le fonctionnement de cette instruction est le suivant :
1. Les instructions incluses dans la boucle sont exécutées.
2. Le booléen est évalué. S’il est faux, on retourne à la première étape. Sinon,
on passe à l’instruction suivant le répéter.
On répète les instructions jusqu’à ce que le booléen soit vrai.
Pour
33
8 3987 TG PA 00
2.2 [si entier1 > entier2 et donc entier3 < 0]
Si l’indice de boucle est supérieur ou égal à entier2,
alors les instructions incluses dans la boucle sont exécutées
sinon l’exécution de la boucle est terminée et on passe à l’instruction
suivant le pour.
3. On incrémente l’indice de boucle de entier3 et on retourne à l’étape 2.
Dans une boucle pour, l’initialisation puis l’incrémentation de l’indice est géré
par l’application. Il est donc interdit (et d’ailleurs sans intérêt) de modifier dans
le code la valeur de l’indice. Vous n’utilisez cette variable qu’en lecture.
Une boucle pour peut toujours être écrite sous la forme d’un tant que ou d’un
répéter. Mais cela oblige le développeur à gérer lui-même l’indice. C’est moins
lisible et source d’erreur. Ainsi, à chaque fois que c’est possible, on emploiera une
boucle pour à la place d’un tant que ou d’un répéter.
Quelques remarques sur les boucles
L’exécution d’une boucle regroupe tous les traitements qui sont réalisés jusqu’à
ce que l’exécution passe à l’instruction suivant la boucle.
Une itération d’une boucle, c’est une exécution des instructions incluses dans la
boucle.
Dans le cas de boucles imbriquées (l’une est à l’intérieur de l’autre), chaque itéra-
tion de la boucle externe entraîne une exécution complète de la boucle interne.
Aphorisme
L’optimisation du code n’est pas un argument magique autorisant à faire n’im-
porte quoi.
34
8 3987 TG PA 00
Séquence 2
Procédures et fonctions
Durée indicative : 5 heures
Dans cette séquence, nous terminons l’étude des éléments clés de la première année.
Ñ Capacités attendues
• Se souvenir du cours de l’année dernière
• Avec le recul, maîtriser ces concepts
Ñ Contenu
1. Introduction ............................................................................................ 36
1A. Définition .................................................................................................... 36
1B. Définition du sous-programme ................................................................. 36
1C. Intérêt .......................................................................................................... 36
2. Les procédures et les fonctions ...................................................... 36
2A. Définitions .................................................................................................. 36
2B. Syntaxe ....................................................................................................... 37
3. Les paramètres ...................................................................................... 40
3A. Syntaxe ....................................................................................................... 40
3B. Mode de passage ....................................................................................... 41
3C. Corrigeons l’exercice .................................................................................. 42
3D. Une fonction est une procédure qui s’ignore .......................................... 46
Synthèse
35
8 3987 TG PA 00
Séquence 2
1. Introduction
1A. Définition
Les sous-programmes ne constituent pas des notions complexes. Pourtant, les étudiants
font souvent des erreurs assez grossières. Nous allons tenter d’éviter cela en reprenant
quelques concepts essentiels.
Il existe deux types de sous-programmes : les procédures et les fonctions.
1C. Intérêt
La grande force des langages de programmation, c’est que l’utilisateur peut écrire ses
propres sous-programmes. C’est utile pour plusieurs raisons :
• lorsque vous exécutez plusieurs fois la même suite d’instructions, soit vous les écri-
vez plusieurs fois, soit, et c’est préférable, vous écrivez une seule fois le sous-pro-
gramme correspondant et vous l’appelez autant de fois que nécessaire ;
• lorsque vous écrivez une application, il est plus simple de diviser le travail en petites
tâches autonomes (sous-programmes) car vous divisez la difficulté ;
• un sous-programme est autonome vis-à-vis de l’application. Vous pouvez le copier/
coller dans un autre programme si vous en avez besoin. C’est la réutilisation du
code que nous reverrons avec la programmation objet (option développeur d’ap-
plications).
2A. Définitions
On utilisera une fonction lorsque le sous-programme renvoie un seul résultat. Dans
le cas contraire (il renvoie aucun ou plusieurs résultats), il faut une procédure.
Quand je parle de résultat, c’est au sens large. Ce peut être un paramètre en entrée qui est
modifié. Par exemple, j’envoie un tableau au sous-programme qui me le retourne trié.
De même que la boucle pour est un cas particulier de boucle tant que (tout pour peut
s’écrire sous la forme d’un tant que), la fonction est un cas particulier de procédure. Nous
le vérifierons dans le paragraphe 3D.
36
8 3987 TG PA 00
Procédures et fonction
2B. Syntaxe
2B1. Introduction
Résumons ce qui précède :
Un sous-programme réalise une tâche précise, il prend des valeurs en entrée et
retourne aucun résultat (procédure), un seul (fonction) ou plusieurs (procédure). Un
sous-programme doit être autonome (donc doit pouvoir être utilisé dans un pro-
gramme par simple copier/coller). Un sous-programme est constitué d’instructions.
Pour réaliser cela, chaque sous-programme devra posséder :
• un nom permettant de l’appeler lorsque l’on souhaite s’en servir ;
• la description des données en entrée et en sortie (les paramètres) ;
• les instructions réalisant le traitement du sous-programme ;
• les variables locales au sous-programme.
Nous allons voir comment traduire cela sous la forme de procédure ou de fonction. Pour
le moment, on ne détaille pas les paramètres.
2B2. La procédure
Voici la syntaxe :
procédure nom (paramètres)
var
déclarations
début
instruction1
...
instructionn
fin
Comment utiliser la procédure dans un programme ? On l’appelle par son nom comme
on le ferait avec une instruction.
37
8 3987 TG PA 00
Séquence 2
2B3. La fonction
Voici la syntaxe :
fonction nom (paramètres) : type
var
déclarations
début
instruction1
...
instructionn
Retourner (expression) // Retour du résultat
fin
Rappelez-vous que la fonction renvoie toujours un résultat. C’est pourquoi :
• à la fin de l’en-tête (ligne contenant le mot-clé fonction), on indique le type du
résultat ;
• il faut explicitement indiquer quel est le résultat renvoyé par la fonction. Je choisis
la convention de l’instruction Retourner dont le paramètre contient le résultat.
Dans ce cas, exécuter Retourner termine la fonction (il est donc sans objet de mettre
des instructions derrière).
Il est classique d’oublier de renvoyer le résultat (ici, cela revient à oublier d’appeler
Retourner). Dans ce cas, la fonction renvoie un résultat indéterminé (aléatoire). C’est
vraiment une erreur bête mais classique (mais bête). Comme je l’ai trop souvent vue dans
vos copies, je rajoute en règle de validation :
Une fonction renvoyant toujours un résultat, son code comprend toujours le type du
résultat dans l’en-tête et se termine toujours par un appel à l’instruction Retourner
pour renvoyer un résultat précis.
Comment utiliser une fonction ? On l’appelle par son nom mais ce n’est pas une instruc-
tion. Par exemple, sin(8) est un nombre, pas une instruction. On utilisera donc une fonc-
tion renvoyant une valeur d’un type donné à la place d’une expression de même type.
Je reviens sur le prêt-à-apprendre précédent. Lorsque je dis que la fonction doit se ter-
miner par un appel à Retourner, cela signifie que toute exécution de la fonction, quelles
que soient les instructions exécutées (cela dépend des tests) doit se terminer par un
Retourner.
Pour comprendre cela, prenons l’exemple de Nom1 et Nom2 :
fonction Nom2 (paramètres) : type
38
8 3987 TG PA 00
Procédures et fonction
Dans les deux cas, Retourner est la dernière instruction exécutée donc tout va bien : les
fonctions renvoient toujours un résultat.
Prenons maintenant l’exemple de Nom3 et Nom4 :
39
8 3987 TG PA 00
Séquence 2
Comme une fonction renvoie toujours un résultat, il faut s’assurer que, quels que
soient les paramètres, la dernière instruction exécutée est toujours Retourner.
3. Les paramètres
Cela terminera l’étude des sous-programmes. Attention, c’est encore une notion très
importante.
3A. Syntaxe
Nous avons vu que les sous-programmes possédaient des paramètres. Ce sont les don-
nées qui entrent et sortent du sous-programme.
La syntaxe sera simple : on indique le nom de chaque paramètre suivi d’un « : » et de son
type. On retrouve l’obligation d’associer toute donnée à un type. Les paramètres sont
séparés par une virgule.
Exemples :
procédure Échange (a : entier, b : entier) fonction Maximum (n1 : réel, n2 : réel) : réel
début début
… …
fin Retourner (…)
fin
Je voudrais attirer votre attention sur un point très important.
Nous avons déjà vu qu’un sous-programme formait un ensemble cohérent et indé-
pendant de tout programme. Ainsi, le nom des paramètres est tout à fait arbitraire
et n’a aucun lien avec les variables du programme.
40
8 3987 TG PA 00
Procédures et fonction
Si l’on nomme les paramètres, c’est pour pouvoir y faire référence dans le corps du sous-
programme. Le nom est juste une étiquette n’apportant aucune sémantique à l’applica-
tion. (Mais c’est utile pour le développeur. Dire Paramètre1 est moins explicite que Âge.)
Pour être certain que vous en êtes conscient, je vous conseille de mettre systémati-
quement des noms différents aux paramètres et aux variables.
Exemple :
procédure Retraite (âge : entier, var DateRetraite : entier, var MontantPension : entier)
Âge est passé par valeur, DateRetraite et MontantPension par adresse.
Vous allez faire un petit exercice pour fixer tout cela.
41
8 3987 TG PA 00
Séquence 2
Exercice 17
Envisageons l’algorithme suivant :
Algorithme échange
var
e1, e2 : entier
début
saisir "Entrez le premier nombre ", e1
saisir "Entrez le second nombre ", e2
afficher "Vos nombres dans l’ordre : ", e1, " et ", e2
échange (e1, e2)
afficher "Vos nombres permutés :", e1, " et ", e2
fin
Indiquez comment sont passés les deux paramètres dans la procédure échange : par valeur ou
par adresse ? Donnez et expliquez l’affichage réalisé par le programme quand on l’exécute.
Modifiez le mode de passage (qui doit devenir par adresse si l’on était par valeur ou l’inverse)
puis donnez à nouveau l’affichage du programme.
42
8 3987 TG PA 00
Procédures et fonction
Quel que soit le mode de passage des paramètres, le programme débute de la même
façon. Les deux variables globales sont créées. Elles ne sont pas encore initialisées donc
leur contenu est indéterminé pour le programme. Cela donne :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 ??? ???
e2 entier f1 2
3
4
(Ici et dans les tableaux suivants, les changements dans l’état de la mémoire sont en gras.)
On exécute les deux saisies. L’utilisateur rentre 50 et 100. La mémoire est alors :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 50 100
e2 entier f1 2
3
4
L’application affiche :
• Vos nombres dans l’ordre : 50 et 100
Nous appelons ensuite la procédure Échange. Et là, il y a deux cas.
43
8 3987 TG PA 00
Séquence 2
On réalise l’affectation c := a :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 50 100
e2 entier f1 2
a entier c3 3 50
b entier g4 4 100
c entier c5 5 50
Puis a := b :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 50 100
e2 entier f1 2
a entier c3 3 100
b entier g4 4 100
c entier c5 5 50
Enfin b := c :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 50 100
e2 entier f1 2
a entier c3 3 100
b entier g4 4 50
c entier c5 5 50
La procédure est terminée. Que se passe-t-il alors ? Et bien, les variables temporaires (ici c) et
les paramètres (ici, a et b) sont supprimés comme le montre l’état de la mémoire suivant.
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 50 100
e2 entier f1 2
3
4
On revient dans le programme principal et on affiche alors :
Vos nombres permutés : 50 et 100.
Bref, les valeurs de e1 et e2 n’ont pas changé.
44
8 3987 TG PA 00
Procédures et fonction
Il est évident que modifier a revient à modifier e1 (et modifier b, c’est modifier e2).
De la même façon, si mon frère lave la voiture de son frère, la mienne devient propre
(cela fonctionne car je n’ai qu’un frère).
Nous arrivons dans la procédure. La variable locale c est créée.
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 50 100
e2 entier f1 2
a entier a1 3 ???
b entier f1 4
c entier c3 5
On réalise l’affectation c := a :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 50 100
e2 entier f1 2
a entier a1 3 50
b entier f1 4
c entier c3 5
Puis a := b :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 100 100
e2 entier f1 2
a entier a1 3 50
b entier f1 4
c entier c3 5
Puis b := c :
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 100 50
e2 entier f1 2
a entier a1 3 50
b entier f1 4
c entier c3 5
45
8 3987 TG PA 00
Séquence 2
La procédure est terminée. Que se passe-t-il alors ? Eh bien, les variables temporaires (ici c) et
les paramètres (ici, a et b) sont supprimées comme le montre l’état de la mémoire suivant.
Tableau des variables État de la mémoire
VARIABLE TYPE ADRESSE DÉBUT A B C D E F G H I J
e1 entier a1 1 100 50
e2 entier f1 2
Exercice 18
Écrivez un algorithme réalisant la saisie de deux nombres et affichant le plus grand. Il devra
contenir et utiliser un sous-programme renvoyant le plus grand de deux nombres. Attention
aux modes de passage des paramètres.
Exercice 19
Écrivez un algorithme calculant la remise, le port et le net à payer (qui vaut montant facture
– remise + port) associés à une commande, sachant que :
• la remise totale est de 5 % à partir de trois articles achetés, 10 % dès cinq et 15 % pour
huit ou plus ;
• le port est de 7,7 € pour une commande de moins de 77 € (remise comprise), 4 € de 77 à
150 € et gratuit au-delà.
L’exercice est simple. Je ne vous demande donc pas de faire « juste » le programme, mais de
réfléchir très sérieusement aux données nécessaires et aux sous-programmes. Je vous demande
notamment de faire un sous-programme pour calculer la remise et un autre pour le port.
La conclusion de l’exercice mérite d’être apprise. D’ailleurs, nous l’avions déjà vu en fin
de paragraphe 2B3. Retournez-donc le lire !
Exercice 20
Prenons une petite fonction toute simple : Minimum, qui renvoie le minimum de deux nom-
bres entiers. Écrivez cette fonction ainsi qu’une instruction faisant appel à elle.
Dans un second temps, recommencez sous la forme d’une procédure Minimum.
46
8 3987 TG PA 00
Procédures et fonction
Exercice 21
Généralisons : prenez la syntaxe générale d’une fonction (voir paragraphe 2B3) et transfor-
mez-la en procédure.
J’insiste sur le fait que cette transformation ne signifie pas que vous deviez dorénavant
vous passer de fonction. Je vous ai proposé ces exercices pour vous aider à bien assimiler
les paramètres et les sous-programmes.
Mais, partout où l’on peut écrire une fonction, on écrit une fonction !
Vous pouvez, dés maintenant, faire et envoyer à la correction le devoir 1 (voir fascicule
« Devoirs » réf, 3987 DG).
47
8 3987 TG PA 00
Synthèse
Sous-programme
Rôle et constitution des sous-programmes :
• un sous-programme réalise une tâche précise ;
• il prend des valeurs en entrée et retourne aucun résultat (procédure), un
seul (fonction) ou plusieurs (procédure) ;
• un sous-programme doit être autonome (donc pouvoir être utilisé dans un
programme par simple copier/coller) ;
• un sous-programme est constitué d’instructions.
On utilisera une fonction lorsque le sous-programme renvoie un seul résultat. Dans
le cas contraire (il renvoie aucun ou plusieurs résultats), il faut une procédure.
Toute fonction peut s’écrire sous la forme d’une procédure. En pratique (avec
un langage de programmation et non plus un algorithme), on peut se trouver
face à des limitations techniques : la majorité des langages n’acceptent comme
résultat de fonction que des types de base (entier, booléen, chaîne, caractère…).
Ainsi, même si d’un point de vue algorithmique il est correct de vouloir faire une
fonction, vous devrez parfois la coder sous la forme d’une procédure.
Une procédure est une instruction, une fonction est une expression du même
type que son résultat. Ainsi :
• partout où vous mettez une instruction, vous pouvez mettre l’appel à une
procédure ;
• partout où vous mettez un booléen (exemple : dans un test ou une boucle),
vous pouvez mettre l’appel à une fonction renvoyant un booléen ;
• partout où vous mettez un entier, vous pouvez mettre l’appel à une fonction
renvoyant un entier ;
• plus généralement, partout où vous mettez une expression d’un type T, vous
pouvez mettre l’appel d’une fonction renvoyant une valeur de type T.
Procédure
Syntaxe de la procédure :
49
8 3987 TG PA 00
Séquence 2
Fonction
Syntaxe de la fonction
Paramètres
Nous avons déjà vu qu’un sous-programme formait un ensemble cohérent et indé-
pendant de tout programme. Ainsi, le nom des paramètres est tout à fait arbitraire
et n’a aucun lien avec les variables du programme.
Pour être certain que vous en êtes conscient, je vous conseille de mettre systéma-
tiquement des noms différents aux paramètres et aux variables.
On distingue deux types de passage de paramètre :
• le passage par valeur : même si la valeur du paramètre change dans le sous-pro-
gramme, la variable correspondante dans le programme principal reste inchan-
gée. Le paramètre est une variable locale au sous-programme initialisée avec la
valeur de la variable du programme ;
• le passage par adresse : si la valeur du paramètre change dans le sous-
programme, la variable correspondante est modifiée dans le programme
principal. Le paramètre est à la même adresse mémoire que la variable du
programme ; concrètement, le paramètre est la variable.
Le passage par valeur est le mode par défaut. Pour passer un paramètre par
adresse, on met le mot var devant.
Remarque
Je ne la reprends pas ici, mais j’aimerais bien que vous reteniez la façon dont sont
implantés les deux modes de passage de paramètres (nous l’avons vu dans le paragra-
phe 3C). Cela vous sera utile pour votre apprentissage.
50
8 3987 TG PA 00
Séquence 3
Tableaux, structures et types
Durée indicative : 5 heures
Nous allons terminer les rappels de première année en étudiant les tableaux. Nous
introduirons ensuite les types de données définis par l’utilisateur, les structures et
les tableaux de structures.
Ñ Capacités attendues
Savoir définir ses propres types de données
Ñ Contenu
1. Introduction ............................................................................................ 52
2. Les tableaux ........................................................................................... 53
2A. Sémantique ................................................................................................. 53
2B. Syntaxe ....................................................................................................... 54
2C. Remarque sur l’indice ................................................................................ 58
2D. Tableau, élément et indice ........................................................................ 59
2E. Gestion mémoire ........................................................................................ 61
2F. Indice et contenu ........................................................................................ 65
3. Définir ses propres types .................................................................. 65
3A. Introduction ................................................................................................ 65
3B. Syntaxe de la définition ............................................................................ 67
3C. Intérêt des définitions de type ................................................................. 67
3D. Les types structurés ................................................................................... 67
3E. Quand utiliser une structure ? .................................................................. 70
Synthèse
51
8 3987 TG PA 00
Séquence 3
1. Introduction
Dans un premier temps, nous allons réviser les notions relatives aux tableaux.
Dans un second temps, nous découvrirons des notions nouvelles. Nous apprendrons
notamment à définir nos propres types de données (oui, je dis bien type !).
Définir un type est très simple, il suffit de l’écrire. L’intérêt, c’est de définir un type struc-
turé (nous l’étudierons finement).
Enfin, nous mélangerons les deux notions de la séquence pour faire des tableaux de
structures, des structures de tableaux, des structures de tableaux de tableaux de struc-
tures de tableaux…
Cette séquence est très importante pour les deux options :
• c’est la dernière séquence pour l’option administrateur de réseaux. Les concepts
abordés sont les plus importants du cours car ce sont les plus pointus. De plus, la
manipulation de tableaux de structures est un sujet d’examen classique. Cela ne
pose pas de difficulté si l’on maîtrise bien les notions, mais, si l’on est fragile, c’est
redoutableå ;
• pour les étudiants de l’option développeur d’applications, cette séquence est une
charnière entre les concepts de base et avancés (pointeurs et objets). Les types
structurés sont très importants car ils apportent une partie de la syntaxe et du for-
malisme utilisés en programmation objetç.
å Raison pour laquelle c’est en effet un bon thème d’examen : l’algorithme à écrire est court, mais
ne se devine pas.
ç Je suis certain que les administrateurs réseau qui ont lu ce paragraphe regrettent de ne pas avoir
choisi l’autre option. (D’ailleurs, pour lire un paragraphe consacré aux développeurs, il faut déjà
avoir des doutes sur son orientation, non ?)
52
8 3987 TG PA 00
Tableaux, structures et types
2. Les tableaux
2A. Sémantique
2A1. Qu’est-ce qu’un tableau ?
Un tableau est avant tout une variable. À ce titre, il possède un nom, un type et une
valeur. Cela dit, un tableau est une variable complexe. (La notion de variable complexe
est une invention didactique de ma part. Ne l’employez donc pas sans explication dans
un examen.)
Attention, je n’utilise pas complexe dans le sens difficileå mais dans le sens qui contient
plusieurs éléments.
Ainsi, j’oppose :
• les variables simples (classiques) qui n’ont qu’une valeur. Il s’agit des variables entiè-
res, booléennes et de type caractère, chaîne…
• les variables complexes, qui sont des variables contenant plusieurs variables. Par
cohérence, nous dirons qu’en tant que variable, elles ne possèdent qu’une valeur
(la leur)ç, mais que cette valeur est décomposable en plusieurs valeurs. Il s’agit des
tableaux et des structures.
Le tableau est une variable complexe dans la mesure où :
• un tableau d’entiers contient plusieurs variables entières ;
• un tableau de caractères contient plusieurs variables caractères…
On ne parlera donc pas de tableau (tout court), mais de tableau de quelque chose,
sous-entendu de « tableau contenant des éléments d’un type donné ». Un tableau ne
peut contenir que des éléments de même typeé.
Mélanger des entiers et des caractères dans un tableau est donc interdit. Pourquoi ? Cela
vient de la nature du tableau que nous abordons maintenant.
53
8 3987 TG PA 00
Séquence 3
2B. Syntaxe
2B1. Déclaration
Un tableau peut avoir une dimension, deux dimensions (comme une feuille de calcul
Excel), trois dimensionsç… ou n dimensions.
La déclaration est simple : on donne le nom du tableau, suivi du mot-clé tableau puis,
entre crochets la taille (nombre d’éléments) de chaque dimension. On indique ensuite le
type de tous les éléments précédé du mot-clé de :
var
Nom : tableau[dim1, dim2, dim3,… , dimn] de type
å C’est la même problématique que sous Excel. Une feuille de calcul étant un tableau
à deux dimensions, une cellule est identifiée par ses deux coordonnées (par exem-
ple, C5 pour colonne C et ligne 5). Lorsqu’une cellule prend de l’importance et contient
une valeur qui possède une sémantique, il faut la nommer. Ainsi, en programmation,
les variables sont par défaut nommées mais on peut les définir dans un tableau. Sous
Excel, c’est le contraire : elles sont par défaut dans un tableau mais on peut les nommer.
Ne poussez cependant pas trop loin la comparaison. Sous Excel, on peut nommer toute cellule de
la feuille ; un même espace mémoire pourra donc à la fois avoir un nom et être dans le tableau. En
programmation, un espace mémoire sera associé soit à un élément d’un tableau, soit à une variable
indépendante, mais pas les deux à la fois. (En vrai, si, c’est possible, mais pas à votre niveau.)
ç Si la feuille Excel est un tableau à deux dimensions, on peut considérer le classeur comme un
tableau à trois dimensions, la première identifiant la feuille et les deux suivantes la cellule dans
la feuille.
54
8 3987 TG PA 00
Tableaux, structures et types
Exemples :
Moyennes : tableau[20] d’entiers
Je dispose de vingt variables entières pour stocker les moyennes (arrondies à
l’entier le plus proche) de mes vingt étudiants.
Notes : tableau[5,20] de réels
J’ai réalisé cinq interrogations ce trimestre. Chacun de mes vingt étudiants pos-
sède une note par interrogation. Ce tableau me permet de les stocker.
Attention, c’est moi qui décide arbitrairement que le premier indice représente
les interrogations (et variera donc de 1 à 5) et le second les élèves (de 1 à 20).
NotesBis : tableau[20,5] de réels
J’ai vingt étudiants dans ma classe, tous ayant une note à chacun des cinq con-
trôles que j’ai réalisé ce trimestre.
Attention, c’est moi qui décide arbitrairement que le premier indice représente mes
étudiants (et variera donc de 1 à 20) et le second les contrôles (de 1 à 5).
Concernant ces trois exemples, je vous dois une remarque importante.
Comme nous rédigeons un algorithme et pas un programme dans un langage spécifi-
que, la syntaxe doit rester flexible. Toute déclaration donnant sans ambiguïté les trois
caractéristiques d’un tableau (le fait que c’est un tableau, ses dimensions et le type de
ses données) est correcte. Il est évident qu’une grammaire rigide dans un algorithme est
un non-sens.
C’est pourquoi j’ai décidé de respecter autant que possible la langue française en me
permettant :
• le pluriel pour les types (entiers et réels au lieu d’entier et réel).
• l’apostrophe (d’entiers et non de entiers).
Observez bien les deux tableaux Notes et NotesBis. Ils sont identiques car ils modélisent
la même réalité. Les deux versions sont absolument équivalentes, tout traitement fait
avec l’un pouvant être fait avec l’autre par une simple permutation des indices. En revan-
che, une fois que l’on a choisi une de ces deux versions, il faut s’y tenir : si l’on définit
Notes avec le deuxième indice représentant l’étudiant, pas question de changer d’idée
en cours de route.
Souvent, trop souvent, mes étudiants me demandent ce que l’on doit mettre en ligne
et en colonneå dans le tableau. C’est parce qu’ils n’ont pas compris que cela ne change
rien. Tout dépend de votre perception des données.
Par exemple, sous Excel, que je parle de la cellule ligne 5, colonne 6 ou de la cellule
colonne 6, ligne 5, c’est pareil ! Cela dit, pour éviter toute ambiguïté ou interrogation
déraisonnableç, Excel utilise des chiffres pour identifier les lignes et des lettres pour
å La ligne étant la première dimension, la colonne la seconde… ou l’inverse ! Cela n’a toujours
pas d’importance tant que l’on conserve les mêmes notations.
ç Déraisonnable car, nous venons de le voir, tant que vous restez cohérent, il n’y a pas d’erreur
possible.
55
8 3987 TG PA 00
Séquence 3
les colonnes. Ainsi, que vous parliez de la cellule F5 ou 5F, tout le monde comprend.
D’ailleurs, si vous permutez les coordonnées, Excel est capable de corriger comme le
prouve cette copie d’écran :
Exercice 22
Je veux stocker toutes les notes de ma section de BTS. Déclarez les tableaux correspondant aux
différentes situations suivantes, de plus en plus précises :
• ma section contient 60 étudiants et je stocke leur moyenne annuelle ;
• en fait, j’ai 2 classes de BTS (1re et 2e année) contenant chacune 30 étudiants. Je
stocke toujours leur moyenne annuelle ;
• j’ai 2 classes de BTS de 30 étudiants chacune et je stocke les vingt notes que cha-
cun obtient sur toute l’année scolaire.
Exercice 23
Je veux stocker toutes les notes de ma section de BTS. Déclarez les tableaux correspondant aux
différentes situations suivantes, de plus en plus précises :
• j’ai 2 classes de BTS de 30 étudiants chacune et l’année est divisée en 2 semestres.
J’effectue 10 contrôles par semestre ;
• le BTS est divisé en 11 matières. Chacune attribue 10 notes par semestre à chacun
des 30 étudiants de mes 2 années de BTS.
En fait, dans mon lycée, il y a deux BTS (IG et NRC). Si l’organisation du BTS NRC est identique
à celle du BTS IG (mêmes nombres d’années, étudiants, semestres, matières et notes), peut-on
regrouper l’ensemble des notes des BTS dans un tableau ? Si oui, donnez sa déclaration. Si non,
dites pourquoi.
56
8 3987 TG PA 00
Tableaux, structures et types
Exercice 24
Avez-vous bien compris ? Dans ce cas, en considérant le dernier tableau de l’exercice précé-
dent, donnez les syntaxes et le principe du traitement (une ligne, n’écrivez pas d’algorithme)
permettant d’obtenir :
• la troisième note d’économie (8e matière) du premier semestre pour l’étudiant 17
en seconde année de BTS IG (1er BTS) ;
• les notes d’économie au troisième contrôle du premier semestre pour tous les
étudiants de seconde année de BTS IG ;
• les notes d’économie au premier semestre pour tous les étudiants de seconde
année de BTS IG ;
• les notes d’économie au premier semestre pour tous les étudiants de BTS IG ;
• les notes d’économie au premier semestre pour tous les étudiants, tous BTS
confondus ;
• les notes d’économie, toutes classes, semestres et étudiants confondus.
Exercice 25
En utilisant le tableau de l’exercice précédent, calculez la moyenne d’économie pour l’ensemble
de mes BTS (toutes années, semestres et étudiants confondus). Faites un sous-programme… et
jouez le jeu du sous-programme qui généralise !
å Vous ne pouvez pas l’avoir oublié car c’était juste au-dessus (paragraphe 2A2) et c’était à
apprendre !
57
8 3987 TG PA 00
Séquence 3
On retiendra :
Pour accéder à un élément d’un tableau, il faut préciser le tableau dont il est ques-
tion puis, au sein de ce tableau, les indices de l’élément voulu.
Syntaxe : on écrit le nom du tableau, suivi entre crochets des indices séparés par
des virgules. Par exemple, pour accéder au troisième élément du tableau Tab (à une
dimension), on écrira Tab[3].
å Cela dit, indicer ainsi (par des valeurs consécutives commençant par un nombre particulier) peut
être utile. Certains langages le permettent d’ailleurs.
ç Je les ai générées par la fonction alea.entres.bornes d’Excel. Elles sont donc bien aléatoires.
58
8 3987 TG PA 00
Tableaux, structures et types
Exercice 26
Je n’ai rien à ajouter, le cas du tableau à une dimension n’est jamais complexe.
59
8 3987 TG PA 00
Séquence 3
Exercice 27
Exercice 28
Je souhaite stocker les températures relevées à 13 h tous les jours d’une année donnée. Mon
objectif est évidemment de réaliser ensuite des statistiques (moyennes pour un mois ou une
saison donnée…). Définissez la ou les variables permettant de stocker toutes ces données.
Attention, c’est moins simple qu’il n’y paraît. Prenez en compte l’usage que je veux faire de
ces données.
Exercice 29
La solution retenue pour l’exercice précédent nous conduit à avoir des éléments qui ne doivent
pas être utilisés. Par exemple, si je veux faire la moyenne des températures d’avril, que penser
du code suivant ?
moyenne := 0
pour i de 1 à 31
moyenne := moyenne + temp[i,4]
fin pour
moyenne := moyenne/31
Proposez une façon efficace de remédier au problème. Par efficace, j’entends une solution uti-
lisable pour tous les mois et pas seulement avril. Vous envisagerez deux solutions : un tableau
ou une fonction.
Exercice 30
Exercice 31
Nous continuons sur la correction de l’exercice 29. Définissez le tableau NbrJours stockant le
nombre de jours de chaque mois puis un sous-programme initialisant le tableau (soit chaque
élément).
60
8 3987 TG PA 00
Tableaux, structures et types
Exercice 32
Écrivez un sous-programme calculant la température moyenne d’un mois donné. Vous utilise-
rez la fonction NbrJours de l’exercice 30.
Exercice 33
Idem, cette fois en utilisant le tableau NbrJours de l’exercice 31. Attention, n’utilisez aucune
variable globale !
å Pour la cinquante-sept mille trois cent quatre-vingt-douzième fois, dire que le premier indice
représente les lignes et l’autre les colonnes est une convention. Prendre l’option inverse ne change-
rait rien. L’important est de rester constant tout au long du programme.
61
8 3987 TG PA 00
Séquence 3
Ce tableau sera en fait stocké en mémoire avec les lignes au bout les unes des autres :
t[1,1] t[1,2] t[1,3] t[2,1] t[2,2] t[2,3] t[3,1] t[3,2] t[3,3] t[4,1] t[4,2] t[4,3]
Ainsi, le compilateur ne gérera pas un tableau de quatre lignes et trois colonnes, mais
un tableau d’une ligne et de 12 colonnes.
Finalement, le tableau t est à deux dimensions pour le développeur mais à une dimen-
sion pour le compilateur. Voici la correspondance des différents éléments :
t[1,1] t[1,2] t[1,3] t[2,1] t[2,2] t[2,3] t[3,1] t[3,2] t[3,3] t[4,1] t[4,2] t[4,3]
t[1] t[2] t[3] t[4] t[5] t[6] t[7] t[8] t[9] t[10] t[11] t[12]
Ainsi, on voit que chaque élément de t à deux dimensions correspond à un unique élé-
ment de t à une dimension et réciproquement. Plus précisément, à chaque couple d’in-
dices ligne,colonne de t à deux dimensions ne correspond qu’un indice colonne dans t à
une dimension. Par exemple, t[3,2], c’est t[8].
Je conserve le même nom de tableau avec les deux représentations pour insister sur le
fait que nous n’avons affaire qu’à un seul tableau, manipulé selon des points de vue
différents.
Maintenant, comment le passage d’un formalisme à l’autre s’effectue-t-il ? Quand vous :
• déclarez var t : tableau[4,3] d’entiers, le compilateur transformera cela en
var t : tableau[12] d’entiers ;
• écrivez t[3,2] := t[1,1] + t[4,3], le compilateur le traduira en t[8] := t[1] +t[12].
La question en suspens, c’est : comment le compilateur passe-t-il d’un format de tableau
à l’autre ? Stocke-t-il toutes les correspondances entre les deux systèmes d’indices ?
un tableau à trois dimensions dans un tableau n’en ayant que deux est moins évident. Et
pour les dimensions plus élevées ? C’est impossible. De même, sur une feuille de papier
(deux dimensions), dessiner des objets plats est évident, représenter une perspective
pour gérer trois dimensions est moins simple et au-delà… on ne sait pas faire.
Finalement, la vraie question à poser, c’est le contraire : pourquoi le langage se fatigue-
t-il à présenter au développeur des tableaux à plusieurs dimensions alors qu’en interne
il ne les gère qu’avec une seule ?
Le langage gère en interne des tableaux à une dimension par obligation ; les calculs à
réaliser pour accéder à une case donnée sont élémentaires pour lui. En revanche, ces cal-
culs seront très complexes pour le développeur et source d’erreurs. Imaginez-vous faisant
une boucle sur un indice d’un tableau à quatre dimensions : traduire cela avec le tableau
linéarisé serait pénible et très peu intuitif ! C’est pourquoi cette tâche est réservée au
compilateur.
La conclusion est amusante : vous manipulez des variables qui n’existent pas. Vos
tableaux à plusieurs dimensions ne sont qu’un habillage destiné à vous simplifier la vieå.
C’est un peu de l’ergonomie !
Les dimensions d’un tableau sont tellement illusoires que l’on peut facilement percevoir
tout tableau comme étant à une seule dimension. Je vous rappelle qu’un tableau con-
tient des éléments d’un type donné qui peut lui-même être un tableau. Ainsi :
• un tableau d’entiers à deux dimensions est un tableau de tableaux d’entiers à une
dimension (une feuille Excel peut être vue comme un tableau de lignes ou de colon-
nes) ;
• un tableau de réels à trois dimensions est un tableau de tableaux de réels à deux
dimensions, soit un tableau de tableaux de tableaux de réels à une dimension ;
•…
åComme les multiples dimensions sont faites pour aider le développeur, vous seriez fort mal
venu de trouver cela complexe.
63
8 3987 TG PA 00
Séquence 3
Voici comment notre tableau t, déclaré t : tableau[4,3] d’entiers, va être stocké (on sup-
pose que les entiers occupent deux octets en mémoire) :
Tableau des variables
VARIABLE TYPE ADRESSE DÉBUT
t entier B2
Vous remarquerez que rien n’indique dans le tableau des variables que j’ai affaire à un
tableau. Pour le compilateur, je n’ai qu’un entier dans les cases B2 et B3. Nous en repar-
lerons.
État de la mémoire
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
A
B
C
Cas général
Tableau t t[1,1] t[1,2] t[1,3] … t[4,3] t[i,j]
(notation à deux dimensions)
Tableau t t[1] t[2] t[3] … t[12] t[(i-1)*3+j] t[i]
(notation à une dimension)
Adresse mémoire du 1er octet B2 B2 B4 B6 … B24 B(2*i)
Vérifions le passage de t[i] à B(2*i) : t[5] devrait être à l’adresse mémoire B(2*5) soit B10.
C’est exact !
Si l’on part de la notation à deux coordonnées, on aura :
t[i,j] = t[(i-1)*3+j] = B(2*((i-1)*3+j)) = B(6*i+2*j-6)
Vérifions : t[4,3] = t[(4-1)*3+3] = t[12] = B(6*4+2*3-6) = B24. C’est parfait !
Cas général
Prenons le cas général d’un tableau t :
• à l lignes et c colonnes ;
• contenant des éléments occupant chacun o octets en mémoire ;
• dont le premier élément est à l’adresse Ba (a représentant le nombre identifiant la
colonne comme précédemment).
Dans ce cas, lorsque le programmeur veut accéder en lecture ou écriture à l’élément
t[i,j], le compilateur ira à l’espace mémoire B(((i-1)*c+j-1)*o+a) et le lira avec les (o-1)
suivants.
64
8 3987 TG PA 00
Tableaux, structures et types
Il est totalement inutile de retenir cette formule. Par contre, elle vous prouve quelque
chose qui faut apprendre :
Un tableau est un ensemble de variables (éléments) de même type. Ces éléments
sont identifiés par des indices permettant au programme d’accéder directement à
l’espace mémoire de l’élément requis. L’accès est donc immédiat.
Je ne vous le démontre pas, mais, faites-moi confiance, pour un tableau à trois, quatre…,
n dimensions, c’est la même chose. La formule sera juste un peu plus complexe !
3A. Introduction
Vous connaissez les types classiques : entier, réel, tableau, booléen, chaîne de caractères,
date…
Et bien, de même que vous pouvez créer vos propres instructions (procédures) et fonc-
tions, vous pouvez créer vos propres types.
65
8 3987 TG PA 00
Séquence 3
Attention, il est impossible de créer le type Teckel puis de définir une variable Nina de
type Teckel. Enfin, c’est impossible si l’on pense au brave animal de chair, de truffe et
de sang.
Je veux dire par là que pour fabriquer nos propres types, nous ne disposons comme
briques que des types de base (de même que pour créer nos propres sous-programmes,
nous n’avions accès qu’aux instructions classiques). Ainsi, pas de miracle.
Imaginez-vous face à un MCD, ébauche d’une informatisation à venir. Prenons par exem-
ple l’entité Client :
CLIENT
date_client représente la date de la première commande du client
num_client
(ce qui permet, par différence avec la date du jour, de connaître
nom_client l’ancienneté du client).
prénom_client
adr_client
tél_client
date_client
L’entité Client possède six propriétés : une date, un entier (l’identifiant) et quatre chaî-
nes (nom, prénom, adresse et téléphone). Lorsque vous manipulerez des occurrences de
Client dans votre application, comment définirez-vous les variables correspondantes ?
Prenons l’exemple concret de l’occurrence Client1.
Pour le moment, la seule solution consiste à définir une variable par propriété :
var
NumClient_Client1 : entier
NomClient_Client1 : chaîne
PrénomClient_Client1 : chaîne
AdrClient_Client1 : chaîne
TélClient_Client1 : chaîne
DateClient_Client1 : date
Maintenant, comment faire pour utiliser l’occurrence dans un sous-programme ? Il faut
passer chacune de ces variables en paramètre. C’est un peu fastidieux !
Imaginez maintenant que j’ai aussi besoin des occurrences Client2, Client3, Client4… Il
me faudrait définir six variables par client. Tout cela n’est pas bien raisonnable.
Je souhaiterais pouvoir définir un type Client, contenant toutes les propriétés de l’entité.
Je pourrais alors définir mes occurrences ainsi :
var
Client1, Client2, Client3, Client4 : Client
Mieux encore, si j’ai 1 000 clients, je pourrais alors les stocker dans un tableau :
var
TabClients : tableau[1000] de Client
Il s’agit de transposer les concepts d’analyse entité et occurrence en concepts de pro-
grammation type et variable.
66
8 3987 TG PA 00
Tableaux, structures et types
type
nom = description
Une fois le type défini, on peut l’utiliser comme n’importe quel type de base (de
même qu’une fois un sous-programme défini, on peut s’en servir comme s’il avait
toujours existé).
Notez bien que l’on déclare un type avec un « = » et une variable avec un « : ». Est-ce
une coquetterie ? Non, il y a une raison sémantique : la définition du type est une équi-
valence puisque le nouveau type est équivalent (égal) à sa description. Au contraire, une
variable est d’un type donné mais n’est pas ce type.
D’un point de vue algorithmique, il est intéressant de faire la distinction pour bien mon-
trer notre compréhension des concepts.
type
Teckel = entier
Une fois mon type Teckel défini, je peux m’en servir comme tout autre type déjà existant.
Je peux notamment définir des variables de ce type :
var
i,j : Teckel
Maintenant, analysons ce que nous venons de faire. Teckel est défini comme étant stric-
tement équivalent à un entier. Ainsi, mes variables i et j, étant de type Teckel, sont de
type entier. En clair, en déclarant deux teckels i et j, j’ai en fait déclaré deux entiers.
Où veux-je en venir ? Et bien, j’ai redéfini le type entier en créant un synonyme. Quel
est l’intérêt de cela ? Strictement aucun, d’autant que le terme Teckel n’est pas très
explicite.
Définir ses propres types n’est intéressant que s’ils sont nouveaux. C’est ce que nous allons
voir dans le paragraphe suivant où nous allons déclarer le type Client du paragraphe 3A.
67
8 3987 TG PA 00
Séquence 3
La syntaxe de définition du type est simple : entre les mots clé structure et fin structure,
on énumère les différentes variables (et leur type) constituant la structure :
type
nom = structure
variable1 : type1
variable2 : type2
...
variablen : typen
fin structure
Les variables constituant le type structuré sont appelées des champs. Toute varia-
ble d’un type structuré possède tous les champs définis dans le type. L’ordre des
champs dans la structure n’a aucune importance.
Exercice 34
var
Cl : Client
Maintenant, comment faire pour indiquer que notre client Cl s’appelle Nina ? Il faut
définir son champ NomClient.
Exercice 35
NomClient := "Nina"
Hélas, cette solution est incorrecte : le compilateur vous dira que la variable NomClient
n’existe pas. Et le compilateur aura raison ! En effet, nous n’avons pas déclaré de variable
NomClient (ou autre), mais une variable Cl contenant un champ NomClient.
Bref, il faut passer par Cl pour accéder à NomClient. C’est assez logique finalement : si nous
avions cinq variables de type Client, utiliser directement NomClient serait ambigu puisque
l’on n’aurait aucun moyen de savoir à laquelle de ces cinq variables on fait allusion.
C’est exactement le même raisonnement que pour accéder à un élément d’un tableau :
on ne dit jamais « je veux l’élément i » mais « je veux l’élément i du tableau t ».
68
8 3987 TG PA 00
Tableaux, structures et types
Quand une variable en contient d’autres (tableau t, structure s), il faut toujours pas-
ser par la variable contenant pour accéder à une des variables contenues :
• pour un tableau t, on met l’indice entre crochets : t[i] identifie l’élément i du
tableau t ;
• pour une structure s, on utilise l’opérateur « . » pour séparer la variable et ses
champs : s.champ identifie le champ champ de la variable structurée s.
Avec un tableau Tab, Tab[i] identifie une variable de même type que les éléments
du tableau. Avec une structure Str contenant un champ Ch, la variable Str.Ch est de
même type que le champ Ch.
Ainsi, si nous avons :
var
a : chaîne
b : tableau[50] de chaînes
c : Bidon
Les trois variables a, b[8] et c.Ch sont absolument équivalentes : ce sont des chaînes de
caractères. La seule chose qui les distingue, c’est la façon dont on les nomme : pour une
variable simple, le nom suffit mais pour une variable incluse dans une autre, il faut pas-
ser par la variable contenant (tableau ou structure) puis spécifier ce que l’on veut (un
élément ou un champ).
å Dans le cours SQL de première année, nous avons vu cet opérateur pour préciser la table d’origine
d’un champ dans une jointure.
ç C’est le même principe que pour les éléments d’un tableau qui sont – je l’ai abondamment
dit – utilisables partout où j’ai des expressions de même type.
69
8 3987 TG PA 00
Séquence 3
Exercice 36
Écrivez un sous-programme permettant d’initialiser une variable de type Client (les valeurs
doivent être demandées à l’utilisateur). Vous ferez deux versions : avec une fonction puis
une procédure.
4A. Introduction
Une fois le type structuré défini, on peut déclarer une variable structurée qui est alors
une variable comme n’importe quelle autre. Elle peut donc faire partie d’une autre
structure.
De même, un tableau est une variable comme une autre. Il peut donc également faire
partie d’une structure.
Dans le même thème, un type structuré est un type comme un autre. On peut donc défi-
nir un tableau contenant des variables structurées.
Nous allons mettre tout cela en œuvre.
å Les langages de programmation modernes proposent des tableaux de taille variable, mais c’est
hors sujet ici.
70
8 3987 TG PA 00
Tableaux, structures et types
71
8 3987 TG PA 00
Séquence 3
Exercice 37
Définissez deux variables : un tableau de quarante éléments et sa variable indiquant le nombre
d’éléments réellement utilisés. Ce tableau servira à stocker les âges de mes étudiants.
Écrivez ensuite un sous-programme remplissant trente-cinq éléments de ce tableau (j’ai une
classe de trente-cinq élèves). Vous mettrez des valeurs aléatoires entre 18 et 23. Pour cela, uti-
lisez la fonction aléatoire(i) renvoyant un nombre entier entre 0 et i-1. À vous de trouver une
formule permettant d’obtenir des valeurs entre 18 et 23. (C’est une réponse à ceux qui se pose
la question de l’intérêt des mathématiques en BTS informatique.)
Exercice 38
Le moment est venu de poser le problème : dans les deux exercices précédents, nous
avons dû systématiquement traîner deux variables : le tableau et la variable associée
indiquant le nombre d’éléments de ce tableau.
Les deux variables sont indissociables. J’insiste : elles forment un tout, un concept cohé-
rent. Cela ne vous dit rien ? Relisez le paragraphe 3E. Nous allons définir un type struc-
turé contenant deux variables : le tableau et le nombre d’éléments de ce tableau.
Exercice 39
Définissez le type puis une variable de ce type. Quelle est la syntaxe pour accéder à un élé-
ment du tableau ?
Reprenons la correction :
type
TableauÂge = structure
Élément : tableau[40] d’entiers
NbrÉléments : entier
fin structure
var
Bts1 : TableauÂge
72
8 3987 TG PA 00
Tableaux, structures et types
Exercice 40
Question finaude : je vous demande d’accéder à un élément du tableau Élément. Mais ce
tableau, il appartient à qui ? Au type TableauÂge ? À Bts1 ? À NbrÉléments ? À une autre
variable ? À un autre type ? Hein ?
Exercice 41
Réécrivez les deux sous-programmes des exercices 37 et 38 en utilisant la structure Bts1.
å Apophtegme du bon professeur Février : « On peut apprendre sans comprendre mais on ne peut
pas comprendre sans apprendre. » Il veut sans doute dire par là que si les bases ne sont pas appri-
ses, les concepts suivants ne seront pas compris. (Et si c’est ce qu’il veut dire, il a raison.)
73
8 3987 TG PA 00
Séquence 3
var
TabCl : tableau[50] de Client
Pour accéder au nom du 8e client, la syntaxe sera : TabCl[8].NomClient, à savoir que l’on
accède au 8e élément du tableau (c’est un client) et, dans cet élément, on accède au
champ NomClient.
Attention, distinguez bien l’indice de tableau et le champ NumClient. Ce sont deux infor-
mations différentes.
Exercice 42
Ne perdons pas nos bonnes habitudes : les clients, cela va, cela vient. Autant dire que je peux
parfois en avoir 120, d’autres fois 470. On supposera que je n’aurai jamais plus de mille clients.
Définissez une structure contenant le tableau de clients et le nombre de clients qu’il contient
comme nous l’avons vu dans le paragraphe 4B.
Exercice 43
Écrivez un sous-programme affichant le nom de chaque client (les clients sont stockés dans une
variable structurée du type défini dans l’exercice précédent).
74
8 3987 TG PA 00
Tableaux, structures et types
75
8 3987 TG PA 00
Synthèse
Les tableaux
On ne parlera pas de tableau (tout court), mais de tableau de quelque chose,
sous-entendu de « tableau contenant des éléments d’un type donné ». Un
tableau ne peut contenir que des éléments de même type. Mélanger des entiers
et des caractères dans un tableau est donc interdit.
Un tableau est un ensemble de variables de même type. Chacune de ces variables
est un élément du tableau. Au sein d’un tableau, chaque élément est identifié
par un numéro appelé indice.
On utilisera un tableau pour stocker un grand nombre de variables équivalentes
et interchangeables (un ensemble de quelque chose : d’adresses, de notes, de
ports réseau…). Le fait que, au sein d’un tableau, chaque élément soit identi-
fié par un indice permet des traitements très puissants avec une simple boucle
pour.
Syntaxe de déclaration :
var
Nom : tableau[dim1, dim2, dim3,… , dimn] de type
Pour accéder à un élément d’un tableau, il faut préciser le tableau dont il est
question puis, au sein de ce tableau, les indices de l’élément voulu. La syntaxe est
simple : on écrit le nom du tableau, suivi entre crochets des indices séparés par
des virgules. Par exemple, pour accéder au troisième élément du tableau Tab (à
une dimension), on écrira Tab[3].
Pour accéder à un élément d’un tableau, il faut fournir une valeur pour chaque
indice (soit un indice par dimension). Toute autre écriture est incorrecte.
Un élément d’un tableau est strictement équivalent à une variable du même
type (un élément d’un tableau d’entiers est un entier, un élément d’un tableau
de chaînes est une chaîne…). L’accès à la valeur d’un élément quelconque du
tableau est immédiat puisque le compilateur n’a qu’un calcul simple à réaliser
pour déterminer l’emplacement de cet élément en mémoire par rapport à la
position du tableau.
Pour accéder à un élément d’un tableau, il faut fournir une valeur pour chaque
indice (soit un indice par dimension).
Un tableau est un ensemble de variables (éléments) de même type. Ces éléments
sont identifiés par des indices permettant au programme d’accéder directement
à l’espace mémoire de l’élément requis. Attention à ne pas confondre l’élément
d’un tableau avec son indice. Bref, ne confondez pas i et t[i].
77
8 3987 TG PA 00
Types
Syntaxe de déclaration
type
nom = description
Une fois le type défini, on peut l’utiliser comme n’importe quel type de base (de
même qu’une fois un sous-programme défini, on peut s’en servir comme s’il avait
toujours existé).
Types structurés
Syntaxe de déclaration
type
nom = structure
variable1 : type1
variable2 : type2
...
variablen : typen
fin structure
Les variables constituant le type sont appelées des champs. Toute variable d’un
type structuré possède tous les champs définis dans le type. L’ordre des champs
dans la structure n’a aucune importance.
Lorsque vous voulez définir une chose décrite par plusieurs valeurs, il faut définir
un type structuré. Dit autrement, un concept doit être représenté par une varia-
ble. Si une variable simple ne suffit pas, on définit un type structuré contenant
toutes les informations nécessaires.
Attention, pour déclarer une variable structurée, il faut avoir préalablement
défini le type correspondant.
78
8 3987 TG PA 00
Tableaux définis dans une structure
Chaque tableau sera accompagné d’une variable entière indiquant le nombre
d’éléments qu’il contient (soit l’indice du dernier élément utilisé).
À chaque fois que vous êtes confronté à un tableau ayant un nombre variable
d’éléments (c’est le cas le plus fréquent), vous devez utiliser une structure (varia-
ble structurée) contenant deux champs :
• le tableau ;
• une variable entière stockant le nombre d’éléments réellement utilisés. Cette
variable doit être mise à jour à chaque évolution du contenu du tableau.
La définition d’un type structuré est alors indispensable pour pouvoir déclarer la
structure.
Les TD qui suivent proposent des éléments de cours : les algorithmes classiques
de parcours des tableaux. Si vous les maîtrisez, vous serez au point pour l’étude
de cas.
79
8 3987 TG PA 00
Travaux dirigés 1 : un seul tableau
L’objet des exercices qui suivent est de mettre en œuvre de façon systémati-
que les concepts vus dans le cours pour que cela devienne un automatisme.
Vous allez donc manipuler tableaux et structures dans tous les sens !
Ces exercices vous permettront également d’étudier les algorithmes classiques
de manipulation des tableaux. Plus que de simples exercices d’application, ils
sont plutôt un complément de cours. Ne les bradez pas !
Enfin, faites-les dans l’ordre, la difficulté étant croissante.
L’année dernière, vous avez étudié les parcours de tableaux et les tris.
Nous allons revoir cela en manipulant un tableau de structures. Comme l’objet de ces exer-
cices est de vous rendre à l’aise avec les structures, nous allons reprendre celles de l’exercice
42, à savoir :
• une structure Client ;
• une structure TabClient contenant un tableau et un entier stockant le nombre d’élé-
ments dans le tableau.
Je vous rappelle les deux types (je renomme le champ NbrÉléments de TabClient en NbrClients
car j’en ai assez de taper le « É ») :
type
Client = structure
NumClient : entier
NomClient : chaîne
PrénomClient : chaîne
AdrClient : chaîne
TélClient : chaîne
DateClient : date
fin structure
TabClient = structure
Élément : tableau[1000] de Client
NbrClients : entier
fin structure
Le champ NumClient est l’identifiant du client au sens analyse (Merise) du terme. Ses diffé-
rentes valeurs sont donc uniques.
Dans tous les exercices, vous devez écrire les sous-programmes les plus généraux possibles.
Pour ne pas alourdir les algorithmes, ne prenez néanmoins pas en compte le cas du tableau
vide. On supposera que ce sont les programmes appelant qui testeront ce cas.
81
8 3987 TG PA 00
Exercice 1
Parcours complet d’un tableau
Nous supposons ici que le champ AdrClient contient la ville du client. Écrivez un sous-pro-
gramme comptant le nombre de clients habitant la ville d’Aubusson. Modifiez ensuite ce
sous-programme pour qu’il retourne le nombre de clients habitant une ville donnée.
Exercice 2
Recherche d’un élément 1/2 (parcours du tableau sous condition)
Écrivez un sous-programme renvoyant le nom d’un client (NomClient) d’un numéro donné.
Attention, le numéro de client est stocké dans le champ NumClient, ce n’est pas l’indice!
Vous écrirez deux sous-programmes, un pour chacune des deux hypothèses suivantes :
1. on suppose que le client existe forcément ;
2. on suppose que le client demandé peut ne pas exister.
Si je ne vous avais rien précisé sur l’existence du client, laquelle des deux hypothèses auriez-
vous dû prendre?
Exercice 3
Recherche d’un élément 2/2 (parcours du tableau)
Dans l’exercice précédent, vous cherchiez un client précis qui pouvait ou non exister. Je vous
demande maintenant d’écrire un sous-programme retournant le client le plus ancien. Vous
supposerez que l’on peut comparer les dates avec les opérateurs habituels (<, >…).
Si nous gérons un champ NbrClients indiquant combien de clients sont actuellement stockés
dans le tableau, c’est parce que ce nombre peut varier. Nous allons maintenant travailler
dans ce cadre, en ajoutant ou en supprimant des éléments du tableau.
Exercice 4
Ajout d’un élément dans un tableau
Écrivez un sous-programme permettant d’ajouter un client au tableau. Faites particulière-
ment attention aux paramètres et au choix de l’élément dans lequel ajouter le client.
Exercice 5
Supprimer le dernier élément d’un tableau
Écrivez un sous-programme permettant de supprimer le dernier client de notre tableau.
82
8 3987 TG PA 00
Exercice 6
Supprimer un élément précis d’un tableau
Écrivez un sous-programme permettant de supprimer un client ayant un numéro NumClient
donné. Pour faire cela, vous devrez écrire deux sous-programmes :
• un sous-programme renvoyant l’indice d’un client ayant un numéro donné. Cela per-
mettra de trouver quel élément doit être supprimé. Vous supposerez que le client peut
ne pas exister ;
• un sous-programme supprimant un client ayant un numéro donné (voir ci-dessous). Ce
sous-programme utilisera le précédent.
Voici une petite aide pour se souvenir comment supprimer un élément d’un tableau. Il faut
éviter les trous : avant la suppression, on a NbrClients éléments d’indices 1 à NbrClients.
Après la suppression, on en aura NbrClients-1, de 1 à NbrClients-1.
Ainsi, tous les éléments à droite de l’élément supprimé sont décalés d’un cran vers le début
du tableau. Une petite métaphore ? Imaginez une file d’attente. Une des personnes faisant
la queue en a assez et s’en va. Que se passe-t-il ? Pour les personnes qui sont devant celle qui
est partie, rien. Pour les autres, c’est Noël : ils gagnent une place.
Faisons la manipulation sur un tableau d’entiers contenant 6 éléments :
8 5 4 79 6 1
8 4 4 79 6 1
Puis le 4e dans le 3e :
8 4 79 79 6 1
Puis le 5e dans le 4e :
8 4 79 6 6 1
Puis le 6e dans le 5e :
8 4 79 6 1 1
Et c’est fini. Les esprits chagrins me diront que le 6e élément, qui devrait être vide, contient
toujours la valeur 1. Certes. Mais maintenant, je n’ai plus 6 éléments, mais 5. Le contenu des
6e, 7e… éléments n’a donc aucune importance. C’est le même principe que pour l’exercice
précédent (voir sa correction).
Notez bien que l’on décale les éléments en partant de l’élément suivant celui que l’on sup-
prime et en allant jusqu’au dernier. Si l’on allait dans l’autre sens, on effacerait les valeurs
donc cela ne fonctionnerait pas.
Au fait, soyons précis avec le vocabulaire : techniquement, on a écrasé l’élément plus qu’on
ne l’a supprimé !
83
8 3987 TG PA 00
Les exercices suivants vont traiter du tri et de la gestion des tableaux triés.
Exercice 7
Expliquez l’intérêt d’un tableau trié par rapport à un tableau non trié.
Exercice 8
Écrivez un sous-programme triant le tableau des clients d’après leur identifiant (NumClient).
Vous devez connaître une méthode de tri et savoir l’appliquer (par exemple, le tri à bulles
vu en première année). Il existe de nombreuses méthodes de tri, plus ou moins efficaces (en
général, plus elle est simple à programmer, moins elle est efficace).
Je vais vous présenter la méthode par insertion que je vous demande de programmer. Elle
n’est pas plus efficace que celle à bulles mais cela vous changera !
Le principe est très simple : trier un tableau du plus petit élément au plus grand revient à
mettre le plus petit en premier, puis celui juste un peu plus grand, puis le suivant et ainsi de
suite :
• nous allons chercher le plus petit élément du tableau et le permuter avec le premier. On
sait alors que le premier élément est trié ;
• on cherche alors le plus petit élément sans prendre en compte le premier (on va donc
de l’indice 2 à l’indice NbrClients). On trouve alors le 2e plus petit que l’on permute avec
le deuxième élément du tableau ;
• on continue. À la ie itération, on cherche le plus petit élément de l’indice i à l’indice
NbrClients. On trouve alors le ie plus petit que l’on permute avec le ie élément du tableau ;
• on s’arrête lorsque l’on a trouvé non pas le plus grand élément, mais celui juste avant.
On le place alors en avant-dernière position. Le dernier élément est forcément le plus
grand.
Nous allons essayer cet algorithme sur un tableau exemple. Pour bien se repérer, les cases
encadrées en noir seront triées , les cases encadrées en vert seront non-triées .
Prenons l’exemple du tableau suivant, pas trié du tout.
5 8 1 2 6 9 8 10 7
On cherche le plus petit élément (c’est la valeur 1 à l’indice 3) et on le permute avec le pre-
mier élément. On permute donc les éléments d’indice 1 et 3.
1 8 5 2 6 9 8 10 7
On cherche maintenant le plus petit élément sans prendre en compte le premier. On va donc
travailler sur les huit derniers éléments. Le plus petit est alors la valeur 2 (indice 4). Je per-
mute donc les éléments d’indice 2 et 4.
1 2 5 8 6 9 8 10 7
84
8 3987 TG PA 00
Je continue. Le plus petit élément (les deux premiers étant exclus) est la valeur 5 à l’indice
3. Je le permute donc avec l’élément à l’indice 3, soit avec lui-même. Cela ne change rien
(l’élément était déjà bien placé).
1 2 5 8 6 9 8 10 7
1 2 5 6 8 9 8 10 7
1 2 5 6 7 9 8 10 8
Il me reste les quatre derniers éléments. Le plus petit de ceux-là est la valeur 8. Ce peut être
celui d’indice 7 ou 9 selon mon algorithme de recherche. Cela ne change rien. Je prends celui
d’indice 7 et je le permute avec celui d’indice 6.
1 2 5 6 7 8 9 10 8
Dans les trois derniers éléments, le plus petit est mon second 8 que je permute avec l’élément
d’indice 7.
1 2 5 6 7 8 8 10 9
Il ne me reste que deux éléments à trier. Ainsi, trouver le plus petit des deux détermine aussi
le plus grand. Positionner le plus petit revient donc à positionner le plus grand.
Le plus petit est à l’indice 9, je permute donc les deux dernières cases.
1 2 5 6 7 8 8 9 10
J’ai l’assurance que mon tableau est trié. Et, en effet, il l’est.
Si nous avions fait encore une itération, on aurait cherché le plus petit élément parmi le
dernier et on l’aurait permuté avec lui-même… inutile !
Pour réaliser ce tri, vous aurez besoin des sous-programmes suivants :
• un pour permuter deux éléments (clients) d’indices donnés ;
• un recherchant le plus petit élément d’un tableau (le critère est la valeur du
champ NumClient). Attention, il faut fournir en paramètre l’indice de départ
à partir duquel on cherche l’élément. On a vu ci-dessus qu’à la première ité-
ration, on va du 1er au dernier élément, à l’itération suivante du 2e au dernier
puis du 3e au dernier…
• enfin, il faut un sous-programme réalisant le tri proprement dit.
Évidemment, les sous-programmes s’appelleront les uns les autres. Ne perdez pas de vue
que mon exemple ci-dessus triait selon les éléments, tandis que l’exercice demande le tri sur
NumClient, soit un champ des éléments.
85
8 3987 TG PA 00
Exercice 9
Écrivez un sous-programme cherchant un client d’un numéro donné. Vous supposerez que le
tableau est trié sur les numéros et que le client peut ne pas exister.
Comme le tableau est trié, il faut appliquer la recherche dichotomique vue en première
année.
Voici un petit rappel de cette méthode. Dans un tableau trié, on compare l’élément du milieu
avec celui que l’on cherche :
• si les deux sont égaux, on a trouvé notre élément ;
• si l’élément du milieu est plus grand, c’est que l’élément cherché est dans la première
moitié du tableau. On recommence donc en prenant en compte le premier demi-tableau
(élément du milieu excepté) ;
• s’il est plus petit, c’est que l’élément cherché est dans la deuxième moitié du tableau.
On recommence donc en prenant en compte le second demi-tableau (élément du milieu
excepté).
Pourquoi ne prend-on jamais l’élément du milieu lors du découpage en demi-tableau ? Car,
si l’on découpe le tableau, c’est parce que cet élément du milieu n’est pas celui que l’on
cherche. Inutile donc de s’en embarrasser ! De plus, cela permettra d’obtenir une condition
d’arrêt si l’on ne trouve pas notre élément.
Vous devez donc gérer deux variables : une indiquant l’indice de début du tableau, l’autre
l’indice de fin. Ces variables évolueront en fonction des sous-tableaux retenus. Pensez à gérer
une condition d’arrêt dans la boucle pour le cas où l’élément n’est pas présent !
Je ne vous donne pas plus d’indications car la recherche dichotomique, c’est du cours : vous
devez savoir la mettre en œuvre quand vous en avez besoin. Si vous avez des difficultés,
exécutez l’algorithme à la main sur un petit tableau.
Une remarque néanmoins. Pour déterminer le milieu du tableau, ne divisez pas par 2 avec la
division réelle mais utilisez div qui réalise la division entière. Par exemple :
• si vous considérez le sous-tableau qui va de l’indice 10 à l’indice 20, l’élément du milieu
sera à l’indice (10+20) div 2 soit 15 ;
• avec un sous-tableau possédant un nombre pair de cases, cela fonctionne également. Si
mon sous-tableau va des indices 11 à 18, l’élément du milieu sera à l’indice (11+18) div
2 soit 14. (Nous ne sommes pas parfaitement au milieu, mais c’est impossible avec un
nombre pair de cases.)
Ce n’est pas un exercice qui se traite en dix minutes. Prenez votre temps.
Exercice 10
Dernier exercice : je vous demande d’écrire un sous-programme ajoutant un client donné au
tableau trié sur le numéro NumClient. Le principe est le suivant :
• il faut localiser dans quel élément du tableau on va ajouter le client. L’objectif est que
le tableau soit toujours trié après l’ajout ;
• une fois l’indice trouvé, il faut écarter les éléments de droite (qui sont plus grands) pour
faire une petite place à notre élément.
86
8 3987 TG PA 00
Exemple, voici un tableau dont 8 éléments sont utilisés :
1 2 5 6 7 8 8 9
Je souhaite ajouter la valeur 4. Elle se positionnera entre 2 et 5, donc entre les éléments
d’indice 2 et 3. On décale donc vers la droite les éléments des indices 3 à 8 (qui seront donc
aux indices 4 à 9) :
1 2 5 5 6 7 8 8 9
J’ajoute maintenant mon 4 dans l’élément d’indice 3 qui vient d’être libéré (en pratique, je
remplace la valeur 5 à l’indice 3 par ma nouvelle valeur ; l’ancienne valeur 5 est à l’indice 4
depuis le décalage) :
1 2 4 5 6 7 8 8 9
Vous pouvez, dés maintenant, faire et envoyer à la correction le devoir 2 (voir fasci-
cule « Devoirs » réf 3987 DG).
87
8 3987 TG PA 00
Travaux dirigés 2 : deux tableaux
Présentation du TD
En fait, nous allons plus ou moins reprogrammer le langage SQL (soyons modestes, plutôt
moins que plus).
Déjà, dans le TD précédent, lorsque nous recherchions un client donné ou le client le plus
ancien… si le tableau avait été table, nous aurions retrouvé des instructions SQL classiques.
Pour garder le lien entre tableaux et base de données, le premier TD utilisait un seul tableau
(table). Ce dernier TD va en utiliser plusieurs. Nous allons donc réaliser l’équivalent de join-
tures.
Je m’en voudrais de vous sembler vieillot. Pourquoi, vous demandez-vous peut-être, mani-
puler des tableaux pour émuler une base de données et réaliser des traitements assez com-
plexes alors qu’une requête SQL fait cela mieux que nous ? Certes, une base de données est
faite pour cela. Mais est-il vraiment utile de déranger (voire d’acheter) un tel outil complexe
pour réaliser un traitement somme toute restreint ? On ne réalise plus de grosse application
de gestion sans base de données : le faire avec des fichiers et des tableaux serait de l’escro-
querie. Mais pour de toutes petites applications… les tableaux sont au poil.
89
8 3987 TG PA 00
Exercice 1
Définissons nos types
Comme nous allons manipuler plusieurs tableaux, j’en profite pour vous faire définir les
différentes données.
Voici le sujet sur lequel nous allons travailler. Il s’agit de réaliser des statistiques sur les horai-
res d’arrivée des différents trains dans une gare donnée.
Un train est caractérisé par son type : TGV, TER…, son numéro, les nombre de places en 1re et
en 2nde et sa ville d’origine (on ne stocke pas la ville d’arrivée puisque c’est systématiquement
celle de la gare que l’on informatise). Tous les trains sont stockés dans un tableau.
Pour chaque train arrivant en gare, on relève son numéro et le décalage à l’arrivée en minu-
tes par rapport à l’horaire prévu (0 pour un train à l’heure, -5 pour un train en avance de 5
minutes, 75 pour un retard d’une heure quinze). Ces deux informations sont stockées dans
un tableau.
Pour changer un peu par rapport au TD précédent, on supposera que 95 trains s’arrêtent
dans cette gare et sont donc concernés. J’insiste : c’est 95, ni 94 ou 96. Ce nombre est cons-
tant.
En revanche, on stocke les arrivées des trains au fur et à mesure. Un historique trop impor-
tant n’étant pas utile, vous dimensionnerez le tableau pour qu’il puisse contenir 10 000 arri-
vées. Lorsque le tableau est plein et que vous ajoutez une nouvelle arrivée, la plus ancienne
(contenue dans le premier élément) doit être supprimée.
Je vous demande de définir les types de données nécessaires au stockage de ces
informations.
Exercice 2
Parcours d’un seul tableau (début)
Écrivez deux sous-programmes :
• un calculant la moyenne des décalages à l’arrivée de tous les trains ;
• un autre calculant le plus petit, le plus grand et le décalage moyen d’un train donné
(identifié par son numéro). Attention, ce n’est pas un algorithme si simple qu’il y paraît :
il ne faut prendre en compte que les arrivées concernant notre train et non toutes cel-
les du tableau. Pour simplifier (temporairement), vous supposerez que le train existe
forcément.
Exercice 3
Parcours d’un seul tableau (fin)
Réécrivez le dernier sous-programme calculant le plus petit, le plus grand et le décalage
moyen d’un train donné. Vous prendrez maintenant le cas général du train qui n’existe pas
forcément.
90
8 3987 TG PA 00
Exercice 4
Parcours des deux tableaux
Écrivez un sous-programme déterminant combien d’arrivées de trains de type TGV ont eu
lieu en retard. (Un même train TGV arrivant trois fois en retard sera comptabilisé trois fois.)
Exercice 5
Recherche
Écrivez la fonction de recherche indiquée à la fin de la correction de l’exercice précédent
(on cherche l’indice d’un train dont le numéro est donné) puis réécrivez NbrTGVRetard en
utilisant cette fonction.
Exercice 6
Écrivez un algorithme complet (et donc plus seulement un sous-programme) permettant de
savoir si un train donné s’arrête dans notre gare (donc s’il fait partie ou non de notre tableau
des trains).
Vous supposerez que la procédure InitTrains (var Trains : tableau[95] de Train) est fournie
(vous pouvez donc vous en servir !). Elle permet de remplir le tableau des trains.
Pour les quatre derniers exercices, nous supposons que le tableau des arrivées est trié par
numéro de train. Ainsi, si nous avons les trains numéro 15, 87 et 665, le tableau contient
d’abord toutes les arrivées du train 15 puis celles du train 87 et enfin celles du 665.
Exercice 7
Il n’y a qu’un train en provenance de Limoges. Combien d’arrivées a-t-il effectué ? (On sup-
posera qu’il est arrivé au moins une fois.) Faites des sous-programmes !
En première approche, pour trouver les arrivées d’un train donné, nous n’allons exploiter
que partiellement le fait que le tableau des arrivées est trié par train : parcourez séquentiel-
lement le tableau jusqu’à trouver les arrivées de votre train. Ensuite, vous avancerez dans le
tableau jusqu’à ce que les arrivées ne concernent plus votre train. Comme le tableau est trié
par train, vous êtes assurés de n’avoir loupé aucune des arrivées cherchées.
Exercice 8
Modifiez l’algorithme précédent en supposant que le train de Limoges peut n’être encore
jamais arrivé dans notre gare.
91
8 3987 TG PA 00
Exercice 9
C’est toujours le même sujet : combien d’arrivées du train de Limoges ont été enregistrées ?
Nous allons maintenant exploiter pleinement la potentialité de notre tableau d’arrivées trié.
Vous allez faire une recherche dichotomique pour trouver une arrivée du train cherché. Cela
vous donnera une arrivée quelconque de ce train. Vous devrez donc reculer puis avancer
dans le tableau pour trouver toutes les arrivées.
Voici une illustration. Prenons le tableau d’entiers suivants :
1 2 4 4 4 4 6 6 7
Exercice 10
Pour terminer cette séquence de TD, je vous demande d’écrire un algorithme complet
(comme dans l’exercice 6) permettant d’indiquer à l’utilisateur combien de voyageurs sont
arrivés dans notre gare en provenance d’une ville donnée. La SNCF vous indique que statisti-
quement, 65 % des places de première et 79 % des places de seconde sont occupées.
Vous avez évidemment toujours à votre disposition la fonction InitTrains (var Trains :
tableau[95] de Train). De même, vous supposerez que tout ce dont vous avez besoin concer-
nant l’initialisation du tableau des arrivées est fourni.
Cet exercice n’est qu’une extension des précédents : il faut reprendre des bouts de code à
gauche à droite et les compléter.
Je vous propose de commencer l’exercice dès maintenant. Si vraiment vous n’y arrivez pas ou,
mieux encore, une fois votre algorithme écrit, lisez ce qui suit et vérifiez votre algorithme à la
lumière des indications. Corrigez alors si besoin est votre travail avant d’étudier la correction.
Voici quelques indications pour réaliser l’exercice. Partez de l’exercice 9. Ce qui change, c’est :
• on ne cherche plus un seul train venant de Limoges, mais de 0 à n trains venant d’une
ville précise. Tout le traitement de l’exercice 9 doit donc être encadré par une boucle
cherchant ces trains en parcourant le tableau des trains ;
• ensuite, c’est trivial mais il faut penser à le faire, le nombre d’arrivées d’un train donné ne suf-
fit plus, il faut réaliser une opération arithmétique avec ce nombre et la capacité du train.
92
8 3987 TG PA 00
Travaux dirigés 3 : sur machine
93
8 3987 TG PA 00
Devoir autocorrectif
Exercice 1
Nous voulons gérer les notes des différents étudiants d’une classe. Pour cela, nous disposons
de trois tableaux :
• un contenant les étudiants ;
• un contenant les différentes matières. Notez que chacune est affectée d’un coefficient ;
• un troisième contenant une note (et l’étudiant et discipline concernés).
Voici les types concernant les étudiants :
type Étudiant =
structure
Num : entier // Numéro de l’étudiant (identifiant)
Nom : chaîne
Prénom : chaîne
fin structure
type Classe =
structure
t : tableau [50] d’Etudiant
NbrÉtudiants : entier
fin structure
Je définis un type Classe contenant un tableau d’étudiants avec une variable NbrÉtudiants
indiquant combien d’éléments du tableau sont effectivement initialisés (soit combien j’ai
d’élèves dans ma classe).
95
8 3987 TG PA 00
Voici les types concernant les matières :
type Matière =
structure
Num : entier // Numéro de la matière (identifiant)
Libellé : chaîne
Coefficient : entier
fin structure
type TabMatières =
structure
t : tableau [20] de Matière
NbrMatières : entier
fin structure
type Note =
structure
NumÉtudiant : entier
NumMatière : entier
Note : entier // je suppose que les notes sont arrondies
fin structure
type TabNotes =
structure
t : tableau [1000] de Note
NbrNotes : entier
fin structure
Soyons sûrs de bien comprendre.
Si je veux les notes de l’étudiant Nina TECKEL dans la matière Programmation, comment
faire ? Il y a trois étapes :
1. Je vais chercher dans le tableau des étudiants le numéro de l’étudiant Nina
TECKEL. Imaginons que ce soit 4.
2. Je vais chercher dans le tableau des matières le numéro de la matière Programmation.
Imaginons que ce soit 13.
3. Dans le tableau des notes, je cherche celle de l’étudiant 4 dans la matière 13.
On supposera qu’un étudiant possède exactement une note par matière et que le tableau des
notes est trié par matières (on a donc toutes les notes de la matière 1 puis toutes celles de
la matière 2…).
96
8 3987 TG PA 00
Travail à faire
1. Écrivez un sous-programme renvoyant la moyenne des notes pour une matière donnée
(identifiée par son libellé). Vous supposerez que la matière existe.
Je vous rappelle que la moyenne d’un étudiant se calcule en additionnant le produit de cha-
que note par son coefficient et en divisant le tout par la somme des coefficients.
Par exemple, si j’ai 15 en étude de cas (coefficient 5), 12 en épreuve pratique (coefficient 3) et
19 en note de synthèse (coefficient 4), ma moyenne sera :
15 x 5 + 12 x 3 + 19 x 4 187
= = 15,58
5+3+4 12
2. Écrivez un sous-programme renvoyant la moyenne d’un étudiant dont on vous fournit le
nom et le prénom. Attention, cet étudiant peut ne pas exister (on supposera néanmoins
qu’il n’y a pas d’homonyme). Vous veillerez à prendre en compte les coefficients des dif-
férentes matières.
Exercice 2
Vous avez enfin trouvé enfin l'opérateur téléphonique qui est vraiment, vraiment moins cher
que tous les autres.
Le problème, c’est que sa grille de tarification est la plus complexe du marché :
• tout appel abouti (le correspondant décroche) est facturé d’un frais fixe (0,046 €) ;
• les 0,046 € de frais de connexion donnent droit à des secondes gratuites. Combien ? Cela
dépend de la tranche horaire ;
• le prix des secondes supplémentaires (au-delà des secondes gratuites) dépend égale-
ment de l’heure d’appel.
On retrouve les vingt-quatre tranches d’une heure formant une journée et numérotées de 1
à 24. Elles possèdent deux propriétés : le nombre de secondes gratuites par appel et le prix
de la seconde.
Par exemple :
• la tranche horaire 0 h – 1 h possède le numéro 1. Les 60 premières secondes sont gra-
tuites (incluses dans les 0,046 €) et les secondes suivantes sont facturées 0,0002 €. (C’est
bien peu ? Certes, mais une seconde, c’est bien court !) ;
• la tranche horaire 14 h – 15 h possède le numéro 15. Un appel passé à cette heure dispose
de 28 secondes gratuites (incluses dans les 0,046 €) puis chaque seconde coûte 0,0005 €.
Très fortement paranoïaque, vous êtes convaincu que les factures que vous recevez sont erro-
nées. Vous bricolez un circuit électronique relié à votre PC remplissant un fichier contenant,
pour chaque tranche horaire, la liste de tous les appels avec leur duréeå.
En effet, connaître le nombre d’appels et leur durée totale n’est plus suffisant à cause des
premières secondes gratuites : il faut impérativement connaître la durée de chaque appel.
Vous allez ensuite écrire un programme exploitant ces données.
97
8 3987 TG PA 00
Pour informatiser cela, vous définissez un type structuré Tarif définissant, pour une tranche
horaire, le nombre de secondes gratuites et le tarif de la seconde supplémentaire :
type Tarif =
structure
NbrSecGratuites : entier
TarifSeconde : réel
fin structure
var
Tab Tarifs : tableau [24] de Tarif
Nous avons donc un tableau de vingt-quatre tarifs, l’indice déterminant la tranche horaire.
Par exemple pour les appels payés de 14 à 15 h :
• TabTarifs[15].NbrSecGratuites = 28 ;
• TabTarifs[15].TarifSeconde = 0,0005.
Pour suivre vos communications, vous récupérez les informations que votre boîtier électroni-
que (à ne pas réaliser) a stocké dans des fichiers.
Pour cela, vous avez les types suivants :
type Appel =
structure
TrancheHoraire : entier
Durée : entier
fin structure
type TypeTabAppels =
structure
t : tableau [10000] de Appel
NbrAppels : entier
fin structure
On retrouve nos tableaux contenant un nombre variable d’éléments. En effet, je peux passer un
seul appel, vingt, trois cents… Chaque élément du champ t correspond à un appel. Je mémorise
la tranche horaire (t[i].TrancheHoraire) correspondante et la durée de l’appel (t[i].Durée).
Remarque importante, on considère que les appels du tableau t contenu dans la structure
TabAppels sont triés sur la tranche horaire. Cela signifie que l’on aura d’abord tous les appels pas-
sés entre minuit et une heure (tranche horaire 1), puis tous les appels dans la tranche horaire 2…
Assurez-vous de bien avoir compris le contenu des différents tableaux et structures,
sinon vous ne pourrez pas écrire l’algorithme demandé. Je ne vous cache pas que
l’essentiel de la difficulté réside là. C’est d’ailleurs pourquoi je ne vous donne pas
d’exemple de contenu de tableau.
Travail à faire
98
8 3987 TG PA 00