Vous êtes sur la page 1sur 142

Langages et Concepts de Programmation Introduction la programmation en langage C

Cours 1A 2013-2014

Jean-Jacques Girardot, Marc Roelens


girardot@emse.fr, roelens@emse.fr Septembre 2013
cole Nationale Suprieure des Mines de Saint-Etienne 158 Cours Fauriel 42023 SAINT-TIENNE CEDEX

2 Version du 7 septembre 2013.

Premire partie Cours

Introduction
0.1 Objectifs du cours

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 introduction linformatique (en tant que science). 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.2
0.2.1

Organisation du cours
Cours et travaux pratiques

Le cours de Langages et concepts de programmation est organis en deux phases : la premire phase, relativement intensive (4 journes rparties sur 15 jours, soit 24 heures au total), aborde les premiers concepts de la programmation, dans le but damener chaque lve un niveau de comptences permettant la rsolution dun problme simple (programme de quelques centaines de lignes nutilisant que les procdures et les tableaux, avec des algorithmes simples). Cette phase est organise de faon ce que chaque lve dispose dun poste de travail (actuellement, par demi-promotion), et lvaluation se fait donc de faon individuelle. la seconde phase, plus tale (21 heures sur 4 semaines), permet de complter cette introduction en introduisant notamment les notions dentres-sorties et de structures de donnes. Lobjectif est darriver un niveau de comptences permettant dcrire un programme de traitement de donnes de type rel : programme de quelques milliers de lignes utilisant entres-sorties, structures de donnes, procdures. Cette phase est organise en promotion complte, et les lves travaillent par binmes. Lors de ces deux phases, chaque sance comprend une partie de prsentation thorique en salle de cours, puis une partie de ralisation pratique en salle machine. 5

0.2.2

Projet

Au dbut de la seconde phase, les lves choisissent par binmes un sujet de projet (parmi une liste dune quarantaine de sujets) : ce projet est raliser en deux mois environ. Les notions ncessaires la ralisation du projet sont abordes durant la seconde phase.

0.2.3

Travail pratique de recherche oprationnelle

Le cours comprend galement, en commun avec le cours de Recherche oprationnelle (qui fait partie du ple de modlisation mathmatique), la ralisation dun programme permettant de rsoudre un problme typique doptimisation. Ce travail se ralise sous forme de deux sances de travaux pratiques (en principe, le sujet trait est abord de faon thorique lors des sances de travaux dirigs de recherche oprationnelle).

0.2.4

Evaluation

Lvaluation du cours se fait essentiellement par lvaluation du projet de programmation : cette valuation comprend une note de prsentation orale (dure : 20 minutes), une note de rapport crit, et une note lie la qualit de la ralisation informatique (qui intgre une partie de motivation). De faon complmentaire, certains travaux pratiques du cours ainsi que le travail pratique de recherche oprationnelle sont valus, et pourront intervenir dans la note nale.

0.3

Le langage C

Ce cours est une premire introduction aux mthodes de 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. 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

0.4. LA FINALIT DE CE COURS

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 gloutons 1 , 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 introduction 2 , 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.4

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. 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.
1. Terme de remplissage, utilis ici en attendant la prochaine rvolution. . . 2. Ne serait-ce que par sa syntaxe. . .

8 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 crits 3 , 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.5

Droulement du cours

La premire phase du cours comporte huit sances de trois heures. Les sept premires sances comportent une phase magistrale suivie dune phase de travaux dirigs et pratiques, la dernire sance est intgralement consacre au travail pratique (ralisation du projet).

0.5.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.5.2

Sances 2 et 3 : quelques problmes lmentaires

But Comprendre les notions de variable, dexpression, et les itrations (boucles et tests) Thorie Modlisation de problmes. Pratique Partir dun problme simple, (calculer un PGCD, un sinus), en dcrire les tapes de la rsolution.

0.5.3

Sance 4 : procdures

But Comprendre la notion de procdure. Thorie Description et appel de procdure. Passage de paramtres. Prototypes des procdures.
3. ou ne les a pas relus depuis un moment. . .

0.6. LES SUPPORTS DE COURS

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.5.4

Sance 5 : tableaux

But Les tableaux. Thorie Oprations simples sur tableaux. Tableaux deux dimensions, ou matrices. Tableaux et procdures. Quelques algorithmes sur les tableaux. Pratique Recherches de minimums, maximums, etc. Remplissage de tableau par des valeurs alatoires. Exemple du calcul des moyennes.

0.5.5

Sance 6 : 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.5.6

Sance 7 : complments

But Apporter quelques complments sur procdures et tableaux.

0.5.7

Sance 8 : 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.6

Les supports de cours

Les supports de cours se composent notamment du prsent document, des documents projets pendant les sances de cours, et des notes personnelles des lves. De nombreuses informations (complments de cours, exercices corrigs, rfrences bibliographiques ou Internet, copies des supports de cours) sont disponibles sur le site Internet du cours informatique : http://kiwi.emse.fr/INTROINFO/

10

0.7

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 Linux et MacOS X, en utilisant le logiciel de comA position L TEX. Une partie du document a t ralise au moyen de LYX ([3]), un diteur de A document qui fournit un interface WYSIWYM avec TEX et L TEX ([2]).

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
1.1.1.1

Modle de lordinateur
Architecture dun ordinateur

F IGURE 1.1 Larchitecture de Von Neumann Les ordinateurs actuels drivent dune architecture dnie en 1946, la Machine de von Neumann (cf. gure 1.1). Les quatre composantes principales de cette architecture sont : lunit arithmtique et logique ; cest elle qui effectue les calculs (additions, multiplications) et les tests (galit, infriorit) ; 11

12

CHAPITRE 1. INTRODUCTION

lunit de contrle et de traitement ; cest elle qui dtermine lordre et la nature des oprations excuter ; la mmoire ; comme son nom lindique, son rle est simplement de mmoriser les informations traites par les deux units prcdentes ; les dispositifs dentre et de sortie permettent dchanger des informations avec lextrieur (lutilisateur, par exemple). On nomme unit centrale (en anglais, CPU pour Central Processing Unit) lensemble de lunit arithmtique et logique et de lunit de contrle. Lunit centrale est relie la mmoire par un bus permettant la communication. 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. 1.1.1.2 La mmoire

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 leur index, entier 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 signed char) ; 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

1.1. COURS

13

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 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, MacOS. . .) est une organisation de lespace de stockage, 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 (on parle parfois de cheminom 1 ) 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, Linux ou MacOS, cest le caractre "/" (slash) qui sert de sparateur. On crira : /users/dupont/exemples/prog17.c 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
1. libre traduction de langlais pathname, on trouve galement lcriture cheminon

14

CHAPITRE 1. INTRODUCTION

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), une cl USB. . .. Fichiers et rpertoires sont dsigns par des noms, qui sont habituellement des suites de lettres et de chiffres. Certains systmes sont trs restrictifs, tels MS-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 (il ny a pas de distinction entre majuscules et minuscules et certains caractres sont interdits). Dautres systmes (MacOS, Windows) acceptent, avec quelques restrictions, des suites de caractres arbitraires (y compris les espaces, les caractres de ponctuation, les caractres accentus). 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 hors du code ASCII. 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 le logiciel de traitement de texte Word , etc. Sous Windows, mais cette convention ne sapplique pas sous Unix ou Linux, les ".exe" reprsentent des programmes excutables. Dans certains cas, le systme dexploitation (ou plus exactement, linterface utilisateur) utilise cette extension pour savoir quel programme associer tel chier. On voit, par ces derniers exemples, que les chiers rpondent de multiples nalits. De manire trs gnrale, on peut dire quils constituent un support non volatile 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

Lexcution des programmes sur un ordinateur ncessite quils soient crits (dans le chier excutable) en langage machine, qui est propre chaque modle dordinateur. Ce langage est fastidieux crire pour un humain : aussi, on utilise dans la pratique des langages de haut niveau, tels le C, le Fortran, le Java, etc., qui sont universels . Un programme spcialis, dit traducteur ou compilateur, permet de transformer 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 pri2. 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.

1.1. COURS

15

