Vous êtes sur la page 1sur 154

Une Introduction au langage C

Cours 1ere Anne 2006-2007

Jean-Jacques Girardot, Marc Roelens


girardot@emse.fr, roelens@emse.fr Septembre 2006

cole Nationale Suprieure des Mines de Saint-Etienne 158 Cours Fauriel 42023 Saint-tienne Cdex

2 Version du 8 septembre 2006.

Premire partie Cours

Introduction
Avant-Propos
Lobjectif gnral de ce cours est lapprentissage de mthodes et outils permettant de rsoudre certains problmes de lingnieur ncessitant un traitement automatis de linformation. Lune des nalits est galement de proposer aux lves entrant en premire anne lcole des Mines de Saint-Etienne une mise niveau en programmation. Il sagit donc, dans un premier temps, danalyser un problme, den proposer un modle, et dtablir une mthode de rsolution possible. Cette phase relve des techniques gnrales de modlisation. Dans un second temps, le modle et la mthode de rsolution choisis sont implments en utilisant efcacement la technologie informatique retenue : lcriture dun programme de traitement en langage C.

0.1 Prambule
0.1.1 Le support de cours
Ce document est une brve introduction la programmation. Pour des raisons qui sont dtailles plus loin, cette introduction seffectue au travers du langage C. Le langage de programmation particulier utilis comme support de la pense dans un cours dinformatique ne devrait jouer quun rle assez secondaire vis vis des concepts enseigns. Ce nest malheureusement presque jamais le cas, et, en particulier dans le cas des initiations linformatique, ce choix du langage joue un rle prpondrant. Lexprience montre que lapprenant est en effet rapidement proccup (voire envahi) par les seuls aspects de mise en uvre du langage choisi, et que les concepts, parfois de haut vol, que lenseignant vise mettre sa disposition sont largement ignors (lorsquils ne sont pas traits par le mpris). Nous voulons construire des programmes solides, et le langage de programmation va nous permettre de crer nos briques. Mais il ne sert rien de construire sur du sable ; la comprhension de la nature et de la structure des donnes, la connaissance de lalgorithmique constituent les fondations de toute construction correcte. Cest un passage difcile, mais oblig. Pour cette raison, nous insistons beaucoup sur les aspects fondamentaux (et en particulier, algorithmiques) de la programmation. Un second cours lui fait suite ([1]), tourn vers les aspects plus formels de lalgorithmique. 5

0.1.2 Le choix du langage


Le choix dun langage de programmation pour une initiation linformatique nest pas, comme on la dj laiss entendre, entirement anodin. Lcole des Mines de Saint-Etienne, qui ne rpugne aucune exprience dans le domaine, a utilis pour ce faire des langages aussi varis que Fortran, Algol 60, APL, Pascal, Scheme, ADA, C, C++, Matlab, Scilab, et probablement quelques autres encore. Quils soient impratifs, fonctionnels, dclaratifs, objets ou enzymes gloutons1, ces langages ont leurs avantages et leurs inconvnients, leurs partisans et leurs dtracteurs, et ont fait parmi les tudiants des heureux, des insatisfaits, et dans tous les cas beaucoup dindiffrents. Ce cours a choisi comme langage support le langage C qui est en lui-mme un petit langage relativement simple apprendre, et comportant peu de concepts. Il constitue une bonne introduction2, pour le programmeur, aux langages objets tels que C++ et Java. Malgr cette simplicit, cest un langage largement utilis dans le domaine industriel : on le trouve ainsi comme langage de dveloppement du systme Unix (et toutes ses variantes) et des utilitaires associs. On lutilise galement dans des applications dinformatique embarque, de contrle de procds industriels, de calculs scientiques, de traitements de donnes diverses. . . Cest enn un langage mature, donc peu soumis des (r)volutions rendant les anciens programmes incompatibles, et disposant sur quasiment toutes les plates-formes denvironnements de dveloppement performants (et du domaine public, ce qui est un avantage non ngligeable). Le langage C, bien sr, ne prsente pas que des avantages. Conu pour permettre au programmeur dutiliser de manire efcace la machine sous-jacente, il impose son utilisateur : de connatre larchitecture gnrale dun ordinateur, an de comprendre comment ces concepts se matrialisent dans ce langage de programmation ; de savoir manipuler le systme dexploitation, puisque, C tant un langage compil, la mise en uvre dun programme ncessite une squence doprations non triviales pour le nophyte. Le chapitre 1 a donc pour objectif annexe de prsenter la structure dun ordinateur (du matriel jusquau logiciel), et de dcrire sommairement la mise en uvre du langage C sur le systme le mieux adapt : UNIX, et en loccurence, Linux

0.2 La nalit de ce cours


Ce document a pour but de prsenter des techniques danalyse permettant de passer, par tapes successives, dun problme, nonc en franais, un programme rsolvant ce problme, crit dans le langage choisi pour cet apprentissage, savoir le langage C. Le lecteur averti pourra aisment transposer les concepts tout langage du mme genre que C, cest--dire un langage de type procdural, intgrant la notion de fonctions (ou procdures, ou sous-programmes), ainsi que la possibilit de crer des structures de donnes : Pascal, C++, VBA, sont des langages ne posant pas de problme ce niveau.
1 2

Terme de remplissage, utilis ici en attendant la prochaine rvolution. . . Ne serait-ce que par sa syntaxe. . .

0.3. DROULEMENT DU COURS

Cette prsentation sappuie largement sur des exemples, simples au dpart, puis de plus en plus complexes. Il est difcile en effet de prsenter demble la mthodologie universelle ( supposer quil en existe une) : ceci, notre avis, ne revt un intrt quaprs une certaine pratique effective de la rsolution de problmes de complexit non triviale. Dans cette prsentation sont successivement abordes diffrentes facettes de cette analyse, savoir lalgorithmique, la structuration par les traitements et la structuration par les donnes. Il faut bien comprendre que ce qui est prsent ne revt pas le caractre de rgles absolues : ne pas les suivre ne condamne pas ncessairement obtenir des programmes incorrects. Cependant, les suivre permet dobtenir des programmes plus facilement comprhensibles par quelquun qui ne les a pas crits3 , et amliore donc la maintenance de ceux-ci (que ce soit pour corriger ou pour amliorer le programme). On est donc ici plutt dans le domaine des bonnes pratiques.

0.3 Droulement du cours


Le cours Introduction linformatique comporte six sances de trois heures, la dernire tant entirement consacre la programmation complte dmini-projet. Ce petit support de cours recouvre les cinq sances dintroduction au langage C. Chaque sance comporte une phase magistrale, et une phase de travaux dirigs et pratiques.

0.3.1 Sance 1 : introduction au matriel et au logiciel


But Savoir diter, compiler et excuter un programme ; apprendre la syntaxe des expressions arithmtiques. Thorie Prsentation de notions sur linformatique, les machines, les algorithmes, les environnements de dveloppement. Introduction au langage C : premiers lments de syntaxe, types de donnes (entiers, rels, caractres) ; reprsentation des donnes ; variables ; expressions. Pratique Matriser un environnement de programmation. Dmonstration de lenvironnement. Le clbre programme Salut, monde .

0.3.2 Sance 2 : quelques problmes lmentaires


But Comprendre les notions de variable, dexpression, et les itrations (boucles et tests) Modlisation de problmes.

Thorie

Pratique Partir dun problme simple, (calculer un PGCD, un sinus), en dcrire les tapes de la rsolution.
3

ou ne les a pas relus depuis un moment. . .

0.3.3 Sance 3 : procdures


But Comprendre la notion de procdure. Description et appel de procdure. Passage de paramtres. Prototypes des procdures.

Thorie

Pratique tapes de la cration dune application : dcomposition en procdures. Procdures et compilations spares. Utilisation de procdures de bibliothque correspondant aux fonctions mathmatiques usuelles.

0.3.4 Sance 4 : tableaux


But Les tableaux. Oprations simples sur tableaux. Tableaux deux dimensions, ou matrices.

Thorie

Pratique Recherches de minimums, maximums, etc. Remplissage de tableau par des valeurs alatoires. Exemple du calcul des moyennes.

0.3.5 Sance 5 : du problme au programme


But Savoir traiter un problme plus complexe.

Thorie Analyse de problme, dcomposition en sous-problmes par les donnes ou par les traitements. Pratique Analyse, conception du problme trait en mini-projet.

0.3.6 Sance 6 : une application


But Sance dintgration pour obtenir le logiciel dont la ralisation est vise dans le cadre du cours. Pratique Prsentation de quelques principes de mise au point.

0.4 Informations en ligne


De nombreuses informations (complments de cours, exercices corrigs, rfrences bibliographiques ou Internet, copies de supports de cours) sont disponibles sur le site Internet du cours informatique : http://kiwi.emse.fr/INTROINFO/

0.5. NOTES TECHNIQUES

0.5 Notes techniques


Ce support de cours a t rdig par Jean-Jacques Girardot et Marc Roelens partir de divers documents antrieurs. Le document lui-mme a t cr sous sous Linux, au moyen de LYX ([3]), un diteur de A document qui fournit un interface WYSIWYM avec TEX et L TEX ([2]).

10

Chapitre 1 Introduction
1.1 Cours
Ce premier chapitre introduit les diverses notions de linformatique pratiquement indispensables la comprhension de lactivit de programmation : ce quest un ordinateur, un chier, un compilateur, et comment mettre en uvre toutes ces choses. . . Aprs cette prsentation sommaire, le cours dcrit quelques lments de base du langage C ainsi que lutilisation de celui-ci sur les machines.

1.1.1 Modle de lordinateur


1.1.1.1 Architecture dun ordinateur

PROCESSEUR
A

bus

MMOIRE

F IG . 1.1 Larchitecture de Von Neumann Les ordinateurs actuels drivent dune architecture dnie en 1946, la Machine de von Neumann (c.f. gure 1.1). Les deux composantes principales sont le processeur (ou unit centrale) et la mmoire, relis entre eux par le bus. Dans cette machine, le problme rsoudre est dcrit sous la forme dinstructions excuter, le programme. Lexcution dun programme est dite processus. La mmoire de la machine contient la fois les instructions et les donnes du processus. Le jeu dinstructions du processeur nest pas universel, mais dpend du modle de la machine. Dautres lments sont connects au bus, ou des bus auxiliaires : les priphriques (cran, clavier, souris, imprimante, modem, scanner, disque dur, lecteur de disquette, de cdrom, etc.), qui permettent la communication avec le monde extrieur et le stockage de linformation. Ces lments sont commands par des instructions spciques du processeur. 11

12 1.1.1.2 La mmoire

CHAPITRE 1. INTRODUCTION

La mmoire dun ordinateur, dite parfois mmoire centrale, peut tre considre comme un espace linaire dlments identiques, les cellules de mmoire. Les lments dune mmoire de taille N sont dsigns par leurs index, entiers de lintervalle [0, N 1]. On appelle galement adresse mmoire lindex dsignant une cellule mmoire. Dans les architectures actuelles, ces cellules sont reprsentes par le regroupement, dit byte ou octet, de huit indicateurs lmentaires, les bits, pouvant avoir chacun la valeur 0 ou 1. Un byte peut donc coder 28 valeurs diffrentes. En langage C, une telle donne permet de reprsenter : soit les valeurs entires comprises entre -128 et +127 (ce qui est appel en C le type char)1 ; soit les valeurs entires comprises entre 0 et 255 (ce qui est appel type unsigned char en C). Selon les besoins du programmeur (et selon les langages de programmation), les cellules de mmoire peuvent tre regroupes (par 2, 3, 4, 8, 16...) pour reprsenter des donnes entires (pouvant prendre de plus grandes valeurs), mais galement des donnes virgule xe ou ottante, des caractres imprimables, des chanes de caractres... 1.1.1.3 Le processeur Le processeur excute des programmes situs en mmoire centrale. Ces programmes comportent des donnes et des instructions destines transformer ces donnes. Une partie du processeur est lunit arithmtique et logique, dont le but est deffectuer diverses instructions de calcul. Le processeur dispose dun petit nombre demplacements de mmoire accs trs rapide (dit registres, au nombre de 16, 32, etc.), qui lui permettent de stocker temporairement des valeurs dlments, et deffectuer des oprations sur ces valeurs (le processeur ne peut effectuer aucune opration directement sur le contenu dune cellule mmoire). 1.1.1.4 Communication entre processeur et mmoire Par lintermdiaire du bus, le processeur peut indiquer une adresse mmoire et lire le groupe dlments (des octets, 2, 4, 8, 16, etc., selon les machines) situs cette adresse. Les valeurs lues sont places dans un ou plusieurs registres du processeur. Celui-ci est ainsi capable de lire les instructions et les donnes lorsque ncessaire. Le processeur peut galement effectuer le transfert dune donne contenue dans un registre vers une cellule mmoire. 1.1.1.5 Les disques durs Les disques durs sont des units de stockage de linformation de grande capacit (dix cent fois la taille de la mmoire centrale), dont le rle est dassurer la conservation permanente des
Trs prcisment, nous devrions crire signed char ; lattribut signed est presque toujours pris par dfaut par le compilateur lorsque unsigned nest pas prcis.
1

1.1. COURS

13

programmes et donnes de lutilisateur. Ces informations sont organises sous la forme dun ou plusieurs systmes de chiers. 1.1.1.6 Les systmes de chiers Un systme de chiers (ceci est vrai pour Unix, Linux, Windows, etc.) est une organisation auto-dcrite, qui comprend deux types dobjets : les rpertoires et les chiers. Un chier est une squence doctets, dsigns globalement par un nom. Ces octets permettent de reprsenter des donnes de lutilisateur ou du systme. Un rpertoire contient des dsignations symboliques (les noms) de chiers ou dautres rpertoires. Il existe dans tout systme de chiers un rpertoire particulier, qui est la racine de ce systme de chiers. Tout chier est dsign par un nom rfrenc dans un rpertoire, et un seul. Tout rpertoire est dsign par un nom, rfrenc dans un autre rpertoire, ou dans la racine. Rpertoires et chiers constituent ainsi une arborescence. Une rfrence un chier particulier (lon parle parfois de cheminom ) se note par la liste des rpertoires quil faut traverser, depuis la racine, pour aboutir ce chier. La syntaxe de cette dsignation dpend des systmes dexploitation. Sous UNIX ou Linux, cest le caractre "/" (slash) qui sert de sparateur. On crira : /users/dupont/exemples/prog17.c Le systme de chiers porte ici le nom users ; le premier slash indique que lensemble a la syntaxe dune rfrence absolue. Sous Windows, cest le caractre "\" qui sert de sparateur ; la dsignation dbute par le nom du disque sur lequel se situe le systme de chiers : c:\users\dupont\exemples\prog17.c Un systme de chiers peut tre install sur un disque dur, mais aussi un CD-ROM, une disquette (sur laquelle lespace disponible est limit 1,44 millions doctets), etc. Fichiers et rpertoires sont dsigns par des noms, qui sont habituellement des suites de lettres et de chiffres. Certains systmes sont trs restrictifs, tels Dos, qui impose des dsignations de la forme XXXXXXXX.YYY , cest--dire huit caractres, le nom proprement dit, suivis dun point, suivis de trois caractres, l extension . Dautres systmes acceptent, avec certaines restrictions, des suites arbitraires de caractres (Mac OS, Windows). Sous UNIX ou Linux, il est possible dutiliser de tels noms, condition de les placer entre caractres quotes ou apostrophes . Nous conseillons pour notre part dutiliser des noms relativement courts (huit lettres, ou moins), constitus de lettres et de chiffres. On vitera en particulier dutiliser, pour les noms de chiers et de rpertoires, des blancs, caractres accentus, et autres signes exotiques. Notons que lextension (le sufxe de la dsignation dun chier) joue un rle important dans la comprhension par lutilisateur de la nature des chiers. Ainsi, les extensions ".c" et ".h" sont rserver pour les programmes crits en C, les chiers ".o" reprsentent des modules objets, rsultats de la compilation dun module source, les ".txt" des chiers de textes, les ".doc" et ".rtf" sont des chiers crs par lutilitaire Word , etc. Sous Windows, mais cette convention ne sapplique pas sous Unix ou Linux, les ".exe" reprsentent des programmes

14

CHAPITRE 1. INTRODUCTION

excutables. Dans certains cas, le systme dexploitation utilise cette extension pour savoir quel programme associer tel chier. Lon voit, par ces derniers exemples, que les chiers rpondent de multiples nalits. De manire trs gnrale, on peut dire quils constituent un support prne 2 linformation. Ils permettent de reprsenter le systme, les informations de lutilisateur, et tout un ensemble de donnes utilises temporairement par le systme ou les programmes de lutilisateur : les zones de travail des diteurs de texte et des compilateurs, les mails envoys ou reus, etc. 1.1.1.7 La programmation des ordinateurs La programmation dun ordinateur se ralise travers le langage machine, qui est complexe et propre chaque modle dordinateur. Lon utilise dans la pratique des langages de haut niveau, tels le C, le Fortran, le Java, etc., qui sont universels. Le plus souvent, un programme spcialis, dit traducteur ou compilateur, transforme le programme ralis en un programme en langage machine spcique lordinateur sur lequel on travaille : cest le processus de compilation. 1.1.1.8 Le systme dexploitation Le systme dexploitation est un complment indispensable lutilisation de tout ordinateur. Il a pour tche de grer les ressources de lordinateur (processeur, mmoire, et surtout priphriques) et de fournir un support lutilisateur, en contrlant lexcution des programmes et utilitaires (compilateur, diteur de texte, etc.). Le systme dexploitation est automatiquement charg en mmoire centrale lors de la mise sous tension de lordinateur, et va ds lors grer le fonctionnement de celui-ci. 1.1.1.9 Lenvironnement de travail Lenvironnement de travail, enn, est lindispensable intermdiaire entre lutilisateur et les ressources de la machine et du systme. Il permet lutilisateur de dclencher lexcution de programmes prexistant sur la machine, dont le rle est de rendre celle-ci utilisable sous une forme conviviale, que ces programmes aient pour but de consulter le Web, lire ou crire du courrier, crer des chiers, des documents, ou dautres programmes. Lenvironnement de travail peut offrir un systme de multi-fentrage (Windows, Gnome sous Linux, etc.) faisant grande consommation des interactions souris, ou un mcanisme bas sur des lignes de commandes telles que : gcc -o prog prog.c Lune des interfaces les plus simples permet uniquement de saisir des lignes tapes au clavier ; chaque ligne est cense reprsenter une commande excuter. Nous disposerons sous Windows dun interprte lmentaire (de nom invite de commande ou parfois bote MS-DOS ), et galement dun interprte plus volu, appel bash. Lon utilise souvent le terme gnrique de shell pour dsigner ces interfaces.
Plus simplement dit, leur contenu perdure lors de la mise hors-tension de lordinateur, alors que celui de la mmoire centrale et des registres de la machine disparat.
2

1.1. COURS
1.1.1.10 Fonctionnement gnral et processus dexcution

15

Parmi les registres du processeur, il en existe un, dit compteur programme, qui dsigne tout instant une adresse en mmoire centrale : cest celle de la prochaine instruction excuter. Lors de lexcution, le processeur effectue les oprations suivantes : 1. il va chercher, dans la mmoire centrale, linstruction dsigne par le compteur programme, et la place dans un registre (dit registre instruction) ; 2. il incrmente le compteur programme, an que celui-ci dsigne linstruction suivante ; 3. il dcode linstruction, vriant quelle est correcte ; 4. il va ventuellement rechercher en mmoire centrale le, ou les oprandes dsigns par linstruction, et les place dans des registres ; 5. il excute linstruction ; cette instruction peut impliquer la modication de certains registres, y compris le compteur programme ; on dit alors que linstruction est un saut, ou un branchement. 6. il va ventuellement crire en mmoire le contenu dun ou plusieurs registres ; 7. le cycle se continue par un retour ltape 1. Le cycle dexcution est le mme, que le processeur soit en train dexcuter des instructions du systme dexploitation, de lenvironnement de lutilisateur, ou du programme de lutilisateur. 1.1.1.11 Notion de variable La mmoire centrale ne contient pas que des instructions, mais sert aussi reprsenter les donnes manipules par le programmeur. Quand le programmeur souhaite utiliser une ou plusieurs cellules mmoire pour stocker une information utile pour le programme, il doit : dterminer le nombre de cellules utiles, cest--dire la taille de la donne ; trouver un emplacement non utilis dans la mmoire permettant de stocker cette donne (suite de cellules contigus en mmoire, de la taille de la donne stocker) ; mmoriser lemplacement (ladresse en mmoire) de la donne pour les manipulations venir ; rserver cet emplacement mmoire an dviter que dautres donnes nutilisent le mme emplacement ; utiliser les bonnes instructions dchange entre le processeur et la mmoire (transfrer le bon nombre doctets, utiliser le bon registre). Ces oprations deviennent trs fastidieuses lorsque la taille du programme (et donc, le nombre de donnes utilises) augmente. La plupart des langages de programmation intgrent donc une gestion des donnes par lintermdiaire dun moyen abstrait : la plupart du temps, ce moyen abstrait est un identicateur, qui est tout simplement un nom choisi par le programmeur. Dans le programme source (en langage de haut niveau), la donne est manipule par son nom ; cest au moment de la traduction en langage machine que le traducteur (le compilateur dans le cas du langage C) effectuera une association entre le nom et lemplacement effectif en mmoire. Toutes les instructions qui manipulent la donne utiliseront lemplacement mmoire associ cette donne. Ces associations nom-emplacement mmoire sont dsignes par le terme

16

CHAPITRE 1. INTRODUCTION

de variables : ce nom prcise que le contenu de la mmoire peut en particulier tre modi par le programme ; la valeur dune variable peut donc changer au cours de lexcution.

1.1.2 Reprsentation des informations


Pour reprsenter des donnes complexes, les octets sont frquemment regroups par deux, quatre, huit. Les conventions de reprsentation de ces donnes complexes dpendent des choix des constructeurs, mais restent en gnral transparentes aux programmes crits dans des langages de haut niveau, tels que le C. Ainsi, les valeurs entires manipules par les programmes sont souvent reprsentes par le regroupement de quatre octets, fournissant 2 32 combinaisons diffrentes. Les entiers ainsi reprsents sont habituellement ceux de lintervalle [231 , 231 1], soit encore [2147483648, 2147483647]. En langage C, une telle donne est dite de type int. Les entiers ne conviennent pas pour toutes les applications. Le calcul scientique ncessite la reprsentation de valeurs relles, pouvant tre trs grandes ou trs petites, avec une partie dcimale, etc. Les machines offrent de telles reprsentations (qui approximent les nombres rels par des fractions dont le dnominateur est une puissance de deux), toujours en utilisant des regroupements doctets. Ces donnes sont dites float et double dans le langage C, et utilisent en gnral 4 et 8 octets respectivement. Enn, les informations le plus frquemment manipules par les applications sont de type alphanumrique. Les ordinateurs utilisent tous pour les lettres, chiffres et certains caractres, une reprsentation normalise dite code ASCII, comportant 128 lments. La table 1.1 en donne 000 001 010 011 100 101 110 NUL DLE SPACE 0 @ P SOH DC1 ! 1 A Q a STX DC2 " 2 B R b ETX DC3 # 3 C S c EOT DC4 $ 4 D T d ENQ NAK % 5 E U e ACK SYN & 6 F V f BEL ETB 7 G W g BS CAN ( 8 H X h HT EM ) 9 I Y i LF SUB * : J Z j VT ESC + ; K [ k FF FS , < L \ l CR GS = M ] m SO RS . > N ^ n SI US / ? O _ o TAB . 1.1 Le code ASCII 111 p q r s t u v w x y z { | } ~ DEL

0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

1.1. COURS

17

la composition et la codication ; les caractres de cette table sont reprsents par des octets, le premier bit de loctet tant 0, les trois suivants le numro de colonne et les quatre suivants le numro de ligne (par exemple, la lettre A est reprsente par la suite binaire 01000001). Un mot, une phrase, un texte sont ainsi reprsentables par une squence doctets. On parle souvent de chane de caractres pour dsigner de telles squences, et les langages de haut niveau disposent de notations spciques pour dnir de telles squences. Le code ASCII ne reprsente cependant quun sous-ensemble trs limit des caractres ncessaires lexpression crite, et dautres normes sont utilises pour la reprsentation des langages indo-europens, du japonais, etc. Malheureusement, ces normes sont multiples, et rien ne garantit la portabilit si ces caractres sont utiliss. Nous retiendrons donc que, pour ne pas avoir de souci, il est : impratif de nutiliser que des caractres du code ASCII pour construire notre code source (instructions, variables, procdures) ; prfrable dviter les caractres non-ASCII (et notamment les caractres accentus) dans les commentaires de programmes, ainsi que dans les chanes de caractres.

1.1.3 Mise en uvre dun programme


1.1.3.1 Quest-ce quun langage de programmation ? Ncessaire (et ennuyeux) intermdiaire entre lhomme et la machine, ltape de programmation consiste rdiger la description dune mthode de rsolution dun problme en une forme comprhensible pour la machine. Cette description implique que lon connaisse la mthode pour rsoudre le problme, lalgorithme, et que lon matrise le langage de programmation choisi. 1.1.3.2 Les tapes de la vie dun programme Un programme3 , toujours conu aprs moultes rexions, va dabord tre cr par lutilisateur sous la forme dun programme source, cest--dire un ou plusieurs chiers contenant le texte du programme, crit dans le langage de haut niveau choisi, C en loccurrence. Ce travail est effectu au moyen dun diteur de texte. Sous Windows, nous utiliserons par exemple lutilitaire NotePad, en sauvegardant le programme sous un nom tel que prog.c (le sufxe .c indique que le chier contient un programme C). Sous Linux, des outils tels que Gedit ou KWrite constituent de bons choix comme outil pour dbuter. Lutilisateur averti, pour sa part, optera souvent pour des logiciels tels que vi ou emacs. Lorsque le programme est termin, et prt tre test, nous allons le compiler, cest--dire le transformer en un programme objet, qui est une reprsentation interne, propre la machine, des instructions traduites par le compilateur, mles diverses autres informations. Cette traduction fournit un chier dit objet, dont le nom va tre prog.o. En vue dune excution ultrieure, il convient dajouter ce chier des utilitaires du systme, qui permettent, entre autres fonctions, dexcuter les lectures et critures ncessites par le programme. Cette seconde phase est dite dition des liens, et fournit un chier reprsentant le programme excutable, de nom prog. Ces
3

Nous nous limitons ici au cas traditionnel des langages compils.

18

CHAPITRE 1. INTRODUCTION

deux tapes (compilation et dition des liens) peuvent senchaner directement par la commande unique : gcc prog.c -o prog Enn, lexcution proprement dite seffectue en entrant simplement le nom du programme excuter : prog On notera que si lon travaille sous Windows, le programme doit obligatoirement comporter un sufxe spcique, indiquant quil est excutable, .exe. La commande de compilation scrit alors : gcc prog.c -o prog.exe Le lancement peut seffectuer par le seul nom prog. Dans ce cas particulier, linterprte de commandes va rechercher le chier de nom prog.exe ou prog.com ; les deux sufxes correspondant deux formats dexcutables reconnus par Windows. Note Le compilateur C opre en fait en plusieurs phases : la compilation proprement dite est prcde dune excution dun prprocesseur, dont le rle sera explicit ultrieurement, et qui sert principalement insrer automatiquement des dclarations permettant au programmeur de faire appel aux oprations dentres-sorties dans son programme.

1.1.4 Un premier programme C


#include <stdio.h> #include <stdlib.h> int main(int argc, char * argv[]) { puts("hello world") ; return 0 ; } F IG . 1.2 Premier programme C La gure 1.2 prsente un premier programme C complet. Ce programme contient les lments suivants : Une premire ligne, destine au prprocesseur : #include <stdio.h> La syntaxe de cette ligne doit tre scrupuleusement respecte. Le caractre dise, #, lorsquil est le premier caractre de la ligne, indique une ligne destine au prprocesseur C ; la commande demande linclusion, dans le programme qui va tre compil, du chier stdio.h qui contient des dclarations permettant de faire appel aux oprations

1.1. COURS

19

