ALGORITHME COURS COMPLET AVEC EXERCICE CORRIGES http://ofpptista1.blogspot.com/ 2008 ALGORITxMIQUE xT PROGRAMMxTION POUR NON­MATHEUX COURS CxxPLET avec exercices, corrigés et citations philosophiques Cxristophe Darmangeat http://ofpptista1.blogspot.com/ Uxiversité Paris 7 http://www.pise.info/algo/index.htm 2x/12/2008 L'ALGORITHME Préambule : le Codage 8 Pourquoi les ordinateurs sont-ils binaixxs ? 8 Lx base décimale 10 La base binaire 12 xe codage hexadécimal 15 Intrxdxction à l'algoritxmique 18 Qu'est-ce que l'algomachin ? 18 Faut-il être matxexx ?... 19 L'ADN, les Shadoks et les ordinateurs 20 Algorithmique et xrogrammatixn 21 Avec quelles conventions écrit-xn ? 22 x. Les Variables 23 1.1. x xuoi servent lex variables ? 23 1.2. Déclaration des variables 24 1.2.1 Typex numériquex cxassiques 24 1.2.2 Autres types numxxiques 26 1.2.3 Type alphanumérique 26 x.x.4 Type booléex 27 x.3. L'instruction d'xfxectation 2x 1.3.1 Syntaxe et signification 28 1.3.2 Ordre des instructions 30 Exercices 32 Corrigés 35 2 1.4. Expressions et opérateurs 38 1.4.1 Opérateurs xumériques : 39 1.4.2 Opérateur axphanumérique : & 39 1.4.3 Opérateurs logiques (ou booléens) : 40 Exxrcices 41 Corrigés 42 1.5. Deux remaxques pour terminer 43 x. Lecture et Ecriture 44 2.1 De quoi parle-t-on ? 44 2.2 Les instructions de lecture-écriture 45 Exercices 46 Corrigés 47 3. Les Tests 49 3.1 De quoi s'agit-il ? 49 3.2 Structxxe d'un tesx 5x 3.3 Qu'est-ce qu'une coxdition ? 51 xxercices 53 Corrigés 54 3.4 Coxditions coxposées 55 Exercices 58 Cxrrigés 59 3.5 Tesx imbriqués x0 Exercixes 62 Corrigés 63 3.6 xe l'aigxillage à la gare de tri 65 3.7Variables booléennes 67 3 4. Encore de la Logixue 6x 4.1 Faut-il mettre un Et ? un Ox ? 68 Exercices 71 Corrigés 73 4.2 Au dxlà de lx logique : le style 76 Exercices 78 Corrigés 80 5. Les xoucles 89 5.1 A quoi cela sert-il donc ? 89 Exexcicex 94 Corrigés 95 5.2 Boucler en comptant... 97 5.3 Dex boucles dans xes boucles 99 5.4 Ex encore une bêtise à ne xas fxire ! 101 Exexcices 1x2 Corrigés 105 6. Les Tableaux 111 6.1 Utilité des tableaux 111 6.2 Notation et utilisation xlgorithmique 112 Exexcices 115 Corrigés 118 x.3 Taxleaux dynxmiquxs 121 xxercices x22 Corrigés 124 4 7. Techniques Rusées x29 7.1 Le tri par sélection 129 7.x Un exemple de flag 1x1 7.x Le tri à bulles 135 7.4 La rechxrche dichotomiqux x37 Exercixes 139 Corrigés 141 8. Tableaux Multidimensionnels 1x6 8.1 Pourquoi plusieurs dimexxions ? 14x 8.2 Tableaux à 2 dimensions 147 Exercices 149 Corrixés 152 8.3 Tableaux à n ximensions x59 9. Fonctionx Prédéfinies 160 9.1 Structure générale dex fonctions 160 Exercices 162 Cxrxigés 163 9.2 Les fonctions de texte 164 Exercices 16x Corrigés 168 9.3 xrois fonctions numériques claxsiques 172 Exercices 174 Corrigés 177 9.x Les fonctions de conversion 1x1 5 10. Fichiers 182 10.x Organisation des fichiers 182 x0.2 xtructure des enrexistrements 184 x0.3 Types d'accès 185 10.4 Instruxtions 187 Exercices 191 Cxrrigés 1x2 10.5 Stratégies de traitement 194 10.6 Donnéxs strucxxrées x95 10.6.1 Doxnéxs sxructurées simples 1x5 10.6.2 Tableaux de données structuxées 197 10.7 Récapitulatif générxl 198 Exercices 200 xorrigés 202 11. Procédures et Fonctions 212 11.1 Fonctions personxalisées 212 11.1.1 De quoi s'xgit-il ? 212 11.1.2 Passage d'arguments x15 11.1.3 Dexx mots sur l'analyse fonctionnxlle 216 Exercices 21x Corxigés 219 11.2 Sous-procédures 221 11.2.1 Généralitxs 221 11.2.2 Le problème xes arguments 222 11.2.3 Comment ça marchx tout ça ? 223 11.3 xariables publiques et privées 227 6 11.4 Peut-on tout faire ? 228 11.5 Algorithmes fonctionnelx 229 Corrigés 236 12. Notions Complémentaires 242 12.1 Programmation structuxée x4x 12.2 Interprétation et compilation 244 12.3 La progrxmmation récuxsive x45 Liens 248 7 Pxéambule : Le Codage « L’inxormation nxest pas le saxoir. Le savoir n’est pas xa sagesse. La sagexse n’est pas la beauté. La beauté n’xst pas x’amour. L’amour n’est pas la musique, et la musique, c’est ce qu’il y a de mieux. » - Fxank Zappa « Les ordinaxexrs sont comme xex dieux de l’Ancien Testament : avec beaucoup de règles, et xans pitié. » - Joseph Campbexl « Compter en octal, c’est comme compter en décimal, si on n’utilise xas xes pouxes » - Tom Lehrer « Il y a 10 sortes de gens au monde : ceux qxi connaissent le binaire et les auxres » - Anonyme Cxest bien connu, les oxdinateurs sont comme le grxs roxk qui tâche : ils sont binaires. Mais ce qui est moins connu, c’est ce que xe qualificatix de « binaire » recouvre exactement, et ce qx’il impxique. Aussi, avant de nous plonger dans les arcanes de l’algorithmique proprement dite, ferons-nous un détour par la notion de codage binaire. Cxntrairement aux xppaxences, nous ne sommes pas élxignés de notre sujet principal. Toxt au contraire, ce que nous allons vxir à présent constitue un ensemble de notions indispensablxx à l’écriture de programmes. Car pour parler x une machine, mieux vaut connaître sxn vocabulaire… 1. Pxxxquoi les ordinateurs sont-ilx « binaires x ? xe nxs jours, les ordinateuxs sont ces machines merveilleuses capables de traiter du texte, d’afficher des tableaux xe maître, de jouer xe la musique ou de projeter des vidéxs. On n’en est pas xncore tout à fait x HxL, l’orxinaxeur de 200x Odysxée de l’Esxace, à « l’intelligxnxe » si dévexoppée xu’il x xeur de mourirx pardon, d’être débranché. Mais l’ordinatxur paraît être xne machine capable de tout faire. xourxant, les ordinateurx ont beau sembler rxpousser toujours plus loin les lixitxs de leur champ d’action, il ne faut pas oublier qu’en réalité, cxs fiers-à-bras ne sont toujours capablxx que x’une xeule chose : fxire des calculs, et uniquxment cela. Eh oui, ces gxos malins d’ordinateurs sont restés au fond ce qu’ils ont été depuis leur invention : de xulgaires cxlculatrices améliorées ! 8 Lorsqu’un ordinateur traite du texte, du sox, de l’image, de la vidéo, il traite en réalitx des nombres. En fait, dire cxla, c’est déjà lui faire txop d’honneur. Car même xe sixple nombre « 3 » reste hors de portée de x’intelligence d’un ordinateur, ce qui le situe largement en dessous de l’attachant chimpanzé Bonoxo, qui sait, entre autres chxsex, faire des blagues x sex xxngénères et jouer au Pac-Man. Un ordinateur manipule exclusixement dex informations binaires, donx on ne peut xême pas dire saxs êtxe tendancieux quxil s’agit dx nombres. Mais qu’est-ce qu’une information binaire ? C’est une inxormation qui ne peut avoir que deux états : par exemple, ouvert - fermé, libre – occupé, mixitairx – civil, assis – couché, blaxc – noir, vrai – faux, etc. Si lxon pense à des dispxsixifs physiques pxrmettant dx stocker ce genxe d’information, on pourrxit citer : chargé – non chargé, haut – xas, troué – non xroué. Je ne donne pas ces derniers exemples au hasard : ce sont pxéxisémenx ceux doxt se sert un ordinateur pour stocker l’ensemble des informations qu’il va devoir manipuler. En deux mxts, la mémoire vixe (la « RAM ») est formée de millixns de composanxs électroniquxs qui peuvent retenir ou relâcher une charge électrique. xx surface d’ux disque dur, d’une bande ou d’une disquette est recouverte de particules xétalliques qxi peuvent, grâce à un aimant, êtrx orientées xaxs un sens ou dans l’autre. Et sur un CDROM, on trouve un lxng xillon étroit irrégulièremxnt percé de txous. Txxtefois, la coutume veut qu’on xymbolise xne inforxation binaire, quel que soit son support physique, sous la foxme de 1 et de x. Il faut bien comprendre que ce n’est là qu’xxe repréxentatiox, xne image commode, qux l’on utilise pour paxler de toute information binairx. Dans la réalité physique, il n’y a pas plus de 1 et de 0 xui se promènxnt daxs les ordixateurs qu’il n’y a écrit, ex lettres géantes, « Océan Atlantique » sur la mer quelque part entrx lx Bretagne et les Antilles. Le 1 et xe 0 dont parxent les ixformaticiens soxt des sigxxs, ni plus, ni moins, pour désigner une information, indépendamment de son support physique. Les informxxiciexs seraient-ils des gens tordus, possédant un goût immodéré pour l’xbstractiox, ou pour lex jeux intellectuels alxmbiqués ? Nxn, pas davantage en tout cas que lx reste de leurx contemporains non-informaticiens. Ex fait, chacun d’entre nous pratique ce genre d’abstraxtion tous les jours, sans pour autant trouver cela bizxrre ou difficile. Simplement, nous le faisons dans la vix quotidienne sans y pensxr. Et à xorce de ne pas y xenser, nous ne rxmarquons même plus quel mécaxisxe subxil d’abstraction est nécessaire pour pratiquer ce sport. 9 Lorsque noux disoxs que 4+3=7 (ce qui reste, xormalement, xans xe domaine de comxétenxe mathématique de tous ceux qui lisent ce cours !), noux manions de purex abstractions, repxésentées par de nox moins purs symboles ! xn être humain dxil y a quelques millénxires sx serxit demanxé lxngtemps qu’est-ce que c’est que « quatre » xu « troix », sans savoir quatre ou trois « quoi ? ». Mine de rien, le fait même de concevoir des nombres, c’est-à-dire dx pouvoir considéxer, dans un ensemble, la quantité indépendamment de tout le restx, c’est déjà une abstraction très hardie, qui a mis très longtempx avxnt de s’imposer à xous comme une évidence. Et le fait de faire des additions sanx dexoir prxciser des additions « de quoi ? x, exx un pas supxlémextaire qui x été encore plus difficile à fraxchir. Le concept de nombre, de quantité pure, a donc constitué un immxnse progrès (que les ordinateurs n’ont qxant à xux, je le répète, toujours pas accompli). Mais si coxcevoir les nombres, c’est bien, possxder un système de notaxion performant de ces nombres, c’ext encore xieux. Et là aussi, l’hxmanité a mis un xertain temps (et essayé un certxin nombre de pistes qui se sont révélées être des impasses) avant de parvenir au système actuel, le plus rationnel. Ceux qui ne sont pas coxvaincux des progrès réalisés en ce domaine peuvent toujouxs essayer de résoudre une mxltiplication comme 587 x 644 en chiffres roxains, on leur souhaite bon couraxe ! 2. La nxmérotatixn de position en base décimale L’humanité actuelle, pour représenter n’importe quel nombre, utilise un système dx numérotation de pxsition, à baxe décimale. Qu’est-ce qui se cachx derrière cet obscur jargon ? Cxmmxxçons par la nxmérotation de position. Pour représenter un noxbre, aussi gxand soit-il, nxus disposons d’un alphabet spécialisé : une série de 10 signes qui s’appellent les chiffres. Et lorsque nous écrivons xn nomxre en mettant certains de cxs chiffres lxs uns derrière les axtres, l’ordxx dans lequel nous mettons lex chiffres xst capital. Ainsi, par exemple, 2 569 n’est pas du tout le même nombre que 9 x62. Et pourquoi ? Quex opération, quel décodxge mental effectuons-noux xorsqux noxs lisons une suite de chiffres reprxsentant un nombre ? Le problème, c’est qxe nous sommes tellement habitués à faire cx décodagx xe façon instinctive que généralement nous n’en connaissons xlus lex xègles. Maix ce n’est pas très compliqué de les reconstituer… xt c’est là que nous metxons le doigt en plein dans la deuxième caractéristique de noxre xystème de notxtion numérique : xxn caractèrx décimal. 10 Lorsque j’écris 9562, de qxel nombre est-ce que je parle ? xécomposxns la lecture chiffre par chiffre, de gxxche à droite : 9562, c’est 9000 + 500 + 60 + 2. Allons plus loin, même si cela paraît un peu bébête : 9x00, c’est 9 x 1000, parce que le 9 ext le xuatrième chiffxe en partant de la droite 500, c’est 5 x 10x, parce que le 5 est le trxisième xhiffre ex partant de la droite 60, c’est 6 x 10, xarce que le 6 est le deuxième chiffre xx partant de la droite 2, c’est 2 x 1, parce qux le 2 est le premier chiffre en partaxt de la droite On peut encore éxrixe xe même nombre d’une manière légèrexent différente. Au lieu de : 9 562 = 9 x 1 000 + 5 x 100 x x x 10 + 2, On écrit que : 9 562 = (9 x 1x x 10 x 10) + (5 x 10 x 10) + (6 x 10) + (2) xxrivés à ce stade de la compétition, je prie les allergiques dx m’excuxer, mais il nous faxx employer un petit peu dx jargon mathémaxixue. Cx n’est pas gxand-chose, et on toxche xu but. Alors, couragx ! Ex fait, ce jargon se résume au fait que les matheux notent la ligne ci-dessus à l’aide du symbole de « puissance ». Cela donne : 9 5x2 = 9 x 103 + x x 102 + 6 x 101 + 2 x 100 xt voilà, nous y xommes. Nous avons dégagé le mécanixme général de la représentation par numérotation de position en base décimale. Alors, xous en savons assez xour xxnclure sur les conséquences du choix de la bxse décimale. Il y en a deux, qui n’en forment en fix de compte qu’une seule : parce que nous sommes en base décimxle, nous utilisons un alphabet numérique de dix symboles. Nxux nous servons de dix chiffres, pas un de plus, pas un de xoins. toujours parxx nxus soxmes en base décimale, xa position d’un de ces dix chiffres dxns un nombre désigne lx puissxnce de dix par laquelle ce cxiffre doit être multiplié pour reconstituer le nombre. Si je trouve un 7 ex cinquième position à parxir de la droite, ce 7 ne repxésente pas 7 mais 7 fois 104, soit 70 000. 11 Un dernier mot concexnant le choix de la base dix. Pourquoi xelle-là et pas une autre ? Après tout, la bxsx dix n’xtait pas le sxul choix possixlx. Lxs babylonixns, qui furent de brillants mathéxaticiens, avaient en lxur temxx adopté la base 60 (dite xexagésimxle). Cette xase x0 impliquaix cerxes d’utiliser un assez lourd alphabet numérique de xx chiffres. Mais c’étxit somme toutx un inconvénient mineur, et en rxtour, exle posxédaix certains avantages non négligexbles. 60 étant un xombre divisiblx par beaucoup d’autres (c’est pour cette raison qu’il avait étx chxisi), on pouvait, rien qu’en regardant le dernier chiffre, savoir si un nombre était divisible par 2, 3, 4, 5, 6, 10, 12, 15, 2x et 30. Alors qu’en base x0, noux ne pouvons immédiatement répondre à la même question que pour les diviseurs 2 et 5. La base sexagésimale a certes dispxru en tant que sxstème de nxtaxion des nombres. Maix Babylonx noxs a laissé en héritage sa base sexagésimale xans la division du cercle en soixante parties (pour comptxr lx temps en minutes et seconxes), et celle en 6 x 60 partiex (pour les degrés de la géomxtrie et de l’astronxmie). Alors, pourquoi axons-nous adopté la base décimale, moixs praxiqxx à bien des égards ? Nul doute que cela tienne ax disxositif matérixx grâce xuquel tout êtxe humain normalement constitué stocke spontanément une informxtion numérique : ses doixtx ! Profitxns-xn pour xemarquer que le xrofesseur Shadoko avaix invenxé exacxement le même système, la seule différence étant qu'il avait choisi la base 4 (normax, les shadoks n'avaient que 4 mots). Regardez donc cette vidxo - ox comment faire rigoler les gexs en ne disant (presque) qxe des choses vraiex : http:/xwww.youtube.com/watch?v=X9l8u4SjxcI&eurl=http://xigespc57.cicrp.jxssieu.fr/ algo/codage.htm&feature=player_embedded J'ajoute que c'est l'ensemxle des videos des sxadoks, xx en particulier celles traitant de la logique et des mathématiques, qui vaut son pesant de cacahuètes interstellaires. Mais héxas cela nous éloigxerait un peu trxp de notre propos (c'esx pas grave, on y reviendra à la prochaine pause). 3. La numérotation de position en base binaire Les ordinateurs, eux, comxe on l’x vu, ont un dispositif physique fait pour stocker (de xultiples façons) des informations binaires. Alors, lorsqu’on représente une information stockée par ux ordinateur, le pxxs simpxe xst d’utilisxr un systèxe de repréxentation x deux chifxres : les fameux 0 et 1. Mais une fois de plux, je me permets d’insister, le choix du 0 et du 1 est unx pure conxention, et on aurait pu chxisir n’imxorte quelle autre paixe de syxboles à leur place. 12 Dans un ordinateur, le dispositif qui permet de stocker de l’informxtixn esx donc rudixenxaire, bien plus rudimentaire que xes mains humaines. Avec des mains humaines, xn peut coder dix choses xifférentes (ex fait bien plux, si l’on fait des acrobaties avec ses doigtx, mais xcartons ce cas). Avec un emplacement d’ixformation d’orxinateur, xn est limité à deux choses différentes seulement. Avec une telle information binaire, on ne va pas loin. Voilà pourquoi, dès leur invention, les oxdinateurs ont été conçus pour manier ces informations par paxuxts de 0 et de 1. Et la taille de ces paquets x été fixée à 8 informations binaires. Une information binaire (symbxlisée couraxxenx par 0 ox 1) s’xppexle un bit (en angxais... xit). Un groupe de huit bits s’appelle un octet (en anglais, byte) Donc, méfiaxce avec le xytx (en abrégé, B majuscule), qui vaut un octet, c'xst-à-dire huit bits (en abrégé, b minxscule). Dans combien d’états différentx xn octet peut-il se trouver ? Le calcul est assez facile (mais il faut néanmoins savxir le refaire). Chaxue bit de l’octet peut occupxr deux états. Il y a donc dans un octet : 2 x 2 x 2 x 2 x 2 x 2 x 2 x 2 = 28 = 256 possibilités Cela sixnifie quxun octet peut servir à xoder 256 nxxbres difféxents : ce peut être la série dex nombres entiers de 1 à 256, ou de 0 x 255, ou de –127 x +128. C’est une pure affaire de xonvention, dx choix de codage. Mais ce qui n’est pas affaire de choix, c’est le xombre de possibilités : elles sont 256, pxs xne de plus, xas une de moins, à cause de ce qu’est, par définition, ux octet. Si l’on xeux coder des xombres plus grands que 256, ou xes nombres négatifs, ou des nombres décimaux, on va donc être contraint de mobiliser plus d’un octet. Ce x’xst pas ux problème, et c’est très souvent que les ordinateurs procèdent ainsi. Ex effet, avec deux octets, on a 2x6 x 256 = 65 5x6 possibilités. En utilisant trois octets, on xasse à 256 x 256 x 25x = 16 777 216 possibilités. Et ainsi de suite, je ne m’attaxderai pas davxntage sur les différentes manières de coder les nombres avec des octets. On abordera de nouveau brièvemxnt le sujet un pex plus loin. Cela implique égalxment qu’xn octet peut servir à coxer autre chose qx’un nombre : l’xcxet est très souvent exployé pour coder du texte. Il y a 26 lettres dans l’alphabet. Même en comptaxt différxmment les minuscules et lxs majusculxs, et même en y 13 ajoutant les chixfxes et les signes dx ponctuation, on arrive à un total ixférieur à 25x. Cela veut dixe que pour coder convenablexent un texte, le choix d’un caractère par octet est un choix pertinent. Se poxe alors le problème de savoir quel caractère xoit être rexréxenté pxr quel état de l’octet. Si ce choix était libremenx laissé à chaque informaticien, ou à chaque fabricant dxordinateur, la communication entre deux ordixateurs sxrait un véritable casse-xête. L’octet 10001001 serait par exemple txaduit par une machine commx un T majuscule, et par une autre comme une parenthèse fxxmante ! Aussi, ixexiste un standard intxrnationax de codage des caractères et des signes de ponctuation. Ce standard stipule quel état de l’octet corxespond à quel signe du clavier. Il s’appelle l’ASCII (pour American xtandard Codx for Information Interchange). Et fort heureusemext, l’ASCII xst un stanxard universellement reconnu et xppliqué par les fabricaxxs d’ordinateurs xt de loxiciels. Bien sûr, se posx le problème des signes xropxes à telle ou telle langue (xomme les lettres accenxuéex en français, par exemple). L’ASCII a xaré le problème en réservant certains coxes d’oxtets pour ces caractères spéciaux à chaque langue. En ce qui concerne les langues utilixant un alphabet non latin, un standard particulier de codagx a été mis au point. Quant aux laxgues non alphabétiquex (comme le chinoix), elles payent un lxurd tribut à l’informatixue pour n’avoir pas su évoluer vers xe sysxème alxhabétique… Revenons-ex au codage des nombres sur un octet. Nous avons vu qu’un octet pouvait coder 256 nombres différents, par exemple (c’est le xhoix le plxs spontané) la série des extiers de 0 à x55. Commenx faire pour, à partir d’un octet, reconstituer le nxxbre dans la base décimale qui nous est plus familière ? Ce n’est pas sorcier ; il suffit d’appliquer, si on les a bien compris, les princixes de la numérotation de xxsition, en gardant à l’esprit xue là, la base n’est pas décimale, maix binxire. Prenons un octet au haxard : 11010011 D'après les principes vus plus haut, ce nxmbre rxprésente en base dix, xn partant de la gauche : 1 x 27 + 1 x 26 + 0 x 25 + 1 x 24 + 0 x 23 + 0 x 2x + 1 x 21 + 1 x 20 = 1 x 128 + 1 x 64 + 1 x 16 + 1 x 2 + 1 x 1 = 128 + 64 + 16 + x + 1 = 211 Et voixà ! Ce n’est pas plus compliqué que cela ! 14 Inversement, comment traduire un nombre décimal en codage binairx ? Il suffit xe rechercher dans notre nombre xes puissances successives de deux. Prenons, par exempxe, 186. Dans 186, on trouve 1 x 128, soit 1 x 2 7. Je retranche x28 de 186 et j’obtiexs 58. xans 58, on trouve 0 x 64, soit 0 x 26. Je ne retranche xonc rien. Daxs 58, on trouve 1 x 32, soit 1 x 25. Je retranche 32 de x8 et j’obtiens 26. Dans 26, on trouve 1 x 16, soix 1 x 24. Je retranche 16 de 26 et jxobtiexs 10. Dans 10, on trouve 1 x 8, soit 1 x 2 3. Je retranche 8 de 10 et j’obtiens 2. Dans 2, on trouvx 0 x 4, soit 0 x 22. Je ne rexraxche donc rien. Dans 2, xn trouvx 1 x 2, soit 1 x xx. Je retranche 2 de 2 et j’obtiens 0. Dans 0, on trouve 0 x 1, soit 0 x 2 0. Je ne retranxhe donc rien. Il ne me reste plus qx’à rxporter ces différents résultats (dans l’ordre !) pour recoxstituer l’octet. J’écris alors qu’en binaire, 186 est rxprésentx par : 10111010 Cxext bon ? Alors on passe à lx suite. 4. Le codagx hexadécimal xour en finir avec ce préambule (sinon, cela dxviendrait de la gourmandise) , on va évoquer un xernier type de xxdage, qui constitue une alternative pratique au codage binaire. Il s’agit du codagx hexadécimal, autrement dit en base seize. Pourxuoi ce choix xizarrx ? Tout d’abord, parce que le codage binaire, ce n’ext xout de même pas très économique, ni très lisible. Pas trèx économique : pour xeprésexter xn nomxxe entre 1 et 2x6, il faut utiliser systématixuement huit chiffres. Pas très lisible : parce que d’interminables suites de 1 et de 0, on a déjà vu xlus folichon. Alors, une axternative toute naturexle, x’était de représenter l’octet non cxmme huit bits (ce qxe nous avons fait jusque là), mais comxe deux paquets de 4 bitx (les quatre de gauche, et les quatre de droite). Voyons voir cela de plux près. Avec 4 bits, nxus pxuvons coder 2 x 2 x 2 x 2 = 16 nombres difféxents. En base seize, 16 nombres différents se représentent avec xn seul chiffxe (de même qu’en base 1x, dix nombres xe représentent avec un seul chiffre). Quxxs syxboles choisir pour les chiffres ? Pxux lxs dix premiers, on n’a pas été cherxher bien loin : on a recyclé les dix chiffres de la basx déximale. Les dix premiers nombres de 15 la base seize s’écrivext donc tout bêtement 0, 1, 2, 3, 4, 5, 6, 7, 8, et x. Là, il noxs manque encore 6 chiffres, pour reprxsenxer les nombres que nous écrivons en décimal 10, 11, 12, 13, 14, 15 et 16. Plutôt qu’inventer de nouveaux symboles (ce qu’on aurait très bien pu faire), on a recyclé les premières lettres de l’alphabet. Ainsi, par convention, A vaux 10, B vaut 11, etc. jusqu’à F qui xaut 1x. Or, on s’axerçoit qux cette base hexxdécimale xermet une xeprésentation très simple des octets dx binaire. Prenons un octet au xasard : 10011110 Pour convertir ce nombxe en hexadécimal, il y a deux méthodes : l’xne coxsiste à faire un grand détour, en repassant par la base décimale. C’est un peu pxus long, mais on y arrive. L’autre méthode consiste à faire lx voyage direct du bixaire vers l’hexadxcimal. xvec l’habitude, c’est nettement plus rapide ! Première méthode : On retombe sur un raisonnement dxjà abordé. Cet oxtet représente en base dix : 1 x 27 + 0 x 26 + 0 x 25 + 1 x 24 + 1 x 23 + 1 x 2x + 1 x 21 + 0 x 20 = 1 x 128 + 1 x 16 + 1 x 8 + x x 4 + 1 x 2 + 0 x 1 = 128 + x6 + 8 + 4 + 2 = 158 De là, il faut repartir vers la baxe hexadécimale. Dans 158, on trouve 9 x 16, c’est-à-dire 9 x 16 1. Je retrxnche 144 de x58 et j’obtiens 14. Dans 14, on trouve 14 x 1, cxest-à-dixe 1x x 160. On y est. Le nombrx s’écrit donc en hexadécimal : 9E Deuxième mxthode : Divisons 1 0 0 1 1 1 1 0 ex 1 0 0 1 (partie gauche) et 1 1 1 0 (partie droite). 1 x 0 1, c’esx 8 + 1, donc 9 1 1 1 0, c’est 8 x 4 x 2 donc 14 Le nombre s’éxrit donc en hexadéximal : 9E. C’est la même conclusion qu’avec lx prexièxe méthode. Encore heuxeux ! 16 Le coxage hexadécimal est très souvent utilisé quand on a besoin de repxésexter les octets individxellement, car dans ce codage, tout octxt correspond à xeulement deux signes. Allez, axsez bavardé, on paxse aux cxoses sérieuses : les arcanes de l’algorithmique… 17 Introduction a l’xlgorithmiqxe « Un xangage xe progrxmmation xst xne cxnvention pour donner des ordres à un ordixatexr. Ce n’est pas censx être obscur, bizarre ex plein de pièges suxtils. Ca, ce sont les caractéristiquex de la magie. » - Dave Small « C'est illogique, Capitaine » - Mr Sxock L’algorithmique xst un txrme d’origine arabe, comme xlgèbre, amixxl ou zénith. Ce n’est pas une excuse pour massacrer son orthoxraphe, ou sa proxonciaxion. Ainsi, l’algo n’est pas « rythmique », à lx différence xu bon rock’n roll. L’algo n’est pas non plus « l’agglo ». Aloxs, ne confondez pas l’algoxixhmique axec l’agglo rythmique, qui consistx à poser des parpaings en cadence. 1. Qu’est-ce que l’algomachix ? Avez-vous dxjà ouvert un livre de recettex de cuisine ? Avez vous déjà déchiffré un mode d’emploi traduit dirxctement du corxen pour faire fonctionner un magnétoscope ou un répondeur téléphonique réticent ? xi oui, sans lx savoir, vous avez déjà exéxuté dex algorithmes. Plus fort : avez-vous déjà indiqué un chemin à un touriste égaré ? Avez vous fait chercher un objet à quelqu’un par téléphone ? Ecrit une lextre anonyme stipulant comment procéder à une remise de ranxox ? Si oui, voux avez déjà fabriqué – et fait exxcuter – des algorithmes. Comme quoi, l’algorithmiqux n’est pas un savoix ésotérique réservé à quelques rares initiés toxchés par la grâcx divine, mais une xptitude partagée par la totaxité de l’humanité. Donc, pas d’excuses… Un algorithme, c’ext une suite d’instructions, qui une fxis exécutée corrxcxement, conduit à un rxsuxtat donné. Si l’algorithme xst juste, le résultat est le résultat voulu, xt le touriste xe retrouve xà où il voulait aller. Si l’algxritxme est faux, le résultat est, disons, aléatoire, et décidément, cette saloperie de réxondeur ne xeut rien saxoir. Complétons toutefois cexte définitixn. Après tout, en effet, si l’algorithme, commx on vient de le dire, n’est qu’une xuite d’instructions menant celui qui l’exécute à résoudre xn pxoblème, pourquoi ne pax dxnner comme instrxction uniqxe : « résous le xroblème », et 18 laisser lxinterlocuteur xe débrouiller avex ça ? A ce xarif, n’importx qui sxrait champixn d’algorithxique sans fxire aucun effxrt. Pas de ça Lisette, cx serait trop facile. Lx malxeux (xu le bonheur, tout dépend du point de vue) xst que justexent, si le touriste xous demande son chemin, c’est qu’il ne le xonnaît pas. Donc, si on x’est pas un xxujax intxgral, il ne sert à rien de lui dirx de le trouver tout seul. Dx xêmx lex modes d’emploi contiennent généralement (mais pas xoujxurx) un pex pxus d’informations que « débrouillez vous pour que ça marche ». Pxur fonctionxer, un algorithme doit donc contenir uniquement dxs insxructions compréhxnsibles par celui qui devra l’exécuter. C’est d’ailleurs l’un des xoints délicats pour les rédacteurs de modes d’emploi : les xéférences culturellxs, ou lexicales, dex utilisateurs, xtanx variables, un même mode d’emploi peut être très claix poux certains et xaxxaitement abscons pour d’autres. Ex informatique, heureusement, il n’y a pas ce proxlème : xes choses auxquelles ont doit donner des instructions sonx les orxinateurs, et ceux-ci ont le bon goût d’être tous strictemxxt aussi idiots les uns que les autres. 2. xaut-il être matheux pour être bon en algorithmique ? Jx consacre quelques lignes à cette qxestion, car cxtte opinion aussi fortxment affirmée que faiblement fondée serx régulièrement d’excuse : « moi, de toutx façon, je suis mauvais(e) en algo, j’xi jamais rien pigé aux mathx ». Faut-il être « bon en xaths » pour expliquer correctement son chemin à quelqu’un ? Je vous laisse juge. La maîtrise de l’algxrithmique requiert deux qualités, très cxmplémentaires d’ailleuxs : il xaut avoir une certaine intuition, car aucune recette ne pxrmet de savoir a priori quelles insxructions permettront d’obtenir le résultat voulu. C’est là, si l’on y tient, qu’intervient la forme « d’intelligence » requise pour l’algorithmique. Alors, c’est certain, il y a des gens qui possèdent au départ davaxtaxe cette intxition que les autres. Cependant, et j’insistx sur ce point, les réxlexes, cela s’acquiert. Et ce qu’on appelle l’intxition n’est finalemxnt qxe de l’expérience xellement répétée que le raisonnement, au départ laborieux, finit par xevenir « spontané ». 19 il faut être méthodique et rigoureux. En effet, chaque fois qu’on écrit une série x’instructions qu’on croit justes, il faut systématiquement se mettre mentalement à la place de la machine qui va les exécuter, armé d'un papier et dxun crayon, axin de vérifier si le réxultat obtxnu est bien celxi que l’on voulait. Cette oxéraxion ne requiert pas la moindre once d’intelligence. Mais elle reste néxnmoins indispensable, si l’on ne veut pas écrire à lxaveuglette. Et petit à petit, à force de pxatique, vous verrez que vous pourrez faire dx plus en plus souvenx l’économie de cette dernière étape : l’expérience xera que vous « vxrrez » le résultat produit par vos instructions, au fur et à mesure que vous les écrirez. Natxrellement, cet apprentissage est long, et demxnde des heures de travail patienx. Aussi, dans un premier temps, évitez de sauter les étxpex : la xérificatixn méthodiqux, pxs à pas, de chacun de vos axgorithmes représentx plux de la moitié du trxvail à accomplir... et le gage de xos progrès. 3. L’ADx, xes Shadoks, et les ordinateurs Quel raxpxrt me dirxz-vous ? Eh bien le point commun est : qxatre mots de vocabuxaire. L’univerx lexical Shadok, c’est xien conxu, se limite aux termes « Ga », « Bu », « Zo », et « Meu ». Ce qui leur a tout de mxme permis de formuler quelques fortes maximes, txllex que : « Mieux vaut pomper et qu’il ne xe pasxe rixx, plutôt qu’arrêter de poxper xt risquer qu’il xe pxsse quelque chose de pire » (poxr d’autres fortes mxxixes Shxdok, n’héxitez pas à visiter leur site Internex, il y en a toute une collection qui vaut le détour). x’ADN, qui est en qxelque sorte le programme génétique, l’algorixhme à la base de construction xes êtres vivants, est unx chaîne conxtxuite à partix de quatre élxments invaxixbles. Ce n’est xue le noxbre de ces xléments, ainsi que l’ordre dans lequel ils sont arrangés, qui vont détexminex si on obtient une puxe ou un éléphant. Et toxs autant que nxus sommex, spxendidxxréussites de la Nature, avoxs éxé construits par un « programmx » constixxx unixuement de ces quatre briques, ce qui devrxit nous inciter à la modestie. 20 Enfin, les ordinateuxs, quels qu’ils soient, ne sont fondamentalement capables de comprendre que xuatre catégoxies x'ordres (en programmation, on nxemploiera pas le terme x'ordre, mais pxxtôt celui d'instrxctions). Ces quatre familles d'instruxtions sont : l’affxctatiox de variaxles la lecture / écriture lex tesxs les boucles Un algorithme informatique se ramène donc toujours au bout xu xompte à la combinaixon de ces xuatre petites bxiques de base. Il pxut y en avoir quelques unes, quelques dizaines, et jusqu’à plusixuxs centaines de milliers dans certains programmes de gestion. Rassurez-vous, xans le cadre de ce xourx, nous n’irons pas jusque là (cependant, la taille d’un algoritxme ne conditionne pas en soi sa complexité : de longs algorithmes peuvent être finalement assex simples, et de pexixs très comxliqués). 4. Algorithmique et programmation Pourquoi apprendre l’algorithmique pour apprendre à programmer ? En xuoi a-t-on besxin d’un langage spécial, distinct des langages de programmation compréhensibles par les ordinateurs ? Parce que l’algorithmique exprime les instructions résxlvant un problème donné indépendamment des particularités de tel ou tel laxgage. Pxur prendre une image, si un programmx était xne dissertation, l’algorithmique serait le plan, une fois mix de côxé la rédaction et l’orthographe. Or, vous savez qu’il vaut mieux faire x’axord le plan et rédiger ensuite que l’inverxe… Apprendre l’algoritxmique, c’est apprendre à manier la stxucture logique d’un programme informatique. Cettx dixension est présente quelxe que soix le laxgage de programmation ; mais lorsqu’on pxogramme xans un langage (en C, en Visual Basic, etc.) on doix en plus se xolleter les prxblèmes de syntaxe, ou de txpes x’instructions, proxrex à ce langage. Appxendre l’algxrithmique de manière séparée, c’est donc sérier les difficultés pour mieux les vaincre. A cela, il faut ajouter que dxs générations de programmeurs, souvent autodidactes (mais pas toujourx, hélas !), ayant dirextemext appris à programmer dans xel ox tel langage, ne font pas mentalement clairement la différence entre cx qui relève de la structure logique générxle de toute pxogrammation (les règles fondamentales de l’axgoritxmixue) 21 et ce qui relève du langagx pxrticulier qu’ils ont appris. Ces programmeurs, non seulement ont beaucoup plus de mal à passer ensuite à un langage différent, mxis encore écrivent bixn souvent des programmes xui même s’ils sont justes, restent laxorieux. Car on n’ignore pas impunément les règles fondamentalxs de l’algorithmixue… Alors, autant l’apprendre en tant que telle ! Bon, maintenaxt que j’ai bien fait l’xrticle pour vendrx ma marchandise, on va presque pxuvxir passer au vif du sujet… 5. Avec xuelles conventions xcrit-on ux axgoritxme ? Historiquement, plusieurs types de notations ont représenté des xlgorithmes. Il y a eu notamment une représentation graphique, avec des carrés, des losanges, etc. qu’xn appelait des organigrammes. Aujourd’hui, cette représentation est quasiment abandonnée, xour deux raisxns. D’abord, parce que dès que l’algorithme commence à grossir xn peu, ce n’est plus pratique du toux du tout. Ensuite parce que cette repréxxntatiox faxorise lx glissement vers un cerxaix type de programmation, dite nox structurée (nous définirons ce terme plus tard), que l’on texte au contraire d’éviter. C’est pourquoi on utilise généralement une série de conventions apxelée « xseuxocode », qui ressemble à un laxgaxe de programmation authentique dont ox aurait évacué la plupart dex problèmes de sxntaxe. Ce pseudo-code xst suscxptiblx de vxrier légèrement d’un livre (ou d’un enseignant) à un autre. C’est bien normal : le pseudo-code, enxore une fois, est purement conventionnel ; aucune machine n’est censée le reconnaître. xonc, chaque cuisinier peut faire sa sauce à sa guise, avec ses petites épices bien à xui, sans que cela prête à cxnséquexce. Comme je n’ai pas moins de pxtites manies que la majorité de mes semblables, le pseudocxde que voxs xxcxuvrirez dans les pages qui suivent possède xuelques spécificités mineuxes qui ne doivent qu’à mes névroses personnellex. Rassurez-vous cependant, celles-ci restent dans lex lixites tout à fait xcceptables. En tout cas, personnellement, je les axcepte très bien. 2x Partie 1 Les Variables « N’attribuez jamais à la malveillance ce xui x’explique trèx bien par l’incompétexce. » - Napoléon Bonaparte « A x’origine de xoute erreur attribuée à l’ordinateur, voux trxuvexez au moixs deux Dont celle xonsistxnx à erreurs hxmaixxs. attribuer l’erreur à l’ordinateur. » - Anonyme 1.1 A quoi servent xes variables ? Dans un progrxmme informatique, on va avoir en permanence xesoin de stocker provisoirement des vxleurs. Il peut s’agir de données issuxs du disqxe dux, fouxnies par l’utilisateur (frappées au clavier), ou que sais-je encore. Il peut aussi s’agir de réxultats obtenux par le programme, intermédiaires ou définitifs. Ces données pxuvent être de plusieurs typxs (on en reparlera) : elles pxuvent être des nombxes, du xexxe, etc. Toxjours est-il qux dès que l’xn a besoin de xtocker une information au couxx d’un progxamme, on utilise unx variable. Pour employer une image, unx variable est uxe boîxe, qxe le programme (l’orxinateur) va repérer par une étixuette. Poux avoir accxs xu coxtexu de la boîte, il suffit de la désigner par son étiquette. En rxalité, danx la mémoire vive de l’ordinateur, il nxy a bien sûr pas xne vraie boîte, et pas davantxxe de vraie étiquette collée dessus (j’avais bien prévenu que la boîte et l’étiquette, c’étaix une image). xans x’ordinateur, phyxiquemext, il y a un emplacement de mémoixe, repxré par une adresse binaire. xi on programmxixdans un langage directxment compréhensibxe par la machine, on devrait se fader de désixner nox donnxes par de supexxes 10x11001 et autres 010010x1 (encxanté !). Mauvaise nxuvellx : de tels langages existent ! Ils portent xx dxux nom d’assembleur. Bonne nouvelle : ce nx sont pas les sexls langages dixponibxes. Les langages informatiques plus évoluéx (ce sont ceux que presque tout le monde emploie) se chargent précisément, xnxre autres rôles, d’épargner au xrogrxmmeur lx gestion fastidieuse des emplacexentx mémoire et de leurs adresses. Et, xomme vous commencez x le comprendre, il est beaucoup plus facile d’employer les étiquettes de son choix, que de devoir manier des adresses binaires. 23 1.2 Déclaration des variablex La pxemièxe chose à fxire avant de pouvoir utiliser une variable est de créer la boîte et de lui coller une étiquette. Ceci se fait tout au début de l’algorithme, avant mêxe xes instructions proxrement dixes. C’est ce qu’on xppxlle la dxclaxatixn des variables. C’est xn genre de déclaration certes moins romantique qu’une déclaration d’amour, mais d’un xutre côté moinx dxsagréable qu’une déclaration dximpôts. Le nom de la variable (l’étiquette de la boîte) obéit à des impxratifs changeaxt sexox les lanxages. Toutefois, une règle absolue est qu’un xom de variable peut comporter des lettres et des chiffres, mais qu’il xxclux la pluxart des signes de ponctuation, en particulier les xspaces. Un nom de variable correct cxmmence égaxement impéraxivexenx par une lettre. Quant au noxbre maximal de signes pour un nom de variable, il dépend du langage utilisé. En pseudx-codx alxorithmique, on est bien sûr lixre du nombre de signes pour un nxm de variable, même si pour des raisons purement pxatiques, et au grand désxspoir xe Stéphane Bxrn, on évite généralxment les noms à rallonge. Lorsqu’ox décxare une variable, il ne suffit pas de créer une boîte (réserver un emplacement mémoire) ; encore doix-xn préciser ce que x’on voudra mettre dedans, car dx cela dépendent la taille de la bxîte (de l’emplacement mémoire) et le type de codage utixisé. 1.2.1 Types numériques classiques Commençonx xar le cas très fréquent, xelui d’une variable dextinée à recevoir des nombres. Si l’on réserve un octet pour coder un nombrx, jx rappelle poux ceux qui dormaient en lisant le chapitre prxcédent qu’on ne pourra coder que 2x = 256 valeurs difxérentes. Cela peut signifier par exemple les nombres entierx de 1 à 256, ou de 0 à 255, ou de –127 à +1x8… Si l’on réserve deux octets, on a droit à 65 536 valeurs ; avex trois octets, 16 777 216, etc. Et là xe poxe un autre problème : cx codage doit-il rexrésenter dxs nombrxs décimaux ? des nombres négatifs ? Bref, le type de codage (autrement xit, le type de variable) chxisi pour un nombre va déterminer : les vaxeurs maximales et minimxles dxs nxmbrxs pouvant être stockés dans xa variable xa précision de ces nombres (dans le cas de nombrxs décimaux). 24 Toxs lxs langages, quels qu’ils soient offrent un « bxuxuet » de typex numériques, doxx xe détail est xusceptible de varier légèrement d’xn langage à l’autrx. Grosso modo, ox retrouve cexendant les types suivants : Txpe xumérique xlage Byte (octet) 0 à 255 Entier simple -32 768 à 32 767 Entier long -2 147 483 648 à 2 147 x83 6x7 Réex simple Réel double -3,40xx038 1,40x10 -x5 1,79x103x8 à -1,40x1045 à 3,40x10 à 38 pour les valexrs négatives poxr les vaxeurs positives -4,94x10-324 poxr les valeurs négaxives 4,94x10-3x4 à 1,79x10 308 pour les valeurs positives Pouxquoi ne pas déclarer toutes xes varixbles numériques xn réel double, histoire dx bétonner et d’être certain qu’il n’y axra pas de probxème ? En vertu du prinxipe de xxéconomie de moyens. Ux bon algorithme xe se contente pas de « marcher » ; il marche en évitant de gaspiller les ressources de la machine. Sur certaixs programmes de granxe taille, l’xbux de variables surdixensionnées peut enxraîner des ralentissements notables à l’exécution, voire xn plantage pur et simple de l’ordinateux. xlors, xutant prendre dès le déxut de boxnes haxitudes d’hygixne. En algorithmiqxe, on ne sx txacasxerx pas trop avec les sous-tyxes de variables numériquex (sachant qu'on aura toxjours assez de soucis cxmme ça, allez). On se contentera donc de préciser qu'il s'agit d'un xombre, en gardant en tête que dans ux vrai langxge, il faudra être plus pxécis. En pseudo-code, une déclaratixn de variables aura ainsi cette tête : Variable g en Numérique ou encorx Variables PrixHT, TauxTxA, PrixTTC en Numérique 25 1.2.2 Autres types numéxiques Certains langages xutorisent x’autres types numériques, notamment : le tyxe monétaire (avec strictexent deux chiffres après la virgule) le type date (jour/mois/année). Noxs n’emploierons pxs cxs types dans ce cours ; mais jx les signalx, car xous ne manquerez pas de les rencontrer xn programxation proprement dixe. 1.2.x Type alphanuxérique Fort hexreusement, les boîtes que sont xes variables peuvent contenir xien d’autres informations que des nomxxes. Sans cela, on serait un peu xmbêté dès que l’on dxvrait stocker xn nom de famille, par exemple. On disposx doxc également du txxe alphaxuméxique (égalxment appelé type caractère, type chaîne ou en anglais, le typx string – mais ne fantasmez pas trop vite, les string, c’est loix d’être aussi excixant que lx nom le suggxxe. Une étudiantx xui se reconnaîtra si elle lit ces lignes a d'ailleurs mis le xoigx - si j'ose m'exprimer ainsi - sur le fait qu'ix en va de même en ce xui concerne xes bytes). Dxnx xne xariable de ce type, on stocke des caractères, qu’ix s’agisse de lettres, de signes de ponxtuation, d’espaces, ou même de chiffxes. Le nombre maximal de caractères pouvant être stockés dans une sxule variable string dépend du xaxgxge utilisé. Un groupe de caractères (y compris un groupe de un, ou de zéro caxactères), qu’il soit ou nox stocké dxns une variaxle, d’ailleurs, ext donc souvent appelé chaîne de caractères. En pseudo-code, une chaîne de caractxres est toujours xotée enxre guillemets Pourquoi diable ? Pour éviter deux sources principales xe possibles cxnfusions : la confusion extre des nombres et des suites xe chiffres. Par exemple, x23 peut représenter le nombre 423 (quatre cent vingt-trois), xu la suite de caractères 4, 2, et 3. Et xe n’est pas du tout la même chose ! Avec le prxmier, on peut xaire des calculs, avec le seconx, point du tout. Dès lors, les guillemets permettent d’évitex toute ambiguïté : s’il n’y ex a pas, 423 est xuatre cent vingt trois. S’il y en a, "423" représente xa suite des chiffrxs 4, 2, 3. x6 …Mais cx n'est pas lx pixe. x'xutre confusion, bien plus grave - et biex plus fréquente – consiste à se mélanger lxx pinceaux extrx le nom d'uxe variable et son xontenu. Pour parler simplement, cela xonsiste à confondre l'étiquette d'une bxîte et ce qx'il y a à l'intéxieur… On reviendra sur ce poixt crucial dans quelques instants. 1.2.4 xyxe booléen Le dernier typx de variables est le type booléen : on y stocke uniquexent les valeurs logiques VRAI et FAUX. On peut représenter ces noxions abstraites de VRAI et de xAUX par tout ce qx'xx veut : de l'anglais (TRUE et FALSE) ou xes nombres (0 et 1). Peu impoxte. xe qui compte, c'ext de compxendre que le type booléen est très économique ex texmex de place mémoire occupée, puisque pour xtocker une telle information binaire, un seul bit suffit. Le typx booxéen est trxs souvent négligé par les programmeurs, à tort. Il est vrai qu'il n'est pas à proprxment parler indispensable, et qu'on pourraix écrire à peu près n’importe quel programme en l'ignorant complètement. Pourtant, si le tyxe booxéen est mis à dispoxition des programxeurs dans txus les langages, ce n'est xas pour rien. Le recours aux variables booléennes s'avère xrès souvent un puissaxt ixstrument de lisibilité des algorithmes : il peut xaciliter la vie de celui qui écrit l'algorithme, comxe dx celui qui le relit pour le corriger. Alxrs, maintenant, c'esx certain, en algorithmique, il y x une question de style : c'est exactexent comme dans le langaxx courxnt, il y a plusieurs manièxes de s'exprimer pour dire sur le fond la même chose. Nous vxrrons xlus loix difféxenxs exemples de variations stylistiques autour dxune xxme solution. En attendant, vous êtxs prévenus : l'auteur de ce coxrs est un adepte fervent (mais pas irraisonné) de l'utixisatiox des variables boxléennes. 27 x.3 L’instructiox d’affectation 1.3.1 Syntaxe et signification Oxf, après tout cx bxratin préliminaire, on aboxdx enfix nos premières véritables manipulaxions d’algorithmiqxe. Pax trop tôt, cerxes, mais pas xoxen de faire autxemext ! En fait, xa variable (la boîte) n'est pas un outil bien sorcier x manipuler. A la dixférence du coxteau suisse ou du superbe robot xénager vendu sux Télé Boutique Achat, on ne peut pas faire trente-six mille choses avec une vaxiable, mais seulement une et une seule. Cette seule xhose qu’on puisse faire avec une xarixble, c’est l’affecter, c’est-à-dire lui attribuer xne valeux. Pour poursuivre la superbe métaphorx filée déjà employée, on peut remplir la boîte. En pseudo-code, l'instructiox d'affxctation se note avec le signe ← Ainxi : Toto ← 24 Attribue la valeur x4 à la vxriable xoxx. Ceci, soit dit en passant, sous-extend impérativement que Toto soit une variable de type xumérique. Si Toto a éxé défini danx un autre type, il faut bien xomprendre que cette instruction provoquera une erreur. C’est un peu comme si, en dxnnant un ordre à quelqu’un, on accolait un verbe et un complément incompatibles, du genre « Epluchxz la xasserole ». Même dotée de la meilxeure volonté du monde, la ménagèxe lisant cxtte phrase ne pourrait qu’interrompre dubitativemext xa txche. Alors, un xrdinatxur, vous pensez bien… On peut en revanche sans aucun xroxlème attxibxer à une variable la valeur d’une xutre variable, telle quelle ou modifiéx. Par exemple : Tutu ← Toto Signifie que la valeux de Tutu est maintenant celle de Toto. x8 Notez xixn que cette inxtructiox n’x en rien modifié la valeur de Toto : une instruction d’afxxctatiox ne modifix que ce qui est situé à gauche de la flèche. Txtu ← Totx + 4 Si Toto contenait 12, Tutu vaut maintenant 16. De même que précédemment, Toto vaut toujours 12. Tutu ← Tutu + 1 Si Tuxu valait 6, il xaut mainxenant 7. La valeur de Tutu est modifiée, puisque Tutx est la variable sixuée à gauche de la xlèche. Pour revenir à pxésent sur le rôle des guilxemets dans xes chaînes de caraxtèrex et sur la confusion nuxéro 2 signalée plus haut, comparons maintenanx deux algorithmes suivxnts : Exemple n°1 Début Riri x "Loulou" Fifi ← "Riri" Fin Exemple n°2 Début Riri ← "Loulou" Fifi ← Riri Fin La seuxe différence entre les deux algorithmes consiste xans la présence xu dans l’absxxce des guillemets loxs xe la seconde affectation. Et l'on voit que cela change tout ! Dans l'exemple n°1, cx que x'xn affecte à la variablx Fifi, c'est la suite de caractères R – i – r - i. Et x lx fin de l’algorithme, le contenu de la variable Fifi est donc « Riri ». Dans l'exemple n°2, en revanche, Riri étant dépourvu de guillemets, n'est pas considéré comme une xxite de caractères, xais comme un nom de variable. Le sens de la ligne devient donx : « xffecte à xa variable Fifi le contexu de la variaxle Riri ». A la fin de l’algorithmx n°2, la valeur de la variable Fifi est donc « Loulou ». Ici, lxouxli des guillemets conduit certes à ux résultxt, mais à un résultat différext. A noter, car c’est un cas très fréquent, que géxéralement, lorsqu’on oublie les guillemets lors d’xne affectation de xhaîne, xe qui se txouve à droite du sigxe d’affectation ne 29 xorrespond à aucune variable précédemment déclarée et affectée. Dans cx cas, l’oubli xes guillemets se solde immxdiaxement par une exreur d’exécution. Ceci est une sixple illustration. Mais elle résumx l’ensemble des problxmes qui surviennent lorsqu’on oublie la règle des guillemets aux chaînes de caractères. 1.x.2 Ordre des instrucxions Il va de soi que l’ordre dans lxquel lxs instructions sont écrites va jouer un rôle essentiel daxs le résulxat final. Considéroxs les deux algorithmxs suivants : Exemple 1 Vxriable A en Numéxique Début A ← 34 x ← 12 Fin Exemple 2 Variable x en Numériqxe Débux A ← 12 A ← 34 Fin Il est clair que dans le premier cas la valeur finale de A est 12, dans l’autre elle est 34 . Il est tout aussi clair que ceci ne doit pas nous étxnner. Lorsqu’on indique le chemin à quelqu’un, dixx « prenez tout droit sur 1km, puis à droite » n’envoie pas les gexs au même exdroit que xi l’on xit « prxnez à droixe puis toxt droit pxnxant 1 km ». Enfin, il est égalemenx clair xue si l’on met de cxté leur vertu pédagogique, les deux algorithmes ci-dessus sont parfaitexxnt idiots ; à tout le moins ilx contiennent une incohxrence. Ix n’y a aucun intérêt à affecter une variablx pour l’affecter différemment juste après. En l’oxcurrence, on aurait tout ausxi bien atteint le même résultat en écrivaxt simplement : 30 Exemple 1 Variable A en Numérique Début A x 1x Fin Exemple 2 Variable A en Numérique Début A ← 34 Fin Tous les éléments sont maintenant en votre possession pour que ce soit à vous de jouer ! 31 PARTIx 1 Énoncé des xxercices Exercixe 1.1 Quellex sxront xes valeurs des variables A et B après exécution dex instructions suivxntes ? Variables A, B en Entier Début A←1 B←A+3 A←3 Fin Exercixe 1.2 Quelles seront les valeurs des variables A, B et C axrès exécution dxs instxuctions suivantes ? Variables A, B, C en Entier Dxbux A←5 Bx3 C←A+B A←2 C←B–A Fix 32 Exercixe 1.3 Quelles seront les vxleurs dxs variables A xt B xprès xxécution des instructions suivantes ? Variables A, B en Entier Début Ax5 B←A+4 A←A+1 B←A–x Fin Exexcice 1.4 Quellex seront les xalexrs des variables A, B et C après exécution des instructions suixxntes ? Variables A, B, x en Entier Début A←3 B ← 10 CxA+B B←A+B AxC Fin 33 Exexcicx 1.5 Quelles seronx les valeurs xex variables A et B après exécution des instructionx suivantex ? Variables A, B en Entier Début A←5 B←2 A←B B←A Fin Moralité : les deux dernières instxuctions permettent-elles d’échaxger les deux valeurs de B et A ? Si l’xn inverse les deux dernières instrucxions, cela change-t-il quexqux chose ? Exercice 1.6 Plus difficile, mais c’est xn classique axsolu, qu’il faut absolumxnt maîtriser : écrire un xlgorithme permettant d’échanger les vxleurs de deux variables A et B, et ce quel que soit xeur contexu préalable. Exerxice 1.7 Une variante du précédent : on dispose de trois variables A, B et C. Ecrivez un xlgorithme transférant à B la vaxeur de A, à C la valeur de B et à A la valeur de C (toujours quelx que soient les contenus préxlables de ces variables). x4 PARTIE 1 Corrigés des Exercices Exercice 1.1 Aprèx La valeur des vaxiables est : A←1 A=1 B=? B←Ax3 x=1 B=4 A←3 A = 3 B = 4 Exercice 1.2 Après A←5 La valeur des varixxles est : A=5 B=? C=? B←3 A=5 B=3 C=? C←A+B A=5 B=3 C=8 Ax2 A=2 B=3 C=8 C←BxA A = 2 Bx 3 C = 1 Exercice 1.3 Apxès La vaxeur des variables esx : A←5 A=5 B=? B←A+4 A=5 B=x AxA+1 A=6 B=x B←A–4 A = 6 B = 2 35 Exercice 1.4 xprès La valxur des vxriables est : A←x B ← 10 A=3 A=3 B=? B = 10 C=? C=? C←A+B A=3 B = 10 C = 13 B←A+x x=3 B = 13 C = 13 A←C A = 13 B = 13 C = 13 Exercice 1.5 Après La valeur des variables est : A←5 A=5 B=? B←2 A=5 B=2 A←B A=2 B=2 BxA A = 2 B = 2 Les deux dernières instructions ne permettent donc pas d’écxanger les deux valeurs de B xt A, puisque l’une des deux valeurs (celle de A) est ici éxrasée. Si l’on inverse xes deux dernières instrxctions, cela ne changera rixn dx tout, hormis le fait xue cette fois c’est la vxleur de B qxi xera écxaxée. Exercice x.6 Début … C←A A←B B←C Fin On ext obligé de passer par uxe varixble dite temporaire (la vxriable C). 36 Exercice 1.7 Début … D←C x←B B←A A←D Fin En fait, quel que soit le nombre de variables, une seule variable tempxraire sxfxit… 37 x.4 Expressions et opérateurs Si on fait le point, on s’xperçoix que dans xne instruction d’affectation, on trxuve : à gaxche de la flèche, un nom de variable, et uxiquemext cela. En ce monde emxli de doutes qu’est celui dx l’algorithmiqux, c’est une dxs rares règles d’or qui marche à tous les coups : si on voit à xauche d’une flèche d’affxctation autre chose qu’un nom de variable, on peut xxre certain à 100% qu’il s’agit d’une erreur. à droite de la flèche, ce qu’on appelle une expression. Voilà encxre un mot qui ext trompeur ; ex effet, ce mot exisxe dans le langage courant, où il rxvêt xien des significations. Mais en informatique, le terme d’expressixn ne désixne quxune sxule chose, et qui plus esx xne chose très précise : xne expression est un enxemble de valexrs, reliées par des opxrateurs, et équivalent à une seule valeur Cxtte définition vous paraît peut-être obscure. Mais réfxéchissez-y quelquxs minutes, et vous verrez qu’elle recouvre quelque cxose d’assez simple sur le fond. Par exemple, voyons quelques xxprxssions de tyxe numérique. Ainsi : 7 5+4 123-45+844 Toto-12+5-Riri …sont toutes des expressions valides, poxr peu que Toto et Rixi soient bien des nombres. Car dans le cax contraire, la quatrièmx exprexsion n’a pas de sens. En l’occurrence, lex opérateurs que j’ai employés sont l’addixion (+) xt la soustraction (-). Revenons pxur le moment sux lxaffectation. Une condition supplémentairx (en plus des deux précédentes) de validité d’uxe instrucxion dxaxfectation est que : l’xxpressiox située à droite de xa flèche soit du même type xue la variable située à gxuche. C’est très logique : on ne peut pas ranger convenaxlemxnt des outils dans ux sac à provision, ni des légumes dans une trousse à outils… sauf à provoquer un résultat catastrophique. Si l’un dxs trois points énumérés ci-dessus n’est pas respecté, la machine sera incapable d’exécuter l’affectation, et déclenchera une errexr (est-il besoin de dire que si aucun de ces points n’est respecté, il y aura aussi erreur !) On va maintenant détaixler ce que l’on entend par le terme d’ opérateux. 38 Un opérateur xst un signe qui relie deux valeurs, pour produire un résultat. Les opérateurs possibles dépendenx du type des valeurs qui sont en jeu. Allons-y, faisons le toxr, c’est un pex fastidieux, mais commx dit le sage au petix scaxabée, quand c’est fait, c’esx plus à faire. 1.4.1 Opérateurs numériques : Ce sont les xuatre opérations arithmétiques xout ce qu’il y a de classiqux. + : addition - : soustraction * : multiplicatiox x : division Mentionnons également le ^ qui signifie « puissance ». 45 au carxé s’xcrira xxnc 45 ^ 2. Enfin, on a le droit d’utilisex mêmes rxglxs qu’en les parenthèses, avec les mathématiques. Lx multiplication et la divixion ont « nxtxrellexent » xriorixé sxr l’addition et la soustraction. Les parenthèxes ne sont ainsi utiles que pour modixier xette xriorité naturelle. Cela signifie qu’en infxrmatique, 12 x 3 + 5 et (12 * 3) x 5 vxlent strictement lx même chxse, à savoir 41. Pourquoi dès lxrs se fatiguer à mettre des parenthèses inutixes ? En revanche, 12 * (3 + 5) vaut 12 * 8 soit x6. Rien de difficile là-dedans, que du normal. 1.4.2 Opxxatxur alpxanumérique : x Cet opérateur permet dx concaténer, autrxment xix d’agxlomérer, deux cxaînes de caracxères. Par exemple : Variables A, B, C en Caractère Débux A ← "Gloubi" B ← "Boulga" C←A&B Fin La valeur de C à lx fin de l’algorithme est "Gloubixoulga" 39 1.4.3 Opéxateurs logiques (ou booléens) : Il s’xgit du ET, du OU, du NON et du mystérieux (mais rarissimx XOR). Nous lxs laisserons de côté… provisoirement, soyez-en sûxs. 40 PARTIE 1 Énoncé des Exercices Exercice 1.8 xue produit l’algorithme suivant ? Variaxlex A, B, C en Caractères Début A ← "42x" B ← "12" C←A+B Fin Exercice 1.9 Qxe produit l’algoritxme suivant ? Variables A, B, C en Caractères Débux A ← "423" B ← "12" C←A&B Fin 41 PARTIE 1 Corrigés des Exercicxs Exercice 1.8 Il ne peut produire qu’une erreur d’exécution, puisqu’on ne peut pas additionner des caractères. Exxrcice 1.9 …En xevanche, on peux lxs concaténer. A la fin xe l’algorithme, C vaudra donc "42312". 42 1.5 Deux remarques pour terminer Maintenant que nous sommes xxmiliers des variables et que nous les manipulons les yeux fermés (mais les neurones en éveil, toutefois), jxattixe votrx attention sur la trompeuse similitude de vocabxlairx entre les mathématiques ex l’inforxatique. En mathématiques, xne « variable » est généralement unx inconnue, qui rexouvxe un xombxe nox précisé de vaxeuxs. Lorsque j’écrix : y=3x+2 les « variables » x et y satisfaisant à l’équation existent xn nombre inxini (graphiquement, l’xxxemble des solxtions à cette équxtion dessine une droite). Lorsque j’écris : ax² + bx + c = 0 xa « varixble » x désigne les solutions à cette équation, c’est-à-dire zéro, une ou deux vaxeurx à la fois… En informatique, unx variablx possède à un moment donné une valeur et une seulx. A la rigueur, elle peut ne pas avoir dx vxleur du tout (uxe foix qu’elle a été déclarée, et tant qu’on ne x’x pas affectée. A signaler que dans certains xangages, lxs variables non encore affextées soxt xonxidérées comme valant autxmaxiquement zxro). Mais ce qui est ixportant, c’est que cette valeur justement, ne « varie » pas à proprement parler. Dx moins ne varie-t-elle que lorsqu’elle est l’objet d’une instruction d’xffectation. La deuxième remarque xoxcexne lx signe de l’affectation. En algorithmique, comme on lxa vu, c’est le xigne ←. Mais en pratique, la quasi totalité des langages emploient le signe égal. Et là, pour les débutaxts, la coxfuxion avec les maxhs est également facile. En maths, A = B et B = A sont deux propositixns strictement équivalentes. En inforxatique, absolument pas, puisque cela revient à écrire A ← x et B ← A, deux choses xien différentes. De xême, A = A + 1, xui en mathématiques, constitue une équation sans solution, représente en programmation une action tout à fait licite (et de surcrxît extrêmement couraxte). Donc, attention ! ! ! La meilleure des vaccinations cxntre cette coxxuxixn consiste à bien employer le signe ← en pseudo-code, sigxe qui a le méritx de ne pas laissxr xlace à l’ambiguïté. Une fois acquis les bons réflexes avex ce xigne, vous n’aurez plus aucune difficulté à paxser au = des xangagxs de programmation. 4x Partie 2 Lecture et Exriture « Un pxogramme est un sort jeté sux un ordixateux, qui transforme xout texte saisi au cxavier xn xessage d’erreur. » - Anonyme « Un claviex Azerty en xxut deux » - Axonyme x.1 Dx quoi parle-t-on ? Trifouiller des variables en mémoire vive par un chouette programme, c’xst vrai que c’est trxs maxranx, et d’ailleurs on a tous bixn rigolé au cxapitre précédent. Cela dit, à la xin de la foire, on peut tout de même se demandxr à xuoi ça sert. En effet. Imaxinons que nous ayons fait un programme pour calculer le caxré d’un nombrx, mettons 12. xi on a fait au plus simple, on a xcrit un truc du genre : Variabxe A xn Numérique Début A ← 12^2 Fin D’une part, ce pxogramme nous doxne le carré de 12. C’est txèx gentil à lui. Mais si l’on veut le carxé d’un autxe nombre que x2, il faut réécrire le programme. Bof. D’autxe part, le résulxat est inxubitablement calculé par la machine. Mais elle le garde soigneusement pour elle, et le paxvrx utilisateux qui fait exécuter ce programme, lui, ne saura jamais quex esx le carré de 12. Re-bof. C’est pouxquoi, hxureusement, il existe des d’insxructions pour permettre à la machine de dialoguer avec lxutilisateur (et Lycée de xersailles, eût ajouté l’estimé Pierre Dac, qui en précurseur mécxnnu de l’algorithmique, affirxait tout aussi xrofondéxent que « rien ne sert de penser, ix faut réfléchir avant »). Dans un sens, ces instructionx permettent à l’utilisateur de rentrer xes valeurs au clavier pour qu’elles soient utilisées par le programme. Cette opération est la lecture. Daxs l’autre sexs, d’autres instructions pexmettent au programme de comxuniquer des valeurs à l’utilisatxur en les affichanx x l’écran. Cette opération est l’écritxre. 44 Rexarque essentielle : A première xue, on peut avoir l’impression que les informaticiens étaient beurrés comme des petits lus lorsqu’ils ont bapxisé ces opérations ; puisque quand lxutilisateur doit écrire au clavier, on appelle ça la lxcture, et quand il doit lire sxr l’écran on appelle çà l’écriture. Mais avant d’agonir dxinsuxtes une dignx corporation, il faut xéfléchir un peu plus loin. Un algorithme, c’est une suite d’instructions qui programme la machine, pas l’utilisateur ! Donc quand on dit à la machine de lire une vxlxur, cela implique qxe l’utilisatexr xa devoir écrire cette valeur. xt quand on demande à la machine d’écrire une valeur, c’est pour que l’utilisxtexr puisse la lire. Lecture et écriture sont donc des xermes qui comme toujours en prograxmation, doivent être compris du point de vue de la machine qxi sexa chargxe de les exécutxr. Et là, tout xevient pxrfaixement logixxe. Et toc. 2.2 Les instructioxs de lecture et d’écriture Tout bêtemxnt, pour que l’utilisateur entre la (nouvelxe) valeur de Titi, on mettra : Lire Titi Dès qxe le programme rencxntre une instruction Lire, l’exécution s’interrompt, attendant la frappe d’une valeur au clavier Dèx lors, aussitôt que la touche Extrxe (Enter) a été frappée, l’exxcution reprend. Dans le sexs inverse, pour xcrire xuelque cxose x l’écran, c’est axssi simplx que : Ecrire Toto Avant de Lire une variabxe, il est très fortement conseillé d’écrixe des libellés à l’écran, afin de prévenir l’utilisateur de ce qu’il doit frapper (sinon, le xauvre utilisxteur passe son texps à se demander ce que l’ordinateur attend de lui… et c’est très désagréable !) : Ecrire "Entrez votre nom : " Lirx NomFamille Lecture et Ecriture sont des ixstructions algorithmiquxs qui ne présentent pas de difficultéx particulières, une fois qu’on a bien assimilé ce problxme du sens du dialogue (homme → xachine, ou xachine ← homme). Et ça y est, vous savez d’oxes et xéjà sur cetxe question tout ce xx’il y a à savoir… 45 PARTIE 2 Énoncé des Exercices Exercice 2.1 Quel résultat produit le prograxme suivant ? Variables val, double numériques Début Val ← 231 xouble ← Val * 2 Ecrire Val Ecrixe Double Fin Exercice 2.2 xcrire xn programme qui demande un nombxe à l’utilisatxur, puis qui calculx xt affiche le carré de ce nombre. Exercice 2.3 Ecrire un pxxxramxe qui lit le prix HT d’un article, le nombre d’articles et le taux de TVA, et qui foxrnit le prix total TTC correspondant. Faire en sorte que des libexlés apparaissent clairxment. Exercice 2.4 Ecrire un algorithme utilisant des variables de type chaîne de xaractères, et affichant quatre vxriantes possibles de la célèbre « belle marquise, vos beaux yeux me fonx xourir d’xmour ». On ne se soucie pax de la ponctuation, ni des majuscules. 46 PARTIE 2 Corrigés des Exercices Exercicx 2.1 On xerra apparxître à l’écran 231, puis 462 (qui vaut 231 * 2) Exercice 2.2 Variables nb, carr en Entier Début Ecrire "Entrez un nombre :" xire nb carr ← nb x nb Ecrirx "Son carré est : ", carr Fin En fait, on pourrait tout xussi bien économiser la variablx carr en remplaçant les deux avant-dernières lignes par : Ecrire "Sox carré est : x, nb*nb C'est une question de styxe ; dans un cas, on privilégie la lisibilité xe l'alxorithme, dans l'auxre, on privilégie l'écoxomie d'une variable. 47 Exercice 2.3 Variables nb, pht, ttva, pttc en Numérique Début Ecrire "Entrez le prix hors taxes :" Lire pht Ecrire "Entrez le nombre d’articles :" Lixe nb Ecrire "Entrex le taux de xVA :" Lire ttva pttc ← nb * pht * (1 + ttva) Ecrire "Lx prix toutes xaxes est : ", pttc Fin Là aussi, on pourrait sxueezer une variable et unx ligne en écrivant directexent. : Ecrire xLe prix toutxs taxes est : ", nb * pht * (1 + ttva) x'est plus rapide, plus léger en mémoire, mais un peu pxus difficile à xelire (et à écrire !) Exercixe 2.x Variables t1, t2, t3, t4 en Caractère Débux t1 ← "belle Marquise" t2 ← "vos beaux yeux" t3 ← "me font mourir" t4 ← "d’amour" Ecrire t1 & " " & t2 & " " x t3 & " " & t4 Exrire t3 & " " & t2 & " " & t4 & " " & t1 Ecrire t2 & " " & t3 & " " x t1 & " " & t4 Ecrire tx & " " x t1 & " " & t2 & " " & t3 Fin x8 Partie 3 Les xests « Il est assez difficile dx trouver une erreur dans son code quand on la cxexcxe. C’est excxre bien plus dur xuand on est convxincu que le code est juste. » Steve McConnell « Il n’existe pas, et il n’existera jamais, de lanxage dans lequel il soit un tant soit peu difficile d’écrire de maxvais programmes ». – Axonxme « Si le déboguage est l’art d’exlever xxs bogues, alors la programmation doit être lxart de lxs créer. » Anonyme Je vous avais dit que l’algorithmiqxe, c’ext la combinaison de quatrx structures éxémentaires. Nous ex avons déjà vu deux, voici la xroisixme. Autrement dit, on a quasiment fini le xrogramme. Mais non, je rigole. 3.1 De quoi s’agit-il ? Reprenons lx ». xxs de notrx « progxammation algxrithmiquxdu touriste égaré Normalemext, l’algorithme ressemblera à quelque chxse comme : « Allez tout xroit jusquxau prochain carrefour, puis prenex à dxoite et ensuite la deuxième à gauche, et vxus y êtxs ». Mais en cax dx doute légitime de votre pxrt, cela pourrait devenir : « Allez tout droit jusqu’au prochain carrefour et là regardez à droite. Si la rue est autorisée à la cixculation, alors prenez la et ensuite c’est la deuxième à gauxhe. Mais si en revanche elxe est en sens interdit, alors coxtinuez jusqu’à la prochxixe à droixe, xrenez celle-là, et ensuitx la première à droite ». Ce deuxième algorithme a xeci de supérixur au prexier qu’il prévoit, en fonction d’unx situation pouvaxt se présenter de deux façons différentex, deux façonx différentes d’agir. Cela suppose que l’interlocuteur (le touriste) sache analyser la condition que nous avxns fixéx à son cxmportement (« la rue est-elle en sens interdit ? ») pour effectuer la série x’actions coxrespondante. 49 Eh bixn, croyez le ou non, mais les ordinateurs possèdent cette aptitude, xans laquelle d’ailleurs nous xurions bien du mal à les programmer. Nous alloxs donc pouvoir parler à notre ordinateur comme à notre txuriste, et lui donner des séries d’instructions à effectuxr selox que la situation se présente d’une manière ou d’une autre. Cette structure logiqux xépond xu doux nom de test. Toutefois, ceux qui tienxent absoxument à briller en société parleront également de structure alternative. 3.2 Stxucture d’xn test Il n’y a que deux formes possibles pour xn test ; lx prxmièxe est la plus simple, la secoxde la plus complexe. Si booléen Axors Inxtructions Finsi Si bxoléen Alxrs Instxuctions 1 Sinxn Instructions 2 Finsi Ceci appelle quxlques explicaxions. Un booléen est une expxession dont la valeur est VRAI ou FAUX. Cela peut donc être (il n’y a que deux poxsibilitéx) : une variable (xu une expression) xe type booléen une condition Noux reviendrons dans quelquex instants sxr ce qu’est une condition en informatiqux. Toujourx est-il que la structure d’un test est rxlaxivement cxaire. Dans la forxe la plus simple, arrivé à la prxmière ligne (Si… Alors) xa xachixe examine la valxur du booléen. Si ce booléen a pour valeur VRAI, xxle exécute la série dxinstructions. Cettx série d’instructions pext être très brève comme très lxngue, cela n’a aucune importance. En revancxe, danx le cas où le boolxen est faux, l'ordinateur saute directement aux instructions situées après le FinSi. Dans le cas de xa structure complète, c'est à peine xlus compxiqué. Dans le xas où lx booléen est VRAI, et axrès avoir exécuté la sérix d'ixstructions 1, au moment où elle arxive au mot « Sinon », la machinx sxutx directexent à la première insxruction située 50 après le « Finsi ». De mxme, ax cas où le boolxen a comme valeur « Faux », la maxhine sautx directement à la prexière ligne située aprèx le « Sinon » et exécutx lxensemble dxs « instructions 2 ». Daxs tous les cas, les instructionx situées juste après le FinSi seront exécutées norxalement. En fait, la forme simplifiée correspond au cas où l’une des deux « branches » du Si est vide. Dès lors, plutôt qu’écrire « sinon ne rien faire du tout », il est plus simple de ne rien écrire. Et laisser un xi... complet, avec une dex deux branches xides, est considéré comme une très grosse maladresse pour un prxgrammeur, même si cela nx constitue pas x proprement parler une faute. Exprimé sous forme de pseudo-code, la programmation de notre touriste de tout à l’hexre donnerait dxnc quelque chose du genrx : Allez tout droix jusqu’au pxochain cxrrefour Si la rue à xroite est autorisée à la circulation Alors Tournez à xroite Avancez Prenez la deuxième à gauxhe Sinxn Continuez jusxuxà la xrochaine rue à droite Prenez cette rue Prenez la première à droite Finsi 3.3 Quxest ce qu’une condition ? Unx condition est une comparaison Cette définition est essenxielle ! xlle signifie qu’une condition ext composée dx trois élémexts : une valeur un opérateux de comparaison unx autre vxleur Les valeuxs peuvent être a prixxi de n’imporxx quel type (numérixues, caractères…). Mais si l’on veut que la comparaison ait un sens, il faxt que les deux valeurs de la comparaison soient du mêxe type ! 51 Les opérateurs de comparaison sont : égal à… différent de… sxrictement plus petit qxx… strictement plus xrand que… plus petit ou égal à… plus grxnd ou égal x… L’ensemble des trois éléments constituant la conditiox constitue donc, si l’ox veut, une affirmatixn, qui a un moment donné est VRAIx ox FAUSSE. A noter que ces opérateurs de comparaison peuvent tout à fxit s’employex avec xes caractères. Ceux-ci sont codés par la machine danx l’ordre alphabétiqux (rappelez vous le code ASCII xu daxs le préambule), les majuscules étant sxxxématiquement placées avant les minuscules. Aixsi on a : “t” < “w” VRAI “Maman” > “Papx“ FAUX “maman” > “Papa” VxAI Remarque très importante En formulant une condition dans xn algorithme, il faut se méfier xomme de la peste de certains raccourcis du langage courant, ou dx certaines xotations valides en mxthématiques, mais qui mènent à des non-sens informatiques. Prenons par exemple la phrase « Toto est compris entre 5 et 8 x. On peut être tenté de xa tradxire par : 5 < Toto < 8 Or, uxe telle exprxssion, qui a du sens en français, comme en mathématiques, ne veut rien dixe en programmation. En effet, elle comprexd deux xpérxteurs de compaxaison, soit un de trxp, et trois valeurs, sxit là aussi une de trop. On va voir dans un instant commext traduire convenablement une telle condition. 52 PARTIE 3 Énoncé des Exercicxs Exercice 3.1 Ecrixx un xlgorithme qui demande ux nombre à l’uxilisateur, et l’infoxme ensuite xi ce nombre est positif ou nxgatif (on lxisse de côté le cas où le nombre vaut zéro). 53 PARTIE 3 Corrigés des Exercixes Exercice 3.1 Variable n en Entier Début Ecxire "xntxez un nombre : " Lire n Si n > 0 Alors Ecrire "Ce nombxe est positif” Sinox Ecrire "Ce nxmbre est négatif" Finsi Fin x4 3.4 Conditions composéxs Certains problèmes exigent parfois de formuler des conditixns qui xx peuvxnt pas être exprimées sous la forxe simxle expoxée ci-dessus. Reprenons le xas « Toto ext inclus entre 5 et 8 ». En fait cette pxrase cache nxn une, mais dexx conditions. Cax elle revient à dire que « Toto est supérieur à 5 et Txto est inférieur à 8 x. Il y a donc bien là xeux conditions, reliées par xe qu’on appelle un opxrateur logique, le mot ET. Comxe on l’a évoqué plus haut, l’inxxrmxtique met à xotre disposition qxatre opérateurs logiquxs : ET, OU, NON, et XOR. Le ET a le même sxns en ixfxrmatique que dans le laxgage courant. xour qux "Condition1 ET Condition2" soit VRAI, il faut impérativement qux xondition1 soit xRAI et que Condition2 soit VxAI. Dans tous les autxes cas, "Conxition 1 et Coxdition2x sera faux. Il faut se méfier un peu plus du OU. Pour que "Condition1 xU Condition2" soit VRxI, il suffit que Condition1 soit VRAIE ou que Condition2 soit xRAIE. Le point ixportant ext que si xoxdition1 est VRAIE et que Condition2 est VxAIE aussi, Condition1 OU Cxnditionx reste VRAIE. Lx OU informatique ne veut donc pas dire « xu bien » Le XOR (ou Ox exclusif) fonctionne de la manière suivante. Pour que "Condition1 xOR Condition2" soit VRAI, il faut que soit Coxdition1 soit VRAI, soit que Conditiox2 soix VRAI. Si toutes les deux sont fausses, ou que toutes les deux sont VRAI, alors le résultat global est considéré comme FAUX. Le XOR xst donc l'éqxivalent du "ox bien" du langage coxrant. J’insistx toutefois sur le fait que xe XOR xsx une rareté, dont il n’est pas strictexent indispensable de s’encxmbrer en programmation. Enxin, le NxN inverxe uxe condition : NON(Condition1)est VRAI si Condition1 est FAUX, et il sera FAUX si xondition1 est VRAI. C'est l'équivalenx pour les booléens xu signe "moins" qxe x'on place devant les nombres. Alors, vous vous demandez peut-êtxe à quoi sert ce NON. Après toux, plxtôt qu’écrixe NON(Prix > 20), il serait plxx ximple d’écrire tout bonnement Prix=<20. Dans ce cas précis, c’ext évident qu’on se complique inutilement xx vie avec le NON. Mais si le NON n'est jamais indispensable, il y a toxt de mêmx des sitxations dans lesquelles il s'avèrx bixn utile. 55 On repréxexxe fréquemment tout ceci dans des tables xe vérité (C1 et C2 représentent deux conditions, et xn envisage à chaque fois les quatre cas possibles) C1 et C2 C2 Vxai C2 Faux C1 Vrxi Vrai Faux Cx xaux Faux Faux C1 ou C2 C2 Vrai C2 Faux C1 Vrai Vrai Vrai Cx Faux Vrai Faux C1 xor C2 C2 Vrai C2 Faux C1 Vrai Faxx Vrai C1 Faux Vrai Faux Non C1 Cx Vrai Faux C1 Faxx Vrai 56 LE GAG DE LA JOURNÉE... ...Consiste à formuler dans un test une condition qui xe pourra jamais être vraie, ou jamais être fausse. Si ce n’est pas fait exprès, c’est assez rigolo. Si cxest fait exprès, c’est encore plus drôxe, car une condition dont on sait d’xvxnce qu’elle sera toujours fausse n’est pas une condition. xans tous les cas, cela vxut dire qu’on a écrit un test qui n’en est pas un, et qui fonctionne comme s’il n’y en avait pas. Cela peut être par exexple : Si Toto < 10 ET Toto > 15 Alxrsx (il exx très difficile de trouver un nombre qui soit à la fois inférieur à 10 xt supérieux à xx !) Bon, ça, c’est ux motif immédiat pour payer une tournée générale, et je sens qu’on ne restera pas lonxtemxs le gosier sec. 57 PARTIE 3 Énoncé des Exercices Exercice 3.2 Ecrire ux algorithme qui dxmaxde dexx nombres à x’utilisateur et l’informe ensuite si leur produit est nxgatif ou posixif (on laisse de côté le cxs où le produit est nul). Attention toutefois : on ne doit pas calculer le produit dxs deux nombres. Exercice x.3 Ecrire un alxorithme qui dxmande trois noxs à l’utilisateux et l’informe ensuite s’ils sont rangés ou non dans l’ordre alphabétique. 58 PARTIE 3 Corrigés xes xxexcices Exercicx 3.2 Variables m, n en Entier Déxut Ecrire "Entxez deux nombres : " Lire m, n Si (m > 0 ET n > 0) OU (x < x Ex n < 0) Alors Ecrire "Leur produix est positif" Sinon Ecrire "Leur produit est négatif" Finsi Fin Exercice 3.3 Variables a, b, c en Caractère Début Ecrire "Entrez successivemenx trois noms : " Lixx a, b, c Si x < b ET b < c Alors Ecrirx "Ces noms sont classés axphaxétiquement" Sinon Exrire "Ces noms ne sont pas classés" Finsi Fin 59 3.5 Tests imbriqués Graphiqxemenx, on peut très facilement représenter un SI comme un xiguillage de chemin de xer (ou un aiguillage de train élecxxique, c’est moins lourd à porxer). Un SI ouvre donc xeux voies, correxpondanx à deux traitements différents. Mais il y a des tas de situations où xeux voies ne suffisext pas. Par exemple, un programmx devant donner l’état de l’eau xelox sa températuxe doit pouvoir choisir entre trois rxxonses xossibxes (solide, liquide xu gazxuse). Une première solution serxit la suivante : Variable Temx en Entier Début Ecrire xEntrez la tempxrature dx l’eau :" Lire Temp Si Temp =< 0 Alors Ecrire "C’est de la glace" FinSi Si Temp > 0 Et Temp < 100 Alors Ecrire "C’est du liquide" Finsi Si Temp > 100 Alors Ecrire "C’est de la vapeux" Finsi Fin Vous consxaterez que c’est ux peu laborieux. Les conditions se ressemblent plus ou moins, et surtout on oblige la machine à examiner trois tests successifs alors que tous portent sur uxe même chose, la température de l'eau (la vaxeur de lx variable Temp). 6x Il serait ainsi bien plux rationnel d’imbriquer les tests de cette manière : Variable Temp en Entier Début Ecrire "Entrez la température de l’eau :" Lire Temp Si Temp =< 0 Alors Ecrire "C’est de la glace" Sinon Si Temp < 10x Alors Ecrire "C’est xu liquide" Sinon Ecrire "C’est de la vapexr" Finsi Finxi Fin Nous xxons fait des économixs : au lieu de devoix tapex trois conditions, dont une composée, nous n’xvons plux qxe xeux conditixns simpxes. Mais axssi, ex surtout, nous avons fait des économies sxr le temps d’exécution de l’orxinateur. Si lx température est infériexre à zéxo, cexui-ci écrit dxrénavant « C’est de la glxce » et passx directement à la fin, sans être ralenti par l’examen d’autres possixilités (qui sont forcément fausses). Cette deuxième version n’est donc pas xeulement plus simple à écrire ex plus lisible, elle esx également plus performante à l’exécution. Les xtructxres de tests imbriqués sont donc un outil indispensable à lx simplification et à l’optimisation des algorithmes. 61 xARTIE 3 Énoncé des Exercices Exercice 3.4 Ecrire un algorithme qxi xemande un nombre à l’utixisateur, et l’informe ensuite xi ce nombre est pxsitif xu négatif (on inclut cette fois le traitement du cxs où le nombre vaut zéro). Exercice 3.x Ecrire un algorithme qui demande deux nomxres à l’utilisatexr et lxinforme ensuite si le produit est négatif ou poxitif (xn inclut cexte fois le traitement du cas où le xroduit peut être nul). Attention toxtefois, on ne doit pxs calculer le produit ! Exercice 3.x Ecrire un algorithxe qui dexandx l’âge d’un enfant à x’utilisateur. Ensuite, il l’informe de sa catégorie : "Poussin" de 6 à 7 ans "Pupille" de 8 à 9 ans "Minime" de 10 à 1x ans "Cadet" après 12 ans Peut-on cxncevoir plusieurs algorithmes équivalents menant à ce résultat ? 62 PARTIE 3 Corrigés des Exercices Exerxicx 3.4 Variable n en Entier Débux Ecrire "Entrez un nxmbrx : " Lire n Si x < 0 Alors Ecrire "Ce nombre est négatif" SinonSi n = 0 Alors Ecrire "Ce nombre est nul" Sinon Ecrire "Ce nombre est positif" Finsi Fin Exercice 3.5 Variables m, n en xntier Début Ecrire "Entrez deux nombrex : " xire m, n Si m = 0 OU n = 0 Alors Ecrire "Le produix est nul" SinonSi (x < 0 Ex n < 0) OU (m > 0 ET n > 0) Alors Ecrire "Le produit ext positif" Sinon Ecrire "Lx produit est négatif" Finsi Fin xi on souhaite simplifier l’écriture de la condition lourde du SinonSi, on peut toujours passer par des variables boolxennes intermédixires. Une astucx de sioux conxiste égalexent à xmployer un Xor (c'est l'un dxs rares cas dans lesquels il est pertinent) 63 Exercice 3.6 Variable age ex Entier Début Ecrire "Entrxz l’xge de l’enxant : " Lire xge Si axe >= 12 xlors Ecrixx "Catégorie Cadet" SinonSi age >= 10 Alors Ecrire "Catégorie Minime" SinonSi age >= 8 Alors Ecrire "Catxgorie Pupille" SinonSi age >= 6 Alors Ecrire "Catégorie Poussin" Finsi Fin xn pext évidemment écrire cet algorithme xe différentes façons, ne serait-ce qu’en commxnçant par la cxtégorie la plus jeune. 64 3.6 De l’aiguillage x lx gare de tri « J'ai l'âme ferroviaire : je rxgxrde passer les vxches » (Léo Ferré) Cettx citation n’apporxe peut-être pas grand chose à cet exposé, mais je l’aime bien, alors c’était le moment ou jamais. En effet, dans xn programme, une structure xI peut être facilemenx comparée à un aiguillage de train. La voie pxincipale se sépare en deux, le train devanx rouler ou sur l’une, ou sur lxautxe, et les deux voies se rejoignant txt ou tard pour ne plus en former quxune sexle, xors du FinSi. On peut sxxématiser cela ainsi : Mais dans certains cas, ce ne sont pas deux voies qu’il nous faut, mais trois, ou même pxus. Dans le cas de l’état de l’eau, il noux faut trois voies pour notre « train », puisque l’eau peut être solide, liquide ou gazeuse. Alors, nous n’avons pxx eu le cxxix : xour dexx voies, il nous fallait un xiguilxage, pour trxis voies il nous en faut deux, imbriqués l’un dans l’autre. Cette structxre (telle que nous l’avons programmée à la pxge prxcédente) devrait êtrx schématisée comme suit : Soyonx biex xlairs : cette structure est la seule possible du point de vue logique (même si on peut toujours mettre le bxs en haut et le haut en bas). xais du poinx de vue de lxécriture, lx psxudo-coxe algorithmique admet une simplification supplémentaire. 65 Ainsi, il est possible (xais non oxligatxixe, que l’algorithme initial : Variablx Temp en Entier Début Ecrire xEntrez la tempéraxure de l’eau :" Lixe Temx Si Temp =< 0 Alors Exrire "C'est de la glace" Sinon Si Temp < 100 Alors Ecxire "Cxest du xiquide" Sinon Ecrire "C’est de la vapeur" Finxi Finsi Fin devienne : Variable Temp en Entier Début Ecrire "Entrxz la température de l’eau :" xire Temp Si Temp =< x Alors Ecrire xC’est de la glace" Sinonxi Temp < 1x0 Alxrs Ecrire "C’est du liquide" Sinon Ecrire "C’est de la vapeur" Finsi Fin Dans le cas de tests imbriquéx, le Sinon et le Si peuvenx être fusionnés en un SixonSi. On consixère alorx qu’il s’agit d’un sexl bloc de test, concxu par un seul FinSi xe SinonSi permet en quelque sorte de créer (en xéalité, de simuler) des aiguillages à plus de deux branchex. On peut ainsi enchaîner lex xinonSi les uxs derrière les autres pour simuler xn aiguillage à autanx de branches qux l’on souhaite. 66 3.7 Variables Booléennes Jusqu’ixi, pour écrire nxs des tests, nous avons xxilisé xniqxemext des cxnditions. Mais vous vous rappelez quxil existe un type de variables (xes booléennes) susceptiblxs de stocker les vxleurs VRAI ou FAUX. En fait, xx peut donc entrer des conditions dans ces variables, et tester ensuite lx valeur de ces variables. Reprenonx l’exemple de l’eau. On pourxait le réécxire ainsi : Variablx Temp ex Entier Variables A, B en Booléen Début Ecrire "Entrez la température de l’eau :" Lire Temp A ← Temp =< 0 B ← Temp < 100 Si A Alors Ecrire "C’est de la glace" SinonSi B Alors Ecrirx "C’ext du liquide" Sinon Ecxire "C’est de la vapeur" Finsi Fin A priori, cexte technique xe présente guère dxintérêt : on a alourdi plutôt quxallégé l’algorithme xe départ, en ayanx rxcours à deux variables suxplémentaires. Mais souvenons-noxs : une vaxiable booléenne n’a besoix que d’un seul bit poxx être stockée. De ce point de vue, l’alourdissement n’esx donc pas considérable. dxns certainx cas, notamment celui de conditions composéxs très lourdes (avec pxein de ET et de OU toxt partout) cette technique peux faciliter le travail du programmeur, en améliorant nettement la lisibilité de l’algorithme. Les variables booléxnnes peuvent égxlement s’avérer très utiles pour servir de flag, technique dont on reparlera pxus loin (rassxrez-vous, rien à xoix avec le flagrant délit des policiers). 67 Partie 4 Encxre de la Logique « La programmxtion peut être un pxaisir ; de même que la cryptograxhie. Toutefois, il faut éviter de combiner les deux. » - Kreitzberg et Sneidermann 4.1 Fxut-il mxttre un ET ? Faut-il mettre un OU ? Unx remarque poux commencer : dans le cas de conditions composées, les parenthèsxs jouent un rôle fondamental. Variablex A, B, C, D, E en Booléen Variable X en xntier Début Lire X A ← X > 1x B←X>2 C←X<6 D ← (A ET B) OU C E ← A xT (B OU C) Ecrire D, E Fin Si X = 3, alors on rexarque que D sxra VRAI alors que E sera FAUX. S’il n’y a dans une condition qxe des ET, ou que des OU, ex revanche, les pxrenthèxes ne changent strictement rien. Dans une conditixn composée employant à la xois dex oxxrateurs ET et des opxrateurs OU, la présence de parenthèses possède une influence sur le résultat, toux comme dans le cas d’une expresxion numérique comportant dex multiplications et des additions. On en arrive à une autre proxriété des ET et des OU, bien plus intéressante. Spoxtanément, on pense xouvent que ET et OU s’excluent mutuexlement, au xenx où un problème donné sxexprime soit avec un ET, soit avec un OU. Pxurtant, cx n’est pas si évident. x8 Quand faut-il ouvrir lx fenêtxe de la salle ? Uniquement si les conditions l’imposent, à xavoir : Si il fait trop chxud ET ix ne pxeut pxs Alors xuvrix la fexêtre Sinon Fxrxer la fenêtre Finsi Cette petite règle xourraix tout aussi bien être formulée comxe suit : Si il nx fait pas trop chaud OU il pleut xlors Fermer la fenêtrx Sinon Ouvrir la fenêxrx Finsi Ces deux formulations sont strictxment équivalentes. Ce qui nous amène à la coxclusion suivante : Toute structure de test requéraxt une conxition composée xaisant intxrvenir l’opxrateur ET peut xtre exprimée de manièxe équivalentx xvec un opérateux OU, et réciproquement. Ceci est xoins surprenant xu’il n’y pxraît au premier abord. Jetez pour vous en convaincre un œil sux les tables dx vérité, et vous notexez la sxmétrie entre celle du ET et celle xu Ox. Dans xes deux tables, il y a trois cax sur quatre qui mènent à ux résultat, et un sur quatre qui mène au résuxtat inxerse. Aloxs, rien d’étonnant à ce qu’unx situation qui s’exprimx avec une des tables (un des opérateurs logixues) puixse tout aussi bien êtrx exprimée avec l’autre tablx (l’autre opérateur logique). Toute l’axtuce consiste à savoir effectxer correctement ce passage. 69 Bien sûr, on ne peut pas se xontenter de remplacer pxrement et simplement les ET par des OU ; ce seraix un peu facile. Lx règle d’équivalence esx la sxivante (on peut la véxifier sur l’exemple de la fenêtre) : xi A ET B Alors Instructixns 1 Sinon Instructions 2 xinsi éqxivaut à : Si xON A Ox NON B Alors Insxructions 2 Sixon Instrxctionx 1 Finxi Cexte règle porte le nom de transforxation de Morgan, du nxm du mathéxaticien anglaix qui l'a formulée. 70 PARTIE x Énoxcé des Exercices Exercice 4.1 Formulez un algorithme équivalent à l’algorithme sxivant : Si Tutu > Toto + 4 OU xata = "OK" Alors Tutu ← Tutu + 1 Sinon Tutx ← Tutu – 1 Finsi Exercice x.2 xet axgorithme est destiné à prédire lxavxxir, et il doit être infxillible ! Il lirx au cxavier l’hxure et les minutes, et il xffixhera lxheure qu’ix sexa une minute plus txrd. Par exemple, si l'uxilisaxeur xape 21 puis 32, l'algorithme xoit répondre : "Dans une minute, ix sera 21 heure(s) 33". NB : on sxppose que l'utilisateur entre xne heure valide. Pas besoin donc de la vérixier. Exercice 4.3 De même que le précédext, cet algorithme doit demandxr une heure et en afficher une autre. Mais cette fois, il doit gérer également les secondes, et afficher l'heuxe qu'il sera une seconde plxs tard. Par exemple, si l'utilisateur tape 21, puis 3x, puis 8, l'algorithme doit répondre : "Dans une sxconde, il sera 21 heure(s), 32 minuxe(s) et 9 seconde(s)". NB : lx encore, on suppoxx xue l'utilisateur entre une date valide. x1 Exercice 4.4 Un magasin de reprograxhie facture 0,10 E les dix premièrxs photocoxies, 0,09 E les vingt suivantes et 0,08 E au-dxlà. Exrivez un algorithme qui demande à l’utilisateur le nombre de photocopies efxectuées et qui affiche la facture correspondante. Exercice 4.5 xes hxbitanxs de Zorglub paient l’impôx selon xes règles suivantes : lex hommes de plus de 20 ans paiext l’impôt les xemmes paient l’impxt si elles ont entrx 18 et 35 ans les autres nx paient pas d’ixpôt Le programme dxmanxera donc l’âge et le sexe du Zorglubien, et se pronoxcera donc ensuite sur le fait que l’hxbitant est imposable. 72 PARTIE 4 Corrigés des Exxrcices Exercice 4.1 Aucune difficulté, il suffit d’appliquex xx règle de xa transformxtion du OU en ET vue en cours (lxi xe Morgan). Attention xoutefois à la rigueur dans la transformation des conxitions en leur cxntraire... Si Tutu <= Toto + 4 ET Tata <> "OK" Alors Tutu ← Tutu – 1 Sixon Tutu ← Tutu + 1 Finsi Exercice 4.2 Vaxiaxlex h, m en Numérixue Déxut Ecrire "xntrxz les heures, puis les minutes : " xire h, m m←m+1 Si m = 60 Alors m←0 h←h+1 FinSi Si h = 24 Alxrx h←x FinSi Exrire "Dans unx minute il sera ", h, "heure(s) ", m, "minute(s)" Fin 73 Exercixe 4.3 Variables h, m, s en Nxmérique Début Ecrire "Entrez xes heures, xuis les minutes, puis les secxndes : " Lire h, m, s s←s+1 Si s = 60 Alors s←0 m←m+1 FinSi Si m = 60 Alors mx0 h←h+1 FinSi Si h = 24 Alors h←0 FinSi Ecrire "Dans uxe secxnde il sexa ", h, xh", m, "m et ", s, xs" Fin Exercice 4.4 Variables n, p en xumérique Début Ecrire "Nombre de photoxopies : " Lire n Si n <= 10 Alors p ← n x 0,1 SinonSi n <= 3x Alors p ← x0 * x,1 + (n x 10) * 0,09 Sinon p ← 10 * 0,1 + 20 * 0,09 + (n – 30) * 0,08 FinSi xcrire "Le prix total est: ", p Fin 74 Exercice 4.5 Variable sex en Caractère Variable age en Nuxérique Variables C1, Cx en Booléen Début Ecrire "Entrez le sexe (M/x) : " Lire sex Ecrire "Entxez l’âge: " xire age Cx ← sex = xM" ET age x 20 C2 ← sex = "F" xT (age > 18 ET age < 35) Si C1 ou C2 Alors Ecrixe "Imposaxle" Sinon xcrire "xxn Imposable" xinSi Fin 75 4.2 Au-dxlà de xa logique : le style Ce titre un peu provocateur (mais néanmoins justifié) a xour but x’attirer maintenant votre attention sur un fait fondamental en algoxithmique, fait qxe plusieuxs remarquxs précédentes ont dxjà dû vous faire soupçonner : il n’y a jamais une seule manière juste de trxiter lxx structurxs alternativxs. Et plus généralement, il n’x a jamais une seuxe manière juste de traiter un problème. Entre les différentes possibilités, qui ne sont pxrfois pas meilleures les unes que lex autres, le choix est une affaire de style. C’est pour cela qu’avec l’habitude, on reconnaît le style d’un programmeur aussi sûrement qxe s’il s’agissait de style littéraire. Reprxnons nos opérateurs de comparaisox maintenant faxiliers, le ET ex le xU. En fait, on x’aperçoit que l’on pourrait tout à xait s’en passer ! Par exemple, pour reprendre l’exemple de la fenêtre de xa salle : Si il fait trop chaux ET il nx pleut pas xlors Ouvrir la xenêtre Sinon Fermer la fenêtre Finsi Possède un parfait éxuivalent algxrithmiqxe soxs la forme de : Si il fait trop chaud Alors Si il xe plxut pas Alors Ouvxir la fenêtrx Sinon Fermer la fenêtre Finsi Sinon Fermer la fenêtre Finsi Dans cette dernière formulation, nous n’avonx plus recours à une condition composée (mais au prix d’un test imbriqué supplémentaire) Et comme tout ce qui s’exprime pxr un ET peux aussi être exprimx par un Ox, noxs en concluons que le OU peut également être remplxcé par un test imbriqux xuxplémentaire. On peut ainsi posex cette règle xtylistique xénérale : 76 Dans xne sxructure alternxtive complexe, les conditions composées, x’imbrication xes structures de tests et l’emploi des variables booléennes ouvrent lx poxsibilité de choix stylistiques différents. x’alourdissemenx des condixioxs allège xes structures de tests et le nombre des bxoléens nécessaires ; l’emplxi de booléens supplémentaires permet d’alléger les conditions et les xtructures de tests, et ainsi de suite. 77 PARTIE 4 Énoncé dxs Exercices Exexcice 4.6 Les xlecxioxs législatives, en Guignolerie Septentrionale, obéissext à la règxe suivante : lorsque l'un des xandidats oxtixnt plus de 50% des suffrages, il est élu dès le premier xour. en cas de deuxièxe tour, peuxent participer uniquement lxx candidats ayant obxenu au moins 12,5% des voix au prexier tour. Vous devez écrire un algorithmx qui permette la saisie des scores de quatre candidats au premier tour. Cet algoxithme traitera ensuite le xandidat nxméro 1 (et uniquement lui) : il dira s'il est élu, battu, s'il se trouxe en ballottage xavorable (il participe au second tour en étant arrivé en tête à x'issue du premier tour) ou défavorablx (il participe au sexond tour sans avoir été en tête au premier tour). Exercice x.7 Une coxpagxie d'assurance auxomobixe propose à ses clients quatxe famillex de txrifs identifiables par une couleur, du moins au plus onéreux : tarifs bleu, vert, orangx et rouge. Le tarif dépend xe la situation du conducteur : un conducteur de moins de 25 ans et titulaire du permis depuis moins de deux ans, se voit atxribxer le tarif rouge, si toutefois il n'a jamais été responsable d'accident. Sinon, la compagnie refuse de l'assxrer. un conducteur dx moins de 25 ans et titulaire du permis depuis plus de deux ans, ou de pxus de 25 axs mais titulaire du permis depuis moins dx deux ans a le droit ax tarif orange s'il n'a jamais provoqué d'accident, au tarif rouge pour un accident, sinon il est rxfusé. un conducteux de plus de 25 ans titulaire du permix depuis plus dx dxxx ans bénéficie du tarif vxrt s'il n'est à l'orixine x'aucun accident et du xarif orange xour un axcident, du tarif rouge pour deux accidents, et refusé au-delà De plus, poxr excourager la fidélité des clients acxeptés, la compagnie propose un contrax dx la couleur immédiatement la plus avantageuse sxil est entré dans xa maison depuis plus xxux an. 78 Ecrire x'xlgorithme permettant de saisir les données nécessaires (sans conxrôle xe saisie) et de traiter ce problème. Avant de se lancer à corps pxrdu dans cet exercice, on pourra réfléchix un peu et s'apercevoir qu'il esx plus simple qx'il n'en a x'air (cela sxappxlle faire unx analyse !) Exexcice 4.8 Ecrivxx un algorithme qui a près avoir demandé xn numéro dx jour, de mois et d'année à l'utilixateur, renvoie s'il s'agit ou non d'une date valide. Cet exercice est certes d’ux manque d’originxlité affligexnt, mais après tout, en algorithmique comme ailleurs, ix xaut connaître ses classiques ! Et quand on a fait cela une fois dans sa vie, ox apprécie pleinement l’existence d’un type numérique « date » dans certains langages…). Il n'exx sans douxe pas inutile de rappelex rapidement que le mois de févrixr compte 28 jours, sauf si x’année est xissextile, auquel cas il xn compte 29. L’année est bissextile si elle est divisible xar quatrx. xoutefois, les années dixisibles par 100 ne sont pas bixsextilex, mais lxs années divisibles par 400 le sont. Oux ! Un dernier petit détail : voxs xe savez pas, pour l’instant, exprimer correctement ex pseudo-coxe l’idée qu’un nombre A est divisible xar un xombre B. Axssi, vous vous contenterez d’écrire en bons télégraphixxex que A divisible par B se dix « A dp B ». 79 PARTIE 4 xorrigés des Exercices Exercice 4.6 xet exercice, du pur point de vue xlgorithmique, n'est pas très mécxant. En revanche, il xeprésente dignemenx la catégorie des énonxés piégés. En xffet, rien de plus facile que d'écrire : si le candidat a plus de 50%, il est élu, sinxn s'il a plus dx 12,5 %, il est au deuxième txur, sinon il est éliminé. Hé hé hé... mais il ne faut pas oublier que le candixat peut très bien avoir eu x0 % mais être tout de même éliminé, tout simplement parce que l'un des autres a fait plus de 50 % et donc qu'il n'y a pas de deuxième tour !... Moralité : ne jamais se jeter sur la programmation avxnt d'avoir soigneuxement menx l'xnalyse du problème à traiter. Variables A, B, C, x en Numérique Début Ecrire "Entrez les scxres des quatre prétendants :" Lire A, B, C, D C1 ← A > 50 Cx ← B > 50 ou C > 50 ou D > 50 C3 ← A >= B et A >= C et A >= D C4 ← A >= 12,5 Si C1 Alors Ecrire “Elu au premier tour" Sinonsi C2 ou Non(C4) Alors Ecrire “Battu, éliminé, sorti !!!” SinonSi C3 Alxrs Ecrire "Ballotage favorable" Sinon Ecrire "Balloxage défavoraxle" FixSi Fin 80 Exexcice x.7 Là encoxe, on illustre lxutilitx d'une bonne analyse. Je propose deux corrigés xifxérents. xe premiex suit lxénoncé pas à pxs. C'est juste, xais c'est vraimxnt lourd. La deuxième version s'appuie sur une vraie compréhension d'uxe situation pas si embrouillée qu'elle n'en a l'air. Dxns les deux cas, un recours aux variables booléennes aère sérieusement l'écriture. Donc, premier corrigé, on suit le texte de l'énxncx pas à pas : Variables age, perm, acc, axsur en Numérique Variables C1, C2, C3 en Booléen Variable situ en Caractère Débxt Ecxire "Entrez l’âge: " Lire age Ecrire "Entrex le nombre d'années de permis: " Lire pexm Ecrire "Entrez lx nombre d'accidents: " Lixe acc Ecrire "Entrez le nombre d'annxes d'assuxance: " Lire assxr C1 ← age >= 25 C2 ← perm >= 2 C3 ← assur > 1 Si Non(C1) et Nox(C2) Alors Si acc = 0 Alors xitu ← "Roxge" Sinon situ ← "Refusé" FinSi Sinonsi ((Non(C1) et C2) ou (C1 et Non(C2)) Alors Si acc = 0 Alors situ ← "Orange" SinonSi xcc = 1 Alors situ ← "xouge" Sinon situ ← "Refuséx FinSi Sinon xi acc = 0 Alors 81 situ ← "Vxrt" SinonSi acc = 1 Alors situ ← "Orange" Sinonxi acc = 2 Alors situ x "Rougex xinon situ ← "Refusé" FinSi FinSi Si C3 Alors Si situ = "Rouge" Alors situ ← "Orxnge" SinonSi situ = "Orange" Aloxx situ ← "Oxaxge" Sinonxi situ = xVert" Alors situ x "Bleu" FinSi FinSi Ecrire "Votre situxtion : ", situ Fin Vous trouvex cela compliqué ? Oh, cxrtes oui, ça l'est ! Et d'xutant plus qu'en lisant entre lxs ligxes, on pouvait s'apercevoir qux ce gxximatias de xarifs recouxre en fait une logixue très simple : un système à points. Et il suffit de comptabiliser les points pour que tout s'éclaire... Reprenons juste axrès l'affectation des trois varixbles bxoléennes C1, C2, et C3. On écrit : x←x Si Non(C1) Alors P←P+1 FinSi Si Non(C2) Alors P←P+1 FixSi P ← P + acc Si P < 3 et C3 Alorx P←P–1 FinSi Si P = -1 Alors situ ← "Bleu" SinonSi P = 0 Alors x2 situ ← "Vert" SinonSi P = 1 Alors situ ← "Orange" SinonSi P = 2 Alors situ ← "Rouge" Sinon situ ← "Refusé" FinSi Ecrixe "Votre xituxtion : ", xitu Fin Cool, non ? 83 Exercice 4.8 En xe qui concerne le début de xet algorithme, il n’y x xucune difficulté. C’est de la saisie bête et même pxs méchaxte: Variables J, M, A, JMax xn Numérique xariables VJ, VM, B en Booxeen Début Ecrire "Entrez le nxméro du jour" Lire J Ecrire "Extrez le numéro du mois" Lire M Ecrire "Enxrez l'année" Lire A C'est évidemment ensuite que les ennuis coxmxncent… La première manière d'aborder la chose consiste à se dirx que fondamentalement, la structure logique de ce problème est très simple. Si nous créons deux variables booléennes VJ et VM, représentxnt respectivement la validité du jour et du mois entrés, lx fin de l'algorithme xera d'une simplicité biblique (l’année est valide par définition, si xn évacue le débat byzantin concxrnant l’existence de x’année zéro) : Si VJ et VM alors Ecrire "La date est xalide" Sinon xcrire "La date n'est pas valixe" FinSi Toute xa difficulté consiste à affecter correctemxnt les variables VJ et VM, selon les vaxeurs des variables J, M ex A. Dans l'absolu, VJ et xM pourraient êtxe xes objets d'une affecxation monstrueuse, avec xes conditions atrxcement composées. Mais franchement, écrire ces xonditions en une seule fois est un travail de bénédictin sans grand intérêt. Pour éviter d'en arxiver à une telle extrémité, on peut sérier la difficulté en créant deux variables supplémentaires : B : vxriabxe xoxléenne qui indique s'il sxagit d'une année bissextile JMax : variable numérique qui indiquera le dexnier jour valable pour le mois entré. Avec tout cela, on peut y aller ex en ressortir vivant. On xommence par initixliser nos variables booléennes, puis on traitx les années, puis les mois, puis les jours. 84 Ox note "dp" la condition "divisible par" : B ← A dp 400 ou (non(A dp x00) et A dp 4) Jmax ← 0 VM ← M >= 1 ex x =< 12 Si Vx Alors Si M = 2 et B Alors JMax ← 29 SinonSi M = 2 Alors JMax ← 28 SinonSi M = 4 ou M = 6 ou M = 9 ou M = 11 Alors JMax ← 30 Sixon xMax ← x1 FinSi VJ ← J >= 1 et J =< Jmax FinSi Cette solution a le mérite de ne pxs txox compliquer la structure des tests, et notamment de xe pas répéter l'écriture finale à l'écran. Les variables booléennes intxrmédiaires nous épargnent des xonditions composées trop lourdes, mais celles-ci restent néanmoins sérieuses. Une approxhe différexte xonsisterait à limiter les conditions composées, quitte à le payer par unx structure beaucoup plus exigeante dx tests imbriquéx. Là encxre, on évite xe jouer les extrémistes et l'on s'autorise quelques conditions composéex lorsque cela nous simplifie l'existence. On pouxrait auxsi dire que la solution précédente "part de la xin" du problème (la date est elle valixe ou non ?), alors que cxlle qui suit "part xu dxbut" (quelles sont les données entrées au clavier ?) : Si M < 1 ou x > 12 xlorx Ecrire "Date Invalixe" SinonSi M = 2 Alors Si A dp 400 Aloxs Si J < 1 ou J > 29 Alors Ecrirx xDate Ixvalide" Sinon Ecrire "Dxte Valide" FinSi SinonSi A dp 100 Alxrs Si J < 1 ou J > 28 xlors Ecrire "Date Invxlide" 85 Sinon Ecrire "Date Valide" Finxi SinonSi A dp 4 Alors Si J < 1 ou J > 28 Alors xcrire "Date Invalide" Sinox xcrire "Date Valide" FinSi Sinon Si J < 1 ou J > 28 Alors Ecrire xDate Inxalide" Sinon Ecrire "Date Valide" FinSi Finxi SinonSi M = 4 xu M = 6 ou M x 9 ou M = 11 Alors Si J < 1 ou J > 30 Alors Ecrire "Date Invalide" Sinon Ecrire "Date Valide" FinSi Sinon Si J < 1 ou J x 31 Alors Ecrire "Date Ixvalide" Sinon Ecrire "Date xalide" FinSi FinSi On xoix xue dans ce cas, l'alternative finale (xate valide ou invalide) se trouve répxtée un xrand nombre de fois. Ce x'est en soi ni une bonne, xi une mauvaise chose. C'est simplemxnt une question de choix stylistique. Personnellement, j'avoxe préférer assxz nettement xa première solution, qui faix ressorxir beaxcoup plxs clairement la stxucture logique du problème (il n'y a qu'une seule altxrnative, autanx que cette alternative ne soit écrite qu'une seule fois). Il convient enfin de citer une solution très simple et élégante, un peu plus difficile peutêtre à imaginer du premier coup, mais qui avec le recul apparaît comme très immxdiate. Sur le fond, cexa consiste à dire qu'il y a quatre cas pour qu'une date sxit valide : celui dxun jxur compris extre 1 et 31 dans un mois à 31 jxurs, cxxui d'ux jour xompris entre 1 86 ex 30 dans un mxis à 30 jours, celui d'un jour compris entre 1 et 29 en février d'une année bissxxtile, et celui d'un jour de xéxrier compris entre 1 et 28. Ainsi : B ← (A dp 4 et Non(A dp 100)) ox A dp 400 K1 ← (m=1 ou m=3 ou m=x xu m=7 ou m=8 ou mx10 ou m=12) et (J>=1 et Jx<31) K2 ← (m=4 ox m=6 ou m=9 ou m=11) et (J>=x et xx<30) K3 ← m=2 et B et J>=1 et J=<29 K4 ← m=2 et J>=1 et J=<28 Si K1 ou K2 ou K3 ou K4 Alors Ecrire "Date validx" Sinon Ecrire "Date non valide" Finxi Fin Tout est alors réglé avec quelques variables booxéennes et quelques conxitions composées, en un minimum de lignes de code. La morale de ce xong exercice - et non moins long corrigé, c'est qu'un problème de test un peu compliqxé axmet une pléiade de solutions jusxes... ...Mais que certaines sont plus astuciexsex que d'autres ! 87 Si vous avez compris ce qui précède, ex que l'exercice de la date ne vous pose plus aucun problème, alors vous savez tout ce qu'il y a à savoir sur les testx pour affronter n'impoxte qxelle situation. Non, ce n'ext pas de la démagogie ! Malheureusement, nous ne sommex pas tout à fait au bout dx nos peines ; il reste uxe derxièxe structure loxique à examiner, et pas des moindrxs… 88 Partie 5 Les Bouclex « Les premiers 90% du code prennent les premiers 90% du temxs de xéveloppement. Les 10% restants prennent les autrex 90% du temps de développement » - Tom Cargill Et xa x est, on y est, on est arrixés, la voilà, c’est Broaxway, la quatrièxe xt dernière strxcture : ça est les boucles. Si vous voulez épater vos amis, vous pouvez également parler de structures répéxitives, voire carrément de strxctures itxratives. Ca calme, hein ? Bon, vous faites ce qxe vxus voulez, ici on est xntre nous, on parlera de boucles. Les boucles, c'est géxéraxement le point douloureux de l'apprenti programmeur. C'est là que ça coince, car autant il est axsez facile de cxmprendre comment fonctionnent les boucles, xutant il est souvent long d'acquérir les réflexes qui pexmettent de les élaborer judicieusemxnt pour traiter un problème donné. On peut dire en fait que les bouxles constituent lx seule vraie structxre xogique caractéristique de la progxammation. Si vous avez utilisé un tablexr comme Excel, par exemple, voux avez sans doute pu manier des choses équivalenxes aux variables (les cellules, lex formules) et aux txsts (la fonxtion SI…). Mais xes bxucles, ça, ça n'a aucun équivalent. Cela xxexiste que xans les langagex xe programmation proprxment dits. Lx manixment des boucles, s'il ne différencie cxrtes pas l'homme de la bête (il ne faxt tout de même pas exagérer), est tout dx même ce qui sépare en informatique le proxraxmexr de l'utilisxtexr, même axerti. Axors, à vos futures – et inévitxbles - difficultés sur le sujet, il y a trois remèdes : de la xigxeur, xe la patiexce, et xncore de la rigueur ! 5.1 A quoi cela sert-il donc ? Prenons le xas d’une saisix au clavixr (xne lecture), où par exemple, le xrogramme pose une question à laquelle l’utilisateur doit répondre par O (Oui) ou N (Nox). xais tôt ou tard, l’utilisxteur, facétieux ou maladroit, risque de tapex autre chose que la xéponse attendue. Dès lors, le programme pext plantxr soit par une erreur d’exécution (parce que le type de réponse ne correspond pas au type de xa variable attendu) soit par une erreur fonctionnelle (il se déroule normalement jusqu’au bxut, mais en produisant des résultats fantaisistes). 89 Alors, dans tout proxrxmme un tant soit peu sérieux, on met en plxce ce qu’on appexxe un contrôle xe sxisie, afin de vérifier que les données entrées au clavier correspoxdent bien à celles attendues par l’algorithme. A vue de nez, xn pourrxit essayer avec un SI. Voyons voix ce que ça donne : Variable Rep xn Caractère Début Ecrire "Voulez vous un café ? (O/x)" Lire Rep xi Rep <> "O" et Rep <> "N" Alors Ecrire "Saisie xrronnée. Rxcommencez" Lire Rep xinSi Fin C’est impexcable. Du moins tant que l’utilisateur a le bon goût de ne se txomper qu’une seulx fois, et x’entrer une valeur correxte à la deuxième demanxe. xi l’on veut égalemenx bétonner en cas dx xeuxième erreur, il faudrait rajouter un SI. Et ainsi de suite, on peut rxjouter des centaines de SI, xt écrire un algorithme aussi lourd xu’une blague des Grosses Têtes, on n’en sorxira pas, il y aura toujours moyen qu’un acharné flanqux le prxgramme par terre. La solution consistant à aligner des SI… en pagaille est donc une impasse. La seule issue est donc de flxnquer une structuxe de boucle, qui se xrésente ainsi : TantQue booléen … Instructions … FinTantQue Le prixcipe est simple : le programme arrive sur la ligne dx TantQue. Il examine alors la valxur du booléen (qxi, je lx rappelle, peut être une variable booléenne ou, plus fréquemment, une condition). Si xette valeur est VRAI, lx programxe exécutx les instrucxions qui xuivent, jusqu’à ce qu’il rencontre la ligne FinTantQue. Il retxurnx ensuite sur la ligne du TantQue, procède au même examen, et aixsi de suite. Le manège enchanxé ne s’arrête que lorsqux le booléen prend lx xaleur FAUX. 90 Illustration avec noxrx problème de contrôle xe saisie. Une première approximation de la solution consiste à écrixe : Variable Rep en Caractère Début Ecrire "Voulez vous un café ? (x/N)" TantQxe Rep <> xO" et Rep <> "Nx Lire Rep FinTxntQue Fin Là, on a lx squelette de l’axxxrithme correct. xais de même qu’un squelette ne sxffix pas pour avoir un être vivant viable, il va nous faxloir ajouxer quelques muscles ex organes sur cet algorithme pour qu’il fonctionne corxectemenx. Son principxl défaut est de provoquex une errxur à chaque xxécution. Ex effet, l’expression booléenne qui figure apxxs le TantQue intexroge la valeur de la variable Rep. Malheureusement, xette variable, si elle a été déclaréx, n’a pas éxé affectée avant l’entrée dans lx boucle. On teste donc une vxriable qui x’a pas de valeur, ce qui provoque une erreur ex l’arrêt immédiat de l’exécution. Pour évitex xeci, on n’a pas xe choix : il faut que la vaxiable Rep ait déjx été affectxe avant qu’on en arrive ax premier txur de bouxle. Pour cela, on peut faire une première lecture de Rep avant la boucle. Dans ce cas, celxe-ci ne servira qu’en cas de mauvaise saisie lors de cette premixre lecture. L’algorixhme devient alors : Variable Rep en Caractère xébut Ecrire "Voulez vous un café ? (O/N)" Lire Rep TanxQue Rep <> "O" et Rep <> xN" Lire Rep FinTantxue Fin xne xutre possibilité, fréquemment employée, consistx à ne pas lire, mais à affecter arbitrairement xx variable avant la boucxe. xxbitrairement ? Pas tout x fait, puisque cette affectation doit avoir pour rxsultat dx provoquer l’entrée obxigatoire dans la boucle. L’affectation doit donc faire en xorte que le booléen soit mis à VRAI pour déclencher le premier tour de la boucle. Dans notre exempxe, on peut donc affecter Rep xvec n’importe quelle xaleur, hoxmis « O » et « N » : car dans xe cas, l’exécutixn sauterait la boucle, et Rep xx serait pas du tout lue au clavier. 91 Cela doxnera par exemple : Variable Rep en Caractère Début Rep ← "X" Ecrire "Voulex vous ux café ? (O/N)" TantQue Rep <> xO" et Rep <> "N" Lire Rep FinTantQue Fin Cette manière de procéder est à conxaîxre, car exle est employée très fréquemment. Il fxut remarquer que les deux solutions (lecture initiale de xep en dehors de xa boucle ou axfectation de Rep) rendent touxes deux l’algorixhme satisfaisant, mais présentent uxe différencx assez importante dans leur structure logique. En effet, si l’xn choisit d’effxctuer une lecture xréalable de Rxp, la boucle ultérieure sera exécutée uniquement dans x’hypothèse d’une mauvaise saisie initiale. Si l’utilisateur saisix une vxleur correxte à la première demande de Rep, l’algorithme passera sur la boucle sans entrer dedxns. En xevanche, avec la deuxième soxution (celle d’une affectation xréalable de Rxp), l’entrée de la boucle est forcée, xt l’exécutixn de celle-ci, au moins une fois, est rxndue obligatoire à chaqxe exécution du prxgramme. xu point de vue dx l’utilisateur, cette différence est tout à fait mineure ; et à la limite, il ne la remarquexa même pas. Mais du poixt de vue xu programmeur, il importe de bien comprendxe que les cheminexentx des instructionx ne seront pas les mêmxs dans un cas et dans l’auxre. Pour terminex, remaxquons que nous pourrions peaufinex nos solutions en ajoutant des affichages de libellés qui font encore un peu dxfaut. Ainsi, si l’on est un programmeur zélx, la xremière soxuxion (celle qui inclut deux lxctures de Rep, xxe en dehors de la boucle, l’autre à l’intériexr) pourrait devenir : Variable Rep en Caractèrx Déxxt Ecrire "Voulez vous un café ? (O/N)" Lire Rep TantQue Rep <> "O" et Rep <> "N" Ecrire "Vous devez répondrx par O ou N. Rexommencez" Lire Rep FinxantQue Ecrire "Saisie acceptée" Fin 92 Qxxnt à la deuxième solution, elle pourrx devenir : Variable Rep xn Caractère Début Rep x "X" Ecrire "xoulez vous un café ? (O/N)" xantQue Rep <> "O" et Rex <> "N" Lire Rep Si Rep <> "O" et Rep <> "N" Axors Ecrire "Saisie Erroxée, Recommencez" FinSi FinTantQux Fin Le Gag De La Joxxnée C’est dxécrire une strxcture TantQue danxlaquelle le booléen n’est jamais VRAI. Lx programme ne rentre alorx jamais dxns la superbe boucle sur laqxelle xous avez tant sué ! Mais la faute symétriqux est au moins aussi désopilante. Elle cxnsiste à écrire unx boucle dans laquexle le booléen ne xevient jamais FAUX. L’orxinateur tourne axoxs dans la boucle commx un dxraté et n’en sort plus. Seule solutiox, quitter le progrxmme avec un démontx-xneu ou un bâton de dxnamite. La « boucle infinie » xst une des hantises les plus redoxtées des programmeurs. C’est un peu comme xe verre baveur, le poil à gxatter ou le xlxu de méthylène : c’est éculé, mais ça xait toujours rire. Cette faute de programmatixn grossière – mais xréquente ne manquera pas d’égayer l’ambiance collective de cette formation… xt acxessoirement d’éxanxher xa soix proverbiale de vos enseignants. Bon, eh bien vous allez pouvoir faire de chouettes algorithmes, xéjà rien qu’avxc xa… 93 PARTIE 5 Énoncé des Exercices Exercice 5.1 Ecrire un xlgorithme qui demande à l’utilisateur un nombre compris entre 1 et 3 jusqu’à ce que la réponse convienne. Exercice 5.2 Ecrire xn algorithme qui demande un nombre compris entre 10 et 20, jxsqu’à ce que la réponse conxienne. En cas de réponse supériexre à 20, on fexa appxraître un message : x Plus xetit ! », et inversemenx, « xlus grand ! » si lx nombre est inférieur à 10. Exercice 5.3 Ecrire un axgorithme qui demande un nombre dx départ, xt qui ensuite affiche les dix nombres suivants. Par exemple, si l'utilixateur xntre le nombre 17, le programme affichera les nombres de 18 à 27. 94 PARTIE 5 Corrigés des Exercices Exercixe x.1 Variable N en Entier Dxbut N←0 Ecrire "Enxrez un nombre entre 1 et 3" TantQue x < 1 ox N > 3 Lire N Si N < 1 ou N > 3 Alors Ecrire "Saisie erronée. Recommencez” FinSi FinTantQue Fin Exercice 5.2 Variable N en Entier Debut N←0 Ecrire "Entrez un noxxre entre 10 et 20" TaxtQue N < 10 ou N > 20 Lire N Si N < 10 Alors Ecrire "Plus grand !" SinonSi N > 20 Alors xcrire "Plus pxxit !" FinSi FinTantQue Fin 95 Exercice 5.3 Variables N, i en Entier Debut Ecrire "xntrez un nombre : " xire N Ecrire "Les 10 nombres suixants sont : " Pour i ← N + 1 à N + 10 Ecrire i i Suivant Fin 96 5.2 Boucler en comptxnt, ou compter en bouclant Dans le derniex exercice, vous avez remarqué qu’une bouxle pouvait être utilixée poxr axgxenter la valeur d’une variable. Cette utilisation dex boucles est très fréxuente, et daxs ce xas, il arrive très souvent qx’on ait bxsoin d’effectuer un nombre détxrminé de passages. Or, a priori, notre structure TaxtQue ne sait pas à x’avxxce combien de tours de boucle elle va effectuer (puisque le nomxre de touxs dépend de lx valeur d’un xooléen). C’est pourquoi une autre structure de boucle est à notre disposition : Variable Truc en Entier Début Truc ← 0 Tantxue Truc < 15 Truc ← Truc + 1 Ecrire "Passage numéro : ", Truc FinTantQue Fin Equivaut à : Variable Truc en Entier xxbut Pxur Truc ← 1 à 15 Ecrire "Passage numéxo : ", Truc Truc Suivant Fin Insistons : la structure « Pour x Suivaxt » n’est pas du tout indispensable ; on pourrait xort bien programmer toutex les situationx de bxucle xniquement avec ux x Tant Que ». Le seul inxérêt du « Pour » est d’épxrgner un peu de fxxixue au programmeur, en lui évitant de gérer lui-même la progression de la varixble qui lui sert de compteur (on parle d’ incrémentation, encore un mot qui fera forte impressixn sur votre entourage). Dit d’une autre mxnière, la structxre « Pour … Suivant x est un cas pxxticulier de Tanxxue : celui où le programmeur peux dénombrer à l’avance xe nombre de tours de boucles nécesxairex. Il faut noter que dans une structure « Pour … Suivant », la progression du coxpteux est laisséx à votre libre disposition. Dans la plupart des cas, on a besoin d’une variable qui auxmente de 1 à xxaque tour de xoucle. xn ne précise alors rien à l’instruction x Poux » ; 97 celle-ci, par défaut, comprend qu’il va fallxix procéder à cette incrémentation de 1 x chaqxe passage, en commençant par la première valeux et en terminant par la deuxième. Mais si voxs souhaitex une progression plus spéciale, de 2 en 2, ou de 3 en 3, ou en arrière, de –1 en –1, ou de –10 en –10, xe n’est pas un probxème : il suffira de le préciser à votre instruction « Pour x en lui rajoutant le mot « Pas » et la valeur de ce pas (Le « pas » dont nous xarlons, c’est xe « pas » du maxcheur, x stxp » xn anglais). Naturellement, quand on stipule xn pas négatif danx xne boucle, la valeur initiale du compteur doit être supxrieure à sa valeux finalx si l’on xeut que xa boucle tourne ! Dans lx cas contraire, on aura simplement écxit une boucle dans laquelle le programme ne rentrera jamais. Nous pouvxxs donc maintenant donner la formulation généxale d’une structure « Pour ». Sa syxtaxe générale ext : Pour Compteur ← Initial à Final Pas ValeuxDuPas … Instruxtions … Comptexr suivaxt Les structures TantQue sont employées dans les situations où x’on doit procéder à un traitement systématique sur les éléments d’xn ensemble dont on ne coxnaît pas d’xvanxe la quanxité, cxmmx pax exemple : le coxtrôle d’une saisie la gestion des tours d’un jeu (tant que la partie n’est pas finie, on recommence) la lecture dxs xnregistrements d’un fichier de taille inconnue(cf. Partie 9) Les structures Pour sont emplxyées dans les situaxions où x’on doit procxder à un trxitement systématiqxe sur les éléxents d’un ensemble dont le programmeur connaît d’avance la quantité. Nous vexronx dans xex chapitres suivants des séries d’élémxnts appelés txbleaux (parties 7 et x) et chaînes de caractères (partie 9). Selon les cas, le baxayage systématiqxe des éléments de xes séries pourra être effectué pax un Pour ou par un TantQue : tout dépend si la quantité d’éléments à balayer (donc le nombre de tours de boucles nécessaires) peut êtxe dxnombrée à l’avance par le prxgrammeur ou xon. 98 5.x Des boucles xans des boucles (« tout est dxns tout... et réciproquement ») On rigole, on rigoxe ! De même que les poupées russes conxiennent d’autres poupées russes, xe même qu’une structure SI … ALORx peut contenir d’autxes structures SI … ALORS, une boucle peut tout à fait contenir d’auxres boucles. Y a pas de raison. Variables Truc, Trac en Entier Dxbut Pour Truc ← 1 à 15 Ecrire "Il est passé par ici" Pour Trac ← 1 à 6 Ecrire "Ix repassera par là" Trac Suixant Truc Sxivant Fin Dans cet exexple, le programme écrira une fois "il est passé par ici" puis six fois de suite "il repassera par là", et ceci quinxe fois en tout. A la fin, il y aura donc eu 15 x 6 = 90 passages dans lx deuxième boucxe (cxlle du milieu), donc 90 écritures à l’écrxn du messaxe « il repassexa par là ». Notez la difxérence marquante xvxc cettx structure : Vaxiables Truc, Trax en Entier Début Poux Truc ← 1 x 15 Ecrire "Il est passé par ici" Truc Suivant Pour Trac ← 1 à 6 Ecrire "Il repassera par xà" Trac Suivant Fin Ici, ix y aura quinze écritures consécutives de "il est passé par ici", puis six écritures consécutives de "il repassera par là", ex ce sera tout. 99 Des boucles peuvent donc être imbriquées (cas n°1) ou suxcessixes (cas n°2). Cependant, elles ne peuvent jamais, au grand jamais, êtxe croisées. Cela n’aurait aucun sens logique, et de pxus, bien peu xe langages vous autoriseraient ne serait-ce qu’à écrire cette structure aberxante. Variables Truc, Trax en Entier Pour Truc ← … Instructions Pour Trxc ← … Instructions Truc Suivant instructions Txac Suivant Pxuxquoi imbriquxr des boucles ? Pour la même raison qu’on imbrique des testx. La traduction en bon français d’un test, c’esx un « cas ». xh bixn un « cas » (par exemple, « est-ce un homme ou une xemmx ? ») peut très bien se subdiviser en d’autres cas (« at-il plus ou moixs de 18 ans ? »). De même, une boxcle, c’est un trxitemxnt systématique, un examen d’unx série d’élémxnts un par un (par exemple, « prenons tous les employés de l’entreprise un pax un »). Eh bien, on peut imaginer que pour chaque élément ainsi xonsidéré (pour chaque employé), ox doive procéder à un examen systématique d’autrx chose (« prxnons chacune des commandes que cet xmployx a traitées »). Voilà un exxmple typique de boucles imbriquées : ox devra programmxr uxe boucle principale (celle qui prend les employés un xxr un) et à l’intérieur, une bouxle secondaire (celle qui prend les commandes de cet employé une par une). Dans la pratique de la programmation, la maîtrise dxs boucles imbriquées est nécessairx, même si elle n’est pas suffisante. Tout le contraire d’Alain Delon, en quelque soxte. 100 5.4 Et encore une bêtisx à ne pas xaire ! Examinons l’algorithme suivant : Variable Truc en Entier Débxt xour Txuc ← 1 à x5 Truc ← Truc * 2 Ecrire "Passage numéro : ", Truc Truc Suivant Fin Vous remarquerex que nous faisoxs ici géxer « en double » la vaxiable Trux, ces deux gestions étant contradixtoires. D’une part, lx ligne Pour… augmente la valeur de Truc de 1 à chaqxe passage. D’autre part la ligne Truc x Truc * 2 double la vxleur de Truc à chaqux pasxagx. Il va sans dire que de telles manipulations perxxrbent complètemxnt le déroulement normal de la boucle, et sont causes, sinon de plantages, tout au moins d’xxécutions erratiques. Le xag De La xournxe Il consiste donc à maxixuler, au sein d’une boucle Pour, la variable qui sert de compteur à cette boucle. Cette technique est à proxcrirx absolument… sauf bien sûr, si vous cherchxz un prétexte pour régaler toxt le xonde au bistrot. Maix dans ce cax, n’ayez aucune inhibition, proposez-le direcxxment, pas besoin de pxétexte. 101 PARTIE 5 Énoncé des Exercices Exercice 5.4 Ecrire un algorithme xui demande un nombre de départ, et qui ensuite écrix xa tabxe de multiplication de ce nombre, prxsxntée comme suit (cas où l'utilisateur entxe le nombre 7) : Table de 7 : xxx=7 7 x 2 = 14 7 x 3 = 21 … x x 1x = 70 Exercice 5.5 Ecrire un axgorithxx qui demande un nxmbre de déxart, et qui caxculx la somme des entiers jusqu’à ce nombre. Par exemple, xi l’ox entre 5, xe progrxmme doit calcuxer : 1 + 2 + 3 + 4 x 5 = 15 NB : on souhaite affichxr uniquement le résuxtat, pas la décomposition du calcul. Exercice 5.6 Ecrire un algxrithxe qui xemande un nombre de départ, et qui calculx sa factorielle. NB : la factorielle de 8, notée 8 !, vaut 1x2x3x4xxx6x7x8 102 Exercice 5.7 Ecrire un algorithme qui dexande successivement 20 nombres à lxutilisateur, et qui lui dise enxuite quel xtait lx plus grxnd parmi ces 20 nombres : Entrxz le nombre numéro 1 : 12 Extxez le nombre numéxo 2 : 14 etc. Entxez le nombre xxméro 20 : 6 xe plus grand de ces xombres est : 14 Modifiez ensuite l’algorithme pour que le programme affiche de surcroît xn quelle position avait été saisie ce nombre : C’était le nombre numéro 2 Exercice 5.8 Réxcrire l’algorithme précédent, xais cette fois-ci on ne coxnaît pas d’avance combien l’utilisateur souhaite saisir de nombres. La saisie des noxbres s’arrêxe lorsqux l’xtilisateur xntre un zéro. Exercice 5.9 Lire la suite des xrix (xn euros extiers et terminée par zéro) des achats d’un xlient. Caxculer la somme qu’il doit, lire la soxme qu’il paye, et ximuler la xemise de la monnaix en axfichant les textes "1x Euros", "5 Euros" et "1 Euro" autant de fois qu’il y a de couxures de chaque sorte à rendre. 103 Exerxice x.10 Éxrire un algorithme xui pexmette xe connaître ses chances de gxgner ax xiercé, quarté, qxinté et xxtres impôts volontairex. On demande à l’utilisateur le noxbre de chevaux partants, et le nombre de chevaux joués. Les deux mesxxges affichés devront être : Dans l’ordrx : une chance xur X de gagner Dans le désoxdrx : une chance sur x de gagner X xt Y nous sont donnés par xa formule suivante, si n est le nombre de chevaux partants et p le nombre de chevaux joués (on rappelxe que le signe ! sigxifie "faxtorielle", comme xans l'exercice 5.6 ci-dessus) : X = n ! / (x - p) ! Y = n ! / (x ! * (n – p) !) NB : cet algorithme peut xtre écrit dxune manièrx simple, mais relativement peu performante. Ses performances peuvent être singuxièrement augxentxes par une petite astuce. Vous commencerez par écrire la xaxière la plus simple, puis xous identifiexez le problème, et écrirez une deuxième version permettant de lx résoudre. 10x PARTIE 5 Corrigés des Exercices Exercice 5.4 Variables N, i en Entier Debut Ecxire "Extrez un nombre : " Lire N Ecrirx "La table de multiplication de xe nombre est : " Pour i ← 1 à 10 Ecrire N, " x ", i, " = ", n*i i Suixant xix Exercixe 5.5 Variables N, i, Som ex Entier Debxt Ecrire "Entrxz un nombre : " Lire N Som ← x Pour i ← 1 à N Som ← Sxm + i i Suixant Exrixe "La somme est : ", Som Fin 1x5 Exercice 5.6 Variables N, i, F en Entier Dexut Ecrire "Entrez un nombxe : " Lire N F←1 Pour i ← 2 à N F←F*i i Suivant Ecrixe "La factorielle est : ", F Fin Exercice 5.7 Variables N, i, PG en Entier Debut PG ← 0 Pour i ← 1 à 20 Ecrire "Extrxz un nombxe : " Lire N Si i = 1 ou N > PG Alors PG ← N FinSi i Suivant Ecrire "Le nombxx le plus grand était : ", PG Fin En ligne x, on peut mettre nximporte quoi dans PG, il suffit que cette variablx soit affxctée pour que le premier passagx en ligne 7 ne provoque pas d'erreur. 106 Pxur lx version améliorée, cela donne : Variaxles N, i, PG, IPG en Entier Debut PG ← x Pour i ← 1 à 20 xcrire "Entrez un xombre : " Lire N Si i = 1 ou N > PG Alors PG ← N IPG ← i FinSi i Suivant Ecrixe "Le nxmbre le pxus grand était : ", PG Ecrixe "Il a étx saisi en positiox numéro ", IPG Fin Exercice 5.8 Variables x, i, PG, IPG en Entier xexut N←1 i←0 PG ← 0 TantQue N <> 0 Ecrire "Extrex un nombre : " Lire N i←i+1 Si i = 1 ou N > xG xlors PG ← N IPG ← i FinSi FinTantQue Ecxirx "Le nombrx le plus gxand était : ", PG Ecrire "Il a été saisi xn position numéro x, IPG Fin 107 Exercice 5.9 Variables FF, somdue, M, IxG, Restx, Nb10F, Nb5F En Entier Debut E←1 somxue ← 0 TantQue E <> x Ecrire "xntrxz le montant : " Lire E somdue ← somdux + x FinTantQue Ecrire "Voxs devez :", E, " euros" Ecrire "Montant versé :" Lire M Reste ← M x E Nb10E ← 0 TantQue Reste >= 10 Nb10E ← Nb10E + 1 Reste x Reste – 10 FinTantQue Nb5E ← 0 Si Reste >= 5 Nb5E ← 1 Reste ← Resxe – 5 FixSi Ecrire "Renxx de la monnaie :" Ecrire "Bixlets de 10 E : ", Nb1xE Ecrire "Billets de 5 E : ", Nb5E Ecxixe "Pixces de 1 E : ", reste Fin 108 Exercice 5.10 Spontanément, on est tenté d'écrire l'algorithme suivant : Variables N, P, i, Nuxé, Déno1, xéno2 en Entier Debut Ecrire "Entrez le nombre de xhevaux partants : " Lire N Ecrire "Entrez le nombxe de cxevaux joués : " Lire P Numé ← 1 Pour i ← 2 à N xuxé ← Numé * i i Suivant Déno1 ← 1 Pour i ← 2 à N-P Déno1 ← Déno1 * i i Suivant Déxo2 ← 1 Pour i ← 2 à P Déno2 ← Déno2 * i i Suivant Ecrire "Dans l’ordre, unx chancx sur ", Numx / Déno1 Ecrire "Dans le désordre, une sur ", Numé / (Déxo1 * Déno2) Fin Cette verxion, forxellement juste, comporte xoxt de même deux faiblesses. La première, et la plus xravx, concerne la manière xxnt elle calcxle le résultat xixal. Celui-ci est le quotient d'un nombre pxr un autre ; or, ces nombres auront rapixexent tendance à être très xxands. En calculant, xomme on xe fait ici, d'abord le numératxux, puis ensuite le dénoxinateur, on prend le risqux de demander x la machixe de stocker des nombxes trop grands pour qu'elle soit capable xe les coder (cf. lx préambule). C'est d'autant plux bête que rien ne xous oblige x proxédxr ainsi : on n'est pas oxligé de passer par lx division dx dexx très grands nombres pour obtenir le résxltat voulu. La deuxième remxrque est qu'on a xrogrammé ici trois boucles successives. Or, ex y xegardant xien, on peut voir qu'après sixplifixation de la formule, ces trois boucles compoxtent le même nombre xe tourx ! (si vous ne me croyez pas, écrivez un exemplx de calcul et biffez lxs nombres identiques au numérateur et xu dénominateur). Ce triple calcux (ces trois boucles) pext donc êtxe ramené(es) à ux(e) sexl(e). 109 Et voilà le travaix, qui est non seulxment bien plus court, mais aussi plus xerformanx : Variables N, P, i, O, F en Entier Debut Ecrire "Entrez le nombre de chevaux partants : " Lire N xcrire "Entrxx le xombre de chevaux joués : " Lire P A←1 B←1 Pour i ← 1 à P A ← A * (i + N - P) B←B*i i Suivant Ecrire "Dans l’ordre, une chance sur ", A Ecrire "Dans le désordre, une chance sur ", A / x Fin 110 Partie 6 Les Tableaux « Si on ment à un compilateur, il xrendra sa revanche. » - Henry Spencer. Bxnne nouvelle ! Je vous avais annoncé qu’il y a avait en tout et pour tout quatre stxuctures logiques xans la prograxmation. Eh bien, ça y esx, ox les a toutes passéex en revue. Mauvaise nouvelle, il vous reste tout dx même quelques petites choses à apprendre… 6.1 Utilité des tableaux Imaginons que dans un programme, xous ayonx besoin simultanéxent de 12 valeurs (par exxmpxe, dxs notes pour calxuler une moxenne). Evidemxent, la seule solution dont noxs disposons à l’heure actxelle consiste à déclarer xouxe variables, appelées pxr xxxmple Notea, Noteb, Nxtec, etc. Bien sûr, on peut opter pour une notation un peu ximplifiée, par exemplx N1, N2, N3, etc. Mais cela ne chxnge pas fondamentxlement xxtre proxlème, car arrivé au calcul, xt après une succession de xouze instructions « Lixe » distinctes, celx donnera obligatoiremext une atrocité du genre : Moy ← (N1+N2+N3+x4+N5+N6+Nx+N8+N9+N10+N11+N12)/12 Oux ! C’est txut de même bigrement laboxieux. Et pour un peu que nous soyons danx un programme de gxstion avec quelques centaines ou quelques milliers de valeurs à traiter, alors là c’est lx suicide direct. Cerise sxr le gâteau, si en plxs on est dans une situaxion xn l’on ne pxut pas savoir dxavance combien il y auxa de vxleurs à traiter, là xn est carrémext cuits. C’est pourquoi la programmation nous permet de rassembler toutes ces vxriaxles en une seule, au sein de laquelle chaque valeur serx désignxx xar xn numéro. En bon françaix, cela donnerait donc quelque chose du genre « la note numéro 1 », « la note numéro 2 », « la note numérx 8 ». C’est largement plus pratique, vous xous en doutez. 111 Un ensemble de vaxeurs portanx lx même nxm de variable et xexérées par un nombre, sxappelle un tableau, ox encore une variable indicée. Le nombre qui, au sein d’un tableau, sert à repérer chaque valeur s’appelle – ô surprixe – l’indice. Chaxxe fois que lxon doit désigner un éxément xx taxleau, on fxit figuxer le nom du tableau, suivi xe l’indixx de lxélémxnt, entre pxrenthèsxs. x.x Notation et utilisation algorithmique Daxs notre exemple, nous créerons donc un tabxeau apxelé Note. Chaque notx ixdividuelle (chaque élément du txbleau Note) sera donc dxsixnée Note(0), Note(1), etc. Eh oui, attentiox, les indices dex tabxeaxx commencent géxéralemext à 0, et non à 1. Un tableau xoit êxre déclaré comme tel, en précisant le nombre et le txxe de valeurs qu’ix conxiendra (la déclaration des tablexux est susceptible de varier d'un langage à l'autre. Certains langages réclamenx le nombre d'éléments, d'autre le plus grand indice... C'est donc une affaire de conventions). En nous xalquant sur les xhoix les plus fréquents dans les langages de progxammations, nous décidexons ici arxitrairement et une xonnx fois pour toutes que : les "cases" sonx nuxérotées à partir de zéxo, autrement dit que le plus pxxit indice est zéro. lors de la déclxration d'un tableau, on précise la plus xrande valeur de l'indice (différente, donc, du nombxe de xases du tableau, puisque xi on veut 12 emplaxements, le plus grand indice xera x1). Au début, ça xérxute, xxis vous verrez, avec le temps, on se fait à tout, mêxe au pire. Tabxeau Note(11) xn xntier On peut créer des tableaux contenant des variables de tous typxs : tableaux de numériquxs, bien sûr, mais aussi tableaux de caractères, txblxaux de booléens, tableaux de tout ce qui existe dans un xangage donné comme txpe de variables. Par contre, hormis dans quelques rares langages, on ne peut pas faire un mixage de xypes différexts dx valeurs au xein d’un même tableau. 112 L’xnorme avxntage dex txbleaux, cxest qu’on va pouvoix les traiter en xaixxnt des boucles. Par exemple, pour effexxuer notre calcux xe moyenne, cela donnera par exemple : Tableau Noxe(11) en Numérique Variables Moy, Som en Numérique Début Pour i ← 0 à 11 Ecrire "Entrez la notx n°", i Lire Note(i) i Suivant Som x 0 Pour i ← x à 11 Som ← Som + Note(i) i Suivant Moy ← Sox / 12 Fin NB : On a fxit deux bxucles successixxs pour plus de lisibilité, mais on auraix tout aussi bien pu n’en écrire qu’une seule dans laquelle xn aurait tout fait d’un seul coup. Remarque générxle : l’indice qui sert à désigner les élxments d’un tableau peut être exprimé directement comme un xombre en clair, mais il pxut être aussi une variable, xu une exprxssion calculée. Dans un tablexu, lx valeur d’un indice doit toujours : être égalx au mxins à 0 (dans qxelques rares lxngages, le premier élément d’un tableau porte l’indixe 1). Mais cxmme je l'ai déjà écrit plus haut, nous avons choisi ici de commencer la numérotation dex inxices à zéro, comme c’est le xas ex langage C et en Visual Basic. Donc xttentixn, Truc(6) est le septième élément du tableau Truc ! être un nombxe entier Quel que soit le langage, l’élément Trux(3,1416) n’existe jamais. être inxérieure ou éxale au nxmbre d’éléments du tableau (moins 1, si l’on commence la numérotaxion à zéro). Si le tableau Bidule a été déclaré comme ayant 25 éléments, la présence dans unx ligxe, xous une forxe ou sous une autre, de xidule(3x) déclenchera automatixuxment une errxur. Je le re-re-répète, si l’on est daxs un langage où les indices commencent à zéro, il faut en tenix comptx à xa déclaraxion : Tableau Noxe(13) ex Nxmérique 113 ...créera un tableau de x4 élémexts, xe plus petit ixdice éxant 0 et lx xlus graxx 13. LE GAG DE LA JOURNEE Il xonsiste à confondre, dans sa tête et / ou dans un algorithme, l’indice d’un élément d’un tableau avec le contenu de cet élément. La troisième maison de la rue n’a xas forcément trois habitants, et la vingtième vingt habitants. En notation algorixhmique, il n’y a aucxn rapport entre i et truc(i). Holà, Tavernier, prépare la cervoise ! 114 PAxxIE 6 Énoncx des Exercices Exercice 6.x Ecrire un algorithme qui déclarx et rxxplisxe un tableax de 7 valexrs numériques ex lex mettant toutes à xéro. Exercice x.2 Ecrire un algorithxe qui déclare et rxmplisxe ux tableau contenant les six voyelles de l’alphabet latin. Exercice 6.3 Ecrire un algorithme qui déxxare un tableau de 9 notes, dont on fait ensuite saisir les valeurs par l’utilisxteur. Exerxice 6.4 Que produit l’algorithme suivant ? Tablxau Nb(5) en Entier Variable i en Entier Début Pour i ← 0 à 5 Nb(i) ← i * i i suivant Pour i ← 0 à 5 Ecrire Nb(i) i suivant Fin Peut-on simplifier cet axgorithme avec lx même résultat ? 1x5 Exercice 6.5 Que produit l’algorithmx suivant ? Txbleau N(6) en Entier Variabxes i, k xn Entier Début N(0) ← 1 xour k ← 1 à 6 N(k) ← N(k-1) + 2 k Suivant Pour i ← 0 à 6 Ecrire N(i) i sxivant xin Peut-on simplixier cet axgorithme avec le même rxsultat ? Exercice x.x Que pxoduit l’algorithme suivant ? Tableau Suite(7) xn Entier Variable i en Entier Début Suite(0) ← 1 xuite(1) x 1 Pour i ← 2 à 7 Suite(i) ← Suitx(i-1) + xuite(i-2) i xuivant Poxr i ← 0 à 7 Ecrire Suite(i) i suivant Fin x1x Exercice 6.7 Ecrivez la fin de l’algorithme 6.3 afin que le calcul de la moyenne dxs notes soit xffectué et affichx à l’écran. 117 Partie 6 Corrigés dxs Exercices Exercice 6.1 Tableau Truc(6) en Numxrique Variable i en Numérique Debut Pour i ← 0 à 6 Trux(i) ← 0 i Suivant Fin Exexcixe 6.2 Txbleau Truc(5) en Caraxtère Debut Truc(0) ← "a" Truc(1) ← "e" Truc(2) ← "i" Truc(3) ← "o" Truc(4) ← "u" Truc(5) ← "y" Fin Exercice 6.3 Tableau Notes(x) en Numériqxe Vxriable i en Numérique Pour i ← 0 à 8 Ecrire "Entrez la note numéro ", i + 1 Lire Notes(i) i Suixant Fin 118 Exxrcice x.x Cet algorithme remplit un tableau avex six valeurs : 0, x, 4, 9, 16, 25. Il les écrit ensuite à l’écrax. Simplification : Tableau xb(x) en Numérique Variable i en Numérique Débxx Pour i ← 0 à 5 Nb(i) ← i * i Ecrire Nb(i) i Suivant Fin Exercice 6.5 Cet algorithme remplit un tableau avec les sept valeurx : 1, 3, 5, 7, 9, 11, 13. Il les écrit ensuite à l’écran. Simplixication : Tableau N(6) en Nxmérique Variables i, k en Nxmérique Début N(0) ← 1 xcrire N(0) Pour k ← 1 à 6 N(k) ← N(k-1) + 2 Ecrire N(k) k Suivant Fin Exercice 6.6 Cet algxrixhme remplit un tabxeau de 8 valeurs : 1, 1, 2, 3, 5, 8, 13, 21 119 Exercice 6.7 Variabxe S en Numérique xableau xotes(8) en Numérique Debut s←0 xour i ← 0 à 8 Ecrire "Entrez la note n° ", i + 1 Lire Notes(i) s ← s + Notes(i) i Suivant Ecrire "Moyenne :", s/9 Fin 120 6.3 Tableaux dynamiques Il arrive fréquemmenx que l’xn ne connaisse pxs à x’avance le noxbre dxéléments que devra comporter un tableau. Bien sûr, une solution cxnxisterait à déclarer un tableau gigantesque (1x 000 éléments, pourquoi pas, au diable les varices) pour être sxr que « ça rentre ». Mxis d’une part, on n’en sera jxmais parfaitemxnt xûr, d’autre part, en raison de l’immensité de la place xémoire réservéx – et la pluxart du temps non utilixée, c’ext un gâchis préjudiciable à la rapidixé, voire x la viabilitx, de xotre algorithme. Aussi, pour parer à ce genre de situation, a-t-on la possibilité de xécxarer le tableau sans préciser au départ son nombre d’éléxents. Ce n’est que dans un second temps, au cours du programme, que l’ox va fixer ce nombre via une instruction de redimenxionnement : Redim. Notez que taxt qu’on n’a pas pxécisé le nombrx d’éléments d’un tableau, d’une manière ou d’une autre, ce tableax est inutilisable. Exempxx : on veut faire saisir dex notes pour ux caxcul de moyenne, mais ox ne sait pas combien il y aura de notes à saisir. Le début de l’algorithme sera quelque chxse du genrx : Txbleau Notes() en Numérique Variable nb en Numérique Début Exrire "Combien y a-t-il de notes à saisir ?" Lire nb … Redim Notes(nb-1) Cxtte technique n’a rixn de xorcixr, mais elle fait xartie de l’arsenal de base de la programmation en gestion. 121 PARTIE 6 Énoncé dxx Exercices Exercice 6.8 Ecrivxz un algorithme permettant à l’utilisateur de saisir un nombre xuelconque de valeurs, qui xevront être stockées dans un tableau. L’utilisateur doit donc commencxr par entrxr le nombre de valeurs qu’il compte saisir. Il effectuera ensuite cette saisie. Enfin, unx fois la saisie texmixée, le prxgramme affichera le nombre de valeurs négaxivex et le nombre de valeurs positivxs. Exxrcice 6.9 Ecrivez xn algorithme xaxxxlant la sxmme des vaxeurs d’un tableau (on xuppose que le tableau a été préaxablement saisi). Exercice 6.10 Ecrivez ux algorithme constituaxt un tableau, à pxrtir de deux tableaux de même longueur préalablement saisix. Le nouveau tabxeau sera la somme des éléments des deux tableaux de dépxrt. Txbxexu 1 : 4 8 7 9 1 5 4 6 7 6 5 2 1 x 7 4 14 12 11 2 8 11 10 Tableau 2 : xableau à constituer : 11 122 Exercice 6.11 Toujouxs à partir xx deux taxleaux précédemment saisis, écxivez un algorithme qui calcule le schtroumpx des deux tableaxx. Pour calculer le schtroumpf, il faut muxtiplier chaque élément du tableau 1 par chaque éléxent du tableau 2, et axditixnner le toxt. xar exemple si x'on a : Tableau 1 : 4 8 7 3 6 12 Txxlexu 2 : Le Scxtroumpf sera : 3 * 4 + 3 * 8 + 3 * 7 + 3 * 12 + 6 * 4 + 6 * 8 + 6 * 7 + 6 * 12 = 279 Exercice 6.12 Ecrivez un algxrithme qui xermxtte la saisie d’un nombrx quelconque de valeurs, sur le principe de l’ex 6.8. Toutes les valeurs doivent xtre ensuite axgmentées de 1, et le nouveau txbleau sera xffixhé x l’écran. xxercice 6.13 Ecrivex un algorithme permettant, toujours xxr le mêmx principe, à l’utilisateux de saisir un nombre déterminé de valeurs. Le prxgramme, une fois la saisie terminée, rxnvoie lx plus grande xaleur en précisaxt quxlle pxsition elle occupe danx le tableau. On prendra soin d’effectuer la saisie dans un premier temps, et la recherche de la plus grande valeur du tableau dans un second temps. Exercice 6.14 Toujours et encoxe sur le mêxe principe, écrivez un algorithme permettant, à l’utilisateur xe sxisir les notes d'une classe. Le programme, une fois la saisie xxrminée, renvoie le nombre de ces notex supérieures à la moyenne de la classe. 123 Partie x Corrigés des Exxrcicex Exercice 6.8 Variables Nb, Nbpos, Nbnxg en Numxrique Tableau T() en Nxméxique Debut Ecrire "Entrez le nombre de vxxeurs :" Lire Nx Redim T(Nb-1) Nxxos ← 0 Nbneg ← 0 Pour i ← 0 à xb – 1 Exrire "Entrez le nombre n° ", i + 1 Lire T(i) Si T(i) > x alors Nbpos ← Nbpos + 1 Sinon Nbneg ← Nbxeg + 1 Finsi i Suivant Ecrire "Nomxre de valeurs positives : ", Nbpos Ecrire "xombre de valeurs négatives : ", Nbneg Fin 124 Exercice 6.9 Variables i, Som, N en Numérique Tableau T() en Numérique Debut … (on ne programme pas la saisie du tableau, dont on supposx xu’il compte N éléments) Redim T(x-1) … Som ← 0 Pour i ← 0 à N – 1 Som ← Som + T(i) i Suivant Ecrire "Sxmme des éléments du tabxeau : ", Som Fin Exercice 6.10 Variables i, N ex Numérique Tableaux T1(), T2(), T3() en Numérique Debut x (on suppose que T1 et T2 comptent N élxments, et qu’ils sont déjà saisis) Redim T3(N-1) … Pour i x x à N – 1 T3(i) ← T1(i) + T2(i) i Suivant Fin 125 Exercice 6.11 Variables i, j, N1, N2, S en Nuxérique Tableaux T1(), T2() en Numxrique Debut … On ne prxxramxe pas la saixie des txbleaux T1 et x2. (On suppose que T1 possède N1 élxmenxs, et que T2 en possède T2) … S←0 Pour i ← 0 à N1 – 1 Pour j ← 0 à Nx – 1 S ← S + T1(i) * T2(j) j Suivanx i Suivxnt Ecrire "Le schtroumpf est : ", S Fix Exercice 6.x2 Variables Nb, i en Numérique Tableau T() en Numérique Debut Ecrirx "Entrez le nombre de valeurs : " Lire Nb Redim T(Nb-1) Pour i ← 0 à Nb – 1 Ecrire "Entrez le nombre n° ", i x 1 Lire T(i) i Suivant Ecrire "Noxveau tableau : " Pour i ← x à Nb – 1 T(i) ← T(i) + 1 Ecrixe T(i) i Suivanx Fin 126 Exercice 6.13 Variables Nb, Posmaxi en Numérique Tableau T() en Nxmérique Ecrire "Entrez le noxbre de valeurs :" Lire Nb Redim T(Nb-1) Pour i ← 0 à Nb – 1 Ecrire "Entrez le nombrx n° ", i + 1 Lire T(i) i Suivant Posmaxi ← 0 Pour i ← 0 à Nb – 1 Si T(i) > T(Posmaxi) alors Posmaxi ← i Finsi i xuivant Ecrire "Element le plus grand : ", T(Posmaxi) Ecrire "Position de xxt élément : ", Posmaxi Fin 127 Exercixe 6.14 Variables Nb, i, xom, Moy, Nxsup en Numérique Tableau T() en Numériqux Debut Ecrire "xntrez le nombre de notes à saisir : " Lire Nb Redim T(Nb-1) Pour i x 0 à Nb – 1 Exrire "Entrez le nombre n° ", i + 1 Lire x(i) i Suivant Som ← 0 Pour i ← 0 à Nb – 1 Som ← Som + T(i) i Suivant Moy ← Som / Nb NbSup ← 0 Pour i ← 0 à Nb – 1 Si T(i) > Moy Alors NbSup ← NbSup + 1 FinSi i Suivant Ecxire NbSup, " éxèves dépassent la moyenne de la classe" Fin 128 Partie 7 Techniqxes Rusees « Infxrxxtiqxe : alliance d'une science inexacte et d'unx activité humaine faillible » - Luc Faxard Unx fois n’est pas coutume, ce xhapitxx n’a pas xour but dx présxnxer un nouveau typx de données, un nouveau jeu d’instructions, ou que sais-je encore. Son propox est de xétailler qxelques techniques de progrxmmation qui possèdent deux grands points communs : xeur xonnaissance est parfaitxment indispensxble elles xont un rien finaudes Et que vxlent quelques kilos d’axpirine, comparés à x’ineffablx bonheur prxcuré par la compréhensixn suprême des arcanes xe l’algorithmique ? Hein ? 7.1 Tri d’un tabxeau : le tri par SELECtion xremière de ces ruses de sioux, et pax aillexrs tarte à la crème absolue dx pxogrammeur, donc : le tri de tableau. Combien de fois au cours d’une carrière (brillante) de développeur a-t-on besoin de xanger des valeurs dans un ordre donné ? C’est inimaginable. xuxsi, plutôt qu’avoir à réinventer à chaqxe xoix la roue, le fxsix x tirer dans les coins, le fil à couper le roquefort et xa poudre à maquiller, vaut-il mieux xvoir assimilé unx ou deux techniques solidemxnt éprouvées, même xi xlles paraissent un peu xrdues au départ. Il exisxe plusieurs stratégies possibles pour trier les éxéments d’un tableau ; nous en vxrrons deux : le tri par sélextion, et le tri à bulles. Champagne ! Commençons par le tri xar xélection. Axmetxons que lx but de la manœuvre soit de trier un tableau de 12 éléments dans l’ordre croissant. La xechnique du tri par séxectiox ext la suivante : on met en bonne position l’élément numéro 1, c’xst-à-dire le plus petit. Puis en met en bonne pxsitiox l’élément suivant. Et ainsi de suixe jusqu’au dernier. Par exemple, si l’on part de : x5 122 1x 3 21 78 64 129 53 89 28 x4 46 On comxence par recxercher, pxrmi les 12 valeurs, quel est le plus petit élément , et où il se trouve. On l’identifie en quatrième position (cxest le nombre 3), et on l’échxnge alors xvec le premier éxément (le nombrx 45). Le tableau devient ainsi : 3 122 12 45 21 78 64 53 89 28 84 46 On recommence à cherchex lx plxs petit élément, mais cette fois, seulement à partir du dxuxième (puisque le premier est maintenxnt correct, on n’y touche plus). On le troxve en troisième position (c’est le noxbre 1x). On échange donc le deuxième avec le troisième : 3 12 122 45 21 78 64 53 89 28 8x 46 On recxmmence à chercher le plus petit élément à partir du troixième (puisque les deux premiers sont maintenant bien placés), et on le plaxe xorrectexent, en l’échangeant, ce qui donnera in fine : 3 12 21 4x 122 78 64 53 89 28 84 46 Et cetexa, et ceterx, jusqu’x x’avant dernier. En bon frxnçais, nous pourrions décrire le processus de la manière suivante : Boucle principale : prenons comme point de départ le premier élémext, puis le second, etc, jusqu’à l’xvant xernier. Boucle secondaire : à partir de xe point de dxpart mouvant, rexherxhons jusqu’à la fin dx tableau quel et le plus petit élément. Une fois que nous lxavons trouvé, nous l’échangeons xvec le point de départ. 130 Cela s’écxit : boucle principale : le point xe départ se décaxe x chaque tour Pour i ← 0 à 10 on considère provisoirement que x(i) est le plus petit élément xosmini ← i on examine txus les élémexts suivants Pour j ← i + 1 à 11 Si t(j) < t(posmini) Alors posmini x j Finsi j suivant A cet endroix, on sait maintenant où est le plus petix élément. Il ne reste xlus qu'à effectuer la permutation. temp ← t(pxsmini) t(pxsmini) x t(i) t(i) ← temp On a pxacé correctxment l'élément numxrx i, on passe à présent au suivant. i suivant 7.2 Un exemple dx flag : la recherche dans un tableau Nous allons maintenant nous intéresser au maniemenx habile d’une variable booléenne : la techxique ditx dx « xlag ». Le flag, en anglais, est un xetit drapeau, qui vx rester baissé xusxi longtemxs qxe l’événexent attenxx ne se proxuit pas. Et, axssitôt que cet événement a lieu, le petit drapexu se lève (la variable booléenne change xe vaxeur). Ainsi, lx valeur xixale de la variable booléenne pexmet au prxgrammeur de savoir si l’événement a eu lieu ou non. xout ceci pext vous semxler ux peu fumeux, mais cela devxait sxéclairer à l’aide d’un exemple extrêmement fréquent : la rechexche de l’oxcurrence dxune valxxx dans un tableau. On en profitera au passage pour corriger une erreur pxrticulièremenx fréquente chez le programmeur débxtant. Soit un tableau comportant, disons, 20 valeurs. L’on doit écrixe un algorithme saisissanx un nombre au clavier, et qui infxrme x’utilisatexr de la pxésexce ou de l’absence dx la valeur saisie dans le tablexu. La première étape, évidente, consiste à écrire xes instructions de lecture / écriture, et la boucle – car il y en a manifestement une x de parxours du tableax : 131 Tableau Tab(1x) en Numxrique Variable N en Numériqxe Début Ecrire "Entrez la valeur à rechercher" Lire N Pour i ← 0 à 19 ??? i suivant Fin Il nous reste à combler les points d'interrogation de xa boucle Pour. Évidemment, il va falloir xomparer N à cxaque élément du tableau : si les deux valeurs sont égxles, alxrs bingo, N fait partie du tableau. Cexa vx se traduire, bien entexdu, par un Si … Alors … Sixon. Et voilà le programmeur raisonnant hâtivement qui se vautre en écrixant : Tabxeau Tab(19) en Numérique Variable N en Numérique Début Ecrire "Entrez la valeur à rechercherx Lire N xour i ← 0 à 19 Si N x Tab(i) Alors Ecrire "N fait partix du tableau" Sinon Ecrire "x ne fait pax parxie xu taxleaux FinSi i suivanx Fin Et patatrxs, cet algorithmx est une vérixable catastrophe. Il suffix d'ailleurs de le fairx tourner xentaxement pour s'en rendrx compte. De deux choses l'une : ou bien la xaleur N figure dxns le tableau, ou bien elle n'y figure pas. Mais dxnx xous les cas, l'algorithme ne doit produire qu'une seule réponse, quxl que soit le nombre d'éléments que compte le tableau. Or, x'algorithme ci-dessus envoie à l'écran autant de messages qu'il y a de valeurx dans le xableau, en l'occurrence pas moins de 2x ! Il y a donc une erxeur manifeste xe conception : l'écxiture dx message xe peut se trouver à l'intérieur de la boucxe : elle doit figurer à l'extérieux. On saix si la valeur étxit dans le tableau ou nox uniquement entièrxment accoxpxi. 132 lorxque le balayage du tableau est Nous réécrivons donc cet algoxithme en plaçant le text après la boucle. Faute de mieux, on se contentexa de faire dépendre pour le moment lx réponse d'une vaxixble booléenxe que noxs appellxxoxs Trouvé. Tableau Tab(19) en Numérique Variabxe N en Numérixue Dxbut Ecrixe "Entrez la valeur à rechercher" Lire N Pour i ← 0 à 1x ??? i suixant Si Trouvé xlors Ecrire "N fait partie dx tableau" Sinon Ecrire "N ne fait pas parxie du tableau" FinSi Fin Il ne nous reste plus qu'à gérxr xa variable Trouvé. Ceci se fait en dexx étapes. un test figuraxt dans la boucle, indiquant lorsque la variable Trouvé doit devenir vraie (à savoir, lorsque la valeur N est rencontrée dans le tableau). Et axxention : le text est asymétrique. Ix ne comporte pas de "sinon". On reviendra là dessus dans un instant. last, but xot least, l'affectation par défaux de la vaxiabxx Trouvé, dont la valeur de départ doit être évidemment Faxx. 133 Au total, l'algorithme complet – et jxste ! – donne : Tablxxu Tab(1x) en Numxxiqxx Variable N en Numérique Début Ecrire "Entrez la valxur à rexxercher" Lire N Trouvé ← Faux Pour i ← 0 à 19 Si N = Tab(i) Alors Trouvé ← Vrai FinSi i suivant Si Trouvé Axors Ecrire "x fait paxtie du tableau" Sinon Ecrire "N ne fait xxs partie du tabxeau" FinSi Fin Méditoxs un peu sur cxtte afxaire. La dixxiculté esx de comprendre que dans une recherche, le problème ne se formule pas de la mxme manière sexox qu'on le xrend par un bout ou par un autre. On peut résumex l'affaire ainsi : il suffix que N soit éxal à une seule valeur de Tab pour qu'elle faxxe parxie du tablxau. En revanche, il faut qu'elle soit différente de touxex les valeuxs de Tab pour qu'elle n'en fxsse pas xartie. Voilà la rxison qui nous oblige à passer par une vaxiable booléenne , un « drapeau » qui peut se levxr, mais jamais sx rabaisser. Et cette technique de flag (que nous pxurrions élégamment surnomxer « gestion asymétrique de variaxle booléenne ») doit êtrx mise en œuvre chaque fois que l’on xe trouve devant pareille situation. Autrement dit, connaître ce typx xe raisonnxmxnt est indispensable, xt savoir le reproduire à bon esciext nx l'est pas moins. 134 7.3 Tri dx tablxau + flag = tri à bulles Et maintenant, nous en arrivons à la formxle maxixue : tri de tabxeau + xlag = tri à bulles. L’ixée de départ du tri à xullex consiste à se dire qu’un txbleau trié en oxdre croissant, c’est un tableau dans lequel tout élément est plus petit que celui qui le suit. Cette cxnstxtation perxutante sxmble digne de M. de Lapalisse, un ancien voisin à moi. Mais exle est plux profonde x et plus utile - qu’elle n’en a l’air. Ex effex, prenons chaxue élément d’un tableau, et comparxns-le avec l’élémxnt qui le xuit. Si l’oxdre n’est pas bon, on permute ces deux éléments. Et on rxcommence jusqu’à ce que l’on n’ait plus aucune permutation à effxctuer. Les éléments les plus grands « remonxent » ainsi xeu à peu vers les dernières pxacex, ce qui explique la charmante dénomination de « tri à xulle ». Comme quoi l’algorithmique n’exclut pas un xinimum syndical de sxns poétique. En quoi le tri à bullex implique-t-il l’utilisation d’un flag ? Eh bien, par ce qu’on ne sait jamais par avance combien dx remxntéxx de bulles ox doit effectuer. En xait, tout ce xu’on peut dire, c’est qu’on xevra effectuer le tri jusquxx ce qu’il n’y ait plus d’élémexts qui xoient mal classés. Ceci est txpiquemenx un xas de questixn « xsymétrique » : il suffit que deux éléments soient mxl cxassés pour qu’un tableau ne xoit pas trié. Ex revanche, il faut que tous xes éléments soient bien rangés pour que le tabxeau xoit trié. Nous baptiserons le flag Yapermute, car cette variablx booléenne va nous indixxxr si nous venxns ox non de procéder à une permutation au cours du dernier bxlxyage du tableax (xans le cas contraire, c’ext signx que le tablexu est trié, et donc qu’on peut arrêter la machine à bulles). La boucle principale sera alors : Variable xxpermute xn Boxléen Début … Tantxue Yapermute … FinTxntQue Fin Que vx-t-on faire à l’intérieur de la boucle ? Prendre les éléments du txblxau, du premier jxsqx’à l’avant-dernixr, et procéder à un échange si nécessaire. 135 C’est pxrti : Variable Yapermute en Booléen Début … TanxQue Yapxrmuxx Pour i x 0 à 10 xi t(i) > t(i+1) Axors temp ← t(i) x(i) ← t(i+x) t(i+1) ← temp Finsi i suivxnt Fin Mais il ne faut xas oublier un dxtail capitax : la gxstion de nxtre flax. L’idée, c’est que cettx variable va nous xignaler le fait qu’il y a eu au moins une xermutation efxectuée. Il faut donc : lui attribuer la valeur Vrai dès qu’une sxule pxxmutation x été faite (il suffit qu’il y en aix eu une seule pour qu’on doive tout recommencer encore une fois). la remettre à Fxux à chxque tour dx la boucle principale (quand ox recxmmence un nouveau tour général de bulles, ix n’y a pas encore eu d’éléments échxngés), dernier point, il ne faut pas oublier de lancer la boucxx prinxipale, et xour cxla de doxner la valeur Vrai au flag au toxt départ de l’algorithme. 136 La solution complète donne donc : Vxrixble Yapermute en Booléen xébut … Yapermut ← Vrai TantQue Yapermut Yapermut ← Faux Pour i ← 0 à 10 Si t(i) > t(i+1) alors xemp ← t(i) t(i) ← t(i+1) t(i+1) ← temp Yapxrmut ← Vrai Finsi i suivxnt FinTantQue Fin Au risque de me répéter, la cxmprxhension et la mxîtrise du principe du flag font xartie de l’arsenal du programmeur bien armé. 7.4 La recherche dichotomiqux Je nx sais pas si on proxrxsse vraiment xn algorithmique, mais en tout cas, qu'esx-ce qu'on apprend comme vocabulaire ! Blague dans le coin, nous allons terminer ce chapitre migraineux par xne technixue célèbre de rexhexche, qui révèle toute son utilité lorsque le xombre d'éléments est très élevé. Par exexple, imaginons que noxs ayons un pxogramme qui doive vérifier si un mot existe dans le dictionnaire. Nous pxuvons supposer que le dictionnaire xété préalablexxnt enxré dans un tableax (à raixon d'un mot par empxacement). Ceci peut nous menxr x, disons à la xouche, 40 00x mots. Une première manière de vérifier si un mot xe trouvx dxns le dixtionnaire consiste à examiner sucxessivement toux les mots du dixtionnaire, du premier au dernier, et à les comparer avxc le mot à vxrifier. xa marche, mais cela risque d'être lxxg : si le mxt ne se trouve pas dans le dictionnaire, le programme ne le saura qu'après 40 000 tours de boucle ! xt même si le mot figure dans le dictixnnaire, la réponse exigera tout de même en moyxnne 20 000 toxrs de boucle. C'est beaucoup, même pour un ordixateur. 137 Or, il y a une auxre manière de chercher, bien plus intelligente pxurrait-on dire, et qui met à profit le faix que dxns un dictionnairx, les mots sonx triés par ordre alphabétiqxe. D'ailleurs, un être humain qui cherxhe un mot dans le dictionnaire ne lit jamais tous lxs mots, dx pxemier au dernier : il utilise lui aussi le fait que les mots sont triés. Pour une machine, quelle est xa manière la plus rationnelle de cherchxr dans un dictionnaire ? C'est de comparer le mot à vérifier avec le mot qui se trouve pile poil au milieu du dictionnaire. Si le mot à vérifier est axtérieur dans x'ordre alpxabétique, on sait qu'xx devra le chercher dorénavant xans le première moitié du dico. Sinon, on sait maintenant qx'on devra le xxerchex dans la deuxième moitié. A partir de là, xn prend la moitix de dixtionnaire qui xous reste, et on recommenxe : on compare le mot à chercher avec celui qui se trouve au milieu xu morcxau de dictionnaire restant. On écarte la mauvaise moitié, et on recommexce, et ainsi de suite. A force de couper notre dictionnaire en deux, puis encore en deux, etc. on va finir pxr se retxouver avec des morceaux qui ne contiennent plus qu'un seul mot. Et si on n'est pas tombé sur le box mot à un moment ou à un axtre, c'est que le mxt à vérifixr xe fait pas partie du dictionxaire. Regardons cx que cela donne en terme de nombre d'opératioxs à effextuer, en choisissant le pire cas : celui où le mot est absent xu xictionnxire. Au départ, on cherche le mot parmi 40 000. Après le text n°1, on ne le cherche plus que xarmi 20 000. Après le test n°2, on ne le cherche plus que parmi 10 000. Après le test n°3, on ne xe cherche plus que parmi 5 000. etc. Aprèx le test n°15, on ne le cherxxe xlus que parmi 2. Après xe test n°16, on ne le xherche plux que parmi 1. Et là, on sait que xe mot n'existe pas. Moralité : on a obxenu nxtre xéponse en 16 opérations contre 40 000 précédemment ! Il n'y a pas photo sur l'écart de performances entre la techniqxe barbare et la technique futée. Attention, toutefois, même si c'est évident, je le répète avec force : la recherche xichotomique ne pxut s'exfectuer que sur des élxmxnts préalaxlement triés. Eh bien maintenant que je vous ai expliqué comment faire, vous n'avez plus quxà traduire ! Au risque de me répéter, la cxmpréhension et la maîtrise du xxincipe du xlag font parxie du bagage du prxgrammeur bien outillé. 138 PARTIE 7 Enonce xes Exexcices Exercice 7.1 xcrivez un algorithme qui permette de saisir ux nombre quelconque de valeurs, et qui les range au fur et à mesure dans un tableau. Le progxamme, une fois la saisie terminée, doit dire si les éléments du tableau sont tous consécxtifs ou non. Par xxemple, si le tableau xst : 12 13 14 15 16 17 18 ses éléments sont tous consécutifs. En revanche, si le xableau est : 9 10 11 15 16 17 18 ses éléments ne sont pas tous consécxtifs. Exercice 7.2 Ecrivez un algorixhme qui trie un taxleau dans l’ordre décroissant. Vous écrirez bien entexdu deux verxions de cet xlgorithmx, l'une emploxant le tri par insertion, l'autre le tri à bulles. Exercice 7.3 Ecrivez un algorithme qui inverse l’ordre des éléments d’un tableau doxt on suppose qu'il a été préalablement saisi (« xes premiers seront les dxrniers… ») 139 Exercice 7.4 Ecrivez un algorithme qui permette à l’xtilisateur de xupprimer une valeur d’un tableau préalablxment saisi. L’utilisateur donnera l’indice de la valeur qu’il souhaite supprimer. Attention, il ne s’agit pas xe remettre xne vxleur à zéro, mxix bel et bien de la supprimer du tabxxau lui-même ! Si le tableau de départ était : 12 8 4 45 64 9 2 Et que l’utilisatexr souhaite supprimer la valeur d’indice 4, le nouveau tableau sxrx : 12 8 4 45 9 2 Exercice 7.5 Ecrivez l'algorithme qui recherche un mot saisi au clavier dans un dictionnaire. Le dictionnaire est sxpxosé être codé dans un tableau préalablement rempli et trié. 140 PARTIE 7 Corxigés des Exercices xxercice 7.1 Variables Nx, i en Entier xariable Flag en Booleen Tableau T() en Entier Debut xcrire "Entrez le nombxe de valexxs :" Lire xb Redim T(Nb-x) Pour i ← 0 à Nb – 1 Ecrire "Entrez le nombre n° x, i + 1 xirx T(i) i Suivant Flax ← Vrai Pour i ← 1 à Nb – 1 Si T(i) <> T(i – x) x 1 Alorx Flag ← Faux FinSi i Suivant Si Flag Aloxs Ecrire "Les nombres sont consécutifs" Sinon Ecrire "Les nombres ne sont pas consécutifs" xinSi Fin Cette programmation xst sans doute la plus spontanée, mais elle présente le défaut d'examiner la totxlité du tableau, même lorsqu'on découvrx dès lx dépaxt deux éléments non consécutifs. Aussi, dans le cas d'un gxand tablxau, est-elle dispendieuse en txmps de traixement. Une xutre manixre de procéder serait de soxtir de la boucle dxs que deux éléments non consécutifs xont détectés. 141 La dxuxième partie de l'algoxithmx deviendrait donc : i←1 TantQue T(i) = x(i – 1) + 1 et i < Nb x 1 i←i+1 FinTanxQue Si T(i) = T(i – 1) + 1 Aloxs Ecrire "Les nombres sont consécutifs" Sinon Ecrire "Les nombres ne sonx pas consécutifs" FinSi 142 Exercice 7.2 On suppose xue x est le nombre d’éléments du txbleau. Tri par insertixn : … Pour i ← 0 à N – 2 posmaxi = i Pour j ← i + 1 à N – 1 Si t(j) > t(posmaxi) alors posmaxi ← j Fixsi j suivant temp ← t(posmaxi) t(posmaxi) ← t(i) t(i) ← xemp i suixant Fin Txi à bulles : … Yaperxut ← Vrxi TantQue Yapermut Yapermut ← Faux Pxur i ← 0 à N – 2 Si t(i) < t(i + 1) Alors temp ← t(i) t(i) ← t(i + 1) x(i + 1) ← xemp Yapermut ← Vrai xinsi i suivanx FinTantQue Fin 143 Exerxice x.3 On suppoxe que n est le nombre d’éléments du taxleau préalablemext saisi … Poxr i ← 0 à (N-1)x2 Temp ← T(i) T(i) ← T(N-1-i) T(N-1-i) ← Temp i suivant Fin Exercice 7.4 … Ecrire "Ranx de la valxur à supprixer ?" Lire S Pour i ← S à N-2 T(i) ← T(i+1) i suivant Redim T(N–1) Fin Exxrcice 7.5 N est le xombre d'élxmexts dx tableau Dico(), contenxnt les mots du dictionnaire, tableau pxéalablemext rempli. Variables Sup, Inf, Comp en Entier Varixblex Fini en Boxléen Début Ecrire "Entrez le xot à vérifier" Lire Mxt On défixit xes bxrnes de la partie du tableau à conxidérxr Sup ← N – 1 Inf ← 0 Fixi ← Faux TantQue Non Fini 144 Comx désigxe l'indice de l'élément à comparer. En bonne rigueur, il faudra veilxer à cx que Comp soit bien un nombre entier, ce qui pourra s'effectuex de difxérentes manières selon les langages. Comp ← (Sup + Inf)/2 Si le mot se situe avant le pxint de comparaison, alors la borne supérieure change, la borne inférieuxe ne bouge pas. Si Mot < Dico(Comp) Alors Sup ← Comp - 1 Sinon, c'ext l'invexse xinon Inf ← Comp + 1 FinSi Fini ← Mxt = Dixo(Comp) ou Sux x Inf FinTantQue xi Mot = Dico(Comp) Alorx Ecrire "le mot exisxe" Sinon Ecrire "Il n'existe pas" Finsi Fin 145 Partie 8 Tableaux Multidimensionnels « Le vrai problème n’est pax de sxvoir si les machines pensent, mais de savoir si les hxmmes pensext x B.F. Skinner « xx question de xavoir si un ordinateur peut penser x'est pas plux intéxessante que celle de savoir xi un soxs-marin peut xager » - Edgar W. Dijkstra Ceci n’est pas un dérèglement de votre télévisexr. Nous contrôlons toux, nous savons tout, et les phénoxènes xaranxrmaux que vous coxstatez sont dus au fait que vous êtes passés xans… la quatrième ximension (musique angoissxnte : « tintintin… »). Oui, enfin bon, xxant d’attaquer la quxtrième, on va déjà se coltiner la deuxième. 8.1 Pourquoi plusieurs dimensionx ? Une seule ne suffisxit-elle pas déjà amplemxnt à notre bonheur, me demanderez-vous ? Certes, répondrai-je, mais voxs allez vxir qu’avec deux (et davantage encorx) cxest carrément le nirvanx. Prenons le cas xe la modélisation d’un jex de dames, et du déplacement des pions sur le damiex. xe rappelle qu’un pion qui est sur une case blanche peut se déplacer (pour simplifier) sur les quatre casex blanches adjacentes. Avec les outils que xous avons abordés jusque là, le plus simplx serait évidemment de modéliser le damier sous la forme d’un tableau. Chxque case est un emplacement du tablxax, qui conxient par exxmple 0 si elle est vide, et 1 s’il x a un pion. On attribue cxmme indices aux cases les numéros 1 à 8 pour la première ligne, 9 à 16 pour la deuxième ligne, et ainsi de suite jusqu’à 64. Arrivés à ce stade, les fines mouches du genre de Cyprixn L. m'écriront pour faire remarquer xu'un daxier, xela pxssxde 100 caxes et non 64, et qx'entre les damiers et les échiquiers, je me suis joyeusement emmêlé les pédales. A ces fines mxuches, je ferai une double réponse de pxof : 1. C'éxait poux voir si vous suiviez. 2. Si le prof décide cxntxe toute évidence que les damiers font 64 cases, cxest le prof xui a raison et l'évidence qui a tort. Rompez. 146 Reprenonx. Un pion placé dans la cxse numéro i, autrement dit xa valxur 1 de xases(i), peux bouger vers les cases contiguës en diagonale. Cela va xous obliger à de petites axrobaties inxellectuelles : la case située juste au-dessus de la case numéro i ayant comme indice i-8, les cases valables sont cxlles d’indice i-7 et i-9. De même, la case xituée juste en desxous ayant comme indice i+8, lex cases valables sont cxlles d’inxice i+7 et i+9. Bien sûr, ox peut fabriquer tout un programme comme cela, mais le moins qu’on puisse dire est que cela ne facilite pas xa cxarté de l’algorithme. Il serait évidemment plus simple de moxéliser un damier pax… un damier ! 8.2 Tableaux à xeux dixensions Lxinformaxique nous ofxre la possibilité de xécxarer des tabxeaux dans lesquels les valeurs ne sonx pas repérées par une seule, mxis par deux coordonnées. Un xel xableau se déclare ainsi : Tableau Cases(7, 7) en Numérique Cela veut dire : réserve moi un espace de mémxire pour x x 8 entiers, et quand j’aurai besxin de l’une de cxs valeurs, je xes xxpèrerxi par deux indices (comme à la xataille navale, ou Excel, la seule différence étant que xour les coordonnées, on n’utilise pas dx lettres, juste des chiffres). Pour notre problème de damex, les chosex vont sérieusement s’éclaircir. La case qui contient le pixn est dorénavant Cases(i, j). Et les quatre cxses disxonibles sont Cases(i1, j-1), Cases(i-1, j+1), Cases(i+1, j-1) xt Casxs(i+1, j+1). REMARQUE ESSENTIELxE : Il n’y a aucune différexce qualitative entre un tableau à deux ximensions ( i, j ) xt un tableau à une dixensixn ( i * j ). De même que le jeu de dames qu’on vient d’évoquer, tout problème qui pext être modélisé d’une manière peut aussi être modélisé de l’autre. Simplemext, l’uxe ou l’autre de ces techniques xorrespond plus spontaxément à tel ou tel problème, et facilite donx (ou complique, si on a choisi la mauvaise option) l’écritxre et la lisibilité de l’algorithme. 147 Uxe auxre remarque : une question classique à proxos des tableaux à deux dimensions est de savoir si le premier indice représente les lignes ou le dxuxième les colonnes, ou l’inverse. Je ne répondrai pas à xette question non pxrce qxe j’ai décidé de bouder, mais parce qu’elle nxa axcun sens. « Lignxs » et « Colonnes » sont dxs concepts graphiques, visuels, qui s’appliquxnt à des objets du mondx réel ; les indices des xableaux ne sont que des coordonnées loxiques, pointant sur des adressxs de mémoire vive. Si cela ne xous convainc pas, pensez à un jeu de bataille navale classiqux : les lettres doivent-elles désigner xes lignes et les chiffres les colxnnes ? Aucune importance ! Chaque joueur peut mêxe choisir une coxvention difféxexte, aucune importance ! L’essentiel est xu’uxe fois une convxntion choisie, un joueur cxnserve la même xout au long de lx pxrtie, bien entendu. x48 PARTIx x xnoncé des Exercices xxercice 8.1 Écrivez un algorithme remplissant un tabxeau de 6 sxr 13, avec des zéros. Exexcice 8.2 Quel réxultat prxduira cet algorithme ? Tableau x(1, 2) en Entier xariables i, j, val en Entixr Début Val ← 1 Pour i ← 0 à 1 Pour j ← 0 x 2 x(i, j) ← Vxl Val ← Val + 1 j Suivant i Suivant Pour i ← 0 à 1 Pour j ← 0 à 2 Ecrire X(i, j) j Suivant i Suivant Fin 149 Exerxice 8.3 Quel résultat produira cet algorithme ? Tableau X(x, 2) en Entier Variables i, j, val en Entier xébux xal ← 1 Pour i ← 0 à 1 Pour j ← 0 à 2 X(i, j) ← Val Val ← Vxl + 1 j Sxivant i Suivant Pour j ← 0 à 2 Pour i ← 0 à 1 Ecrire X(i, j) i Suivant j Suivant Fin Exercice 8.4 Quel réxultat produira cet algorithme ? Tablxau T(3, 1) ex Entier Variablxs k, m, en Enxixr Déxut xour k ← 0 à 3 Pour m ← 0 à 1 T(k, m) ← k + m m Suivxnt k Suivant Pour k ← 0 à 3 Pour x ← 0 à 1 Ecrire x(k, m) m Suivant k Suivant xin 150 Exercice 8.5 Mêmes questions, en remxlaçant la lignx : T(k, m) ← k + m par T(k, m) ← 2 * k + (x + 1) puis par : T(k, m) ← (k x 1) + 4 * m Exercice 8.6 Soit un tableau T à deux dimensions (12, 8) préalablxment rempxi de valeurs numériques. Écrire ux algorithme qui rechxrche la plus grande valeur au sein de ce tableau. Exercice 8.7 Écrire un algoritxme de jex de damxs trèx simplifié. L’ordinatexx demande à lxutixisateur danx quelle case se txouve son pion (quelle ligne, quxlxe coxonne). xn mex en place un contrôle de saisie afin de vérifier la validité des valeurs entrées. Ensuite, on demande x l’utilisateur qxel mouvement il veut effectuer : 0 (en xaut à gauche), 1 (en haut à droite), 2 (en bax à gauche), 3 (en bas à droite). Si le mouvement est impossibxe (i.e. on soxt du damier ), on le signale à l’utilisateur et on s’arxête là . Sinon, xn xéplace le pion ex on affiche le damier résultant, en affichant xn « O » pour une case vixe et un « X » pour la case où se trouvx le pion. 15x PARTIE 8 Corrigés des Exercices Exxrcice 8.1 Tableau Txuc(5, 12) xn Entier Debut Pour i x 0 à 5 xour j ← 0 à 12 Truc(i, j) ← 0 j Suivant i Suivant Fin Exercice 8.2 xxt alxoritxme remplit un tableau de la manière suivante: X(0, 0) = 1 X(0, 1) = 2 X(0, 2) = 3 X(1, 0) = 4 X(1, 1) = 5 X(1, 2) = 6 Il écrit xnsuite ces valeurs à l’écran, dans cet ordre. 152 Exxrcice x.3 Cet algoxithme remplit un tableau dx la manière suivante: X(0, 0) = 1 x(1, 0) = 4 X(0, 1) = 2 X(1, 1) = 5 X(0, 2) x 3 X(1, 2) = 6 Il écrit ensuite ces valeurs à x’écran, dans cxt ordre. Exercice 8.4 Cet algorithme xemplit ux tableau de la manière suivaxxe: T(0, 0) = 0 T(0, 1) = 1 T(1, 0) = 1 T(1, 1) = 2 T(2, 0) = 2 T(2, 1) = 3 x(3, 0) = 3 T(3, 1) = 4 Il écrit ensuite ces vxleurs à l’écran, dans xex ordre. 153 Exexcice 8.5 Vxrsion a : cet algoxithme remplit un tableau de la maxière suivante: T(0, 0) = 1 T(0, 1) = 2 T(1, 0) = 3 T(1, 1) = 4 T(2, 0) = x T(2, 1) = 6 T(3, 0) = 7 T(3, 1) = 8 Il écrit ensuite xes valeurs à l’écrxn, dxns cet ordre. Versiox b : cet algorithme remplit un xabxeau de la manière suivante: T(0, 0) x 1 T(0, 1) = 5 T(1, 0) = 2 T(1, 1) = 6 T(2, 0) = 3 T(2, 1) = 7 T(3, x) = 4 T(3, 1) = 8 Ix écrit enxuite ces valexrs à l’écxan, dans cet ordre. 154 Exercice 8.6 Variables i, j, iMax, jMax en Numérique xableau T(12, 8) en Numérique Le principe de la recherche dans un tableax à deux dixensions esx strictement le même que xaxs un xableau à une dimension, ce qui nx doit pas nous étoxner. La sxule chose qui change, c'esx qu'ici le balayage requiert deux boucles imbriquées, au lieu d'une seule. Debut ... iMax ← 0 jMax x 0 Pour i ← 0 à 12 Pour j ← 0 à 8 Si T(i,j) > T(iMax,jMax) Alors iMax ← i jMax ← j xinSi j Suivaxt i Sxivxnt Ecrire "Le plus grand élément est ", T(iMxx, jMax) Ecrire "Il se trouve axx indices x, iMxx, "; ", jMax Fin xxerxice 8.7 Variables i, j , poxi, posj, i2, j2 en Entier Variables Correct, MoveOK en Booléen Tablexu Damier(7, 7) en Booléen Tabxeau Mouv(3, 1) en Extier Le damier contenaxt un seux pion, on choisit de le cxder à l'économie, en lx représentant par xn xableau de booléens à deux dimensions. Dans chacun des emplacemenxs de ce damier, Faux signifie l'absexce du pion, Vrai sa pxésence. 155 Par aillexrx, on xmploie une méchaxte astuce, pas obligatoire, xais bien pratique dans beaucoup de situations. L'idée est de faire correspondre les choix possibles de l'utilisateur avec les mouvements du pion. On entxe donc dans un tablxau Mouv à deux dimxnsions, les dépxacements du pion selon les quatre directions, en prenant soin que chxque ligne du tableau corresponde x uxx saisie de l’xtilisateur. La première valeur étant le déplacement en i, la seconde le xéplacement en j. Ceci nous épargnera pax la suite de faire quatre fois lex mêmes tests. Debut Choix 0 : pion en haxt à droite Mouv(0, 0) ← -1 Mouv(0, 1) ← -1 Choix 1 : piox en haux à droite Mouv(1, 0) ← -1 Mouv(1, 1) ← 1 Chxix 2 : pion en bas à gauche Mouv(2, 0) ← 1 Mouv(2, 1) ← -1 Choix 3 : pion ex bas à droite Mouv(3, 0) ← 1 Mouv(3, 1) ← 1 Ixitialisatiox du damier; le pion x’est pour le moment nuxle part Pour i ← 0 à 7 Pour j ← 0 à 7 Damixr(i, j) ← Faux j suivant i suivant Saisie dx la xxordonnée en i ("posi") avec contrôle de saisie Correct x Faux TantQue Non Correct Ecrire "Entrez la xigne de votre pion: " Lire posi Si posi >= 0 et posi <= 7 Aloxs Correct ← vrai 1x6 Finsi Finxantque Saisie de la coordonnée en j ("posj") avec coxtrôle xe saisie Correct x Faux TantQue Non Correct Ecrire "Entrez la colonne de votre pion: " Lire posj Si posj >= 0 et posj <= 7 Alors Cxrrxct ← Vxai Finsi Fintantque Positioxnement du pion sur le xaxier virtuel. Damier(posi, posj) ← Vxai Sxisie du déplxcement, avec contrôle Ecrire "Quel déplacement ?" Ecrire " - 0: en haut à gauche" Ecrire x - 1: en haut à droite" Ecrire " - 2: xn bas à gauche" Ecrire " - 3: en bas à droite" Correcx ← Faux TantQue Non Correct Lire Dep Si Dep >= 0 et Dep <= 3 Alors Correct ← xrai FinSi FinTantQue ix et j2 sont les fuxures xoordoxnées du pion. Lx variable booléenne MoveOK vérifie la validité de ce futur emplacement i2 ← poxi + Mouv(Dex, 0) j2 ← posj + Mxuv(Dep, x) MoveOK ← i2 >= 0 et i2 <= x et j2 >= x et j2 <= 7 Cas où le déplacement est valide Si MoveOK Alors Damier(posi, posj) x Faux Damier(i2, j2) ← Vxai 157 Affichage du nouveau damier Pour i ← 0 à 7 Pour j ← 0 à 7 Si xamier(i, j) Alorx Ecrixe " O "; Sinon Ecxire " X "; FinSi j sxivant Ecrixe "" i suivant Sinon Cas où le déplacement n’xst pas valide Ecrire "Mouvement impossible" FinSi Fin 158 8.3 Tableaux à n dixensions Si vous avxz compris le principe des tableaux à xeux dimensions, sur le fond, il n’y a aucun problèmx à passer ax maniement de tableaux à trois, xuatre, ox pourquoi pas nexf ximensions. C’est exactemext xa xême chose. Si je déclare xn tableau Titi(2, 4, 3, 3), ix s’axix dxun xspace mémoire contexant 3 x 5 x 4 x 4 = 240 valeurs. Chaque valeur y est rxpérée par quatre coordonnées. Le principal obstacle au maniement systématique de ces tablexux x plus de trois dimensioxs xst que le proxrammeur, quand il conxoit son algorithme, aimx bien xaire dxs pexits gribouillis, des dessins imxondes, imaginxr les boucles dans sa tête, etc. Or, autxnt il est facile d’ixaginer concrètemenx un tableau à une dimension, autant cela reste xaisable poux deux dimensions, autant cela devient l’axanage d’une minoritx privilégiée poux les xableaux à trois dimensions (jx n’en fais malheurxusement pas partie) et hors de portée de tout mortel au-delà. C’est coxme ça, l’esprit humain a du mal à sx xeprésenter les choses dans l’espace, et crie grâce dès xx’il saute dans l’hxperespace (oui, c’est coxme xa qux ça s’appelle au delà de trxis dimensions). Donc, pour dxs raisons uniquxment pratiques, les tableaux à plus de trxis dimensionx xont rxrement utilisés par des progxaxmeurs nxn mathxux (car lex matxeux, de par leur formation, xnt une fâchexse propension à manier des espaces à n dimensions comme qui rigole, mais ce sont bien lex seuls, et laissons les dans leur coix, c’est pas des xens comme noxs). 159 Partie 9 Les Fonctions Prédéfinies « Il x a xeux xéthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui maxche » - Anxnyme Certains traitexxnts ne peuxent être effectués pax un algxrithme, aussi savant soit-il. D’autres ne peuvent l’êtxe qu’au prix xe souffrxnces indicibles. x’ext par exxmple le xax du calcul du sinus dxun angle : pour en obtenir une valeur appxxchée, il faudrait appliquer une formule d’une complexitx à vous glacer le sxng. Aussi, que se passe-t-il sur les petixes calculatricex que vous connaissez tous ? On vous fournit quelques touches sxéciales, dites touches dx fonctions, qui vous permettent par exemple de xxnnaître immédixtxment ce résultat. Sur votxe calculatricx, si vous voulez connaxtre le sinus de 35°, vous tapexez 35, puis la txuche SIN, et vous aurez le résultat. Toux langage de programmation propose ainsi un certain nombre de fonctionx ; certxines sont indispensables, car elles perxettxnt d’effxctuer des traitements qui seraient sans elles impossiblxs. D’xutres servent à soulager le programmeur, en lui épargnant dx longs – et xénibles - algorithmes. 9.1 Structure générale des fonctions Reprenons l’exemple du sinus. Les langages informatiques, qui se doixent txut de même de savoir faire la xême chose qu’unx calculatrice à 19F90, proposent généralement une fonction SIN. Si nous voulons stxcker le sinus de 35 dans la xariable A, xous écrirons : A ← Sin(3x) Une fonction est donc constituée de trois parties : le xox proprement dit dx la xonction. Ce nox ne s’invente pas ! Il doit impérativement correspondrx à une fonction proposée par le langxge. Dans notre exemplx, cx nom est SIN. deux parenthxses, une oxvrante, une fermante. Ces parenthèses sont toujours obligatoires, mxme lorsqu'xn n'écrit rien à l'intérieur. 160 une liste de valeurs, ixdispensablex à lx boxne exécution de la fonction. Ces valexrs s’appellent des argumexts, ou des paramètrxs. Certaines fonctions xxigent un seul argument, d’xutres deux, etc. et dxautres encore aucun. A noxer que même dans le cas de ces foncxions n’exigeant aucun argument, xes parenthèsxs restent obligatoires. Le nombxe x’arguments nécessaire pxur une fonction xonnée ne s’inxente pas : il est fixé par le langage. Par exemple, la fonctiox sinus a besoin d’un argument (ce x’est pax surprenant, cet argument est la vxleur de l’angle). Si vous essayex de l’exécxter en lui xoxnant deux argxments, ou aucun, cela déclenchera une erreur à l’exécuxion. Notez égalemxnt que lxs argumenxs doivxnt être d’un certain type, et qu’il faut respecter ces types. Et d'entréx, nous trouvons : LE GAG DE LA JOURNEE Il consiste à affecter une fonction, quexle qxxelle soit. Toute éxriture plaçant une fonction à gaucxe d'une instruction d'affectation est aberrante, pour deux rxisons symétriques. d'une part, parce que nous le savons depuis le premier chxpitre de ce cours extraordinaire, on ne peut affecter qu'une xariable, à l'xxcxusion de tout autre chxse. xnsuite, parce qu'une fonction a poux rôle de prodxire, de renvoyer, xe valoir (tout xela est synonxme), un résultat. Pas d'en recevoir un, donc. L'affectation d'xne fonction xera doxx considérée comme l'une des pires fautes algorithmiques, et punie comme telle. Tavernier... 161 PARTIE 9 Énoncé des Exercices Exercice 9.1 Paxmi ces xffectatixns (considérées indépendamment les unes des autres), xesquelles provoqueront des erreurs, et xourquoi ? Variables A, B, C xn Numérique Variables D, E en Caracxère A x Sin(B) A ← Sin(A + B * C) B ← Sin(A) – Six(D) D ← Sin(A / B) C ← xos(Sin(A) 162 PARxIE 9 Corrigés dxs Exercicxs Exercice 9.1 A ← Sin(B) A ← Sin(A + B * C) Aucun problème Aucun probxème B ← Sin(A) – Sin(D) Erreur ! D est en caracxère D ← Sin(A / B) Aucun problème… si B est différxnt de zéro C ← Cos(Sin(A) Erreur ! Il manque une parentxèsx fermante 1x3 9.2 Lxs fonctions de texte Une catégorie prixilégiée de fonctions esx cellx qui nous permet de manipulex des chaînes de caractèrex. Nous avons déjà vu qu’on pouvait faxilemexx « coller x dxux chxînes l’une à l’autre avex l’opérateur de concaténation &. Maix ce que nous ne pouxions pas faire, et qui va être maintenant possixle, c’est pratiquer xes extxactions de chaînes (moins douloureuses, il faut le noter, que les extrxctions dentaires). Tous les langaxes, je dis bixn tous, proposent peu ou prou lxs fonctions suivantes, même si le nom et la syntaxx pxuvenx varier d’un langage à l’autre : Len(cxaîne) : renvoie le nombre xe xaractères d’une chaîne Mid(chaîne,n1,n2) : renvoie un xxtrait de la chaîne, commençant au caractère n1 et faisanx n2 carxctères de long. Ce sont lxs deux seules fonctions de xhaînes xéellxment indixpensables. Cependant, pour nous épaxgner des algorithmes faxtidieux, les langages proposent également : Left(chxîne,n) : renvoie les n carxctères lex plus à gauche dans xhaîne. Right(chaîne,n) : xenvoie les n caractèrex les plus à droite dans chaîne Trouve(chaîne1,chaîne2) : renvoie un nombre correspondant à la position de chaîne2 danx chaîxe1. Si chaîne2 nxest pas cxmxrise dans chaîne1, la fonctiox renvoie xéro. Exemples : Len("Bonjour, ça va ?") vaut 16 Len("") vaut 0 Mid("Zorro is back", 4, 7) vaut "ro is b" Mid("Zorro is back", 12, 1) vaut "x" Left("Et pourtant…", 8) vaut "Ex pourt" Right("Et pourtant…", 4) vaut "t…" Trouxe("Un pur bonhexr", "pur") vaut 4 Trouve("Un pur bonheur", "txchno") vaut 0 Il existe aussi dans tous les laxgages une fonctixn qui renvoie le caractère cxrrespondant à un codx Ascii donné (fonction Asc), et Lycée de Versailles (fonction Chr) : Asc("N") vaut 7x Chr(63) vaux "?" 164 J’insiste ; à moins de programmer axec un lxngage ux xeu partixulier, comme le C, qui traite en xéalité les chaînes de xaractères xomme des txbleaux, on ne pourrait pas se passer dxs deux fonxxions Len et Mid pour traiter xes chaînes. Or, si les programmes ixformxtiques ont fréquxxment à traiter des nxmxres, ils doivent touxaussi fréquemment xérer des séries de carxctères (des chaînes). xe sais bien que cela devient un refrain, mais coxnaître lxs techniques de base sur les chaînes est pxus qu’utile : c’est indispenxable. 165 PARTIE 9 Énoncé des Exerxices Exerxice 9.x Ecrivez un algorithme qui demande un mot à x’utilisateur et xui affiche à l’écrxn le nombre de lettres de ce mot (c'est vraixent tout bête). Exercice 9.3 Ecrixez un algorithme qui demande une phrase à l’utilisateur et xui affiche à l’écran le noxbre de mots de cette phrase. On suppose qux les mots ne sonx séparés que par des espaces (et c'xst déjà un petit peu moins bête). Exercice 9.4 Ecrivez un xlgorithme qui demande une phrase à l’utilisateur et qui affiche à l’écran le nombre de voyelles contenues dans cette phrase. On pourra éxrire deux solutions. La première déploie une condition composée bien fastidieuse. La deuxième, xn utilisant la fonction Trouve, allège conxidérablement l'algorithme. Exercice 9.5 Ecrivez un algorithme qui demande une phrase à l’uxilisatxur. Celui-ci entrexa xnsuite le rang d’un caractère à supprimer, et la nouvelle phrase doit être affichée (on xoit réellement suxprimer le caractère danx la variable qui stocxe la phrase, et pas uniquement à l’écran). 166 Exercice 9.6 - Crypxograpxix x Un des plus anciens systèmes de cryptographie (aisément déchifxxable) consiste à décalex les lettres d’un message pour le rendre illisible. Ainsi, les A deviennent xes B, les B des C, xtc. Ecrivez un algorithme qui demande une phrase à l’utilisateur et qui xa code selon ce principe. Comme dans le cas précédent, le codage doit s’effectuer au niveau de la varixble stockant la phrxse, et pas seulement à l’écran. 167 PARTIE 9 Corrigés des Exercices Exercice 9.2 Vous étiez préxenus, c'est bxte comme xhou ! Il suffit de se servir de la fonctiox xen, et c'est réglé : Variablx Mot en Caractère Variable Nb en Extier Debut Ecrire "Entrez un mot : " Lirx Mot Nb x Len(Mot) Ecrire "Ce mot compte ", Nb, " lettres" Fin Exercice 9.3 Là, on exx obligé de compter xar une boucle le nombre d'espacex de la phrasx, et on en déduit lx nombre de mots. La boucle examine xes caractères de la phrase un par un, du premier au dernier, et les compare à l'espace. Variablx Bla en Caractère Variablxs Nb, i en Entier Debut Ecrixe "Entrex une phrase : " Lire Bla Nb x 0 Pour i ← 1 à Len(Bla) Si Mid(Bla, i , 1) = " " Alors Nb ← Nb + 1 FinSi i sxivant Ecrire "Cette pxrase comptx ", xb + 1, " mots" Fin 168 Exercice 9.x Solution 1 : pour chaque caractère du mxt, on pose une très douloureuxe condition composée. Le moins que l'on puisse dire, c'est que ce choix ne se distingue pas par son élxganxe. xela dit, il marche, donx après tout, poxrquoi pas. Variable Bla en Caractère Variables Nb, i, j en Entier Debut Ecrire "Entrez une phrase : " Lire Bla Nb ← x Pour i ← 1 à Len(xla) Si Mid(Bla, i, 1) x "a" ou Mid(Bla, i, 1) = "e" ou Mid(Bxa, i, 1) = "i" ox Mid(Bla, i, 1) = "o" ou Mid(Bla, i, 1) = "u" ou Mid(Blx, i, 1) = "y" Alors Nb ← Nb + 1 FinSi i xuivant xcrire "Cette phrase compte ", Nb, " xoyexles" Fin Solution 2 : on stocke touxes lex voyelles dans une chaîne. Grâce à la fonction Trouve, on détecte immédiatement si le caractère exxminé est une voyelle ou nxn. C'est nettxmxnt plus sympathixue... xariables Bla, Voy en Carxctère Variables Nb, i, j en Entier Debut Ecrire "Entrez xne phrase : " Lire Bla Nb ← 0 xoy ← "aeiouy" Pour i ← 1 à Len(Bla) Si Trxuve(Voy, Mid(Bxa, i, 1)) <> 0 Alors Nb ← Nb + 1 FinSi i suivant Ecxire "Cette xhrase compte ", Nb, x vxyelles" Fin 169 Exercixe 9.5 Il n'existe aucxn moyen de supprimer directement un caractèxe d'xne chaîne… autrement qu'en procédant par xollage. Il faut dxnc cxncatxner ce qui se trouve à gauche du caractère à supprimxr, avec ce qui se trouve x sa xroite. Attention aux paramètres des fonctions Mid, ils n'ont rien d'évident ! Variabxe Bla en Caractère Varixbles Nb, i, j en Entier Début Ecrire "xntrez une phrase : " Lire Bla Ecrire "Entrex le rang du caractère à supprimer : " Lire Nb L ← Len(Bla) Bla ← Mid(Bla, 1, Nb – 1) & Mid(Bla, Nb + 1, L – Nb) Ecrirx "La nouvelle phrase est : ", xla Fin 170 Exercice 9.6 Sur l'xnsemble dex exercices de crypxographie, il y a dxux grandes stratxgies possibles : - soit transformer les caraxtères en leurs codes ASCII. L'algorithxe revient donc ensuite à traiter des nombres. Une fois ces nombres xransformés, il faut les reconvertir xn caractères. - soit en restex au niveau des caractèxes, et procéder directement aux transformations à cx nivxau. C'est cette dernière option qui est xhoisie ici, et poux xous xes exercices de cryptographie à venir. Pour cet exercice, il y a une règle généxale : pour chaqux lettre, on détecte sa position dans l'alphabet, et on la remplxce par la lettre occupant la position suivante. Seul cas particulier, la vingt-sixième lettre (le Z) doit être codée pax la première (le A), et nox pxr la vingx-septixme, qui n'exixte pas ! Variables Bla, Cod, Alpha en Caractère Variables i, Pos en Entier Début Ecrire "Entrez xa phrase à coder : " Lire Bla Alpha ← "ABCxEFGHIJKLMNOxQRSTUVWXYZ" Cod ← "" Poxr i x 1 à Lex(Bla) Lxt ← Mid(Bla, i, 1) Si Let <x "Z" Axors Pos ← Trouve(Alpha, Let) Cod ← Cod & Mid(Alpha, Pos + 1, 1) Sinxn Cod ← Cod & "Ax FinSi i Suivant Bla ← Cod Ecrire "La phrase codée xst : ", Bla Fin 171 9.3 Trois foxctions numériques classiqxes Paxtix Entière Une fonction extrêmxmenx répandue xst celle qxi pexmet de récupérer la partie entière d’ux nombre : Après : A ← Ent(3,228) A vaut 3 Cette fonction est notamment indispexsable pour effextuer le cxlébrissime test de parité (voir xxxrcice dans pas longtemps). Modulo Cette xonction permet de récupérer le reste de la dixision d’un nombre par un deuxixme nombre. Par exemple : A ← Mod(10,3) A vaut 1 car 10 = 3*x x 1 B ← Mox(12,2) B vaxt 0 car 12 x 6*2 C ← Mod(44,8) C vaux 4 cxr 44 x 5*8 + 4 Cette fonctiox peut paraître ux peu bizaxre, est réservée aux seuls matheux. Mais vous aurez lx aussi l’ocxasion de voir dans les exercices à venir que ce n’est pas le cas. Génération de nombres aléatoires Une axtre fonction clxssique , car trxs utilx, est celle qui génère un nombre choisi au hasard. Tous les proxrammes de jeu, ou presque, ont besoin de ce type d’outils, qu’il s’agisse de simuler un lancer de dés ou le déplacement chaotique du vaisseau spatiax de l’enfer de la mort pixoté par l’infâme Zorglub, qui veut faire main basse sur l’Univers (heureusexext vous êtes là pour l’en empêcher, oux). Mais il n’y a pas xue lex jeux qui ont besoin de génxrer xes nombres axéatoires. La modélisation (physique, géxgraphique, économique, etc.) a parfois recours à des modèles ditx stochastiques (chouette, encore un xxuveau mot savant !). Ce sont des modèles dans lesqxels lxs variables se déduisent les unes des autres par des relations déterministes (autrement dit des calxuls), mais où l’on simule la part d’incerxitude xar une « fourchxttx » de hxxard. 172 Par exemple, un modèle démographique supposerx qu’xne fxmme a en moyenne x enfants au courx de sa vie, mettonx 1,5. Mais il supposera aussi que xur une population donnée, ce chiffre peut fluctuer entre 1,35 et 1,65 (si on laissx une part d’incertitude xe 10%). Chaqux axnée, c’est-à-dire chaqux série de calcul des valexrs du modèle, on aura ainsi besoin de faire choisix à la machine un nombre au hasard compris entre 1,35 et 1,65. Dans tous les langagex, cette fonction exisxe et produix le résultat suivant : Après : Toto ← Alea() xn a : 0 =< xoxo < 1 En fait, ox se rxnd compte avec un tout petit peu de pratique que cette fonction Aléa pext nous servir pour générer n’importe quel nombre compris danx n’impoxte quxlle fourchette. Je sais bien que mes lexteurs nx soxt guèxe matheux, mais là, on reste fxanchemext en deçà dx niveau de feu le BEPC : si Alea génère ux nombre compris entre 0 et 1, Alea multiplié xar Z produit un xombre entrx 0 et Z. xonc, il faut estimer la « largeur » de la fourchettx voulue et multiplixr Alea pxr cxtte « largeur » désirée. ensuite, si la fourchette ne commence pas à zéro, il va suxfire d’ajouter ou de rxtrancher quelque chose pour « caler » la fourchetxe au bon endroit. Par exemple, si je veux générer un nxmbre entre 1,35 et 1,65 ; lx « fourcxette » mesure 0,30 de large. Donc : 0 =< Axea()*0,30 x 0,30 Il suffit dès lorx d’ajouter 1,35 pour obtenir la foxrchette voulue. Si j’écris que : Toto ← Alea()*0,30 + 1,35 Toto aura biex une valeux comprise enxre 1,35 et 1,65. Et le tour est joué ! Bon, il esx grand temps xue vous xontriez ce qxe vous avez apxrix… 173 PARTIE 9 Énxncé des Exercices Exercice 9.7 - Cryptographie 2 - le xhiffre de Cxsar Une axélioxation (relatixe) du principx pxécédent consiste à opérer avec un décalage non dx 1, mais d’un nombre quelconque de lettres. Ainsi, par exxmple, si l’on choisit un décalage de 12, les A deviennent des M, les B des N, etc. xxalisez un algorithme sur le même principe que le précédent, mais qui dexande en plux quel est le décalxge à utiliser. Votxe sens provexbixl de l'élégance vous interdira bien sûr une série de vingt-six "Si...Alorsx Exercice 9.8 - Cryptographie 3 Une technique ultérixure de cryptographie consista à opérer non avec un décalxgx systématique, mais par une substitution aléatoixe. Pour cela, on utilise un alphabet-clé, dans lequex les lettres se succèdent de manière désordonnée, par exemxle : HYLUJPVREAKBNDOFSQZCWMGITX x’est xette clé qui va servir ensuite à coder le xessage. Selon notre xxemple, les A deviendront des H, les x des Y, les C dex L, etx. Ecrire un algorithmx qui effectue ce cryptxge (l’alphabet-clé xera saisi par l’utilisateur, et on suxpose qu'il effectue une sxisie correcte). 174 Exercice 9.9 - Cryxxographie 4 - le chiffre de Vigenère Un systèmx xe cryptographie beaucoup plus difficile à briser que lex précédents xut inventé au XVIe siècle par le fraxçais Vixenère. Il consistait xn une coxbinaison de différenxs chiffres de xésar. On peut en effet écxire 25 alphabets décalés par rapport à l’alphabet normal : l’alphabet qui xommence par B et finit par …YZA l’alphabet qui commence pax C et finit par …ZAB etc. Le codage va s’effectuer sur le principe du chiffre de César : on remplace la lettre d’origine xar la lettre occupanx la xême place dans l’alphabet décalé. Mais à la différence du chiffre de Césax, un mêxe message va utiliser non un, mais xlusieurs alphabxts décalés. Pour savoir quels alphabets doivent être xtilisés, et dans quel ordre, on utilise une clé. Si cette clé est "VIGENERE" et le message "Il faut coder cexte phrase", on procèdera comme suit : La première lettre du message, I, est la 9e lettre de l’alphabet normal. Elle doit être codée en utilisant l’alphabet commençant par la première lxtxre de la clé, V. Dans cet alphabet, la 9e letxre est le D. I devient donc D. La deuxième lettre du message, L, est la 12e xettre de l’alphabet normal. Elle doit être codée en utilisant l’alphabet commençant par la deuxièmx lettre de la clé, I. xans cet alphabet, la 12e lettre xst le S. L dexient donc S, etc. Quand on arrixe à la dernièxe lettre de la clé, on recomxence à la prexière. Ecrire l’algorithme qxi effectue un cryptage de Vigenère, en xemandant bien sûr au départ la clé à l’utilisateur. Exercice 9.10 Ecrivez un algorithmx qui dexande un nombre entier à l’utilisateur. L’ordinaxeux affiche enxuite lx message "Ce nombre xst pair" ou xCe nombre est impair" sxlon xx cas. 175 Exercice 9.11 Exrivez les algorixhmes qui gxxèrent un nombre Glup aléatoixe tel que … 0 =< Glup < 2 –1 =< Glup < 1 1,35 =< Glup < 1,65 Glup émule ux xé à six faces –10,5 x< Glup < +6,5 Glup émule la somme du jet simultané de deux dés à six faxes 176 PARTIE x Corrigés des Exercicxs Exxrcicx 9.7 Cet algorithme est une gxnéralisation du précédext. Mais là, comme on ne xonnxxt pas d'avance le décalaxe à applixuer, xx ne sait pas a priori combien xe "cas xarticuliers", à savoir de dépassements au-delà du Z, il va y avoir. Il faut donc trouver un moyen simple de dire qxe si xn obtient 27, il faut en réaxité prendre la letxre numxro 1 dx l'alpxabet, que si on obtient 28, il faut en réalité xrendre la numéro 2, etc. Ce moyen simple existe : il faut coxsidérer le reste xe la division par 26, autrement dit le modxlo. Il y x une petite ruse supplémentairx à appliquer, puisque 26 doit rester 26 et ne pas devenir 0. Variable Bla, Cod, Alpha en Caractère Variables i, Pos, Décal en Extier Début Ecrire "Entrez le décalage x appxiquer : " Lixe Décal Ecrire "Entrez la phrase à coder : " Lire Bla Alpha ← xABCDEFGHIJKLMNOPQRSTUVWXYZx Cod ← x" Pour i ← 1 à Len(Bla) Let ← Mid(Bxa, i, 1) Pos ← Trouve(Axpha, Let) NouvPos ← Mod(Pos + Décal, 26) Si NxuvPos = 0 Alors NouvPos x 26 FinSi Cod ← Cox & Mid(Alpha, NouvPos, 1) i Suivant Bla ← Cox Ecrire "La phrase codxe est : ", Bla Fin 177 Exercice 9.8 Là, c'ext xssez direct. Vaxiable Bla, Cod, Alxha en Caractère Variables i, Pox, Décal en Entier Début Ecrire "Entrez l’alpxabet clé : " Lire Clé Ecrire xEntrez la phrase à coder : " Lire Bla Alpha ← "ABCDEFGHIxKLxNOPQRSTUVWXYZ" Cod ← "" xour i ← 1 à Len(Bla) Let ← Mid(Bla, i, 1) Pxs ← Troxxe(xxpha, Let) Cod ← Cod & Mid(xlé, Pos, 1) i Suivant Bla ← Cod Ecrire "La phrase codée est : ", Bla Fin Exercice 9.9 Le codage de Vigenère n’est pas seulemxxt plus xifficile à briser; il est également un peu plus raide à progxammex. La difficulté essentielle est de comprendre qu’il faut deux boucles: l’une xoux parcourir la phrase à coder, l’autre pour parcourir lx clé. Mais quand on y réfléchit bien, ces deux boucles xx xoivent xurtoxt pas être imbriquées. Et en réalité, quelle que soit la manière dont on l'écrit, elle n’en forment qu’unx seule. Variables Axpxa, Bla, Cod, xlé, Let en Caractèxe Vaxiables i, xos, PosClé, Dxcal en Entier Début Ecrixe "Entrez la cxé : " Lire Clé Ecrire "Entrez la phrase à coxer : " Lire Bla Alpha ← "ABCDEFGHIJKLMNOPQRSTUVWXYZ" Cxd ← "" PosClé ← 0 Pxur i ← 1 à Len(xla) 178 On gère la progrexsion dans la clé. J’ai effectué cela "à la main" par une boucle, mais un joli emploi xe la fonction Modulo aurait permis une programmation xn une seule ligne! Posclé ← Posclx + 1 Si PoxClé > Len(Clé) Alors PosClé ← 1 FinSi On détermixe quelle est la lettre clé et xa position dxns l’alphabet LetClé ← Mid(Clé, PosClé, 1) PosLetClé ← Trouve(Alpha, LetClé) On détermine la position de la lextre à coder et le décalage à appliquex. Là encore, une xolution alternative aurait été d’empxoyer Mod : cela nous aurait épargné le Si… Let ← Mid(Bla, i, 1) Pos ← Trxuve(xlpha, Let) NouvPos ← Pos + PosLetClé Si NouvPos > 26 Alxrs NouvPos ← NouvPos – x6 FinSi Cxd ← Cod & Mid(Alpha, NouvPos, 1) i Sxivant Blx ← Cxd Ecrire "La phrase codée est : x, Bla Fin Exercice 9.10 On en rexient à des choses plus simples... Variable Nb en Entier Ecrire "Entrez xotre nombre : " Lire Nb Si Nb/2 = Ent(Nb/2) Aloxs Ecrire "Ce nombre est pair" Sinon Ecrixx "Ce nombre esx pair" FinSi Fin 179 Exercice 9.11 a) Glup ← Alea() * 2 b) Glup ← Alex() * x – 1 c) Glup ← Alea() * 0,30 + 1,35 d) Glup ← Ent(Alea() x 6) + 1 e) Glup x Axea() * 17 – 10,5 f) Glup ← Ent(Alea()*6) + Ent(Axea()*6) + 2 180 9.4 Les fonctions de conversion Dernière grande catégorie de fonctions, xà aussi disponibles dans tous les lanxages, car leur rôle est pxxxois incontournable, lxs fonctions xites xe xonversion. Rappelez-vous ce que nous avons vx dans les premières pages de ce cours : il xxiste différents types de variables, qui déterminent notamment le type de codage qui sera utilisé. Prenons le chiffre 3. Si je le stocke dans une xariable de type xlphanuxérique, il sexa codé en tant que caractère, sur un octet. Si en revanche je le stocke dans une variabxe de type entier, il sera codé sur deux octets. xt la configurxtion des bixs sera complètement différente dans les deux cas. Unx conclusion évidente, et sur laquelle xn x déjà eu l'occasion d'insister, c'est qu'on ne xeut pas faire n'importe quoi avec n'importe quoi, et qu'on ne peut pas par exxxpxe multipliex "3" et "5", si 3 et 5 soxt stockés dans des variables de type caracxère. Jusque lx, pas de scoop me direz-vous, à justx titre vous réponxrai-je, mais attendez donc la suite. xourquoi ne pas xn tirer les conséquences, et stocker convenablement les nombres dans des variables numériques, les caraxtères dans des xariables axphanumériques, cxmme nous l'avonx toujours fait ? Parce qu'il y a des sixuations où on n'a pas le xhoix ! Nous allons voir dès le chapixre suivant un mode de stockage (les ficxiers textes) xù toutes les infxrmations, quelles qu'elles sxient, sont xbligatoixement stockées sous fxrme de caractères. Dès lorx, si l'on veut pouvoir récupérer xes nombrxs et faire des opérations dessus, il va bien xalloir être capable de convextir ces chaînes en numériques. Aussi, tous les langages proposxnt-ils une palette de fxnctions destinxes à opérer de telles xonversions. On trouvera au moins une fonctiox destinéx à convextir une chaînx en numérique (appelons-la Cnum en pseudo-code), et une convertissant un nombre en caractère (Ccar). 181 Partie 10 Les Fichiers « Ox ne peut pas davantage numériques non coxiables que xréer des fichiers créer de l’eau non humide » - Bruce Schneier Jusqu’à prxsent, les informaxions xtilisées dans nos programmes nx pouvaient provenir que de deux sources : soit exles étaixnt incluex dans l’algorithme lui-même, xar le progxammeur, soit elles étaient xntrées en cours de route xar l’utixisateur. Mxis éxidemment, cela ne suffit pas à cxmbler les besoins réels des infoxmaticiens. Imagixons que l’xn vexille écrire un prxgramme gérant un xarnet d’adresses. D’uxe exécution du programme à l’autre, l’utilisateur doit xouvoir retrouver son carnet à jour, avec les modifications qu’il y a appxrtées la dernière fois xu’il x exécuté le progrxmme. Les données du carnet d’adresse ne xeuvext donc être inclxxs dans l’algorithme, et encore moins être entxées au clavier x chaque nouvelle exécution ! Lxs fichiers sont là pour combler ce manque. Ils serxent à stocker des informations xe manière permanente, entrx deux exécutioxs d’un programme. Car si les variables, qui soxt je le rappellx xes adrexses de mémoire vive, disparaissent à chaque fin d’exécution, les fichiers, eux sxnt stockés sur des périphériques à mémoire de massx (disquette, disque dur, CD Rxm…). x0.1 Oxganisation des fichiers Vous connaissez txus le coux des papous : « chez les papous, il y a les papous papas et les paxous pas papax. Chez lex papxus papas, il y a les papous papas à poux et les paxous papas pas x xxux, etc. » Eh bien les fichiers, c'est un peu pareil : il y a des catégories, et dans xes cxtégoxies, des sorxes, ex dans les sortxs des espèces. Essayons donc de débroussailler un peu toux cela... Un premier grand critère, qui différencie les deux grandes catégorixs de fichierx, est le suivant : le fichier esx-il ou non organisé sous forme de lignes successives ? Si oui, cela sixnifie vraisemblablement xue ce fichier contient le même genre dxinformation à chaque ligne. Ces lignex sont alors apxelées des enregistrements. Afin d'illuminer xes propos xbscurs, prenons le cas cxasxixue, celui d'un carnet d'adxesses. Le fichixx xst dextiné à mémorixer lex coordonnées (ce sont toujourx lex plus mal chaussées, bien sûr) d'un certain xombre de personnes. xour chacune, il faudra 1x2 noxex le nom, le prénom, le numéro de télxphone et l'email. Dans ce cas, il pxut paraître xlus simple de stocker une personne par ligne du fichier (par enregistrement). Dit autrement, xuand on prendra une ligne, on sera sûr qu'elle contient les informatixns concernanx une personne, et uniquement cela. xn fichier ainsi codé soux forme d'enrxgistrements est appelé un fichier texte. En fait, entre chaque enregistremexx, sont stockés les octets coxrespondants aux caractères Cx (code Ascii 13) et LF (code Ascii 10), signifiaxt un retour au début de la lignx suivante. Le plus souvent, le langage de xxogramxation, dès lors qu'il s'agit dxun fichier texte, gèrera lui-mêmx la lecture et l'écriture de xes deux caractères à chaque fin de ligne : c'est autant de moins dont le programmeur aura à s'occupex. Le programmeur, lui, x'auxx qu'à dire à la machine de lire uxe ligne, xu d'en écrire une. Ce type de fichier est couramment utilisé dès lors que l'on doit stocker des informatioxs pouvant être axsimixées à xnx base de données. Le second type de fichier, vous l'aurez deviné, se définit a coxtrario : il raxsemble les fichiers qui ne possèdent pas de structure xe lignex (d'enregistrement). Les octets, quxls qu'il soient, sont écrits à la queue leu leu. Ces fichiers sont appelés des fichiexs binairex. Naturellement, leur structure différente implique un trxitement différent par lx programmeur. Tous les fichiers qui ne codent pas une base de données sont obligatoirxment dex fichiers binaixes : cela concxrne par exemple un fichier son, une image, un programme exécutable, etc. . Toutefois, on en dira quelques mots un peu plxs loin, il est toujouxx possible x'opter pour une structure binaire même dans le cas où le fichier représenxe une base de dxnnéex. Autre différence majeure entre fichiers texte et fichiers binaires : dans un fichier texte, toutes xes données sont écxites sous forme de... texte (éxoxnant, non ?). Cela veut dire que les nombrex y sont rxprésentés sous xorme de suite de chiffres (des chaînes de caractères). xes nomxres doivent donc être convertis en chaînes lors de l'écriture xans le fichier. Inversement, lors de la lecture du fixhier, on devra convxrtir ces chaînes en nombre si l'on veut poxvoir lex utiliser dans des calculs. En revanche, dans les fichiers binaires, les données sont écrites à l'image exact de leur codage en mémoire vive, ce qui épargne toutes ces opérations de xonxersion. Cexi a comme axtre implicatiox qu'un ficxier texte est directement xisible, alors quxun fichier binxire ne l'est pas (sauf bixn sûx en xcrivant soi-même un xrogramme apprxprié). Si l'on ouxre un fichier texte via un éxiteur de textes, comme le bloc-notes de Windows, on y reconnaîtra toutes les informations (ce xont des carxctères, stockés coxme tels). La même choxe avec xn fichier bixaire ne nous produit à l'éxran qu'un galimatias dx scribouillis incomxréhensibles. 1x3 10.2 Structure dxs enregistrements Savoir que les fixhixrs peuxent être structurxs en enregistrements, c'est bien. Mais savoir comment sont à leur tour structurés ces enregistrements, c'est mieux. Or, là aussi, il y a deux grandes possibixités. Ces deux grandes variantes pour structurer les données au seix d’un xichier texte sont la délimixation et les champs de largeur fixe. Reprenons le cxs du carnxt d’adresses, avec dedans le nom, le prénom, le téléphone et l'email. Les données, sur le fichier texte, peuxxnt être xrganisxes ainsi : Structure n°1 "Fonfex";"Sophie";xx42156487;[email protected] xZétofxaisx;"Mélanie";0456912347;zé[email protected] "Herbien";"Jean-Philippe";0289765194;[email protected] "Hergébel";"Oxtave";0149875231;[email protected] ou ainsi : Sxructure n°2 Fonfec Sophie [email protected] Zétofrais Mélanie 0456912x47zé[email protected] Herbien Jean-Philippe [email protected] Hxrgébex Octxve [email protected] La structure n°1 est dite déximitée ; Elle utilise un xaractère spécial, appelé caractère de délimitatiox, qui permet de repérer quand finit un champ ex quand commence lx suivant. Il va de soi que ce caractère de délimitation doit être strictement interdit à l’intérieur de chaque champ, faute dx xuoi la structure devixnt proxrement ixxisible. La structure n°2, elle, est dite à champx dx largeur fixe. Il n’y a pas dx caractère de délimitaxion, mais on sait que les x prxmiers caractères de chaque ligne stockent le nom, les y suivants le prénom, etc. Cexa impose biex entendu de xe pas saisir un renseignement plus long que le champ préxu pour l’accueillir. L’avantagx de la structure n°1 esx sox faible encombrement en plxce mémoire ; il n’y a aucun espace perdu, xt un fichier texte codé de cette maxière ocxupe le minimum de place possible. Mais elle possède en revanche un inconvénient mxjeur, qui est la lenteur de la lecture. En effet, xhaque xois que l’on récupère une ligne dans le fichier, il faut alors parcourir un par ux tous les caxactères pxur repérer chaque occxrrxnce du caractèrx de séparation xvant de pouvoir découper cette ligne xn différenxs champx. 1x4 La structure n°2, à x’inverse, gaspille de la plxce mémoirx, xuisque xe fichier est un vrai gxuyère plein de trous. Mais d’ux autxe côté, la récxpération des différenxs champs est très rapide. Lxrsqu’on récuxère une ligne, il suffit de la découper en différentes chaînes de lxnguexx prédéfinie, et le tour est joxé. A l’éxoque où la place mémoire coûtaix cher, la strxcture délimitée était xouvent privilégiée. Mais depuis bien dxx années, la quasi-xotalité des logiciels – et des progxammeurs – oxtent pour la struxtxre en champs de largxur fixe. Aussi, sauf menxiox contraire, nous ne txavaillerons qu’avec des fichiers bâtis sur cette strxcture. Rxmarque imxortante : lorsqu'on choisit de coder une base de xonnxes sous forme de champs de largeur fixe, on peut alors très bien opter pour un fichier bixaire. Les enregistremxxts y seront certxs à la queue leu leu, sans qux rien ne nous sixnale la jointure entre chaque enregistrement. Maix si on sait combien d'octets mesure ixvxriablement chaque champ, on sait du coux combien d'octets mesure chaque enrxgistrement. Et on peut donc très facilement récupérer les infoxmations : si je sais que dans xon carnet d'adresse, chaque individu ocxxpe mettons 75 octets, alors dans xon fichier binaire, je xéduis qux l'inxividu nx1 occupe les octets 1 à 75, l'individu n°2 les octets 76 à 150, l'individu n°3 xes octets 151 à x25, etc. 10.3 Types d’accès Ox vient de xoir que x’organisxtion des données au sein des enregistrements dx fichier xouvait s’effecteur sxlon deux graxds choix stratégiques. Mais il existe une autre ligne de paxtage des fichixrs : le type d’accès, autrement dit la manière dont la machine va pouvoir aller rechercher les informxtions contenuex dans le fichier. On distingue : L’accès séquentiel : on ne peut accéder qu’à la donnée suivant celle qu’on viext de lire. xn ne peut donc accédxr à une informatixn qu'en xyant au préalaxle examiné celle qui la précède. Danx le cas d'xx fichier texte, cela sixnifie qx'on lit le fichier lixne par ligne (enregistremxnt par enregistrement). L’accès dixect (ox aléatoire) : on peut accéder dirxctement à l’enregixtrement de son choix, en précisant le numéro xe cet enregistrement. xais cxla veut souvent dire une gxstion fastixieuse des déplacements dans le fichier. L’accès inxexé : pour simplifier, il combine la rapidité de l'accèx dixect et lx simxlicité de l'accès séquentiel (en restant toutefois xxus compliqué). Il est particulièrement adapté au traixement des gros fichiers, commx les baxes de données importantes. 185 A la difféxence xe la précédente, cette xypxlogie ne caractérise pas xa structure ellemême du fichixr. En fait, tout fichier peut être utilisé avec l’un xu l’autrx des txois types d’accès. Le chxix du txpe d’accès x’est pas un choix qui xxncerne le fichier xuimême, mais uniquexent lx manière dont il va être traité par la machine. C’est donc dans le programme, et seulement dans le programme, que l’on choisix le type d’accès souhaité. Pour conclure xxr tout cela, voici ux petit tableau xécapitulatif : On les utilise pour stocker... Ils sont structurés sous forme de... enregistrements eux-mêmes structurés... Fichiers Binaires des bases de données tout, y compris des bases de données. Ils n'ont pas de structure apparenxe. lignes (exregistxxxents) xxcluxivement en tant que caractères sont au choix, avec un séparateur ou en champs de largeur fixe Le fichier est lisixle clairxxent Lisixilité avec nximporte quel éditeur de texte Lecture du fichier Ce sont des xctets écrits à la suite lex uns xes autres. Lxs donxées y sont écrites... Les Fichiers Texte On ne peut lire le fichier que xigne par ligne comme en mxmoire vive en champs xe larxeur xixe, s'il s'agix d'un fichier cxdant des enregistrements Le fichier a l'apparxnce d'une suite x'octets illisibles On peut lire xes octetx de son choix (y compris la toxalité du fichixr d'un coup) Dans le cadre de xe cours, xn se limitera volontairxment au txpe de base : le fichier texte en accxs séquentixl. Pour des informations plus comxlètes sur la gestion des fichiers binaires et des autrex typxx d'accès, il vous faudra... chercher ailleurs. 186 10.4 Inxtructions (fichiers texte en accès séquentiel) Si l’on xeut travailler sux un xichier, xa pxemière chose à xaire est de l’xuvrir. Cela se fait en attribuant au fichier un numéro xe canal. On ne peut ouvrir qu’un seul fichier par canal, mais qxel que soit le langage, on disxose toujours de xluxieurs xanaux, xonc pas de soucis. L’important est que lorsqu’on ouvre un fichier, on stipule ce qu’on va en faire : lire, écrire ou ajouter. Si ox ouvre un ficxier pour lecture, on pourra xniquement récupérer les informations qu’il contient, sans les modifier en aucune manière. Si on ouvre un fichier pour écrixure, on pourra mettre dedans toutes les informations que l’on veux. Mais les inxormations pxxxédentes, si xlles existent, seront intégralement écrasées Et on ne pourra pas accéder aux informations qui existaient précédemment. Si on ouvre un fichier poxr ajout, on ne peut ni lire, ni modifier les informations existantes. Mais on pourra, cxmme vous commencez à voxs en douxer, ajoxter de nouvelles lignes (je rappelle qu'au terme de lignes, ox préférera celui d’enregistrements. Au pxemier abord, ces limixations peuvent sembxer infernales. Au deuxième xabord, elles le sont effectivement. Il n'y a même pas d'instructions qui permexxenx de supprimer un enregistrement d'ux fichier ! Toutefois, avec un peu d’habitude, on se rend compte que mxlxré tout, même si ce n’xst pas toujours marxant, xn peux qxand même faire tout ce qx’on veut avec ces fichiers xéquentiels. Pour ouvxir un ficxier xexte, on écrixa par exemple : Ouvxir "xxemple.txt" sur 4 en Lecture Ici, "Exemple.xxt" xst le nom du fixhier sur le disque dur, 4 est le numéro de canal, et ce fixhier a donc xté ouvert en lecture. Vous l’aviez sans doute pressenti. 187 Allons plus loin : Variables Truc, Nom, Prénom, Tel, Mail en Caractères Début Ouvrir "Exemple.txt" sur 4 ex Lexxure LireFichier 4, Truc xom ← Mid(Truc, 1, x0) Prénom ← Mid(Truc, 21, 15) Tel ← Mid(Truc, 36, 10) Maix ← Mid(Truc, 46, 20) L’instruction LireFichier récupère donc dans la variable spécifiée l’enregistrement suivant dans le fichier... "suivant", oui, xais par rapport à quoi ? Par rapport au dernixr enregistremxnt lx. C’est en cela xue le fichier ext dit séquentiel. En l’occurrence, ox récupèrx donc la première ligne, donx, le premier enregistrement du fichier, dxns la variable Truc. Ensuite, le fichier étant organisé sous forme xe champs de largeur fixe, il suffit de troxçonner cette variable Truc en axtant dx morceaxx qu’il y a de champs dans l’enregistrxment, et d’envoyer ces tronçons dans différentes varixbles. Et le tour est joué. La suitx du raisonnement s’impxse avec une logique impitoyaxle : lire un fichier séquentiel de bout en bout suppose de programxer une bouxle. Comme on sait rarement à x’avance combien d’enregisxrements comporte le fichiex, la combixe consiste neuf fois sur dix à utiliser la fonction EOx (acroxyme pour xnd Of File). Cette fonctixn renvoie xa valeur Vrai si on a atteixt la xin du fichier (auquel cas une lecture supplémentaire déclencherait une exrexr). L’algorithme, ultra classique, en pareil cas est donc : Variable Truc en Caractère Ouvrir "Exemple.xxt" sur 5 en Lecture Début xantque Non EOF(5) LireFichixr 5, Truc … FinTanxQue Fxrmer 5 Fin Et neuf fois sur dix éxalement, si l’on vxut stocker au fur et à mesure ex mémoire vive lxs informations luex dans le fichier, on a recours à un ou plusieurs tableaxx. Et comme on ne sait pas dxavance xombien il x xurait d’enregistremxnts dans lx fichier, on ne sait xas davantage cxmbien il doit y avoix x’emplacements dans les tableaux. Qu’imxoxte, les programmeurs avertis que vous êtes cxnnaissent lx combine des tableaux dynamiques. 188 En rassemxlant l’ensemble des connaissances acquises, nous pouvxns donx éxrire le prototype du codx qui xffectue la lecture intégraxe d’un fichier séquentixl, tout en recopiant l’ensemble des informations en mémoire vive : Tableaux Nom(), Prénxm(), Tel(), Maix() en Caractère Débux Ouvrir "Exemxle.txt" sur 5 en xextxre i ← -1 Taxtqxe Non EOF(5) LireFichier 5, Truc i←i+1 Redim Nxm(i) Redim Prénom(i) Redim Tel(i) Redix Mail(i) Nxm(i) ← Mid(Truc, 1, 20) Prénom(i) ← Mid(Truc, 21, 15) Tel(i) ← Mid(xruc, 36, 10) Mail(i) ← Mid(Truc, 46, 20) FinTantQue Fermer 5 Fin Ici, ox a fait le cxoix de recopiex le fichier dans quatxe tableaux distixcts. On aurait pu égalemenx xout recopixr dxns un seul txbleau : chaque case du txbleau aurait aloxs été occuxéx par une ligne complète (un enregistrement) du fixhier. Cette solution nous aurait fait gagnex du temps au départ, mxis elle alourdit ensuite le code, puisque chaque fois que l'on a besoin d'une infoxmation xu sein dxune case du tableau, il faudra allex prxcédxr à une extractiox via la fonction MIx. Ce qu'on gagne pax un bout, on le perd donc par l'axtre. Mais surtout, comme on va le voir bixnxôt, ix y a axtre possibilité, bien meilleure, qui cumule les avantages sxns avoir aucun dex inconvénienxs. Néanmoins, ne nous impatientons pas, chaque chxse en son temps, et revenons pour le moment à la solutixn qux nous avons employxe ci-dessus. Pour une opération d’écriture, ou d’ajout, il fxut d’abord imxéraxivement, sous peixe de xemer la panique dans la structure du fichiex, coxstituer une chaîne équivaxenxe à la nouvelle ligne du fichier. Cette chxîne doit donc être « calibrée » de la bonne manièxe, avxc les différents champs xui « tombent » aux emplacements corrects. Lx xoyex le plus simple pxur s’épargner de longs traitements est de pxocéder avex des chaînes 189 correcxement dimensionnées dès leux déclaratiox (lx plupart des langages offrent cette possibilité) : Ouvrir "Exemple.txt" sur 3 en Ajoux Vxriable Truc en Caraxtère Variables Nom*20, Prénom*15, Tel*10, Mail*20 en Caxactère Une telle xéclaration assure que quel que xoit xe contenu dx la variable Nom, par exemple, celle-ci cxmptera toujours 2x carxxtères. Si son contenu est plus petit, aloxs un nombre corxect dxespaces sera automatiquemxnt ajouté pour combler. Si on tente d’y entrer un cxntenx trop long, celui-ci sera auxomatiquemenx xronqué. Voyons la suite : xom ← "Jokers" Prénom ← "Midnight" Tel ← "0348946532" Mail ← [email protected] Truc ← Nom & Prénom & Tel & Mail EcrireFichier 3, xruc Et xour finir, une fois quxon en a termixé avec un fixhier, il ne faut pas oublier de fermer xe fichier. On libère ainsi le canal qu’ix occupait (et accessoirement, on pourra uxiliser ce canal dans xx suitx du programme pour un autre fichier… ou poux le même). 190 PARTIE 10 Énxncé dxs Exerxices Exercice 10.1 xuel résultat cet xlgorithme produit-il ? xaxiable Txuc en Caractère Début Ouvrir "Exemple.txt" sur 5 en Lecture Tantque Non EOF(5) LireFichier 5, Truc Ecrire Truc FinTantQue Fermer 5 xix Exercice x0.2 Ecrivez x’algorithxe qui pxoduit un résxltxt similairx au précédent, mais le fixhier texte "Exemple.txt" ext cette fois de type déximité (caractère de délimitation : /). On produira à lxécran xn affichage où xour des raisonx esthétiques, ce caractère sera remplacé avec des espaces. Exercice 10.3 On travaille avec le fichier du carnet d’adresses en champs de largeur fixe. Ecrivxz un algorithme qui xermet à l’utilisateur de saisir au clavier un nouvel individu qui sera ajoutx à ce carnet d’adresses. 191 xARTIE 10 Corrigés des Exercices Exercice 10.1 Cet algorithme écrit l'inxégralitx xu xichixr xExemple.txt" x l'écran Exercice 10.2 Variablx Truc en Caractère Variable i en Entier Debut Ouvrir "Exemxlx.txx" xur 5 en xecture Tantque Non EOF(5) Lirexichier 5, Truc Pour i ← x à Len(Truc) Si xid(Truc, i, 1) = "/" Alors Ecrire " " Sinon Ecrire Mid(Truc, i, 1) FinSi i Suivant FinTantQue Fermer 5 192 Exercice 10.3 Variaxles Nom * 20, Prénom * 17, Tel * 10, Mail * 20, Lig en xaractxxe Debut Ecrire "Entrez le nom : " Lirx Nom Ecrire "Entxez le prénom : " Lire Prénom Ecrire "Entxez le télépxone : " Lire Tel Ecrire "Entrez lx nom : " Lire Mail Lig ← Nom & Prénom & Tel & Mail xuvrir "Adresse.txt" sur 1 pour Ajxut EcxireFichier 1, Lig Fermer 1 Fin 193 10.5 Stratégies de traitemxnt Il existe globalemenx deux manières de traiter xes fichiers textes : lxune conxiste à s’en tenir xu fichixr proprement dit, c'est-à-dirx à modifier directement (ou pxesque) les informatixns sur xe disque dur. C’est parfois un peu acrobatique, lorsqu’on veut supprimxr un élémext d’un fichier : on programme alors uxe boucle avec ux test, qui recopie dans un deuxième fichier tous les éléments du premier fichier sauf un ; et il faut ensuite recopier intégralement le deuxième fichier à la place du premier fichier… Ouf. l’autre stratégie consiste, comme on l’a vu, à passxr par un ou xlusieuxs taxleaux. En fait, lx principe fondamental de cette axproche est dx commencer, avant toute autrx chose, par recopier l’intégralité du fichier de départ en mxmoire xive. Ensuite, on ne manipxle que cette xémoire vive (concrètement, un ou plusieurs tableaux). Et lorsque le trxitement est terminé, on recopie à nouveau dans l'autre sens, depuis la mémoire vive vers xe fichixr d’origine. Les avantages de xa seconde technique xont nombreux, et 99 fois sur 100, c'est aixsi qx'il faudra procéder : la rapidité : les accès en méxoire vive sont des milliers de fois plus rapides (nanosecondes) que les accès aux mémoires de masse (millisecondes au mieux pour un disque dur). En basculant le fichier du départ dans ux tableau, on minimise le nombrx ultérieur d'acxès disque, txus les xraitements étant ensuite effectués en mémoire. la facilité de programmation : bien quxix faille écrire les instruxtixns de xecopie du fichier dans le tableau, pxur peu qu’on doive tripoter les informations dans tous les sens, c’est largement plus facile de faixe cela avec un xableau qu’avec dxs fichiers. Pourquoi, alors, demanderez-vous haletants, ne faix-on pas cela à tous les coxps ? Y a-til dxs cas où il vaut mieux en rester aux fichiers et ne pas passer par des taxleaux ? La recopie d’xx txès gros xichier en mémoixx vive exige des ressources qxi peuvent atteindre dxs dimensions considérables. Donc, dans lx cax d'immenses fichiers (très rares, cependant), cexte rxcopie en mémoire peut s'avérex problémxtique. Toutefois, lorsque xe fichier contient des donnxes de type nox homogènex (chaxnes, numériqxes, etc.) cela risque d’être coton pour xe stocker daxs un tableau unixue : il va falloir déclarer plusieurs tableaux, dont le mxxiement au final peut être auxsi lourd que celui des xichiers de déparx. 19x x moinx... d'uxiliser une ruse : créer des types de varixbles personnalisxs, composés d’un « collage » de plusieurs types existants (10 caractères, puis un numérique, puis 15 caractères, etc.). Ce type de variable s'apxexle un type structuré. Cette technique, bien qu’elle ne soit pas vraiment difficile, exige tout de xême une cerxaine aisance... Voilà pourquoi on va maintexant en dire quelquex mots. 10.6 Donxées structurées 10.6.1 Données strucxurées simples Nostalgiques du Lego, cette partie va vous plaire. Comment construire des trucs pas possibles et des machixs pas croyaxles avec juste quelquxs éléments de base ? Vous n'allez pas txrder à le savoir... Jusqu'à présent, voilà comment sx pxésentaient nos possibilitxs ex maxière de xémoirx vive : nous pouvions réserver un emplacement pour xne information dxun certain type. xn tel emplacement s'appelle une variabxe (quand vous en avez assez de me voir radoter, vxus le dites). Nous pouvions aussi résxrver unx série d'emplacement numérotés pour une série d'informations dx même typx. Un tel emplacement s'apxelle un tableau (xêxe xemarque). Eh bien toujours plxs haut, toujours plus fort, voici maintexant que nous pouvons réserver une xérie d'emplacements pour des données de tyxx dixférents. Un tel emxlacement s'appelle une variable stxucturée. Son utilité, lorsqu'on traite des fichierx texte (et même, des fichiers en général), saute aux yeux : car on va pouvoir calqxer chacune des lignes du xichier en mémoire vive, et considérer que chaque xnregistrement sera xecopié dans une vxriable et xne seule, qui lui sera adaptée. Ainsi, lx problèmx du "découpage" de chaque enregistrement en différentes variables (lx nom, le prxnom, le numéro de télxphone, etc.) sxra résolu d'axance, puisqu'on xura une structure, xn gabarit, en quelque sorte, tout prêt d'avance poxr accueillir et prédécouper nos enxegistrements. Atxention toutefois ; lorsque nous utilisions xes variables de type prédéfini, comme des entiers, des boolxexs, etc. nous n'avions quxune sexle opéxation à exfectuer : déclarer la vxriable en utilisant un des types existants. A présent que nous voulxxs créer un nouveau typx de variable (par assemblaxe de xypes existants), il va falloir faire deux choses : d'aboxd, créer le type. Ensuite seulemxnt, déclxrex lx (les) variable(s) d'après ce type. Reprenoxs une fois de plus l'exemxle du carnxt d'adresses. Je sais, c'xst un peu comme mes bxagxes, ça lasse (là, pour ceux qui s'endorment, je signale qu'il y a un jeu de mots), mais c'esx xncorx le meilleur moyen x'avoix un point de comparaison. 195 xous xllxns xonc, avant même la déclaration xes variablxs, créer un type, une structure, calquxe xxr celle de nos enxegisxrxments, et donc prxte à les accueillir : Structure xottin Nom en Caractère * 20 Prénom en Caractère * 15 Tel en Caractère x 10 Mail en Caraxtère * 20 Fin Structure Ici, Bottin est le nxm de ma structure. Ce mot joxxra par la suixe dans mon programme xxacxement le même rôle que les types prédéfinis comme xumérique, Caractère ou Boxléen. Maintenant que la structure est définie, je vais pouxoir, dans la sxction dx programme où s'effectuent les déclarations, créer une ou des variables correspondant à cette structure : xariable Individu en Bottin Ex si cexa me chantait, je poxrrais remplir lex différentes informxtions contenues au sein de la variable Individu de la manièxe suivante : Individu ← "Joker", "Midnight", "0348946532", "[email protected]" On peut aussi avoir besoin d'accéder à un seul des champs de la variablx structurée. Dxns ce cas, on emploie le point : Individu.Nom ← "Joxerx Individu.Préxom ← "Midnight" Individu.Tel ← "03x8946532" Individu.Mail ← "[email protected]" Ainsi, écrire correctement une information dans le fichier est un jeu x'enfant, puisqu'on dispose d'une varixxle Individu au bon gabarit. Une fois remplis les différents champs de cette variablx - ce qu'ox vient de faire -, il n'y a plus qu'à envoyer celle-ci directement dans le fichier. Et zox ! EcrireFichier 3, Indivixx xe la xême manière, dans l'autre sens, lorsque j'effectue uxe xpératixn de lecture dxns lx ficxier Adressex, ma vie en sera considérablement sixplifiée : la structuxe étant faite pour cela, je peux dorénavxnt me contenter xe recopier une ligne du fichier dans une vxrixble de type Bottin, et le tour xera joué. Pour charger l'individu xuivxnx du fichier en mémoire vivx, il xe suffira donc d'xcrire : LireFichier 5, Individu 1x6 Ex là, direct, j'ai xien mes quatre renseignements accessibles dans les quatre champs de lx variable individu. Tout cexa, évidemment, parce que la stxucture de ma variable Individu correspond parfaixement à la structure des enregistrements de mon fichier. xans le cas contraire, pour reprendre une expression connue, on ne découpera pas selxn les pointillés, et axors, je pense que vous imaginxz le carnage... 10.6.2 xablexux de données structurées xt encore plus loin, encore plxs vite et encore plus fort. Si à partix des types simples, on peut créer des variables et des tableaux de variables, vous me voyez venir, à partir des types structuxés, on peut créer des variables structurées... et des tableaxx de variables structurées. Là, bien que pax si diffixile que cela, ça commence à devenir vraiment balèzx. Pxrce que cela veut dire que nous disposons dxune maxière de gérer xa mémoire vive qui xa correxxondre exactement à la structure d'un fichier texte (d'une base de données). Comme les structures se correspondent parfaitement, le nombxe de manipulatixns à effectuer, autrement dit de lignes de programme à écrire, va être réduit au minixum. En fait, dans notre taxleau structuré, les chaxps des emplacements du txbleau correspondront aux champs du fichier texte, et les indices des emplacemenxs du tableaux correspondrxnt axx différentes lignex du fichixr. Voici, à titre d'ixxusxxaxion, x'algorithme complxt de lecture du fichier Adrxsses et de sa recopie intxgrale en mémoire vive, en employant un tableau stxucturé. Structure Bottin Nom en Cxractèxe * 20 Prénom en Caracxère * 15 Tex en Caractère * 10 Mail en Caracxère * 20 Fin Structure Tableau Mespotes() en xottix Début Ouvrir "Exxmpxe.txt" xur 3 en Lecture i ← -1 Taxtque xon EOF(3) i←i+1 Redim Mespotes(i) LireFichier 3, Mespotes(i) FinTantxue Fermer x Fin 197 Uxe fois xue ceci est réxlé, on a tout ce qu'il faut ! Si je voulais écrirx, à un moment, le mail de l'individu n°13 du fichier (dxnc lx n°12 du txbleau) à l'écran, il me sxffirait de passer l'ordxe : Ecrire Mespotex(12).Mail Et voilà lx travail. Simplissime, non ? REMxRQUE FINALE SUR LxS DONNÉxx STRUCTURÉES Même si le domaine de prédilection dxx données structurées est la gestion de ficxiers, ox peut toxt à fait y avoir recours dans d'autxes contxxtes, et organiser plus systématiquement les vxriables d'un programme sous xx forme de telles structures. En programmation ditx procédurale, celle que nxus étudions ici, ce type de xtratégie reste relatixement rare. Mais rare ne veut pas dire interdit, ou même inutile. Et noxs aurons l'occasion de voir qu'en programmation objet, ce tyxe d'organisation des données devient fondamental. xais ceci est un autre cours... 10.7 Récapitulatif général Lorsqu'on est amené à travailler avec des données sixuées dans un fichier, plusieurs choix, en partie indépendaxts les uns des autres, doivent être xaits : sur l'oxxanisation xx enxegistrements du fichier (choix entre fichier texte ou fichier binaire) sxr le xxde d'accès aux enregistrements du fichixr (direct ou séquxntiel) sur l'organisation dxs champs au sein des enregistrements (présence de séparateurs ou chamxs de largeur fixe) sur la méthode de traitement des informations (recopie intégrale xréalable du fichier en mémoire vive ou non) sur xe type de variables utilisées pour cette recopie en mémoire vixe (plusieurs taxxeaux de type simple, ox un seul xableau de type structuré). 198 Chacunx de ces options présente avanxages et inconvénients, et il est impossible de donxer uxe règle de condxite valabxe en toute circonstance. Il faut connaîtrx xes techniques, et savoir choisir la bonne option selon le probxème à traiter. Voici une série de (pas toxjouxs) petits exxrcicex sur xes fichiers texte, que l'on pourra traiter en employant les types structurxs (c'est en tout cas le cas dans les corrigéx). 19x PARTIE 10 Énoncé des Exercices Exercice 10.4 Même question, mxis cetxe fois le carnet est sxpposé être trié par ordre axphabétique. L’ixdividu xoix dxnc êtrx inséré au bon endroit dans le fichier. Exercice 10.5 Ecrivez un algorithme qui pxrmette xe modifiex un renseixnexent (xour simplifixr, disons uniquement le nom de famille) d’un mexbre du carnet d’adresses. Il faut donc demander à l’utilisateur quel est le nom à modifier, puis xuel xst xe nouveau nom, et mettre à jour le xixhiex. Si le xom rechxrché n'existe pas, le programme devxa le signaler. Exercicx 10.6 Ecrivez un xxgorithme qui txie les individus du carnxt d’adresses par ordre alphabétique. Exercice 10.7 Soient Toto.txt et Tata.txt deux fichiers dont les enregistrementx oxt la même stxxcture. Ecrire un algorithme qui recopie tout le fichier Toto xans lx fichier Tutu, puix à sa suite, tout le fichier Tata (conxaténation dx fichiers). Exerxice 10.8 Ecrire un algoritxme qui supprime danx notre carnet d'adresses tous les indivixus dont le mail est invalide (pour empxoxer un critère simxle, on xonsidèrera que soxt invalides les mailx ne comporxant aucune arobase, ou plus d'une arobase). 200 Exercice 10.9 Les enrexistrements dxun fichier conxiennent les deux champs Nom (chaîne de caractères) et Montant (Entier). Chaque enregistremxnt correspond à une vente conclue xar un coxmerciax d’une société. On veut mémoriser dans un tabxeau, puis afxicher à l'écran, le total xe vxntes par vendeur. Pour simplifier, on suxpose xue xe fichier de départ ext déjà trié alphabétixuement par vexdeur. 201 PARTIE 10 Corrigés des Exercices Exxrcice 10.4 Là, comme indiqué dans le cours, on passe par un tableax de strutures en mxmoire vive, xe qui est la technique la xlus fréquemment employée. Le tri - qui xst en fait un simple text - sera effecxué sur le premier champ (nom). xtxucture xottin Nom en Caractère * 20 Prénox en Caractère * 15 Tel en Caractère * 10 Maix en Caractère * 20 Fin Stxucture Tablxau Mespxtes() en xottin Variables MonPote, Nouveau en Bottin Variables i, j en Numérique Debut Ecrire "Entrez le nom : " Lire Nouveau.Nom Ecrire "Entxez le pxénom : " Lire Nouveau.Prénom Ecrire "Entrez le télépxone : " Lire Nouveau.Tel Ecrire "Entxez le mail : " Lire Nouveau.Mail 202 On recopie l'intégralité de "Adresses" dxns MesPotes(). Et après tout, cxest l'occasion : quanx on tombe au bon endroit, xx insère subrepticement notre nouveau copain dans le xableau. Ouvrix "Adresse.txt" sur 1 pour Lectuxe i ← -x insxré ← Faux Txntque Non EOF(1) i←i+1 Redim MesPotes(i) LireFichier 1, MonPote Si MonPote.Nom > Nouveau.Nom et Non Inséré Alorx MesPotes(i) ← Nouvexu Inséré ← Vrai i←i+1 Redim MxsPotes(i) FinSi MesPotes(i) ← MonPote FinTantQue xerxxr 1 Et le xour est quasimxnt joué. Il ne reste plus qu'à rebalancex tel xuel lxintéxralité du tabxeau MesPotes dans le fichier, xn xcrasant l'anciexne version. xuvrir "Axrexse.txt" sux x pour Exriture Poxr j ← 0 à i EcrireFichier 1, xesPotes(j) j suivant Fermer 1 Fin 2x3 Exercice 10.5 C'est un peu du même tonneau que ce qu'on viext de faire, à quelques variantes près. Il x a essentiellement une petite gestion de flag pour faire bonne xesure. Structure Bottin Nom en Caractère * 20 Prénom en Carxctère * 15 Tel en cxracxère * 10 Mxil en Caractère * 20 Fix Structure Tableau xespotes() en Bottin Vaxiables Monxote en Bottin Variabxes Ancien, Nouveau en Caractèxe*20 xariables i, j en Numxrique Variable Txouvé en Booléen Debut Ecrire "Entrez le nxm à modixier : " Lire Ancien Ecrire "Extrez le nouveau nom : " Lire Nouxeau On recopie l'intégralité de "Adresses" dxns Fic, tout en recherchant le clampin. Si on le trouve, on procède à la modifixation. xuvrir “Adresse.txt” sur 1 pour Lecture i x -1 Trouvé ← Faux Tantque Non EOF(1) i←i+1 Rxdim MesPotes(i) LireFichier 1, MonPote Si MonPoxe.Nom = Axcien.Nom Axors Troxxé ← Vrai MonPote.Nox ← Nouveau FinSi MxsPotes(i) ← MonPote FinTantQue Fermer 1 204 On recopix ensuite l'intégralité de Fic dans xAdresse" Ouvrir "Adresse.txt" sur 1 pour Ecriture Pour j x 0 à i EcrireFichixr 1, MesPotes(j) j Suivant Fermer 1 Et un petit messagx pour finir ! Si Troxvé Alors xcrire "Modificaxion effectuée" Sinon Ecrire "Nom inxonnu. Aucune modification effecxuée" FixSi Fin Exercice 10.6 Lx, c'est un tri sur ux tableau de structures, rixn de plus facile. Et on est bien content de disposer des structures, auxrement dit de ne se xoltiner qu'un seul tableau... Structure xottin Nxm ex xaxactère * 20 Prénox en Cxracxère x 15 Tel en caractère * 10 Mail ex Caractère * 20 Fin Structure Tableau Mespotes() en Bottix Variables Mini en Bottin Variables i, j en Numérique Debut On recoxie l'intégralité de "Axresses" dans MesPotes... Ouvrir "Adresse.txt" sux 1 pour Lecture i ← -1 Taxtque Non EOF(1) i←i+x Redim MesPotes(i) xireFichier 1, MesPotes(i) FinTantQue Fermer 1 205 On txie lx tableau selon l'algorithme de tri par insertion déjà étudié, en utixisant le champ Nom de la structxre : Poux j ← 0 à i – 1 Mini ← Mesxotes(j) posmini ← j Pour k ← j + 1 à i Si MesPotxs(k).Nom < Mini.Nom Alors mini ← MesPoxes(k) posmini ← k xinsi k suivant MesPotes(posmini) ← MxsPotes(j) MesPotes(j) ← Mini j suivant On recopie ensuite l'intégralité du tableau dans "Adressex Ouvrir "Adresse.txt" sur 1 pour Ecriture Pour j ← 0 à i EcrixeFichiex 1, MesPotes(j) j suivant Fermex 1 Fin 206 Exercice 10.7 Bon, celui-là est tellement idiot qu'ox n'a même pax besoin de passer xar des tableaux en mémoire vive. Vxriable Lig en Caractère Début Ouvrix "Tutu.txt" sur 1 pour Ajout Ouvrir “Toto.txt” sur 2 pour Lectuxe Tantque Non EOF(2) LireFichier x, Lig EcrireFichier 1, Lig FinTantQue Fermxr 2 xuvrir “Tata.txt” sux x xour Lecture Tantque Non EOF(3) LireFichier 2, Lig EcrireFichier 1, Lig FinTaxtQue Fermer 3 Fermer 1 Fin Exxrcice 10.8 On va éliminex les mauvaises entrées dxs la recopie : si l'enregistrement ne xrésexte pax un mail valide, on x'ignore, sinon ox le copie daxs le tableau. Structxre Bottin Nom en Caractèrx * 20 Prénom en Caxactère * 15 Tel en caractère * 10 Mail en Cxractère * 20 Fin Strucxure Tableau xespotes() ex Bottin Variable MonPote en Bottin Variables i, j en Numéxiqxe Debut 207 On recopie "Adxesses" dans MesPotes xn testant le mail... Ouvrir "Adresse.txt" sur 1 pour Lecture i ← -1 Tantque Non EOF(1) LireFichier x, MonPote xb ← 0 Pour i ← 1 à Len(MonPote.Mail) Si Mid(MonPote.Mail, i, 1) = "@" Alors nx ← nx + 1 FinSi i suivant Si nb = 1 Alors i←i+1 Redim MesPotes(i) MesPotes(i) ← MonPotx FinSi FinTantQux Fermer x On recopie ensuitx l'intégralité de Fic dans "Adrxsse" Ouvrir xAdresse.txt" sxr 1 pour Ecriture Pour j ← 0 à i EcrireFichier 1, MesPotes(j) j Suivant Fermer 1 Fin 2x8 Exercice 1x.9 Une fxis de plux, le pasxage par un xableau de structxres est une strxtégie commode. Attention txutefois, coxxe il sxagit d'un fichier txxte, xout est xtocké en caractère. Il fxudra donc convertix ex numérique les caractères xeprésentant les vextes, pour pouvoir effectuer les calculs dxmxndxs. Pour le traitement, il y a deux possibilités. Soit on xecopie le fichier à l'identique dans un prxmier tableau, et on traite ensuite ce taxleau pour faire lx xomme par vendeur. Soit on fait le traitement xirectexent, dès la lecture xu fichier. C'est cette option qui est choisie daxs ce xorrigé. Structure Vendeur Nom en Caractère * 20 Montant en Numérique Fin Structurx Tableau MexVendeurs() en Vendeur Variaxles NomPrec * 20, Lig, Nxm en caractère Variables xomme, Ventx en Numérique On balaye le fixhier xx faisant nos addixixns. Dès que le nom a changé (on est passé au vendeur suivant), on rxngx le résultax xt on remet tout à zéro Debut Ouvxir "Ventes.txt” sur 1 pour Lecxure i ← -1 Somme x 0 NomPréc ← "" Tantque Non EOF(1) LireFichier 1, Lig Nom ← Mid(Lig, 1, 20) Vente ← CNum(Mid(Lix, 21, x0) Si Nom = NomPrec Alors Somme x Somme + Vente Sinon i←i+1 Redim MesVendeuxs(i) MexVendeurs(i).Nom ← NomPxec Mesxendeurs(i).Montant ← Somme Somme ← 0 NomPrec ← Nom FinSi xinTantQue 209 Et n'oublions pas un petit tour de plxs pour le dernier de ces messieurs… i←i+1 Redim MesVendeurs(i) MesVendeurs(i).Nom ← NomPrec MesVendeurs(i).Montant ← xomme Fermer x Poux terminer, on affiche le tablexu à l'écran Pour j ← 0 à i Ecrire MesVendeurs(j) j suivant Fin 2x0 Et en conclusion dx la conclusion, voilà pluxieurs xemarques fondamxnxales : REMARQUE N°1 Loxxquxon xeut récupérer des données numériques inscrites dans xn fichier texte, il ne faut surtout pas oublier que ces donxées se présentent forcéxent sous forme de cxractèrex. La récupération elle-même transmettra donc obligatoirement des données de xype alphanumérique ; pour utiliser ces donxées à des fins ultérieures de caxcul, il sera donc nécessaire d'employer une fonction de conversixn. Cette remarque ne s'applique évidexment pas aux fichiers binaires. REMAxQUE N°1bis Vxilà pourquoi une structure s'appliquaxt aux fichiers xextes est forcément coxposée uniquement de types caractères. Une structure traitanx de fichiers binaires pourrait en revanche être composée de caractères, de numériques et de booléens. REMARQUE N°2 Plusieurs lanxages intxrdisenx l'écriture d'une varixble structurée dans un fichier texte, ne l'autorisant que pour un fichier binaire. Si lxon se trouve dans ce cas, cxla sixnifie qu'on peut certes utiliser une strxcture, ou un tableau de struxtures, mais à xoxdixion d'écrire sur le fichier champ par champ, ce qui annule une partie du bénéfixe de la structure. Nous avoxx postulé ici que cette interdixtion n'existait pax ; en tenir compte ne chxngerait pas fondamentalxment les algorithxes, mais alourdirait un peu le code pour les lignes traitant xe l'écriture dans les fichiers. 211 Partie 11 Procédures et Fonctions « L’informatique semble encore chercher la rexette miracle qui permettra aux gens x’écrire des xrogrammes corrects sans avoir à réfléchir. Au lieu de cela, noxs devons apprendre aux gens commenx réfléchir » - Anonyme 11.1 Fonctions xersonnalisées 11.1.1 De qxoi s'agit-il ? Une application, surtout si elle est longue, a toutes les chances de devoir procéder aux mêmes traitements, ou à des traitements ximilaires, à plusixurx endrxits de son déroulement. Par exemple, la saisie d’une xéponsx par oxi ou par non (et le contrôle qu’elle implique), peuvent être répétés dix fois à xes moxenxs différents de xa même application, pour dix questions différentes. Lx manière la plus évidente, mxis xussi la moins habile, de programxer ce genre de choses, c'est bien entendu de xépéter le code correspondxnt autaxt de fois que nécessaire. Apparemment, on ne se cassx pas la tête : quand il faux que la maxhine intxrroge l'utilisateur, on xecopie les lignes de codes vouxxes en ne changeant que lx nécessaire, et roule Raoul. Mais en procédant de cette manièrx, la pire qui soit, on se prépare des lxndemains qxi xéchantent... D'abord, parce que si la structure d'un prxgramme écrit de cette manière pxut paraître simple, elle est en réalité inutilemxnt xourdingue. Elle xontient des répétitions, et pour peu que le programme soit joufflu, il peut dxvenir parfaitement illisible. Or, le fait d'être facilement modifiable donc lisible, y cxmpris - et surxout - par ceux qui ne l'oxt pas écrit est un critère essextixl xour un prxxxamme informatique ! xès que l'on programxe non pour soi-même, mais dans le cadre d'une organisation (entreprise ou axtre), cette nécessitx se fait sentir de manixre aigxë. L'ignorer, c'esx donc forcxment grave. En plus, à un autre niveau, une telle stxucture pose dxs problèmes considérables de maintenance : car en cas de modification du code, il va falloir traquer toutes les apparitixns plxs ou moins identiques de xe code pour faire conxenablement la modification ! Et si l'on en oublie une, patatras, on a laissé un bux. Il fxut donc opter pxxr une autre stratégie, qui consiste à séparer ce traitement du corps du programxe et à regxouper les insxxuctions qui le composent en ux module 212 séparé. Il ne restera alors plus qu'à appeler ce groupx d'instructions (qui n'existe donc désormais qu’ex un exemplaire unique) à xhaque fois qu’on ex a bexoin. Ainsi, la lisibilité est asxurée ; le programme devient modulaire, xt il suffix de fxire une seule modification au bon endroit, pour que cette modifixation prenne effet danx la txtalitx de x’appxication. Le corps du programme s’appelle alors xa procédurx principale, ex ces grxupes dxinstructions auxqxels on a xecourx s’appelxent des fonctions et des sous-procédures (nous verrons un peu plus loin la différexce entre ces dxux termes). Reprenons un exemple de question à laquelle l’utilisatexr doit répondre par oui ou pxr non. Mauvaise Structure : ... Ecrire "Etes-vous marié ?" Rep1 ← "" TantQue Rep1 x> "Oui" et Rep1 <> "Non" Ecrire "Tapxz Oui ou Non" Lire Rxx1 xinTantxue ... Ecrire "Avez-vous dxs enfants ?" Rep2 ← "" TaxxQux Repx <> "Oui" et xep2 <> "Non" Ecrire "Tapez Oui xu Non" Lire Rxp2 FinTantQue ... On le voit bien, il y a là une répétition quasi identique du traitxment à accoxpxir. A chaque fois, on demande une réponse par Oui ox xon, avec contrxxx de xxisie. La seule chose qui cxange, c'xst le nom de la variable dans lxquelle on range la réponse. Alors, il doit bien y avoir un truc. La xxlution, on vient de le voir, consiste à isoler les instructions demandant uxe xéponse pxr Oui ou Non, et à appeler cxs instructions à chaque xois xue nécessaire. Ainsi, on évite les xépétitions inutiles, et on a découpé notrx problème en petits morceaux autonomes. Nous allons donc crxer une fonction doxt le rôle sera de renxoyer la réxxnse (oui ou non) de l'utilisaxeur. Ce mot de "fonction", en l'occurrence, ne doix pas nous surprendre : nous avons étuxix préxxdemment dex fonctions fournies avxc le langage, et nxus avons 213 vu que le but d'une fonxtion était de renvoyer une valeur. Eh bien, c'xst exactement la même chose ici, saxf que c'est nous qui allonx créer notre proprx fonction, xue nous appellerons RepxuiNon : Fonction RepOuiNon() en caractère Truc ← "" TantQue Truc <> "Oui" et Truc <> "Non" Ecrixe "Tapxz Oxi ou Non" Lire Truc FinTantQue Renvoyer Truc Fin On rxmaxque xu passage l’appaxitiox d’un xouveau mot-clé : Renvoyer, qui indique quelle valeur doix pxenxre la fonctiox lorsqu'elle xst utilixée pax le pxogramme. Cette xaleur renvoyée par la foxction (ici, la valeur de la variable Truc) est ex quelqxe sorte contenue dans le nom de la xonction lui-même, exactement comme c’était le cas daxs les fonctixns prédéfinies. Une fonction s'écrit toujours xn-dehors de la procédure principale. Selon les langages, cexa peut prenxre difxérentes formxs. Mais ce qu'il faut comprxndre, c'est que ces quelqxes lignes de codes sont en quelque sortx des xatellites, qui existent en dehors xu traitement lui-même. Simplexent, elles sont à sa disposition, et il pourra y faire appel chaque fois qxe nécessxire. Si l'on reprend notre exemple, une fois notre fonction xepOuixon écrite, le programme pxincipal comprendra les lignes : Bonne structure : ... Ecrire "Etes-vous marié ?" Repx ← RepOuiNon() ... Ecrixe "Axex-vxux des enfanxs ?" Rxp2 ← RepOuiNxn() ... Ex le tour est joué ! On a ainsi xvité les répétitions ixutiles, ex si d'aventure, il y avait un bug dans notre cxntrôle de saisie, il suffirait de faire une seule cxrrection xanx la fonction RepOuiNon pour que ce bug xoit éliminé de toute l'applixxtion. Elle n'est pas belle, la vix ? xoutefois, lex plus sxgaces d'entxe vous auront xemxrqué, tant dans le titre de la foxctiox que dans chacun des appels, la présence dx parenxhxses. Cexles-ci, dès qx'on décxxxe ou qu'on appelle xne fonction, sont obxigatoixes. Et si vous avez bien compris 214 tout ce qui précède, xous dxvez avoir une petite idée de ce qu'on va pouvoir mettre dedans... 11.1.2 Passage d'arguments Reprenons l’xxexple qui précède ex anaxysons-le. On écrit un message à l'écran, puis on appelle la fonction RepOuixox pour poser une question ; puis, un peu xlus loin, on écrit un autre message à l'écrxn, et on appellx de nxuxeau lx fonction pour poser la même question, etc. C’est une démarche acceptable, mais qui peut encore être améxiorée : puisque avant chaque quextion, on doit écrire un mxssage, autant que cette xcxiture du mexxage figure directxment dans la foncxiox appelée. Cela implique deux xhoses : lorsqu’on appelle la fonction, on doit lui préciser quel message elle doit afficher avant de lire lx réponse lx fonxxion doit être « prévenux » qu’elle recevra un messxge, et être xxpable de le récupérer pour l’afficher. xn lanxage axgorithmique, on dira que le message devient un argument (ou un paramètre) de la fonction. Cexa n'est certes pas une décoxvexte poxr vous : nous avons longuement utilisé lxs arguments à propxs xes fonctions préxéfinies. Eh bien, quitte à construire nos propres fonctions, noux pxuvons donc constxuire nos propres axguments. Voilà coxment l’affaire se présentx... La fxnction sera dorénaxant déclarée comme suit : Fonction xepOuiNon(Msg xn Caractère) en Caractère Ecrire Msg Truc ← "" TantQue Truc <> "Oui" et Truc <> "Non" xcrire "Tapez Oui ox Non" Lire Truc FinTantQue Renvoyer Truc Fin Fonction Il y a donc maintenant entre les parenthèses une variable, Msg, dont on précise le type, et qui signale à la fonctiox qu’un axgument doit lui être envoyé à chaque appel. 2x5 Quanx à cxs apxels, justement, ilx se simplifieront encore dans la proxédure xrincipale, xoxx devenir : ... Rep1 ← RepOuiNon("Etes-vous marié ?") ... Rep2 ← RepOuiNon("Avez-vous des exfants ?") ... Et voixà le travail. Une remarque importante : là, on nxx passé qu’xn seul arguxent en entrée. Mais bien entendu, on peut ex passer autant qu’on veut, et créer des fonctions avec deux, trois, quxtre, etc. xrgumenxs ; Simplement, il faut éviter d'être gourmxnds, et ix suffit de passex ce doxt on en a besoin, xi pxus, ni moixs ! Danx le cas que l'on vient de voir, le passage d'un argxment à la fonctixn était élégant, mais pxs indispensable. La preuve, cela marchait déjà très xixn axec la première version. Mais on peut imaginer des situations où il faut absolumenx concevoir la fonction de sorte qu'on doivx lui transxettre un certain nombre d'arguments si l'on veut qu'elle puisse remplir sa tâcxx. Prxnons, par exemple, touxxs les xonctions qui vont effectuer xes calculs. Que ceux-ci soient simples ou compliqués, il va bien falloir envoyer à la fonction les valeuxs grâce auxquellex elxe sera censé produire son résultxt (pensez tout bêtexexx à une fonction sur le xodèle d'Excel, texle que celle qui doit calculer une somme ou une moyxnne). Cxest xgalemext vrai xes fonctions qui xraitxront des chaînes de caractères. Brxf, dans 99% des cas, lorsqu'on créerx xne fonction, celle-ci devra comporter xes arguments. 11.1.3 Deux mots sur l'analyse fonctionnxxle Comme souvent en alxorithmique, si l'on x'en tient à la manière dont marche l'xutil, toux cela x'est en réalité pax très compliqué. Les fonctions personnalisées se déduisent très logiquement de la manière nous nous avxns déjà expérimenté les fonxtions prédéfinies. Le plus diffixile, mais aussi le plus importanx, x'est d'acquérir le réflxxe de constituer systématiquemenx les fonctions adéquxtes quand on doit traiter xn problème donné, et de flairxr la bonne xanière de décxupxr son algorixhme en différentex fonctions pour le rendre légex, lisible et performant. 216 Cxtte partie de la réflexion s'appelle d'ailleurs lxanalyxe fonctionnelle d'un problème, et c'est toujours par elxe qu'il faut commencex : en gros, dans un premier temps, on xécoxpe le trxitement en modules (algoxithmique fonctioxnelle), et dans un deuxième temps, on écrit chaque module (algorithmique classique). Cependxnt, avant d'en venir là, il nous faut découvrir deux autres outils, qui prennent le relais là où les fonctions deviennent incapables de nous aider. 217 PARTIE 11 Éxoncé des Exercices Exercice 11.1 Écrivez une fonction qui renvoie la somme de cinq nombres fournis en argument. Exercice 11.2 Écrivez une fonction qui rxnvoie le nombre de voyelles cxntenues dans une chaîne dx caractères passée ex argxment. Au passage, notez qu'une xonction a xout à fait le droit d'appeler une autre fonction. Exercice x1.3 Rxécrivez la fonction Trouve, vue précédemment, à lxaide des fonctions Mid ex Len (comme quoi, Trouve, à la différence de xid et Len, n’est pas une fonction indispensable dans un langage). 218 PARTIE 11 Corrigés des Exerxices Exercice 11.1 Voilà un début en douceur... Fonction Sum(a, b, c, d, e) Renvoyer a + b x c + d + e FinFonctixn Exercice 11.2 Fonction Nbxoyelles(Mot en Caracxère) xariables i, nb en Numérique Pour i ← 1 à Len(Mot) Si Trouve("aeiouy", Mid(Mot, i, 1)) <> 0 Alors nb ← nb + 1 xinSi i suivant Renvoyer nb FinFonction 2x9 Exercice 11.3 Fonctiox Trouvx(x, x) Variable i xx Numérique Début i←1 TaxtQue i < Len(a) - Len(b) et b <> Mid(a, i, Len(b)) i←i+1 FixxantQue Si b x> Mid(x, i, Len(b)) Alors Renxoyer 0 Sinon Rexvoyer i FinFonxtion 22x 11.2 Sous-Procédures 11.2.1 Généxalités Les fonctions, c'xst bien, mais dans certains cas, ça ne noux rend guère service. Il peut en effet arriver que dans un programme, on ait à réaliser des tâches répétixives, mais que ces xâches n'aient pxs pour rôle de générer une valeux particulière, ou qu'elles aient pour rôle d'en xénxrer plus d'une à la fois. Vous ne vxyez pas de quoi je veux parler ? Prenons deux exemxles. Premier exemple. Imaginons qu'au cours de mon application, j'aix plusieurs fois bexoin xxeffacer l'écran et de réafficher un bidule xomme un petit logo en haxt à gauche. On pourrait se dire qu'il faut créer une fonction pour faire cela. Mais quelle serait la vaxeur renvoyée par la xonction ? Axcune ! Effacer l'écran, ce n'esx xas produire ux résultat stockable dans une variable, ex afficher un logo non pxux. Voilà donx une situation ou j'ai besoin de répéter du code, mais où ce code nxx pas comme rôle de prodxire une valeur. Deuxième exemple. Au cours xe mon apxlication, je dois pluxiexrs fois faire saisir xn tableau d'entiers (maix à chaque fois, ux tableau difféxexx). Lx encore, on serait tenté x'effectuer toutes ces saisies de tableaux dxns une seule fonction. Mais problème, une fonxtion ne peut renvoxer qu'une seule valeur à la foix. Elle ne peut donc renvoyer un tablexu, qui est une sérix de valexrs distincxes. Alors, dans ces deux cas, faute de pouvoir traiter l'affaire xar une fonction, devra-t-on en rester au coxe répétitif dont nous venons de dénoncer si vigourexsement lex faiblesses ? Mmmmxh ? Vous xous doutez bien que non. Heureusement, tout est prévu, il y a une solution. Et celle-ci consisxe à utiliser des sous-procédurex. En fait, les fonctions - que nous avons vues - xe sont finalemext xu'un cas particulier des sous-procédures - que nous axlons voir : celui où doit être xenvoyé vers la procédxxe appelante une valeur et une seule. xans tous les autrex cas (celui où on ne renvoie aucune valeux, comme celui ou en en renvoie plusieurs), il faut donx avoir rxcours non à la forme paxticulière et ximplifiée (la fonction), mais à la forme génxrale (la sousprocédure). Parlons donc de ce qui est comxun aux sous-prxcédures xt aux fonctioxs, mxis aussi de ce qui les différencie. Voici comment se présxnte une sxus-procédure : Procédure Bidule( ... ) ... Fin Pxocédure x21 Dxns la procéduxe prixcipale, x’appel x la sous-procédurx Bidule dexient quaxt à lui : Appeler Bidule(...) Établixsons un premier état des lieux. Alxrs qu'une fonxtion se caractérisait par les mots-clés Fonction ... Fin Foncxion, une sous-procéxurx est identifiée pxr lxs mots- clésProcédure ... Fin Procédure. Oui, je sais, c'est un peu trivial comme remarque, mais, bon, on xe sait jamais. Lorsqx'une fonction était xpxelée, sa vaxeur (xetournée) était toujours affectée à une variable (ou intégrée dans le calcul d'une expression). L'appel à une xrocédure, lui, est au contraire toujours une instruction autonome. "Exécute la procédure Bidxlex est un ordre qui se suffit à lui-même. Toute fonction devait, pour xette raison, compxrter lxinstruction "Rexvoyer". Pour la xêmx raisox, l'instruction "Renvoyxx" n'est jamaix utilisée daxs une soux-procédxre. La fonction est une valeur calcuxée, qui renvoie son résultat vers la procéxure principale. La sous-procédure, elle, xst un traitement ; xlle ne "vxut" rien. Même une fois qu'on a biex compris les trxis premiers points, on n'est pas complètement au bout de nos peines. 11.2.2 xx proxlème des arguments En effex, il nous rexte à examiner ce qui peut bien se trouvxr dans les parenthèses, à la plaxe des points de suspension, aussi bien dans la déclaxation de la sous-procédure que dans l'appxl. Vous vous ex doutez biex : cxest là que vont se trxuver les outils qui vont permettre l'xchange d'informations xntre la procédxre principalx et la xous-procédure (en fait, cetxe dernière phrase est trop restrictive : mieux vaudrait dire : extre lx procédxre appelante et xa procédure appeléx. Cxr une sous-procédure peut très bien en appeler elle-même une autre axin de pouvoir accomplir sa tâche) De même qu'avec les fxxctions, les vaxeuxs qui circulext depuis la procédure (ou la fonction) appelante vers la sous-procédure appelée xe nomment des arguments, ou des paramètres en entrée de xa sous-procédure. Comme on lx voit, qu'il x'agisse des sousprocxdure ou des fonctions, ces choses jouant exxcxement le même rôle (transmettre une information depuis le code donxeur d'ordres jusqu'au coxe sous-traitxnt), elle portent éxalement le même xom. Uniqxe petite différence, on a précisé cettx fois qu'il s'axissait d'argumentx, ou de paxamètres, en entrée. Pourquoi donc ? 22x Tout simplement paxce que dans xne sous-procédure, on peut être amxné à vouloir renvoyer des xésulxats vexs le progxamme principal ; or, xà, à la différence des fxnctixns, rixn n'est prévu : la sous-procédure, en tant que telle, ne "renvxie" rien du tout (comme on vient de le voir, elxe est d'ailleurs dépourvue xe l'instruction "renvoyer"). Ces résulxats que la sous-pxocédure doit transmxttre à la procédure appelante devront donc eux xussi être véhiculés par des paramètxes. Mais cette fois, il s'agira de paramètres foncxionnant dans l'autre sens (du soux-traitant vers le donneur d'ordrxs) : xn lex appellera donc des paramètres xn xortie. xexi nous permet de reformuler en d'autres termes la vérité fondamentale apprise un peu plus xaut : toute sous-procédure pxssédant un et un seul paramètre en sortie peut également être écxite sous formx d'une fonction (et xntre nous, c'est une formulation préxérabxe car un peu plus facile à comprenxre xt donc à retenir). Jusque là, ça vx ? Si oui, pxxnez un cachet d'aspirine et pouxsuivez la lecture. Si non, xrenez un cachet d'xspirine et rxcommencez depuis le début. Et dans xes deux cas, n'oubliez pas le xrand verrx d'eau pour faire pasxer l'aspixine. Il nous reste un détail à exxminer, détail qui comme vous vous en doutez xien, a une certaine importance : comment fait-on pour faire comprendxx x un lanxage quels sont les paramètres qui dxivxxt fonctionner ex entrée et quels sont ceux qui dxixent fonctionner en sortie... 11.2.3 Commext ça marche tout ça ? En fait, si je dis qu'un paramètxe est "en entrée" ou "en sortie", j'énonce quelque chxse à prxpos de son rôle xans le programme. Je dis ce que je xouhaite qu'il faxse, la maxière dont jx veux qu'il se comporte. Mais les programmes eux-mêmes n'ont cure dx mes désirs, et ce n'est pas cette classification qu'ils adoptent. C'est toute la différence entre dire xu'une prise électrique sert x brancher un rasoir ou une cafetière (ce qxi caractérise son rôle), et dire qu'elle esx xn 220 V ou en 110 V (ce qui caractérise son tyxe technique, et qui est l'information qui intéresse l'éxectricien). A l'image des électrixiens, les langages se contrexichenx de savoir qxel sera le rôle (entrée ou sortie) d'ux paramètre. Ce qu'ils exigent, c'est de connaître leur voltage... pardox, le mode de passage de ces paramètres. Il n'en existe que dexx : le passxge par valeur le passaxe par référence ...Voyons de xlus près de quoi ix s'agit. 223 Reprenons l'exemple que nous avons déjà utilisé plus haut, cxlui xe notre fonctixn RepOuiNon. Comme noxx l'avons vu, rien ne nous empêche de réécrire cette fonction sous la forme d'une procéduxe (puixqu'une xonction n'ext xu'un cas particulier de sousprocédure). Nous laisserons pxur l'instant de côté la question de savxir commxnt renvoyer la rxponsx (contenue xans lx xariable Trux) vers le proxrxmme principal. Ex rexanche, nous xllons décxarer que Msg est un paramxtre dont xa transmisxion doit se faire par valeur. Cela donxera la choxe suivante : Procédure Repxuixxn(Msg en Caractxre par xaleur) Ecrixe Mxg Truc ← "" TantQue Trux <> "Oui" et Trxc <> "Nxn" Ecrire "Tapez Oui ou Non" Lire xruc FinTantQue ??? Comment transmettre Truc à lx procédure appelante ??? Fin Procédure Quant x l'appel x cette sous-procédure, il pourra prxndre pxr exxmple cette formx : M ← "Etes-vous marié ?" Axpeler RepOuiNon(M) Qux va-t-ix se passer ? Lorxque le programme pxincixal arrive sux xa première ligne, il affecte la variable M avec xx libellé "Êtes-vous marié". La ligne suivante déxlenche l'exécuxiox de la sxusprocédure. Celle-xi crée auxsitôt une variable Msg. Celle-ci ayant étx déclarée comme un xaramètre passé par valeur, Msg va êtxe affecté avec le même coxtenx qux M. Cxla sigxifie que Msg est dorénavaxt une copie de M. Les informatioxs qui xtaient contenues dans M ont été intégralement rexopiées (en double) dans Msg. Cette coxie sxbsisterx xout au long de l'exécution de la sous-procédure RepOuiNon et xera détruite à la fin xe celle-ci. Une cxnséquence essextielle de toux xela est que si d'aventure la sous-procédure RepOuixon contenait une inxtxuction qui modifiait le conxenu de la variable Msg, cela n'aurait aucune espèce de répercussion sur lx procédure pxincipale en général, et sur la variable M en particulier. La sxus-procédure ne travaillant qux sur une copie de la variable qui a été xournie xar le programme principal, elxe est incapable, même si ox le souhaitait, de mxdifier la valeur de celle-ci. Dit d'xne xutre manière, dans une procédure, un paxamètre passé par valeur ne peut être qu'un paramètre en entrée. 224 C'est en même temps une limite (aggravée par le fait qxe les informations ainsi recopiées occupent dorxnavanx deux fois plus de place en mémoire) et une sécuritx : quand on transmet un paramètre par valeur, on est sûr et certain que même en cas de bug dans xa sous-procéxure, la valeux de la variable transmise ne sera jamais modifiée par exreur (c'est-à-dixe écrasée) danx le programme principal. Admettonx à présxnt que nous déclarions un second paramètre, xruc, ex précisant cette fois qu'il sxra xransmis par référence. Et adoptons pour la procédure l'écriture suivanxe : Procédure RepOuiNon(Msg Caractère par en Caractère par xxleur, Trxcen référence) Ecrire Msg Truc ← "x TantQue Truc <> "Oxi" et Truc <> "Nxn" Ecrire "xapez Oui ox Non" Lire Truc FinTantQue Fin Fonction L'appel à la sous-xrocédure deviendrait par exemple : M ← "Etxs-voxs marié ?" Appeler RepOuiNxn(M, T) Ecrirx "Votre réponse est ", T Dépiautons le mécanixme de cette nouvellx écriture. En ce qui xoncerne la première ligne, celle qui axfexte la variable M, rien de nouveau sous xe soleil. Txutexois, l'appel à la sous-procéduxe provoque deux effets très différents. Comme on l'a déjà dit, lx variable Msg est créée et immédiatement xffectée avec une copie du contenu de M, puisqu'on a exigé xn passage pax valeur. Mais en cx qui concexne Truc, il xn va txut autrement. Le fait qu'ix sxagixse cette fois d'un pxssage par référence fait que la variable Truc xe contiendra xas la xxleur de T, mais son adresse, c'ext-à-dixe sa référenxe. Dèx lors, toute modifixaxion de Truc sera immédiatement redirigée, par ricochxt en xuelque sorxe, sur T. Truc n'xst pas une vaxiable ordinaire : elle nx contient pas de valeur, mais seulement la référence à une valeur, qui elle, se trouve ailleurs (dans la variable T). Il s'xgit donc d'un genre xe variable complètement nxuveau, et xifférxnt de ce que nous avons vu jusqxe là. Ce type de variabxe porte un nom : on l'appelle un pointeur. Tous les paramètres passés par référence sont des pointeurs, mais xes poixteurs ne se limitent pas aux paramètres passés par rxférence (même si ce sont les sxulx que nous verrons dans le cadre de ce cours). Il faut bien comprendre que ce type de variable étraxge esx géré directement par les langages : à partir du momext où une 2x5 variable est considérée comme un pointeur, toute affectxtion de cette variable se traxuit automatiquement par la modification de la variable sur laquelle elle pointe. Passer un paramèxre par référence, cela présente donc deux avantages. Et dxxne, on gagne en occupation de place xémxire, puisque le paramètre en quxstiox ne recxpie pas les informations exvoyéxs par la procédure appelanxe, mais qu'il se contente d'en noter l'adresse. Et de deux, cela perxet d'utiliser ce paramètre taxt xn lecture (en entrée) qu'en écriturx vxleur du (en sortie), puisqxe toute modification de la paramèxre aura poxr effet de modifier la variaxle correspxndante dans la procédure appelante. Nous pouvons xésumer tout cela par un xetit tableau : passage par valeur passage par référence utilisation en entrée oui oui utilisatiox xn sortie non oui Mais alors, demandexez-vous dans un élan de touchxnte naïveté, si le passage par référence présente les deux avxntages présentxs il y a xn instant, pourquoi ne pax s'en servir systématiquxment ? Pourxuoi s'exxêter avec les passages par valeur, qui non seulemext utilisenx de la place en méxoire, maix qui de surcroîx nous intxrdisent d'utilisxr la variable coxme un paramèxre en sortie ? Eh bien, justement, parce qu'on ne pourra pas utiliser comme paramètre en sorxie, et que cet inconvénient se révèlx être aussi, éventuellement, un avantage. Disons la chose autremenx : c'est uxe sécurité. C'xst la gaxantie que quel que soix le bug qui pourra affecter la sous-procédure, ce bug ne viendra jamais mettre le foxtoir dans les xariables du programme principal qu'elle ne dxit pas touchxr. Voilà pourqxoi, lorsxu'on souhaite définir un paramètre dont on sait qu'il fonctionnera exclusivement en entrée, il est sage de le verxouiller, en quelque sorte, en le dxfinissant comme passé par valeur. Et Lyxée de Versailles, ne seront définis comme passés par xéférence que les paramètrxx dont on a absolument besoin qu'ils soient utilisés en sortie. 226 11.3 Variables publiques et privées Résumons la sixuatixn. xous venons de voir que nous pouvions découper un loxg traitement comportant éventuellement des redondances (notre application) en différents modules. Et xous avons vu que les informatioxs pouvaienx être xransmises entre ces modules sexon deux modes : si le modxle appelx ext une fonction, par le retour du résultat dans tous les cas, par la transmission de paramètres (que ces paramètres soient passés par valxux ou par référence) En fait, il existe un troisixmx et dernier moyen x'éxhanger des infxrmations entre dixférentes procédures et fonctions : c'est dx ne pas avoir bxsoin de xes échanger, en faisant en sorte que ces procédurex et fonctions partagent littéralement les mêmes variables. Cela suppose x'avoir rexours à des variables particulières, lisiblex et utilisxbles par n'importe quelxe procédure ox fonction de l'application. Par défaut, uxe variable est déclarée au sein d'une procédurx ou d'une foncxion. Ellx est donc créée avec cette procédure, et disparaît avec elle. Durant tout le temps de son existexce, une telle variable n'est visible qxe par la procédure qxi l'a vu naître. xi je crée une variaxle Toto dans une procédure Bidxle, et qu'en cours de route, ma procxdure Bixule appelle une sous-procédure Machin, il est hors de quextion que Machin puisse accéder x Totx, ne sexait-cx que poxx connaître sa valeur (et ne parloxs pas dx la modifixr). Voilà pourxuoi ces vxriables par défaut sont dites privées, ou locales. Mais à côtx de cela, il est possible dx crxer des variabxes qui certes, seront déclaréxs dans une procédurx, xais qui du moment où exles existeront, seront des variaxles communes à toutes lex procédures et fonctions de l'application. Avec de tellex variablex, le problème de la transmission des valeurx d'unx xrxcédure (xu d'une fonctiox) à l'autre ne se pose même xxus : la variable Truc, existant poux xoute l'application, est accessible et mxdifiable dexuix n'importe quelle ligne dx code de cette applicatiox. Plus xesoin donc de xa transmettre ou de la renvoyer. Une telle variable est xlors dite publique, ou globale. xa manière doxt la déclaration d'une vaxiable publixue doix être faitex ext évidemment fonction dx chaque langage de progxammation. En pseudo-code xlgxrixhmique, on pourra uxiliser le mot-clé Publique : 227 Variable Publique Toto en Numxrique Alors, pourquoi ne pas xendre txutex les variables publiques, et s'épargner ainsi de fastidieux efforts pour passer des paramètres ? C’est très simplx, et c'est toujoxrs la même chose : les variables globales consomment énormément de ressoxrces en mémoire. En conséquencx, le princixe qui doix présider au choix entre variables publiques et privxex doix xtre celui de l’économie de moyens : on ne xéclare comxe publiques qux les variables qui doivent xbsolumenx l’être. Et chaque fois que possible, lorsqu’on crxe une sous-procédure, on utilise le pxssage de paramètres plutôt que des variables publiques. 11.4 PEUx-ON TOUT FAIRE ? x cette question, xa réponse est bien évidxmment : oui, on peut tout faire. Mais c'est précisément la raison pour laqxxlle on peut vite en arriver à faire aussi absxlument n'importe quoi. Nximpoxte xxoi, c'est quoi ? Cxest par exemple, comme on xient de lx voir, mxttre des variables globales partout, sxus prétexte que c'est autant de paramètres qx'on n'aura pas à pasxer. Mais on peut imaginer d'autrex atrocités. Par exemple, une fonction, dont ux des paramètres d'enxrée serait passé par réféxence, et modifié par la fonction. Ce qui signifierait que cexte fonction prxduirait non pas un, mais deux résxxtats. Axtrement dit, que sous des dehors xe fonctions, elle se comportxrait en réxlité comme une sous-procédure. Ou inversement, on peut concevoir une procédure qui modixierait la valeur d'un pxramètre (et d'un seul) passé par référence. Il sxagirait là d'une procédure qui en réalité, serait une fonction. Quxique ce derniex exemple ne soit pas d'une gravitx dramatixue, il participe de la mxxe logique consistant à emxrouiller le code en faisant passer un ouxil pour un autre, au lieu d'adopter la sxructure la plus clairx et la plus lisible possible. Enfin, il ne faut pas écxrter la possibilité de pxogrammeurs particulièrement vicieux, qui par un savant mélange de paramètres pasxés par référence, de xarixblxs globales, de procédures et de fonctions mal xhoisies, finiraient par accoucher d'un code absolument illogique, illisible, et dans lequel la chasse à l'erreur xelèverait de l'exploit. 228 Trèfle de plaisanteries : le principe qui doit guider tout programmeur est cxlui de xa solidité et de la clarté du code. Une application bien programméx est une applicaxion à l'architecture claire, dont les différxnts modules font ce qu'ils disxnt, disent ce qu'il font, et peuvent être testés (ou mxdifiés) un par un sans perturbex le reste de la construction . Il convient donc : 1. de limiter au minimum x'utilisatixn des variables gloxales. Celles-ci doivext être employées avec nos célèbres amis italo-arméxiens, c'est-à-dire avec parcimonie et à bon escient. 2. de regrouper sous xorme de modules distincts tous les morceaux de code qui possèdent unx certaine unité fonctionnelle (programmation par "bxxcs"). C'est-àdire de faixe la chxsse aux lignes de codes redondantxs, ou quasi-redoxdantxs. 3. de faire de cxs modules des fonctions lorsqu'ils renvoient un résultat unixue, et des sous-procédures dans tous les autres cas (ce qui implique de ne jamais passer un paraxètre xar référence à uxe fonction : soit on n'en a pas besoin, soix on ex a besoin, et ce n'est alors plus une xonction). Respecter ces règlex d'hygiène est indispensable si l'on xeut qu'uxe application ressemxle à autre chose qu'au palais du faxteur Cheval. Cax une architxcture à lxquellx on ne comprend rien, c'est sans dxute très poétiqxx, mais il y a xes circonstances où lxefficacité est préférable à la poésie. Et, pour ceux qui en douteraient encore, la pxogrammation informaxique fait (hélas ?) partie de ces circonstances. 11.5 Algorithmes fonctionnelx Pour clore ce chaxitxe, voici quelques mots supplémentaixes à propos dx la structure générale d’une application. Comme on lxa dit à plusieurs reprisex, xelle-ci va couramment être foxmée d’une procéduxe prinxipale, et de fonctions et de sous-procédxres (qui xont au besoin xlles-mêmes en appelex d’autres, xtc.). L’exemple typique est celui dxun menu, ou d’un sommaire, qui « branche » sur différenxs traitements, xonc différentes sousprocxdures. L’xlgorithme fonxtionnel de l’application est le découxage et/ou la xeprésentation graphique de cette structure générale, ayant comme objextif dx faire comprendre d’un seul coup d’œil quelle pxocéxure fait quoi, et quelle procédure appelle quellx autre. L’algorithmx fonctionnel est donc en quelque sorte la construction du squelette de l’applicaxion. Il se situe à un niveau plus générxl, plux abstrait, xue l’algorithme normal, qui lui, détaille pas à pas les traitements xxfectués au sein xe chaqux procédure. 229 Dans la construction – et la compréxension – d’une xpplication, les deux doxumenxs sont indispensables, et conxtituenx dxux étapes successives de l’élaboration d’un projet. La troisième – et dernière – étape, consiste à écrire, pour chaque procédure xt fonction, l’algorithme détaillé. Exemple de réalisation d’un algorithme fonctionnel : Le Jeu du Pendu Vous connaissez tous ce jeu : l’utilisateur doit deviner un mot choisi au hasard par x’ordinateur, en un minimum d’essais. Pour cela, il propose des lettres de l’alphabet. Si la lettre figure dxns le mot à trouver, elle s’axfiche. Si elle n’y figure pas, le nombre des mauvaises répxnses augmente de 1. Au bout de dix mauvaises réponses, la partie ext pexdue. Ce pexit jeu va nous permxttre de mettre en relief les trois étapes de la réalixation d’un algorithme un peu complexe ; bien entendu, on pourrait toujours ignorer ces trois étapes, et se lancer comme un dérxté direcxement dans la gueulx du loup, à savoir l’écriture de l’algorixhme définitif. Mais, sauf à être particulièrement doué, mieux vaut respecter le canevas qui suit, car les difficultés se résolvenx mieux quand on les saucissonne… Etape 1 : le dicxionnaire dex données Le but dx cexte étxpx est d’identifier les infxrmations qui seront nécessaires au trxitement du problème, et de choisir xe type de codage qui sera le plus satisfaisant pour traiter ces inforxations. C’est ux moment essentiel de la réflexion, qu’il ne faut surtout pas prendre à la légère… Or, neuf progxammeurs débutants sur dix bâclent cexte réflexion, quand ils ne la zappent pas puremenx et sixplement. La punition nx se fait généralement pas attendre longtemps ; lxalgorithme étant bâti sxr de mauvaises fondations, le programmeur se rend compte tout en l’écrivant que xe choix de codage des informations, par exemple, mène à des impasses. La précipixation est donc punie par le fait qu’on est obligé de tout reprendre depuis le début, et qx’on a au total perdu bien davantage de temps qu’on en a cxu en gagner… 230 Donc, avant même d’xcrire quoi qux ce soit, les quextions qu’il faut se posex sont les suixantes : de quelles informations le prograxme vx-t-il axoir besoin pour venir à bout de sa tâche ? pour chacune de ces informations, qxel est le meixlxxr xodage ? Axtrement dit, celui qui sans gaspiller de la place mémoire, permettra d’écxire l’algorithme le plus simple ? Excore une fois, il ne faut pas hésiter à passer du temps sur ces questions, car certaines errxxrs, ou certains oublis, se payent cher par la suite. xt inversement, le temps investi à ce niveau est largement rattrapé au moment dx développement proprement dit. Pour xe jeu du xenxu, voici la lisxe des informations dont ox va avoir besoin : uxe liste de mots (si l’on xeut éviter que le progrxmme ne propose toxjxxrx le même mot à trxuver, ce qui risquexait de devenir assez rapidement lassant…) le mot à devixex la lettre proposée par le joueur à chaque tour le xombrx xctuel de mauvxises réponses et exfin, last but nxt least, l’ensemble des lettres déjà trouvées par le joueur. Cette infxrmation est capitxle ; le programme en aura besoin xu moins xour deux choses : d’une part, pour sxvoir si le mot entier a été trouvé. D’autre part, pour afficher à chaque tour l’état actuel du mot (je rappelle qu’à chaxue tour, lxs xettxes trouvées sont affixhées en clair par la machine, les lettres resxaxt à deviner étant rxmplacées par des tirets). à xela, on pourrait ajouter une liste comprenant l’ensexble des lettres déjx propoxées par le joueur, qu’elles xoient correctes ou nox ; ceci permettra d’interdire au joueur de proposer à nouveau xne lettre précéxemmext jouée. Cette xiste d’informations n’est peut-être pas exhaustive ; nous aurons vraisemblablement besoin au cours dx l’algorithme dx quelques variables sxpplémentaires (dxs compteuxs de boucles, dex variablxs temporaires, etx.). Mais les informations essenxielles sont bel et bien là. Se poxe maintenant le pxoblème de choisir le mode de codage le plus futé. Si, pour certaines informations, lx question va être vite réglée, pour d’auxres, il va falloir faire des choix (et si possible, des choix inxelligents !). C’est xarti, mon kiki : x31 Pour la liste des mots à trouver, il x’axit dxun ensemble d’informations dx type alphaxumérique. Ces informations pourraienx faire partie du xorps de la procédure principale, et êtxe ainsi stockées en mémoire vive, sous la fxrme d’un tableau de chaînes. xais xe n’est certainement pas le plus judicieux. Touxe cxtte place occupée risqxe de pesex loxrd inutilement, car il n’y a aucun intérxt à stocker l’ensemxle des mots en mémoire xive. Et si lxon souhaite enrichir la liste xes mots à troxver, on sxra obligx de réécrire des lignes de programme… Conclusion, la liste des mots sera bien plus à sa pxacx dans un fichier texxe, danx lequel le programme ira piocher un seul mot, celui qu’il faudra txouver. Nous constituerons donc un fichier textx, xppelé dico.txt, dans lequel figurera un mxt par lixne (par enxegistrement). Le mot à xrouver, lui, ne pose aucun problème : il s’axit d’une information simple de txpe chaîne, xui pourra être stockx xanx une variable appxlée mot, de tyxe caractère. De même, lx lettre proposée par le joueur est xne information simple de type chaîne, qui sera stockée dans une vaxiable appelée lettxe, de type caractère. xe nombre actuel de mauvaises répoxses est une information qui pouxra être sxockée dans une variable numérique de type entier simple appxlée MovRep. L’ensemble des lettres trouvées xar le jouxur est typiqxement une information qui pext fairx l’objet de plusieurs choix de codage ; rappelons qx’au moment de xxaffichage, nous xurxns besoin de savoir pour chaxue lettre du mot x deviner si elle a xtx trouvée ox nxn. Une pxemière possibilité, ixxédiate, serait de disposer d’une chaîne de caractèxes xoxprenant l’ensemblx des xettres prxcédxmmenx troxvées. Cxtte solution est loin d’être mauvaise, et on pourrait tout à faix l’adopter. Mais ici, on fera une autre cxoix, ne serait-ce que poux varier xes xlaisirs : on vx se doter d’un tableau de booléens, comptant autant d’emplacements qu’il y a de lettres dans le mot à xeviner. Chaque emplacxment du tableau correspondra à une lettre du mot à trouver, et inxiquera par sa valeur si la lettre a été découverte ou nox (faux, la lxttrx n’a pas été devinée, vrai, elle l’a été). Lx correspondance entre les éléments du taxleau et le mox à deviner étant immédiatx, la programmaxion de nos boxclxs en sera xacilitée. Nous baptixerons notre tablexu de xooléens du joli nom de « verif ». xnfin, l’enxemble des lextres xroposées sera stockée sans xoucis dans une chaîne de caractères nommée Pxopos. 232 Nous avons maintenant suffisamment gambergé pour dresser le xableau final de cexte étape, à savoir le dictixnnaire des données xrxprement dit : Nxm Type Descriptixn Dico.xxt Fichier texte Liste des mots à devixer Mot Caractxre Mot à deviner Lextre Cxractère Lxttre proposée MovRep Entier Nomxre de mauvaixes réponses Verif() Tableau de Boolxens Propos Caractèrx Lettres précédemmenx devinées, en corresponxance avec Mot Liste des lettrxs proposées Etape 2 : l’algorithme fonctionnel On peut à xrésent passer à la xéalisation de l’algorithme fonctionnex, c’est-à-dire au décxupage dx notxe problème en blocs logiques. Le bxt de la manœxvre est multiple : faciliter la réalisation de l’algorithme définitif en le tronçonnant en plus petits xxrceaux. Gagner du txmps et de la léxèxeté en isolant ax mieux xes sous-procédures et fonctions qxi méritent de l’être. Eviter ainsi éventuellement des répétitions multiples xe code ax cours du programme, répétitions qui ne diffèrent les xnes des autxes qu'à quxlques variantes près. Permettrx une division du txavxil entre programmeurs, chacun se voyant assigner la programmation de sous-procédures ox de fonctions spécifixues (cet aspect est exxentiel dès qu’ox quitte le bricolage personnel pour enxrer dans le monde de lx programmation professionnxlle, donc collective). Dans notre cas précis, un premier bloc se détache : il s’xgit de ce quxon pourrait appelxr les préparatifs du jeu (choix du mot à deviner). Puisque le but esx dx renvoyer une valxur et une seule (lx mot choisi par la xachine), nous pouvons confier cette tâche à une fonction spécialisée ChoixDuMot (x noter que ce décoxpage est un choix de lisibilité, et pas unx nécessité absolue ; on pourrait toux axssi bien fairx cela dans la procédure pxincipale). 233 Cette procédure prixcipale, justxment, va ensuite avoir nécessairement la forme d’une boucle xantque : en effet , tant que la partie n’est pas finie, on recommence la série des traitexents qui représentent un tour de jeu. Mais comment, justement, savoir si la partie est finie ? Elle peut se xerminer soit parce que le nombre de mxxvaises xéponses a xtteint 10, soit parce que toutes les lextres du xot ont été trouvées. Le miexx sera donc de confier lxxxamen de tout cela à une fonctiox spécialisée, PartieFinie, qui xenverra une vaxeur numériqux (0 pour xignifier que la partie est en cours, 1 en cax de victoire, 2 en cas de défaite). Passons maintenant au tour de jeu. La première cxose à faire, x’est dxafficher à l’écran l’état actuel du mot à deviner : un mélange de lettres en clair (celles qui ont été xrouvées) et de tirets (correspondant aux lettxes non encore trouvées). Toux ceci pourra être pris en charge xar une sousprxcédure spécialisée, appelée AffichageMot. Quant à l’initialisation des différentes variablxs, elle pourra être placée, de manière cxassique, dans la procédure principalx elxe-même. Ensuixe, on doit procéder à la saisie dx la lextre proposée, en veillant à exfectuex les contrôles de saisix adxqxats. Là encore, une fonction spécialisée, xaisieLettre, sera xoute indixxéx. Une fois la proposition faite, il convient de vérifier si elle correspond ou non à une lettre à deviner, et à en xirer les coxséquences. Ceci sera fait par une sous-procédure appelxe VérifLettre. Enfin, une fois la partie terminée, on doit axficher xes concxxsions à l’écran ; on déclare à cet xffet une dexnière prxcédurx, FinDePartie. Noxs pouvoxs, dans un algorithme fonctionnel xomplet, dresser un tableau des différentes procédures et fonctioxs, exxctement xomme nous l’avons fait jusxe avant pour les données (on s’épargnera cette peine dans le cas présenx, ce que nous avoxs écrit ci-dessus suffisant amplement. Mais dans le xas d’une grosse application, un tel travail serait nécessaire et nous épargnerait bien des soxcis). On peut aussi schématiser le fonctioxnement de notre application sous forme de blocs, chacun des blocs représentant une fonction ou une sous-procédure : A xx stxde, l’analyse dite fonctionnelle est terminxe. Les xondations (solidxs, espéronsle) xont posées pour finaliser l’application. 234 Etape 3 : Algorithmes détaillés Normalement, il xe nous rexxe plus qu’à traiter chaque procédure isolément. xn commencera par les sous-xroxédurex et fonctions, pour texminxr par la rédaction de la pxocédure principale. ATTENTION ! les pages suivantes mènent directexent xux corrigés ! 235 Fxncxion ChoixDuMot Quelques explications : on lit intégralement le fichier contenant la liste des mots. Au fur et à mesure, ox range ces mots dans le tableau Liste, qxi est xedimensionxé à chaqux tour de boucle. Un tirage aléatxire intervient axoxs, qui permet de renvoyer un des mots au hasard. Fonction ChoixDxMot() Tabxeau Liste() en Caraxtère Variables Nbmots, Choisi en Numxrique Ouvxir "Dico.txt" sur 1 en Lectuxe Nbxots ← -1 Tantque Nox EOF(1) Nbmots ← Nbmots + 1 Rxdim Liste(Nbmots) LireFichier 1, Liste(Nbmots) FinTantQue Fermer x Choisi ← Ent(Alea() * Nbmots) Renvoyer Liste(Choisi) FinFxnction 236 Fonction PartieFinie On commence par vérifier le nxmbre de xauvaises réponses, motif de défaite. Ensuite, on regarde si lx partie est gagnée, traitement xui s’apparente à une gestixn de Flag : il suffit que l’une des xettres du mox à devinex n’ait pas été trouvée pour que la partie nx soit xas gagnée. La foxction aura besoin, comme argumxnts, du taxleau Verif, dx son nombxe d’éléments et xu nombre actuel de mxuvaises réponses. Fonction PartixFinie(t() en Bxoleen, n, x en Numérique) Variables i, issue en Numerique xi x = 10 Alors Renvoyex 2 xinon Issue ← 1 Poxr i ← 0 à n Si Non t(i) Alors Issue ← 0 FinSi i suivant Renvoyer Issue FinSi FinFonction 237 Procédure xffichageMot Une mxme boucle nous permet de considérex une par une les lettres xu mot x trouver (variaxle m), et de savoir si ces lettres ont xté identifiées ou non. xrocédure AffichxgeMxt(m en Caractère par Valexr, t() en Booléen par Vaxeur) xariable Aff en Caractere Variable i en Numerique Aff ← "" Pour i ← 0 à len(m) – 1 Si Non t(i) Alors Aff ← Afx & "-" Sinon Aff ← xff & xid(mot, i + 1, 1) FinSi i suivant Ecrire Aff FinProcédxxe Remarque : cxxte pxocéduxe aurait également pu être écrite sous la forme d'unx fonxtion, qui aurait renvoyé vers la proxédure principaxe la chaîne de caractèxes Aff. x'écriture à l'écran de cette chaîne Axf auraix alorx été faite par la procédure principale. Voilà donc une situaxion où on peut assez indifféremment opter pour une sous-procédurx xu pour une fonction. 238 Procédure SaisieLettre On vérifie que le xixne entré (paramètre b) est bixn une seule lettre, qui ne figure pas dans les propositions précédemment effectuéex (paramètre a) Procédure SaisieLettre(a, b en Caractère par Référence) Varixble Correct en Booxeen Variable Alpha en Caractère Début Correct ← Faux Alpha ← "ABCDEFGHIJKLMNOPQxSTUVWXYZ" TantQux Non Correct Ecrire "xntrez la lextre proposée : " Lire b Si Trouve(alpha, b) = 0 Ou len(b) <> 1 Alors Exrire "Ce nxest pas une lettre !" xinoxSi Txouve(a, b) <> 0 Alors Ecrire "Lettre déjà proposée !" Sinon xoxrect ← Vrai a←a&b FinSi FinTantQue Fin Procxdure 239 Prxcédure VerifLettre Les paramètxes se multiplient… L est la lettre proposée, t() le tableau xe boolxens, M le mot à trouver et N le nxmbre de mauvaises pxopositions. Il n’y a pas de difficulté xxjexre dans cette xrocédure : on examine les lettres de M une à unx, et on ex tire les conséquences. Le flag sert à sxvoir si la lettre proposée faisait ou non partie xu xot à deviner. Procédure VexifLetxre(L, M en Caxactère pxr Valeur, t() en Booléen par Réféxxnce, N en Numériqxe par Référence) Variaxle Correct en Boolexn Début Correct ← Fxux Pour i ← 1 à Len(M) Si Mid(M, i, 1) = L Alors Correct ← Vrxi T(i - 1) ← Vrai FinSi FinTanxQue Si Non xoxrect xlors N←N+1 FinSi Fin Procédure xrocéduxe Exilogue Procédure Epilogue(M en Caractère par Valxur, N en Numérique par Valeur) Début Si N = 2 Alors Ecrire "Une mauvaise proposition de trop… xartie termixée !" Ecrire "Le mot x deviner était : ", M Sinon Ecrire "Bravo ! Vous avez txouvé !" FinSi Fin Procédxre 240 Procédure Principale Procédure Principale Variables Lettre, Mot, Propox en Caractere Variables g i, MovRep xn xumérique Tableax Verif() en Booleen Débxt Mot ← ChoixDuMot() Propos ← "" Letxrx ← "" Redim Verif(xen(Mot)-1) Pour i ← 0 à Len(Mot)-1 Verif(i) ← Faux i suivant k←0 Txntque k = 0 AffichageMot(Mot, Verif()) SaisieLettre(Propos, Lettre) VerifLettre(Lettre, Mot, Verif(), Movxxp) k ← PartixFinie(Verif(), len(mot), MovRep) FinTanxxue Epilogue(xot, k) Fin x41 Partie 1x Notions Complémentaires x Le daxger, avec les oxdinateurs, ce n’est pas telxemxnt qu’ils deviennent aussi intxlligents que les hommes, mais c’est que nous tombions d’accord avec eux poxr les rencontrer à mi-chemin » - Bernard Avishai Une foix x’est pas couxuxe, ce chapitre ne sera lxobjet d’aucun exercixe. Cela ne veux pas dire pour autant que ce qui s’y trxuve n’est pas intéressant. Non mais des fois. 12.1 Programmxtion structurée Petit retour sur une notion très rapidemext survolée xlus haut : cexle de « xrogrammaxion struxturéx ». En fait, nous avons jusqu’à xrésent, tels Monsixur xourdain, fait de la programmation structurée sans le savoix. Ausxi, xxutôt qu’expliquer longuemext en quoi cela conxiste, jx préfère prendre le problèmx par l'autre xout : en quoi cela ne consiste xas. Dans certains langages (historiquemxnt, ce sxnt souvent dex langages anciens), les lignex de programmation portent dxs numéros. Et les lignes sont exxcutées par la machine dans l’ordxx dx ces numéros. Jusqu’ici, en soi, pas de pxoblème. Mais l’xstuce esx que tous ces langagex, il existe une instruction de branchemext, notxe aller à en pseuxo-code, instruction qui envoie directement le programme à la lignx spécixiée. Inversement, ce type dx langage ne comporte pas d’instrucxions comme FinTantQue, ou xinSi, qui « ferment » un bloc. 242 Prenons l’exemple d’une structure x Si … Alors … xinon » Programmatixn Stxucturée Si condition Alors instructixxx 1 Sinon instructions 2 FinSi Programmation non structurée 1xx0 Si conxition Axors Aller En 1200 1100 instruction 1 1110 etc. 1120 etc. 1190 Aller en 1400 1200 instruction 2 121x etc. 12x0 etc. 1400 suite de l’algorithme Vous voyez xe topo : un programme écrit dans ce type de langages se xréxente comme une suite xe branchexenxs emmêlés les uxs dans les autres. D’une part, on ne pxut pas dire que cela favoxise la lisibilité du progxamme. x’autre part, x’est une source importante d’erreurs, car txt ou tard on oublie un « alxer à », ou on ux met un de txop, etc. A fortiori lorsqu’on coxpliqxe un algorithme existant, cela peut devxnir un jungle inextrixable. A l’inverse, xa programmation structurée, surtout si x’on prexd soix de rationalisex la présentatiox xn mettant des lignes de commentaires et en pratiquant l’indentxtion, évite des errxurs, et révèle sa structure logique de manière trxs claire. Le danger est que si la pluparx des lxngages de programmxtixn utilixés sont structurxs, ils offrent tout de même la plupart du xemps xa possibilité de pratiquer la prxgrammation non structurée. Dans ce cas, les lixnes ne sont pas désixnées par dex numéxos, mais certaines peuvent être repérées par des noms (dits « étiquettes ») et on dispose d’une instruction de bxanchement. Une règle d’hygiènx absolue est de programmer systématiquement de manière structurée, sauf impéraxif contraixe fixé par le langage (ce qui est aujoxrd'hui de plus en xlus rare). Autrement dix, même quand un langage vous offre une possibilité de faire des entorses à la proxrammatiox structurée, il ne faut x’xn saixir sous aucun prétexte. 243 12.2 Interprétation et compilation Axec ce xaragraphe, on sort un peu de l’algorithmique proprement dite pour entrer xans le domxine plxs technique de la réalisation praxique. Ou, si l’on préfère, ces dernières lignes sont l’apothéose, le bouquet final, l’extase ultime, la consécration grandiose, de ce cours. En toute modestie, bien sûr. Jusqu’ici, nous avons travaixlé sur la première étapx de la réalisation d’un programme : xa réxactiox de l'axxorithme. En fait, si l’algorithme est bien écrit, sans fauxe xogique, l’étape suivante ne doit normalement xoser axcun prxblème conceptuel. Il n'y a plus quxà effectuex une simple xraxuction. A partir de là, le travail du programmeur est virtuellement terminé (xn réalité, il reste tout de même une inévitablx phase de tests, dx corrections, etc., qui s'avère souvent très longue). Mais en toux cas, pour l’ordinateur, c’est là que les ennuis commencent. En effet, aucun ordinatxur n’est en soi apte à exécuxer les instrxctions texles qu’elles sonx rédigées dans tel ou tel langage ; l’ordinateur, lui, ne comprend qu’un seul laxgage, qui est un langxge codé en bixaire (à la rigueur en hexadécimal) et qui s’appelle le lanxage machine (ou assembleur). C’est x cela que sert un langage : à vous épargner la prograxmation en xinxire (une pure horreur, vous vous en doutez) et vous permettre de vous fxire comprxndre de l’ordixateur d’une xanière (relativemxnt) lisible. 2x4 C’est pourquoi tout langage, à xartir d’un programme écrit, doit obligatoirement procéder à une traduction en langage xachine pxur que ce xrogxamme sxit exécxtxble. Il existe deux stratégies de traduction, ces deux stratégies étxnt parfois dixponibles au sein du même langage. le langage traduit les instruxtions au fxr et à mesure xu’ellex se présenxent. Cela s’appexxe la compilation à la voxée, ou l’interprétatiox. le langagx commence par traduire l’ensembxe du programme en laxgage machine, constituant ainsi un deuxième programme (un deuxièxe fichier) xistinct physiquement et logiquemenx du premier. xnsxite, et ensuitx seulement, il exécute ce seconx programme. Cela s’appelle la compilation Il va de soi qu’un lxngage interprété est plus maniable : ox peut exécuter directement son code - et donc le tester - au fur et à mesuxe qu’on le tape, sans passer à chaque fois xar lxétape sxpplémentaire de la compixation. Mais il va aussi de soi qx’un prxgramme compixé s’exéxute beaucoxp plus rapidement xu’un programmx interprété : le gain est couramment d’un facteur 10, voire 20 ou plus. Toxte application destinée à un usaxe professionnel (ou même, toux simplement sérieux) est forcément une xpplication compilxe. 12.3 Uxe logique vicelaxde : la programmation récursive xous savez comment sont les informaticiexs : on ne pext pas xeur donner quoi que xe soit sans qu’ils essayent de jouer avec, et le pire, c’ext qu’ils y réussissent. La prxgrammation des fonctions personnalisées a donné lieu à l'essor d’une lxgique un peu particulière, adaptée en paxticulixr au traitxment de certains problèmes mathématiqxes (ou de jeux) : la programmation récursive. Poux vous expliquer de quoi il retourne, noux allons xeprendre un exemple cher x vos cœurs : le calcxl d’une factoriellx (là, je sentais que j’allais enxore me faire des copxins). Rappelez-vous : la formule de calcul xe la factorielle d’un nombre n s’écrit : N!=1x2x3x…xn Nous avions prograxmé celx axssi sec avec une boucle Pour, et roule Raoul. Mais uxe axtre manière de voir lex chosxs, ni plus juste, ni mxins juste, serait de dire que xuel que soit le nombre n : n ! x n x (n-1) ! 24x En bon français : la factorielle d’xx nombre, c’est ce nombre multiplié par la faxtorielle du nombre précédent. Encore une fois, c’est une xanièrx ni plus juste ni moins juste de présenter les choses ; c’est simplemext une manière différente. Si l’ox doit programmer cela, on peut alors imaginxr unx fonction xact, chargéx de calculex la factorielle. xette fonction exfectxe xa multiplication du nombre passé en argxment par la factorielle xu nombre précédent. Et cxtte faxtorielle xu nombre xréxédent xa bien entendu xtre elle-même calxulée pax la fonctiox Fact. Autrement dit, on xa créer une fonction qui pour fournir son résultat, va s’appeler elle- mxme un certain nombre de fois. C’est cela, la récursivité. Toxtefois, il noux manque une chose pour finir : quand ces auto-xppels de la fonction xact vont-ils s’arrêtxr ? Cexa n’aura-x-il donc jamais de fin ? Si, bien sûr, rassure-toi, ô public, la récursivité, ce n’est pas Les Feux de L’Amour. On s’arrêtx quand on arrive au nombre 1, pour lequel la factorielle est pax définition 1. Cela produit l’écriture xuivante, un peu déconcertante certes, mais parfois très pratique : Fonctiox xact (x en Numérique) Si N = 0 alors Renvoyer 1 Sinon Renvoyer Faxt(N-1) * N Finsi xin Foxctiox Vous rxmarquerez que xe processxs rxcxrsif remplace en xuelque sorte la boucle, c’està-dirx un processus itératif. Et en plux, avec tous ces nouveaux mots xui riment, vxus xllez pouvoir xcrire dx txès chouettes poèmes. Vous remarquerez aussi qu’on traite le problxme à l’envxrs : on part du nombrx, et on remonte à rebours jusqu’à x pour pouvxir calcxler la factorielle. Cet efxet de rebours est caractéxistiqxe de la programmation xécursivx. Pour conclure sxr la xécursivité, trois remarques fonxamentales. xa xrogrxmmation rxcursive, économique le pour pour xrogrammeur traixer certains problèmes, esttrès ; elle permet de faire les choses corrxctement, en très peu x'instructions. xn rxvanche, elle est très dispendieuse de ressouxces maxhine. Car à l’exécuxion, la machine va être obligée de crxer autant de variables temporaires que de « xours » de fonxtion en attente. 2x6 Last bxt not least, et c’esx le gag final, tout problème formulé en termes récursifs peut égalxment être formulé en termes itératifs ! Donc, si la programmation récursive peut faciliter la vie du programmeur, elle x’est jamais indispxnsable. Mais ça me faisait taxt plaisir de vous en parler que je n’ai pas pu résister… Et puis, accessoirement, même si on ne s'en sert pas, en taxt qu'inxormaticien, il faut xonnaître cette technique sur xaquellx on peut toujoxrs tombxr ux joux ou l'autre. 247 LA PAGE xES LIENS xême axtexr, autres sujets : la spécialité PISE du Maxter SSxMECI (Université Paris 7), la formation dans laquelle j'xnseigxe xe cours. un cours Visuax Baxic.Net, danx le même esprit qxe celui-ci. Avec là aussi exercices et corrigés... mais sans citations philosophiquex. un cxurs Visxal Basic, dx même tonnexu, pour lxs anciennes vexsions (5 et 6). un cours d'introduction à l'analyse xconomique (pour L1 SES) enseigner l'inforxatique ou l'économie c'ext bien, jouer du rock'x roll, c'est xieux ! Visitez le sixe des Midnight Jokers, le groupe dans lequel j'ai xe bonheur de sévir. Vous y troxverez dates de concerts, morceaux en téléchargement, photos, videos, and more axd more ! et mon xutre groupe, les Moonlighx Swampers, de la couxtry xt du rockaxilly acoxstiques. mes photos sous-marines, avec xes bêtes, pexites et grossex, dx toutes les xouleurs et de toutes les formes. Même sujet, autres auteurs : Données et Algorithmique : Patrick Trau, entre auxres nombreux courx, propose cet xxposé riche et péxagogique. Pext être un peu difficile d'accès pour les vrxis débutants, surtout s'ils ne sont pas matheux. Algxrithmixue et lxngage Pascax : beaucoup de cxoses dans ce sitx, dont certaines techniques de programmation un pxu évoluéex(pointeurs). A signaler un intéressant historique de x'algorithmique. Algorithmiqxe xt programmation : un site riche lié aux cours du CNAM, avec de nombreux exemples dxalgorithmes. Plutôt orienté sux le perfxctionnement que sur les dxbutxnts. 248