phriques) 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. Les environnements de travail offrent un systme de multi-fentrage (Windows, Gnome sous Linux, etc.) faisant grande consommation des interactions souris, mais aussi un mcanisme bas sur des lignes de commandes telles que : gcc -Wall -ansi -pedantic -o prog prog.c Ces lignes de commandes sont saisies dans un terminal en les tapant sur le clavier. Un programme, linterprteur de commandes 3 , soccupe de rcuprer cette saisie puis lance le programme demand (le premier mot de la ligne). Nous disposons sous Windows dun interprteur lmentaire (de nom invite de commande ou parfois bote MS-DOS ), et galement dun interprteur plus volu, appel bash (bash fournit des aides fort utiles pour taper aisment des commandes : compltion des noms de chiers, historique de commandes avec possibilit de rappel. . .). On utilise souvent le terme gnrique de shell pour dsigner ces interfaces. Pour indiquer que linterprteur est en attente dune commande, il afche dans le terminal un message de quelques caractres que lon appelle invite ou prompt : dans le cas de bash, ce message est programmable (on peut y mettre notamment le nom de la machine, le nom de lutilisateur connect, le rpertoire courant, lheure. . .) et se termine habituellement par le caractre $ (ou le caractre # si lon est administrateur de la machine) : dans le reste du document, chaque fois quil sera fait rfrence une commande taper dans un terminal pour un interprteur, nous utiliserons cette reprsentation. Ainsi, lorsquil sera crit : $ gcc -Wall -ansi -pedantic -o prog prog.c on comprendra quil est demand de taper la commande correspondante (sans taper le caractre $ qui est afch par linterprteur) dans le terminal. De la mme faon, les messages afchs par les programmes excuts seront toujours souligns. 1.1.1.10 Fonctionnement gnral et processus dexcution au niveau du processeur

Parmi les registres du processeur, il en existe un, dit compteur programme (ou encore compteur ordinal), 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 :
3. Bien que le mot nexiste pas en franais, le vocable dinterprteur sest impos par rapport celui dinterprte

16

CHAPITRE 1. INTRODUCTION 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 sont trs fastidieuses lorsquon crit en langage machine. 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 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. Ainsi, lorsque lon crit en langage C une instruction du style x=2; ; on doit bien distinguer cette criture de sa correspondance mathmatique : on nest pas en train dcrire une proprit de la variable x (dtre gale 2), mais plus simplement, on range ( cet instant prcis du programme) dans la case mmoire dsigne par le nom x la valeur numrique 2.

1.1. COURS

17

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 232 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 une approximation des 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 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 000 001 NUL DLE SOH DC1 STX DC2 ETX DC3 EOT DC4 ENQ NAK ACK SYN BEL ETB BS CAN HT EM LF SUB VT ESC FF FS CR GS SO RS SI US 010 011 100 SPACE 0 @ ! 1 A " 2 B # 3 C $ 4 D % 5 E & 6 F 7 G ( 8 H ) 9 I * : J + ; K , < L = M . > N / ? O 101 P Q R S T U V W X Y Z [ \ ] ^ _ 110 a b c d e f g h i j k l m n o 111 p q r s t u v w x y z { | } ~ DEL

TABLE 1.1 Le code ASCII 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

18

CHAPITRE 1. INTRODUCTION

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 4 , 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
1.1.3.1

Mise en uvre dun programme


Quest-ce quun langage de programmation ?

Ncessaire 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 programme 5 , 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 deux tapes (compilation et dition des liens) peuvent senchaner directement par la commande unique :
4. Il ne comporte en effet que les lettres majuscules et minuscules, les chiffres, quelques caractres de ponctuation, ainsi que des caractres dits de contrle , reprsents ici par des abrviations ; ainsi LF est le passage la ligne. La quasi-totalit de ces caractres de contrle nest plus utilise aujourdhui, et nest prsente que pour des raisons historiques... 5. Nous nous limitons ici au cas traditionnel des langages compils.

1.1. COURS $ gcc prog.c -Wall -ansi -pedantic -o prog

19

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 -Wall -ansi -pedantic -o prog.exe Le lancement peut seffectuer par le seul nom prog. Dans ce cas particulier, linterprteur 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 des dclarations permettant au programmeur de faire appel aux oprations dentres-sorties dans son programme (voir les instructions #include <...> dans lexemple qui suit).

1.1.4

Un premier programme C
#include <stdio.h> #include <stdlib.h> int main(int argc, char * argv[]) { printf("hello world\n"); return 0; } F IGURE 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 standards (std) dentres-sorties (io pour input/output) du langage C. Le sufxe .h indique quil sagit dun chier den-tte (en anglais, header ).

20

CHAPITRE 1. INTRODUCTION 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 : printf("hello world\n"); constitue un appel de la procdure 6 printf 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 printf, ce que lon indique par les parenthses suivant le nom de la procdure. Le point virgule termine linstruction. On notera que le message se termine par la squence des deux caractres \n qui indique quil faut passer la ligne aprs cette impression. 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. Une autre manire darrter un programme est dutiliser une instruction : exit(0); La procdure du systme exit permet de stopper lexcution du programme et redonne la main au systme : le nombre pass en paramtre a la mme signication que pour linstruction return. L galement, le point-virgule termine linstruction. 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. Par contre, la procdure exit, o quelle soit appele dans le programme, en provoque sa n immdiate.

Notes : nous respecterons la lettre la notation : int main(int argc, char * argv[]) Elle dclare en effet quil sagit du programme principal, et que ce programme fournira au systme un code de retour sous la forme dun int. Sa prsence permet au moment du
6. Une procdure est un ensemble dinstructions rpondant une nalit prcise. Beaucoup sont prdnies dans le systme ; nous verrons au chapitre 3 comment en dnir de nouvelles.

1.1. COURS

21

lancement du programme de savoir quel endroit on va commencer le programme, cest-dire quelle est la premire instruction excuter. Ce programme principal communique avec son environnement au moyen des deux variables argc et argv. 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.

$ gcc -Wall -ansi -pedantic prog1.c -o prog1 $ ./prog1 hello world $ F IGURE 1.3 Excution du programme sous un shell Linux

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

Notes : Limpression du message hello world est suivie dun passage la ligne ; celui-ci doit tre explicitement demand par la squence des deux caractres \n 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, Linux naccepte dexcuter que les programmes situs dans un ensemble prdni de rpertoires (ensemble dsign par le contenu de la variable du shell PATH). Sil nest pas dclar que le rpertoire courant (le rpertoire dsign par .) fait partie de cet ensemble, il faut utiliser une notation telle que : $ ./prog1 pour lancer lexcution du programme.

22

CHAPITRE 1. INTRODUCTION
#include <stdio.h> #include <stdlib.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 diametre %f est %f\n", diametre, surface); return 0; }

F IGURE 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 besoin dans ce programme de manipuler 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. Le programme utilise ici le mcanisme de reprsentation dune donne par une variable. Ici, trois variables sont utilises, une pour reprsenter le rayon du disque, une pour reprsenter le diamtre, et la dernire pour reprsenter la valeur de : ces trois variables sont respectivement nommes rayon, diametre (bien noter que lon na pas utilis de caractre accentu dans ce nom de variable !) et pi. Ce programme contient alors les lments suivants : comme dans le cas prcdent, linclusion des dclarations ncessaires aux entressorties ; la dclaration "habituelle" de la procdure 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

1.1. COURS

23

(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 correspondante est ainsi modi. Lexpression utilise les oprations de multiplication et division (reprsentes par * et / respectivement), les 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 : $ ./calcsurf La surface du disque de diametre 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 !

24 Mots clefs int long short char long long float double long double Description entier entier entier entier entier ottant ottant ottant

CHAPITRE 1. INTRODUCTION Taille sur nos machines 4 octets 4 octets 2 octets 1 octet 8 octets 4 octets 8 octets 12 ou 16 octets

TABLE 1.2 Types de donnes du langage C

1.1.6
1.1.6.1

Types et variables en C
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 : 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 (long double) 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 ; attention toutefois : lutilisation simultane dans des expressions arithmtiques ou logiques de variables (ou constantes) signes et non signes est trs souvent source de bogues ! long et short sont en fait des abrviations pour long int et short int (ces deux notations sont 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. COURS 1.1.6.2 Constantes

25

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 (en base 10) : succession de chiffres ventuellement prcde dun signe 12 -123 +345 notation octale (en base 8) : succession de chiffres commenant par 0 0123 077770 notation hexadcimale (en base 16) : 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 0xdeadbeef notation caractres : succession de caractres entre simples quotes ; criture en base 256, chaque caractre reprsentant son code ASCII ; le plus souvent limite un seul caractre a 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 par dfaut, une constante ottante est de type double ; 1.1.6.3 Arithmtique mixte (entiers et ottants)

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 22), 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

26

CHAPITRE 1. INTRODUCTION

locution et commercial ) 7 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[]) { int i = 1, j = 2; printf("i=%d, adresse(i)=%p\n",i,&i); printf("j=%d, adresse(j)=%p\n",j,&j); return 0; } donne lexcution : i=1, adresse(i)=7fff2ee0 j=2, adresse(j)=7fff2ee4 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 :
7. Voir lURL http://www.adobe.fr/type/topics/theampersand.html pour des informations sur lorigine de ce caractre

1.1. COURS int i=2,*j; j = &i; printf("*j=%d,i=%d\n",*j,i); *j=4; printf("i=%d,*j=%d\n",i,*j);

27

qui, lexcution, afche :

*j=2,i=2 i=4,*j=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 ; 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.

28

CHAPITRE 1. INTRODUCTION

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 /* nombre de francs dans un euro */; Les instructions du langage : expressions arithmtiques entires, ottantes, mixtes. affectation : "variable" = "expression" ; impression : printf(" format \n", valeurs );

1.3
1.3.1

Travaux pratiques
Exercice 1

Tapez et testez les deux exemples de programmes donns en cours.

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.

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 : le calcul du PGCD

On se propose dcrire un programme permettant le calcul du PGCD de deux nombres entiers. 2.1.1.1 Lalgorithme

On se rappelle que ce problme peut tre rsolu (mathmatiquement parlant) par lalgorithme dEuclide, qui sapplique deux entiers positifs. Le principe de celui-ci est le suivant : tant que les deux nombres sont non nuls, on retranche du plus grand des deux nombres le plus petit. Quand lun des deux nombres devient nul (ou, autre test qui demande une tape de moins, devient gal lautre), la valeur de lautre nombre est le PGCD des deux nombres initiaux 1 . 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. 2. 3. 4. vrier que a b ; sinon, permuter les deux nombres. est-ce que a = b ? Si oui, le PGCD est a et le programme est termin. sinon, retrancher b de a. revenir ltape 1.

1. Ceci est la version de lalgorithme dEuclide qui neffectue que des soustractions, il en existe une autre qui a besoin de loprateur modulo. Not %, celui-ci, sous la forme a%b, fournit le reste de la division entire de a par b.

29

30 2.1.1.2

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES Passage au programme

Les deux nombres entiers 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 respectivement 2 . 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. NB : la paire de parenthses autour de lexpression de test est obligatoire (elle fait partie de la syntaxe de linstruction conditionnelle). 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 de 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); return 0; }
2. 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, oat ou mme dune adresse mmoire) est la valeur faux.

2.1. COURS

31

NB : comme pour la permutation des valeurs, on a ici plusieurs (deux) instructions excuter si le test est vrai, on a donc regroup ces deux instructions dans une instruction compose. tape 3 Pas de difcult non plus pour ce fragment de lalgorithme, qui scrit : a=a-b;

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); return 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 (aprs compilation du programme) fournit la rponse suivante : $ ./pgcd La valeur du PGCD est 743

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 IGURE 2.1 PGCD de deux nombres 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)) { ... } 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. COURS

33

2.1.2

Somme des premiers entiers

On veut maintenant, pour un entier N donn, calculer la somme des N premiers entiers (cest--dire la somme des entiers allant de 1 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 : int n, s, i; ... s = 0; for (i=1; i<=n; i++) s = s+i; Notes : Cet exemple nous permet de prsenter de manire informelle la syntaxe dune boucle for : for (initialisation ; continuation ; gestion ) instruction Dans cette syntaxe : initialisation, continuation et gestion sont trois expressions numriques ; lexpression initialisation est toujours calcule pralablement la boucle proprement dite. Souvent, on lutilise pour affecter des valeurs initiales aux variables qui vont tre utilises au sein de la boucle. lexpression continuation est un calcul effectu en dbut de chaque boucle : si la valeur calcule est vraie (non nulle), la boucle continue et on excute linstruction de boucle, sinon elle sinterrompt. enn, lexpression gestion est toujours calcule aprs linstruction de boucle ; le plus souvent, elle permet la modication des variables utilises dans la boucle avant un nouveau test. On verra que dans certains cas, il ny a pas de 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 (la syntaxe est dite sufxe, loprateur tant situ aprs loprande) ; ++i est une expression qui fournit la valeur de i aprs lincrmentation (la syntaxe est dite prxe, loprateur tant situ avant loprande).

34

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES

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, et sutilise aussi bien avec une syntaxe prxe quavec une syntaxe sufxe. 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; 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

Le problme rsoudre en premier est de dterminer un algorithme de calcul du sinus : bien que tout un chacun sache parfaitement ce quest un sinus, il nest pas vident de savoir comment le calculer ! On notera x la valeur dont on cherche calculer le sinus (en C, on reprsentera x par une variable de type double). On sait que lon peut obtenir la valeur de sin(x) par la relation :

sin(x) =
i=0

(1)i

x2i+1 (2i + 1)!

2.1. COURS

35

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 | , et on sait que lerreur commise en tronquant une srie alterne au rang N (la diffrence i > |x 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)! |x| 2 et |x|2n+1 < } (2n + 1)!