dentres-sorties standards du langage C. Le sufxe .h indique quil sagit dun chier dinclusion (en anglais, header ). De mme, la ligne suivante demande linclusion des dclarations des procdures utilitaires de base du langage. Il est raisonnable de la placer systmatiquement dans tout programme C. Le programme C est constitu dinstructions places lintrieur de la construction, entre les accolades : int main(int argc, char * argv[]){ ... } Ces instructions vont tre excute en squence. La premire : puts("hello world") ; constitue un appel de la procdure4 puts qui afche sur le terminal une chane de caractres. Celle-ci est dnie, dans le langage C, par la suite des caractres qui la composent, place entre doubles apostrophes. Cette chane est transmise la procdure puts, ce que lon indique par les parenthses suivant le nom de la procdure. Le point virgule termine linstruction. La seconde instruction : return 0 ; permet larrt du programme. Cest en fait un ordre de sortie dune procdure (dans ce cas, la procdure main) et de retour lappelant (en loccurrence, de retour au systme dexploitation), qui permet ici lapplication de spcier un code de retour, qui est une valeur numrique entire. La valeur 0 indique une terminaison normale du programme. Les autres valeurs indiquent des ns anormales. Ce code de retour peut tre test par les langages de commandes. Insistons immdiatement sur le fait que linstruction return permet de quitter une procdure et de revenir la procdure appelante, et ce nest que lorsquelle est utilise depuis le main quelle permet darrter le programme. Une autre manire darrter un programme est dutiliser un appel de la procdure exit, sous la forme : exit(0) ; La procdure du systme exit transmet au systme une indication sur la terminaison du programme : le nombre 0 indique ici une terminaison juge normale par le programmeur. L galement, le point-virgule termine linstruction. Notes : nous respecterons la lettre la notation : int main(int argc, char * argv[])
Une procdure est un ensemble dinstructions rpondant une nalit prcise. Beaucoup sont prdnies dans le systme ; nous verrons au chapitre 3 comment les dnir en C.
4

20

CHAPITRE 1. INTRODUCTION

Elle permet en effet de dclarer quil sagit du programme principal : ceci permet au moment du lancement du programme de savoir quelle est la premire instruction excuter (ce nest pas la premire instruction qui apparat dans le code source). Ce programme principal communique avec son environnement au moyen des deux variables argc et argv, et que ce programme fournira au systme un code de retour sous la forme dun int. Tout ceci sera expliqu en dtail ultrieurement, mais retenons toutefois que cest ainsi que doit tre dclar tout programme C conforme. nous prendrons lhabitude de terminer systmatiquement nos procdures main par une instruction return x ; ou exit(x) ; Lexcution du programme sous Linux est prsente la gure 1.3, tandis que la gure 1.4 nous montre la mme opration sous Windows. [P]$ gcc prog1.c -o prog1 [P]$ prog1 hello world [P]$ F IG . 1.3 Excution du programme sous un shell Linux

C:\temp> gcc prog1.c -o prog1.exe C:\temp> prog1.exe hello world C:\temp> F IG . 1.4 Excution du programme sous un shell Windows