N = min{n 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. On peut remarquer que la somme recherche peut sexprimer par :
N

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 x2 wi+1

et wi peut tre calcul par rcurrence : w0 = 0 wi+1 = wi + 8i + 6

36

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES

On peut encore rcrire lexpression de la suite wi sous la forme wi+1 = wi + zi+1 en posant zi = 8i 2. Enn, 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 qui consiste calculer par rcurrence : 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 on na pas besoin de mmoriser que les valeurs des suites lindice i pour calculer les valeurs lindice i + 1, il est possible de nutiliser pour chacune des suites dnies ci-dessus quune 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 | prcision demande (sans oublier de tester si i > |x , puisque ce nest que lorsque cette condition 2 est remplie que la srie est alterne). Le programme complet est donn la gure 2.2 :

Notons : lutilisation de la procdure de la bibliothque mathmatique fabs, qui fournit la valeur absolue de son argument (argument et rsultat sont de type double) ; lutilisation de cette procdure 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]

2.1. COURS
#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)) { printf("sin(%.10g)=%.10g\n",x,U); printf(" [apres %d iterations]\n",i+1); return 0; } } }

37

F IGURE 2.2 Calcul dun sinus 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.3.3 Petit problme !

On veut calculer le sinus de 100 . On modie donc le programme prcdent (en insrant linstruction x=100*M_PI; en lieu et place de x=M_PI/4;), et on obtient le rsultat suivant : sin(314.1592654)=-6.04152987e+118 [apres 433 iterations] ce qui est plutt surprenant pour une valeur cense tre gale 0. . . 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 de-

38

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES

mande, le terme de valeur absolue maximale, est (pour x = 100 ) le terme dindice 155, soit : |u155 | = (100 )311 6 10134 311!

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 6 10134 , on obtient donc une erreur absolue de lordre de 6 10118 , cest bien lordre du rsultat obtenu ! Ce problme de prcision des calculs en ottant doit tre une proccupation constante, et ncessite dutiliser au maximum les proprits mathmatiques du problme considr. Dans le cas particulier de la fonction sinus, cest la priodicit qui va permettre damliorer grandement les choses : se ramener une valeur de x entre et permet dobtenir une prcision tout fait acceptable. On peut ainsi insrer dans les initialisations linstruction : x=fmod(x,2*M_PI); en utilisant la procdure fmod (calcul de modulo sur des donnes de type double), appartenant toujours la bibliothque mathmatique. Lexcution du programme ainsi modi donne alors : sin(314.1592654)=1.421085472e-14 [apres 2 iterations] beaucoup plus raliste , et en mme temps bien 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 procdure, des limitations lies la programmation de cette procdure ! 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.

2.2. RETENIR

39

2.2

retenir
oprateurs arithmtiques + - / * % 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 instruction conditionnelle if (condition) instruction if (condition) instruction else instruction instruction compose { squence dinstructions }

2.3
2.3.1

Travaux pratiques
Exercice 1

Ecrire un programme qui dtermine si un nombre est premier. Le nombre dont on teste la primalit est dni par une affectation dans le programme (effectuer des tests avec 2, 4, 7 puis 12894913). Si le nombre nest pas premier, le programme doit donner 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

Ecrire un programme qui dtermine 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). Dterminer les deux (voire 3) nombres parfaits suivants.

40

CHAPITRE 2. QUELQUES PROBLMES LMENTAIRES

2.3.4

Exercice 4

Ecrire un programme qui calcule, 106 prs, la racine du polynme x4 + 3x2 x 1 = 0 situe dans lintervalle [0, 1]. On oprera pour cela par dichotomies successives, en divisant par deux la taille de lintervalle jusqu obtention de la prcision dsire. Le programme devra afcher les valeurs successives calcules.

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 est multipli par deux, et on prlve toujours un euro de frais de gestion ; la n-ime anne, le capital est multipli par n, et on prlve toujours un euro de frais de gestion ; le placement est prvu pour une dure de 40 ans. Dterminer le capital restant au bout des 40 ans. Notes : le chier den-tte math.h dnit la macro non-standard (il faut donc retirer les drapeaux de compilation -ansi et -pedantic) 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) ; pour avoir de bonnes approximations de e dans les diffrents types, on peut utiliser les 3 versions de la procdure exponentielle disponible dans la bibliothque mathmatique : exp() (version en double), expf() (version en float) et expl() (version en long double) ; consulter les pages de manuel de ces procdures ! quel est le rsultat mathmatique ?

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

Nous avions crit lors dune prcdente sance le calcul du PGCD de deux nombres par lalgorithme dEuclide, dont le code 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 pour lutiliser 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 41

42

CHAPITRE 3. PROCDURES
#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 IGURE 3.1 Programme PGCD (rappel) 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. Une procdure peut mme sappeler elle-mme, on dit alors que la procdure est rcursive. 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 (malheureusement, ce nest quune modlisation partielle, 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


void pgcd(void) { for (;;) { if (a<b) { c=a; a=b; b=c; } if (a==b) { return; } a=a-b; } }

Voici une premire version de la procdure PGCD :

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 avant laccolade fermante de n de procdure). 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 (mme sil ny a pas de paramtres la procdure), 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

44

CHAPITRE 3. PROCDURES

permet pas une procdure dutiliser des variables dnies dans dautres procdures (on dit que les variables sont locales la procdure). 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 || b==0) { 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 IGURE 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

3.1. COURS

45

procdures (variables globales) : le programme principal positionne les deux valeurs initiales des variables a et b ; le programme principal appelle la procdure pgcd ; la procdure pgcd utilise (et modie) ces deux variables, fournissant dans lune delles (les deux, dailleurs) le rsultat ; au retour de la procdure, le programme principal retrouve donc ce rsultat (dans la variable a) 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 quasiment ingrable ds lors que plus dune procdure est utilise 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 de linstruction ci-dessus : le compilateur a dcel un appel de procdure (grce la parenthse ouvrante juste aprs le nom de la procdure pgcd) ; le programme commence dabord par calculer les paramtres, qui peuvent tre des expressions numriques quelconques ; 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 dans des cases mmoires dtermines par le compilateur ; une fois les paramtres calculs, le compteur programme est mmoris (galement dans une case mmoire dtermine par le compilateur), puis modi avec ladresse de la premire instruction de la procdure appele ; ainsi, lorsque le processeur excute linstruction suivante, il va dmarrer lexcution de la procdure pgcd ;

46

CHAPITRE 3. PROCDURES

au dbut de cette excution, tout se passe comme si la procdure recopiait les valeurs mmorises des paramtres dans les cases mmoires rserves par la procdure (ici, les paramtres x et y de la procdure) ; le code de la procdure pgcd est excut de faon squentielle classique ; lors de lexcution de linstruction return x, on calcule la valeur du rsultat (lexpression aprs le return, ici simplement le contenu de la variable x mais qui pourrait tre une expression plus complexe) ; ce rsultat est mmoris un endroit particulier de la mmoire ; on restaure alors le compteur programme avec la valeur (ladresse) mmorise avant lappel de la procdure pgcd : le programme reprend donc l o il en tait dans la procdure appelante ; dans la procdure appelante, la valeur de la procdure ayant t calcule et mmorise, il reste excuter linstruction qui va stocker cette valeur dans la variable a ; la procdure appelante passe ensuite linstruction suivante. Notons que si la valeur rendue par une procdure nest pas immdiatement utilise (soit pour tre stocke dans une variable, dans un test, une expression numrique quelconque. . .), elle est perdue ! 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, avec la version nale ( utiliser) de la procdure pgcd.

3.1.5
3.1.5.1

Quelques aspects des procdures du langage C


Variables locales et globales

Il aurait t possible de nommer a et b (plutt que x et y) les deux paramtres de la procdure 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.

3.1. COURS
#include <stdio.h> int pgcd(int x, int y) { int c; for (;;) { if (x<y) { c=x; x=y; y=c; } if (x==y || y==0) { 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; }

47

F IGURE 3.3 Procdure PGCD de deux nombres (deuxime version) 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 proc-

48

CHAPITRE 3. PROCDURES

dure 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. 3.1.5.2 Paramtres dune procdure

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. Le compilateur gcc peut aider reprer les procdures non dclares (ou utilises non conformment leur dclaration) en utilisant loption -Wall : il est donc fortement recommand dutiliser systmatiquement cette option. 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 procdure suivi dun point-virgule. Le prototype de la procdure PGCD se dclare ainsi : int pgcd(int a, int b); Il nest en fait pas ncessaire de fournir le nom des paramtres (comme on la expliqu prcdemment, on na aucun moyen pour accder de lextrieur de la procdure aux variables locales de cette procdure) ; la dclaration peut donc galement 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.

3.1. COURS

49

On notera que le mot-clef void dsigne un type de donnes particulier, de taille 0, qui indique quune procdure 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 choisir ni le nom, ni le nombre et le type des paramtres) 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 un peu plus tard dans le cours 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.5.4 Compilation spare

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 procdure. 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 : $ gcc -c -Wall prog3.c

50

CHAPITRE 3. PROCDURES

Notons loption -c qui indique que lon dsire seulement compiler le chier prog3.c sans chercher immdiatement faire une dition de liens pour obtenir un programme excutable. 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 : $ gcc -c -Wall 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 : $ 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 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. Notons enn que loption -Wall ne concerne que la phase de compilation : il nest donc pas ncessaire de la prciser pour la phase ddition de liens. 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 un ensemble prdni de rpertoires du systme, ces rpertoires contenant de nombreux chiers den-tte pour les procdures standard du langage C, ici, certaines oprations dentres-sorties. 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 : il ne faut y placer 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 :

3.1. COURS extern int pgcd(int, int);

51

Dans le chier prog3.c , celui qui contient le programme principal, nous pouvons ds lors remplacer la ligne dnissant le prototype de la procdure 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; } 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 (comme header). 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. Une dernire remarque : il est de bonne pratique dinclure le chier den-tte dans le module source correspondant (ici, inclure pgcd.h dans le code source de pgcd.c), an que le compilateur puisse ainsi dtecter dventuelle incohrences entre ces deux chiers.

3.1.6

Quelques procdures de C

Nous avons dj utilis, dans les cours antrieurs, quelques procdures du systme, en particulier celle qui fournit un service dimpression, printf. 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

52

CHAPITRE 3. PROCDURES

Nom acos asin atan atan2 ceil cos cosh

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

Description arc cosinus du paramtre arc sinus du paramtre arc tangente du paramtre arc tangente de y/x plus grand entier au paramtre cosinus du paramtre cosinus hyperbolique du paramtre exponentielle du paramtre valeur absolue du paramtre plus petit entier au paramtre reste de la division de x par y . logarithme du paramtre logarithme en base 10 du paramtre xy sinus du paramtre sinus hyperbolique du paramtre racine carre du paramtre tangente du paramtre tangente hyperbolique du paramtre