Notes : Limpression du message hello world est suivie dun passage la ligne ; celui-ci est automatiquement ajout par la procdure puts. Sous Windows, lutilisation du sufxe .exe est obligatoire, pour indiquer quun chier reprsente un programme excutable. Sous Linux, un autre mcanisme est utilis pour reprer les programmes excutables, et lutilisation dun tel sufxe nest pas ncessaire. Cependant, pour des raisons de scurit, Linux naccepte dexcuter que les programmes situs dans un ensemble prdnis de rpertoires (ensemble dsign par le contenu de la variable du Shell PATH. Sil nest pas dclar que le rpertoire courant fait partie de cet ensemble, il faut utiliser une notation telle que : [P]$ ./prog1 pour lancer lexcution du programme.

1.1. COURS

21

#include <stdio.h> int main(int argc, char * argv[]) { float diametre=12.25 ; float pi=3.1415926535 ; float surface ; surface = pi*(diametre/2)*(diametre/2) ; printf("La surface du disque de diamtre %f est %f\n", diametre, surface) ; return 0 ; } F IG . 1.5 Surface dun disque

1.1.5 Un second exemple


La gure 1.5 propose un autre exemple, calculant la surface dun disque dont le diamtre est donn. Nous avons donc besoin dans ce programme de reprsenter au moins deux donnes : le diamtre et la surface calcule. Ces donnes doivent tre reprsentes par des nombres en virgule ottante (il nexiste aucune raison particulire pour que ce soient des entiers), ce qui en C sappelle le type float ; nous dnommerons ces variables diametre et surface. Nous reprsenterons galement la valeur de par une variable dnomme pi. Ce programme contient alors les lments suivants : comme dans le cas prcdent, linclusion des dclarations ncessaires aux entres-sorties ; la dclaration "habituelle" de la fonction main ; les dclarations des trois variables de type float, deux dentre elles recevant une valeur initiale ; remarquons la syntaxe dune dclaration de variable : nomdetype nomdevariable[=valeurinitiale]; la valeur initiale tant optionnelle ; lorsque plusieurs variables sont de mme type, on peut les dclarer par une seule instruction, et les trois dclarations pourraient tre remplaces par : float diametre=12.25,pi=3.1415926535,surface; un nom de variable (ce que lon dsigne souvent par le terme didenticateur) peut comporter des caractres alphabtiques (attention, non accentus) minuscules ou majuscules, des chiffres (sauf en premire position) ou le caractre _ ; les instructions proprement dites : la premire calcule la surface du disque, elle utilise les variables diametre et pi (dans la partie droite du signe gal), et la variable surface (dans la partie gauche du signe gal) ; elle met en uvre une opration appele affectation, dont la syntaxe est variable = expression Son rle est de stocker dans la case mmoire associe la variable la valeur de lexpression : le contenu de la case mmoire est ainsi modi.

22

CHAPITRE 1. INTRODUCTION

Lexpression elle-mme fait appel aux oprations de multiplication et division (reprsentes par * et / respectivement), et aux parenthses servant regrouper des calculs. Dans cette expression apparaissent galement des noms de variables : dans ce cas, on calcule la valeur de lexpression en remplaant le nom de la variable par le contenu de la case mmoire qui lui est associe. la seconde afche le rsultat au moyen dune procdure du systme, printf, qui permet limpression de messages et de valeurs numriques. Notons le fonctionnement de printf. Il y a ici trois paramtres, spars par des virgules, le tout tant entre parenthses. le premier paramtre, une chane de caractres, dcrit de quelle manire lafchage doit seffectuer ; dans cette chane : un caractre autre que % est imprim tel quel. le caractre % introduit la description dun afchage : %f indique que lafchage correspond un nombre de type float. enn, \n est une convention dcriture qui permet de reprsenter, lintrieur dune chane, le caractre LF (line-feed, ou passage la ligne), de code ASCII 00001010. Limpression de ce caractre provoque un passage la ligne. les autres paramtres reprsentent les valeurs imprimer ; la premire spcication dafchage de la chane, ici %f, dcrivant comment simprime la premire valeur (le contenu de la case mmoire associe la variable diametre), la seconde spcication (encore %f) sappliquant la seconde valeur (le contenu de la case mmoire associe la variable diametre, etc. Signalons, toujours propos de printf, que %f fournit un afchage par dfaut ; une notation telle que %12f indique que lon dsire que lafchage du nombre occupe 12 caractres au moins (mais plus si ncessaire), et %12.4f prcise que lon veut en outre exactement 4 chiffres aprs la virgule. la syntaxe des lignes est relativement souple ; des blancs, ou des passages la ligne, peuvent tre insrs (sauf lintrieur des mots-clefs, identicateurs de variables et constantes) an daugmenter la lisibilit des programmes. Le rsultat afch par le programme est : La surface du disque de diamtre 12.250000 est 117.858818 Note importante : on a indiqu que toutes les dclarations de variables doivent prcder toutes les instructions ; mme si certains compilateurs tolrent un entrelaage des instructions et des dclarations, cette pratique ne doit en aucun cas tre recommande !

1.1.6 Types et variables en C


1.1.6.1 Types scalaires Le langage C utilise des mots-clefs spciques pour dsigner les types de donnes de base, que lon nomme parfois types scalaires, manipuls dans le langage. Le tableau 1.2 dcrit ceux que nous utiliserons le plus frquemment. Quelques commentaires sur ce tableau :

1.1. COURS
Mots clefs int long short char long long float double long double Description entier entier entier entier entier ottant ottant ottant Taille sur nos machines 4 octets 4 octets 2 octets 1 octet 8 octets 4 octets 8 octets 12 ou 16 octets

23

TAB . 1.2 Types de donnes du langage C les tailles indiques dpendent des machines et des compilateurs. Lopration sizeof() permet de connatre la taille en nombre doctets dune donne ou dun type de donne. La norme du langage prcise simplement que : sizeof (char ) sizeof (short) sizeof (int) sizeof (long ) sizeof (f loat) sizeof (double) sizeof (longdouble) tout type entier peut tre prcd du mot-cl unsigned qui indique que le type doit tre considr comme non-sign , cest--dire positif ; un type sign sur p bits (8, 16, 32 ou 64) permet de coder les valeurs entires allant de 2p1 2p1 1, le type non-sign permet de coder les valeurs entires allant de 0 2p 1 ; long et short sont en fait des abrviations pour long int et short int, qui sont des critures autorises ; le type long long est une extension non normalise (le compilateur signale ce problme si lon utilise les options -ansi -pedantic -Wall) ; les types ottants utilisent une reprsentation normalise (dite IEEE-754) permettant de coder des nombres virgule ottante ; le type float et double sont des types standards, le type long double est une extension dont la taille dpend de lenvironnement de dveloppement (12 octets par dfaut sous Linux, 16 octets sous Solaris ou IRIX, 16 octets sous Linux avec option de compilation particulire) ; les prcisions relatives des ces reprsentations (qui sont des reprsentations approches des nombres rels) sont de lordre de 107 pour le type float, de 1016 pour le type double et de 1032 pour le long double sur 16 octets. 1.1.6.2 Constantes Le langage C permet dutiliser des constantes numriques dans le code source. Les formats de ces constantes sont prciss ci-dessous : constantes entires notation dcimale : succession de chiffres ventuellement prcde dun signe 12 -123 +345

24

CHAPITRE 1. INTRODUCTION
notation octale : succession de chiffres commenant par 0 0123 077770 notation hexadcimale : succession de chiffres prcde des caractres 0x ou 0X ; les chiffres hexadcimaux sont les chiffres de 0 9, ainsi que les lettres de a (ou A) f (ou F) 0x101 0XFADA 0xBeef notation caractres : succession de caractres entre quotes ; criture en base 256, chaque caractre reprsentant son code ASCII ; le plus souvent limite un seul caractre a ab 12b 1234 constantes ottantes un signe ventuel, une partie entire (succession de chiffres dcimaux), un point ., une partie dcimale (succession de chiffres dcimaux), un exposant ventuel constitu de la lettre e ou de la lettre E, suivi dun signe ventuel et dun entier dcimal 1.34 -1. +0.45 .37 1e-10 -1.23E+9 +.12E-2

1.1.6.3 Arithmtique mixte Le mlange de valeurs entires et ottantes (constantes, variables) est autoris dans une expression numrique. Lorsquun oprateur est utilis avec des oprandes de types diffrents (entier et ottant), la valeur entire est convertie en valeur ottante avant lapplication de loprateur. Ainsi, dans le programme de calcul de la surface dun disque (g. 1.5 page 21), lexpression diametre/2 est quivalente diametre/2.0. Cependant, dans un calcul tel que i/2*f, o i est un entier et f est un ottant, le calcul intermdiaire i/2 seffectue en entier, puisque les deux oprandes de la division sont des entiers, et cest une division entire qui est excute. Donc, si i a la valeur 7 et f la valeur 3.5, i/2*f fournit comme rsultat 10.5, tandis que f*i/2 fournit 12.25... 1.1.6.4 Variables et adresses On a indiqu que le compilateur, lorsquil trouve une dclaration de variable, va rserver un emplacement mmoire pour stocker la donne : cest que lon appelle ladresse mmoire de cette donne. Le langage C offre la possibilit davoir accs cette adresse : il suft pour cela dutiliser loprateur du langage & (ampersand en anglais, esperluette en franais, parfois dsign par la locution et commercial )5 devant le nom de la variable. La procdure printf prcdemment mentionne possde un format spcique %p permettant dafcher une adresse. Ainsi, le petit programme ci-dessous : #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[])
5

Voir lURL http ://www.adobe.fr/type/topics/theampersand.html

1.1. COURS
{ int i = 1, j = 2; printf("i=%d, adresse(i)=%p\n",i,&i); printf("j=%d, adresse(j)=%p\n",j,&j); exit(0); } donne lexcution : i=1, adresse(i)=7fff2ee0 j=2, adresse(j)=7fff2ee4

25

On notera que le dcalage entre les deux valeurs (afches dans un format hexadcimal) est de 4 octets, correspondant bien la taille en mmoire dun entier. De plus, le langage C permet galement de manipuler des variables de type adresse. Pour dclarer une telle variable, on fera prcder le nom de la variable du caractre *, comme par exemple : int i=2,*j; qui dnit une variable i de type int (de valeur initiale 2), et une variable j de type adresse en mmoire dune donne de type int . On pourra alors mmoriser la valeur dune adresse dentier dans la variable j comme par exemple : j = &i; Notons que le compilateur vrie la cohrence de type, cest--dire ici que ladresse de i est bien du type adresse dentier . Enn, le langage C dispose de loprateur *, qui est loprateur rciproque de loprateur &, cest--dire un oprateur qui, plac devant une variable de type adresse, permet de dsigner le contenu de la case mmoire dsigne par cette adresse. Cet oprateur est utilisable aussi bien dans une expression que dans une partie gauche daffectation, comme dans les exemples suivants : printf("*j=%d\n",*j); *j=4; printf("i=%d\n",i); qui, lexcution, afche : *j=2 i=4 Ceci sexplique comme suit : j contient, du fait de la premire affectation (j = &i;), ladresse mmoire de i, variable de type int contenant la valeur 2 ;

26

CHAPITRE 1. INTRODUCTION

la premire impression de message utilise comme second paramtre lexpression *j, ce qui signie le contenu de la case mmoire dont ladresse est dans la variable j ; cest donc bien la valeur de i (2) qui est afche ; linstruction *j=4; modie le contenu de la case mmoire dont ladresse est stocke dans la variable j, ce qui revient donc exactement effectuer linstruction i=4; la deuxime impression afche la valeur de i, qui est bien 4 ! Terminons ce paragraphe par quelques remarques : on utilise souvent la terminologie de pointeur comme synonyme dadresse mmoire ; lenvironnement de dveloppement garantit que ladresse mmoire 0, souvent dnomme NULL, ne peut dsigner une adresse mmoire contenant une donne dintrt pour le programme ; cette valeur particulire sera trs souvent utilise pour signier que la variable ne dsigne aucune adresse relle ; le langage C use beaucoup (abuse ?) de la notion dadresse mmoire : il est donc relativement important de bien la comprendre.

1.2 retenir
La procdure main correspond au programme excuter. Les inclusions du prprocesseur se placent en tte du programme #include <stdio.h> Toute variable doit tre dclare avant son utilisation ; elle peut recevoir une valeur initiale int toto ; int titi=530 ; float facteur=6.55957 ; Les instructions du langage : expressions arithmtiques entires, ottantes, mixtes. affectation : "variable" = "expression" ; impression : puts(" chane de caractres ") ; printf(" format \n", valeurs ) ;

1.3 Travaux pratiques


Chaque tudiant enverra les programmes raliss au cours de ces travaux pratiques sous la forme dun ml unique, comportant les textes des programmes, spars par trois lignes blanches les uns des autres, ladresse girardot@emse.fr. Le sujet du ml comportera le nom de ltudiant, et la mention TP 1.

1.3. TRAVAUX PRATIQUES

27

1.3.1 Exercice 1
Tapez et testez les deux exemples de programmes donns en cours. Note : il nest pas ncessaire denvoyer ces deux programmes dans votre ml de compte-rendu.

1.3.2 Exercice 2
crire un programme ralisant une conversion de degrs Fahrenheit vers des degrs Celsius. La valeur convertir est 327,35 F.

1.3.3 Exercice 3
crire un programme convertissant des francs en euros et rciproquement. Les rsultats seront afchs avec deux chiffres signicatifs, en respectant les consignes lgales de conversion. Les valeurs convertir sont 592,25 francs et 155,76 euros.

28

CHAPITRE 1. INTRODUCTION

Chapitre 2 Quelques problmes lmentaires


2.1 Cours
Ce chapitre sintresse plus spciquement la modlisation de problmes simples, et aux tapes de lanalyse permettant la transformation de ces problmes en programmes pouvant tre traits par lordinateur. Les premiers exemples sont volontairement pris dans un domaine bien connu qui est celui des mathmatiques, an de pouvoir mettre laccent sur la mthodologie de passage de ces problmes bien connus limplmentation informatique dun programme rsolvant ce problme.

2.1.1 Un premier problme : lalgorithme dEuclide


On se propose dcrire un programme permettant le calcul du PGCD de deux nombres. 2.1.1.1 Lalgorithme On se rappelle que ce problme peut tre rsolu (mathmatiquement parlant) par lalgorithme dEuclide. Le principe de celui-ci (qui sapplique des entiers positifs) est le suivant : retrancher du plus grand des deux nombres le plus petit. Quand un nombre devient nul (ou, autre test quivalent, devient gal lautre), la valeur de lautre nombre est le PGCD des deux nombres initiaux1. Nous nous intresserons ici au problme de la transcription en C de cet algorithme. Nous noterons ces 2 nombres A et B , en convenant que nous maintiendrons toujours A B . Les tapes de lalgorithme sont les suivantes : 1. vrier que A B ; sinon, permuter les deux nombres. 3. sinon, retrancher B de A. 4. revenir ltape 1.
Ceci est la version de lalgorithme dEuclide qui neffectue que des soustractions, il en existe une autre qui a besoin de loprateur modulo.
1

2. est-ce que A = B ? Si oui, le PGCD est A et le programme est termin.

29

30

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES

2.1.1.2 Passage au programme Les deux nombres sont reprsents par deux variables, notes A et B de type int. Dtaillons maintenant les tapes dcrites ci-dessus : tape 1 Comparer deux nombres seffectue au moyen dun oprateur de comparaison ; les notations <, <=, ==, >, >= et != reprsentent respectivement les oprations de comparaison infrieur, infrieur ou gal, gal, suprieur, suprieur ou gal, et enn diffrent. Ces oprations comparent leurs oprandes, et fournissent un rsultat dit boolen, dont les valeurs, vrai ou faux, sont reprsentes par les entiers 1 et 0 respectivement2. Elles peuvent sutiliser dans les instructions conditionnelles, dont les syntaxes sont : if (test) instruction-1 if (test) instruction-1 else instruction-2 Dans le premier cas, instruction-1 est excute si et seulement si test est la valeur vrai. Dans le second cas, si test est vrai, instruction-1 est excute, et elle seule ; si test est faux, instruction-2 est excute, et elle seule. La comparaison de A et B va donc pouvoir sutiliser dans une instruction dbutant par : if (A<B) ... Se pose maintenant la question de la permutation des A et B . La meilleure solution consiste utiliser une variable intermdiaire (appelons la C ), sous la forme : C=A ; A=B ; B=C ; Cependant, cet change se compose de trois instructions, alors que la syntaxe des instructions conditionnelles nous parle dune instruction unique. La solution ce problme consiste regrouper ces instructions en un bloc, en les plaant entre accolades. Le rsultat constitue une instruction compose unique. Notre test devient ainsi : if (A<B) { C=A ; A=B ; B=C ; } tape 2 Nous disposons de tous les lments ncessaires la transcription de cette tape, qui met en jeu une instruction conditionnelle, une impression, et un arrt de lexcution : if (A==B) { printf("La valeur du PGCD est %d\n", A) ; exit(0) ; } tape 3 Pas de difcult non plus pour ce fragment de lalgorithme, qui scrit :

A=A-B ;
Le langage C considre en ralit que toute valeur non nulle reprsente la valeur vrai et que la valeur 0 (sous la forme dun int, char ou oat) est la valeur faux.
2

2.1. COURS

31

tape 4 Une solution pour revenir la premire tape du programme consiste enclore lensemble des instructions de celui-ci dans une forme rptitive ; voici trois syntaxes au choix : for ( ; ;) instruction while(1) instruction do instruction while(1) ; On notera que le 1 suivant les while reprsente en fait la valeur boolenne vrai : lexpression teste qui conditionne la rptition de la boucle est donc toujours vraie. L encore, nous utiliserons des accolades pour transformer notre squence de trois tapes en une instruction compose unique : for ( ; ;) { if (A<B) { C=A ; A=B ; B=C ; } if (A==B) { printf("La valeur du PGCD est %d\n", A) ; exit(0) ; } A=A-B ; } 2.1.1.3 Le programme nal Nous pouvons maintenant proposer la version nale du programme, dont le texte source est donn dans la gure 2.1. Lexcution fournit la rponse suivante : La valeur du PGCD est 743 2.1.1.4 Un cas non prvu ! On na pas dmontr que lalgorithme ci-dessus se termine en un temps ni (dmonstration laisse au lecteur). Ceci est toutefois loccasion de prciser que, si lun des entiers est nul alors que lautre ne lest pas, lalgorithme boucle indniment. On pourrait traiter ce problme en modiant le test darrt, par exemple en testant si la valeur de B nest pas nulle : if ((A==B) || (B==0)) { ... }

32

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES


#include <stdio.h> int main(int argc, char * argv[]) { int A, B, C ; A = 834389 ; B = 944353 ; for ( ; ;) { if (A<B) { C=A ; A=B ; B=C ; } if (A==B) { printf("La valeur du PGCD est %d\n", A) ; return 0 ; } A=A-B ; } } F IG . 2.1 PGCD de deux nombres

Noter au passage que les oprateurs logiques en C scrivent && (et logique), et || (ou logique) ; ne pas oublier le doublement du symbole, car les oprateurs & et | existent galement, et ont un tout autre sens ! En fait, il conviendrait, au dbut du programme, de vrier que les valeurs A et B satisfont les conditions dapplication de lalgorithme, par exemple en insrant le fragment : if (A<=0 || B<=0) { printf("Algorithme non applicable\n"); exit(1); }

2.1.2 Somme des premiers entiers


Dans notre exemple prcdent, le problme pos tait en lui-mme une description algorithmique de sa solution, description quil convenait simplement de traduire dans le langage C. Dans la grande majorit des cas, il convient dabord de choisir (ou de concevoir) un algorithme adapt au problme, avant de passer la forme informatique. Prenons comme exemple de problme trouver, pour un N donn, la somme des entiers jusqu N . Premire version Une premire approche peut consister btir une boucle qui va numrer ces nombres et calculer leur somme. Un tel programme scrit aisment :

2.1. COURS
int N, S, i; ... S = 0; for (i=1; i<=N; i++) S = S+i;

33

Notes : Cet exemple nous permet de prsenter de manire informelle la syntaxe dune boucle for : for (initialisation ; continuation ; gestion ) instruction Dans cette syntaxe, la partie initialisation permet daffecter des valeurs initiales aux variables qui vont tre utilises au sein de la boucle. Lexpression continuation est un calcul dune valeur boolenne qui indique si la boucle se poursuit ou sinterrompt. Enn, la partie gestion permet la modication des variables utilises dans la boucle avant un nouveau test. Il ny a pas ncessairement un lien direct entre le test de continuation de la boucle et les variables modies dans lexpression de gestion de la boucle. Par ailleurs, lexpression ci-dessus i++ fait appel loprateur de post-incrmentation, ++, spcicit du langage C (et de ses descendants, tels C++ ou Java). Loprateur ++ permet dincrmenter une variable entire (cest--dire de lui ajouter 1). Les instructions : i++ ; ++i ; i=i+1 ; sont quivalentes et ont pour effet dajouter 1 la variable i. Cependant, les expressions i++ et ++i ont des sens diffrents : i++ est une expression qui fournit la valeur de i avant lincrmentation ; ++i est une expression qui fournit la valeur de i aprs lincrmentation. Ainsi, aprs lexcution du fragment de programme suivant : int i, j, k ; ... i=4 ; j=++i ; k=i++ ; les variables i, j et k ont pour valeurs respectives 6, 5 et 5. Signalons enn lexistence de loprateur -- de dcrmentation, qui linstar de ++, permet de retrancher 1 une variable. Seconde version Cependant, le problme de la sommation des N premiers entiers nous est connu depuis longtemps, et nous savons que :
N

i=
i=1

N (N + 1) 2

Ceci nous permet de proposer la formulation suivante : int N, S; ... S = N * (N+1) / 2;

34

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES

Cette criture est non seulement plus lgante que notre premire version, mais elle est aussi plus efcace ! Elle est, pour N = 100, environ 40 fois plus rapide. Mieux encore, alors que le temps dexcution de la premire version est clairement propotionnel N (plus N est grand, plus le programme est lent), le temps dexcution de la seconde version est constant, indpendant de la valeur de N . Cet exemple trivial fait apparaitre la ncessit de trouver lalgorithme qui sera le plus efcace avant de coder cet algorithme. Nous reviendrons naturellement sur cet aspect important de linformatique dans la suite de ce cours, ainsi que dans le cours consacr aux algorithmes et structures de donnes ([1]).

2.1.3 Le calcul dun sinus


Nous allons maintenant dtailler une dmarche similaire, mais plus complexe, la faveur du problme suivant : on cherche calculer pour un angle donn la valeur du sinus de cet angle. 2.1.3.1 Lalgorithme On notera x la valeur dont on cherche calculer le sinus ; en C, cest une variable de type double. On sait que lon peut obtenir la valeur de sinus(x) par la relation : sin(x) =
i=0

(1)i

x2i+1 (2i + 1)!

Ceci ne donne pas proprement parler un algorithme, puisque par dnition, un algorithme doit se terminer aprs un nombre ni doprations ! Mais de toutes faons, on ne cherche en fait qu calculer une valeur approche du sinus : comment pourrait-il en tre autrement avec des machines qui ont une prcision limite, et qui commettent des approximations pour reprsenter les nombres. On cherche donc majorer lerreur commise en calculant la valeur du sinus. Pour cela, on peut remarquer que la srie est alterne (change de signe, valeur absolue dcroissante) pour | i > |x , et on sait que lerreur commise en tronquant une srie alterne au rang N (la diffrence 2 entre la limite mathmatique et la somme partielle au rang N ) est infrieure la valeur absolue du terme de rang N . Si est la prcision demande, on obtient donc comme formule de calcul :
N

sin(x) =
i=0

(1)i

x2i+1 (2i + 1)! | n> |x| 2 et |x|2n+1 < ) (2n + 1)!

N = min(n N 2.1.3.2 Dtail de lalgorithme

La formule obtenue ci-dessus nest cependant pas satisfaisante : il ny a pas doprateur dexponentiation ou de factorielle en C. Il faut donc continuer lanalyse.

2.1. COURS
On peut remarquer que la somme recherche peut sexprimer par :
N

35

sin(x) = UN =
i=0

ui x2i+1 (2i + 1)!

ui = (1)i et la suite ui pouvant elle-mme sexprimer par : u0 = x ui+1 = ui

x2 (2i + 2)(2i + 3)

En posant wi = 2i(2i + 1) = 4i2 + 2i, on obtient : ui+1 = ui wi+1 wi+1 x2 wi+1 = w i + 8i + 6 = wi + zi+1

en posant zi = 8i 2. La valeur de zi peut se calculer par la rcurrence : z0 = 2 zi+1 = zi + 8 En regroupant tout cela, on obtient cette fois lalgorithme de calcul : z0 w0 u0 U0 zi+1 wi+1 ui+1 Ui+1 2 0 x x zi + 8 wi + zi+1 x2 = ui wi+1 = Ui + ui+1 = = = = = =

Comme dhabitude, on va utiliser pour chacune des suites dnies ci-dessus une seule variable : la valeur de la variable litration i reprsente la i-me valeur de la suite. Il est donc primordial de respecter lordre de calcul indiqu ! Rappelons encore que le test darrt consiste tester si la valeur de |ui+1| est infrieure la | , puisque ce nest que lorsque cette condition prcision demande (sans oublier de tester si i > |x 2 est remplie que la srie est alterne). Le programme complet est donn ci-dessous :

36

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES


#include <stdio.h> #include <stdlib.h> #include <math.h> int main (int argc,char *argv[]) { double x,x2,z,w,u,U; double epsilon; int i,imin; /* on calcule sin(pi/4) a 10-6 pres */ x=M_PI/4;epsilon=0.000001; /* initialisations */ x2=x*x;z=-2;w=0;u=x;U=x;imin=fabs(x/2); for (i=0;;i++) { z=z+8;w=w+z;u=-u*x2/w;U=U+u; if ((i > imin) && (fabs(u) < epsilon)) { (void) printf("sin(%.10g)=%.10g\n",x,U); (void) printf(" [apres %d iterations]\n",i+1); return 0; } } }

Notons : lutilisation de la fonction de la bibliothque mathmatique fabs, qui fournit la valeur absolue de son argument (argument et rsultat sont de type double) ; lutilisation de cette fonction ncessite linclusion du chier den-tte de cette bibliothque, nomm math.h ; lutilisation de la macro M_PI (valeur de ) galement dnie dans ce chier den-tte. lutilisation de (void) indique que lon nutilise pas le rsultat fourni par la procdure printf. Lexcution de ce programme donne le rsultat : sin(0.7853981634)=0.7071067812 [apres 5 iterations] ce qui est un rsultat tout fait acceptable ( comparer au rsultat thorique 22 soit autour de 0.707106781187). On peut noter aussi que ce rsultat est obtenu assez rapidement (5 itrations reprsentent une trentaine doprations). On peut constater sur cet exemple quon obtient un code trs compact, mais que la lecture du code ne permet que trs difcilement de retrouver ce que ce code calcule ! Do lutilit de documenter son code, sans oublier de prciser, ds que lingnierie inverse devient difcile, la fonction prcise du code en question.

2.1. COURS
2.1.3.3 Petit problme !

37

On veut calculer le sinus de 100. On modie donc le programme prcdent (en insrant linstruction x=100; en lieu et place de x=M_PI/4;), et on obtient le rsultat suivant : sin(100)=-8.261375665e+25 [apres 142 iterations] ce qui est plutt surprenant pour une valeur cense tre comprise entre -1 et 1 ! Comme cela arrive frquemment, limprcision numrique des ordinateurs est la cause du problme. La formule utilise est mathmatiquement exacte : cependant, elle ajoute des termes de valeurs absolues trs diffrentes. Si le dernier terme est infrieur la prcision demande, le terme de valeur absolue maximale, est (pour x = 100) le terme dindice 49, soit : 10099 1042 99! La prcision relative de la reprsentation des nombres ottants selon la norme IEEE-754 est de lordre de 1016 (253 pour tre prcis !) : sur une valeur absolue de lordre de 1042 , on obtient donc une erreur absolue de lordre de 1026 , cest bien lordre du rsultat obtenu ! Dans le cas particulier de la fonction sinus, on peut amliorer grandement les choses en utilisant une proprit mathmatique supplmentaire, savoir la priodicit : se ramener une valeur de x entre et permet dobtenir une prcision tout fait acceptable. On peut ainsi insrer dans les initialisations linstruction : |u49 | = x=fmod(x,2*M_PI); en utilisant la fonction fmod (calcul de modulo sur des donnes de type double), appartenant toujours la bibliothque mathmatique. Lexcution du programme ainsi modi donne alors : sin(100)=-0.5063656423 [apres 13 iterations] beaucoup plus raliste , et en mme temps plus rapide ! On pourrait encore amliorer le programme en utilisant dautres proprits de la fonction sinus (sin( + x) = sin(x) ou sin( x) = sin(x)) an de se ramener une valeur de x comprise entre 0 et . Ce quil faut retenir : il faut tre parfaitement conscient, lorsque lon programme une fonction, des limitations lies la programmation de cette fonction ! Ne pas en tenir compte peut amener des consquences non ngligeables, les personnes intresses par ce sujet pourront consulter avec intrt la page suivante : http://www.math.psu.edu/dna/disasters pour se convaincre du caractre parfois dramatique de tels oublis : chec dinterception dun missile Scud par un missile Patriot d une erreur de prcision sur le calcul du temps ; chec du tir inaugural dAriane V d la rutilisation dun code incorrect issu dAriane IV (et inutile dans le cas dAriane V ) ; naufrage de la plate-forme ptrolire Sleipner A d la rupture dun lment par mauvaise approximation dune loi dlasticit.

38

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES

2.2 retenir
instruction compose { squence dinstructions } oprateurs de comparaison < <= == >= > != oprateurs logiques et logique &&, ou logique || boucle innie : for ( ; ;) instruction while (1) instruction do instruction while (1) ; boucle for : for (initialisation ; continuation ; gestion ) instruction

2.3 Travaux pratiques


Chaque tudiant enverra les programmes raliss au cours de ces travaux pratiques sous la forme dun ml unique, comportant les textes des programmes, spars par trois lignes blanches les uns des autres, ladresse girardot@emse.fr. Le sujet du ml comportera le nom de ltudiant, et la mention TP 2.

2.3.1 Exercice 1
On veut dterminer si un nombre est premier. Le nombre dont on teste la primalit est dni par une affectation dans le programme. Si ce nombre nest pas premier, le programme donne une dcomposition en deux termes non triviaux.

2.3.2 Exercice 2
Modier le programme prcdent pour imprimer tous les facteurs du nombre si celui-ci nest pas premier.

2.3.3 Exercice 3
On veut dterminer si un nombre est parfait, cest dire gal la somme de ses diviseurs, hormis lui-mme. Les deux premiers nombres parfaits sont 6 (1+2+3) et 28 (1+2+4+7+14).

2.3.4 Exercice 4
On se propose de calculer, 106 prs, la racine du polynme x4 + 3x2 x 1 = 0 situe dans lintervalle [0 1].

2.3. TRAVAUX PRATIQUES

39

On oprera pour cela par dichotomies successives, en divisant par deux la taille de lintervalle jusqu obtention de la prcision dsire.

2.3.5 Exercice 5
Un banquier propose un placement sur le principe suivant : linvestissement initial est e 1 euros (e est la base des logarithmes nperiens) ; la premire anne, on prlve un euro de frais de gestion ; la seconde anne, le capital restant est multipli par deux, et on prlve toujours un euro de frais de gestion ; la n-ime anne, le capital restant est multipli par n, et on prlve toujours un euro de frais de gestion ; le placement est prvu pour une dure de 25 ans. Dterminer le capital restant au bout des 25 ans. Notes : le chier den-tte math.h dnit la macro M_E qui est la meilleure approximation de e sur la machine ; essayer plusieurs types ottants ; en C, sont disponibles les types float (32 bits), double (64 bits) et long double (128 bits) ; quel est le rsultat mathmatique ?

40

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES

Chapitre 3 Procdures
3.1 Cours
Ce cours sintresse plus spciquement lintroduction de la notion de procdure, qui nous permettra de structurer et organiser efcacement le code dun programme.

3.1.1 Retour au PGCD


#include <stdio.h> int A, B, C ; int main(int argc, char * argv[]) { A = 834389 ; B = 944353 ; for ( ; ;) { if (A<B) { C=A ; A=B ; B=C ; } if (A==B) { printf("La valeur du PGCD est %d\n", A) ; return 0 ; } A=A-B ; } } F IG . 3.1 PGCD de deux nombres (version 1)

41

42

CHAPITRE 3. PROCDURES

Nous avions crit lors dune prcdente sance le calcul du PGCD de deux nombres par lalgorithme dEuclide, dont le texte source est rappel dans la gure 3.1. Que faire si notre souhait est de calculer le PGCD de trois nombres A, B et C ? On peut naturellement calculer le PGCD des deux premiers, A et B , puis ayant obtenu le rsultat dans la variable A, recopier les mmes instructions, en remplaant B par C , pour obtenir le rsultat dsir. La ralisation est lourde, et source de nombreuses erreurs car on oublie frquemment de modier un nom de variable dans le code recopi ! Et que dire sil sagit de calculer le PGCD de dix nombres, ou encore de calculer le PGCD divers endroits dun programme ! Il existe naturellement de meilleures solutions ce problme, qui passent par lcriture de procdures, dites parfois sous-programmes, subroutines (anglicisme !), et de manire plus impropre encore, fonctions. Une procdure permet dcrire une seule fois un traitement particulier, utilis plusieurs reprises au sein dun programme. On verra que cette notion permet galement de structurer un programme complexe, en dcomposant le traitement en plusieurs sous-tches, chacune tant reprsente par une procdure (ou un ensemble de procdures).

3.1.2 La notion de procdure


Une procdure est lassociation dun nom et dun ensemble dinstructions du langage. On peut ainsi tablir un certain parallle entre procdure et instructions dune part, variable et donnes dautre part. Dnir une procdure, cest lui donner un nom et dnir son contenu, cest--dire la succession des instructions qui la composent. Une fois la procdure dnie, elle devient utilisable tout endroit du programme en faisant simplement rfrence son nom. En langage C, ceci se fait en accolant au nom de la procdure les caractres (). Il faut bien comprendre le schma dexcution particulier lors de lappel dune procdure, qui ne suit pas le schma dexcution squentiel normal du processeur : ce sont dailleurs des instructions spciques du processeur qui sont utilises pour la gestion des procdures. lorsque le processeur excute linstruction spcique correspondant lappel de procdure, il mmorise le compteur programme qui dsigne alors linstruction suivante (dans le ot initial dinstructions) ; le compteur programme est modi de faon ce que la prochaine instruction excute soit la premire instruction de la procdure appele ; en n de procdure, une autre instruction spcique permet dindiquer que le compteur programme doit tre restaur avec la valeur mmorise avant lappel de la procdure. Ce mcanisme particulier peut tre rpt autant de fois que souhait, et il est possible que la procdure appelle une autre procdure, qui appelle une autre procdure... : le processeur mmorise chaque fois ladresse de linstruction suivante, et cest toujours la dernire adresse mmorise qui est restaure lors dune n de procdure. On verra ultrieurement quune procdure peut recevoir des paramtres permettant de modier son comportement, et fournir un rsultat. Les procdures peuvent ainsi modliser certaines fonctions mathmatiques (partiellement dans tous les cas, ne serait-ce que parce que les ordinateurs ne permettent de reprsenter que des sous-ensembles des entiers et des rels), et parfois en calculer les valeurs.

3.1. COURS

43

3.1.3 La procdure PGCD, premire version


Voici une premire version de la procdure PGCD : void pgcd(void) { for ( ; ;) { if (A<B) { C=A ; A=B ; B=C ; } if (A==B) { return ; } A=A-B ; } } Elle reprend les instructions de notre premire version du programme, en les englobant dans une dclaration de procdure : void pgcd(void) Cette dclaration dbute par le mot-clef void, qui indique que la procdure ne rend pas de rsultat. Le nom de la procdure (qui doit avoir les mmes caractristiques quun nom de variable) est suivi de la liste de ses paramtres : ici, le mot-clef void indique quil ny a pas de paramtres. Le couple daccolades qui encadre les instructions dnit le corps de la procdure. Enn, on a retir de la procdure lordre dimpression ainsi que lordre darrt du programme. Ces deux instructions ont t remplaces par : return ; qui est linstruction en langage C permettant dindiquer la n de la procdure (lorsque le traitement doit sarrter avant la n normale, cest--dire lexcution de la dernire instruction). Le nom de cette instruction permet dailleurs de mmoriser facilement que lon retourne lexcution du programme principal. Cette procdure va tre appele par lexpression suivante : pgcd() ; Notons les parenthses, obligatoires, qui indiquent lappel de procdure. Il ny a rien lintrieur de ces parenthses (la procdure na pas de paramtres), et elle ne fournit pas de rsultat. Lorsque cette expression est excute, le code situ lintrieur de la procdure est excut. Nous avons maintenant un autre problme rgler : les variables A, B et C sont dnies dans la procdure main. Or, la procdure pgcd doit utiliser ces variables : mais le langage C ne permet pas une procdure dutiliser des variables dnies dans dautres procdures !

44

CHAPITRE 3. PROCDURES

On peut contourner dans un premier temps cette difcult en rendant les variables globales, cest--dire connues par toutes les procdures. En langage C, ceci se fait en dclarant les variables en dehors de toute procdure. On peut par exemple les dnir en tte du programme, et toutes les procdures dnies ultrieurement dans le code source pourront y accder (la rgle gnrale est quune variable doit tre dclare avant dtre utilise). Notons toutefois que la variable C nest utile que pour changer les variables A et B (elle ne sert pas dans la procdure main) : on a donc tout intrt dclarer cette variable dans la procdure pgcd. La gure 3.2 donne la nouvelle version, code selon ces considrations, du programme. #include <stdio.h> int A, B ; void pgcd(void) { int C ; for ( ; ;) { if (A<B) { C=A ; A=B ; B=C ; } if (A==B) { return ; } A=A-B ; } } int main(int argc, char * argv[]) { A = 834389 ; B = 944353 ; pgcd() ; printf("La valeur du PGCD est %d\n", A) ; return 0 ; } F IG . 3.2 Procdure PGCD (premire version)

3.1.4 La procdure PGCD, deuxime version


La procdure que nous venons dcrire communique avec le programme principal (la procdure main) par lintermdiaire des variables A et B, qui sont ici partages entre les deux pro-

3.1. COURS

45

cdures (variables globales). Le programme principal positionne les deux valeurs A et B, puis appelle la procdure qui consulte (et modie) ces deux variables, fournissant dans lune delles (les deux, dailleurs) le rsultat. Au retour de la procdure, la programme principal retrouve donc ce rsultat et peut limprimer. Cette approche impose au programmeur dtre parfaitement conscient du rle de la procdure et des variables quelle consulte et modie, tche qui devient trs complexe lorsquun grand nombre de procdures sont utilises dans lapplication. Pour simplier cette gestion, les langages de programmation en gnral, et C en particulier, permettent de dclarer quune procdure reoit des paramtres et fournit un rsultat. Au niveau de la dclaration, on doit alors indiquer entre les parenthses suivant le nom de la procdure la liste des paramtres (nom et type), et indiquer (le cas chant) le type du rsultat (entier int, ottant double...). La dclaration de notre procdure pgcd devient alors : int pgcd(int X, int Y) Nous dclarons cette fois que la procdure rend un rsultat de type int, et admet deux paramtres de type int, connus sous les noms de X et Y lintrieur du code. Les noms choisis pour dsigner les paramtres de la procdure nont de sens qu lintrieur de celle-ci, et sont indpendants des noms choisis dans le reste du programme. Une procdure est ainsi plus proche, dans son aspect, dune fonction mathmatique, si son excution ne dpend que des seuls paramtres. Il convient galement modier le corps de la procdure, pour que celle-ci travaille sur les variables X et Y, ainsi que linstruction permettant la sortie de la procdure. Celle-ci rendant un rsultat, nous le fournissons dans linstruction return, qui scrit maintenant : return X ; Enn, le mode dappel de la procdure est modi. Nous crirons par exemple : R = pgcd(A,B) ; la variable R ayant t dclare de type entier. Comment fonctionne maintenant la procdure pgcd ? Dtaillons les tapes successives de lexcution. avant lappel, les paramtres sont calculs : ici, il sagit juste de rcuprer les valeurs contenues dans les variables A et B, mais il pourrait tre ncessaire deffectuer des oprations ; ces valeurs sont mmorises temporairement ; comme avant tout appel de procdure, le compteur programme est mmoris, puis modi avec ladresse de la premire instruction de la procdure appele ; avant mme lexcution de la premire instruction dnie par le programmeur, les valeurs mmorises pour les paramtres sont recopies dans les variables locales (ici, X et Y) ; lors de lexcution de linstruction return, on calcule la valeur du rsultat (lexpression aprs le return, ici simplement le contenu de la variable X mais qui pourrait tre plus complexe), puis on restaure le compteur programme ; dans le programme appelant, avant dexcuter linstruction suivante, le rsultat fourni par la procdure est conserv dans la variable R. Notons que si la valeur rendue par une procdure nest pas immdiatement utilise, elle est perdue !

46

CHAPITRE 3. PROCDURES

Comme ce sont les valeurs des paramtres qui sont passes la procdure appele, on dit que le langage C effectue un passage des arguments par valeur. Dautres langages peuvent utiliser dautres techniques (passage par adresse, par rfrence). La gure 3.3 donne la nouvelle version du programme.

#include <stdio.h> int pgcd(int X, int Y) { int C ; for ( ; ;) { if (X<Y) { C=X ; X=Y ; Y=C ; } if (X==Y) { return X ; } X=X-Y ; } } int main(int argc, char * argv[]) { int A, B, R ; A = 834389 ; B = 944353 ; R = pgcd(A,B) ; printf("La valeur du PGCD est %d\n", R) ; return 0 ; } F IG . 3.3 Procdure PGCD de deux nombres (deuxime version)

Questions : 1. Les variables A et B dclares dans la procdure main sont-elles modies lors de lappel de la procdure pgcd ? 2. Quen est-il si lon appelle A et B (au lieu de X et Y) les paramtres de la procdure pgcd ?

3.1. COURS

47

3.1.5 Quelques aspects des procdures du langage C


3.1.5.1 Variables locales et globales Il aurait t possible de nommer A et B (plutt que X et Y) les deux paramtres de la fonction pgcd. Nous aurions eu alors dans notre programme coexistence de variables de mme nom, mais reprsentant des donnes diffrentes. Dans le corps de la procdure pgcd, toute rfrence la variable A dsigne en fait la variable A de la procdure pgcd . Cest pourquoi on parle de variables locales dans ce cas dutilisation. Il est particulirement recommand que toute variable spcique une procdure, qui na besoin dtre connue que de cette procdure, soit dclare en tant que variable locale cette procdure ! Cette vision prsente lnorme avantage de lindpendance totale entre les noms (et les contenus) de variables de procdures diffrentes : on peut utiliser un nom de variable au sein dune procdure sans crainte de modication du fonctionnement dune autre procdure. Sans ce mcanisme, la gestion des noms de variables sans risque dinterfrence deviendrait extrmement lourde, donc en pratique, irralisable ! Rappelons que le langage C, comme de nombreux langages, autorise toutefois lutilisation de variables globales, et il faut alors prendre garde ces risques dinterfrences. Il convient donc dviter au maximum lutilisation de variables globales, celles-ci pouvant tre sources de nombreux problmes et bogues, extrmement difciles dtecter et corriger. Signalons enn que le langage C autorise galement la dnition de variables locales lintrieur de nimporte quel bloc dinstructions (suite dinstructions entre accolades). Prenons lexemple de la procdure pgcd : la variable locale C nest utilise que dans le premier bloc dinstructions, consistant changer les deux variables X et Y. Il aurait t possible dcrire ce bloc dinstructions comme suit : if (X<Y) { int C ; C=X ; X=Y ; Y=C ; } Le dplacement de la dclaration int C ; aprs laccolade ouvrante qui suit le test if (X<Y) a pour effet de restreindre la visibit de cette variable (on utilise souvent le terme de porte de la variable) au seul segment de code situ entre cette accolade ouvrante et laccolade fermante correspondante. Rappelons, en insistant lourdement, que la dclaration de variables locales dans une procdure ou dans un bloc dinstructions doit tre faite avant la premire instruction de cette procdure ou de ce bloc. Note : on a parfois tendance croire que le fait de dclarer une variable locale un bloc dinstructions rend le programme moins gourmand en mmoire, lespace ncessaire pour stocker la donne ntant utilis que pendant lexcution du bloc concern. Ceci est malheureusement inexact ! En effet, toutes les variables locales sont cres en dbut de procdure ; ce nest que dans le cas dun compilateur optimis, et si lon a plusieurs variables locales de mme type dans des blocs dinstructions diffrents que lon peut gagner un peu de place mmoire.

48 3.1.5.2 Paramtres dune procdure

CHAPITRE 3. PROCDURES

Les paramtres dune procdure (on parle souvent darguments de la procdure) se comportent comme des variables locales la procdure : ils ne sont donc accessibles quau sein de la procdure elle-mme (notons que la procdure peut tout--fait modier la valeur de ces variables). Leur particularit est de recevoir une valeur initiale au moment de lappel de la procdure : ces valeurs peuvent donc tre diffrentes lors de deux appels diffrents au sein du programme ; ceci est donc foncirement diffrent des variables locales initialises de la procdure, qui recoivent les mmes valeurs chaque appel de la procdure. Enn, insistons sur le fait quil importe, lors dun appel, de passer le nombre correct de paramtres, ainsi que des paramtres dont les types sont conformes aux types attendus par la procdure. 3.1.5.3 Notion de prototype La description dune procdure incluant le type du rsultat et les types des arguments est dite prototype de la procdure. Cest une dclaration, au mme titre que int C ; . En principe, toute procdure doit tre dclare, la dclaration se composant du prototype de la fonction suivi dun point-virgule. La procdure PGCD se dclare ainsi : int pgcd(int A, int B) ; Il nest en fait pas ncessaire de fournir le nom des paramtres ; la dclaration peut donc scrire : int pgcd(int, int) ; Dans la pratique, la dclaration, toujours utile, nest indispensable que si la procdure est utilise dans le texte du programme source avant que napparaisse sa dnition. Pour cette raison, on place souvent dans le programme source la dnition des procdures avant leur premire utilisation. On notera que le mot-clef void dsigne un type de donnes particulier, de taille 0, qui indique quune fonction ne fournit pas de rsultat, comme dans void toto(int), ou na pas de paramtre, comme dans int clock(void). En rsum, un prototype ne dcrit pas comment une procdure est programme, mais simplement comment et dans quelles conditions elle peut tre utilise. Enn, on notera quun programme C comporte obligatoirement une procdure de nom main. Cest cette procdure (dont on ne peut pas choisir le nom) qui est appele lorsque lon demande lexcution du programme. En principe, le prototype de cette procdure est le suivant : int main(int argc, char * argv[]) ; Nous verrons ultrieurement ce que dsigne exactement une dclaration telle que char * argv[] . Notons toutefois que ce prototype impose un rsultat cette procdure : cest pour cette raison que lon doit toujours terminer la procdure main par une instruction de type return X ;

3.1. COURS
3.1.5.4 Compilation spare

49

Les grosses applications dveloppes en langage C peuvent atteindre quelques centaines de milliers de lignes de code, voire quelques millions de lignes. Ces applications sont dveloppes par des quipes pouvant comporter des dizaines de programmeurs. On ne peut gure envisager de voir un programmeur travailler sur un programme comportant des millions de lignes de code, tandis que les autres attendent quil ait ni ses modications pour maintenir leur tour les procdures dont ils sont responsables ! La solution consiste rpartir lensemble du programme source en plusieurs chiers spars, qui peuvent tre dits et compils sparment. Il est bien sr ncessaire de rassembler ensuite les rsultats de ces compilations pour pouvoir procder lexcution du programme. Imaginons que notre programme de calcul de PGCD soit jug assez complexe pour relever dune telle approche. Il serait possible de placer, par exemple, la procdure pgcd dans lun de ces chiers, et la procdure main dans un autre. Que faut-il faire pour que cette solution fonctionne ? Tout dabord, nous allons crer un chier source contenant le programme principal , celui dans lequel la procdure main est dclare, et puisque cette procdure main va faire appel la procdure pgcd, il faut quelle connaisse le prototype de cette fonction. Nous allons donc insrer, avant la dnition de main, le prototype suivant : extern int pgcd(int, int) ; Le mot-clef extern indique que la procdure pgcd nest pas dnie dans ce chier, mais dans un autre, tout en fournissant son prototype, qui permet au compilateur de vrier que lutilisation de cette procdure est conforme sa dnition. Si le chier contenant la procdure main a pour nom prog3.c, nous le compilerons par la commande : [P]$ gcc -c prog3.c Notons loption -c qui indique que lon dsire seulement compiler le chier prog3.c. Le rsultat de lopration est un nouveau chier, de nom prog3.o qui contient le code objet de notre programme. Il faut ensuite crer un second chier source, contenant le texte de la procdure pgcd, et que nous nommerons par exemple pgcd.c. De la mme manire que ci-dessus, nous compilerons ce chier par : [P]$ gcc -c pgcd.c L encore, un chier, de nom pgcd.o, va tre construit par le compilateur. Nous pouvons alors crer le programme excutable, par une commande telle que : [P]$ gcc prog3.o pgcd.o -o prog3 Notons que cette fois-ci, ce sont les noms des chiers contenant les codes objet (donc, se terminant par lextension .o ), que nous transmettons la commande gcc. Le compilateur gnrera le chier prog3, qui contient le programme directement excutable. Nous avons en fait dcompos la cration du programme excutable en deux tapes : la premire consiste compiler indpendamment les divers modules sources pour obtenir les modules

50

CHAPITRE 3. PROCDURES

objets correspondants ; la seconde rassemble ces modules objets (plus, ventuellement, des modules objets dits de bibliothque contenant les procdures dnies par le standard C) pour fournir le module excutable. Cette seconde tape est souvent dit dition des liens . Cette approche permet ainsi de modier lune ou lautre des procdures, sans avoir besoin de recompiler systmatiquement tout le code source de lapplication. 3.1.5.5 Fichiers dinclusion Nous avons dj prsent la commande include du prprocesseur. Cette commande a pour but daller chercher le chier prcis en paramtre, et de linsrer, dans le corps du programme, pour ltape de compilation. La commande admet les deux syntaxes suivantes : #include <stdio.h> #include "toto.h" Dans la premire forme, le chier de nom stdio.h est recherch dans les rpertoires contenant les dclarations des procdures prdnies du systmes, ici, certaines oprations dentressorties. Dans la seconde forme, le chier, ici toto.h est cherch dabord dans le rpertoire courant (puis dans les rpertoires du systme, comme ci-dessus) ; un tel chier a en gnral t cr par lutilisateur. De tel chiers, dits souvent chiers dinclusion, peuvent contenir nimporte quelles instructions du langage C. En gnral cependant, lon ny place que des dclarations et dautres instructions destines au pr-processeur. Il nous serait possible, pour simplier lutilisation de la procdure pgcd, de dnir son prototype dans un tel chier. Crons le chier pgcd.h , contenant la seule ligne : extern int pgcd(int, int) ; Dans le chier prog3.c , celui qui contient le programme principal, nous pouvons ds lors remplacer la ligne dnissant le prototype de la fonction par la ligne suivante : #include "pgcd.h" Notre programme principal devient : #include <stdio.h> #include "pgcd.h" int main(int argc, char * argv[]) { int A, B ; int R ; A = 834389 ; B = 944353 ; R = pgcd(A,B) ; printf("La valeur du PGCD est %d\n", R) ; return 0 ; }

3.1. COURS

51

Le gain despace est dans ce cas prcis assez rduit. En gnral un module objet va contenir plusieurs procdures, et le chier include correspondant va contenir lensemble des dclarations de ces procdures. On notera que les chiers dinclusion utilisent par convention lextension .h . Ceci simplie la vie de lutilisateur, qui sait que lorsquil a dans un rpertoire les trois chiers suivants : pgcd.c pgcd.h pgcd.o

Ceux-ci reprsentent en principe un module source, le chier dinclusion contenant les prototypes des procdures du module source, et enn le module objet correspondant.

3.1.6 Quelques procdures de C


Nous avons dj utilis, dans les cours antrieurs, quelques procdures du systme, en particulier celles qui fournissent des services dentres sorties, printf et puts. Nous proposons ici la description de quelques unes des procdures dusage relativement frquent dans les applications. 3.1.6.1 Oprations mathmatiques Pour les calculs scientiques, C propose une vaste bibliothque de procdures, dont certaines sont dcrites la gure 3.4. On notera que les paramtres et les rsultats sont de type double (sur les machines que nous utilisons, ces nombres ottants sont reprsents sur 8 octets, ce qui fournit 16 17 chiffres dcimaux signicatifs). Plutt que de fournir dans chaque programme lensemble de ces fonctions, lenvironnement de programmation permet : dinclure dans les programmes sources des chiers de dclarations des prototypes ; nous lavons fait avec le chier stdio.h. dinclure dans les programmes excutables des bibliothques contenant ces fonctions prcompiles, au moyen du paramtre -lnom., par exemple -lm pour les oprations mathmatiques. Lutilisation de ces oprations mathmatiques ncessite donc linclusion de leur dclaration, obtenue en insrant la ligne suivante en tte du programme : #include <math.h> Par ailleurs, il est ncessaire dindiquer, lors de la phase ddition des liens, que ces procdures sont prendre dans la bibliothque mathmatique standard du systme, en incluant loption -lm. Notes La fonction fmod fournit le reste de la division quotient entier ; le diviseur doit tre non nul. Ainsi, fmod(4.1,1.5) fournit comme rsultat 1.1. Le rsultat est du signe du premier paramtre. la fonction atan2 fournit larc dont le sinus est k x et le cosinus k y , avec k > 0.

52

CHAPITRE 3. PROCDURES

Nom acos asin atan atan2 ceil

plus grand entier au paramtre cos double cos(double x) cosinus du paramtre cosh double cosh(double x) cosinus hyperbolique du paramtre exp double exp(double x) exponentielle du paramtre fabs double fabs(double x) valeur absolue du paramtre floor double floor(double x) plus petit entier au paramtre fmod double fmod(double x, reste de la division double y) de x par y . log double log(double x) logarithme du paramtre log10 double log10(double x) logarithme en base 10 du paramtre pow double pow(double x, xy double y) sin double sin(double x) sinus du paramtre sinh double sinh(double x) sinus hyperbolique du paramtre sqrt double sqrt(double x) racine carre du paramtre tan double tan(double x) tangente du paramtre tanh double tanh(double x) tangente hyperbolique du paramtre F IG . 3.4 Quelques procdures mathmatiques du Langage C

Prototype double acos(double x) double asin(double x) double atan(double x) double atan2(double x, double y) double ceil(double x)

Description arc cosinus du paramtre arc sinus du paramtre arc tangente du paramtre arc tangente de x/y

3.1. COURS
Nom abs atof atoi atol exit Prototype Description int abs(int p) Valeur absolue du paramtre double atof(char* s) Conversion caractres vers ottant int atoi(char* s) Conversion caractres vers entier long atol(char* s) Conversion caractres vers entier void exit(int cr) Arrt du programme, fourniture dun code de retour labs long labs(long p) Valeur absolue du paramtre rand int rand(void) Fournit un entier pseudo-alatoire srand void srand(int seed) Initialisation du gnrateur de nombres pseudo-alatoires F IG . 3.5 Quelques utilitaires de C

53

Le rsultat de certaines fonctions, lorsquil sort du domaine de dnition des procdures, peut tre reprsent par des congurations spciques qui simpriment sous la forme inf (inni, par exemple le rsultat dune division par zro) ou nan (not a number). 3.1.6.2 Oprations utilitaires Dautres procdures fournies par le systme sont vocation utilitaire. La gure 3.5 en prsente certaines. Lutilisation de ces oprations ncessite linclusion de leur dclaration, obtenue en insrant la ligne suivante en tte du programme : #include <stdlib.h> Notes Lopration rand fournit les lments successifs dune squence de nombres pseudoalatoires, calculs partir dun germe qui est 1 par dfaut. La mme squence est donc fournie chaque nouvelle excution du programme. Lopration srand permet de modier le germe (1 par dfaut) utilis par lopration rand. On peut initialiser ce germe avec une valeur diffrente chaque excution dun programme pour viter dobtenir, lors dune simulation, des rsultats strictement identiques chaque excution. Par exemple, la formule magique : time((time_t *)0) fournit le nombre de secondes coules depuis le 1er janvier 1970. Cette valeur peut tre utilise comme paramtre de srand(), en dbut dexcution du programme, pour obtenir des suites alatoires diffrentes chaque excution du programme (pour utiliser time, il faut inclure dans le programme les dclarations de time.h).

54

CHAPITRE 3. PROCDURES

3.2 retenir
dnition de procdure type-du-rsultat nom (liste des paramtres) { corps de la procdure } paramtre type-du-paramtre nom-du-paramtre type void utilis pour indiquer labsence de paramtres ou de rsultats sortie et fourniture de rsultat : return ; ( utiliser pour terminer une procdure sans rsultat) return expression ; (lexpression doit fournir une valeur du type dclar pour la procdure) variables locales elles sont dclares au dbut du bloc constituant la procdure. appel de procdure procdures sans paramtre nom() procdure avec paramtres nom(liste de valeurs) Un appel de procdure doit respecter le nombre, lordre, et les types des paramtres. dclaration de procdure : au moyen du prototype type-du-rsultat nom (liste des paramtres) ; Dans le prototype, les noms de paramtres sont facultatifs. dclaration de procdure externe : au moyen du mot-clef extern inclusion de dclarations : commande du prprocesseur #include "file.h" procdures prdnies du langages : la dclaration de leurs prototypes se trouve dans les chiers math.h (procdures mathmatiques) et stdlib.h (autres procdures standard )

3.3 Travaux pratiques


Chaque tudiant enverra les programmes raliss au cours de ces travaux pratiques sous la forme dun ml unique, comportant les textes des programmes, spars par trois lignes blanches les uns des autres, ladresse girardot@emse.fr. Le sujet du ml comportera le nom de ltudiant, et la mention TP 3.

3.3. TRAVAUX PRATIQUES

55

3.3.1 Exercice 1
crire une fonction qui calcule le PPCM de deux nombres entiers. crire une fonction qui indique si deux nombres sont premiers entre eux.

3.3.2 Exercice 2
Reprendre la procdure PGCD dnie au paragraphe 3.3, page 46. Que se passe-t-il si lon effectue lappel : pgcd(0,11) Comment protger la procdure contre tout paramtre incorrect ? Comment une procdure peutelle signaler une erreur quelle dtecte au programme appelant ?

3.3.3 Exercice 3
On se propose de transformer en procdure le programme de recherche de racine de lquation x4 + 3x2 x 1 = 0 (exercice 4, chapitre 2). Cette procdure prendra comme paramtres les bornes de lintervalle de recherche, a et b, ainsi que la prcision dsire, epsilon. On utilisera cette procdure pour calculer, 106 prs, la racine du polynme situe dans lintervalle [0 1], puis, 107 prs, la racine situe dans lintervalle [1 0].

3.3.4 Exercice 4
crire (en vous basant sur un travail antrieur) une procdure premier(n) qui indique si son paramtre est un nombre premier. Raliser le programme qui afche les N premiers nombres premiers (avec N au moins gal 100).

3.3.5 Exercice 5
Consulter le manuel de rfrence de lopration rand() (par la commande man 3 rand), puis crire une procdure fournissant une valeur alatoire entre 1 et N, N tant un entier strictement positif.

3.3.6 Exercice 6
Identier, dans le projet, les parties qui vont se transformer en une (ou plusieurs) procdures. Rchir en particulier aux paramtres quil conviendra de transmettre ces procdures.

56

CHAPITRE 3. PROCDURES

Chapitre 4 Tableaux
4.1 Introduction
Ce cours va nous permettre daborder les tableaux, qui sont des collections dobjets de mme nature, les lments dun tableau de taille N tant dsigns par les entiers de lintervalle [0, N 1].

4.1.1 Un premier exemple


Imaginons que nous souhaitions traiter les notes (numriques) dun groupe de 10 lves : calculer la meilleure note, la moins bonne, la moyenne, la mdiane, convertir en notation-lettre. . . Pour stocker ces notes, il est possible dutiliser autant de variables que de notes, mais ceci prsente de nombreux inconvnients : la dclaration de ces variables devient trs vite fastidieuse ! le traitement est galement trs lourd puisque lon ne dispose daucun moyen ( part copier-coller le code, ce qui est en plus source derreurs) de traiter chaque note ; on ne dispose en particulier daucun lment du langage pour traiter globalement ces notes ; si le nombre de notes vient varier, lcriture des codes de traitement est encore alourdie. Cest pour ces raisons que les langages de programmation de haut niveau (dont C fait bien sr partie), offrent tous la possibilit de reprsenter des collections de donnes de mme type : les tableaux. Supposons donc que nous ayons traiter les 10 valeurs : 12 8 13 10 6 8 19 20 9 16 Nous allons reprsenter ces donnes par une variable de type tableau dentiers ; en C, une telle variable se dclare comme suit : int notes[10] ; Par rapport une dclaration de variable scalaire, nous avons simplement ajout, derrire le nom de la variable, un nombre entre crochets. Cette valeur, qui est obligatoirement un entier, indique le nombre dlments rservs pour le tableau. 57

58

CHAPITRE 4. TABLEAUX

Un lment du tableau est alors dsign par lexpression notes[indice], dans laquelle indice est une expression quelconque dont la valeur doit tre entire et comprise entre 0 et 9. Attention : ne pas oublier que si le tableau est dclar de taille N , le dernier lment est celui dindice N 1 (ceci est source derreurs frquentes). Linitialisation des lments du tableau peut scrire : notes[0]=12 ; notes[1]=8 ; notes[2]=13 ; ... notes[9]=16 ; Comme pour toute variable, on peut, au moment de la dclaration, initialiser les valeurs du tableau : une telle initialisation seffectue par : int notes[10] = {12, 8, 23, 24, 6, 8, 19, 20, 9, 4} ; Le fragment de programme suivant permet de calculer, par une boucle, la moyenne des notes du tableau (les variables somme, moyenne et indice ayant t dclares en int) : somme = 0 ; indice = 0 ; while (indice < 10) { somme = somme+notes[indice] ; indice = indice+1 ; } moyenne = somme/10 ; Ou encore : somme = 0 ; for (indice=0 ; indice<10 ; indice=indice+1) somme = somme+notes[indice] ; moyenne = somme/10 ; On notera la syntaxe de cette dernire forme : for (valeur_initiale ; test_de_rptition ; gestion_de_lindice) instruction qui est quivalente . . . valeur_initiale ; while (test_de_rptition) tion_de_lindice ; } { instruction ges-

4.1.2 Les tableaux


4.1.2.1 Caractristique de base Les tableaux sont reprsents par des arrangements contigus de cellules de mmoire. Lencombrement dun tableau est le produit du nombre dlments par la taille dun lment. Un tableau de 10 int utilise donc 10 4, soit 40 octets de la mmoire sur nos machines. La norme du langage prcise que les lments du tableau sont rangs en mmoire par valeurs croissantes de leurs indices.

4.1. INTRODUCTION
4.1.2.2 Dclaration de tableau

59

Lors dune dclaration dun tableau dans un programme, la taille du tableau doit tre indique dune manire ou dune autre : int notes[10] ; int titi[10] = {2,3,5,6,7,8,10,13,14,19} ; int tutu[] = {1,2,3,4,5} ; On notera dans ce dernier cas que la taille du tableau nest pas indique, mais que le nombre dlments (5) peut tre dduit par le compilateur partir des valeurs indiques. Les dclarations suivantes, par contre, sont incorrectes ou provoqueront des erreurs lexcution : int jojo[] ; int juju[5]={1,2,3,8,10,12,15} ; La premire nindique pas la taille du tableau ; la seconde tente dinitialiser avec 7 valeurs un tableau dclar 5 lments. Enn, lexemple suivant est correct : int premiers[1000]={2,3,5,7} ; Dans le tableau ainsi dclar, de 1000 lments, seuls les 4 premiers reoivent une valeur. Il nest pas possible de prsumer de la valeur des lments non initialiss : certains compilateurs peuvent dcider daffecter une valeur par dfaut (0, pour des entiers), mais un programme ne doit en aucun cas considrer ceci comme un fait acquis. Notons enn que la taille du tableau doit tre connue au moment de la compilation. Il est ainsi incorrect dutiliser une variable pour dclarer la taille dun tableau, et le code suivant provoquera une erreur : int n ; int tab[n] ; 4.1.2.3 Accs aux lments des tableaux Dans une expression, la notation tab[i] permet de rfrencer llment i du tableau tab. Cette expression sapparente une rfrence un nom de variable, et peut donc tre utilise dans la partie gauche dune affectation (ce que lon appelle une left-value ou lvalue) : tab[i] = expression ; cette criture ayant pour effet de remplacer la valeur de llment i de tab par celle de lexpression. Notons aussi que des critures telles que tab[i]++ sont lgales et ont pour effet dincrmenter llment i du tableau tab. Cest naturellement une erreur que dutiliser comme indice une valeur non entire, ngative, ou encore suprieure ou gale la taille du tableau. Attention : cette erreur ne sera pas signale par le compilateur (ce nest pas une erreur de syntaxe, mais une erreur smantique ), mais peut entraner une erreur dexcution, puisque le programme accde ainsi (en lecture ou en criture), un emplacement quil nest pas suppos consulter ou modier.

60 4.1.2.4 Tableaux et adresses

CHAPITRE 4. TABLEAUX

On a vu que lon peut accder individuellement aux lments dun tableau. Il nest par contre pas possible de manipuler le tableau globalement ; en particulier, il nest pas possible daffecter une valeur un tableau, et les critures ci-dessous provoqueront des erreurs de compilation : int tab1[10],tab2[10]; tab1={0,1,2,3,4,5,6,7,8,9}; /* ERREUR !! */ tab1=tab2; /* ERREUR !! */ En fait, lorsque lon utilise le nom dune variable de type tableau sans faire rfrence un indice de ce tableau, cette expression dsigne en fait ladresse mmoire du premier lment. Ainsi, le code suivant est parfaitement correct : int tab[10],*adr,i; adr=tab; /* OK */ i=*adr; /* equivaut a i=tab[0] */ la premire instruction consistant stocker dans la variable adr de type adresse dentier ladresse mmoire du premier lment du tableau tab, qui est bien de type entier. Il est par ailleurs totalement licite dutiliser la notation indicielle (valeur entire entre crochets) avec une variable dnie non pas comme un tableau, mais comme une adresse. Ainsi, le code suivant est tout fait correct : int tab[10],*adr; adr=tab; if (adr[2]==4) /* si le deuxieme element du tableau vaut 4 */ ... Par contre, lcriture suivante est incorrecte : int tab[10],*adr; tab=adr; /* ERREUR !! */ car ceci reviendrait vouloir changer ladresse en mmoire o est stock le tableau tab, ce qui nest pas possible (cest le compilateur qui gre cette adresse). On a ainsi tradition de dire que le nom dun tableau est une adresse constante . On verra par la suite que lon mlange allgrement ces deux notions, utilisant selon les prfrences du programmeur la version tableau ou la version adresse. Il ne faut cependant pas oublier que ces deux notions ne sont pas tout fait identiques.

4.1. INTRODUCTION
4.1.2.5 Tableaux de caractres

61

Nous avons en fait dj manipul (sans le savoir) un type de tableau fort utile, les tableaux de caractres. Ceux-ci permettent la dnition de chanes de caractres, utilises pour la reprsentations des donnes alphanumriques, des messages, etc. Un tableau de caractres peut se dclarer sous des formes telles que : char char char char tab1[10] ; tab2[10]={0,1,2,3,4,5,6,7,8,9} ; tab3[10]={H,e,l,l,0x6f,48,49,50,51,52} ; tab4[10]="ABCD" ;

Les tableaux tab2 et tab3 sont initialiss avec des valeurs entires (qui doivent appartenir lintervalle [128, 127]), fournies ici sous forme dcimale (50), hexadcimale (0x6f) ou caractre (e), reprsentant en loccurrence les codes des caractres 2, o et e respectivement. Les premiers lments du tableau tab4 sont initialiss avec les valeurs reprsentes par la chane de caractres "ABCD". Attention ! Cette chane contient 5 valeurs, qui sont les quatre lettres A, B, C et D, et le nombre 0 que le compilateur utilise comme marqueur de n de chane. Nous reviendrons sur cette convention dans la section 4.1.3. Notons encore que dans ce cas prcis, les lments dindices 5 9 ne sont pas initialiss. 4.1.2.6 Tableaux et procdures Un tableau peut tre utilis comme paramtre dune procdure : int proc(int titi[10]) { ... } ... int toto[10] ; proc(toto) ; Dans cet exemple, le paramtre titi de la procdure proc est dclar en tant que tableau de 10 lments. La procdure est ensuite appele avec comme paramtre un tableau de taille adquate. Il a t indiqu que toute utilisation du seul nom du tableau fait rfrence ladresse mmoire du premier lment : cest donc ladresse mmoire du tableau qui est passe la procdure. Ceci a deux consquences immdiates : dans la compilation de la procdure proc, le compilateur ne tient pas compte de la taille dclare pour le paramtre (car il na pas besoin dallouer la place mmoire pour le tableau, seule ladresse est transmise et stocke dans la variable locale titi), et il est quivalent dcrire : int proc(int titi[]) Attention : cette notation nest possible que pour les arguments dune procdure, pas pour dclarer des variables locales ! On trouvera galement souvent la notation quivalente : int proc(int * titi)

62

CHAPITRE 4. TABLEAUX

nous avons dj signal la grande similitude entre tableau et adresse. puisque la procdure accde ladresse mmoire du tableau, toute modication du contenu du tableau dans la procdure modie effectivement le tableau pass en paramtre ; Enn, signalons quune procdure laquelle on a pass un tableau en argument na aucun moyen (par le langage lui-mme) de connatre la taille du tableau : il ny a pas doprateur taille de tableau, et loprateur sizeof() dj mentionn appliqu un tableau argument de procdure rendra comme rsultat la taille dune adresse mmoire, soit 4 octets dans nos implmentations. Ceci impliquera donc toujours que : soit la procdure connat a priori la taille du tableau ; soit un autre argument de la procdure en prcise la taille. 4.1.2.7 Exemples Voici un exemple de procdure calculant la somme des lments dun tableau reu comme paramtre. Comme indiqu ci-dessus, le deuxime argument prcise la taille du tableau. int pruc(int titi[], int n) { int i ; int somme=0 ; for (i=0 ; i<n ; i++) somme = somme+titi[i] ; return somme ; } Retour la procdure pruc Les deux paramtres permettent de transmettre la procdure le tableau (en fait, son adresse), ainsi que le nombre dlments de ce tableau. Des appels valides de la procdure sont par exemple : pruc(toto,10) ; printf("%d\n", pruc(toto,10)) ; Dans le premier cas, le rsultat fourni par la fonction nest pas utilis. Dans le second cas, il est imprim par la procdure printf. On notera que lappel : pruc(toto,8) ; permet de calculer la somme des 8 premiers lments du tableau, bien que toto ait t dclar de dimension 10. Note Une criture quivalente la premire est : pruc(&toto[0],10) ; Le premier paramtre se lit adresse de llment zro du tableau toto. Cette notation permet de transmettre ladresse dlments autres que le premier du tableau. Ainsi, puisque les lments sont rangs en mmoire par valeurs croissantes des indices, lexpression :

4.1. INTRODUCTION
pruc(&toto[2],8) ;

63

permet de calculer la somme des lments 2 9 du tableau. Voici un second exemple : la procdure minmax calcule le minimum et le maximum des lments dun tableau pass en paramtre. Le rsultat est plac dans un autre tableau, galement pass en paramtre : void minmax(int tab[], int res[], int n) { int i ; int max, min ; max = min = tab[0] ; for (i=1 ; i<n ; i++) { if (min > tab[i]) min = tab[i] ; if (max < tab[i]) max = tab[i] ; } res[0]=min ; res[1]=max ; } Voici un programme utilisant cette procdure #include <stdio.h> int main(int argc, char * argv[]) { int juju[10]={1,2,3,5,6,8,10,12} ; int res[2] ; minmax(juju, res, 10) ; printf("%d %d\n", res[0], res[1]) ; return 0 ; }

4.1.3 Chanes de caractres


4.1.3.1 Introduction Une chane de caractres est une suite doctets non nuls, se terminant par un octet gal 0, dit souvent null. En C, une telle chane est reprsente par un tableau de char : grce la convention du zro nal, il est possible de connatre la taille de la chane ; il suft de compter les caractres jusquau caractre 0 qui marque la n. Le compilateur reconnat pour les chanes de caractres une notation de constante dbutant et se terminant par une double quote, encadrant la chane dnir : "En voici une"

64

CHAPITRE 4. TABLEAUX

Lorsque cette convention est utilise, le caractre double-quote " lui-mme doit tre prcd dun caractre \, dit caractre dchappement, ou back-slash, ce dernier caractre, pour tre reprsent, devant lui-mme tre prcd dun autre back-slash. Le caractre dchappement permet la reprsentation de certains caractres dits de contrle : ainsi, le passage la ligne se note \n. Dans un programme C, une chane de caractres reprsente une rfrence un tableau. Une notation telle que "ABCDE"[3] reprsente llment dindice 3 du tableau, cest dire le caractre D dont la reprsentation dcimale est 68 ; "ABCDE"[5] est la valeur 0 marquant la n de la chane. Notons encore que les compilateurs C effectuent une concatnation implicite de chanes de caractres qui se suivent dans le texte dun programme C. Ainsi, les deux lignes suivantes dnissent-elles la mme chane : "ABC" "XY" "012345" "ABCXY012345" Ceci permet de disposer agrablement les longues chanes sur plusieurs lignes, an daugmenter la lisibilit des programmes. Enn, rappelons que la plus grande attention doit tre porte la manipulation de chanes contenant des caractres en dehors du code ASCII : caractres accentus, signes montaires. . . Les rsultats peuvent dpendre de lenvironnement : systme dexploitation, compilateur, variables denvironnement. 4.1.3.2 Oprations sur chanes de caractres La gure 4.1 dcrit certaines des oprations de base (procdures standards) relatives aux chanes de caractres. Les prototypes de ces fonctions sont dcrits dans le chier dinclusion string.h. Notes 1. ces oprations reposent sur la convention implicite quune chane de caractres est reprsente par une suite (ventuellement vide) doctets de valeur non nulle, suivie par un octet de valeur gale 0. Si lun des paramtres ne respecte pas ce schma, le comportement est indtermin (mais on peut prdire des problmes. . .) 2. dans les oprations entranant le transfert dlments (telles strcat, strcpy, etc.) la destination est le premier paramtre de la procdure. 3. le mot-clef const prcise que le paramtre transmis dsigne une zone de mmoire qui ne sera pas modie par la procdure. 4. les versions avec n (strncat, strncpy, strncmp) limitent lopration au plus n caractres ; attention : dans le cas de strncpy, si la chane source contient plus de n caractres, la chane rsultat ne contient pas le 0 nal ! 5. les oprations ne tiennent pas compte des tailles effectives des tableaux utiliss. Cest au programmeur de sassurer que la taille de loprande destination est sufsante pour recevoir lensemble des octets de la source.

4.1. INTRODUCTION
Nom strcat Prototype Description char * strcat(char * d, Concatnation de const char * s) deux chanes strcmp int strcmp(const char * d, Comparaison de const char * s) deux chanes strcpy char * strcpy(char * d, Copie dune chane const char * s) strlen int strlen(const char * s) Longueur dune chane strncat char * strncat(char * d, Concatnation de const char * s, int n) deux chanes strncmp int strncmp(const char * d, Comparaison de const char * s, int n) deux chanes strncpy char * strncpy(char * d, Copie dune chane const char * s, int n) F IG . 4.1 Quelques oprations sur chanes de caractres 4.1.3.3 Exemples de manipulation de chanes de caractres Dclaration dune chane char c1 [] = "Une suite doctets" ;

65

Le compilateur dduit ici que la taille du tableau est de 19 octets (incluant loctet nal de valeur 0). On aurait pu dclarer de faon quivalente : char *c1 = "Une suite doctets" ; Longueur dune chane Par convention, la longueur dune chane de caractres est le nombre doctets non nuls de la chane ; ainsi, la valeur de lexpression : strlen("ABCD") ; est 4 (le nombre doctets non nuls), et non 5, nombre doctets servant reprsenter la chane. Copie dune chane char c2[10] ; ... strcpy(c2,"ABCD") ; Dans ce fragment de programme, le tableau c2, de dix lments, reoit une copie des lments de la chane "ABCD". Aprs lexcution, les lments du tableau c2 ont pour valeurs : 65 66 67 68 0 ? ? ? ? ?

66

CHAPITRE 4. TABLEAUX

(Les points dinterrogation reprsentent les lments non modis du tableau c2.) Ce serait une erreur dexcuter : strcpy(c2,"ABCDEFGHIJKLMNOP") ; car le tableau c2 nest pas de taille sufsante pour recevoir une chane de 16 caractres, cest-dire 17 valeurs. On peut, pour se protger de tels dbordements, utiliser la procdure strncpy : strncpy(c2,"ABCD",10) ; qui permet dindiquer que 10 octets au plus doivent tre copis (en comptant loctet null de n de chane). Attention, si la seconde chane est de taille suprieure ou gale au nombre maximum doctets copier, il ny a pas insertion de null en n de chane, ce qui risque de provoquer des erreurs ultrieures. . . Concatnation Lopration de concatnation permet dajouter, au bout dune chane de caractres, une copie dune autre chane. Lopration modie son premier oprande. Aprs lexcution de : strcat(c2,"XYZ") ; les lments du tableau c2 ont maintenant pour valeurs : 65 66 67 68 88 89 90 0 ? ?

Impression La spcication de format %s permet limpression dune chane : printf("c2 vaut : \"%s\"\n", c2) ; imprimera : c2 vaut : "ABCDXYZ" Comparaison Lopration de comparaison sapplique deux chanes de caractres. Le rsultat est un entier qui est ngatif si la premire chane est infrieure la seconde, nul si les deux chanes sont gales, et positif si la premire est suprieure la seconde. strcmp("ABCD","ABD") Cette expression rend une valeur ngative, car la chane "ABCD" est situe avant la chane "ABD" dans lordre lexicographique (trs prcisment, C est situ avant D dans le code ASCII). Une criture possible en C de la procdure strcmp est la suivante :

4.1. INTRODUCTION
int strcmp(char s1[], char s2[]) { int c1, c2 ; int i ; for (i=0 ; ;i++) { c1=s1[i] ; c2=s2[i] ; if (c1 == 0 || c2 == 0 || c1 != c2) return c1-c2 ; } }

67

4.1.4 Retour sur la procdure main


Nous avions indiqu que tout programme C devait comporter une procdure main, et nous pouvons dsormais prciser quels en sont les arguments. Rappelons que le prototype de cette procdure est : int main (int argc,char *argv[]); Les paramtres (que tout le monde a coutume de dnommer argc et argv bien que, comme pour toute procdure, le nom puisse tre choisi tout fait arbitrairement) sont donc : un entier, qui est le nombre darguments de la ligne de commande au moment de lexcution du programme (argc pour argument count) ; un tableau de chanes de caractres, qui sont les arguments (argv pour argument values). Ainsi, si le programme prog est lanc par la commande (dans un interprteur de commandes de type shell ou tout autre moyen dinterfaage) prog arg1 arg2 la valeur de la variable argc sera de 3, et le tableau argv contiendra : argv[0] = "prog" argv[1] = "arg1" argv[2] = "arg2" NB1 : noter que le nom du programme lui-mme fait partie des arguments, et que la valeur argc vaut donc au minimum 1 ! NB2 : tous les arguments sont du type chane de caractres ; si lon souhaite utiliser un argument de type entier ou ottant, il faudra utiliser une fonction de conversion lintrieur du code source du programme ;

68 4.1.4.1 Utilisation des arguments de la fonction main

CHAPITRE 4. TABLEAUX

Il est bien sr possible dutiliser ces arguments. Ils permettent notamment de fournir au moment de lexcution (et sans aucune entre-sortie ou dialogue avec lutilisateur) des informations au programme. Dailleurs, chaque fois que nous utilisons un outil (diteur de texte, compilateur, dbogueur), nous faisons appel cette convention.

4.2 retenir
dclaration de tableau : type nom[dimension] ; dclaration avec initialisation : type nom[dimension]= {liste de valeurs} ; indice dun lment de tableau 0 valeur < dimension lment de tableau nom[indice] nom[indice]=valeur dclaration de pointeur type * nom ; chane de caractres notation spcique pour un tableau de caractres caractre null ajout la n de la chane "ABCD" quivaut au tableau contenant les cinq caractres de codes 65, 66, 67, 68 et 0. oprations sur chanes : dnies dans string.h tableau et pointeurs tableau et procdure passage des tableaux par adresse

4.3 Travaux pratiques


Chaque tudiant enverra les programmes raliss au cours de ces travaux pratiques sous la forme dun ml unique, comportant les textes des programmes, spars par trois lignes blanches les uns des autres, ladresse girardot@emse.fr. Le sujet du ml comportera le nom de ltudiant, et la mention TP 4.

4.3.1 Exercice 1
On se propose de dterminer la moyenne olympique dune suite de N notes. Celles-ci sont donnes sous la forme dun tableau. Il convient de supprimer de ces notes la plus leve (ou

4.3. TRAVAUX PRATIQUES

69

lune des plus leves en cas de ex-aequo) et la plus faible, et de calculer la moyenne des N 2 restantes. crire une fonction dont le prototype est le suivant : double moy_olymp(int notes[], int N) ;

4.3.2 Exercice 2
crire une fonction qui ralise une permutation alatoire dun tableau dentiers (on peut utiliser la fonction rand). Si possible, cette fonction ne doit pas crer de copie du tableau, mais le permuter en place . Le prototype de cette fonction doit tre : void permute_tableau (int tab[],int N);

4.3.3 Exercice 3
On dsire manipuler des polynmes de degr arbitraire (infrieur une valeur maximale prdtermine, par exemple 31). imaginer une reprsentation, base sur un tableau, pour de tels polynmes ; implanter une procdure dvaluation de la fonction polynomiale en un point donn ; raliser la procdure daddition de deux polynmes.

4.3.4 Exercice 4
On se propose de construire un histogramme dcrivant la rpartition des valeurs des lments dun vecteur tel que celui-ci : { 2, 3, 7, 6, 9,11,12,15,18,17, 14,13,12, 7, 8, 7, 5, 3, 2, 1, 1, 0, 2, 8,11,13,12,11, 6, 3} ; Le programme afchera lhistogramme dans la fentre du terminal, en utilisant des blancs et des toiles, comme dans lexemple de la gure 4.2. crire une fonction dont le prototype est : void histog(int v[], int nb) Modier le programme an de pouvoir choisir la hauteur de lhistogramme. Le prototype devient : void histog(int v[], int nb, int H)

4.3.5 Exercice 5
On veut maintenant analyser le gnrateur de nombres alatoires fourni par le systme, rand(). On tirera 10000 valeurs alatoires, comprises entre 0 et 50, dont on tudiera la rpartition au moyen du gnrateur dhistogrammes de lexercice 2.

70 * ** ** *** **** ***** * ******* ** ******** **** ******** **** ********* **** ********* * ***** * ************ ***** ************** ****** *************** ****** *************** ****** ***************** ******* ******************* ******** ********************* ******** ****************************** F IG . 4.2 Histogramme

CHAPITRE 4. TABLEAUX

4.3.6 Exercice 6
Modier le programme prcdent, an de gnrer cette fois une distribution gaussienne qui sera calcule par le programme (on peut approcher une distribution gaussienne par une somme de douze valeurs alatoires uniformes de [-0.5,0.5]). On tracera lhistogramme de la rpartition.

4.3.7 Exercice 7
On se propose de lire une valeur numrique entire positive sur le terminal, en utilisant une procdure permettant de lire un caractre, getchar()1. La procdure lisant un caractre la fois, elle devra tre appele plusieurs fois de suite an de permettre de dcoder un nombre crit avec plusieurs chiffres. La procdure devra rejeter le caractre indiquant la n du nombre (tel un blanc, un passage la ligne, etc) au moyen de lopration ungetc().

4.3.8 Exercice 8
Modier le programme de lexercice prcdant, an quil permette de lire une valeur relle, exprime avec un point dcimal optionnel, telle que 152.11 ou 0.017, mais aussi 315, .5 ou encore 1..
1

On consultera naturellement le manuel dutilisation de cette opration sous Unix, par man getchar.

4.3. TRAVAUX PRATIQUES

71

4.3.9 Exercice 9
On se propose maintenant (cet exercice constituant la suite des deux prcdents) dcrire un programme permettant de dcoder une dure, comportant plusieurs valeurs numriques reprsentant des heures, minutes et secondes. Le caractre h suivra le nombre indiquant lheure, le caractre : sparera les minutes des secondes, les secondes pouvant elles-mme tre exprimes avec une partie dcimale. Des exemples de valeurs acceptables sont : 3h25 (trois heures et vingt-cinq minutes), 17:21 (dix-sept minutes et vingt-et-une secondes), ou encore 11h27:11.45.

72

CHAPITRE 4. TABLEAUX

Chapitre 5 Du problme au programme


5.1 Cours
Les problmes traits au chapitre 2, de nature mathmatique (calcul dun PGCD ou dun sinus), taient sufsamment simples pour tre traits en une seule passe , cest--dire par lcriture directe (aprs toutefois un peu de rexion) du programme correspondant. Il faut bien prendre conscience que dans la ralit, aucun problme nest sufsamment simple pour tre abord ainsi. Il est trs souvent ncessaire de procder une analyse permettant de dcomposer le problme en sous-problmes, puis ventuellement encore en sous-problmes, jusqu aboutir un problme pouvant tre trait directement. On retrouve ici une dmarche trs usuelle dans le domaine de lingnieur : que ce soit un systme industriel destin traiter des matriaux pour laborer des produits manufacturs, ou un programme complexe destin traiter des donnes pour construire dautres donnes, la dmarche gnrale danalyse, de dcomposition en sous-ensembles fonctionnels indpendants, est identique. Noue donnerons dans ce chapitre trois exemples danalyse et de rsolution de petits problmes informatiques : le calcul de lintervalle de temps sparant deux dates, le placement de 8 reines sur un chiquier, et enn la ralisation dun programme de MasterMind.

5.1.1 Calcul dintervalle de temps


On cherche calculer lintervalle de temps (en jours, heures, minutes, secondes) sparant deux instants donns. Chaque instant est dni par la donne des jour, mois, anne, heure, minute, seconde. 5.1.1.1 Une premire dcomposition Dterminer directement ce nombre de jours, heures, minutes et secondes est assez difcile. On va donc dcomposer ce travail en tapes plus simples. On va dans un premier temps calculer le nombre de secondes entre les deux instants donns : une fois ce nombre connu, de simples divisions et calculs de restes permettent dobtenir les quatre donnes voulues. 73

74

CHAPITRE 5. DU PROBLME AU PROGRAMME

Maintenant, pour calculer ce nombre de secondes, on va en fait calculer, pour chaque instant, lintervalle (en nombre de secondes toujours) par rapport une date de rfrence T0 . On utilise donc la relation : T2 T1 = (T2 T0 ) (T1 T0 ) On choisit comme date de rfrence le 1er janvier 1970 0h00. On sait en effet que cest sous cette forme que sont stockes de nombreuses informations de date dans le systme Unix, et on dispose en plus dune fonction de bibliothque time qui permettra de tester notre propre version de cette fonction. On supposera donc dornavant que les instants T 1 et T2 sont postrieurs cette date. On peut ainsi dja crire une partie du code : int delta_secondes ( int J1, int M1, int A1, int h1, int m1, int s1, int J2, int M2, int A2, int h2, int m2, int s2) { return N(J1,M1,A1,h1,m1,s1)-N(J2,M2,A2,h2,m2,s2); } On ne tiendra pas compte (pour linstant) des problmes de passage entre heure dt et heure dhiver : toutes les dates sont supposes tre exprimes en temps universel. 5.1.1.2 Analyse de la fonction N On notera pour la suite J, M, A, h, m et s les jour (de 1 31), mois (de 1 12), anne (suprieure 1970), heure (de 0 23), minute (de 0 59), seconde (de 0 59)1 . On peut encore dcomposer le problme en remarquant que la quantit recherche est la somme : du nombre de secondes entre le 1er janvier 1970 0h00 et le 1er janvier de lanne A 0h00 (ce nombre ne dpend que de A, on le note N1 (A)) ; du nombre de secondes entre le 1er janvier de lanne A 0h00 et le 1er jour du mois M de lanne A 0h00 (ce nombre ne dpend que de A et M, on le note N2 (M, A)) ; du nombre de secondes entre le 1er jour du mois M de lanne A 0h00 et le jour J du mois M de lanne A 0h00 (ce nombre ne dpend que de J, on le note N3 (J )) ; du nombre de secondes entre le jour J du mois M de lanne A 0h00 et le jour J du mois M de lanne A lheure h :m.s (ce nombre ne dpend que de H, M et S, on le note N4 (h, m, s)). On peut ainsi crire : N (J, M, A, h, m, s) = N1 (A) + N2 (M, A) + N3 (J ) + N4 (h, m, s) On peut de plus remarquer que N1 , N2 et N3 sont des nombres de secondes correspondant des jours entiers : il est ainsi possible dcrire N i = Nji 86400, les Nji correspondant aux nombres de jours (et 86400 est le nombre de secondes par jour). On peut donc crire la fonction N:
dans un souci de simplicit, on ne tiendra pas compte des secondes supplmentaires parfois ajoutes pour corriger les dfauts de dure de rvolution terrestre.
1

5.1. COURS
int N (int J,int M,int A,int h,int m,int s) { return N_4(h,m,s)+86400*(Nj_1(A)+Nj_2(M,A)+Nj_3(J)); } 5.1.1.3 Calcul de N4 (h, m, s) Ce calcul est trs simple : on peut crire directement la fonction : int N_4 (int h,int m,int s) { return s+60*(m+60*h); } 5.1.1.4 Calcul de Nj3 (j ) Pas de difcult particulire non plus ! On crit : int Nj_3 (int j) { return j-1; } 5.1.1.5 Calcul de Nj1 On peut crire : Nj1 (A) =
A1 a=1970

75

nj (a)

o nj (a) dsigne le nombre de jours de lanne a. On sait que les annes comportent 365 jours, sauf les annes bissextiles qui en comportent 366. On rappelle que, dans le calendrier grgorien, sont bissextiles les annes divisibles par 4, sauf celles divisibles par 100, moins quelles ne soient aussi divisibles par 400 2 . On peut donc crire une fonction que lon note bissextile(A) permettant de tester si son argument est bissextile. Cette fonction permet ensuite dcrire lalgorithme de calcul de Nj 1 , crit ci-dessous en C : int n_j (int a) { if (bissextile(a)) return 366; return 365; }
Les lecteurs intresss par les problmes dajustement de calendrier peuvent consulter lURL http ://www.emse.fr/roelens/calendar.txt
2

76

CHAPITRE 5. DU PROBLME AU PROGRAMME

int Nj_1 (int annee) { int nb,a; for (nb=0,a=1970;a<annee;a++) nb+=n_j(a); return nb; } Le code de la fonction bissextile peut lui-mme scrire : int bissextile (int annee) { if (annee % 4) return 0; if (annee % 100) return 1; if (annee % 400) return 0; return 1; } 5.1.1.6 Calcul de Nj2 Calcul galement non trivial. En effet, les mois ont un nombre de jours variable, et il nexiste pas vraiment de formule permettant de calculer ce nombre de jours en fonction du numro du mois. Il est alors plus pratique dcrire une fonction qui effectue un calcul spcique en fonction de chaque mois. Notons au passage que le calcul est modi partir du mois de mars si on est dans une anne bissextile, do lutilit de passer en paramtre lanne ! Voici une (ce nest bien sr pas la seule) faon dcrire cette fonction : int Nj_2 (int mois,int annee) { int nb=0; switch (mois) { case 12: /* on ajoute le nb de jours de novembre */ nb+=30; case 11: /* on ajoute le nb de jours doctobre */ nb+=31; case 10: /* on ajoute le nb de jours de septembre */

5.1. COURS
nb+=30; case 9: /* on ajoute le nb de jours daout */ nb+=31; case 8: /* on ajoute le nb de jours de juillet */ nb+=31; case 7: /* on ajoute le nb de jours de juin */ nb+=30; case 6: /* on ajoute le nb de jours de mai */ nb+=31; case 5: /* on ajoute le nb de jours davril */ nb+=30; case 4: /* on ajoute le nb de jours de mars */ nb+=31; case 3: /* on ajoute le nb de jours de fevrier */ /* 29 si annee bissextile, 28 sinon */ if (bissextile(annee)) nb+=29; else nb+=28; case 2: /* on ajoute le nb de jours de janvier */ nb+=31; case 1: return nb; } }

77

Remarque 1 : on rutilise ici la fonction bissextile, dj utilise pour la fonction Nj 1 . Cette rutilisation est lun des avantages du dcoupage en fonctions : une fonction reprsente une suite dinstructions utilisable autant de fois que souhait. Remarque 2 : de lanne. cette fonction dpend stricto sensu non pas de lanne, mais de la bissextilit

Remarque 3 : on a utilis la smantique particulire du switch ... case en C, attention bien la comprendre !

78

CHAPITRE 5. DU PROBLME AU PROGRAMME

Remarque 4 : cette criture nest pas ncessairement la plus efcace ! 5.1.1.7 Correction dune inexactitude On signale alors que la rgle utilise pour le calcul des annes bissextiles est inexacte : en effet, les annes divisibles par 4000 et dont le quotient est impair (comme 4000, 12000...), ne sont pas bissextiles3 ! Il suft alors de modier la fonction bissextile, pour la version suivante : int bissextile (int annee) { if (annee % 4) return 0; if (annee % 100) return 1; if (annee % 400) return 0; if (annee % 4000) return 1; if ((annee / 4000) % 2) return 0; return 1; } On voit alors quaucun autre code nest modi, en particulier, pas le code de Nj 1 et Nj2 qui utilisent cette fonction. Cest aussi un avantage de cette conception : partir du moment o la smantique (ce quelle est cense faire) et linterface (son nom, ses paramtres, son type de rsultat) ne sont pas modies, il nest pas ncessaire de modier les fonctions utilisatrices. 5.1.1.8 Le bug du 19 janvier 2038 Si on teste le programme prcdent, avec la date du 19 janvier 2038 3 heures 14 minutes et 8 secondes (temps universel), on obtient un temps ngatif (pour tre prcis, on obtient -2147483648) ! Ceci est d au fait que les entiers (int) sont classiquement cods sur 32 bits : or, la date indique, le nombre de secondes est de 231 , qui dans le codage sur 32 bits, correspond 231 = 2147483648. Il faudra donc dici l trouver une parade ce problme : si lon se rfre au bug de lan 2000, on peut estimer que la majorit du travail de correction sera effectue en dcembre 2037... Plus srieusement, la parade est dj trouve : il suft de passer un codage des dates sur 64 bits (la majeure partie des systmes dits 64 bits le font dj). Ce codage ne posera problme que dans (approximativement) 292 milliards dannes. Encore une fois, il faut tre conscient des limitations de limplantation informatique des fonctions.
3

Cette modication propose par lastronome Herschell na jamais t adopte. . .

5.1. COURS

79

5.1.2 Le problme des reines sur un chiquier


On cherche placer N reines sur un chiquier NxN de faon ce quaucune des reines ne soit en mesure de prendre une autre (deux reines sont toujours sur des horizontales, verticales et diagonales diffrentes). Plus prcisment, on cherche crire un programme dont le seul argument est la valeur de N : le programme doit alors afcher sous une forme dessine (pas besoin de graphique compliqu, se contenter de dessins alphanumriques) les reines sur lchiquier. En n de programme, on indique le nombre de solutions diffrentes obtenues. 5.1.2.1 Un peu danalyse On peut rsoudre ce problme de faon brutale (les anglo-saxons appellent cette mthode brute force algorithm) : on gnre toutes les positions possibles des N reines sur lchiquier, et on teste pour chaque position si les reines peuvent se prendre ! On peut toutefois amliorer un peu lalgorithme en remarquant que chaque ligne de lchiquier doit contenir une et une seule reine. On peut alors reprsenter une position des N reines par un tableau de taille N, llment dindice i du tableau correspondant au numro de colonne dans laquelle se trouve la reine de la ligne. Lalgorithme peut alors scrire trs simplement : gnrer la position initiale , initialiser le nombre de solutions zro ; tant que lon na pas ni si la position est convenable, la dessiner et incrmenter le nombre de solutions (sinon, ne rien faire) ; gnrer la position suivante ; afcher le nombre de solutions obtenues. Comme dhabitude, nous utiliserons un tableau de taille maximale xe, dont une partie seulement sera effectivement utilise pour un N particulier (N infrieur la taille maximale, bien entendu !). 5.1.2.2 Gnration des positions Lalgorithme indiqu ci-dessus parle de position initiale et de position suivante : encore convient-il de prciser ce que sont ces notions ! Revenons notre modle : une position est pour nous un tableau de N entiers de 0 N-1. On a donc un ordre naturel sur ces positions qui est lordre lexicographique : la premire position est (0, 0, . . . , 0), la suivante est (0, 0, . . . , 1), jusqu (0, . . . , 0, N 1), puis (0, . . . , 1, 0), . . .la dernire tant (N 1, . . . , N 1). On peut trs facilement gnrer la position initiale : il suft de mettre zro tous les lments du tableau ! Pour gnrer la position suivante, on incrmente le dernier lment du tableau. Si ce dernier lment prend la valeur N, alors on le remet 0 est on incrmente lavant dernier. Si cet avant-dernier lment prend la valeur N, on le remet 0 et on incrmente lantpnultime. . . Lorsque le premier lment prend la valeur N, on a ni !

80

CHAPITRE 5. DU PROBLME AU PROGRAMME

Note : pensez au fonctionnement dun compteur kilomtrique, qui afche des chiffres de 0 9. . . On trouvera ci-dessous un premier morceau de notre programme. #include <stdio.h> /* taille maximale de lechiquier */ #define NMAX 32 typedef int position[NMAX]; void init_position (int N,position p) { int i; for (i=0;i<N;i++) p[i]=0; } /* cette fonction rend 0 si on est a la derniere */ /* position, et 1 sinon */ int next_position (int N,position p) { int j; for (j=N-1;j>=0;j--) if (++p[j]==N) p[j]=0; else break; return j!=-1; } int main (int argc,char *argv[]) { position pos; int N,nb; if (argc==2) N=atoi(argv[1]); else N=8; init_position(N,pos); for (nb=0;;) { if (test_position(N,pos)==1) { dessine_position(N,pos);nb++;

5.1. COURS
} if (next_position(N,pos)==0) break; } (void) printf("%d positions trouvees\n",nb); return 0; } 5.1.2.3 Test dune position