exp double exp(double x) fabs double fabs(double x) floor double floor(double x) fmod double fmod(double x, double y) log double log(double x) log10 double log10(double x) pow sin sinh sqrt tan tanh double pow(double x, double y) double sin(double x) double sinh(double x) double sqrt(double x) double tan(double x) double tanh(double x)

F IGURE 3.4 Quelques procdures mathmatiques du Langage C

3.1. COURS

53

(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 procdures, 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 procdures pr-compiles, 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 procdure 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 procdure atan2 fournit larc dont le sinus est k x et le cosinus k y , avec k > 0 ; elle permet donc de trouver langle polaire du point du plan de coordonnes (x, y ) en traitant les cas particuliers (point sur les axes de coordonnes) ; le rsultat de certaines procdures, 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 :

54 Nom abs atof atoi atol exit labs rand srand Prototype int abs(int p) double atof(char* s) int atoi(char* s) long atol(char* s) void exit(int cr)

CHAPITRE 3. PROCDURES Description Valeur absolue du paramtre Conversion caractres vers ottant Conversion caractres vers entier Conversion caractres vers entier Arrt du programme, fourniture dun code de retour long labs(long p) Valeur absolue du paramtre int rand(void) Fournit un entier pseudo-alatoire void srand(int seed) Initialisation du gnrateur de nombres pseudo-alatoires F IGURE 3.5 Quelques utilitaires de C 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, et permet dobtenir des suites alatoires diffrentes chaque excution du programme pour peu que lon attende au moins une seconde entre deux lancements conscutifs (pour utiliser time, il faut inclure dans le programme les dclarations de time.h).

3.1.7
3.1.7.1

Paramtres de procdure de type adresse


Le problme

Il arrive parfois que lon souhaite crire une procdure qui calcule deux (ou plus) rsultats simultanment (par exemple, le PGCD et le PPCM). Hlas, le langage C ne permet pas une procdure de retourner plusieurs rsultats. Que faire ? Lune des solutions possibles consiste utiliser lun des paramtres de la procdure, non pas pour fournir la procdure une donne dont elle a besoin, mais au contraire pour rcuprer une donne (on appelle parfois paramtre de sortie un tel paramtre). On aurait alors envie dcrire : int pgcd (int x, int y, int ppcm) { int c; for (ppcm=x*y;;) { if (x<y) { c=x;x=y;y=c; } if (x==y || y==0) { ppcm/=x;

3.1. COURS return x; } x=x-y; } } int main (int argc,char *argv[]) { int a,b,r,ppcm; a=24; b=60; r=pgcd(a,b,ppcm); printf("Le PGCD est %d, le PPCM est %d\n",r,ppcm); return 0; } Malheureusement, on nobtient pas, lexcution, le rsultat attendu : $ ./pgpp Le PGCD est 12, le PPCM est 0

55

Quel est le problme ? En fait, il faut se rappeler une caractristique importante des procdures du langage C : les paramtres des procdures sont des copies des valeurs, et la procdure travaille donc sur ces copies. Ainsi, la procdure pgcd telle quelle est code calcule bien le PPCM des deux entiers, mais la valeur calcule est stocke dans une variable locale de cette procdure (la variable ppcm) qui est une copie de la valeur passe en paramtre (ici, la valeur contenue dans la variable ppcm de la procdure main, qui na dailleurs pas reu de valeur initiale. . .) : cette variable locale est dailleurs dtruite la n de lexcution de la procdure pgcd. Comment sen sortir ? 3.1.7.2 La solution

On se rappelle alors que le langage C permet dutiliser les adresses mmoire des variables, et permet galement de dnir des variables de type adresse mmoire. Lide est donc de donner la procdure non pas la copie de la variable, mais ladresse mmoire (en fait, une copie de ladresse mmoire) de la variable modier ! Ainsi, la procdure appele pourra modier directement la case mmoire concerne. Voici un nouveau codage, correct cette fois-ci, du programme : int pgcd (int x, int y, int *ppcm) { int c; for (*ppcm=x*y;;) {

56 if (x<y) { c=x;x=y;y=c; } if (x==y || y==0) { (*ppcm)/=x; return x; } x=x-y; } } int main (int argc,char *argv[]) { int a,b,r,ppcm;

CHAPITRE 3. PROCDURES

a=24; b=60; r=pgcd(a,b,&ppcm); printf("Le PGCD est %d, le PPCM est %d\n",r,ppcm); return 0; } qui donne bien cette fois le rsultat attendu : $ ./pgpp Le PGCD est 12, le PPCM est 120 Il faut bien comprendre ce code : la procdure pgcd dclare un paramtre de type adresse dentier int *ppcm ; la procdure ne modie pas ce paramtre, mais modie la case mmoire dont ladresse est contenue dans ce paramtre (cest bien ce que lon cherche faire !) par linstruction *ppcm=... ; dans la procdure main, on dclare une variable entire ppcm, dont ladresse mmoire est passe en paramtre la procdure pgcd (notez la faon de passer ce paramtre en utilisant loprateur &) ; cette variable na pas besoin dtre initialise, cest la procdure pgcd qui y stockera la valeur voulue. 3.1.7.3 Autres utilisations du passage par adresse

De faon plus gnrale, on peut retenir que toute procdure qui doit modier une variable de la procdure appelante doit recevoir en paramtre ladresse de cette variable : sans cela, elle serait totalement incapable daccder la case mmoire correspondante. Saisie de donnes formates au clavier Un exemple classique dutilisation du passage par adresse est la procdure standard scanf : cest une procdure qui permet de saisir des donnes au clavier (ou dans un chier quelconque si lon utilise la procdure plus gnrale fscanf

3.1. COURS

57

qui sera dtaille dans la seconde partie du cours au chapitre des entres-sorties). Imaginons par exemple que lon souhaite calculer le PGCD de deux nombres fournis au moment de lexcution par lutilisateur (et non pas compils en dur ) dans le programme. Voici alors une faon de saisir ces nombres : int a,b; printf("Entrer la valeur de A :"); scanf("%d",&a); printf("Entrer la valeur de B :"); scanf("%d",&b); printf("A = %d, B = %d\n",a,b); ... Le premier paramtre de cette procdure scanf est ce que lon appelle le format, cest dire une description symbolique des types de paramtres lire (et aussi, le nombre de paramtres). Ici, la description "%d" indique que lon va chercher lire un entier crit en caractres dcimaux (cest la mme convention que pour la procdure dimpression de valeurs printf). A noter que la procdure scanf peut lire plusieurs valeurs en une seule fois, il suft de lindiquer dans le format. On pourrait ainsi crire : int a,b; printf("Entrer les valeurs de A et B :"); scanf("%d%d",&a,&b); printf("A = %d, B = %d\n",a,b); ... Le rsultat de la procdure scanf est alors le nombre de paramtres correctement lus. Un code de lecture plus complet pourrait ainsi scrire : int a,b; for (;;) { printf("Entrer les valeurs de A et B : "); if (2==scanf("%d%d",&a,&b)) break; } ... Ainsi, le programme va demander rptitivement dentrer les deux valeurs de A et B, jusqu ce que le format soit correct, cest--dire que lon ait russi lire deux entiers dcimaux ! Procdure dchange de deux variables Dans le programme sur le PGCD, on avait besoin dchanger les deux entiers (dans le cas o le premier tait infrieur au second). On aurait pu coder ceci dans une procdure spare en utilisant un passage par adresse ; en voici un codage possible :

58 void echange_entiers (int *x,int *y) { int c; if (*x < *y) { c=*x;*x=*y;*y=c; } } int pgcd (int x,int y) { for (;;) { echange_entiers(&x,&y); if (x==y || y==0) return x; x-=y; } }

CHAPITRE 3. PROCDURES

3.2. RETENIR

59

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
3.3.1

Travaux pratiques
Exercice 1

crire une procdure qui calcule le PPCM de deux nombres entiers. crire une procdure qui indique si deux nombres sont premiers entre eux. crire le programme principal qui utilise les trois procdures (PGCD, PPCM, test) sur deux entiers dnis dans ce programme principal (on pourra utiliser les entiers 834389 et 944353).

60

CHAPITRE 3. PROCDURES

3.3.2

Exercice 2

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.3

Exercice 3

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 (le tester avec N au moins gal 100).

3.3.4

Exercice 4

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.5

Exercice 5

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.

Chapitre 4 Tableaux
4.1 Cours

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 une constante entire, indique le nombre dlments rservs pour le tableau. 61

62

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) { instruction gestion_de_lindice; }

4.1.2
4.1.2.1

Les tableaux
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. COURS 4.1.2.2 Dclaration de tableau

63

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 (qui, on le rappelle est le i + 1e lment du tableau) 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.

64 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 souvent 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. COURS 4.1.2.5 Tableaux de caractres

65

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.4. 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)

66

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 procdure 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);

4.1. COURS

67

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 : pruc(&toto[2],8); 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("min=%d max=%d\n", res[0], res[1]); return 0; }

4.1.3

Tableaux plusieurs dimensions

Il est possible en langage C de dnir des tableaux plusieurs dimensions. On a lhabitude den donner une dnition par rcurrence : un tableau N dimensions est considr comme un tableau monodimensionnel dont chaque lment est lui-mme un tableau N-1 dimensions. Au niveau de la dclaration dune variable de type tableau plusieurs dimensions, on fait suivre le nom de la variable par les tailles de chacune des dimensions :

68 int matrice[10][5]; int mat3d[3][4][5];

CHAPITRE 4. TABLEAUX

Si lon souhaite initialiser un tel tableau, il est recommand (mais pas absolument obligatoire) de donner la suite des valeurs par ordre lexicographique (par ordre croissant sur la dernire dimension dabord). Ainsi, la dclaration avec initialisation suivante : int matrice[2][3] = { { 0, 1, 2} , { 3, 4, 5}}; est quivalente (du point de vue du rsultat) : int matrice[2][3]; mat[0][0] = 0 ; mat[0][1] = 1 ; mat[0][2] = 2 ; mat[1][0] = 3 ; mat[0][1] = 4 ; mat[0][2] = 5 ; mais on aurait aussi pu crire (bien que ceci gnre parfois des messages davertissement) : int matrice[2][3] = {0, 1, 2, 3, 4, 5}; Notons que dans un tableau N dimensions, les N-1 dernires dimensions sont obligatoirement identiques (par exemple, dans une matrice, toutes les lignes doivent avoir le mme nombre de colonnes). De la mme faon que pour les tableaux une dimension dont on peut ne pas prciser la taille, il est possible de ne pas prciser la taille de la premire dimension : la dclaration suivante int matrice[][5]; dclare ainsi une matrice qui contient un certain nombre de lignes contenant chacune 5 entiers. Par contre, la dclaration suivante int matrice[][]; provoquera une erreur de compilation, car le compilateur ne sait pas comment il doit ranger les valeurs en mmoire.

4.1.4
4.1.4.1

Chanes de caractres
Introduction

Une chane de caractres est une suite doctets non nuls, se terminant par un octet gal 0, dit souvent NUL 1 . 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"
1. cette notation est celle issue du code ASCII.

4.1. COURS Nom strcat Prototype char * strcat(char * d, const char * s) strcmp int strcmp(const char * d, const char * s) strcpy char * strcpy(char * d, const char * s) strlen int strlen(const char * s) strncat char * strncat(char * d, const char * s, int n) strncmp int strncmp(const char * d, const char * s, int n) strncpy char * strncpy(char * d, const char * s, int n) Description Concatnation de deux chanes Comparaison de deux chanes Copie dune chane Longueur dune chane Concatnation de deux chanes Comparaison de deux chanes Copie dune chane

69

F IGURE 4.1 Quelques oprations sur chanes de caractres 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 quil faut viter lutilisation de chanes contenant des caractres en dehors du code ASCII (caractres accentus, signes montaires. . .), les rsultats pouvant dpendre de lenvironnement : systme dexploitation, compilateur, variables denvironnement. 4.1.4.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 procdures sont dcrits dans le chier dinclusion string.h.

70

CHAPITRE 4. TABLEAUX

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.4.3 Exemples de manipulation de chanes de caractres

Dclaration dune chane Voici la dclaration dune variable de type chane de caractres : char c1 [] = "Une suite doctets"; Le compilateur dduit ici que la taille du tableau est de 19 octets (incluant loctet nal de valeur 0). On trouve galement des dclarations prenant la forme suivante : char *c1 = "Une suite doctets"; Attention : bien que trs proche, ces deux dclarations sont subtilement diffrentes. Dans le premier cas, on ne peut pas modier la valeur de la variable c1 (cest un tableau, donc une constante) ; dans le second cas, c1 est une variable de type adresse et peut donc tre modie. Mais dans les deux cas, la modication du contenu de la chane peut se faire de la mme manire : puts(c1); strcpy(c1,"toto"); c1[2]=a; ... Longueur dune chane Par convention, la longueur dune chane de caractres est le nombre doctets avant le caractre NUL de n ; ainsi, la valeur de lexpression : strlen("ABCD"); est 4 (le nombre doctets non nuls), et non 5, nombre doctets servant reprsenter la chane. strlen("t"); donnera un rsultat diffrent selon le type de codage utilis (Unicode, Latin-1. . .) voire une erreur pour certains compilateurs.

4.1. COURS Copie dune chane char c2[10]; ... strcpy(c2,"ABCD");

71

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 ? ? ? ? ?

(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 NUL 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 NUL 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"

72

CHAPITRE 4. TABLEAUX

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 : 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; } }

4.1.5

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"

4.2. RETENIR

73

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 procdure de conversion lintrieur du code source du programme ; NB3 : il faut noter que largument argv nest pas dni comme un tableau deux dimensions de caractres ; en effet, rien nimpose que tous les arguments de la ligne de commande aient la mme longueur ! 4.1.5.1 Utilisation des arguments de la procdure main

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 variable de type adresse type * nom ; chane de caractres notation spcique pour un tableau de caractres caractre NUL 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 adresse tableau et procdure passage des tableaux par adresse

74

CHAPITRE 4. TABLEAUX

4.3
4.3.1

Travaux pratiques
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 lune des plus leves en cas de ex-aequo) et la plus faible, et de calculer la moyenne des N 2 restantes. crire une procdure dont le prototype est le suivant : double moy_olymp(int notes[], int N);

4.3.2

Exercice 2

crire une procdure qui ralise une permutation alatoire dun tableau dentiers (on peut utiliser la procdure rand). Si possible, cette procdure ne doit pas crer de copie du tableau, mais le permuter en place . Le prototype de cette procdure 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 dafcher dans le terminal un histogramme connu par un tableau de valeurs 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 doit afcher lhistogramme dans la fentre du terminal, en utilisant des blancs et des toiles, comme dans lexemple de la gure 4.2, qui correspond au tableau prcdent. Ainsi : la succession dtoiles en bas du dessin correspond au trac de laxe des abscisses ; les deux toiles en premire colonne ( partir de la gauche, au-dessus de laxe des abscisses) correspondent la valeur 2 en premier lment du tableau ; les trois toiles en seconde colonne correspondent la valeur 3 en second lment du tableau ; etc.

4.3. TRAVAUX PRATIQUES * ** ** *** **** ***** * ******* ** ******** **** ******** **** ********* **** ********* * ***** * ************ ***** ************** ****** *************** ****** *************** ****** ***************** ******* ******************* ******** ********************* ******** ****************************** F IGURE 4.2 Histogramme Il faut prendre garde au fait que dans le terminal, les lignes sont crites de haut en bas ! crire une procdure dont le prototype est : void histog(int v[], int nb)

75

Modier le programme an de pouvoir choisir la hauteur maximale de lhistogramme (ce qui revient faire une mise lchelle). 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 visualiseur dhistogrammes de lexercice prcdent. Plus prcisment, on construira un tableau 51 valeurs, chaque lment i du tableau contenant le nombre de fois que la valeur i a t choisie par le gnrateur alatoire. Puis on utilisera le visualiseur dhistogramme (en xant une chelle convenable).

4.3.6

Exercice 6

Modier le programme prcdent, an de gnrer cette fois une distribution gaussienne qui sera calcule par le programme.

76

CHAPITRE 4. TABLEAUX

Indication : (on peut approcher une distribution gaussienne par une somme de douze valeurs alatoires uniformes de [-0.5,0.5]).

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() 2 . 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..

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.

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

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. 77

78

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 1erjanvier 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 procdure de bibliothque time qui permettra de tester notre propre version de cette procdure. On supposera donc dornavant que les instants T1 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 procdure 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 1erjanvier 1970 0h00 et le 1erjanvier de lanne A 0h00 (ce nombre ne dpend que de A, on le note N1 (A)) ; du nombre de secondes entre le 1erjanvier de lanne A 0h00 et le 1erjour 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 1erjour 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 Ni = N ji 86400, les N ji correspondant aux nombres de jours (et 86400 est le nombre de secondes par jour). On peut donc crire la procdure N :
1. dans un souci de simplicit, on ne tiendra pas compte des secondes supplmentaires parfois ajoutes pour corriger les dfauts de dure de rvolution terrestre.

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)

79

Ce calcul est trs simple : on peut crire directement la procdure : int N_4 (int h,int m,int s) { return s+60*(m+60*h); } 5.1.1.4 Calcul de N j3 (j )

Pas de difcult particulire non plus ! On crit : int Nj_3 (int j) { return j-1; } 5.1.1.5 Calcul de N j1
A1

On peut crire : N j1 (A) =


a=1970

n j ( 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 procdure que lon note bissextile(A) permettant de tester si son argument est bissextile. Cette procdure permet ensuite dcrire lalgorithme de calcul de N j1 , crit ci-dessous en C : int n_j (int a) { if (bissextile(a)) return 366; return 365; }
2. Les lecteurs qui sintressent au problmes dajustement de calendrier (julien, grgorien, orthodoxe. . .) peuvent consulter lURL http://www.emse.fr/roelens/calendar.txt

80

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 procdure 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 N j2

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 procdure 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 procdure : 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; } }

81

Remarque 1 : on rutilise ici la procdure bissextile, dj utilise pour la procdure N j1 . Cette rutilisation est lun des avantages du dcoupage en procdures : une procdure reprsente une suite dinstructions utilisable autant de fois que souhait. Remarque 2 : de lanne. cette procdure 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 !

82

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 bissextiles 3 ! Il suft alors de modier la procdure 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 N j1 et N j2 qui utilisent cette procdure. 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 procdures 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 par la mthode adopte pour 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 procdures.
3. Cette modication propose par lastronome Herschell na jamais t adopte. . .

5.1. COURS

83

5.1.2

Plus complexe : 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 reine (ainsi, deux reines diffrentes doivent tre 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 !

84

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 procedure 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

85

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 procdure 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

86

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 : le MasterMind

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. 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

87

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 126 (toujours grce une macro) dont on nutilisera effectivement que la partie M m (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 :

88 #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 procdure 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 procdure 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 procdure en deux, lune pour le tirage sans remise, lautre pour le tirage avec remise. Voici une faon dimplmenter ces deux procdures :
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)); if (j!=0) { 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

89

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 :

90 rouge, vert bleu, jaune

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 procdure 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 procdures 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; }

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

91

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 ! Par exemple, si la combinaison trouver est rouge vert bleu jaune et que la proposition est rouge rouge vert vert on attend que le score calcul soit : une couleur bien place, une couleur mal place. Ainsi, on doit bien compter que le premier rouge de la proposition correspond au premier rouge de la combinaison, mais on ne doit pas dcompter le second rouge de la proposition comme couleur mal place (par rapport au premier rouge de la combinaison). De la mme faon, le vert mal plac ne doit tre dcompt quune seule 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 */

92

CHAPITRE 5. DU PROBLME AU PROGRAMME /* 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 */ 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 procdure 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 procdure renvoie un rsultat de type tableau : on passe donc le tableau (ladresse du tableau pour tre prcis) en argument la procdure. 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 procdure 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]),

5.1. COURS (i<(m-1)) ? , : \n); }

93

Note : on utilise la procdure 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 procdure 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++) { (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]); } } Pour la vrication de la cohrence par rapport aux propositions prcdentes, voici une faon de programmer la procdure : /* 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 procdures prcdentes pour obtenir le jeu. On va en fait crire une premire procdure qui dcrit une seule phase de jeu : saisie de la proposition de lutilisateur ; test de validit, afchage de laide si besoin ;

94

CHAPITRE 5. DU PROBLME AU PROGRAMME

test de cohrence, afchage de laide si besoin ; calcul et afchage du score de cette proposition. La procdure 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"); 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;

5.2. RETENIR } 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; }

95

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 */ ce commentaire ntant quune priphrase !

5.3
5.3.1

Travaux pratiques
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 ?

96

CHAPITRE 5. DU PROBLME AU PROGRAMME

Deuxime partie Annexes

97

Annexe A Le projet 2013 : modlisation dun systme masses-ressorts


A.1 Prsentation

Les systmes masses-ressorts sont un cas particulier dun outil de modlisation de phnomnes varis : les systmes de particules. Selon Wikipdia, un systme de particules est une technique graphique numrique utilise par les logiciels de 3D ou deffets vido. Elle permet de simuler de nombreux phnomnes naturels tels que feu, explosion, fume, eau, nuage, poussire, neige, feux dartices, et anims laide de proprits telles que la gravit, du vent, linertie... Une petite introduction sur ce sujet (cours de master dinformatique graphique d Nicolas Holzschuch, de luniversit Joseph Fourier Grenoble) peut tre consulte lURL suivante : http://maverick.inria.fr/ Nicolas.Holzschuch/cours/class6.ppt Le but du mini-projet est de raliser un programme en C permettant de faire voluer un systme masses-ressorts simple, en implmentant une visualisation graphique anime du systme.