81

Pour tester une position, on doit vrier que pour tout couple de reines, les positions correspondent des lignes diffrentes (cest vrai par construction !), des colonnes diffrentes et des diagonales diffrentes. Pour tester si ce sont des colonnes diffrentes, il suft de vrier que les valeurs des lments sont diffrentes. Pour tester si ce sont des diagonales diffrentes, il suft de tester si la valeur absolue de la diffrence entre les numros de lignes est diffrente de la valeur absolue de la diffrence entre les numros des colonnes (faire un dessin, si besoin). On en dduit le code de la fonction de test : int test_position (int N,position p) { int i,j; for (i=0;i<N;i++) for (j=0;j<i;j++) if (p[i]==p[j] || (p[i]-i)==(p[j]-j) || (p[i]+i)==(p[j]+j)) return 0; return 1; } 5.1.2.4 Dessin de lchiquier Laiss titre dexercice au lecteur. . . 5.1.2.5 Quelques rsultats On obtient les rsultats suivants, pour les petites valeurs de N : N=1 : 1 position N=2 : 0 position N=3 : 0 position N=4 : 2 positions N=5 : 10 positions N=6 : 4 positions N=7 : 40 positions

82

CHAPITRE 5. DU PROBLME AU PROGRAMME

N=8 : 92 positions On notera que le temps de calcul pour N=8 commence tre long : ceci sexplique par la complexit en N N de lalgorithme, soit dj plus de 16 millions de positions tester ! Cette mthode est bien sre loin dtre efcace. . .

5.1.3 Toujours plus complexe


On a vu dans les exemples prcdents que la complexit dun problme pouvait porter sur les traitements : les donnes sont simples mais les traitements effectuer sur icelles sont analyser, dcomposer... Il est un autre domaine de complexit portant cette fois-ci sur les donnes du problme : leur nombre, leur diversit, amnent une analyse plus pousse de ces donnes, do peuvent en dcouler dailleurs des rexions sur les traitements. Cest ce qui va tre mis en vidence sur lexemple suivant. On veut crire un programme permettant de jouer au MasterMind. Lordinateur choisit une combinaison de couleurs, et lutilisateur essaie de la deviner en proposant des combinaisons : pour chaque combinaison propose, lordinateur indique le nombre de couleurs bien places et le nombre de couleurs mal places . 5.1.3.1 Description prcise du jeu Il convient tout dabord de bien prciser le fonctionnement voulu du jeu, car bien que ce soit un jeu connu, un certain nombre de variantes existent ! La combinaison dcouvrir est une suite (ordonne) de m couleurs, ces couleurs tant prises parmi p couleurs disponibles. Selon le choix de lutilisateur, chaque couleur peut tre utilise une seule fois (jeu simple), ou plusieurs fois (jeu plus complexe). On souhaite que lutilisateur puisse choisir la valeur de m entre 2 et 6, et la valeur de p entre 2 et 8, les 8 couleurs (au maximum) utilises tant rouge, vert, bleu, jaune, marron, violet, orange, rose. On considre galement que le nombre de propositions est limit M , variant de 6 12 : lutilisateur a perdu sil ne trouve pas la combinaison au bout des M essais. Le programme choisit une combinaison alatoirement (si possible, toutes les combinaisons ont une probabilit gale) ; ensuite, tant que lutilisateur na pas trouv la solution, le programme demande une nouvelle proposition. Il compare cette proposition la combinaison trouver, et indique combien de couleurs sont bien places et combien sont mal places (attention : si une couleur apparat plusieurs fois dans la combinaison ou dans la proposition, on ne doit la compter quune seule fois !). Si lutilisateur a trouv la combinaison, il indique le nombre de coups jous. Si le nombre maximal dessais est atteint, le programme indique au joueur quil a perdu et donne la combinaison. Enn, pour aider lutilisateur, le jeu doit proposer les aides suivantes : chaque nouvelle proposition valide est compare aux prcdentes et les incohrences sont signales ; il doit tre possible de revoir lensemble des propositions dj faites avec les scores associs.

5.1. COURS
5.1.3.2 Analyse, modlisation des donnes

83

Paramtres Comme indiqu ci-dessus, on note m le nombre de couleurs de la combinaison, p le nombre de couleurs possibles, M le nombre maximal de combinaisons proposables par lutilisateur. On a galement besoin dun indicateur permettant de savoir si une couleur peut tre utilise une seule fois ou plusieurs fois : on notera multi cet indicateur, valant 1 si lon peut rpter une couleur, et 0 sinon. Note : une fois choisis, ces paramtres ne sont plus modis au cours du jeu.

Couleurs On a bien sr besoin de reprsenter informatiquement les couleurs ! Chaque couleur sera reprsente par un entier entre 0 et p 1. Puisque la valeur maximale de p est 8, cela donne donc un entier entre 0 et 7. On peut donc utiliser des variables de type char (entier sur 8 bits) pour coder la couleur. On a galement besoin dune reprsentation textuelle des couleurs (il est plus commode pour le joueur de lire rouge, vert ou bleu que 0, 3 ou 6. . .). On utilisera pour cela des chanes de caractres, stockes dans un tableau : lindice i du tableau correspond la description textuelle de la couleur i. Combinaison Comme une combinaison est une srie de couleurs, on va utiliser un tableau de couleurs (donc, un tableau de char) pour coder les combinaisons. Le nombre de couleurs de la combinaison tant limit 6, tous les tableaux seront de taille 6 (on utilisera toutefois une macro en C pour dnir cette valeur). Si le nombre m est infrieur 6, on nutilisera quune partie de chaque tableau. Tableau de jeu Il est ncessaire de conserver en mmoire toutes les combinaisons joues (an de pouvoir grer laide). Comme chaque combinaison est un tableau, on va donc utiliser un tableau deux dimensions pour grer ce tableau de jeu : le premier indice correspond au numro de combinaison, le deuxime indice correspond au numro de la couleur au sein de la combinaison. On va utiliser un tableau de taille 12x6 (toujours grce une macro) dont on nutilisera effectivement que la partie Mxm (le coin suprieur-gauche ou nord-ouest). Scores On a besoin, pour chaque proposition, de stocker le score . Ce score tant ici compos de deux valeurs, on utilisera un tableau deux dimensions, chaque ligne comportant deux valeurs : lindice 0 correspond au nombre de couleurs bien places, lindice 1 correspond au nombre de celles qui sont mal places. Encore une fois, le nombre de lignes du tableau sera pris comme une valeur maximale (nombre dessais) dont seule une partie sera effectivement utilise pour une valeur de M donne. Traduction en C Traduit en C, cela donne la version suivante :

84 #define MAXCOMBI 6 #define MAXCOULEURS 8 #define MAXESSAIS 12

CHAPITRE 5. DU PROBLME AU PROGRAMME

typedef char mm_combi[MAXCOMBI]; typedef char mm_jeu[MAXESSAIS][MAXCOMBI]; typedef int mm_scores[MAXESSAIS][2]; int m,M,p,multi; Note : on a utilis la dnition de type en C (mot-cl typedef) permettant de donner un nom de type parlant nos variables. 5.1.3.3 Les traitements Une fois les donnes modlises, on peut sintresser aux diffrents traitements que le programme doit effectuer. Chaque traitement fera lobjet dune (ou plusieurs) procdure qui ralise informatiquement le traitement correspondant. On prcisera alors les donnes dentre et les rsultats en sortie de chaque procdure. 5.1.3.4 Tirage au sort de la combinaison Il sagit de choisir alatoirement m valeurs entre 0 et p, tirage effectu sans remise si on nautorise quune seule fois chaque couleur, avec remise si on peut utiliser plusieurs fois chaque couleur. On sait que lon dispose dune fonction rand() qui, daprs notre documentation, effectue un tirage pseudo-alatoire entre 0 et RAND_MAX. Pour obtenir un tirage pseudo-alatoire entre 0 et n 1, il suft deffectuer un modulo n (on ngligera les imperfections 4 de rpartition dun tel tirage). Si le tirage se fait avec remise, chaque couleur de la combinaison est obtenue par un tirage indpendant des autres. Si le tirage est fait sans remise, on peut utiliser une procdure ressemblant beaucoup un exercice du chapitre 4 (gnration dune permutation alatoire) en tronquant la gnration aprs le pe lment. Les paramtres de cette procdure sont donc : en entre, m, p et lindicateur multi ; en sortie, la combinaison initiale ; comme tout rsultat de type tableau, le paramtre est pass par adresse la procdure. do un prototype en C de cette procdure : int init_combi (int m,int p,int multi,mm_combi la_combi); La fonction rend 0 si le tirage a russi, -1 en cas de problme (tirage sans remise avec m suprieur p). On peut bien sr dcomposer cette fonction en deux, lune pour le tirage sans remise, lautre pour le tirage avec remise. Voici une faon dimplmenter ces deux fonctions :
4

Do viennent-elles, et pourquoi les ngliger ?

5.1. COURS
int init_combi_remise (int m,int p,mm_combi la_combi) { int i; for (i=0;i<m;i++) la_combi[i]=(rand() % p); return 0; } int init_combi_sansremise (int m,int p,mm_combi la_combi) { char aux[MAXCOULEURS]; int i,j; if (m>p) return -1; for (i=0;i<p;i++) aux[i]=i; for (i=0;i<m;i++) { j=(rand() % (p-i)); la_combi[i]=aux[i+j]; aux[i+j]=aux[i]; } return 0; } int init_combi (int m,int p,int multi,mm_combi la_combi) { srand(time(0)); if (multi) return init_combi_remise(m,p,la_combi); return init_combi_sansremise(m,p,la_combi); } 5.1.3.5 Lecture de la proposition de lutilisateur

85

On souhaite que linterface permettre lutilisateur de donner sa proposition sous la forme de noms de couleurs. On utilisera pour sparer les couleurs des caractres spciaux comme les espaces, les tabulations, ou ventuellement les virgules. Sont ainsi des entres convenables (dans le cas m = 4 et p = 6) : rouge vert bleu jaune rouge, vert bleu,jaune ainsi que : rouge, vert bleu, jaune

86

CHAPITRE 5. DU PROBLME AU PROGRAMME

On fera en sorte que, si le joueur entre une ligne vide ou un nombre de couleurs insufsant, le programme afche laide (impression des combinaisons prcdemment joues). On prendra galement garde ne pas lire trop de couleurs (on stoppe ds que lon en a lu m), et vrier que les couleurs sont bien les p premires. Notre fonction de lecture aura alors comme prototype : int lire_la_combi (int m,int p,mm_combi la_combi); la valeur retourne tant le nombre de couleurs effectivement lues. Note : ce niveau du cours, les entres-sorties nont pas t abordes, et on ne dtaillera pas limplmentation de cette procdure. Avertissement : on rappelle que les erreurs de conception des entres-sorties sont frquemment lorigine de dysfonctionnements des programmes. 5.1.3.6 Manipulation des couleurs On va avoir besoin pour imprimer les combinaisons, ou bien pour effectuer la saisie des combinaisons, de convertir le nom dune couleur en son numro et rciproquement. Il est alors souhaitable dcrire les deux fonctions de conversion suivantes : int numero_couleur (char *str_couleur); char *chaine_couleur (int num_couleur); la premire donnant le numro de la couleur dnie par la chane de caractres passe en argument (et -1 en cas derreur), la seconde donnant la description sous forme de chane de caractres de la couleur passe en argument (et 0 en cas derreur). On trouvera ci-aprs une (ce nest pas la seule) faon dimplmenter ces deux fonctions : char *tab_couleurs[MAXCOULEURS] = {"rouge","vert","bleu","jaune", "marron","violet","orange","rose"}; int numero_couleur (char *str) { int i; for (i=0;i<MAXCOULEURS;i++) if (!strcmp(str,tab_couleurs[i])) return i; return -1; } char *chaine_couleur (int num) {

5.1. COURS
if ((num<0)||(num>=MAXCOULEURS)) return 0; return tab_couleurs[num]; } 5.1.3.7 Calcul du score dune proposition