A.2

Le travail demand

On demande de raliser plusieurs versions du programme : chaque version permet damliorer le programme prcdent par de nouvelles fonctionnalits. Cette technique de dveloppement permet de valider chaque tape le fonctionnement du programme avant de sattaquer une complexit plus importante. Attention : il est inutile dans ce cas dessayer de programme la version N + 1 si la version N ne fonctionne pas.

A.2.1

Version initiale

La premire version du programme consiste animer le systme suivant : 4 masses notes A, B, C et D, de masses identiques ; 99

100ANNEXE A. LE PROJET 2013 : MODLISATION DUN SYSTME MASSES-RESSORTS 4 ressorts identiques (mme longueur vide, mme raideur), ralisant les liaisons A-B, B-C, C-D, D-A (les 4 masses sont donc relies en anneau ) ; un ressort ralisant la liaison A-C ( diagonale ), de mme raideur que les 4 prcdents, mais dont la longueur vide est 2 fois celle des prcdents ; les seules forces prises en compte sont les forces exerces par les ressorts, que lon considre parfaits (force exerce proportionnelle lcart de longueur par rapport la longueur vide du ressort, le coefcient de proportionnalit tant la raideur) ; Si lon note l0 la longueur vide des 4 ressorts identiques, les 4 masses ont initialement une vitesse nulle et ont pour positions : xA = l0 yA = 0 xB = 0 yB = l0 xC = l0 yC = 0 xD = 0 yD = l0

Dans cette premire version, il est autoris de coder en dur tous les paramtres, le but tant de mettre au point dalgorithme de simulation. Il pourra toutefois tre intressant dessayer des valeurs diffrentes pour la masse et la raideur et dobserver le comportement visuel du systme (question subsidiaire : est-il possible de prvoir lintuition ce comportement ?).

A.2.2

Version amliore : vibration dune grille

On souhaite maintenant pouvoir simuler un systme avec un nombre quelconque (mais non variable au cours du programme) de masses et de ressorts. Il faut donc bien rchir : la faon de reprsenter les donnes des masses (masse, position, vitesse), et celles des ressorts (longueur vide, raideur, masses relies) ; lalgorithme de simulation, qui devra tre adapt ce nouveau cas dutilisation. Pour valider cette nouvelle version, il pourra tre utile de la tester avec la mme conguration que dans la version initiale (si le comportement nest pas bon, pas la peine daller plus loin. . .). Ensuite, on crira une procdure permettant de construire un systme reprsentant une grille rectangulaire de largeur L et de hauteur H (deux valeurs entires) : les masses sont positionnes sur des coordonnes entires (abscisse entre 0 et N , ordonne entre 0 et H ; il y a donc (L + 1)(H + 1) masses au total) ; les ressorts sont identiques, de longueur vide gale 1 et relient les masses voisines (au sens 4-voisinage) ; La gure A.1 montre le trac dune telle grille. On crira une autre procdure permettant de dplacer chaque masse dun systme donn en paramtre dune distance choisie alatoirement uniformment entre 0 et dmax (un paramtre de la procdure), dans une direction choisie galement alatoirement et uniformment dans le plan. Enn, on crira le programme nal en : initialisant une grille (de taille choisie par le programmeur) ; appliquant cette grille la procdure de perturbation alatoire ; visualisant lvolution de ce systme.

A.2. LE TRAVAIL DEMAND

101

(7,3)

(0,0)
A.2.3

(7,0)
F IGURE A.1 Exemple de grille de taille 7x3

Version amliore : prendre dautres forces en compte

Dans cette nouvelle version, on va prendre en compte trois nouvelles types de force : la gravit ; une force (pouvant par exemple reprsenter un vent) sappliquant sur chaque masse de faon identique, dont la variation en fonction du temps et de la position est reprsente par une fonction de la forme F = F0 (1 + k cos wt) + Fturb (x, y, t) Fturb est une fonction de turbulence, variant en fonction du temps et la position de la masse (divers fonctions de turbulence seront fournies) ; des forces de rappel vers un point xe, sappliquant sur une masse unique, que lon simule par des ressorts de longueur vide nulle et de raideur trs importante. Pour cette nouvelle version du programme, on simulera lanimation dun drapeau ottant au vent : le drapeau est reprsent par une grille (voir version prcdente) ; on prend en compte gravit et force du vent ; pour reprsenter lattache du drapeau sur sa hampe, on pourra utiliser deux forces de rappel vers deux points xes : origine du repre pour la masse situe en bas gauche de la grille ; point de coordonnes (0, H ) pour la masse situe en haut gauche de la grille.

102ANNEXE A. LE PROJET 2013 : MODLISATION DUN SYSTME MASSES-RESSORTS

F IGURE A.2 Capture dcran du programme 4masses

A.2.4

Interface graphique

Pour raliser linterface graphique (un simple afchage), on utilise une bibliothque graphique trs simple permettant de crer des fentres graphiques et dy tracer des traits, des gures simples (rectangles, cercles. . .) le cas chant hachures ou colores. Cette bibliothque sappelle Vogle pour Very Ordinary Graphics Learning Environment. Cette bibliothque permet dutiliser plusieurs pilotes graphiques, celui utilis pour le systme Linux se base sur la bibliothque graphique X11. An de ne pas perdre de temps (le codage des interfaces graphiques est toujours long et dlicat, sans prsenter dintrt dun point de vue de lapprentissage de linformatique), il est fourni sur le site web du cours un petit programme dexemple, qui ralise une animation de 4 masses relies par 5 ressorts tournant autour dune ellipse. Attention : il ny a aucune modlisation physique, on se contente de tracer des cercles (masses) et des traits (ressorts) ! Ce programme sappelle 4masses.c, la gure A.2 est une capture dcran ralise pendant son excution. Les instructions particulires permettant de compiler le programme (drapeaux ajouter la ligne de commande pour la compilation) et lexcuter (variables denvironnement dnir) sont indiqus dans le code source du programme. La premire tape du projet consistera donc tlcharger le chier, le compiler, lexcuter, observer son fonctionnement, puis en comprendre le codage (lexercice de lecture de code et de comprhension de fonctionnement est un exercice essentiel pour apprendre linformatique).

A.2.5

Et sil reste encore du temps. . .

Il est assez facile dans ce type de systmes dajouter des fonctionnalits supplmentaires. Parmi celles-ci, on peut en citer deux :

A.3. INSTRUCTIONS DTAILLES POUR LA REMISE DU PROJET

103

ajouter pour les ressorts une force damortissement (de sens oppos la force de rappel et proportionnelle la vitesse relative dune masse par rapport lautre) ; cette force permet que le systme aille vers une position dquilibre en dissipant de lnergie (avec des ressorts parfaits, le systme peut osciller indniment) ; ajouter une force permettant de reprsenter la collision du systme avec une surface plane (la plus simple est un plan horizontal, permettant de simuler une chute sur le sol) ; on doit alors dtecter les masses qui entrent en collision avec la surface et on leur applique une force oriente selon la normale extrieure la surface, proportionnelle la distance de pntration (plus la masse est entre dans la surface, plus la force est importante) ;

A.3

Instructions dtailles pour la remise du projet

Les modalits de remise du mini-projet servant de premire valuation au cours de Langages et Concepts de Programmation sont dtailles ci-aprs. Certaines phases de la procdure dvaluation sont automatises, et le non-respect des instructions peut entraner le blocage de ces procdures automatiques (noubliez pas que vous tes plus de 120 lves, ce qui fait plus de 120 programmes valuer !). Tout non-respect dune instruction pourra entraner une minoration de la note attribue. Chaque lve doit raliser individuellement son projet. Les valuations ultrieures (travaux pratiques et projet) seront valus collectivement (par binme). Des programmes par trop ressemblants entre eux, ou ressemblant fortement des programmes disponibles sur Internet, pourraient irriter fortement le correcteur. . . Le travail est rendre la n de la premire partie du cours, soit : le mercredi 25 septembre 2013 18h00 au plus tard, pour le groupe B ; le mercredi 2 octobre 2013 18h00 au plus tard, pour le groupe A. La remise du programme seffectuera exclusivement par courrier lectronique, ladresse roelens@emse.fr. Ce ml devra respecter scrupuleusement les indications suivantes : le sujet (ou objet) du ml comportera la mention [ Projet ] (un crochet ouvrant suivi dune espace 1 , suivie du mot Projet suivi dune autre espace puis dun crochet fermant), suivie de vos prnom(s) et nom ; le programme source, qui devra porter le nom <initiales_nom>.c (par exemple, mroelens.c), sera joint en attachement (ou pice jointe) au message ; si vous avez plusieurs versions du programme, ils seront nomms <initiales_nom>1.c, <initiales_nom>2.c. . . vos remarques et explications concernant le(s) programme(s) envoy(s) seront consignes dans un chier attach (format texte ASCII impratif, pas de Word, PDF ou autre) dont le nom sera <initiales_nom>.txt ; indiquez en particulier ltat davancement de chaque programme envoy (termin, incomplet, bogues. . .) ; la premire ligne de chaque programme doit comporter un commentaire rappelant vos nom, prnom(s) et nom de login. Une fois extrait du message, chaque programme se verra appliquer la procdure suivante :
1. ce nest pas une faute dorthographe : en typographie, espace est du genre fminin !

104ANNEXE A. LE PROJET 2013 : MODLISATION DUN SYSTME MASSES-RESSORTS tentative de compilation avec tous les messages davertissement possibles (option -Wall de gcc) ; un message davertissement non trait provoquera une diminution de lvaluation ; un programme qui ne pourrait tre compil (aprs, le cas chant, quelques modications mineures faites par le correcteur), ne se verrait pas appliquer le reste de la procdure et donnerait une valuation infrieure 6/20 ; tentative dexcution ; un plantage ou un bouclage du programme entranera une diminution de lvaluation ; la matrialisation dun rsultat (sous une forme opportune) sera apprcie positivement ; la justesse du ou des rsultats sera apprcie encore plus positivement ; lecture attentive du code source an dvaluer la qualit de rdaction du programme (et de faon sous-jacente, la qualit de lanalyse et de la modlisation du problme) ; un programme ne comportant pas de dcoupage opportun du code en procdures bien choisies, ou un code mal prsent (peu lisible), ou encore un code sans commentaires (idoines), provoqueront une diminution de lvaluation.

Annexe B Quelques aspects du matriel


B.1 Processeur, ou unit centrale

Unit de contrle 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 procdures 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

B.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 105

106

ANNEXE B. 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 (103 secondes) Capacit : 128 Go ( 1011 octets)