87

tant donn une combinaison et une proposition, on doit calculer le nombre de couleurs bien places et le nombre de couleurs mal places. Il faut bien prendre garde ce quune couleur ne soit jamais compte deux fois ! Pour cela, on commence par calculer le nombre de couleurs bien places : on compare les couleurs aux mmes indices dans la combinaison et dans la proposition. Si les couleurs sont identiques, on ajoute un au nombre de bien places. An dviter de recompter cette couleur en tant que mal place, on remplacera la couleur dans la combinaison par une valeur non attribue (MAXCOULEURS, par exemple) et dans la proposition par une valeur non attribue diffrente (MAXCOULEURS+1, par exemple). Il faut donc faire attention faire des copies pralables de la combinaison et de la proposition ! On peut calculer ensuite les couleurs mal places : il faut cette fois-ci tester les couleurs des positions diffrentes dans la combinaison et dans la proposition. On utilisera le mme mcanisme de remplacement des couleurs par des valeurs non attribues si lon trouve des couleurs concordantes. On obtient alors le code C suivant : /* le resultat est le nombre de "bien places" */ int teste_combi (int m,mm_combi la_combi,mm_combi essai, int score[2]) { mm_combi la_combibis,essaibis; int i,j; for (i=0;i<m;i++) { la_combibis[i]=la_combi[i]; essaibis[i]=essai[i]; } /* on calcule le nombre de bien places : on modifie */ /* alors la combi et lessai pour ne pas les */ /* recompter en tant que mals places */ for (i=0,score[0]=0;i<m;i++) if (la_combi[i]==essai[i]) { score[0]++; la_combibis[i]=MAXCOULEURS; essaibis[i]=MAXCOULEURS+1; } /* on calcule le nombre de mal places : on modifie */ /* encore la combi et lessai pour ne pas compter */ /* deux fois la meme couleur */

88

CHAPITRE 5. DU PROBLME AU PROGRAMME


for (i=0,score[1]=0;i<m;i++) for (j=0;j<m;j++) if ((i!=j)&&(la_combibis[i]==essaibis[j])) { score[1]++; la_combibis[i]=MAXCOULEURS; essaibis[j]=MAXCOULEURS+1; } return score[0]; }

Note : la fonction rend un rsultat de type entier alors quon sattend ce quelle rende un score. Ceci est d au fait quen C, il nest pas possible quune fonction renvoie un rsultat de type tableau : on passe donc le tableau (ladresse du tableau pour tre prcis) en argument la fonction. Le rsultat est ici le nombre de couleurs bien places : on teste si ce rsultat est gal m pour savoir si lon a trouv la combinaison. 5.1.3.8 Gestion de laide Laide comprend deux parties : si le joueur ne saisit pas une proposition complte, on afche les propositions prcdentes et les scores ; si le joueur saisit une proposition correcte, on commence par vrier quelle est cohrente avec les propositions prcdentes ; cela signie que le score obtenu par chaque proposition prcdente doit tre identique au score que lon aurait obtenu si la combinaison tait identique la nouvelle proposition. Pour afcher une proposition, on peut tout--fait crire une fonction spcique, comme celle indique ci-aprs : void print_combi (int m,mm_combi la_combi) { int i; for (i=0;i<m;i++) (void) printf("%s%c",chaine_couleur(la_combi[i]), (i<(m-1)) ? , : \n); } Note : on utilise la fonction chaine_couleur dnie prcdemment ; noter galement lutilisation de lexpression x ? y : z, qui si x est vrai (non nul) vaut y, et z sinon. On peut alors crire la fonction dafchage des combinaisons prcdentes elle-mme : void print_aide (int m,int i,mm_jeu le_jeu,mm_score sc) { int j; for (j=0;j<i;j++) {

5.1. COURS
(void) printf("Prop. %d :",j); print_combi(m,le_jeu[j]); (void) printf("\t%d bien places, %d mal places\n", sc[j][0],sc[j][1]); } }

89

Pour la vrication de la cohrence par rapport aux propositions prcdentes, voici une faon de programmer la fonction : /* teste si la proposition i est coherente avec les */ /* precedentes : rend 1 sil y a incoherence, 0 sinon */ int teste_incoherence (int m,int i,mm_jeu le_jeu, mm_score le_score) { int j,tmp_score[2]; for (j=0;j<i;j++) { (void) teste_combi(m,le_jeu[i],le_jeu[j],tmp_score); if ((tmp_score[0]!=le_score[j][0])|| (tmp_score[1]!=le_score[j][1])) { (void) printf("proposition incoherente" " avec reponse %d\n",j); return 1; } } return 0; } 5.1.3.9 Le jeu complet On peut maintenant combiner les fonctions prcdentes pour obtenir le jeu. On va en fait crire une premire fonction qui dcrit une seule phase de jeu : saisie de la proposition de lutilisateur ; test de validit, afchage de laide si besoin ; test de cohrence, afchage de laide si besoin ; calcul et afchage du score de cette proposition. La fonction rend 1 si lutilisateur a trouv la solution, et 0 sinon. Voici une implmentation de cette phase de jeu : int phase_jeu (int m,int p,int i,mm_combi la_combi, mm_jeu le_jeu,mm_score le_score) { for (;;) { if (lire_combi(m,p,le_jeu[i])!=m) { (void) printf("erreur de saisie !\n");

90

CHAPITRE 5. DU PROBLME AU PROGRAMME


print_aide(m,i,le_jeu,le_score); continue; } if (teste_incoherence(m,i,le_jeu,le_score)) { print_aide(m,i,le_jeu,le_score); continue; } break; } if (teste_combi(m,la_combi,le_jeu[i],le_score[i])==m) { (void) printf("combinaison trouvee en %d coups !\n",i); return 1; } (void) printf("%d bien places, %d mal places\n", le_score[i][0],le_score[i][1]); return 0; }

On peut maintenant crire le jeu complet : gnration de la combinaison trouver ; rptition dune phase de jeu tant que le nombre dessais est infrieur au maximum et que la combinaison nest pas trouve ; si le joueur na pas trouv, afchage de la solution. ce qui peut se programmer comme suit : int partie (int m,int p,int multi,int M) { mm_combi la_combi; mm_jeu le_jeu; mm_score le_score; int i; if (init_combi(m,p,multi,la_combi)==-1) { (void) printf("ERREUR !\n"); return 2; } for (i=0;i<M;i++) if (phase_jeu(m,p,i,la_combi,le_jeu,le_score)) return 1; (void) printf("vous navez pas trouve," " la combinaison etait:\n"); print_combi(m,la_combi); return 0; }

5.2. RETENIR

91

5.2 retenir
avant tout choix dalgorithme, se poser la question de la nalit de lapplication raliser lorsque cest possible et utile, rchir longuement lalgorithme et aux structures de donnes mettre en uvre dcomposer le problme en sous-problmes plus simples, que lon programmera sous forme de procdures, et ventuellement de modules spars crire les programmes de manire claire, lisible et are, en privilgiant les commentaires signicatifs ; exemple a contrario : i=i+1 ; /* On ajoute 1 i */

5.3 Travaux pratiques


5.3.1 Exercice 1
Faire lanalyse, la modlisation, la conception du mini-projet. On rchira notamment aux points suivants : comment reprsenter les donnes du problme ? comment reprsenter la solution du problme ? par quel algorithme peut-on trouver la solution du problme ? question subsidiaire : cet algorithme est-il efcace, peut-on lamliorer ?

92

CHAPITRE 5. DU PROBLME AU PROGRAMME

Deuxime partie Annexes

93

Annexe A Quelques aspects du matriel


A.1 Processeur, ou unit centrale
Unit de commande transfert des instructions depuis la mmoire dcodage et excution des instructions Registres : mmoire trs rapide situe dans lUC adresse : dsignent un lment de la mmoire donne : reprsentent une valeur tat : reprsentent une partie de ltat du processeur Unit arithmtique et logique dcodage des fonctions oprations arithmtiques de base + oprations logiques, dcalages Performances lies la frquence dhorloge et la nature du processeur mesures en MIPS, Millions of Instructions Per Second

A.2 Mmoire
Mmoire centrale Volatile Technologie : circuits silicium Espace linaire dlments identiques lments : des octets (byte) de 8 bits ; Un lment peut reprsenter 28 valeurs distinctes Dsigns par les entiers de lintervalle [0, N 1] Les lments sont directement accessibles par la CPU Les temps daccs sont trs rduits (108 secondes) Capacit : 256 Mo ( 108 octets) Mmoire secondaire 95

96

ANNEXE A. QUELQUES ASPECTS DU MATRIEL


Rmanente Diverses technologies (disques, CD ROMS. . .) Accs par blocs dlments Transferts vers (ou depuis) la mmoire centrale Temps daccs plus importants (10 3 secondes) Capacit : 128 Go ( 1011 octets)

A.3 Bus
Un bus est un ensemble de ls connectant des units fonctionnelles au sein dun ordinateur bus interne CPU cache (300 bits Pentium Pro) bus donne Processeur Mmoire lignes adresses [16, 32, 48 bits] lignes donnes [8, 16, 32, 64 bits] signaux [contrle et logique] normes : ISA, PCI, etc.. . . bus externe : Ordinateur Priphrique arbitrage : centralis/dcentralis normes : IDE, SCSI, USB, etc.. . .

A.4 Exemple de Processeur


La gure A.1 page ci-contre montre un Pentium Pro, processeur Intel sorti en mars 1995. Ses caractristiques sont les suivantes : bus interne 300 bits, bus externe 64 bits mmoire 4 Go, mmoire virtuelle 64 To processeur : 5.5 M transistors, cache 62 M transistors horloge 200 MHz La gure A.2 page 98 (snarfe dun cours de Stanford University) dtaille limplmentation matrielle des diffrentes fonctions dun Pentium 4.

A.4. EXEMPLE DE PROCESSEUR

97

F IG . A.1 Pentium Pro : processeur, 2 caches de 512 Ko

98

ANNEXE A. QUELQUES ASPECTS DU MATRIEL

F IG . A.2 Pentium 4

Annexe B Environnement de dveloppement


Avant-propos
Il ne nous (les enseignants en informatique) a pas sembl souhaitable pour ce cours dintroduction linformatique de mettre disposition des lves un environnement de dveloppement intgr tel que ceux que lon peut trouver dans lindustrie. En effet, par leur ct intgr, ils tendent parfois cacher les concepts informatiques (chiers, processus, programme, compilateur, dbogueur, etc.) sous-jacents, dont lapprentissage est aussi un des objectifs du cours. De plus, les environnements choisis (Linux et gcc dun ct, et DJGPP sous Windows de lautre) font partie de la grande famille des logiciels libres, et ce titre sont utilisables dans tout contexte, y compris commercial. Un avantage non ngligeable est aussi le fait quon y trouve un grand nombre dutilitaires bien commodes pour les enseignants car identiques ceux quils utilisent quotidiennement. Vous pourrez donc parfois trouver frustes ce mode de travail et ces environnements, mais ils conviennent tout--fait au but que nous cherchons atteindre dans ce premier cours.

B.1 Lenvironnement de base


Rappel : le matriel utilis est le parc de micro-ordinateurs du 4e tage, utilisant au choix le systme dexploitation Microsoft Windows2000 ou le systme Linux. La fabrication de vos programmes va ncessiter lutilisation successive de plusieurs outils : diteur de texte, compilateur, dbogueur. Lenvironnement de programmation ntant pas intgr, vous aurez donc dclencher lexcution de ces outils manuellement .

B.2 Utilisation sous Windows


Nous utilisons sous Windows un environnement de dveloppement particulier, DJGPP, qui permet dutiliser le compilateur gcc du projet GNU. 99

100

ANNEXE B. ENVIRONNEMENT DE DVELOPPEMENT

F IG . B.1 Commande DOS

B.2.1 Linterprteur de commandes


Pour mettre en uvre DJGPP, il est ncessaire de disposer dun interprteur de commandes, donc le rle est prcisment de saisir des lignes de texte tapes au clavier pour dclencher lexcution des commandes concernes. Sous lenvironnement Windows, le plus connu de ces interprteurs est la bote MS-DOS , que vous pouvez lancer par le menu Dmarrer puis le sous-menu Programmes, puis le sous-sous-menu Accessoires (choix Invite de commandes)1. La gure B.1 montre une telle fentre. Il est possible galement dutiliser une fentre bash (c.f. gure B.2 page suivante), dont linterprte utilise une syntaxe lgrement diffrente de celle de linterprte de commandes DOS. Le lancement dun programme se fait par lintermdiaire dune commande, cest--dire une ligne de texte frappe au clavier et termine par la touche Return ; par exemple, la commande C:\TMP> notepad va cherche un chier excutable (dont le nom est notepad.exe ou notepad.com), et dclencher lexcution de ce programme. Ces chiers sont recherchs dans le rpertoire courant et dans un ensemble de rpertoires prciss par la commande DOS path. Certaines commandes admettent des arguments et/ou des options, qui sont des chanes de caractres qui suivent le nom du programme (N.B. : le programme est totalement matre du format et de la signication de ces arguments supplmentaires). C:\TMP> notepad foo.c C:\TMP> gcc -o foo.exe foo.c
1

lauriez-vous trouv seuls ?

B.2. UTILISATION SOUS WINDOWS

101

F IG . B.2 Fentre bash sous DOS Note : DJGPP fournit un autre interprteur, nomm bash, driv du Bourne shell connu sur les stations Unix. Cest un interprte offrant de trs nombreuses fonctionnalits (wildcarding en particulier). Voici quelques commandes : exit interrompre linteraction dir liste des chiers du rpertoire courant . le rpertoire courant .. la racine du rpertoire cd changement de rpertoire c:> cd ..\durand\cours mkdir nom crer un nouveau rpertoire copy nom1 nom2 recopier un chier c:> copy prog2.c a:\durand rem nom supprimer un chier rename nom1 nom2 renommer nom1 c:> rename toto.c.txt toto.c toto excuter le programme toto.exe ou toto.com c:> notepad a : passer sur la disquette c : passer sur le disque c :

102

ANNEXE B. ENVIRONNEMENT DE DVELOPPEMENT

F IG . B.3 Le notepad Windows et sa fentre de slection de chier

B.2.2 Lditeur de texte


Le premier programme que vous aurez utiliser pour construire vos propres programmes est lditeur de texte : cest lui qui va vous permettre dcrire vos programmes source en langage C. Vous pouvez utiliser lun des diteurs fournis avec le systme : le bloc-notes, aussi appel notepad, assez rudimentaire (c.f. gure B.3) ; lditeur wordpad, un peu plus sophistiqu. Vous pouvez aussi utiliser tout autre diteur de texte votre convenance. Rappelez-vous simplement que : vos chiers sources doivent tre des chiers en mode texte seulement ; vos chiers sources en C doivent avoir un nom se terminant par .c : cette terminaison particulire permet au compilateur (voir plus loin) de deviner le type de langage contenu dans le chier.

B.2.3 Le compilateur
Le programme permettant de fabriquer des programmes excutables partir de vos chiers sources est gcc (GNU C compiler). Cest en fait un enchaneur de passes, qui va successivement lancer : le prprocesseur (travaille uniquement au niveau du texte, aucune connaissance de la syntaxe du langage) ; le compilateur (traduit le code source en langage dassemblage) ; lassembleur (traduit le langage dassemblage en code objet) ;

B.2. UTILISATION SOUS WINDOWS

103

lditeur de liens (ajoute au code objet les routines de dmarrage et darrt ainsi que les fonctions pr compiles ncessaires). B.2.3.1 Compilation dun programme indpendant Si votre chier source sappelle prog.c, la fabrication du programme se fait par la commande : gcc prog.c qui construit (si tout se passe bien !) le programme nomm a.exe. Si lon veut donner un autre nom au programme, on peut utiliser une option de gcc : gcc -o prog.exe prog.c loption -o tant suivie de largument prog.exe qui est le nom donner au programme rsultat (encore une fois, le sufxe .exe permet de reprer le type du contenu du chier). Si vous souhaitez avoir des messages davertissement (qui sont des aides vritables la mise au point lorsque lon sait les interprter), vous pouvez utiliser loption -W du compilateur : gcc -o prog.exe -Wall prog.c Pour lancer le programme, il suft alors de taper : prog.exe ou encore plus simple : prog B.2.3.2 Gnration de chiers intermdiaires La fabrication dun programme est une succession de passes. Il est possible de demander lexcution des passes une par une, an de gnrer les chiers intermdiaires. Par exemple, le prprocesseur peut tre appel par : gcc -o prog.i -E prog.c puis le compilateur par gcc -o prog.s -S -Wall prog.i puis lassembleur par gcc -o prog.o -c prog.s et enn lditeur de liens par gcc -o prog.exe prog.o Les chiers prog.i (pr-trait), prog.s (compil) sont des chiers texte que vous pouvez lire avec votre diteur. Les chiers prog.o (objet) et prog.exe (excutable) sont des chiers binaires.

104

ANNEXE B. ENVIRONNEMENT DE DVELOPPEMENT

B.2.4 Mise au point des programmes


Il est vraisemblable que certains de vos programmes comporteront des erreurs (des bogues en franais, traduction des bugs anglais). Un outil trs pratique pour dtecter ces bogues est le metteur au point, ou dbogueur, dont le rle est dexcuter sous contrle le programme fautif et de pouvoir examiner le contenu de la mmoire, la succession des appels de fonctions, etc... Lorsque le compilateur utilis est gcc, loutil de mise au point utiliser est gdb. B.2.4.1 La prparation du dbogage Pour ce faire, le dbogueur a besoin dune version particulire du programme excutable : cette version est obtenue par une option spcique du compilateur. Ainsi, la construction dun programme en vue de son dbogage sobtient par : gcc -o prog -g prog.c Notez : lutilisation de loption -g (si lon compile passe par passe, il faut prciser cette option pour la phase de compilation et la phase ddition de liens). B.2.4.2 Mise au point sous Windows Le dbogueur gdb est fourni avec lenvironnement DJGPP. On notera que, lors de la compilation, le nom pass en argument de loption -o ne doit pas comporter le sufxe .exe. Le compilateur construit deux chiers : lexcutable classique prog.exe un autre chier prog, ce dernier tant requis par le dbogueur. B.2.4.3 Mise au point sous Linux Le dbogueur de choix sous Linux est gdb. B.2.4.4 Description de gdb gdb permet de dboguer du C, du C++ et du Modula2. On peut aussi ltendre dautres langages. Cest un dbogueur en ligne de commande : lors de son excution, il afche un petit message (le prompt, habituellement (gdb) ) et attend les commandes de dbogage. Il excute la commande, afche ventuellement le rsultat, et attend la commande suivante. Pour appeler ce dbogueur sur le programme prog (attention : ne pas oublier la procdure particulire pour gnrer un programme en vue dun dbogage), il suft de lancer la commande : gdb prog

B.2. UTILISATION SOUS WINDOWS


B.2.4.5 Un premier exemple Voici un programme dont lexcution va entraner une division par zro : #include <stdio.h> int main(int argc, char * argv[]) { int tab[10], i ; for (i=0 ; i<10 ; i++) tab[i] = (i+3)/(i-5) ; printf("Fini\n") ; } La compilation et lexcution nous donnent : [CTEST]$ gcc -g bug1.c [CTEST]$ a.out Floating point exception [CTEST]$

105

Le lancement de ce programme sous le metteur au point permet davoir une ide prcise de la nature et de lemplacement de lerreur (les commandes tapes par lutilisateur sont indiques en gras) : [CTEST]$ gdb a.out GNU gdb 5.2.1-2mdk (Mandrake Linux) Copyright 2002 Free Software Foundation, Inc. (gdb) run Starting program : /home/girardot/CTEST/a.out Program received signal SIGFPE, Arithmetic exception. 0x08048372 in main (argc=1, argv=0xbffff6a4) at bug1.c :8 8 tab[i] = (i+3)/(i-5) ; (gdb) quit The program is running. Exit anyway ? (y or n) y [CTEST]$ Notes : La commande gdb a.out est le lancement du dbogueur sous le systme dexploitation utilis (fentre de commande Windows ou Linux). Le dbogueur est ds lors en attente de commande (son prompt est (gdb) ). Ici, lexcution du programme tester est dclenche immdiatement par la commande run . Lerreur (une division par 0) est dtecte la ligne 8 du programme bug1.c, et le texte source de cette ligne est imprime. La commande quit permet, aprs conrmation, darrt lexcution du dbogueur. B.2.4.6 Un deuxime exemple Voici un programme dont le temps dexcution est trs long, et donne limpression quil a entam une boucle sans n :

106

ANNEXE B. ENVIRONNEMENT DE DVELOPPEMENT


#include <stdio.h> void toto(int * d, int s) { * d = s + * d; return ; } int main(int argc, char * argv []) { int i, j, k ; i=j=k=0 ; for (i=0 ; i>=0 ; i++) { for (j=i ; j>=0 ; j++) toto(&k,j) ; } printf("%d %d %d\n", i, j, k) ; }

Lexcution du programme ne donne aucun rsultat visible, et au bout de quelques minutes, grande est la tentation de faire contrle-C pour linterrompre, ce qui, bien entendu, ne donne que peu dindications sur son fonctionnement. Voici le programme excut sous le contrle du dbogueur : [CTEST]$ gdb bug2 GNU gdb 5.2.1-2mdk (Mandrake Linux) Copyright 2002 Free Software Foundation, Inc. (gdb) run Starting program : /home/girardot/CTEST/bug2 Program received signal SIGINT, Interrupt. 0x08048396 in main (argc=1, argv=0xbffff6a4) at bug2.c :17 17 toto(&k,j) ; (gdb) Aprs avoir lanc le dbogueur, puis lexcution du programme tester, nous avons au bout de quelques minutes tap contrle-C pour linterrompre. gdb nous signale que cette interruption a eu lieu la ligne 17 du programme source, avant lappel de la procdure toto. Nous pouvons consulter les valeurs des variables : (gdb) print i $1 = 1 (gdb) print j $2 = 1832284597 (gdb) print k $3 = -1345098718 (gdb) Nous pouvons continuer lexcution du programme interrompu :

B.2. UTILISATION SOUS WINDOWS


(gdb) continue Continuing.

107

Aprs une nouvelle interruption (par contrle-C ), nous pouvons consulter nouveau les variables : (gdb) print i $4 = 6 Lvolution de la valeur de la variable i montre que le programme semble sexcuter normalement. Nous pouvons excuter la procdure courante ligne par ligne : (gdb) next 16 for (j=i ; j>=0 ; j++) (gdb) next 17 toto(&k,j) ; (gdb) next 16 for (j=i ; j>=0 ; j++) (gdb) next 17 toto(&k,j) ; (gdb) print j $7 = 1804878402 (gdb) next 16 for (j=i ; j>=0 ; j++) (gdb) next 17 toto(&k,j) ; (gdb) print j $8 = 1804878403 (gdb) Lexcution en mode ligne par ligne montre lenchanement des appels de la fonction toto au sein de la boucle dans laquelle on fait varier la valeur de j . Il est possible de suivre plus nement lexcution au moyen de la commande step . Celleci va non seulement excuter ligne par ligne, mais va de plus permettre de tracer les procdure appeles : (gdb) step toto (d=0xbffff63c, s=1804878403) at bug2.c :5 5 * d = s + * d; (gdb) step 7 } (gdb) step main (argc=1, argv=0xbffff6a4) at bug2.c :16 16 for (j=i ; j>=0 ; j++) (gdb) step 17 toto(&k,j) ; (gdb) step

108

ANNEXE B. ENVIRONNEMENT DE DVELOPPEMENT


toto (d=0xbffff63c, s=1804878404) at bug2.c :5 5 * d = s + * d; (gdb) step 7 } (gdb) step main (argc=1, argv=0xbffff6a4) at bug2.c :16 16 for (j=i ; j>=0 ; j++) (gdb) step 17 toto(&k,j) ; (gdb) step toto (d=0xbffff63c, s=1804878405) at bug2.c :5 5 * d = s + * d; (gdb) backtrace #0 toto (d=0xbffff63c, s=1804878406) at bug2.c :5 #1 0x0804839f in main (argc=134513486, argv=0x1) at bug2.c :17 #2 0x4003b082 in __libc_start_main () from /lib/i686/libc.so.6 (gdb)

Notons enn lutilisation de la commande backtrace qui permet de connatre le contexte de la ligne en cours : nous sommes ici dans la procdure toto (ligne 5 du texte source bug2.c ), appele depuis la procdure main ( la ligne 17 du texte source bug2.c ), elle-mme appele par la procdure gnrique de lancement dun programme C, qui porte le nom barbare de __libc_start_main . B.2.4.7 Rcapitulatif de gdb Commandes de base (gdb) run Si votre programme ncessite des arguments, on tape la commande : (gdb) run arg1 arg2 ... Il est possible dutiliser pour cette commande run labrviation r . Pour quitter le dbogueur, on tape la commande : (gdb) quit Il est possible dutiliser pour cette commande quit labrviation q . On peut interrompre le programme courant en cours dexcution par un contrle-C . tout moment, un programme interrompu peut tre continu par la commande continue , dont labrviation est c . B.2.4.8 Points darrt Un point darrt permet de stopper lexcution du programme un endroit prcis du code. Pour mettre un point darrt lentre de la fonction fonc, il suft de taper la commande : Pour lancer lexcution du programme, il suft de taper la commande :

B.2. UTILISATION SOUS WINDOWS


(gdb) break fonc

109

Ainsi, break main permet dinterrompre le programme immdiatement avant le dbut de lexcution de la procdure principale. Pour stopper une ligne dtermine du programme source (la ligne 14, par exemple), on utilise la commande (gdb) break 14 Il est possible dutiliser pour la commande break labrviation b . On peut continuer lexcution par la commande continue (abrviation c ), ou bien excuter en mode pas pas par les commandes step ou next (abrviations s et n respectivement). On notera quil existe des instructions stepi et nexti , similaires step et next , mais qui nexcutent quune instruction de la machine la fois. Enn, la commande finish permet de poursuivre lexcution dune procdure jusqu son retour la procdure appelante, et dinterrompre lexcution ce moment. B.2.4.9 Visualisation de donnes Pour visualiser le contenu dune variable, il suft de taper (gdb) print x $1 = 4 (gdb) print tab[2] $2 = 6.13 Largument de la commande print est en fait toute expression C qui a un sens dans le contexte dexcution courant. B.2.4.10 Visualisation de code Lors dune excution de programme, la commande list (abrviation l ) permet dafcher lcran les 10 lignes qui entourent la ligne courante. B.2.4.11 La documentation en ligne Le dbogueur fournit la commande help , qui permet de disposer dindications prcises sur la syntaxe dune commande ou dun groupe de commandes. Sous Linux, la commande man fournit une indication plus ou moins dtaille sur le fonctionnement et les options des outils du systme. Essayez par exemple man gcc ou man gdb . DJGPP, ainsi que Linux, possdent un systme de documentation en ligne : on peut visualiser cette documentation par la commande info. On peut ainsi trouver de la documentation sur : le compilateur : info gcc le dbogueur : info gdb

110

ANNEXE B. ENVIRONNEMENT DE DVELOPPEMENT

F IG . B.4 Fentre Xterm

B.3 Utilisation sous Linux


Il ny a pas doutil particuliers installer sous Linux, qui propose en standard le compilateur gcc, et nombre dinterprtes de commande et dditeurs de textes.

B.3.1 Fentre de commande


Les fentres de commandes se lancent par le choix dun lment dans le menu Terminaux . Les gures B.4 et B.5 page ci-contre fournissent des exemples de lapparence de tels terminaux. Le choix de linterprte est laiss lutilisateur. Nous suggrons bash qui est lun des plus rpandus et offre diverses facilits de rappel et ddition des commandes. Quelques exemples de commandes : exit interrompre linteraction ls liste des chiers du rpertoire courant . le rpertoire courant .. la racine du rpertoire cd changement de rpertoire [tp] cd ../durand/cours mkdir nom crer un nouveau rpertoire cp nom1 nom2 recopier un chier

B.3. UTILISATION SOUS LINUX

111

F IG . B.5 Fentre Eterm [tp] cp prog2.c /home/eleves/durand rm nom supprimer un chier mv nom1 nom2 renommer nom1 [tp] mv toto.c truc.c toto excuter le programme toto [tp] toto [tp] gcc -o titi titi.c cd revenir dans son rpertoire daccueil cd coursc/tp passer dans le rpertoire dsign

B.3.2 diteur de textes


De nombreux diteurs de textes sont disponibles, des plus simples, tels Gedit ou KWrite, aux plus complexes, tels vi ou emacs. Gedit (c.f. B.6 page suivante) est un bon choix initial. Il offre une dition pleine page, lutilisation de la souris, les copier-coller, etc. Il existe un menu spcialis (Applications diteurs de texte) qui permet le lancement de ces outils, dont lexcution peut tre galement demande depuis la ligne de commande. Lditeur KWrite (c.f. B.7 page suivante) propose des fonctions similaires, et assure la coloration syntaxique des programmes, ce qui aide la dtection des apostrophes et parenthses mal fermes. Lditeur Kate est assez similaire.

112

ANNEXE B. ENVIRONNEMENT DE DVELOPPEMENT

F IG . B.6 Lditeur Gedit sous Linux

F IG . B.7 Lditeur KWrite sous Linux

B.3. UTILISATION SOUS LINUX

113

Nous ne conseillons pas, dans un premier temps, lutilisation des outils plus complexes, tels vi ou emacs, qui ont, bien sr, leur raison dtre dans le cadre de dveloppements de grande envergure.

B.3.3 Compilateur
Pour mmoire, rappelons que le compilateur le plus appropri reste gcc. Mentionnons ici quelques-unes des options les plus utiles : -o : cette option doit tre suivie dun identicateur, qui indique sous quel nom le module excutable cr par le compilateur sera conserv. Cest une bonne pratique que dutiliser comme nom le mme que celui du programme source, dpourvu de lextension .c , comme dans : gcc -o prog3 prog3.c -Wall : signaler lors de la compilation toutes les constructions pouvant tre considres comme douteuses , mme si elles sont lgales, car est peuvent correspondre une erreur de programmation. Un exemple typique est : if (a=b) ... qui est lgale, mais peut aussi rsulter dune erreur de lcriture : if (a==b) ... -ansi : demander au compilateur le strict respect de la norme ANSI C. -pedantic : demander au compilateur de signaler toutes les constructions ne respectant pas la norme ISO C. -g : demander la gnration dans le programme dinformation spciques, destines au metteur au point gdb.

114

ANNEXE B. ENVIRONNEMENT DE DVELOPPEMENT

Annexe C Projet 2006


C.1 Prsentation
Cette annexe dcrit le projet propos en 2006 aux lves de premire anne, et servant dvaluation au cours Introduction linformatique . Certaines sances de travaux dirigs et pratiques du cours peuvent aussi aborder, titre dexemple, quelques aspects de ce mini-projet. On notera que le programme dont les spcications sont dcrites par cette annexe est raliser individuellement par chaque tudiant, principalement la dernire journe du cours, et rendre en n de la session, soit : le 15 septembre 2006 18h00 au plus tard, pour le groupe 1 ; le 22 septembre 2006 18h00 au plus tard, pour le groupe 2 ; sous la forme dun ml envoy ladresse girardot@emse.fr. Ce ml devra respecter scrupuleusement les indications suivantes : le sujet du ml comportera la mention P ROJET : suivi de vos prnom(s) et nom ; le programme source, nomm <votre_nom_de_login>.c, sera joint en attachement au ml ; le corps du ml pourra ventuellement contenir vos remarques sur ltat davancement du programme envoy (termin, incomplet, bogues. . .). le programme lui-mme dbutera par un commentaire contenant votre nom, prnom et login.

115

116

ANNEXE C. PROJET 2006

Annexe D Pour information : projet 2005


D.1 Prsentation
Cette annexe dcrit le projet propos en Septembre 2005 aux lves de premire anne. Il est plac dans ce polycopi titre purement indicatif. Un projet diffrent est propos chaque anne en application du cours.

D.2 Manipulation de polynmes


Le but de ce mini-projet est la ralisation dun programme permettant deffectuer quelques manipulations simples sur des polynmes. Le programme doit implmenter : un moyen de dnir (informatiquement) un polynme coefcients rels (ou plus exactement, reprsentables par un type double en C) de degr infrieur une limite xe (on prendra 31 comme valeur de cette limite, mais elle devra tre dnie sous forme dune macro du langage C) ; une procdure dafchage sous forme textuelle dun tel polynme ; pour le polynme 3X 4 + X 2 1.2X + 4, cet afchage peut ressembler : P = + 3 X^4 + 0 X^3 + 1 X^2 - 1.2 X^1 + 4 X^0 ; indication : consulter attentivement le manuel de la procdure printf ! une procdure de calcul de la fonction polynomiale associe un polynme en un point ; une procdure de drivation (formelle) dun polynme ; des procdures daddition et de multiplication de deux polynmes ; une procdure permettant de rechercher une racine dun polynme sur un segment [a, b] ; Le programme principal pourra ainsi raliser successivement : la dnition dun polynme P = X 4 X 2 + X 1 et son afchage ; le calcul de P (2) et lafchage de cette valeur ; le calcul de Q = P et son afchage ; le calcul de R = P + Q et son afchage ; le calcul de T = (X 2 + X 1) R et son afchage ; la recherche dune racine pour le polynme T dans lintervalle [2; 2] ; 117

118

ANNEXE D. POUR INFORMATION : PROJET 2005

Recommandation : calculez formellement les rsultats demands, puis vriez que vos calculs informatiques concordent.

D.3 Sil vous reste du temps


Si les fonctions prcdentes ont t correctement implmentes, vous pouvez vous intresser aux points suivants : reprendre la procdure dafchage textuel an de la rendre un peu plus belle , en vitant dafcher les coefcients nuls, en vitant dafcher les coefcients gaux 1 ou -1, en modiant lafchage des monmes de degrs 1 et 0, comme sur lexemple suivant : P = 3 X^4 + X^2 - 1.2 X + 4 ; tracer une reprsentation graphique dun polynme sur un intervalle donn, par exemple le polynme T sur lintervalle [2; 2]. crire une procdure permettant de dnir le polynme de degr n et de coefcient de plus haut degr gal 1 dont on connat les n racines (relles) ; crire une procdure permettant de dnir le polynme de degr n dont on connat les valeurs en n + 1 points distincts ; on rappelle que le polynme de degr au plus n, tel que P (xi ) = yi pour i [0..n] est :
n

B (x0 , . . . , xn ) =
i=0

yi
j =i

X xj xi xj

Le programme principal pourra utiliser ces procdures sur les exemples suivants : le calcul du polynme U dont les racines sont -1, 0, 2 et 3, et son afchage ; V (1) = 2 V (0) = 1 et son afchage graphique. le calcul du polynme V tel que : V (1) = 2 V (2) = 1

D.3.1 Note : graphiques


An daider la ralisation de la partie dafchage graphique, il est possible dutiliser la bibliothque VOGLE, cette bibliothque utilisant elle-mme le systme graphique standard XW INDOWS. Un exemple dutilisation de cette bibliothque, vex.c, est fourni sur le site du cours : http ://kiwi.emse.fr/INTROINFO. Cet exemple permet de crer une fentre graphique et dy afcher des segments de droite et du texte (en couleur, si besoin). Le but du mini-projet ntant pas la comprhension intgrale de cette bibliothque, ni celle des concepts gnraux de lenvironnement graphique, il nest pas recommand de passer trop de temps sur la qualit de lafchage graphique, et les fonctions montres en exemple sont ainsi sufsantes pour la qualit demande.

D.4. CRITRES DVALUATION

119

D.4 Critres dvaluation


Les critres dvaluation du mini-projet sont notamment : le respect des indications de lnonc ; la compilation sans erreur ni warning du programme (avec options -Wall -ansi -pedantic) ; lexcution sans plantage du programme compil ; le nombre de fonctionnalits implmentes (de faon correcte. . .) ; la qualit de la programmation (dcoupage opportun du code en procdures, lisibilit du code, commentaires. . .)

120

ANNEXE D. POUR INFORMATION : PROJET 2005

Annexe E Pour information : projet 2004


E.1 Prsentation
Cette annexe dcrit le projet propos en Septembre 2004 aux lves de premire anne. Il est plac dans ce polycopi titre purement indicatif. Un projet diffrent est propos chaque anne en application du cours.

E.2 Les rgles du jeu


An dassurer lassimilation des concepts introduits lors des cours et travaux dirigs, il est propos aux lves de rsoudre un petit problme par lcriture dun programme en langage C. Ce programme est raliser individuellement par chaque lve (des programmes par trop ressemblants pourraient provoquer une certaine irritation des correcteurs). Il est rendre en n de semaine bloque, par courrier lectronique, en respectant scrupuleusement les indications suivantes : le courrier doit tre arriv au responsable ladresse girardot@emse.fr le vendredi soir (17 septembre pour le groupe A, 24 septembre pour le groupe B) 18h30 ; le sujet du message doit tre Mini-projet C, groupe A/B ; il doit tre joint au message un attachement (chier joint) qui est le code source du programme ; ce programme devra porter le nom de login de llve (mroelens.c par exemple) ; le corps du message pourra comporter quelques indications ou commentaires sur la ralisation du programme. Chaque programme se verra appliquer le traitement suivant : tentative de compilation avec tous les warnings possibles (option -Wall de gcc) ; un warning non trait provoquera une diminution de lvaluation ; un programme qui ne pourrait tre compil serait fort mal apprci ! tentative dexcution ; un bouclage ou un plantage du programme serait encore fort mal apprci ; la matrialisation dun rsultat (sous une forme opportune) sera apprcie positivement ; la justesse du ou des rsultats sera apprcie encore plus positivement ; 121

122

ANNEXE E. POUR INFORMATION : PROJET 2004

lecture attentive du code source an dvaluer la qualit de rdaction du programme ; un programme ne comportant pas de dcoupage opportun en fonctions serait fort mal ressenti, de mme quun programme sans aucun commentaire !

E.3 Le problme
On veut raliser une implmentation du clbre jeu de la vie 1 . Dans ce jeu, on dispose dun tableau rectangulaire de cellules : chaque cellule, qui a 8 voisines, peut tre vivante ou morte. partir dun motif initial (qui indique les cellules vivantes et mortes initiales), on applique les rgles de transformation suivantes : si linstant t, une cellule morte a exactement trois voisines vivantes, alors linstant t + 1, cette cellule est vivante (rgle de naissance) ; si linstant t, une cellule vivante a deux ou trois voisines vivantes, alors linstant t + 1, cette cellule est vivante (rgle de survie) ; si linstant t, une cellule ne vrie aucune des deux conditions prcdentes, alors linstant t + 1, cette cellule est morte. Le but du projet est, partir dun motif initial, de construire et dafcher le tableau de cellules chaque tape.

E.4 Quelques prcisions


E.4.1 Taille du tableau
Nous nous contenterons dans un premier temps de travailler sur un tableau rectangulaire ni, comprenant NB_LIGNES lignes de NB_COLONNES chacune (ces deux valeurs seront prcises dans le code source par des macros). Pour les relations de voisinage aux bords de ce tableau, on pourra, au choix : soit ajouter une bordure ctive faisant le tour du tableau qui contient des cellules toujours mortes ; soit replier le tableau en considrant premire et dernire ligne comme voisines, ainsi que premire et dernire colonne.

E.4.2 Afchage
Pour raliser lafchage, on pourra, au choix : soit utiliser la bibliothque curses qui permet de grer un terminal de type alphanumrique en mode plein cran ; soit utiliser la bibliothque vogle qui permet de crer simplement une fentre de taille donne, et dafcher pixel par pixel dans cette fentre.
1

Voir par exemple http ://www.math.com/students/wonders/life/life.html

E.5. CORRECTION

123

Vous trouverez sur le site du ple http://kiwi.emse.fr/POLE/ des exemples simples (chiers curs_ex.c et vogle_ex.c) dutilisation de ces bibliothques partir desquels vous pouvez construire votre propre programme.

E.4.3 Saisie du motif initial


La ralisation minimale comprend une procdure spcique dinitialisation du motif (motif cod en dur dans le programme). Une ralisation un peu plus pousse permet de dnir le motif partir dun ou plusieurs arguments de la ligne de commande (selon des modalits que vous devez dnir). Enn, si les tapes prcdentes ont t implmentes avec succs, il est possible de raliser une saisie graphique la souris (sinspirer du programme dexemple vogle_ex2.c).

E.5 Correction
Cette section propose une correction, rdige par Marc Roelens. Cette solution ne doit pas tre considre comme lunique ou la meilleure, mais constitue simplement une description dune dmarche dattaque du problme.

E.6 Donnes du problme


Lide la plus naturelle consiste reprsenter le jeu par une matrice (tableau deux dimensions) : chaque lment de la matrice, repr par son indice de ligne et son indice de colonne, doit reprsenter ltat de la cellule , savoir vivante ou morte. Nous avons besoin de reprsenter galement la taille de la matrice, savoir le nombre de lignes et le nombre de colonnes. En C, comme il est difcile ce niveau dutiliser des tableaux dynamiques (de tailles variables), il est possible dutiliser un tableau de taille maximale xe (taille maximale possible du jeu), dont on nutilise quune partie (coin nord-ouest ). Pour le type des lments du tableau, comme nous navons que deux valeurs reprsenter, le type unsigned char (valeur entire entre 0 et 255) est largement sufsant (et le plus conome en mmoire). Une cellule contenant un 0 est considre comme morte, une cellule contenant une valeur non nulle est considre comme vivante. Voici donc, en fonction des indications prcdentes, une solution possible : /* tailles maximales du jeu */ #define LMAX 1024 #define CMAX 1280 /* les variables du jeu */ unsigned char jeu[LMAX][CMAX]; int nbl,nbc;

124

ANNEXE E. POUR INFORMATION : PROJET 2004

E.7 Traitements
Le principe gnral du programme est trs simple : initialiser le jeu afcher le jeu tant que le jeu nest pas ni faire voluer le jeu afcher le jeu n Nous allons dtailler chacune de ces procdures.

E.7.1 Initialisation du jeu


Dans cette initialisation, il faut tout dabord choisir la taille du jeu (nombre de lignes et de colonnes). On peut, dans un premier temps, coder en dur ces deux valeurs. Dans un second temps, on pourra, par exemple, les passer en arguments du programme. Pour la saisie du motif initial (les cellules vivantes initiales), on peut utiliser plusieurs techniques : codage en dur dans le programme ; codage du motif dans les arguments du programme (difcile) ; gnration dun motif alatoire ; par exemple, pour chaque cellule, on effectue un tirage dune valeur entre 0 et 100 : si cette valeur est infrieure un seuil p (autre paramtre du programme), on dcide que la cellule est vivante, sinon, elle est morte ; (cette mthode gnre un pourcentage moyen p de cellules vivantes) saisie graphique ( la souris) du motif. Dans tous les cas, nous utiliserons le mme prototype pour la procdure dinitialisation : int init_jeu (int argc,char *argv[], int *nbl,int *nbc, unsigned char jeu[LMAX][CMAX]); dans lequel : argc et argv sont les arguments du programme (paramtres de la procdure main) ; nbl et nbc sont les adresses des nombres de lignes et de colonnes (on passe les adresses car ces variables doivent tre modies par la procdure) ; jeu est le tableau du jeu (en fait, ladresse mmoire du tableau). La procdure rend 0 si tout sest bien pass (la procdure dinitialisation a t jusqu son terme), et -1 en cas de problme.

E.7.2 Gestion de lvolution du jeu


Le cur de lalgorithme consiste effectuer une tape de vie : tant connue la conguration linstant t, calculer la conguration linstant t + 1.

E.7. TRAITEMENTS

125

Dans le calcul de la nouvelle conguration, la procdure essentielle est celle qui calcule le nombre de voisins vivants dune cellule donne : il est donc souhaitable den faire une procdure spare. Cette procdure devra dailleurs prendre en compte le cas particulier des bords : soit on considre que le tableau est entour dune bordure de cellules toujours mortes ; soit on considre que le tableau est priodique (ou, ce qui revient au mme, repli sur lui-mme), la premire et la dernire ligne tant voisines, de mme que la premire et la dernire colonne. En fonction de ce nombre, et de la nature de la cellule, on dtermine la nature de la cellule linstant suivant. Il est pratiquement indispensable dans ce cas deffectuer le travail sur deux structures de donnes distinctes ; on peut, au choix : copier la structure de linstant t dans un tableau temporaire, et calculer la structure linstant t + 1 partir du tableau temporaire dans le tableau initial ; calculer la structure linstant t + 1 dans un tableau temporaire, puis recopier ce tableau dans le tableau initial. Les deux solutions sont identiques en termes dencombrement mmoire et de temps de calcul. Dans les deux cas, une procdure de copie de tableau dans un autre tableau est utile ! Nous choisissons pour la suite la premire solution.

E.7.3 Afchage du jeu


Cet afchage est bien sr fortement dpendant de linterface choisie ! Nous pouvons cependant prciser le prototype de la procdure dafchage : void affiche_jeu (unsigned char jeu[LMAX][CMAX], int nbl,int nbc);

E.7.4 Fin du jeu


Le programme gnral doit tester si le jeu est ni. An de ne pas trop compliquer, on peut simplement dcider darrter le jeu sur rception dun vnement utilisateur (touche tape au clavier par exemple). Le codage de cette procdure va bien sr dpendre de linterface choisie, mais dans tous les cas, on peut implmenter une procdure de test de n de jeu selon le prototype suivant : int test_jeu_fini (void); cette procdure rendant une valeur non nulle si lon a dtect lvment utilisateur stoppant le jeu, et 0 sinon.

E.7.5 Codage
Voici une solution possible (ce nest bien sr pas la seule) pour les procdures gnriques (indpendantes de linterface).

126 E.7.5.1 Recopie dun jeu Procdure simple programmer !

ANNEXE E. POUR INFORMATION : PROJET 2004

/* fonction qui copie le tableau "src" dans le tableau "dst" */ /* seul le coin nord-ouest de taille nbl*nbc est copie */ void copie_jeu (unsigned char src[LMAX][CMAX], int nbl,int nbc, unsigned char dst[LMAX][CMAX]) { int i,j; for (i=0;i<nbl;i++) for (j=0;j<nbc;j++) dst[i][j]=src[i][j]; } E.7.5.2 Nombre de voisins vivants An dallger lcriture, cette procdure est implmente par une double boucle permettant de dcrire la cellule et ses 8 voisins. Cas de la bordure morte Voici le code correspondant cette option possible du jeu :

/* fonction qui calcule le nombre de cellules */ /* vivantes voisines de la cellule (i,j) dans */ /* le cas du jeu a "bordure morte " */ int nb_voisins_vivants (unsigned char jeu[LMAX][CMAX], int nbl,int nbc,int i,int j) { int di,dimin,dimax,dj,djmin,djmax,nbvv; dimin=(i==0 ? 0 : i-1); dimax=(i==(nbl-1) ? i : i+1); djmjn=(j==0 ? 0 : j-1); djmax=(j==(nbl-1) ? j : j+1); nbvv=(jeu[i][j] ? -1 : 0); for (di=dimin;di <= dimax;di++) for (dj=djmin;dj <= djmax;dj++) if (jeu[di][dj]) nbvv++; return nbvv; } Noter lutilisation dexpressions conditionnelles, de la forme : exp ? v1 : v2

E.7. TRAITEMENTS

127

interprter comme suit : lexpression exp est value ; si exp est vraie (non nulle), lexpression v1 est value et son rsultat est le rsultat de lexpression globale ; si exp est fausse (nulle), lexpression v2 est value et son rsultat est le rsultat de lexpression globale. Dans ce code, di et dj sont les indices des lignes et colonnes voisines de la cellule (i, j ) ; di (resp. dj) varie entre dimin et dimax (resp. djmin et djmax), ces valeurs tant calcules en fonction de i (dans le cas gnral, ce sont i-1 et i+1, mais on tient compte des bords). La valeur initiale de nbvv est -1 si la cellule (i, j ) est vivante : en effet, dans la double boucle, on va dcompter la cellule comme voisine delle-mme, cette initialisation corrige la valeur.

Cas du jeu priodique

Voici le code correspondant cette autre option possible du jeu :