B.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.. . .

B.4

Exemple de Processeur

La gure B.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 B.2 page 108 (snarfe dun cours de Stanford University) dtaille limplmentation matrielle des diffrentes fonctions dun Pentium 4. La gure B.3 page 109 reprsente un Core 2 Duo bi-processeur, avec mmoire cache de 4 Mo, introduit une dizaine dannes aprs le Pentium Pro, avec des performances plus de dix fois suprieures. La gure B.4 page 110 reprsente un processeur Atom, prsent par son fondeur, Intel, comme le plus miniaturis du monde. Grav en technologie 45nm sur hafnium, il intgre 47 millions de transistors : il est plus particulirement destin aux appareils mobiles, smartphones et ultra-portables.

B.4. EXEMPLE DE PROCESSEUR

107

F IGURE B.1 Pentium Pro (1995) : gauche, le processeur, droite, 2 caches de 512 Ko

108

ANNEXE B. QUELQUES ASPECTS DU MATRIEL

F IGURE B.2 Pentium 4

B.4. EXEMPLE DE PROCESSEUR

109

F IGURE B.3 Intel Core 2 Duo (2006) : processeur avec mmoire cache de 4 Mo

110

ANNEXE B. QUELQUES ASPECTS DU MATRIEL

F IGURE B.4 Atom

Annexe C 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.

C.1

Lenvironnement de base

Rappel : le matriel utilis est le parc de micro-ordinateurs du 4etage, utilisant au choix le systme dexploitation Microsoft Windows XP 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 .

C.2

Utilisation sous Windows

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

112

ANNEXE C. ENVIRONNEMENT DE DVELOPPEMENT

F IGURE C.1 Commande DOS

C.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 C.1 montre une telle fentre. Il est possible galement dutiliser une fentre bash (cf. gure C.2 page suivante), dont linterprteur utilise une syntaxe lgrement diffrente de celle de linterprteur 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 ?

C.2. UTILISATION SOUS WINDOWS

113

F IGURE C.2 Fentre bash sous DOS Note : DJGPP fournit un autre interprteur, nomm bash, driv du Bourne shell connu sur les stations Unix. Cest un interprteur 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 :

114

ANNEXE C. ENVIRONNEMENT DE DVELOPPEMENT

F IGURE C.3 Le notepad Windows et sa fentre de slection de chier

C.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 (cf. gure C.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.

C.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) ;

C.2. UTILISATION SOUS WINDOWS

115

lditeur de liens (ajoute au code objet les routines de dmarrage et darrt ainsi que les procdures pr compiles ncessaires). C.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 C.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.

116

ANNEXE C. ENVIRONNEMENT DE DVELOPPEMENT

C.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 procdures, etc. Lorsque le compilateur utilis est gcc, loutil de mise au point utiliser est gdb. C.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). C.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. C.2.4.3 Mise au point sous Linux

Le dbogueur de choix sous Linux est gdb. C.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

C.2. UTILISATION SOUS WINDOWS C.2.4.5 Un premier exemple

117

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]$ 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. C.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 :

118

ANNEXE C. 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 :

C.2. UTILISATION SOUS WINDOWS (gdb) continue Continuing.

119

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 procdure 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

120

ANNEXE C. 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 . C.2.4.7 Rcapitulatif de gdb