/* fonction qui calcule le nombre de cellules */ /* vivantes voisines de la cellule (i,j) dans */ /* le cas du jeu "periodique"*/ int nb_voisins_vivants (unsigned char jeu[LMAX][CMAX], int nbl,int nbc,int i,int j) { int di,direel,dj,djreel,nbvv; nbvv=(jeu[i][j] ? -1 : 0); for (di=(i-1);di <= (i+1);di++) { direel=(di+nbl)%nbl; for (dj=(j-1);dj <= (j+1);dj++) { djreel=(dj+nbc)%nbc; if (jeu[direel][djreel]) nbvv++; } } return nbvv; } La variable direel calcule lindice rel prendre en compte pour accder la ligne dindice di (qui peut prendre des valeurs allant de 1 nbl. Noter que lon neffectue pas simplement une opration modulo (on ajoute au pralable nbl), car en C, le rsultat de -1 % N est 1 et non pas N 1 !

128 E.7.5.3 Procdure dvolution

ANNEXE E. POUR INFORMATION : PROJET 2004

On peut alors coder, en fonction des procdures prcdentes, la procdure globale dvolution : void evolue_jeu (unsigned char jeu[LMAX][CMAX], int nbl,int nbc) { unsigned char jeutmp[LMAX][CMAX]; int nbv,i,j; /* on effectue la copie du jeu initial */ copie_jeu(jeu,nbl,nbc,jeutmp); for (i=0;i < nbl;i++) for (j=0;j < nbc;j++) { nbv=nb_voisins_vivants(jeutmp,nbl,nbc,i,j); if (jeutmp[i][j]) jeu[i][j]=((nbv==2) || (nbv==3)); else jeu[i][j]=(nbv==3); } } Note : on notera lutilisation directe du rsultat dun test comme valeur affecte jeu[i][j] ; on rappelle ce propos quen C, le rsultat dun test vrai est la valeur (entire) 1, et que le rsultat dun test faux est la valeur (entire) 0. E.7.5.4 Procdure principale Voici le code de la procdure main : int main (int argc,char *argv[]) { int nbl,nbc; unsigned char jeu[LMAX][CMAX]; if (init_jeu(argc,argv,&nbl,&nbc,jeu)==-1) return 1; affiche_jeu(jeu,nbl,nbc); for (;!test_jeu_fini();) { evolue_jeu(jeu,nbl,nbc); affiche_jeu(jeu,nbl,nbc); }

E.8. INTERFACES UTILISATEUR


return 0; }

129

E.8 Interfaces utilisateur


Trois interfaces utilisateur vont tre prsentes : une interface simple la printf (sur terminal) ; une interface un peu plus volue utilisant la bibliothque curses (sur terminal plein cran) ; une interface graphique utilisant la bibliothque vogle sur pilote X11.

E.8.1 Interface terminal


E.8.1.1 Initialisation Linitialisation consiste simplement rcuprer les arguments de la ligne de commande, les interprter, vrier leur cohrence, et gnrer le tableau initial de jeu par tirage alatoire. Cette gnration fait lobjet dune procdure spare. On rappelle que les arguments sont : le nombre de lignes ; le nombre de colonnes ; ventuellement, le pourcentage de vivants pour le gnrateur alatoire. Voici un codage possible : /* generation dun jeu aleatoire a p % de vivants */ void jeu_aleatoire (unsigned char jeu[LMAX][CMAX], int nbl,int nbc,int p) { int i,j; for (i=0;i < nbl;i++) for (j=0;j < nbc;j++) jeu[i][j]=((rand()%100) < p); } /* initialisation du jeu : on verifie la coherence */ /* des parametres, on genere un jeu aleatoire */ int init_jeu (int argc,char *argv[], int *nbl,int *nbc, unsigned char jeu[LMAX][CMAX]) { int v,p; if ((argc < 3) || (argc > 4))

130

ANNEXE E. POUR INFORMATION : PROJET 2004


return -1; /* le premier argument est le nombre de lignes, il */ /* doit etre positif et inferieur a LMAX */ v=atoi(argv[1]); if ((v < 1)||(v >= LMAX)) return -1; *nbl=v; /* le second argument est le nombre de colonnes, il */ /* doit etre positif et inferieur a CMAX */ v=atoi(argv[2]); if ((v < 1)||(v >= CMAX)) return -1; *nbc=v; /* si le troisieme argument est present, cest le */ /* pourcentage de vivants, qui doit etre entre 0 et */ /* 100 ; sinon, on prend la valeur par defaut 35 */ if (argc==4) { v=atoi(argv[3]); if ((v < 0)||(v > 100)) return -1; p=v; } else p=35; jeu_aleatoire(jeu,*nbl,*nbc,p); return 0;

} E.8.1.2 Afchage La procdure dafchage afche un caractre par cellule (@ si la cellule est vivante, un blanc si la cellule est morte), ligne par ligne. Voici un codage possible : void affiche_jeu (unsigned char jeu[LMAX][CMAX], int nbl,int nbc) { int i,j; for (i=0;i < nbl;i++) { for (j=0;j < nbc;j++) putchar(jeu[i][j] ? @ : ); putchar(\n);

E.8. INTERFACES UTILISATEUR


} } Noter nouveau lutilisation dune expression conditionnelle. E.8.1.3 Test darrt

131

Cette procdure lit une chane de caractres au clavier : si le premier caractre de la chane lue est q, la procdure retourne 1, sinon elle retourne la valeur 0. int test_jeu_fini (void) { char ligne[80]; return fgets(ligne,80,stdin) && ligne[0]==q; } Noter que cette procdure est bloquante : lutilisateur doit appuyer sur Entre pour passer la gnration suivante du jeu.

E.8.2 Interface curses


On sinspire bien sr du petit exemple curs_ex.c. Cette interface reprend beaucoup de linterface terminal (y compris linitialisation alatoire du jeu), avec quelques amliorations : gestion dun mode plein cran (pas de dlement des afchages successifs) ; test darrt non bloquant (au bout dun temps dattente x, on passe la gnration suivante) ; test darrt par simple touche (pas de validation par touche Entre). E.8.2.1 Initialisation On reprend la mme procdure que pour linterface terminal, que lon complte par linitialisation du package curses : /* initialisation du jeu : on verifie la coherence */ /* des parametres, on genere un jeu aleatoire */ int init_jeu (int argc,char *argv[], int *nbl,int *nbc, unsigned char jeu[LMAX][CMAX]) { int v,p; int row,col; ...... code identique au mode terminal ..... /* initialisation du package CURSES */ initscr();

132

ANNEXE E. POUR INFORMATION : PROJET 2004


/* on recupere les valeurs du nombre de lignes et */ /* de colonnes de la fenetre (getmaxyx est une macro) */ getmaxyx(stdscr,row,col); /* on teste si le jeu nest pas plus grand que */ /* lecran */ if ((*nbl > row) || (*nbc > col)) { endwin(); return -1; } /* on passe en mode brut, sans echo, avec un timeout */ /* de 500 millisecondes sur les saisies clavier */ raw(); noecho(); timeout(500); return 0;

} E.8.2.2 Afchage Pour afcher, on commence par effacer lcran, puis on afche un caractre @ pour chaque cellule vivante : void affiche_jeu (unsigned char jeu[LMAX][CMAX], int nbl,int nbc) { int i,j; clear(); for (i=0;i < nbl;i++) for (j=0;j < nbc;j++) if (jeu[i][j]) mvaddch(i,j,*); refresh(); } E.8.2.3 Test darrt On teste simplement si lutilisateur a frapp la touche q au clavier : si oui, on termine proprement (effaage de lcran, restauration de lcran) et on retourne la valeur 1, sinon, on retourne 0. On rappelle que le timeout sur la fonction getch a t positionn dans la procdure dinitialisation 500 millisecondes. int test_jeu_fini (void) {

E.8. INTERFACES UTILISATEUR


if (getch()==q) { clear();refresh(); endwin(); return 1; } return 0; }

133

E.8.3 Interface vogle


Cette interface va permettre notamment de saisir le motif initial la souris, et un vritable afchage graphique. On sinspire du petit exemple vogle_ex2.c, dans lequel : TX correspond au nombre de colonnes ; TY correspond au nombre de lignes ; ZOOM correspond au diamtre des cercles afchs pour reprsenter une cellule vivante (on prendra dans cet exemple un diamtre gal 20). E.8.3.1 Initialisation Pour saisir le motif initial, on dtecte les clics sur la souris, auquel on donne le sens suivant : un clic sur le bouton de gauche ajoute une cellule vivante la position de la souris ; un clic sur le bouton de droite enlve une cellule vivante la position de la souris ; un clic sur le bouton du milieu rinitialise un tableau vide (une procdure spare pour cette fonctionnalit) ; la validation se fait par frappe de la touche q. An de visualiser ce que lon fait, on peut : soit grer un afchage incrmental ; soit rafcher tout le tableau chaque modication. La solution propose choisit la premire option. /* procedure de mise a zero dun tableau de jeu */ void raz_jeu (unsigned char jeu[LMAX][CMAX], int nbl,int nbc) { int i,j; for (i=0;i<nbl;i++) for (j=0;j<nbc;j++) jeu[i][j]=0; } #define ZOOM 20 /* initialisation du jeu : on verifie la coherence */

134

ANNEXE E. POUR INFORMATION : PROJET 2004

/* des parametres, on saisit le tableau initial */ int init_jeu (int argc,char *argv[], int *nbl,int *nbc, unsigned char jeu[LMAX][CMAX]) { int v; int wid,hei; int i,j,nb,wpix,hpix; float x,y,lastx,lasty; ..... code identique a linterface terminal ..... ..... pour recuperer *nbl et *nbc ..... /* initialisation du package VOGLE */ /* taille de la grille (en pixels) */ wpix=(*nbc)*ZOOM; hpix=(*nbl)*ZOOM; /* taille de la fenetre (en pixels) : VOGLE */ /* utilise une "bordure" de 16 pixels */ wid=wpix+16; hei=hpix+16; prefsize(wid,hei); vinit("X11") ; /* pour utiliser tout lecran (VOGLE utilise */ /* un ecran "carre" par defaut) */ ortho2(0.,*nbc,0.,*nbl); expandviewport(); viewport(-1.,1.,-1.,1.); /* on veut des cercles "pleins" */ polyfill(1); /* on met a zero le jeu initial */ raz_jeu(jeu,*nbl,*nbc); /* on efface lecran en blanc */ color(WHITE); clear(); /* on trace en bleu */ color(BLUE); lastx=2.;lasty=2; do { if (checkkey()==q) { return 0; } /* on teste si un bouton de la souris a ete */

E.8. INTERFACES UTILISATEUR


/* "clique", en recuperant la position (x,y) */ /* on teste aussi si le clic na pas eu lieu */ /* a la meme position que le precedent, auquel */ /* cas on ne fait rien (lors dun seul clic, on */ /* recoit en fait de 20 a 50 evenements !) */ nb=slocator(&x,&y); if (!nb || (x==lastx && y==lasty)) { /* si pas de clic, on temporise un peu */ /* (10 ms) et on recommence... */ usleep(10000); continue; } lastx=x;lasty=y; if (nb & 0x02) { /* si on a clique le bouton du milieu, */ /* on efface tout et on recommence... */ raz_jeu(jeu,*nbl,*nbc); color(WHITE); clear(); color(BLUE); continue; } /* on calcule les indices i et j dans le tableau */ /* correspondant a la position de la souris ; */ /* x et y sont dans [-1,1] donc on ajoute 1 et */ /* on divise par 2 pour etre dans [0,1] ; on */ /* multiplie ensuite par *nbl (ou *nbc) et on */ /* prend la partie entiere */ j=(int) (*nbc)*(x+1.)/2.; i=(int) (*nbl)*(y+1.)/2.; /* si on a clique sur le bouton de gauche, on */ /* trace le cercle et on affecte une cellule */ /* vivante ; si cest le bouton de droite, on */ /* efface le cercle (on le trace en blanc) et */ /* on affecte une cellule morte */ if (nb==1) { circle(j+0.5,i+0.5,0.5); jeu[i][j]=1; } else { color(WHITE); circle(j+0.5,i+0.5,0.5);

135

136 color(BLUE); jeu[i][j]=0; } } while (1) ; } E.8.3.2 Afchage

ANNEXE E. POUR INFORMATION : PROJET 2004

Pas de problme particulier : on efface, et on trace un cercle pour chaque cellule vivante. void affiche_jeu (unsigned char jeu[LMAX][CMAX], int nbl,int nbc) { int i,j; backbuffer(); color(WHITE);clear();color(BLUE); for (i=0;i < nbl;i++) for (j=0;j < nbc;j++) if (jeu[i][j]) circle(j+0.5,i+0.5,0.5); swapbuffers(); } Note : on a ajout des appels aux procdures backbuffer et swapbuffers pour viter certains problmes de temporisation dafchage. On gre alors deux fentres : une afche et une cache . Lappel backbuffer indique que lon dessine dans la fentre cache, lappel swapbuffers change les deux fentres. E.8.3.3 Test darrt On teste simplement si lutilisateur a appuy sur la touche q : si oui, on retourne la valeur 1, sinon, on attend un peu, et retourne la valeur 0. int test_jeu_fini (void) { if (checkkey()==q) { vexit(); return 1; } usleep(500000); return 0; }

E.8. INTERFACES UTILISATEUR


Note :

137

lexcution, la prise en compte de la frappe de la touche q peut tre assez longue. . .

138

ANNEXE E. POUR INFORMATION : PROJET 2004

Bibliographie
[1] Jean-Jacques Girardot et Marc Roelens. Structures de donnes et Algorithmes en C. Accessible par la page http://kiwi.emse.fr/POLE/SDA/, septembre 2005.
A TEX 2 , guide pratique. Addison-Wesley, France, Juin 1995. [2] Christian Rolland. L

[3] LyX-Team. Implmentation de LyX. http://www.lyx.org.

139

140

BIBLIOGRAPHIE

Table des gures


1.1 1.2 1.3 1.4 1.5 2.1 3.1 3.2 3.3 3.4 3.5 4.1 4.2 Larchitecture de Von Neumann . . . . . . . . . Premier programme C . . . . . . . . . . . . . . Excution du programme sous un shell Linux . . Excution du programme sous un shell Windows Surface dun disque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 18 20 20 21 32 41 44 46 52 53 65 70 97 98 100 101 102 110 111 112 112

PGCD de deux nombres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PGCD de deux nombres (version 1) . . . . . . . . . . Procdure PGCD (premire version) . . . . . . . . . . Procdure PGCD de deux nombres (deuxime version) Quelques procdures mathmatiques du Langage C . . Quelques utilitaires de C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Quelques oprations sur chanes de caractres . . . . . . . . . . . . . . . . . . Histogramme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

A.1 Pentium Pro : processeur, 2 caches de 512 Ko . . . . . . . . . . . . . . . . . . A.2 Pentium 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.1 B.2 B.3 B.4 B.5 B.6 B.7 Commande DOS . . . . . . . . . . . . . . . . . . . . . . Fentre bash sous DOS . . . . . . . . . . . . . . . . . . Le notepad Windows et sa fentre de slection de chier Fentre Xterm . . . . . . . . . . . . . . . . . . . . . . . Fentre Eterm . . . . . . . . . . . . . . . . . . . . . . . Lditeur Gedit sous Linux . . . . . . . . . . . . . . . . . Lditeur KWrite sous Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

141

142

TABLE DES FIGURES

Index
(void), 36 != (opration), 30 # (caractre), 18 % (caractre), 22 %f (format), 22 && (opration), 32 * (opration), 22 ++ (oprateur), 33 -Wall (option), 113, 121 -ansi (option), 113 -g (option), 104, 113 -lm (option), 51 -o (option), 113 -pedantic (option), 113 -- (oprateur), 33 . (rpertoire), 101, 110 .c (sufxe), 17 .exe (sufxe), 20 .h (sufxe), 19 .o (sufxe), 17, 113 .. (rpertoire), 101, 110 / (opration), 22 / (sparateur, chiers), 13 < (opration), 30 <= (opration), 30 == (opration), 30 > (opration), 30 >= (opration), 30 \ (sparateur, chiers), 13 \n (format), 22 { (caractre), 30 || (opration), 32 } (caractre), 30 abs (procdure), 53 accolades, 30 acos (procdure), 52 143 ADA, 6 adresse mmoire, 12 affectation, 21 Algol 60, 6 algorithme, 17 algorithme dEuclide, 29 alphanumrique, 16 APL, 6 apostrophe, 13 arborescence, 13 argc, 20 argv, 20 ASCII, 16 asin (procdure), 52 atan (procdure), 52 atan2 (procdure), 52 atof (procdure), 53 atoi (procdure), 53 atol (procdure), 53 backslash, 13 backtrace (gdb), 108 bash, 14, 101 bloc, 30 boolen, 30 branchement, 15 break (gdb), 109 bus, 11, 96 byte, 12, 95 C, 6 C++, 6 cd (commande), 101, 110 ceil (procdure), 52 Celsius, 27 chane de caractres, 17, 19 char, 12

144 char (dclaration), 23 cheminom, 13 code ASCII, 16 code de retour, 19, 20 commandes cd, 101, 110 copy, 101 cp, 110 dir, 101 exit, 101, 110 gcc, 109 gdb, 109 ls, 110 man, 109 mkdir, 101, 110 mv, 111 rem, 101 rename, 101 rm, 111 compilateur, 14 compilation, 14, 18 phases, 18 compteur programme, 15 continue (gdb), 107 copy (commande), 101 cos (procdure), 52 cosh (procdure), 52 cp (commande), 110 dclaration, 21 dclarations char, 23 double, 16, 23, 39 extern, 49 oat, 16, 23, 39 int, 16, 23 long, 23 long double, 23, 39 long long, 23 short, 23 unsigned, 23 void, 48 dcrmentation (oprateur), 33 dise, 18 diffrent (oprateur), 30 dir (commande), 101 DJGPP, 99, 104 do (instruction), 31 Dos, 13 double (dclaration), 16, 23, 39

INDEX

e (valeur M_E), 39 editeur de texte, 17 edition des liens, 17 egal (oprateur), 30 emacs, 17 entier, 95 entiers, 16 Euclide (algorithme), 29 exemples Calcul dun sinus, 35 Dates, 73 Hello World, 18 MasterMind, 82 PGCD, 31, 46 Reines, 79 Somme des N premiers entiers, 32 Surface dun disque, 21 exit (commande), 101, 110 exit (procdure), 19, 53 exp (procdure), 52 extension, 13 extern (dclaration), 49 fabs (procdure), 36, 52 Fahrenheit, 27 faux (boolen), 30 chier, 13 extension, 13 nom sparateur, 13 nish (gdb), 109 oat (dclaration), 16, 23, 39 oor (procdure), 52 fmod (procdure), 37, 52 for (instruction), 31 Fortran, 6 gcc, 109, 113

INDEX
gdb, 104, 113 backtrace, 108 break, 109 continue, 107 nish, 109 help, 109 list, 109 next, 107, 109 nexti, 109 print, 106, 109 quit, 105, 108 run, 105, 108 step, 107, 109 stepi, 109 Gedit, 17 Girardot (Jean-Jacques), 9 Gnome, 14 GNU, 99 header, 19 help (gdb), 109 identicateur, 15 if (instruction), 30 include (prprocesseur), 18 inclusion, 19 inclusions math.h, 36 stdio.h, 18 stdlib.h, 53 string.h, 64 index, 12 infrieur (oprateur), 30 infrieur ou gal (oprateur), 30 info (Linux), 109 instruction compose, 30 instructions affectation, 21, 26 impression, 26 return, 19 int (dclaration), 16, 23 KWrite, 17 labs (procdure), 53 langage machine, 14 LF, 22 line-feed, 22 Linux, 6, 13, 14, 17, 20, 99, 104, 110 list (gdb), 109 log (procdure), 52 log10 (procdure), 52 long (dclaration), 23 long double (dclaration), 23, 39 long long (dclaration), 23 ls (commande), 110 mmoire, 11, 95 mmoire secondaire, 95 Mac OS, 13 Machine de von Neumann, 11 main (procdure), 48 man (Linux), 109 MasterMind (exemple), 82 math.h (inclusion), 36 Matlab, 6 MIPS, 95 mkdir (commande), 101, 110 mv (commande), 111 M_E (valeur e), 39 M_PI (valeur pi), 36 next (gdb), 107, 109 nexti (gdb), 109 norme C, 113 NotePad, 17 octet, 12, 95 oprateurs ++, 33 --, 33 de comparaison, 30 logiques, 32 sizeof, 23, 62 options -Wall, 113, 121 -ansi, 113 -g, 104, 113 -lm, 51 -o, 113

145

146 -pedantic, 113 priphriques, 11 paramtre, 48 Pascal, 6 passage la ligne, 20, 22 PATH, 20 Pentium 4, 96 Pentium Pro, 96 PGCD, 29 pi (valeur M_PI), 36 pow (procdure), 52 prprocesseur, 18 include, 18 print (gdb), 106, 109 printf (procdure), 22, 24 procdure, 19, 42 procdures abs, 53 acos, 52 asin, 52 atan, 52 atan2, 52 atof, 53 atoi, 53 atol, 53 ceil, 52 cos, 52 cosh, 52 exit, 19, 53 exp, 52 fabs, 36, 52 oor, 52 fmod, 37, 52 labs, 53 log, 52 log10, 52 main, 19, 48 mathmatiques, 51 pow, 52 printf, 22, 24 puts, 19 rand, 53 sin, 52

INDEX
sinh, 52 sqrt, 52 srand, 53 strcat, 65 strcmp, 65 strcpy, 65 strlen, 65 strncat, 65 strncmp, 65 strncpy, 65 tan, 52 tanh, 52 processeur, 11, 95 processus, 11 programmation, 17 programme, 11 programme excutable, 17 programme objet, 17 programme principal, 20 programme source, 17 programmes Calcul dun sinus, 35 Dates, 73 Hello World, 18 MasterMind, 82 PGCD, 31, 46 Reines, 79 Somme des N premiers entiers, 32 Surface dun disque, 21 prototype, 48 puts (procdure), 19, 20 quit (gdb), 105, 108 quote, 13 rpertoire, 13 rpertoire courant, 20 racine, 13 rand (procdure), 53 registre, 12, 95 rem (commande), 101 rename (commande), 101 ressources, 14 return (instruction), 19

INDEX
rm (commande), 111 Roelens (Marc), 9, 123 run (gdb), 105, 108 saut, 15 Scheme, 6 Scilab, 6 shell, 14 short (dclaration), 23 signed char, 12 sin (procdure), 52 sinh (procdure), 52 sinus, 35 sizeof (oprateur), 23, 62 slash, 13 sqrt (procdure), 52 srand (procdure), 53 stdio.h (inclusion), 18 stdlib.h (inclusion), 53 step (gdb), 107, 109 stepi (gdb), 109 strcat (procdure), 65 strcmp (procdure), 65 strcpy (procdure), 65 string.h (inclusion), 64 strlen (procdure), 65 strncat (procdure), 65 strncmp (procdure), 65 strncpy (procdure), 65 sufxe, 13 sufxes .c, 17 .exe, 20 .h, 19 .o, 17, 113 suprieur (oprateur), 30 suprieur ou gal (oprateur), 30 tan (procdure), 52 tanh (procdure), 52 traducteur, 14 unit arithmtique et logique, 95 unit centrale, 11, 95 UNIX, 6, 13 unsigned (dclaration), 23 unsigned char, 12 valeur, 16 valeurs entires, 16 valeurs relles, 16 variables, 16 vi, 17 void, 36 void (dclaration), 48 von Neumann, 11 vrai (boolen), 30 while (instruction), 31 Windows, 13, 14, 20, 99

147

148

INDEX

Table des matires


I Cours
Introduction 0.1 Prambule . . . . . . . . . . . . . . . . . . . . . . . . . 0.1.1 Le support de cours . . . . . . . . . . . . . . . . 0.1.2 Le choix du langage . . . . . . . . . . . . . . . 0.2 La nalit de ce cours . . . . . . . . . . . . . . . . . . . 0.3 Droulement du cours . . . . . . . . . . . . . . . . . . . 0.3.1 Sance 1 : introduction au matriel et au logiciel 0.3.2 Sance 2 : quelques problmes lmentaires . . . 0.3.3 Sance 3 : procdures . . . . . . . . . . . . . . . 0.3.4 Sance 4 : tableaux . . . . . . . . . . . . . . . . 0.3.5 Sance 5 : du problme au programme . . . . . . 0.3.6 Sance 6 : une application . . . . . . . . . . . . 0.4 Informations en ligne . . . . . . . . . . . . . . . . . . . 0.5 Notes techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3
5 5 5 6 6 7 7 7 8 8 8 8 8 9 11 11 11 11 12 12 12 12 13 14 14 14 15 15 16 17 17 17

1 Introduction 1.1 Cours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.1 Modle de lordinateur . . . . . . . . . . . . . . . . . . . . 1.1.1.1 Architecture dun ordinateur . . . . . . . . . . . 1.1.1.2 La mmoire . . . . . . . . . . . . . . . . . . . . 1.1.1.3 Le processeur . . . . . . . . . . . . . . . . . . . 1.1.1.4 Communication entre processeur et mmoire . . . 1.1.1.5 Les disques durs . . . . . . . . . . . . . . . . . . 1.1.1.6 Les systmes de chiers . . . . . . . . . . . . . . 1.1.1.7 La programmation des ordinateurs . . . . . . . . 1.1.1.8 Le systme dexploitation . . . . . . . . . . . . . 1.1.1.9 Lenvironnement de travail . . . . . . . . . . . . 1.1.1.10 Fonctionnement gnral et processus dexcution 1.1.1.11 Notion de variable . . . . . . . . . . . . . . . . . 1.1.2 Reprsentation des informations . . . . . . . . . . . . . . . 1.1.3 Mise en uvre dun programme . . . . . . . . . . . . . . . 1.1.3.1 Quest-ce quun langage de programmation ? . . . 1.1.3.2 Les tapes de la vie dun programme . . . . . . . 149

150 Un premier programme C . . Un second exemple . . . . . . Types et variables en C . . . . 1.1.6.1 Types scalaires . . . 1.1.6.2 Constantes . . . . . 1.1.6.3 Arithmtique mixte 1.1.6.4 Variables et adresses retenir . . . . . . . . . . . . . . . . Travaux pratiques . . . . . . . . . . . 1.3.1 Exercice 1 . . . . . . . . . . . 1.3.2 Exercice 2 . . . . . . . . . . . 1.3.3 Exercice 3 . . . . . . . . . . . 1.1.4 1.1.5 1.1.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

TABLE DES MATIRES


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 21 22 22 23 24 24 26 26 27 27 27 29 29 29 29 30 31 31 32 34 34 34 37 38 38 38 38 38 38 39 41 41 41 42 43 44 47 47 48 48 49

1.2 1.3

2 Quelques problmes lmentaires 2.1 Cours . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.1 Un premier problme : lalgorithme dEuclide . 2.1.1.1 Lalgorithme . . . . . . . . . . . . . 2.1.1.2 Passage au programme . . . . . . . 2.1.1.3 Le programme nal . . . . . . . . . 2.1.1.4 Un cas non prvu ! . . . . . . . . . . 2.1.2 Somme des premiers entiers . . . . . . . . . . 2.1.3 Le calcul dun sinus . . . . . . . . . . . . . . 2.1.3.1 Lalgorithme . . . . . . . . . . . . . 2.1.3.2 Dtail de lalgorithme . . . . . . . . 2.1.3.3 Petit problme ! . . . . . . . . . . . 2.2 retenir . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Travaux pratiques . . . . . . . . . . . . . . . . . . . . 2.3.1 Exercice 1 . . . . . . . . . . . . . . . . . . . . 2.3.2 Exercice 2 . . . . . . . . . . . . . . . . . . . . 2.3.3 Exercice 3 . . . . . . . . . . . . . . . . . . . . 2.3.4 Exercice 4 . . . . . . . . . . . . . . . . . . . . 2.3.5 Exercice 5 . . . . . . . . . . . . . . . . . . . . 3 Procdures 3.1 Cours 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 . . . . . . . . . . . . . . . . . . . . . . . . . . Retour au PGCD . . . . . . . . . . . . . . . . La notion de procdure . . . . . . . . . . . . . La procdure PGCD, premire version . . . . La procdure PGCD, deuxime version . . . . Quelques aspects des procdures du langage C 3.1.5.1 Variables locales et globales . . . . . 3.1.5.2 Paramtres dune procdure . . . . . 3.1.5.3 Notion de prototype . . . . . . . . . 3.1.5.4 Compilation spare . . . . . . . . .

TABLE DES MATIRES


3.1.5.5 Fichiers dinclusion . . . . 3.1.6 Quelques procdures de C . . . . . . 3.1.6.1 Oprations mathmatiques 3.1.6.2 Oprations utilitaires . . . retenir . . . . . . . . . . . . . . . . . . . . Travaux pratiques . . . . . . . . . . . . . . . 3.3.1 Exercice 1 . . . . . . . . . . . . . . . 3.3.2 Exercice 2 . . . . . . . . . . . . . . . 3.3.3 Exercice 3 . . . . . . . . . . . . . . . 3.3.4 Exercice 4 . . . . . . . . . . . . . . . 3.3.5 Exercice 5 . . . . . . . . . . . . . . . 3.3.6 Exercice 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

151 50 51 51 53 54 54 55 55 55 55 55 55 57 57 57 58 58 59 59 60 61 61 62 63 63 64 65 67 68 68 68 68 69 69 69 69 70 70 70 71

3.2 3.3

4 Tableaux 4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Un premier exemple . . . . . . . . . . . . . . . . . . . . . . 4.1.2 Les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.2.1 Caractristique de base . . . . . . . . . . . . . . . 4.1.2.2 Dclaration de tableau . . . . . . . . . . . . . . . . 4.1.2.3 Accs aux lments des tableaux . . . . . . . . . . 4.1.2.4 Tableaux et adresses . . . . . . . . . . . . . . . . . 4.1.2.5 Tableaux de caractres . . . . . . . . . . . . . . . . 4.1.2.6 Tableaux et procdures . . . . . . . . . . . . . . . 4.1.2.7 Exemples . . . . . . . . . . . . . . . . . . . . . . 4.1.3 Chanes de caractres . . . . . . . . . . . . . . . . . . . . . . 4.1.3.1 Introduction . . . . . . . . . . . . . . . . . . . . . 4.1.3.2 Oprations sur chanes de caractres . . . . . . . . 4.1.3.3 Exemples de manipulation de chanes de caractres 4.1.4 Retour sur la procdure main . . . . . . . . . . . . . . . . . 4.1.4.1 Utilisation des arguments de la fonction main . . . 4.2 retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Travaux pratiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Exercice 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.2 Exercice 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.3 Exercice 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.4 Exercice 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.5 Exercice 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.6 Exercice 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.7 Exercice 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.8 Exercice 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.9 Exercice 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . .

152 5 Du problme au programme 5.1 Cours . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.1 Calcul dintervalle de temps . . . . . . . . . . . . 5.1.1.1 Une premire dcomposition . . . . . . 5.1.1.2 Analyse de la fonction N . . . . . . . . 5.1.1.3 Calcul de N4 (h, m, s) . . . . . . . . . . 5.1.1.4 Calcul de Nj3 (j ) . . . . . . . . . . . . 5.1.1.5 Calcul de Nj1 . . . . . . . . . . . . . . 5.1.1.6 Calcul de Nj2 . . . . . . . . . . . . . . 5.1.1.7 Correction dune inexactitude . . . . . . 5.1.1.8 Le bug du 19 janvier 2038 . . . . . . . . 5.1.2 Le problme des reines sur un chiquier . . . . . . 5.1.2.1 Un peu danalyse . . . . . . . . . . . . 5.1.2.2 Gnration des positions . . . . . . . . . 5.1.2.3 Test dune position . . . . . . . . . . . 5.1.2.4 Dessin de lchiquier . . . . . . . . . . 5.1.2.5 Quelques rsultats . . . . . . . . . . . . 5.1.3 Toujours plus complexe . . . . . . . . . . . . . . 5.1.3.1 Description prcise du jeu . . . . . . . . 5.1.3.2 Analyse, modlisation des donnes . . . 5.1.3.3 Les traitements . . . . . . . . . . . . . . 5.1.3.4 Tirage au sort de la combinaison . . . . 5.1.3.5 Lecture de la proposition de lutilisateur 5.1.3.6 Manipulation des couleurs . . . . . . . . 5.1.3.7 Calcul du score dune proposition . . . . 5.1.3.8 Gestion de laide . . . . . . . . . . . . . 5.1.3.9 Le jeu complet . . . . . . . . . . . . . . 5.2 retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Travaux pratiques . . . . . . . . . . . . . . . . . . . . . . 5.3.1 Exercice 1 . . . . . . . . . . . . . . . . . . . . . .

TABLE DES MATIRES


73 73 73 73 74 75 75 75 76 78 78 79 79 79 81 81 81 82 82 83 84 84 85 86 87 88 89 91 91 91

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

II Annexes
A Quelques aspects du matriel A.1 Processeur, ou unit centrale A.2 Mmoire . . . . . . . . . . . A.3 Bus . . . . . . . . . . . . . A.4 Exemple de Processeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

93
95 95 95 96 96

B Environnement de dveloppement 99 B.1 Lenvironnement de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 B.2 Utilisation sous Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 B.2.1 Linterprteur de commandes . . . . . . . . . . . . . . . . . . . . . . . 100

TABLE DES MATIRES


Lditeur de texte . . . . . . . . . . . . . . . . . . . Le compilateur . . . . . . . . . . . . . . . . . . . . B.2.3.1 Compilation dun programme indpendant B.2.3.2 Gnration de chiers intermdiaires . . . B.2.4 Mise au point des programmes . . . . . . . . . . . . B.2.4.1 La prparation du dbogage . . . . . . . . B.2.4.2 Mise au point sous Windows . . . . . . . B.2.4.3 Mise au point sous Linux . . . . . . . . . B.2.4.4 Description de gdb . . . . . . . . . . . . B.2.4.5 Un premier exemple . . . . . . . . . . . . B.2.4.6 Un deuxime exemple . . . . . . . . . . . B.2.4.7 Rcapitulatif de gdb . . . . . . . . . . . . B.2.4.8 Points darrt . . . . . . . . . . . . . . . B.2.4.9 Visualisation de donnes . . . . . . . . . B.2.4.10 Visualisation de code . . . . . . . . . . . B.2.4.11 La documentation en ligne . . . . . . . . B.3 Utilisation sous Linux . . . . . . . . . . . . . . . . . . . . . B.3.1 Fentre de commande . . . . . . . . . . . . . . . . B.3.2 diteur de textes . . . . . . . . . . . . . . . . . . . B.3.3 Compilateur . . . . . . . . . . . . . . . . . . . . . B.2.2 B.2.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

153 102 102 103 103 104 104 104 104 104 105 105 108 108 109 109 109 110 110 111 113

C Projet 2006 115 C.1 Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 D Pour information : projet 2005 D.1 Prsentation . . . . . . . . . D.2 Manipulation de polynmes D.3 Sil vous reste du temps . . . D.3.1 Note : graphiques . . D.4 Critres dvaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 117 117 118 118 119 121 121 121 122 122 122 122 123 123 123 124 124 124

E Pour information : projet 2004 E.1 Prsentation . . . . . . . . . . . . . E.2 Les rgles du jeu . . . . . . . . . . E.3 Le problme . . . . . . . . . . . . . E.4 Quelques prcisions . . . . . . . . . E.4.1 Taille du tableau . . . . . . E.4.2 Afchage . . . . . . . . . . E.4.3 Saisie du motif initial . . . . E.5 Correction . . . . . . . . . . . . . . E.6 Donnes du problme . . . . . . . . E.7 Traitements . . . . . . . . . . . . . E.7.1 Initialisation du jeu . . . . . E.7.2 Gestion de lvolution du jeu

154 Afchage du jeu . . . . . . . . . . . Fin du jeu . . . . . . . . . . . . . . . Codage . . . . . . . . . . . . . . . . E.7.5.1 Recopie dun jeu . . . . . . E.7.5.2 Nombre de voisins vivants . E.7.5.3 Procdure dvolution . . . E.7.5.4 Procdure principale . . . . E.8 Interfaces utilisateur . . . . . . . . . . . . . . E.8.1 Interface terminal . . . . . . . . . . . E.8.1.1 Initialisation . . . . . . . . E.8.1.2 Afchage . . . . . . . . . E.8.1.3 Test darrt . . . . . . . . . E.8.2 Interface curses . . . . . . . . . . . . E.8.2.1 Initialisation . . . . . . . . E.8.2.2 Afchage . . . . . . . . . E.8.2.3 Test darrt . . . . . . . . . E.8.3 Interface vogle . . . . . . . . . . . . E.8.3.1 Initialisation . . . . . . . . E.8.3.2 Afchage . . . . . . . . . E.8.3.3 Test darrt . . . . . . . . . Bibliographie Figures Index Table des matires E.7.3 E.7.4 E.7.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

TABLE DES MATIRES


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 125 125 126 126 128 128 129 129 129 130 131 131 131 132 132 133 133 136 136 139 141 143 149