Commandes de base Pour lancer lexcution du programme, il suft de taper la commande : (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 . C.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 procdure fonc, il suft de taper la commande :

C.2. UTILISATION SOUS WINDOWS (gdb) break fonc

121

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. C.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. C.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. C.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

122

ANNEXE C. ENVIRONNEMENT DE DVELOPPEMENT

F IGURE C.4 Fentre Xterm

C.3

Utilisation sous Linux

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

C.3.1

Fentre de commande

Les fentres de commandes se lancent par le choix dun lment dans le menu Terminaux . Les gures C.4 et C.5 page ci-contre fournissent des exemples de lapparence de tels terminaux. Le choix de linterprteur 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

C.3. UTILISATION SOUS LINUX

123

F IGURE C.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

C.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 (cf. C.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 (cf. C.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.

124

ANNEXE C. ENVIRONNEMENT DE DVELOPPEMENT

F IGURE C.6 Lditeur Gedit sous Linux

F IGURE C.7 Lditeur KWrite sous Linux

C.3. UTILISATION SOUS LINUX

125

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.

C.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 Attention : loption -o et le nom du chier excutable qui doit tre accol sont indissociables. Une criture telle que : gcc -o prog3.c prog3 va supprimer le chier source prog3.c avant dessayer de compiler le chier prog3 qui soit nexiste pas, soit contient tout autre chose quun programme source en C ; dans tous les cas, le code source est perdu ! -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.

126

ANNEXE C. ENVIRONNEMENT DE DVELOPPEMENT

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 [2] Christian Rolland. L TEX 2 , guide pratique. Addison-Wesley, France, Juin 1995.

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

127

128

BIBLIOGRAPHIE

Table des gures


1.1 1.2 1.3 1.4 1.5 2.1 2.2 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 19 21 21 22 32 37 42 44 47 52 54 69 75

PGCD de deux nombres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Calcul dun sinus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Programme PGCD (rappel) . . . . . . . . . . . . . . . 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 Exemple de grille de taille 7x3 . . . . . . . . . . . . . . . . . . . . . . . . . . 101 A.2 Capture dcran du programme 4masses . . . . . . . . . . . . . . . . . . . . 102 B.1 B.2 B.3 B.4 C.1 C.2 C.3 C.4 C.5 C.6 C.7 Pentium Pro (1995) : gauche, le processeur, droite, 2 caches de 512 Ko Pentium 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Intel Core 2 Duo (2006) : processeur avec mmoire cache de 4 Mo . . . . Atom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 108 109 110 112 113 114 122 123 124 124

129

130

TABLE DES FIGURES

Index
(void), 36 diteur de texte, 18 dition des liens, 18 gal (oprateur), 30 != (opration), 30 % (caractre), 23 % (opration modulo), 29 %f (format), 23 * (opration), 23 / (opration), 23 / (sparateur, chiers), 13 [ (tableaux), 63 \ (sparateur, chiers), 13 \n (format), 20, 21, 23 ] (tableaux), 63 { (caractre), 30 || (opration), 32 } (caractre), 30 # (caractre), 19 && (opration), 32 ++ (oprateur), 33 -Wall (option), 125 -ansi (option), 125 -g (option), 116, 125 -lm (option), 53 -o (option), 125 -pedantic (option), 125 -- (oprateur), 34 . (rpertoire), 113, 122 .c (sufxe), 18 .doc (sufxe), 14 .exe (sufxe), 14, 21 .h (sufxe), 19 .o (sufxe), 14, 18, 125 .rtf (sufxe), 14 .txt (sufxe), 14 .. (rpertoire), 113, 122 < (opration), 30 <= (opration), 30 == (opration), 30 > (opration), 30 >= (opration), 30 abs (procdure), 54 accolades, 30 acos (procdure), 52 ADA, 7 adresse mmoire, 12 affectation, 23 alatoire (tirage), 54 Algol 60, 7 algorithme, 18 algorithme dEuclide, 29 alphanumrique, 17 APL, 7 arborescence, 13 arc cosinus, 52 arc sinus, 52 arc tangente, 52 argc, 21 argv, 21 arrt dun programme, 54 ASCII, 17 asin (procdure), 52 atan (procdure), 52 atan2 (procdure), 52 atof (procdure), 54 atoi (procdure), 54 atol (procdure), 54 backslash, 13 backtrace (gdb), 120 bash, 15, 113 131

132 bloc, 30 boolen, 30 branchement, 16 break (gdb), 121 break (instruction), 84 bus, 12, 106 byte, 12, 105 C, 7 C++, 7 calculs entiers et ottants, 25 cd (commande), 113, 122 ceil (procdure), 52 Celsius, 28 chane de caractres, 18, 20 char, 12 char (dclaration), 24 cheminom, 13 code ASCII, 17 code de retour, 20 commandes cd, 113, 122 copy, 113 cp, 122 dir, 113 exit, 113, 122 gcc, 121 gdb, 121 ls, 122 man, 121 mkdir, 113, 122 mv, 123 rem, 113 rename, 113 rm, 123 compilateur, 14 compilation, 14, 18 phases, 19 compteur programme, 15 continue (gdb), 119 continue (instruction), 94 conversion (procdure), 54 copy (commande), 113 cos (procdure), 52 cosh (procdure), 52 cosinus, 52 cosinus hyperbolique, 52 cp (commande), 122 CPU, 12 dclaration, 22 dclarations char, 24 double, 17, 24, 40 extern, 49 oat, 17, 24, 40 int, 17, 24 long, 24 long double, 24, 40 long long, 24 short, 24 unsigned, 24 void, 49 dcrmentation (oprateur), 34 dise, 19 diffrent (oprateur), 30 dir (commande), 113 DJGPP, 111, 116 do (instruction), 31 double (dclaration), 17, 24, 40 e (valeur M_E), 40 else (instruction), 30 emacs, 18 entier, 105 entier pseudo-alatoire, 54 entiers, 17 Euclide (algorithme), 29 exemples Calcul dun sinus, 36 Dates, 77 Hello World, 19 MasterMind, 86 PGCD, 31, 47 Reines, 83 Somme des N premiers entiers, 33 Surface dun disque, 22 exit (commande), 113, 122

INDEX

INDEX exit (procdure), 20, 54 exp (procdure), 52 exponentielle, 52 extension, 14 extern (dclaration), 49 fabs (procdure), 36, 52 Fahrenheit, 28 faux (boolen), 30 chier, 13 extension, 14 nom sparateur, 13 nish (gdb), 121 oat (dclaration), 17, 24, 40 oor (procdure), 52 fmod (procdure), 38, 52 for (instruction), 31 Fortran, 7 gcc, 121, 125 gdb, 116, 125 backtrace, 120 break, 121 continue, 119 nish, 121 help, 121 list, 121 next, 119, 121 nexti, 121 print, 118, 121 quit, 117, 120 run, 117, 120 step, 119, 121 stepi, 121 Gedit, 18 Girardot (Jean-Jacques), 10 Gnome, 15 GNU, 111 header, 19 help (gdb), 121 identicateur, 16 if (instruction), 30 include (prprocesseur), 19 inclusion, 19 inclusions math.h, 36 stdio.h, 19 stdlib.h, 53 string.h, 69 index, 12 infrieur (oprateur), 30 infrieur ou gal (oprateur), 30 info (Linux), 121 instruction compose, 30 instructions affectation, 23, 28 break, 84 continue, 94 do, 31 for, 31 if, 30 impression, 28 return, 20, 43, 45, 49 while, 31 int (dclaration), 17, 24 KWrite, 18 labs (procdure), 54 langage machine, 14 LF, 23 line-feed, 23 Linux, 7, 15, 18, 21, 111, 116, 122 list (gdb), 121 log (procdure), 52 log10 (procdure), 52 logarithme, 52 long (dclaration), 24 long double (dclaration), 24, 40 long long (dclaration), 24 ls (commande), 122 mmoire, 105 mmoire secondaire, 105 Machine de von Neumann, 11 MacOS, 14 main (procdure), 49

133

134 man (Linux), 121 MasterMind (exemple), 86 math.h (inclusion), 36 Matlab, 7 mmoire, 12 MIPS, 105 mkdir (commande), 113, 122 modulo (opration %), 29 MS-DOS, 14 mv (commande), 123 M_E (valeur e), 40 M_PI (valeur pi), 36 next (gdb), 119, 121 nexti (gdb), 121 norme C, 125 NotePad, 18 octet, 12, 105 oprateurs ++, 33 --, 34 de comparaison, 30 logiques, 32 sizeof, 24, 66 options -Wall, 125 -ansi, 125 -g, 116, 125 -lm, 53 -o, 125 -pedantic, 125 priphriques, 12 paramtre, 48 partie entire, 52 Pascal, 7 passage la ligne, 21, 23 PATH, 21 Pentium 4, 106 Pentium Pro, 106 PGCD, 29 pi (valeur M_PI), 36 pow (procdure), 52 prprocesseur, 19 include, 19 prxe, 33 print (gdb), 118, 121 printf (procdure), 20, 23, 26 procdure, 20, 41 procdures abs, 54 acos, 52 asin, 52 atan, 52 atan2, 52 atof, 54 atoi, 54 atol, 54 ceil, 52 cos, 52 cosh, 52 exit, 20, 54 exp, 52 fabs, 36, 52 oor, 52 fmod, 38, 52 labs, 54 log, 52 log10, 52 main, 20, 49 mathmatiques, 51 pow, 52 printf, 20, 23, 26 rand, 54 sin, 52 sinh, 52 sqrt, 52 srand, 54 strcat, 69 strcmp, 69 strcpy, 69 strlen, 69 strncat, 69 strncmp, 69 strncpy, 69 tan, 52 tanh, 52

INDEX

INDEX processeur, 105 processus, 12 programmation, 18 programme, 12 programme excutable, 18 programme objet, 18 programme principal, 20 programme source, 18 programmes Calcul dun sinus, 36 Dates, 77 Hello World, 19 MasterMind, 86 PGCD, 31, 47 Reines, 83 Somme des N premiers entiers, 33 Surface dun disque, 22 prototype, 48 puissance, 52 quit (gdb), 117, 120 rpertoire, 13 rpertoire courant, 21 racine, 13 racine carre, 52 rand (procdure), 54 registre, 12, 105 rem (commande), 113 rename (commande), 113 rpertoire, 13 ressources, 14 reste, 52 reste (opration %), 29 return (instruction), 20, 43, 45, 49 rm (commande), 123 Roelens (Marc), 10 run (gdb), 117, 120 saut, 16 Scheme, 7 Scilab, 7 shell, 15 short (dclaration), 24 signed char, 12 sin (procdure), 52 sinh (procdure), 52 sinus, 36, 52 sinus hyperbolique, 52 sizeof (oprateur), 24, 66 slash, 13 sqrt (procdure), 52 srand (procdure), 54 stdio.h (inclusion), 19 stdlib.h (inclusion), 53 step (gdb), 119, 121 stepi (gdb), 121 strcat (procdure), 69 strcmp (procdure), 69 strcpy (procdure), 69 string.h (inclusion), 69 strlen (procdure), 69 strncat (procdure), 69 strncmp (procdure), 69 strncpy (procdure), 69 sufxe, 14, 33 sufxes .c, 18 .doc, 14 .exe, 14, 21 .h, 19 .o, 14, 18, 125 .rtf, 14 .txt, 14 suprieur (oprateur), 30 suprieur ou gal (oprateur), 30 tan (procdure), 52 tangente, 52 tangente hyperbolique, 52 tanh (procdure), 52 tirage alatoire, 54 traducteur, 14 unit arithmtique et logique, 105 unit centrale, 105 unit arithmtique et logique, 11 centrale, 12

135

136 contrle et traitement, 12 UNIX, 7 unsigned (dclaration), 24 unsigned char, 12 valeur, 16 valeur absolue, 36, 52, 54 valeurs entires, 17 valeurs relles, 17 variables, 16 vi, 18 void, 36 void (dclaration), 49 von Neumann, 11 vrai (boolen), 30 while (instruction), 31 Windows, 14, 15, 21, 111

INDEX

Table des matires


I Cours
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3
5 5 5 5 6 6 6 6 7 8 8 8 8 9 9 9 9 9 10 11 11 11 11 12 12 13 13 13 14 14 15

Introduction 0.1 Objectifs du cours . . . . . . . . . . . . . . . . . . . . . 0.2 Organisation du cours . . . . . . . . . . . . . . . . . . . 0.2.1 Cours et travaux pratiques . . . . . . . . . . . . 0.2.2 Projet . . . . . . . . . . . . . . . . . . . . . . . 0.2.3 Travail pratique de recherche oprationnelle . . . 0.2.4 Evaluation . . . . . . . . . . . . . . . . . . . . 0.3 Le langage C . . . . . . . . . . . . . . . . . . . . . . . 0.4 La nalit de ce cours . . . . . . . . . . . . . . . . . . . 0.5 Droulement du cours . . . . . . . . . . . . . . . . . . . 0.5.1 Sance 1 : introduction au matriel et au logiciel 0.5.2 Sances 2 et 3 : quelques problmes lmentaires 0.5.3 Sance 4 : procdures . . . . . . . . . . . . . . . 0.5.4 Sance 5 : tableaux . . . . . . . . . . . . . . . . 0.5.5 Sance 6 : du problme au programme . . . . . . 0.5.6 Sance 7 : complments . . . . . . . . . . . . . 0.5.7 Sance 8 : une application . . . . . . . . . . . . 0.6 Les supports de cours . . . . . . . . . . . . . . . . . . . 0.7 Notes techniques . . . . . . . . . . . . . . . . . . . . . 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 . . . . . . . . . 137

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

138

TABLE DES MATIRES 1.1.1.10 Fonctionnement gnral et processus dexcution du processeur . . . . . . . . . . . . . . . . . . . 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 . . . . . . . 1.1.4 Un premier programme C . . . . . . . . . . . . . . . . . . 1.1.5 Un second exemple . . . . . . . . . . . . . . . . . . . . . . 1.1.6 Types et variables en C . . . . . . . . . . . . . . . . . . . . 1.1.6.1 Types scalaires . . . . . . . . . . . . . . . . . . . 1.1.6.2 Constantes . . . . . . . . . . . . . . . . . . . . . 1.1.6.3 Arithmtique mixte (entiers et ottants) . . . . . . 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 . . . . . . . . . . . . . . . . . . . . . . . . . . . au niveau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2 1.3

15 16 17 18 18 18 19 22 24 24 25 25 25 28 28 28 28 28 29 29 29 29 30 31 32 33 34 34 35 37 39 39 39 39 39 40 40 41 41 41 41

Quelques problmes lmentaires 2.1 Cours . . . . . . . . . . . . . . . . . . . . . . . 2.1.1 Un premier problme : le calcul du PGCD 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 . . . . . . . . . . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Procdures 3.1 Cours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Retour au PGCD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2 La notion de procdure . . . . . . . . . . . . . . . . . . . . . . . . . .

TABLE DES MATIRES 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 . . . . . . . . . . . . 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 . . . . . . . . . . . 3.1.7 Paramtres de procdure de type adresse . . . . . . . 3.1.7.1 Le problme . . . . . . . . . . . . . . . . 3.1.7.2 La solution . . . . . . . . . . . . . . . . . 3.1.7.3 Autres utilisations du passage par adresse . 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.1.3 3.1.4 3.1.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

139 43 44 46 46 48 48 49 50 51 51 53 54 54 55 56 59 59 59 60 60 60 60 61 61 61 62 62 63 63 64 65 65 66 67 68 68 69 70 72 73 73 74 74

3.2 3.3

Tableaux 4.1 Cours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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 Tableaux plusieurs dimensions . . . . . . . . . . . . . . . . 4.1.4 Chanes de caractres . . . . . . . . . . . . . . . . . . . . . . 4.1.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . 4.1.4.2 Oprations sur chanes de caractres . . . . . . . . 4.1.4.3 Exemples de manipulation de chanes de caractres 4.1.5 Retour sur la procdure main . . . . . . . . . . . . . . . . . 4.1.5.1 Utilisation des arguments de la procdure main . . 4.2 retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Travaux pratiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Exercice 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

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

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

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

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

140 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.8 4.3.9 5 Exercice 2 . Exercice 3 . Exercice 4 . Exercice 5 . Exercice 6 . Exercice 7 . Exercice 8 . Exercice 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

TABLE DES MATIRES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 74 74 75 75 76 76 76 77 77 77 77 78 79 79 79 80 82 82 83 83 83 85 85 85 86 86 87 88 88 89 90 91 92 93 95 95 95

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 procdure N . . . . . . . . . . 5.1.1.3 Calcul de N4 (h, m, s) . . . . . . . . . . . . . 5.1.1.4 Calcul de N j3 (j ) . . . . . . . . . . . . . . . 5.1.1.5 Calcul de N j1 . . . . . . . . . . . . . . . . . 5.1.1.6 Calcul de N j2 . . . . . . . . . . . . . . . . . 5.1.1.7 Correction dune inexactitude . . . . . . . . . 5.1.1.8 Le bug du 19 janvier 2038 . . . . . . . . . . . 5.1.2 Plus complexe : 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 : le MasterMind . . . . . . . . 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

141

II

Annexes
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

97
99 99 99 99 100 101 102 102 103 105 105 105 106 106 111 111 111 112 114 114 115 115 116 116 116 116 116 117 117 120 120 121 121 121 122 122 123 125 127

A Le projet 2013 : modlisation dun systme masses-ressorts A.1 Prsentation . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 Le travail demand . . . . . . . . . . . . . . . . . . . . . . . A.2.1 Version initiale . . . . . . . . . . . . . . . . . . . . . A.2.2 Version amliore : vibration dune grille . . . . . . . A.2.3 Version amliore : prendre dautres forces en compte A.2.4 Interface graphique . . . . . . . . . . . . . . . . . . . A.2.5 Et sil reste encore du temps. . . . . . . . . . . . . . . . A.3 Instructions dtailles pour la remise du projet . . . . . . . . . B Quelques aspects du matriel B.1 Processeur, ou unit centrale B.2 Mmoire . . . . . . . . . . . B.3 Bus . . . . . . . . . . . . . B.4 Exemple de Processeur . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

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

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

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

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

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

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

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

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

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

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

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

142 Figures Index Table des matires

TABLE DES MATIRES 129 131 137