You are on page 1of 205

Initiation au Langage C

Alexandre Mesl e 16 juin 2009

Table des mati`res e


1 Notes de cours 1.1 Introduction . . . . . . . . . . . . . . 1.1.1 Dnitions et terminologie . . e 1.1.2 Hello World ! . . . . . . . . . 1.1.3 Structure dun programme C 1.1.4 Commentaires . . . . . . . . 1.2 Variables . . . . . . . . . . . . . . . 1.2.1 Dclaration . . . . . . . . . . e 1.2.2 Aectation . . . . . . . . . . 1.2.3 Saisie . . . . . . . . . . . . . 1.2.4 Achage . . . . . . . . . . . 1.2.5 Entiers . . . . . . . . . . . . . 1.2.6 Flottants . . . . . . . . . . . 1.2.7 Caract`res . . . . . . . . . . . e 1.2.8 Constantes . . . . . . . . . . 1.3 Oprateurs . . . . . . . . . . . . . . e 1.3.1 Gnralits . . . . . . . . . . e e e 1.3.2 Les oprateurs unaires . . . . e 1.3.3 Les oprateurs binaires . . . . e 1.3.4 Formes contractes . . . . . . e 1.3.5 Oprations htrog`nes . . . e ee e 1.3.6 Les priorits . . . . . . . . . . e 1.4 Traitements conditionnels . . . . . . 1.4.1 Si ... Alors . . . . . . . . . . . 1.4.2 Switch . . . . . . . . . . . . . 1.4.3 Boolens . . . . . . . . . . . . e 1.4.4 Les priorits . . . . . . . . . . e 1.4.5 Prprocesseur . . . . . . . . . e 1.5 Boucles . . . . . . . . . . . . . . . . 1.5.1 Dnitions et terminologie . . e 1.5.2 while . . . . . . . . . . . . . 1.5.3 do ... while . . . . . . . . 1.5.4 for . . . . . . . . . . . . . . 1.5.5 Accolades superues . . . . . 1.6 Tableaux . . . . . . . . . . . . . . . 1.6.1 Dnitions . . . . . . . . . . e 1.6.2 Dclaration . . . . . . . . . . e 1.6.3 Initialisation . . . . . . . . . 1.6.4 Acc`s aux lments . . . . . . e ee 1.6.5 Exemple . . . . . . . . . . . . 1.7 Cha nes de caract`res . . . . . . . . e 1.7.1 Exemple . . . . . . . . . . . . 1.7.2 Dnition . . . . . . . . . . . e 6 6 6 7 7 8 9 9 9 10 10 10 11 12 12 14 14 14 15 16 17 18 19 19 21 22 23 23 25 25 25 26 26 27 28 28 28 28 29 29 32 32 32

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

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

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1.7.3 Dclaration . . . . . . . . . . . . . . e 1.7.4 Initialisation . . . . . . . . . . . . . 1.7.5 Acc`s aux lments . . . . . . . . . . e ee 1.7.6 Achage . . . . . . . . . . . . . . . 1.7.7 Saisie . . . . . . . . . . . . . . . . . 1.7.8 Probl`mes lis ` la saisie buerise . e e a e 1.7.9 La biblioth`que string.h . . . . . . e 1.7.10 Exemple . . . . . . . . . . . . . . . . 1.8 Fonctions . . . . . . . . . . . . . . . . . . . 1.8.1 Les procdures . . . . . . . . . . . . e 1.8.2 Variables locales . . . . . . . . . . . 1.8.3 Passage de param`tres . . . . . . . . e 1.8.4 Les fonctions . . . . . . . . . . . . . 1.8.5 Passages de param`tre par rfrence e ee 1.9 Structures . . . . . . . . . . . . . . . . . . . 1.9.1 Dnition . . . . . . . . . . . . . . . e 1.9.2 Dclaration . . . . . . . . . . . . . . e 1.9.3 Acc`s aux champs . . . . . . . . . . e 1.9.4 Typedef . . . . . . . . . . . . . . . . 1.9.5 Tableaux de structures . . . . . . . . 1.9.6 Structures et fonctions . . . . . . . . 1.10 Pointeurs . . . . . . . . . . . . . . . . . . . 1.10.1 Introduction . . . . . . . . . . . . . 1.10.2 Tableaux . . . . . . . . . . . . . . . 1.10.3 Allocation dynamique de la mmoire e 1.10.4 Passage de param`tres par rfrence e ee 1.10.5 Pointeurs sur fonction . . . . . . . . 1.11 Fichiers . . . . . . . . . . . . . . . . . . . . 1.11.1 Dnitions . . . . . . . . . . . . . . e 1.11.2 Ouverture et fermeture . . . . . . . 1.11.3 Lecture et criture . . . . . . . . . . e 1.12 Listes Cha ees . . . . . . . . . . . . . . . . n 1.12.1 Le probl`me . . . . . . . . . . . . . . e 1.12.2 Pointeurs et structures . . . . . . . . 1.12.3 Un premier exemple . . . . . . . . . 1.12.4 Le cha nage . . . . . . . . . . . . . . 1.12.5 Utilisation de malloc . . . . . . . . . 1.12.6 Oprations . . . . . . . . . . . . . . e 1.12.7 Listes doublement cha ees . . . . . n 2 Exercices 2.1 Variables et oprateurs . . . . . . . . . . e 2.1.1 Entiers . . . . . . . . . . . . . . . 2.1.2 Flottants . . . . . . . . . . . . . 2.1.3 Caract`res . . . . . . . . . . . . . e 2.1.4 Oprations sur les bits (diciles) e 2.1.5 Morceaux choisis (diciles) . . . 2.2 Traitements conditionnels . . . . . . . . 2.2.1 Prise en main . . . . . . . . . . . 2.2.2 Switch . . . . . . . . . . . . . . . 2.2.3 Lchiquier . . . . . . . . . . . . e 2.2.4 Heures et dates . . . . . . . . . . 2.2.5 Intervalles et rectangles . . . . . 2.2.6 Prprocesseur . . . . . . . . . . . e 2.2.7 Nombres et lettres . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

32 32 33 33 33 35 35 35 37 37 39 40 42 44 45 45 45 45 46 46 47 50 50 52 55 58 60 61 61 61 62 65 65 65 68 69 71 74 74 76 76 76 76 77 77 78 79 79 79 80 80 81 81 83

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

. . . . . . . . . . . . . . 2

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Boucles . . . . . . . . . . . . . . . . . . . . . 2.3.1 Comprhension . . . . . . . . . . . . . e 2.3.2 Utilisation de toutes les boucles . . . . 2.3.3 Choix de la boucle la plus approprie e 2.3.4 Morceaux choisis . . . . . . . . . . . . 2.3.5 Extension de la calculatrice . . . . . . 2.4 Tableaux . . . . . . . . . . . . . . . . . . . . 2.4.1 Exercices de comprhension . . . . . . e 2.4.2 Prise en main . . . . . . . . . . . . . . 2.4.3 Indices . . . . . . . . . . . . . . . . . . 2.4.4 Recherche squentielle . . . . . . . . . e 2.4.5 Morceaux choisis . . . . . . . . . . . . 2.5 Cha nes de caract`res . . . . . . . . . . . . . e 2.5.1 Prise en main . . . . . . . . . . . . . . 2.5.2 Les fonctions de string.h . . . . . . . 2.5.3 Morceaux choisis . . . . . . . . . . . . 2.6 Fonctions . . . . . . . . . . . . . . . . . . . . 2.6.1 Gomtrie . . . . . . . . . . . . . . . . e e 2.6.2 Arithmtique . . . . . . . . . . . . . . e 2.6.3 Passage de tableaux en param`tre . . e 2.6.4 Dcomposition en facteurs premiers . e 2.6.5 Statistiques . . . . . . . . . . . . . . . 2.6.6 Cha nes de caract`res . . . . . . . . . e 2.6.7 Programmation dun Pendu . . . . . . 2.6.8 Tris . . . . . . . . . . . . . . . . . . . 2.7 Structures . . . . . . . . . . . . . . . . . . . . 2.7.1 Prise en main . . . . . . . . . . . . . . 2.7.2 Heures de la journe . . . . . . . . . . e 2.7.3 Rpertoire tlphonique . . . . . . . . e ee 2.8 Pointeurs . . . . . . . . . . . . . . . . . . . . 2.8.1 Aliasing . . . . . . . . . . . . . . . . . 2.8.2 Tableaux . . . . . . . . . . . . . . . . 2.8.3 Exercices sans sous-programmes . . . 2.8.4 Allocation dynamique . . . . . . . . . 2.8.5 Pointeurs et pointeurs de pointeurs . . 2.8.6 Passages de param`tres par rfrence . e ee 2.8.7 Les pointeurs sans toile . . . . . . . . e 2.8.8 Tableau de tableaux . . . . . . . . . . 2.8.9 Triangle de Pascal . . . . . . . . . . . 2.8.10 Pointeurs et rcursivit . . . . . . . . e e 2.8.11 Tri fusion . . . . . . . . . . . . . . . . 2.9 Fichiers . . . . . . . . . . . . . . . . . . . . . 2.9.1 Ouverture et fermeture . . . . . . . . 2.9.2 Lecture . . . . . . . . . . . . . . . . . 2.9.3 Ecriture . . . . . . . . . . . . . . . . . 2.9.4 Lecture et criture . . . . . . . . . . . e 2.9.5 Enigma . . . . . . . . . . . . . . . . . 2.10 Matrices . . . . . . . . . . . . . . . . . . . . . 2.11 Listes Cha ees . . . . . . . . . . . . . . . . . n 2.11.1 Pointeurs et structures . . . . . . . . . 2.11.2 Maniement du cha nage . . . . . . . . 2.11.3 Oprations sur les listes cha ees . . . e n 2.11.4 Listes doublement cha ees . . . . . . n 2.11.5 Fonctions rcursives et listes cha ees e n

2.3

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

84 84 85 85 85 86 88 88 88 89 89 89 91 91 91 92 93 93 95 96 97 98 99 99 99 101 101 101 103 104 104 104 105 105 105 106 107 108 108 108 109 112 112 112 112 112 112 117 118 118 118 120 120 121

A Quelques corrigs e A.1 Variables et oprateurs . . . . . . . . . . . . . . . . e A.1.1 Entiers . . . . . . . . . . . . . . . . . . . . . A.1.2 Flottants . . . . . . . . . . . . . . . . . . . A.1.3 Caract`res . . . . . . . . . . . . . . . . . . . e A.1.4 Oprations binaires . . . . . . . . . . . . . . e A.1.5 Morceaux choisis . . . . . . . . . . . . . . . A.2 Traitements conditionnel . . . . . . . . . . . . . . . A.2.1 Prise en Main . . . . . . . . . . . . . . . . . A.2.2 Switch . . . . . . . . . . . . . . . . . . . . . A.2.3 Heures et dates . . . . . . . . . . . . . . . . A.2.4 Echiquier . . . . . . . . . . . . . . . . . . . A.2.5 Intervalles et rectangles . . . . . . . . . . . A.2.6 Nombres et lettres . . . . . . . . . . . . . . A.3 Boucles . . . . . . . . . . . . . . . . . . . . . . . . A.3.1 Utilisation de toutes les boucles . . . . . . . A.3.2 Choix de la boucle la plus approprie . . . e A.3.3 Morceaux choisis . . . . . . . . . . . . . . . A.4 Tableaux . . . . . . . . . . . . . . . . . . . . . . . A.4.1 Prise en main . . . . . . . . . . . . . . . . . A.4.2 Indices . . . . . . . . . . . . . . . . . . . . . A.4.3 Recherche squentielle . . . . . . . . . . . . e A.4.4 Morceaux choisis . . . . . . . . . . . . . . . A.5 Cha nes de caract`res . . . . . . . . . . . . . . . . e A.5.1 Prise en main . . . . . . . . . . . . . . . . . A.5.2 Les fonctions de string.h . . . . . . . . . . A.5.3 Morceaux choisis . . . . . . . . . . . . . . . A.6 Fonctions . . . . . . . . . . . . . . . . . . . . . . . A.6.1 Gomtrie . . . . . . . . . . . . . . . . . . . e e A.6.2 Arithmtique . . . . . . . . . . . . . . . . . e A.6.3 Passage de tableaux en param`tre . . . . . e A.6.4 Dcomposition en facteurs premiers . . . . e A.6.5 Statistiques . . . . . . . . . . . . . . . . . . A.6.6 Chaines de caract`res . . . . . . . . . . . . e A.6.7 Programmation dun pendu . . . . . . . . . A.6.8 Tris . . . . . . . . . . . . . . . . . . . . . . A.7 Structures . . . . . . . . . . . . . . . . . . . . . . . A.7.1 Heures . . . . . . . . . . . . . . . . . . . . . A.7.2 Rpertoire tlphonique . . . . . . . . . . . e ee A.8 Pointeurs . . . . . . . . . . . . . . . . . . . . . . . A.8.1 Exercices sans sous-programmes . . . . . . A.8.2 Pointeurs sans toiles et triangle de Pascal . e A.8.3 Fonctions rcursives . . . . . . . . . . . . . e A.8.4 Tri fusion . . . . . . . . . . . . . . . . . . . A.9 Fichiers . . . . . . . . . . . . . . . . . . . . . . . . A.9.1 Ouverture et fermeture . . . . . . . . . . . A.9.2 Lecture . . . . . . . . . . . . . . . . . . . . A.9.3 Ecriture . . . . . . . . . . . . . . . . . . . . A.9.4 Lecture et criture . . . . . . . . . . . . . . e A.10 Listes Cha ees . . . . . . . . . . . . . . . . . . . . n A.10.1 Pointeurs et structures . . . . . . . . . . . . A.10.2 Maniement du cha nage . . . . . . . . . . . A.10.3 Listes doublement cha ees . . . . . . . . . n A.10.4 Fonctions rcursives et listes cha ees . . . e n

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

124 124 124 125 126 127 128 130 130 133 133 134 136 139 141 141 142 143 146 146 147 147 149 151 151 152 152 154 154 156 158 159 160 161 162 163 165 165 166 170 170 171 173 177 181 181 181 181 182 184 184 184 187 190

B Projets 194 B.1 Agenda (pour les PPAs) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 A Mthodologie e A.1 Le probl`me . . . . . . . . . . . . . . e A.2 Les r`gles dor . . . . . . . . . . . . . e A.2.1 Gnralits . . . . . . . . . . e e e A.2.2 Fonctions . . . . . . . . . . . A.2.3 Compilation spare . . . . . e e A.3 Dbogage . . . . . . . . . . . . . . . e A.4 Dure de vie du code . . . . . . . . . e A.4.1 Le code doit tre rutilisable e e A.4.2 Le code doit tre adaptable . e A.5 Exemple : le carnet de contacts . . . A.5.1 util.h . . . . . . . . . . . . . A.5.2 util.c . . . . . . . . . . . . . . A.5.3 tableau.h . . . . . . . . . . . A.5.4 tableau.c . . . . . . . . . . . A.5.5 eMails.c . . . . . . . . . . . . A.5.6 makele . . . . . . . . . . . . 195 195 195 195 195 196 196 196 196 197 197 197 197 198 199 201 204

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Chapitre 1

Notes de cours
1.1
1.1.1

Introduction
Dnitions et terminologie e

Un programme excutable est une suite dinstructions excute par le processeur. Ces instructions sont e e e tr`s dicile ` comprendre, si par exemple, vous ouvrez avec un diteur de texte (notepad, emacs, etc) un e a e chier excutable, vous verrez sacher un charabia incomprhensible : e e 00000000 0000001f 0000003e 0000005d 0000007c 0000009b 000000ba 000000d9 000000f8 00000117 00000136 00000155 00000174 00000193 000001b2 000001d1 000001f0 0000020f 0000022e 0000024d 0000026c 0000028b 000002aa 000002c9 000002e8 00000307 ... Il nest pas envisageable de crer des programmes en crivant des suites de chires et de lettres. Nous e e allons donc utiliser des langages de programmation pour ce faire. Un programme C est un ensemble dinstructions qui se saisit dans un chier .c ` laide dun diteur a e

(ex. : Notepad), ce type de chier sappelle une source. Les instructions qui y sont crites sappellent e du code ou encore le code source. Un compilateur est un logiciel qui lit le code source et le convertit en un code excutable, cest-`-dire un ensemble dinstructions comprhensible par le processeur. La e a e compilation dune source se fait en deux tapes : la compilation proprement dite et le linkage. On utilise e en gnral le terme compilation en englobant les deux tapes prcdemment cites. e e e e e e La compilation ` proprement parler produit un chier objet, dont lextension est .obj. a Les sources peuvent tre rparties dans plusieurs chiers, ceux-ci doivent tous tre compils sparment. e e e e e e Ensuite, le linkage des dirents chiers objets est assemblage produisant un excutable .exe. e e Certains environnement de dveloppement servent dditeur, et prennent en charge la compilation et le e e linkage (eclipse, dev-C++).

1.1.2

Hello World !

Allez sur http://www.01net.com/telecharger/windows/Programmation/langage/fiches/2327.html, cliquez sur tlcharger. Installez Dev-C++. Ouvrez un nouveau chier source. Copiez-collez le code ciee dessous dans lditeur : e #include<s t d i o . h> #include<c o n i o . h> int main ( ) { p r i n t f ( H e l l o World ! \ n ) ; getch ( ) ; return 0 ; } Sauvegardez ce chier sous le nom helloWorld.c. Dans le menu Excuter, cliquez sur Compiler. Remare quez que la compilation a produit un chier helloWorld.exe. Vous avez deux faons de lexcuter : c e double-cliquez directement sur helloWorld.exe Dans le menu Excuter, cliquez sur excuter. e e

1.1.3

Structure dun programme C

Importation des biblioth`ques e #include<s t d i o . h> #include<c o n i o . h> Selon ce que lon souhaite faire dans notre programme, on peut avoir besoin de direntes fonctions. e Celles-ci sont disponibles dans des biblioth`ques. Par exemple : e stdio.h propose des fonctions de saisie et dachage conio.h propose dautre fonctions dentres-sorties e Corps du programme int main ( ) { p r i n t f ( H e l l o world ! ) ; getch ( ) ; return 0 ; } On place dans les accolades du main les instructions que lon souhaite voir sexcuter : e int main ( ) {

<i n s t r u c t i o n s A E x e c u t e r > return 0 ; } Remarquez que chaque ligne se termine par un points-virgule. Pour acher une variable de type aphanumrique en C, on utilise printf(<valeur ` afficher>) ;. Les littraux de type alphanumriques en e a e e C scrivent entre doubles quotes. getch() ; nous sert ` suspendre lexcution du programme jusqu` ce e a e a que lutilisateur appuie sur une touche.

1.1.4

Commentaires

Un commentaire est une squence de caract`res ignore par le compilateur, on sen sert pour expliquer e e e des portions de code. Alors ayez une pense pour les pauvres programmeurs qui vont reprendre votre e code apr`s vous, le pauvre correcteur qui va essayer de comprendre votre pense profonde, ou bien plus e e simplement ` vous-mme au bout de six mois, quand vous aurez compl`tement oubli ce que vous aviez a e e e dans la tte en codant. On dlimite un commentaire par /* et */. Par exemple, e e int main ( ) { / Ceci e s t un commentaire : L i n s t r u c t i o n c i d e s s o u s a f f i c h e H e l l o morld ! Ces p h r a s e s s o n t i g n o r e s par l e c o m p i l a t e u r . e / p r i n t f ( H e l l o world ! \ n ) ; return 0 ; }

1.2

Variables

Une variable est un emplacement de la mmoire dans lequel est stocke une valeur. Chaque variable porte e e une nom et cest ce nom qui sert ` identi lemplacement de la mmoire reprsent par cette variable. a e e e e Pour utiliser une variable, la premi`re tape est la dclaration. e e e

1.2.1

Dclaration e

Dclarer une variable, cest prvenir le compilateur quun nom va tre utilis pour dsigner un emplacee e e e e ment de la mmoire. En C, on dclare les variables juste apr`s laccolade suivant main() (pour le moment). e e e On place les instructions ` excuter ` la suite de la dclaration de variables. a e a e main ( ) { <d e c l a r a t i o n de v a r i a b l e s > <i n s t r u c t i o n s a executer > } Nous ne travaillerons pour le moment que sur les variables de type numrique entier. Le type qui y e correspond, en C, est int. On dclare les variables enti`res de la mani`re suivante : e e e int <v a r 1 >, <v a r 2 >, . . . , <var n >; Cette instruction dclare les variables var 1, var 2, ..., var n de type entier. Par exemple, e #include<s t d i o . h> int main ( ) { int v a r i a b l e 1 , v a r i a b l e 2 ; int a u t r e v a r i a b l e 1 , a u t r e v a r i a b l e 2 ; return 0 ; } On appelle bloc le contenu des accolades du main.

1.2.2

Aectation

Si on souhaite aecter ` la variable v une valeur, on utilise loprateur =. Par exemple, a e int main ( ) { int v ; v = 5; return 0 ; } Ce programme dclare une variable de type entier que lon appelle v, puis lui aecte la valeur 5. Comme e vous venez de le voir, il est possible dcrire directement dans le code une valeur que lon donne ` une e a variable. Notez labscence de include, ce programme neectue aucune entre-sortie, il nest donc pas e ncessaire dimporter les biblioth`ques dentres/sorties. e e e Les oprations arihmtiques disponibles sont laddition (+), la soustraction (-), la multiplication (*), e e la division enti`re dans lensemble des entiers relatifs (quotient : /, reste : %). e int main ( ) { int v , w, z ; v = 5; w = v + 1; 9

z = v + w / 2; v = z % 3; v = v 2; return 0 ; }

1.2.3

Saisie

Traduisons en C linstruction Saisir <variable> que nous avons vu en algorithmique. Pour rcuprer e e la saisie dun utilisateur et la placer dans une variable <variable>, on utilise linstruction suivante : s c a n f ( %d , &<v a r i a b l e >); scanf suspend lexcution du programme jusqu` ce que lutilisateur ait saisi une valeur et press la e a e touche return. La valeur saisie est alors aete ` la variable <variable>. Noubliez surtout pas le &, e a sinon des choses absurdes pourraient se produire !

1.2.4

Achage

Traduisons maintenant linstruction Afficher variable en C. Cette instruction permet dacher la valeur dune variable. p r i n t f ( %d , <v a r i a b l e >); Cette instruction ache la valeur contenue dans la variable variable (ne vous laissez pas impressionner par lapparente complexit de cette instruction !). Nous avons tendu, en algorithmique, linstruction e e Afficher en intercalant des valeurs de variables entre les messages achs. Il est possible de faire de e mme en C : e p r i n t f ( l a v a l e u r de l a v a r i a b l e v e s t %d , v ) ; Cette instruction substitue ` %d la valeur de la variable v. Il est possible de ltendre ` volont : a e a e p r i n t f ( l e s v a l e u r s d e s v a r i a b l e s x , y e t z s o n t %d , %d e t %d , x , y , z ) ; Cette instruction substitue ` chaque %d les valeurs des trois variables x, y et z. Par exemple, le programme a suivant #include<s t d i o . h> int main ( ) { int a , b , c ; a = 1; b = 2; c = 3 p r i n t f ( La v a l e u r de a e s t %d , c e l l e de b e s t %d , e t c e l l e de c e s t %d . , a , b , c ) ; return 0 ; } ache La valeur de a est 1, celle de b est 2, et celle de c est 3.

1.2.5

Entiers

Trois types de base servent ` reprsenter les entiers : a e nom taille (t) nombre de valeurs (28t ) cha de format ne short 1 octet 28 valeurs %hd int 2 octets 216 valeurs %d long 4 octets 232 valeurs %ld 10

Entiers non signs e Par dfaut, les entiers permettent de stocker des valeurs de signe quelconque. Si on prxe un type entier e e par unsigned, on le restreint ` des valeurs uniquement positives. Dans ce cas, on a a nom taille (t) nombre de valeurs (28t ) valeur min valeur max format unsigned short 1 octet 28 valeurs 0 28 1 %hu 16 unsigned int 2 octets 2 valeurs 0 216 1 %u unsigned long 4 octets 232 valeurs 0 232 1 %lu La plage de valeur dun unsigned short, encode en binaire, est e {0000 0000, 0000 0001, 0000 0010, 0000 0011, . . . , 1111 1110, 1111 1111} Entiers signs e Si par contre les donnes sont signes, on a comme plage de valeurs e e nom taille (t) nombre de valeurs (28t ) plus petite valeur short 1 octet 28 valeurs 27 16 int 2 octets 2 valeurs 215 32 long 4 octets 2 valeurs 231 La plage de valeur dun short, encode en binaire, est aussi e plus grande valeur 27 1 215 1 231 1

{0000 0000, 0000 0001, 0000 0010, 0000 0011, . . . , 1111 1110, 1111 1111} Mme si les codages sont les mmes, la signication ne lest pas, les nombres entiers positifs sont cods e e e sur lintervalle : {0000 0000, 0000 0001, 0000 0010, 0000 0011, . . . , 0111 1100, 0111 1101, 0111 1110, 0111 1111} Et les nombres ngatifs sur lintervalle e {1000 0000, 1000 0001, 1000 0010, 1000 0011, . . . , 1111 1100, 1111 1101, 1111 1110, 1111 1111} Les nombres ngatifs sont disposs du plus grand jusquau plus petit, lintervalle prcdent code les e e e e valeurs : {27 , (27 1), (27 2), (27 3), . . . , 4, 3, 2, 1} Les oprations arithmtiques sont excutes assez btement, si vous calculez 0111 1111 + 0000 0001, ce e e e e e qui correspond ` (27 1) + 1, le rsultat mathmatique est 27 , ce qui se code 1000 0000, ce qui est le a e e codage de 27 . Soyez donc attentifs, en cas de dpassement de capacit dun nombre entier, vous vous e e retrouverez avec des nombres qui ne veulent rien dire. Si vous souhaitez faire des calculs sur des rels, un e type ottant sera davantage adapt. e

1.2.6

Flottants

Les ottants servent ` reprsenter les rels. Leur nom vient du fait quon les reprsente de faon sciena e e e c tique : un nombre dcimal (` virgule) muni dun exposant (un dcalage de la virgule). Trois types de e a e base servent ` reprsenter les ottants : a e nom taille cha de format ne float 4 octet %f double 8 octets %f long double 10 octets %Lf Il est conventionel dcrire des littraux ottants avec un point, par exemple lapproximation ` 102 pr`s e e a e de secrit 3.14. Il est aussi possible dutiliser la notation scientique, par exemple le dcimal 1 000 e scrit 1e3, ` savoir 1.103 .Nous nous limiterons ` la description du type float, les autres types obissent e a a e a ` des r`gles similaires. e 11

Reprsentation en mmoire dun float e e Le codage dun nombre de type float (32 bits) est dcoup en trois parties : e e partie taille le bit de signe 1 bit lexposant 8 bits la mantisse 23 bits Le nombre est positif si le bit de signe est ` 0, ngatif si le bit de signe est ` 1. La mantisse et lexposant a e a m sont cods en binaire, la valeur absolue dun ottant de mantisse m et dexposant e est 23 .2e . Le plus e 2 (223 1) grand entier quil est possible de coder sur 23 octets est , le plus grand exposant est 27 , donc 223 (223 1) (27 ) (223 1) (27 ) le plus grand ottant est .2 , donc le plus petit est .2 . 23 2 223

1.2.7

Caract`res e

Un char sert ` reprsenter le code ASCII dun caract`re, il est donc cod sur 1 octet. Il est possible a e e e daecter ` une telle variable toute valeur du code ASCII entoure de simples quotes. Par exemple, a e laectation suivante place dans a le code ASCII du caract`re B. e char a ; a = B ; De la mme faon que lon code des nombres entiers sur 1 octet avec un short, un char contient avant e c tout un nombre cod sur 1 octet. Pour acher le caract`re corrspondant au code ASCII stock dans un e e e char, on utilise la cha de format %c, et pour acher le code ASCII lui-mme on utilise la cha de ne e ne format %d. Si on souhaite manipuler des char comme des nombres, le type unsigned char permet de coder des valeurs positives sur 1 octet, alors que char code aussi bien des nombres positifs que ngatifs. e Par consquent, les caract`res de code ASCII 255 et 128 correspondent aux unsigned char de valeurs e e 255 et 128 et aux char de valeurs 1 et 128.

1.2.8

Constantes

Une constante est une valeur portant un nom, contrairement aux variables, elles ne sont pas modiables. Les constantes en C sont non types, on les dnit dans lentte de la source, juste en dessous des #include. e e e La syntaxe est #define <NOM CONSTANTE> <valeurConstante>, par exemple #define N 25 dnit une e constante N qui a la valeur 25. Au dbut de la compilation, un programme appel prprocesseur e e e eectue un rechercher/remplacer et substitue ` toutes les occurences de <NOM CONSTANTE> la valeur a <valeurConstante>. Faites donc tr`s attention au fait que dans lexemple prsent, le prprocesseur e e e va remplacer tous les N par des 25. Donc si une variable sappelle N , le prprocesseur va le remplacer e par un 25 ! Si par exemple vous crivez e #include<s t d i o . h> #define N 25 int main ( ) { int N; N = 12; p r i n t f ( N = %d , N ) ; return 0 ; } Le prprocesseur va le transformer en e #include<s t d i o . h>

12

#define N 25 int main ( ) { int 2 5 ; 25 = 1 2 ; p r i n t f ( N = %d , 2 5 ) ; return 0 ; } Vous remarquez que les seules exceptions sont les valeurs dlimites par des ". e e

13

1.3
1.3.1

Oprateurs e
Gnralits e e e

Oprandes et arit e e Lorsque vous eectuez une opration, par exemple 3 + 4, le + est un oprateur, 3 et 4 sont des oprandes. e e e Si loprateur sapplique ` 2 oprandes, on dit quil sagit dun oprateur binaire, ou bien darit 2. Un e a e e e oprateur darit 1, dit aussi unaire, sapplique ` un seul oprande, par exemple -x, le x est loprande e e a e e et le - unaire est loprateur qui, appliqu ` x, nous donne loppos de celui-ci, cest-`-dire le nombre e e a e a quil faut additionner ` x pour obtenir 0. Il ne faut pas le confondre avec le - binaire, qui appliqu ` x et a ea y, additionne ` x loppos de y. a e En C, les oprateurs sont unaires ou binaires, et il existe un seul oprateur ternaire. e e Associativit e Si vous crivez une expression de la forme a + b + c, o` a, b et c sont des variables enti`res, vous e u e appliquez deux fois loprateur binaire + pour calculer la somme de 3 nombres a, b et c. Dans quel ordre e ces oprations sont-elles eectues ? Est-ce que lon a (a + b) + c ou a + (b + c) ? Cela importe peu, e e car le + entier est associatif, ce qui signie quil est possible de modier le parenth`sage dune somme e dentiers sans en changer le rsultat. Attention : lassociativit est une raret ! Peu doprateurs sont e e e e associatifs, une bonne connaissance des r`gles sur les priorits et le parenth`sage par dfaut est donc e e e e requise. Formes prxes, postxes, inxes e Un oprateur unaire est prxe sil se place avant son oprande, postxe sil se place apr`s. Un oprateur e e e e e binaire est inxe sil se place entre ses deux oprandes (a + b), prxe sil se place avant (+ a b), e e postxe sil se place apr`s (a b +). Vous rencontrez en C des oprateurs unaires prxes et dautres e e e postxes (on imagine dicilement un oprateur unaire inxe), par contre tous les oprateurs binaires e e seront inxe. Priorits e Les r`gles des priorits en C sont nombreuses et complexes, nous ne ferons ici que les esquisser. Nous e e appelerons parenth`sage implicite le parenth`sage adopt par dfaut par le C, cest ` dire lordre e e e e a dans lequel il eectue les oprations. La premi`re r`gle ` retenir est quun oprateur unaire est toujours e e e a e prioritaire sur un oprateur binaire. e

1.3.2

Les oprateurs unaires e

Ngation arithmtique e e La ngation arithmtique est loprateur - qui ` une oprande x, associe loppos de x, cest-`-dire le e e e a e e a nombre quil faut additionner ` x pour obtenir 0. a Ngation binaire e La ngation binaire ~ agit directement sur les bits de son oprande, tous les bits ` 0 deviennent 1, et e e a vice-versa. Par exemple, ~127 (tous les bits ` 1 sauf le premier) est gal ` 128 (le premier bit ` 1 et tous a e a a les autres ` 0). a Priorits e Tous les oprateurs unaires sont de priorit quivalente, le parenth`sage implicite est fait le plus ` droite e ee e a possible, on dit que ces oprateurs sont associatifs ` droite. Par exemple, le parenth`sage implicite de e a e lexpression ~-~i est ~(-(~i)). Cest plutt logique : si vous parvenez ` placer les parenth`ses direment, o a e e prevenez-moi parce que je ne vois pas comment faire... 14

1.3.3

Les oprateurs binaires e

Oprations de dcalages de bits e e Lopration a >> 1 eectue un dcalage des bits de la reprsentation binaire de a vers la droite. Tous les e e e bits sont dcals dun cran vers la droite, le dernier bit dispara le premier prend la valeur 0. Lopration e e t, e a << 1 eectue un dcalage des bits de la reprsentation binaire de a vers la gauche. Tous les bits sont e e dcals dun cran vers la gauche, le premier bit dispara et le dernier devient 0. Par exemple, 32 << 2 e e t associe ` 0010 0000 << 2 la valeur dont la reprsentation binaire 1000 0000 et 32 >> 3 associe ` 0010 a e a 0000 >> 3 la valeur dont la reprsentation binaire 0000 0100. e Oprations logiques sur la reprsentation binaire e e Loprateur & associe ` deux oprandes le ET logique de leurs reprsentations binaires par exemple e a e e 60 & 15 donne 12, autrement formul 0011 1100 ET 0000 1111 = 0000 1100. Loprateur | associe ` e e a deux oprandes le OU logique de leurs reprsentations binaires par exemple 60 | 15 donne 63, autrement e e formul 0011 1100 OU 0000 1111 = 0011 1111. Loprateur ^ associe ` deux oprandes le OU exclusif e e a e logique de leurs reprsentations binaires par exemple 60 ^ 15 donne 51, autrement formul 0011 1100 e e OU EXCLUSIF 0000 1111 = 0011 0011. Deux ^ successifs sannulent, en dautres termes a^b^b=a. Aectation Ne vous en dplaise, le = est bien un oprateur binaire. Celui-ci aecte ` loprande de gauche (appele e e a e e Lvalue par le compilateur), qui doit tre une variable, une valeur calcule ` laide dune expression, qui e e a est loprande de droite. Attention, il est possible deectuer une aectation pendant lvaluation dune e e expression. Par exemple, a = b + (c = 3); Cette expression aecte ` c la valeur 3, puis aecte ` a la valeur b + c. a a Priorits e Tous les oprateurs binaires ne sont pas de priorits quivalentes. Ceux de priorit la plus forte sont les e e e e oprateurs arithmtiques (*, /, %, +, -), puis les oprateus de dcalage de bit (<<, >>), les oprateurs de bit e e e e e (&, ^, |), et enn laectation =. Reprsentons dans une tableau les oprateurs en fonction de leur priorit, e e e plaons les plus prioritaire en haut et les moins prioritaires en bas. Parmi les oprateurs arithmtiques, c e e les multiplications et divisions sont prioritaires sur les sommes et dirence : e noms oprateurs e produit *, /, % sommes +, Les deux oprateurs de dcalage sont de priorit quivalente : e e ee noms oprateurs e dcalage binaire >>, << e Loprateur & est assimil ` un produit, | ` une somme. Donc , & est prioritaire sur |. Comme ^ se trouve e ea a entre les deux, on a noms oprateurs e ET binaire & OU Exlusif binaire ^ OU binaire | Il ne nous reste plus qu` assembler les tableaux : a

15

noms oprateurs e produit *, /, % somme +, dcalage binaire e >>, << ET binaire & OU Exlusif binaire ^ OU binaire | aectation = Quand deux oprateurs sont de mme priorit le parenth`sage implicite est fait le plus ` gauche pose e e e a sible, on dit que ces oprateurs sont associatifs ` gauche. Par exemple, le parenth`sage implicite de e a e lexpression a - b - c est (a b) c et certainement pas a - (b - c). Ayez donc cela en tte lorsque vous manipulez des oprateurs non e e associatifs ! La seule exception est le =, qui est associatif ` droite. Par exemple, a a = b = c; se dcompose en b = c suivi de a = b. e

1.3.4

Formes contractes e

Le C tant un langage de paresseux, tout ` t fait pour que les programmeurs aient le moins de caract`res e ae e e possible ` saisir. Je vous prviens : jai plac ce chapitre pour que soyez capable de dcrypter la bouillie a e e e que pondent certains programmeurs, pas pour que vous les imitiez ! Alors vous allez me faire le plaisir de faire usage des formes contractes avec parcimonie, noubliez pas quil est tr`s important que votre code e e soit lisible. Unaires Il est possible dincrmenter (augmenter de 1) la valeur dune variable i en crivant i++, ou bien ++i. e e De la mme faon on peut dcrmenter (diminuer de 1) i en crivant i-- (forme postxe), ou bien --i e c e e e (forme prxe). Vous pouvez dcider dincrmenter (ou de dcrmenter) la valeur dune variable pendant e e e e e un calcul, par exemple, a = 1; b = ( a++) + a ; value successivement les deux oprandes a++ et a, puis aecte leur somme ` b. Loprande a++ est e e a e value ` 1, puis est incrmente, donc lorsque la deuxi`me oprande a est value, sa valeur est 2. Donc e e a e e e e e e la valeur de b apr`s lincrmentation est 3. Lincrmentation contracte sous forme postxe sappelle une e e e e post-incrmentation. Si lon crit, e e a = 1; b = (++a ) + a ; On op`re une pr-incrmentation, ++a donne lieu ` une incrmentation avant lvaluation de a, donc e e e a e e la valeur 4 est aecte ` b. On peut de faon analogue eectuer une pr-decrmentation ou a poste a c e e decrmentation. Soyez tr`s attentifs au fait que ce code nest pas portable, il existe des compilateurs e e qui valuent les oprandes dans le dsordre ou di`rent les incrmentations, donnant ainsi des rsultats e e e e e e autres que les rsultats thoriques exposs prcdement. Vous nutiliserez donc les incrmentation et e e e e e e decrmentation contractes que lorsque vous serez certain que lordre dvaluation des oprandes ne e e e e pourra pas inuer sur le rsultat. e Binaires Toutes les aectations de la forme variable = variable operateurBinaire expression peuvent tre e contractes sous la forme variable operateurBinaire= expression. Par exemple, e

16

avant apr`s e a = a + b a += a = a - b a -= a = a * b a *= a = a / b a /= a = a % b a %= a = a & b a &= a = a ^ b a ^= a = a | b a |= Vous vous douterez que

b b b b b b b b lgalit ne peut pas tre contracte... e e e e

1.3.5

Oprations htrog`nes e e e e

Le fonctionnement par dfaut e Nous ordonnons de faon grossi`re les types de la faon suivante : long double > double > float > c e c unsigned long > long > unsigned int > int > unsigned short > short > char. Dans un calcul o` les oprandes sont de types htrog`nes, loprande dont le type T est de niveau le plus lv u e ee e e ee e (conformment ` lordre nonc ci-avant) est slectionn et lautre est converti dans le type T . e a e e e e Le probl`me e Il se peut cependant que dans un calcul, cela ne convienne pas. Si par exemple, vous souhaitez calculer 1 linverse dun nombre entier x, et que vous codez x int i = 4 ; p r i n t f ( L i n v e r s e de %d e s t %d , i , 1/ i ) ; Vous constaterez que rsultat est inintressant au possible. En eet, comme i et 1 sont tout deux de type e e entier, cest la division enti`re est eectue, et de toute vidence le rsultat est 0. Changer la cha de e e e e ne format int i = 4 ; p r i n t f ( L i n v e r s e de %d e s t %f \n , i , 1/ i ) ; se rv`lera aussi dune inecacit notoire : non seulement vous vous taperez un warning, mais en plus e e e printf lira un entier en croyant que cest un ottant. Alors comment on se sort de l` ? Ici la bidouille a est simple, il sut dcrire le 1 avec un point : e int i = 4 ; p r i n t f ( L i n v e r s e de %d e s t %f \n , i , 1 . / i ) ; Le compilateur, voyant un oprande de type ottant, convertit lors du calcul lautre oprande, i, en e e ottant. De ce fait, cest une division ottante et non enti`re qui est eectue. Allons plus loin : comment e e faire pour appliquer une division ottante ` deux entiers ? Par exemple : a int i = 4 , j= 5 ; p r i n t f ( Le q u o t i e n t de %d e t %d e s t %f \n , i , j , i / j ) ; Cette fois-ci cest inextricable, vous pouvez placer des points o` vous voudrez, vous narriverez pas ` u a vous dbarasser du warning et ce programme persistera ` vous dire que ce quotient est -0.000000 ! Une e a solution particuli`rement crade serait de recopier i et j dans des variables ottantes avant de faire la e division, une autre mthode de bourrin est de calculer (i + 0.)/j. Mais jesp`re que vous ralisez que e e e seuls les boeufs proc`dent de la sorte. e Le cast Le seul moyen de vous sortir de l` est deectuer un cast, cest ` dire une conversion de type sur coma a mande. On caste en plaant entre parenth`se le type dans lequel on veut convertir juste avant loprande c e e que lon veut convertir. Par exemple, 17

int i = 4 , j= 5 ; p r i n t f ( Le q u o t i e n t de %d e t %d e s t %f \n , i , j , ( f l o a t ) i / j ) ; Et l`, a fonctionne. La variable valeur contenue dans i est convertie en float et de ce fait, lautre a c oprande, j, est aussi convertie en float. La division est donc une division ottante. Notez bien que le e cast est un oprateur unaire, donc prioritaire sur la division qui est un oprateur binaire, cest pour a e e c que la conversion de i a lieu avant la division. Mais si jamais il vous vient lide saugrenue dcrire e e int i = 4 , j= 5 ; p r i n t f ( Le q u o t i e n t de %d e t %d e s t %f \n , i , j , ( f l o a t ) ( i / j ) ) ; Vous constaterez tr`s rapidement que cest une alternative peu intelligente. En eet, le rsulat est ottant, e e mais comme la division a lieu avant toute conversion, cest le rsultat dune division enti`re qui est converti e e en ottant, vous avez donc le mme rsultat que si vous naviez pas du tout cast. e e e

1.3.6

Les priorits e

Ajoutons le cast au tableau des priorits de nos oprateurs : e e noms oprateurs e oprateurs unaires cast, -, ~, ++, -e produit *, /, % somme +, dcalage binaire e >>, << ET binaire & OU Exlusif binaire ^ OU binaire | aectation =

18

1.4

Traitements conditionnels

On appelle traitement conditionnel un portion de code qui nest pas excute systmatiquement, cest ` e e e a dire des instructions dont lexcution est conditionne par le succ`s dun test. e e e

1.4.1

Si ... Alors

Principe En algorithmique un traitement conditionnel se rdige de la sorte : e si condition alors instructions n Si la condition est vrie, alors les instructions sont excutes, sinon, elles ne sont pas excutes. e e e e e e Lexcution de lalgorithme se poursuit alors en ignorant les instructions se trouvant entre le alors e et le finSi. Un traitement conditionnel se code de la sorte : i f (< c o n d i t i o n >) { <i n s t r u c t i o n s > } Notez bien quil ny a pas de point-virgule apr`s la parenth`se du if. e e Comparaisons La formulation dune condition se fait souvent ` laide des oprateurs de comparaison. Les oprateurs de a e e comparaison disponibles sont : == : galit e e != : non-galit e e <, <= : infrieur `, respectivement strict et large e a >, >= : suprieur `, respectivement strict et large e a Par exemple, la condition a == b est vrie si et seulement si a et b ont la mme valeur au moment o` e e e u le test est valu. Par exemple, e e #include<s t d i o . h> int main ( ) { int i ; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %d , &i ) ; i f ( i == 0 ) { p r i n t f ( Vous avez s a i s i une v a l e u r n u l l e \n . ) ; } p r i n t f ( Adios ! ) ; return 0 ; } Si au moment o` le test i == 0 est valu, la valeur de i est bien 0, alors le test sera vri et linstruction u e e e e printf("Vous avez saisi une valeur nulle\n.") sera bien excute. Si le test nest pas vri, les e e e e instructions du bloc ... suivant le if sont ignores. e

19

Si ... Alors ... Sinon Il existe une forme tendue de traitement conditionnel, on la note en algorithmique de la faon suivante : e c si condition alors instructions sinon autresinstructions n Les instructions dlimites par alors et sinon sont excutes si le test est vri, et les instructions e e e e e e dlimites par sinon et finSi sont excutes si le test nest pas vri. On traduit le traitement condie e e e e e tionnel tendu de la sorte : e i f (< c o n d i t i o n >) { <i n s t r u c t i o n s 1 > } else { <i n s t r u c t i o n s 2 > } Par exemple, #include<s t d i o . h> int main ( ) { int i ; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %d , &i ) ; i f ( i == 0 ) { p r i n t f ( Vous avez s a i s i une v a l e u r n u l l e \n . ) ; } else { p r i n t f ( La v a l e u r que vous s a i s i , a s a v o i r %d , n e s t pas n u l l e . \ n , i ) ; } return 0 ; } Notez la prsence de loprateur de comparaison ==. Nutilisez jamais = pour comparer deux vae e leurs !. Connecteurs logiques On formule des conditions davantage labores en utilisant des connecteurs et et ou. La condition A et e e B est vrie si les deux conditions A et B sont vries simultanment. La condition A ou B est vrie e e e e e e e si au moins une des deux conditions A et B est vrie. Le et scrit && et le ou scrit ||. Par exemple, e e e e voici un programme C qui nous donne le signe de i j sans les multiplier. #include<s t d i o . h> int main ( ) { int i , j ; 20

p r i n t f ( S a i s i s s e z deux v a l e u r s : ) ; s c a n f ( %d %d , &i , &j ) ; p r i n t f ( Le p r o d u i t de c e s deux v a l e u r s e s t ) ; i f ( ( i < 0 && j < 0 ) | | ( i >= 0 && j>= 0 ) ) { p r i n t f ( p o s i t i f \n . ) ; } else { printf ( ngatif ) ; e } p r i n t f ( . \ n ) ; return 0 ; } Accolades superues Lorsquune seule instruction dun bloc if doit tre excute, les accolades ne sont plus ncessaires. Il est e e e e possible par exemple de reformuler le programme prcdent de la sorte : e e #include<s t d i o . h> int main ( ) { int i , j ; p r i n t f ( S a i s i s s e z deux v a l e u r s : ) ; s c a n f ( %d %d , &i , &j ) ; p r i n t f ( Le p r o d u i t de c e s deux v a l e u r s e s t ) ; i f ( ( i < 0 && j < 0 ) | | ( i >= 0 && j>= 0 ) ) p r i n t f ( p o s i t i f \n . ) ; else printf ( ngatif ) ; e p r i n t f ( . \ n ) ; return 0 ; } Oprateur ternaire e En plaant linstruction suivante ` droite dune aectation, c a <v a r i a b l e > = (< c o n d i t i o n >) ? <v a l e u r > : <a u t r e v a l e u r > ; on place valeur dans variable si condition est vri, autrevaleur sinon. Par exemple, e e max = ( i >j ) ? i : j ; place la plus grande des deux valeurs i et j dans max. Plus gnralement on peut utiliser le si ternaire e e dans nimporte quel calcul, par exemple p r i n t f ( %d\n , ( i > ( l = ( j >k ) ? j : k ) ) ? i : l ) ; j = (j>k) ? j : k) place dans l la plus grande des valeurs j et k, donc (i > (l = (j > k) ? j : k)) ? i : l est la plus grande des valeurs i, j et k. La plus grande de ces trois valeurs est donc ache e par cette instruction.

1.4.2

Switch

Le switch en C scrit, avec la syntaxe suivante : e 21

switch(< nomvariable >) { case <v a l e u r 1 > : <i n s t r u c t i o n s 1 > ; break ; case <v a l e u r 2 > : <i n s t r u c t i o n s 2 > ; break ; / . . . / case <v a l e u r n > : <i n s t r u c t i o n s n > ; break ; default : / i n s t r u c t i o n s / } Noubliez surtout pas les break ! Si par exemple, nous voulons acher le nom dun mois en fonction de son numro, on crit e e switch ( numeroMois ) { case 1 : p r i n t f ( j a n v i e r ) ; break ; case 2 : p r i n t f ( f e v r i e r ) ; break ; case 3 : p r i n t f ( mars ) ; break ; case 4 : p r i n t f ( a v r i l ) ; break ; case 5 : p r i n t f ( mai ) ; break ; case 6 : p r i n t f ( j u i n ) ; break ; case 7 : p r i n t f ( j u i l l e t ) ; break ; case 8 : p r i n t f ( aout ) ; break ; case 9 : p r i n t f ( septembre ) ; break ; case 10 : p r i n t f ( o c t o b r e ) ; break ; case 11 : p r i n t f ( novembre ) ; break ; case 12 : p r i n t f ( decembre ) ; break ; default : p r i n t f ( Je c o n n a i s pas c e mois . . . ) ; }

1.4.3

Boolens e

Une variable boolenne ne peut prendre que deux valeurs : vrai et f aux. Il nexiste pas de type boolen e e a ` proprement parler en C. On utilise des int pour simuler le comportement des boolens. On reprsente e e la valeur boolenne f aux avec la valeur enti`re 0, toutes les autres valeurs enti`res servent ` reprsenter e e e a e vrai. Utilisation dans des if Lorsquune condition est value, par exemple lors dun test, cette condition prend ` ce moment la valeur e e a vrai si le test est vri, f aux dans le cas contraire. La valeur enti`re 0 reprsente la constante f aux et e e e e toutes les autres sont des constantes vrai. Observons le test suivant : i f (8) { // . . . 1 est un littral de type entier dont le valeur est non nulle, donc il reprsente le boolen vrai. De ce fait, e e e le test if (8) est toujours vri. Par contre le test if (0) nest jamais vri. e e e e La valeur vrai Mme si tout entier non nul a la valeur vrai, on prend par dfaut la valeur 1. Lorsquune condition est e e value, elle prend la valeur 1 si elle est vri, 0 dans le cas contraire. par exemple, e e e e x = (3 >2); On remarque que (3>2) est une condition. Pour dcider quelle valeur doit tre aecte ` x, cette condition e e e a est value. Comme dans lexemple ci-dessus la condition est vrie, alors elle prend la valeur 1, et cette e e e e valeur est aecte ` x. e a 22

Connecteurs logiques binaires Les connecteurs || et && peuvent sappliquer ` des valeurs (ou variables) enti`res. Observons lexemple a e suivant : x = ( 3 && 0 ) | | ( 1 ) ; Il sagit de laectation ` x de lvaluation de la condition (3 && 0) || (1). Comme 3 est vrai et 0 est a e faux, alors leur conjonction est fausse. Donc (3 && 0) a pour valeur 0. La condition 0 || 1 est ensuite value et prend la valeur vrai. Donc la valeur 1 est aecte ` x. e e e a Oprateur de ngation e e Parmi les connecteurs logiques se trouve !, dit oprateur de ngation. La ngation dune expression est e e e vraie si lexpression est fausse, fausse si lexpression est vraie. Par exemple, x = !(3==2); Comme 3 == 2 est faux, alors sa ngation !(3 == 2) est vraie. Donc la valeur 1 est aecte ` x. e e a

1.4.4

Les priorits e
des priorits en y adjoignant les connecteurs logiques et les oprateurs de e e oprateurs e cast, -, ~, !, ++, -*, /, % +, >>, << >, <, >=, <= ==, != & ^ | &&, || () ? : =, +=, -=, . . .

Compl`tons notre tableau e comparaison : noms oprateurs unaires e produit somme dcalage binaire e comparaison galit e e ET binaire OU Exlusif binaire OU binaire connecteurs logiques if ternaire aectations

1.4.5

Prprocesseur e

Macro-instructions Le C nous permet de placer ` peu pr`s nimporte quoi dans les constantes. Si par exemple, on est lass a e e dcrire des instructions de retour ` la ligne, il sut de dnir e a e #define RC p r i n t f ( \n ) Dans ce cas, toutes les occurrences de RC dans le code seront remplaces par des printf("\n"). Par e exemple #include<s t d i o . h> #define BEGIN { #define END } #define #define #define #define RC p r i n t f ( \n ) AFFICHE DEBUT p r i n t f ( Debut ) AFFICHE FIN p r i n t f ( Fin ) AFFICHE MLILIEU p r i n t f ( M i l i e u )

23

#define RETOURNE 0 return 0

int main ( ) BEGIN AFFICHE DEBUT ; RC; AFFICHE MLILIEU ; RC; AFFICHE FIN ; RC; RETOURNE 0; END ache Debut Milieu Fin Macros paramtres e e Il est possible de paramtrer les instructions du prprocesseur. Par exemple, e e #define TROIS FOIS N ( n ) ( 3 ( n ) ) va remplacer toutes les occurences de TROIS FOIS N(...) par (3 * (...)) en substituant aux points de suspension la valeur se trouvant entre les parenth`ses de la constante. Par exemple e #include<s t d i o . h> #define #define #define #define RC p r i n t f ( \n ) DECLARER INT( i ) int i AFFICHER INT( i ) p r i n t f ( %d , i ) SAISIR INT ( i ) s c a n f ( %d , &i )

int main ( ) { DECLARER INT( k ) ; p r i n t f ( S a i s i s s e z un e n t i e r : ) ; SAISIR INT ( k ) ; p r i n t f ( Vous avez s a i s i ) ; AFFICHER INT( k ) ; RC; return 0 ; } ache Saisissez un entier : 4 Vous avez saisi 4

24

1.5

Boucles

Nous souhaitons crer un programme qui nous ache tous les nombres de 1 ` 10, donc dont lexcution e a e serait la suivante : 1 2 3 4 5 6 7 8 9 10 Une faon particuli`rement vilaine de procder serait decrire 10 printf successifs, avec la lourdeur des c e e copier/coller que cela impliquerait. Nous allons tudier un moyen de coder ce type de programme avec e un peu plus dlgance. ee

1.5.1

Dnitions et terminologie e

Une boucle permet dexcuter plusieurs fois de suite une mme squence dinstructions. Cette ensemble e e e dinstructions sappelle le corps de la boucle. Chaque excution du corps dune boucle sappelle une e itration, ou plus informellement un passage dans la boucle. Lorsque lon sapprte ` excuter la e e a e premi`re itration, on dit que lon rentre dans la boucle, lorsque la derni`re itration est termine, on e e e e e dit quon sort de la boucle. Il existe trois types de boucle : while do ... while for Chacune de ces boucles a ses avantages et ses inconvnients. Nous les passerons en revue ultrieurement. e e

1.5.2

while

En C, la boucle tant que se code de la faon suivante : c while(< c o n d i t i o n >) { <i n s t r u c t i o n s > } Les instructions du corps de la boucle sont dlimites par des accolades. La condition est value avant e e e e chaque passage dans la boucle, ` chaque fois quelle est vrie, on excute les instructions de la boucle. a e e e Un fois que la condition nest plus vrie, lexcution se poursuit apr`s laccolade fermante. Achons e e e e par exemple tous les nombres de 1 ` 5 dans lordre croissant, a #include<s t d i o . h> int main ( ) { int i = 1 ; while ( i <= 5 ) { p r i n t f ( %d , i ) ; i ++; } p r i n t f ( \n ) ; return 0 ; } Ce programme initialise i ` 1 et tant que la valeur de i nxc`de pas 5, cette valeur est ache puis a e e e incrmente. Les instructions se trouvant dans le corps de la boucle sont donc excutes 5 fois de suite. La e e e e variable i sappelle un compteur, on g`re la boucle par incrmentations successives de i et on sort de la e e boucle une fois que i a atteint une certaine valeur. Linitialisation du compteur est tr`s importante ! e Si vous ninitialisez pas i explicitement, alors cette variable contiendra nimporte quelle valeur et votre programme ne se comportera pas du tout comme prvu. Notez bien par ailleurs quil ny a pas de e point-virgule apr`s le while ! e 25

1.5.3

do ... while

Voici la syntaxe de cette boucle : do { <i n s t r u c t i o n s > } while(< c o n d i t i o n >); La fonctionnement est analogue ` celui de la boucle tant que ` quelques dtails pr`s : a a e e la condition est value apr`s chaque passage dans la boucle. e e e On excute le corps de la boucle tant que la condition est vrife. e e e En C, la boucle rpter ... jusqu` est en fait une boucle rpter ... tant que, cest-`-dire une e e a e e a boucle tant que dans laquelle la condition est value ` la n. Une boucle do ... while est donc e e a excute donc au moins une fois. Reprennons lexemple prcdent avec une boucle do ... while : e e e e #include<s t d i o . h> int main ( ) { int i = 1 ; do { p r i n t f ( %d , i ) ; i ++; } while ( i <= 5 ) ; p r i n t f ( \n ) ; return 0 ; } De la mme faon que pour la boucle while, le compteur est initialis avant le premier passage dans la e c e boucle. Un des usages les plus courant de la boucle do ... while est le contrle de saisie : o #include<s t d i o . h> int main ( ) { int i ; do { p r i n t f ( S a i s i s s e z un e n t i e r p o s i t i f ou n u l : ) ; s c a n f ( %d , &i ) ; i f ( i < 0) p r i n t f ( J a i d i t p o s i t i f ou n u l ! \ n ) ; } while ( i < 0 ) ; return 0 ; }

1.5.4

for

Cette boucle est quelque peu dlicate. Commenons par donner sa syntaxe : e c f o r (< i n i t i a l i s a t i o n > ; <c o n d i t i o n > ; <pas >) { <i n s t r u c t i o n s > } 26

L<initialisation> est une instruction excute avant le premier passage dans la boucle. La <condition> e e est value avant chaque passage dans la boucle, si elle nest pas vrie, on ne passe pas dans la boucle e e e e et lexcution de la boucle pour est termine. La <pas> est une instruction excute apr`s chaque passage e e e e e dans la boucle. On peut convertir une boucle for en boucle while en procdant de la sorte : e <i n i t i a l i s a t i o n > while(< c o n d i t i o n >) { <i n s t r u c t i o n s > <pas> } On re-crit lache des 5 premiers entiers de la sorte en utilisant le fait que <initialisation> = i = e 1, <condition> = i <= 5 et <pas> = i++. On obtient : #include<s t d i o . h> int main ( ) { int i ; f o r ( i = 1 ; i <= 5 ; i ++) p r i n t f ( %d , i ) ; p r i n t f ( \n ) ; return 0 ; } On utilise une boucle for lorsque lon connait en entrant dans la boucle combien ditrations devront e tre faites. Par exemple, nutilisez pas une boucle pour pour contrler une saisie ! e o

1.5.5

Accolades superues

De la mme faon quil est possibl de supprimer des accolades autour dune instruction dun bloc if, on e c peut supprimer les accolades autour du corps dune boucle si elle ne contient quune seule instruction.

27

1.6

Tableaux

Considrons un programme dont lexcution donne : e e Saisissez dix valeurs : 1 : 4 2 : 7 3 : 34 4 : 1 5 : 88 6 : 22 7 : 74 8 : 19 9 : 3 10 : 51 Saissez une valeur 22 22 est la 6-eme valeur saisie Comment programmer cela sans utiliser 10 variables pour stocker les dix premi`res valeurs saisies ? e

1.6.1

Dnitions e

Une tableau est un regroupement de variables de mme type, il est identi par un nom. Chacune des e e variables du tableau est numrote, ce numro sappelle un indice. Chaque variable du tableau est donc e e e caractrise par le nom du tableau et son indice. e e Si par exemple, T est un tableau de 10 variables, alors chacune delles sera numrote et il sera possible e e de la retrouver en utilisant simultanment le nom du tableau et lindice de la variable. Les direntes vae e riables de T porteront des numros de 0 ` 9, et nous appellerons chacune de ces variables un lment de T . e a ee Une variable ntant pas un tableau est appele variable scalaire, un tableau par opposition ` une e e a variable scalaire est une variable non scalaire.

1.6.2

Dclaration e

Comme les variables dun tableau doivent tre de mme type, il convient de prciser ce type au moment e e e de la dlaration du tableau. De mme, on prcise lors de la dclaration du tableau le nombre de variables e e e e quil contient. La syntaxe est : <type> <nomdutableau >[< t a i l l e > ] ; Par exemple, int T [ 4 ] ; dclare un tableau T contenant 4 variables de type int. e

1.6.3

Initialisation

Il est possible dinitialiser les lments dun tableau ` la dclaration, on fait cela comme pour des variables ee a e scalaires : <type> <nom>[< t a i l l e >] = <v a l e u r d i n i t i a l i s a t i o n >; La seule chose qui change est la faon dcrire la valeur dinitialisation, on ecrit entre accolades tous c e les lments du tableau, on les dispose par ordre dindice croissant en les sparant par des virgules. La ee e syntaxe gnrale de la valeur dinitialisation est donc : e e

28

<type> <nom>[< t a i l l e >] = {< v a l e u r 0 >, <v a l e u r 1 >, . . . , <v a l e u r n 1>}; Par exemple, on cre un tableau contenant les 5 premiers nombres impairs de la sorte : e int T [ 5 ] = { 1 , 3 , 5 , 7 , 9 } ;

1.6.4

Acc`s aux lments e ee

Les lments dun tableau ` n lments sont indics de 0 ` n 1. On note T[i] llment dindice i du ee a ee e a ee tableau T. Les cinq lments du tableau de lexemple ci-avant sont donc nots T[0], T[1], T[2], T[3] et ee e T[4].

1.6.5

Exemple

Nous pouvons maintenant mettre en place le programme du dbut du cours. Il est ncessaire de stocker e e 10 valeurs de type entier, nous allons donc dclarer un tableau E de la sorte : e int E [ 1 0 ] ; La dclaration ci-dessus est celle dun tableau de 10 int appel E. Il convient ensuite deectuer les saisies e e des 10 valeurs. On peut par exemple procder de la sorte : e p r i n t f ( S a i s i s s e z d i x v a l e u r s : \n ) ; p r i n t f ( 1 ) ; s c a n f (%d , &E [ 0 ] ) ; p r i n t f ( 2 ) ; s c a n f (%d , &E [ 1 ] ) ; p r i n t f ( 3 ) ; s c a n f (%d , &E [ 2 ] ) ; p r i n t f ( 4 ) ; s c a n f (%d , &E [ 3 ] ) ; p r i n t f ( 5 ) ; s c a n f (%d , &E [ 4 ] ) ; p r i n t f ( 6 ) ; s c a n f (%d , &E [ 5 ] ) ; p r i n t f ( 7 ) ; s c a n f (%d , &E [ 6 ] ) ; p r i n t f ( 8 ) ; s c a n f (%d , &E [ 7 ] ) ; p r i n t f ( 9 ) ; s c a n f (%d , &E [ 8 ] ) ; p r i n t f ( 10 ) ; s c a n f (%d , &E [ 9 ] ) ; Les divers copier/coller necssaires pour rdiger un tel code sont dune laideur ` proscrire. Nous procderons e e a e plus lgament en faisant une boucle : ee p r i n t f ( S a i s i s s e z d i x v a l e u r s : \n ) ; f o r ( i = 0 ; i < 10 ; i ++) { p r i n t f ( %d , i +1); s c a n f ( %d , &E [ i ] ) ; } Ce type de boucle sappelle un parcours de tableau. En r`gle gnrale on utilise des boucles pour manier e e e les tableaux, celles-ci permettent deectuer un traitement sur chaque lment dun tableau. Ensuite, il ee faut saisir une valeur ` rechercher dans le tableau : a p r i n t f ( S a i s s e z une v a l e u r \n ) ; s c a n f ( %d , &t ) ; 29

Nous allons maintenant rechercher la valeur t dans le tableau E. Considrons pour ce faire la boucle e suivante : while (E [ i ] != t ) i ++; Cette boucle parcourt le tableau jusqu` trouver un lment de E qui ait la mme valeur que t. Le a ee e probl`me qui pourrait se poser est que si t ne se trouve pas dans le tableau E, alors la boucle pourrait e ne pas sarrter. Si i prend des valeurs strictement plus grandes que 9, alors il se produira ce que e lon appelle un dbordement dindice. Vous devez toujours veiller ` ce quil ne se produise pas de e a dbordement dindice ! Nous allons donc faire en sorte que la boucle sarrte si i prend des valeurs e e strictement suprieures ` 9. e a while ( i < 10 && E [ i ] != t ) i ++; Il existe donc deux faons de sortir de la boucle : c En cas de dbordement dindice, la condition i < 10 ne sera pas vrie. Une fois sorti de la boucle, e e e i aura la valeur 10. Dans le cas o` t se trouve dans le tableau ` lindice i, alors la condition E[i] != t ne sera pas u a vrie et on sortira de la boucle. Un fois sorti de la boucle, i aura comme valeur lindice de llment e e ee de E qui est gal ` t, donc une valeur comprise entre 0 et 9. e a On identie donc la faon dont on est sorti de la boucle en testant la valeur de i : c i f ( i == 1 0 ) p r i n t f ( %d ne f a i t pas p a r t i e d e s d i x v a l e u r s s a i s i e s , t ) ; else p r i n t f ( %d e s t l a %deme v a l e u r s a i s i e , t , i +1); Si (i == 10), alors nous sommes sorti de la boucle parce que llment saisi par lutilisateur ne trouve ee pas dans le tableau. Dans le cas contraire, t est la i+1-`me valeur saisie par lutilisateur. On additionne e 1 ` lindice parce que lutilisateur ne sait pas que dans le tableau les lments sont indics ` partir de 0. a ee e a Rcapitulons : e #include<s t d i o . h> #define N 10 #define SAISIR INT (num , nom) \ { \ p r i n t f ( %d : , num ) ; \ s c a n f ( %d , &(nom ) ) ; \ } int main ( ) { int E [N] , i , t ; p r i n t f ( S a i s i s s e z d i x v a l e u r s : \n ) ; f o r ( i = 0 ; i < N ; i ++) SAISIR INT ( i +1, E [ i ] ) ; p r i n t f ( S a i s s e z une v a l e u r \n ) ; s c a n f ( %d , &t ) ; i = 0; while ( i < N && E [ i ] != t ) i ++; i f ( i == N) p r i n t f ( %d ne f a i t pas p a r t i e d e s d i x v a l e u r s s a i s i e s , t ) ; else

30

p r i n t f ( %d e s t l a %deme v a l e u r s a i s i e , t , i +1); p r i n t f ( \n ) ; return 0 ; }

31

1.7
1.7.1

Cha nes de caract`res e


Exemple

Etant donn le programme dont lexcution est trace ci dessous : e e e Saisissez une phrase : Les framboises sont perchees sur le tabouret de mon grand-pere. Vous avez saisi : Les framboises sont perchees sur le tabouret de mon grand-pere. Cette phrase commence par une majuscule. Cette phrase se termine par un point. Comment faire pour saisir et manier des squences de caract`res de la sorte ? e e

1.7.2

Dnition e

Une cha de caract`res est un tableau de char contenant un caract`re nul. Le caract`re nul a 0 ne e e e pour code ASCII et scrit \0. Les valeurs signicatives de la cha de caract`res sont toutes celles e ne e places avant le caract`re nul. On remarque donc que si le caract`re nul est en premi`re position, on a e e e e une chaine de caract`res vide. e Par exemple, la phrase Toto sera code de la sorte : e T o t o 0 . . . Prenez bien note du fait que le dernier caract`re de la chaine est suivi dun caract`re nul. e e

1.7.3

Dclaration e

Comme une cha de caract`res est un tableau de char, on le dclare : ne e e char <nom chaine >[< t a i l l e c h a i n e > ] ; Par exemple, on dclare une chaine c de 200 caract`res de la sorte : e e char c [ 2 0 0 ] ; Attention ! Le nombre maximal de lettres quil sera possible de placer dans c ne sera certainement pas 200 mais 199, car il faut placer apr`s le dernier caract`re de la cha un caract`re nul ! e e ne e

1.7.4

Initialisation

On initialise une cha ` la dclaration, et seulement ` la dclaration de la sorte : ne a e a e char <nom chaine >[< t a i l l e c h a i n e >] = < v a l e u r i n i t i a l i s a t i o n >; O` la valeur dinitiallisation contient la juxtaposition de caract`res formant la cha entoure de guilleu e ne e mets (double quotes). Par exemple, char c [ 5 0 ] = Toto ; Cette instruction dclare une cha de carat`res c initialise ` "Toto". Les 5 premiers lments du tableau e ne e e a ee seront occups par les 4 caract`res de la cha ainsi que par le carat`re nul, les autres contiendront des e e ne e valeurs non signicatives. Observez bien lexemple suivant : char c [ 4 ] = Toto ; Cette dclaration engendrera un warning ` la compilation et probablement une erreur ` lexcution car e a a e laectation du caract`re nul ` la 5-`me position du tableau donnera lieu ` un dbordement dindice. e a e a e

32

1.7.5

Acc`s aux lments e ee

Du fait quune chaine de caract`re est un tableau, il est ais den isoler un lment. Ainsi c[i] est le e e ee i+1-`me lment de la cha c. On teste donc si le premier carat`re de c est une majuscule de la sorte : e ee ne e i f ( c [ 0 ] >= A && c [ 0 ] <= Z ) p r i n t f ( C e t t e p h r a s e commence par une m a j u s c u l e . \ n ) ; else p r i n t f ( C e t t e p h r a s e ne commence pas par une m a j u s c u l e . \ n ) ; Cette proprit permet aussi dacher une cha caract`re par caract`re : ee ne e e int i = 0 ; while ( c [ i ] != 0 ) p r i n t f ( %c , c [ i ++]); Notez que le corps de la boucle while est itr jusqu` ce que le caract`re nul soit rencontr. Il est donc ee a e e impratif que votre cha se termine par le caract`re nul et que le caract`re nul se trouve e ne e e dans la plage dindices du tableau. Est-ce que le code suivant est correct ? char c [ 2 6 ] ; int i ; f o r ( i = 0 ; i < 2 6 , i ++) c [ i ] = a + i ; Si la question vous est pose, vous pouvez prsumer que ce code nest pas correct. Le fait que chaque e e lment du tableau contienne un caract`re non nul ne peut que corroborer cette prsomption... Si lon ee e e souhaite placer lalphabet dans une cha ne, on proc`de de la sorte : e char c [ 2 7 ] ; int i ; f o r ( i = 0 ; i < 2 6 , i ++) c [ i ] = a + i ; c [26] = 0; Notez bien que le tableau contient 27 lments si lon compte le caract`re nul, et que celui-ci est plac ` ee e ea la n du tableau juste apr`s la boucle. e

1.7.6

Achage

Nous avons vu quil tait possible dutiliser le fait quune cha est un tableau pour lacher. Il existe e ne une mthode plus simple, en utilisant printf avec la cha de format "%s". Par contre soyez attentifs e ne au fait que si votre cha ne contient pas de caract`re nul ou que le caract`re nul se trouve en dehors de ne e e la plage dindice de votre cha ne, il faudra vous attendre aux pires horreurs ` lexcution ! Dans le code a e donn en exemple nous pouvons donc crire linstruction dachage de la cha saisie par lutilisateur : e e ne p r i n t f ( Vous avez s a i s i : \ n%s , c ) ;

1.7.7

Saisie

Cest maintenant que les choses se corsent, il faut tre tr`s attentif lors des saisies : tout dbordement e e e dindice et/ou absence de carat`re nul peut donner lieu ` des bugs tr`s diciles ` trouver ! La plus e a e a grande vigilance est donc de mise. Beaucoup damateurs utilisent des fonctions comme gets. Par exemple, #include<s t d i o . h> #define N 20 int main ( ) { 33

char c h a i n e [N ] ; int i ; p r i n t f ( S a i s i s s e z une p h r a s e : \ n ) ; gets ( chaine ) ; f o r ( i = 0 ; c h a i n e [ i ] != 0 ; i ++) p r i n t f ( c h a i n e [%d ] = %c ( code ASCII : %d ) \ n , i , c h a i n e [ i ] , c h a i n e [ i ] ) ; p r i n t f ( c h a i n e [%d ] = %c ( code ASCII : %d ) \ n , i , c h a i n e [ i ] , c h a i n e [ i ] ) ; return 0 ; } Tout dabord compilons ce programme : [klaus@Isengard chaines]$ gcc -Wall mauvaiseSaisie.c -o mauvaiseSaisie.c /home/klaus/tmp/ccyKd0hf.o: In function main: mauvaiseSaisie.c:(.text+0x24): warning: the gets function is dangerous and should not be used. La premi`re raction du compilateur est une insulte. A-t-il raison ? Testons ce programme : e e [klaus@Isengard chaines]$ ./mauvaiseSaisie Saisissez une phrase : Les framboises sont perchees sur le tabouret de mon grand pere. chaine[0] = L (code ASCII : 76) chaine[1] = e (code ASCII : 101) chaine[2] = s (code ASCII : 115) chaine[3] = (code ASCII : 32) chaine[4] = f (code ASCII : 102) chaine[5] = r (code ASCII : 114) chaine[6] = a (code ASCII : 97) chaine[7] = m (code ASCII : 109) chaine[8] = b (code ASCII : 98) chaine[9] = o (code ASCII : 111) chaine[10] = i (code ASCII : 105) chaine[11] = s (code ASCII : 115) chaine[12] = e (code ASCII : 101) chaine[13] = s (code ASCII : 115) chaine[14] = (code ASCII : 32) chaine[15] = s (code ASCII : 115) chaine[16] = o (code ASCII : 111) chaine[17] = n (code ASCII : 110) chaine[18] = t (code ASCII : 116) chaine[19] = (code ASCII : 32) chaine[20] = (code ASCII : 20) chaine[21] = (code ASCII : 0) Erreur de segmentation Que se passe-t-il ? Des horreurs ! La fonction gets est la pire des choses qui puisse arriver ` un proa gramme C ! Ne lutilisez sous aucun prtexte ! Maintenant, nous allons envisager une faon propre de e c saisir une cha de caract`re : fgets. La syntaxe est la suivante : ne e f g e t s (< c h a i n e >, < t a i l l e >, s t d i n ) ; La taille de la cha saisie est limite par <taille>, caract`re nul compris. Le rsultat est plac dans ne e e e e <chaine>. Tous les caract`res supplmentaires saisis par lutilisateur ne sont pas placs dans <chaine>, e e e seuls les (<taille> 1) premiers caract`res sont rcuprs par fgets. Nous saisirons donc la phrase de e e ee notre programme de la sorte : f g e t s ( c , 200 , s t d i n ) ;

34

1.7.8

Probl`mes lis ` la saisie buerise e e a e

Lorsque vous saisissez des caract`res avec fgets, les caract`res ignors ne sont pas limins du buer. Cela e e e e e signie quils iront parasiter la prochaine saisie. Il convient donc tout dabord de vrier sil reste des cae ract`res dans buer et de les liminer si ncessaire. Commenons par le premier point : comment sassurer e e e c que tous les caract`res saisis ont t lus ? La rponse est tr`s simple : grce au caract`re dchappement e ee e e a e e \n. La saisie est valide par le carat`re dchappement, il sagit donc toujours du dernier caract`re saisi. e e e e Le buer a donc t entir`rement lu si caract`re dchappement a t lu. Si ce caract`re a t lu, alors il ee e e e ee e ee gure juste avant le caract`re nul dans la cha On le rep`re donc de la sorte : e ne. e while ( c [ i ] != 0 ) i ++; i f ( c [ i 1] != \n ) p r i n t f ( La s a i s i e e s t i n c o m p l e t e ) ; else p r i n t f ( La s a i s i e e s t c o m p l e t e ) ; Si la cha c a t saisie correctement, aucun risque de dbordement dindice ou de bouclage inni ne ne ee e peut se prsenter. La boucle au dbut de lextrait recherche le caract`re nul dans la cha e e e ne. On sort de la boucle quand c[i] == 0, donc lindice du carat`re nul est i. Si lavant dernier caract`re de la cha e e ne, donc celui dindice (i 1) est le caract`re dchappement, alors la saisie a t compl`te et le buer est e e ee e vide. Sinon, cest que des caract`res ont t laisss dans le buer par fgets. Il convient donc, si lon e ee e souhaite eectuer dautres saisies par la suite, de vider le buer. getchar est une instruction retournant un caract`re lu dans le buer. Si le buer est vide, getchar attend une saisie de lutilisateur non valide e e par le caract`re dchappement ! On vide donc le buer de la sorte : e e while ( g e t c h a r ( ) != \n ) ; Le point-virgule ` la n de linstruction indique au compilateur que la boucle na pas de corps. Cette a boucle lit le buer jusqu` ce que le caract`re dchappement ait t lu. Pour davantage de lisibilit, on a e e ee e dnit une macro-instruction vidant le buer : e #d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) Vriez bien avant de lancer cette instruction que le buer nest pas vide, sinon le programme bouclera e jusqu` ce que lutilisateur ait saisi un caract`re dchappement. a e e

1.7.9

La biblioth`que string.h e

Cette biblioth`que propose des fonctions de maniement de cha e nes de caract`res, ` savoir : e a strcmp : comparer deux cha nes. strlen : longueur dune cha de caract`re ne e strsubs : rechercher une sous-cha ne strcat : concatner deux cha e nes strcpy : copier une cha ne Il vous est conseill dexaminer de quelle faon fonctionnent ces fonctions, et comment elles g`rent le e c e caract`re nul. e

1.7.10

Exemple

#include<s t d i o . h> #define N 10 #define CLEAR BUFFER while ( g e t c h a r ( ) != \n ) int main ( ) { char c h a i n e [N ] ; 35

int i ; p r i n t f ( S a i s i s s e z une p h r a s e : \ n ) ; f g e t s ( c h a i n e , N, s t d i n ) ; i = 0; while ( c h a i n e [ i ] != 0 ) i ++; i f ( i > 0 && c h a i n e [ i 1] != \n ) CLEAR BUFFER; else c h a i n e [ i 1] = 0 ; p r i n t f ( Vous avez s a i s i : \ n%s \n , c h a i n e ) ; i f ( c h a i n e [ 0 ] >= A && c h a i n e [ 0 ] <= Z ) p r i n t f ( C e t t e p h r a s e commence par une m a j u s c u l e . \ n ) ; else p r i n t f ( C e t t e p h r a s e ne commence pas par une m a j u s c u l e . \ n ) ; i = 0; while ( c h a i n e [ i ] != 0 && c h a i n e [ i ] != . ) i ++; i f ( c h a i n e [ i ] == . ) i f ( c h a i n e [ i +1] == 0 ) p r i n t f ( C e t t e p h r a s e s e t e r m i n e par un p o i n t . \ n ) ; else p r i n t f ( Vous avez s a i s i p l u s d une p h r a s e . \ n ) ; else p r i n t f ( C e t t e p h r a s e ne s e t e r m i n e pas par un p o i n t . \ n ) ; return 0 ; }

36

1.8
1.8.1

Fonctions
Les procdures e

Une procdure est un ensemble dinstructions portant un nom. Pour dnir une procdure, on utilise e e e la syntaxe : void nomprocedure ( ) { / instructions / } Une procdure est une nouvelle instruction, il sut pour lexcuter dutiliser son nom. Par exemple, pour e e excuter (on dit aussi appeler ou invoquer) une procdure appele pr, il sut dcrire pr();. Les deux e e e e programmes suivants font la mme chose. Le premier est crit sans procdure : e e e #include<s t d i o . h> int main ( ) { p r i n t f ( Bonjour \n ) ; return 0 ; } Et dans le deuxi`me, le printf est plac dans la procdure afficheBonjour et cette procdure est appele e e e e e depuis le main. #include<s t d i o . h> void a f f i c h e B o n j o u r ( ) { p r i n t f ( Bonjour \n ) ; } int main ( ) { afficheBonjour ( ) ; return 0 ; } Vous pouvez dnir autant de procdures que vous le voulez et vous pouvez appeler des procdures depuis e e e des procdures : e #include<s t d i o . h> void a f f i c h e B o n j o u r ( ) { p r i n t f ( Bonjour \n ) ; } void a f f i c h e U n ( ) { p r i n t f ( 1\n ) ; } void a f f i c h e D e u x ( ) { 37

p r i n t f ( 2\n ) ; } void afficheUnEtDeux ( ) { afficheUn ( ) ; afficheDeux ( ) ; } void a f f i c h e A u R e v o i r ( ) { p r i n t f ( Au r e v o i r \n ) ; } int main ( ) { afficheBonjour ( ) ; afficheUnEtDeux ( ) ; afficheAuRevoir ( ) ; return 0 ; } Ce programme ache : Bonjour 1 2 Au revoir Regardez bien le programme suivant et essayez de dterminer ce quil ache. e #include<s t d i o . h> void p r o c e d u r e 1 ( ) { p r i n t f ( debut p r o c e d u r e 1\n ) ; p r i n t f ( f i n p r o c e d u r e 1\n ) ; } void p r o c e d u r e 2 ( ) { p r i n t f ( debut p r o c e d u r e 2\n ) ; procedure1 ( ) ; p r i n t f ( f i n p r o c e d u r e 2\n ) ; } void p r o c e d u r e 3 ( ) { p r i n t f ( debut p r o c e d u r e 3\n ) ; procedure1 ( ) ; procedure2 ( ) ; p r i n t f ( f i n p r o c e d u r e 3\n ) ; } int main ( ) {

38

p r i n t f ( debut main\n ) ; procedure2 ( ) ; procedure3 ( ) ; p r i n t f ( f i n main\n ) ; return 0 ; } La rponse est e debut main debut procedure debut procedure fin procedure 1 fin procedure 2 debut procedure debut procedure fin procedure 1 debut procedure debut procedure fin procedure 1 fin procedure 2 fin procedure 3 fin main

2 1

3 1 2 1

Vous remarquez au passage que main est aussi une procdure. main est excute automatiquement au e e e lancement du programme.

1.8.2

Variables locales

Une procdure est un bloc dinstructions et est sujette aux mmes r`gles que main. Il donc possible de e e e dclarer des variables : e void nomprocedure ( ) { / d e c l a r a t i o n de v a r i a b l e s / / instructions / } Attention, ces variables ne sont accessibles que dans le corps de la procdure, cela signie quelle naissent e au moment de leur dclaration et quelles sont dtruites une fois la derni`re instruction de la procdure e e e e excute. Cest pour cela quon les apelle des variables locales. Une variable locale nest visible quentre e e sa dclaration et laccolade fermant la procdure. Par exemple, ce code est illgal : e e e #include<s t d i o . h> void maProcedure ( ) { char a = b ; }

int main ( ) {

39

char b = k ; p r i n t f ( %c , %c \n , a , b ) ; return 0 ; } En eet, la variable b est dclare dans la procdure main, et nest donc visible que dans cette mme e e e e procdure. Son utilisation dans maProcedure est donc impossible. De mme, la variable a est dclare e e e e dans maProcedure, elle nest pas visible dans le main. Voici un exemple dutilisation de variables locales : #include<s t d i o . h> void unADix ( ) { int i ; f o r ( i = 1 ; i <= 10 ; i++ ) p r i n t f ( %d\n , i ) ; }

int main ( ) { unADix ( ) ; return 0 ; }

1.8.3

Passage de param`tres e

Il est possible que la valeur dune variable locale dune procdure ne soit connue quau moment de lappel e de la procdure. Considrons le programme suivant : e e int main ( ) { int i ; p r i n t f ( V e u i l l e z s a i s i r un e n t i e r : ) ; s c a n f ( %d , &i ) ; / Appel d une p r o c e d u r e a f f i c h a n t l a v a l e u r de i . / return 0 ; } Comment dnir et invoquer une procdure afficheInt permettant dacher cet entier saisi par lutilie e sateur ? Vous conviendrez que la procdure suivante ne passera pas la compilation e void a f f i c h e I n t ( ) { p r i n t f ( %d , i ) ; } En eet, la variable i est dclare dans le main, elle nest donc pas visible dans afficheInt. Pour y e e remdier, on dnit afficheInt de la sorte : e e void a f f i c h e I n t ( int i ) { p r i n t f ( %d , i ) ; } i est alors appel un param`tre, il sagit dune variable dont la valeur sera prcise lors de lappel e e e e de la procdure. On peut aussi considrer que i est une valeur inconnue, et quelle est initialise lors e e e 40

de linvocation de la procdure. Pour initialiser la valeur dun param`tre, on place cette valeur entre e e les parenth`ses lors de lappel de la procdure, par exemple : afficheInt(4) lance lexcution de la e e e procdure afficheInt en initialisant la valeur de i ` 4. On dit aussi que lon passe en param`tre la e a e valeur 4. La version correcte de notre programme est : #include<s t d i o . h> void a f f i c h e I n t ( int i ) { p r i n t f ( %d , i ) ; } int main ( ) { int i ; p r i n t f ( V e u i l l e z s a i s i r un e n t i e r : ) ; s c a n f ( %d , &i ) ; afficheInt ( i ); p r i n t f ( \n ) ; return 0 ; } Attention, notez bien que le i de afficheInt et le i du main sont deux variables direntes, la seule e chose qui les lie vient du fait que linstruction afficheInt(i) initialise le i de afficheInt ` la valeur du a i du main. Il serait tout ` fait possible dcrire : a e #include<s t d i o . h> void a f f i c h e I n t ( int j ) { p r i n t f ( %d , j ) ; } int main ( ) { int i ; p r i n t f ( V e u i l l e z s a i s i r un e n t i e r : ) ; s c a n f ( %d , &i ) ; afficheInt ( i ); p r i n t f ( \n ) ; return 0 ; } Dans cette nouvelle version, linstruction afficheInt(i) initialise le j de afficheInt ` la valeur du i a du main. Il est possible de passer plusieurs valeurs en param`tre. Par exemple, la procdure suivante ache la e e somme des deux valeurs passes en param`tre : e e void afficheSomme ( int a , int b ) { p r i n t f ( %d , a + b ) ; } Linvocation dune telle procdure se fait en initialisant les param`tres dans le mme ordre et en sparant e e e e les valeurs par des virgules, par exemple afficheSomme(3, 4) invoque afficheSomme en initialisant a a ` 3 et b ` 4. Vous devez intialiser tous les param`tres et vous devez placer les valeurs dans lordre. a e Rcapitulons : e 41

#include<s t d i o . h> void afficheSomme ( int a , int b ) { p r i n t f ( %d , a + b ) ; } int main ( ) { int i , j ; p r i n t f ( V e u i l l e z s a i s i r deux e n t i e r s : \ na = ) ; s c a n f ( %d , &i ) ; p r i n t f ( b = ) ; s c a n f ( %d , &j ) ; p r i n t f ( a + b = ) ; afficheSomme ( i , j ) ; p r i n t f ( \n ) ; return 0 ; } La procdure ci-avant sexcute de la faon suivante : e e c Veuillez saisir deux entiers : a = 3 b = 5 a + b = 8 Lors de lappel afficheInt(r) de la procdure void afficheInt(int i), r est le param`tre eectif e e et i le param`tre formel. Notez bien que i et r sont deux variables distinctes. Par exemple, quache e le programme suivant ? #include<s t d i o . h> void i n c r ( int v ) { v++; } main ( ) { int i ; i = 6; incr ( i ); p r i n t f ( %d\n , i ) ; } La variable v est initialise ` la valeur de i, mais i et v sont deux variables direntes. Modier lune e a e naecte pas lautre.

1.8.4

Les fonctions

Le principe Nous avons vu quun sous-programme appelant peut communiquer des valeurs au sous-programme appel. e Mais est-il possible pour un sous-programme appel de communiquer une valeur au sous-programme e appelant ? La rponse est oui. Une fonction est un sous-programme qui communique une valeur au e sous-programme appelant. Cette valeur sappelle valeur de retour, ou valeur retourne. e

42

Invocation La syntaxe pour appeler une fonction est : v = nomfonction ( p a r a m e t r e s ) ; Linstruction ci-dessus place dans la variable v la valeur retourne par la fonction nomfonction quand e lui passe les param`tres parametres. Nous allons plus loin dans ce cours dnir une fonction carre qui e e retourne le carr de valeur qui lui est passe en param`tre, alors linstruction e e e v = carre (2); placera dans v le carr de 2, ` savoir 4. On dnira aussi une fonction somme qui retourne la somme de e a e ses param`tres, on placera donc la valeur 2 + 3 dans v avec linstruction e v = somme ( 2 , 3 ) ; Dnition e On dnit une fonction avec la syntaxe suivante : e typeValeurDeRetour nomFonction ( l i s t e P a r a m e t r e s ) { } La fonction carre sera donc dnie comme suit : e int c a r r e ( int i ) { / instructions / } Une fonction ressemble beaucoup ` une procdure. Vous remarquez que void est remplac par int, void a e e signie aucune type de retour, une procdure est donc une fonction qui ne retourne rien. Un int est e adapt pour reprsenter le carr dun autre int, jai donc choisi comme type de retour le type int. e e e Nous dnirons la fonction somme comme suit : e int somme ( int a , int b ) { / instructions / } Linstruction servant ` retourner une valeur est return. Cette instruction interrompt lexcution de la a e fonction et retourne la valeur place immdiatement apr`s. Par exemple, la fonction suivante retourne e e e toujours la valeur 1. int un ( ) { return 1 ; } Lorsque lon invoque cette fonction, par exemple v = un ( ) ; La valeur 1, qui est retourne par un est aecte ` v. On dnit une fonction qui retourne le successeur e e a e de son param`tre : e

43

int s u c c e s s e u r ( int i ) { return i + 1 ; } Cette fonction, si on lui passe la valeur 5 en param`tre, retourne 6. Par exemple, linstruction e v = successeur (5); aecte ` v la valeur 6. Construisons maintenant nos deux fonctions : a int c a r r e ( int i ) { return i i ; } int somme ( int a , int b ) { return a + b ; } Vous noterez quune fonction ne peut pas retourner un tableau, une fonction ne peut retourner que des valeurs scalaires. Vous comprendrez pourquoi en tudiant les pointeurs. e

1.8.5

Passages de param`tre par rfrence e ee

En C, lorsque vous invoquez une fonction, toutes les valeurs des param`tres eectifs sont recopis dans les e e param`tres formels. On dit dans ce cas que le passage de param`tre se fait par valeur. Vous ne pouvez e e donc, a priori, communiquer quune seule valeur au programme appelant. Eectivement : seule la valeur de retour vous permettra de commnuniquer une valeur au programme appelant. une fonction ne peut retourner que des valeurs scalaires. Lorsque vous passez un tableau en param`tre, la valeur qui est recopie dans le param`tre formel est e e e ladresse de ce tableau (ladresse est une valeur scalaire). Par consquent toute modication eectue e e sur les lments dun tableau dont ladresse est passe en param`tre par valeur sera repercute sur le ee e e e param`tre eectif (i.e. le tableau dorigine). Lorsque les modications faites sur un param`tre formel dans e e un sous-programme sont reprcutes sur le param`tre eectif, on a alors un passage de param`tre par e e e e rfrence. Nous retiendrons donc les trois r`gles dor suivantes : ee e Les variables scalaires se passent en param`tre par valeur e Les variables non scalaires se passent en param`tre par rfrence e ee Une fonction ne peut retourner que des valeurs scalaires

44

1.9
1.9.1

Structures
Dnition e

Nous avons utilis des tableaux pour dsigner, avec un nom unique, un ensemble de variables. Par exemple, e e un tableau T ` n lments est un ensemble n de variables dsignes par la lettre T . Dans un tableau, les a ee e e variables doivent tre de type homog`ne, cela signiant quil nest pas possible de juxtaposer des char et e e des int dans un tableau. Lorsque lon souhaite faire cohabiter dans une variable non scalaire des types htrog`nes, on utilise des structures. ee e Une structure, appel enregistrement dans dautres langages, est une variable contenant plusieurs vae riables, appeles champs. Si une structure t contient un char et un int, chacun de ces champs portera e un nom, par exemple i et c. Dans ce cas, t.c dsignera le char de t et t.i lint de t. e

1.9.2

Dclaration e

Pour crer un type structur, on utilise la syntaxe suivante : e e struct nomdutype { typechamp_1 nomchamp_1; typechamp_2 nomchamp_2; ... typechamp_n nomchamp_n; }; On prcise donc le nom de ce type structur, et entre les accolades, la liste des champs avec pour chacun e e deux son type. Vous remarquez que le nombre de champs est x davance. On nacc`de pas ` un champ e e a avec un indice mais avec un nom. Considrons par exemple le type structur suivant : e e struct p o i n t { double abs ; double ord ; }; Ce type permet de reprsenter un point dans R2 , avec respectivement uns abscisse et une ordonne. struct e e point est maintenant un type, il devient possible de dclarer un point p comme tout autre variable : e struct p o i n t p ;

1.9.3

Acc`s aux champs e

On acc`de aux champs dune variable structure ` laide de la notation pointe e e a e nomvariable.nomduchamp Ainsi, le champ ord de notre variable p sera accessible avec p.ord et le champ abs de notre variable p sera accessible avec p.abs. Voici un exemple de programme illustrant ce principe : #include<s t d i o . h> struct p o i n t { double abs ; double ord ; };

45

main ( ) { struct p o i n t p ; p . ord = 2 ; p . abs = p . ord + 1 ; p r i n t f ( p = (%f , %f ) \ n , p . abs , p . ord ) ; } Ce programme ache : p = (3.000000, 2.000000) Attention, loprateur dacc`s au champ . est prioritaire sur tous les autres oprateurs unaires, binaires e e e et ternaires ! Il faudra vous en rappeler quand on tudiera les listes cha ees. e n

1.9.4

Typedef

On se dbarasse du mot cl struct en renommant le type, on utilisera par exemple la syntaxe suivante : e e #include<s t d i o . h> typedef struct p o i n t { double abs ; double ord ; } point ;

main ( ) { point p ; p . ord = 2 ; p . abs = p . ord + 1 ; p r i n t f ( p = (%f , %f ) \ n , p . abs , p . ord ) ; } point est donc le nom de ce type structur. e

1.9.5

Tableaux de structures

Rien de nous empche de crer des tableaux de structures, par exemple : e e #include<s t d i o . h> #define N 10 typedef struct p o i n t { double abs ; double ord ; } point ;

main ( ) { p o i n t p [N ] ; int i ;

46

p [ 0 ] . ord = 0 ; p [ 0 ] . abs = 1 ; f o r ( i = 1 ; i < N ; i ++) { p [ i ] . ord = p [ i 1 ] . ord + 1 . ; p [ i ] . abs = p [ i 1 ] . abs + 2 . ; } f o r ( i = 0 ; i < N ; i ++) { p r i n t f ( p[%d ] = (%f , %f ) \ n , i , p [ i ] . abs , p [ i ] . ord ) ; } } Ce programme ache : p[0] p[1] p[2] p[3] p[4] p[5] p[6] p[7] p[8] p[9] = = = = = = = = = = (1.000000, 0.000000) (3.000000, 1.000000) (5.000000, 2.000000) (7.000000, 3.000000) (9.000000, 4.000000) (11.000000, 5.000000) (13.000000, 6.000000) (15.000000, 7.000000) (17.000000, 8.000000) (19.000000, 9.000000)

1.9.6

Structures et fonctions

Lorsquon les passe en param`tre, les structures se comportent comme des variables scalaires, cela sie gnie quon ne peut les passer en param`tre que par valeur. Par contre, un tableau de structures est e ncessairement pass en param`tre par rfrence. Recrivons le programme prcdent avec des souse e e ee e e e programmes : #include<s t d i o . h> #define N 10 typedef struct p o i n t { double abs ; double ord ; } point ; void i n i t T a b l e a u P o i n t s ( p o i n t p [ ] , int n ) { int i ; p [ 0 ] . ord = 0 ; p [ 0 ] . abs = 1 ; f o r ( i = 1 ; i < n ; i ++) { p [ i ] . ord = p [ i 1 ] . ord + 1 . ; p [ i ] . abs = p [ i 1 ] . abs + 2 . ; } } void a f f i c h e P o i n t ( p o i n t p )

47

{ p r i n t f ( (%f , %f ) , p . abs , p . ord ) ; } void a f f i c h e T a b l e a u P o i n t s ( p o i n t p [ ] , int n ) { int i ; f o r ( i = 0 ; i < n ; i ++) { p r i n t f ( p[%d ] = , i ) ; affichePoint (p [ i ] ) ; p r i n t f ( \n ) ; } } main ( ) { p o i n t p [N ] ; initTableauPoints (p , N) ; a f f i c h e T a b l e a u P o i n t s (p , N) ; } Comme une structure se comporte comme une variable scalaire, il est possible de retourner une structure dans une fonction, il est donc possible de modier le programme ci-avant de la sorte : #include<s t d i o . h> #define N 10 typedef struct p o i n t { double abs ; double ord ; } point ; point nextPoint ( point previous ) { point r e s u l t ; r e s u l t . ord = p r e v i o u s . ord + 1 . ; r e s u l t . abs = p r e v i o u s . abs + 2 . ; return r e s u l t ; } void i n i t T a b l e a u P o i n t s ( p o i n t p [ ] , int n ) { int i ; p [ 0 ] . ord = 0 ; p [ 0 ] . abs = 1 ; f o r ( i = 1 ; i < n ; i ++) p [ i ] = nextPoint (p [ i 1 ] ) ; } void a f f i c h e P o i n t ( p o i n t p ) { p r i n t f ( (%f , %f ) , p . abs , p . ord ) ; } 48

void a f f i c h e T a b l e a u P o i n t s ( p o i n t p [ ] , int n ) { int i ; f o r ( i = 0 ; i < n ; i ++) { p r i n t f ( p[%d ] = , i ) ; affichePoint (p [ i ] ) ; p r i n t f ( \n ) ; } } main ( ) { p o i n t p [N ] ; initTableauPoints (p , N) ; a f f i c h e T a b l e a u P o i n t s (p , N) ; }

49

1.10

Pointeurs

La notion de pointeur est tr`s importante en C, elle va vous permettre de comprendre le fonctionnement e dun programme, de programmer de faon davantage propre et performante, et surtout de concevoir des c programmes que vous ne pourriez pas mettre au point sans cela. Une des premi`res choses ` comprendre quand on programme, cest quune variable est un emplacee a ment de la mmoire dans lequel vous allez placer une valeur. En programmant, vous utilisez son nom e pour y lire ou crire une valeur. Mais ce qui se passe au coeur de la machine est quelque peu plus come plexe, les noms que lon donne aux variables servent ` masquer cette complexit. a e Pour le compilateur, une variable est un emplacement dans la mmoire, cet emplacement est identi e e par une adresse mmoire. Une adresse est aussi une valeur, mais cette valeur sert seulement ` spcier e a e un emplacement dans la mmoire. Lorsque vous utilisez le nom dune variable, le compilateur le remplace e par une adresse, et manipule la variable en utilisant son adresse. Ce syst`me est ouvert, dans le sens o` vous pouvez dcider dutiliser ladresse dune variable au lieu e u e dutiliser son nom. Pour ce faire, on utilise des pointeurs.

1.10.1

Introduction

Un pointeur est une variable qui contient ladresse mmoire dune autre variable. e Dclaration e T est le type dune variable contenant ladresse mmoire dune variable de type T . Si une variable p de e type T contient ladresse mmoire dune variable x de type T , on dit alors que p pointe vers x (ou bien e sur x). &x est ladresse mmoire de la variable x. Exposons cela dans un exemple, e #include<s t d i o . h> void main ( ) { int x = 3 ; int p ; p = &x ; } x est de type int. p est de type int, cest ` dire de type pointeur de int, p est donc faite pour contenir a ladresse mmoire dun int. &x est ladresse mmoire de la variable x, et laectation p = &x place e e ladresse mmoire de x dans le pointeur p. A partir de cette aectation, p pointe sur x. e Achage La cha de format dune adresse mmoire est %X. On ache donc une adresse mmoire (tr`s utile ne e e e pour dbugger :-) comme dans lexemple ci-dessous, e #include<s t d i o . h> void main ( ) { int x = 3 ; int p ; p = &x ; p r i n t f ( p c o n t i e n t l a v a l e u r %X, q u i n e s t a u t r e que l a d r e s s e %X de x , p , &x ) ; }

50

Acc`s ` la variable pointe e a e Le lecteur impatient se demande probablement ` quoi peuvent servir toutes ces toiles ? Quel peut bien a e tre lintrt des pointeurs ? e ee Si p pointe sur x, alors il est possible daccder ` la valeur de x en passant par p. Pour le compilae a teur, p est la variable pointe par p, cela signie que lon peut, pour le moment du moins, utiliser e indirement p ou x. Ce sont deux faons de se rfrer ` la mme variable, on appelle cela de laliasing. e c ee a e Explicitons cela sur un exemple, #include<s t d i o . h> void main ( ) { int x = 3 ; int p ; p = &x ; p r i n t f ( x = %d\n , x ) ; p = 4 ; p r i n t f ( x = %d\n , x ) ; } Laectation p = &x fait pointer p sur x. A partir de ce moment, p peut tre utilis pour dsigner la e e e variable x. De ce fait, laectation x = 4 peut aussi tre crite p = 4. Toutes les modications opres e e ee sur p seront rpercutes sur la variable pointe par p. Donc ce programme ache e e e x = 3 x = 4 Rcapitulons e Quache, ` votre avis, le programe suivant ? a #include<s t d i o . h> void main ( ) { int x = 3 ; int y = 5 ; int p ; p = &x ; p r i n t f ( x = %d\n , x ) ; p = 4 ; p r i n t f ( x = %d\n , x ) ; p = &y ; p r i n t f ( p = %d\n , p ) ; p = p + 1 ; p r i n t f ( y = %d\n , y ) ; } x est initialis ` 3 et y est initialis ` 5. Laectation p = &x fait pointer p sur x, donc p et x sont e a e a deux critures direntes de la mme variable. Le premier printf ache la valeur de x : plus prcisment e e e e e x = 3. Ensuite, laectation p = 4 place dans la valeur pointe par p, ` savoir x, la valeur 4. Donc le e a deuxi`me printf ache x = 4. Laectation p = &y fait maintenant pointer p sur y, donc la valeur de p e est la valeur de la variable pointe y. le troisi`me printf ache donc *p = 5. Noubliez pas que comme e e p pointe sur y, alors p et y sont deux alias pour la mme variable, de ce fait, linstruction p = p + 1 e peut tout ` fait scrire y = y + 1. Cette instruction place donc dans y la valeur 6, le quatri`me printf a e e ache donc y = 6. Ce programme ache donc : 51

x = 3 x = 4 *p = 5 y = 6

1.10.2

Tableaux

Il est possible daller plus loin dans lutilisation des pointeurs en les employant pour manipuler des tableaux. Tout dabord, claircissons quelques points. e Dmystication (et dmythication) du tableau en C e e Les lments dun tableau sont juxtaposs dans la mmoire. Autrement dit, ils sont placs les uns ` cot ee e e e a e des autres. Sur le plan de ladressage, cela a une consquence fort intuitive. Sachant quun int occupe e 2 octets en mmoire et que &T [0] est ladresse mmoire du premier lment du tableau T , quelle est e e ee ladresse mmoire de T [1] ? La rponse est la plus simple : &T [0] + 2 (ne lcrivez jamais ainsi dans un e e e programme, vous verrez pourquoi plus loin dans le cours...). Cela signie que si lon connait ladresse dun lment dun tableau (le premier en loccurrence), il devient possible de retrouver les adresses de tous les ee autres lments de ce tableau. ee Jai par ailleurs, une assez mauvaise surprise pour vous. Vous utilisez sans le savoir des pointeurs depuis que vous utilisez des tableaux. Etant donn la dclaration int T [50], vous conviendrez que les dsignations e e e {T [0], . . . , T [49]} permettent de se rfrer aux 50 lments du tableau T . Mais vous est-il dj` arriv, en ee ee ea e passant un tableau en param`tre, dcrire T sans crire dindice entre crochets ? Par exemple, e e e #include<s t d i o . h> void i n i t T a b ( int K [ ] , int n ) { int i ; f o r ( i = 0 ; i < n ; i ++) K[ i ] = i + 1 ; } void a f f i c h e T a b ( int K [ ] , int n ) { int i ; f o r ( i = 0 ; i < n ; i ++) p r i n t f ( %d\n , K[ i ] ) ; } int main ( ) { int T [ 5 0 ] ; i n i t T a b (T, 5 0 ) ; a f f i c h e T a b (T, 5 0 ) ; return 0 ; } Vous remarquez que lorsque lon passe un tableau en param`tre ` un sous-programme, on mentionne e a seulement son nom. En fait, le nom dun tableau, T dans lexemple ci-avant, est ladresse mmoire du e premier lment de ce tableau. Donc, T est une variable contenant une adresse mmoire, T est par ee e consquent un pointeur. Lorsque dans un sous-programme auquel on a pass un tableau en param`tre, e e e on mentionne un indice, par exemple K[i], le compilateur calcule ladresse du i-`me lment de K pour e ee lire ou crire ` cette adresse. e a

52

Utilisation des pointeurs Commenons par observer lexemple suivant : c #include<s t d i o . h> main ( ) { char t [ 1 0 ] ; char p ; t [0] = a ; p = t; p r i n t f ( l e p r e m i e r e l e m e n t du t a b l e a u e s t %c . \ n , p ) ; } La variable t contient ladresse mmoire du premier lment du tableau t. p est un pointeur de char, donc e ee laectation p = t place dans p ladresse mmoire du premier lment du tableau t. Comme p pointe vers e ee t[0], on peut indirement utiliser p ou t[0]. Donc ce programme ache e le premier element du tableau est a. Calcul des adresses mmoire e Tout dabord, je tiens ` rappeler quune variable de type char occupe un octet en mmoire. Considrons a e e maintenant les dclarations e char t[10] ; et char p = t ; Nous savons que si p pointe vers t[0], il est donc ais daccder au premier lment de t en utilisant le e e ee pointeur p. Mais comment accder aux autres lments de t ? Par exemple T [1] ? Souvenez-vous que les e ee lments dun tableau sont juxtaposs, dans lordre, dans la mmoire. Par consquent, si p est ladresse ee e e e mmoire du premier lment du tableau t, alors (p + 1) est ladresse mmoire du deuxi`me lment de ce e ee e e ee tableau. Vous tes conviendrez que p est la variable dont ladresse mmoire est contenue dans p. Il est e e possible, plus gnralement, dcrire (p + 1) pour dsigner la variable dont ladresse mmoire est (p + 1), e e e e e cest ` dire (la valeur contenue dans p) + 1. Illustrons cela dans un exemple, le programme a #include<s t d i o . h> main ( ) { char t [ 1 0 ] ; char p ; t [ 1 ] = b ; p = t; p r i n t f ( l e deuxieme e l e m e n t du t a b l e a u e s t %c . \ n , ( p + 1 ) ) ; } ache le deuxi`me element du tableau est b. e En eet, p + 1 est ladresse mmoire du deuxi`me lment de t, il est donc possible dutiliser indirement e e ee e (p + 1) et t[1]. Plus gnralement, on peut utiliser (p + i) ` la place de t[i]. En eet, (p + i) est ladresse e e a du i-`me lment de t, et (p + i) est la variable dont ladresse mmoire est (p + i). Par exemple, e ee e

53

#include<s t d i o . h> #define N 26 main ( ) { char t [N ] ; char v = A ; char p ; int i ; p = t; / i n i t i a l i s a t i o n du t a b l e a u / f o r ( i = 0 ; i < N ; i ++) ( p + i ) = v++; / a f f i c h a g e du t a b l e a u / f o r ( i = 0 ; i < N ; i ++) p r i n t f ( %c , ( p + i ) ) ; p r i n t f ( \n ) ; } Ou encore, en utilisant des sous-programmes, #include<s t d i o . h> #define N 26 void i n i t T a b ( char k , int n ) { int i ; int v = A ; f o r ( i = 0 ; i < n ; i ++) ( k + i ) = v++; } void a f f i c h e T a b ( char k , int n ) { int i ; f o r ( i = 0 ; i < n ; i ++) p r i n t f ( %c , ( k + i ) ) ; p r i n t f ( \n ) ; } main ( ) { char t [N ] ; initTab ( t , N) ; afficheTab ( t , N) ; } Ces deux sous-programmes achent A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

54

Arithmtique des pointeurs e Supposons que le tableau t contienne des int, sachant quun int occupe 2 octets en mmoire. Est-ce que e (t + 1) est ladresse du deuxi`me lment de t ? e ee Mathmatiquement, la rponse est non, ladresse du deuxi`me lment est t+(la taille d un int) = (t+2). e e e ee Etant donn un tableau p dlments occupant chacun n octets en mmoire, ladresse du i-`me lment e ee e e ee est alors p + i n. Cependant, la pondration systmatique de lindice par la taille occupe en mmoire par chaque lment e e e e ee est dune part une lourdeur dont on se passerait volontier, et dautre part une source derreurs et de bugs. Pour y remdier, le compilateur prend cette partie du travail en charge,on ne pondrera donc pas les e e indices ! Cela signie, plus explicitement, que quel que soit le type des lments du tableau p, ladresse ee mmoire du i-`me lment de p est p + i. On le vrie exprimentalement en excutant le programme e e ee e e e suivant : #include<s t d i o . h> #define N 30 void i n i t T a b ( int k , int n ) { int i ; k = 1 ; f o r ( i = 1 ; i < n ; i ++) ( k + i ) = ( k + i 1) + 1 ; } void a f f i c h e T a b ( int k , int n ) { int i ; f o r ( i = 0 ; i < n ; i ++) p r i n t f ( %d , ( k + i ) ) ; p r i n t f ( \n ) ; } main ( ) { int t [N ] ; initTab ( t , N) ; afficheTab ( t , N) ; }

1.10.3

Allocation dynamique de la mmoire e

La lecture du chapitre prcdent, si vous y avez survcu, vous a probablement men ` une question que e e e ea les l`ves posent souvent : Monsieur pourquoi on fait ca ?. Cest vrai ! Pourquoi on manipulerait les ee tableaux avec des pointeurs alors que dans les exemples que je vous ai donn, on peut le faire sans les poine teurs ? Dans la mesure o` un tableau est un pointeur, on peut, mme ` lintrieur dun sous-programme u e a e auquel un tableau a t pass en param`tre, manipuler ce tableau avec des crochets. Alors dans quel cas ee e e utiliserons-nous des pointeurs pour parcourir les tableaux ? De la mme faon quil existe des cas dans lesquels on connait ladresse dune variable scalaire mais e c pas son nom, il existe des tableaux dont on connait ladresse mais pas le nom.

55

Un probl`me de taille e Lorsque lon dclare un tableau, il est obligatoire de prciser sa taille. Cela signie que la taille dun e e tableau doit tre connue ` la compilation. Alors que faire si on ne connait pas cette taille ? La seule e a solution qui se prsente pour le moment est le surdimensionnement, on donne au tableau une taille tr`s e e (trop) leve de sorte quaucun dbordement ne se produise. e e e Nous aimerions procder autrement, cest ` dire prciser la dimension du tableau au moment e a e de lexcution. Nous allons pour cela rappeler quelques principes. Lors de la dclaration dun tableau e e t, un espace mmoire allou au stockage de la variable t, cest ` dire la variable qui contient ladresse e e a mmoire du premier lment du tableau. Et un autre espace mmoire est allou au stockage des lments e ee e e ee du tableau. Il y a donc deux zones mmoires utilises. e e La fonction malloc Lorsque vous dclarez un pointeur p, vous allouez un espace mmoire pour y stocker ladresse mmoire e e e dun entier. Et p, jusqu` ce quon linitialise, contient nimporte quoi. Vous pouvez ensuite faire pointer a p sur ladresse mmoire que vous voulez (choisissez de prfrence une zone contenant un int...). Soit cette e ee adresse est celle dune variable qui existe dj`. Soit cette adresse est celle dun espace mmoire cre ea e ee spcialement pour loccasion. e Vous pouvez demander au syst`me dexploitation de lespace mmoire pour y stocker des valeurs. La e e fonction qui permet de rserver n octets est malloc(n). Si vous crivez malloc(10), lOS rserve 10 oce e e tets, cela sappelle une allocation dynamique, cest ` dire une allocation de la mmoire au cours de a e lexcution. Si vous voulez rserver de lespace mmoire pour stocker un int par exemple, il sut dappeler e e e malloc(2), car un int occupe 2 octets en mmoire. e En mme temps, cest bien joli de rserver de lespace mmoire, mais a ne sert pas ` grand chose si e e e c a on ne sait pas o` il se trouve ! Cest pour a que malloc est une fonction. malloc retourne ladresse u c mmoire du premier octet de la zone rserve. Par consquent, si vous voulez crer un int, il convient e e e e e dexcuter linstruction : p = malloc(2) o` p est de type int. Le malloc rserve deux octets, et retourne e u e ladresse mmoire de la zone alloue. Cette aectation place donc dans p ladresse mmoire du int noue e e vellement cr. ee Cependant, linstruction p = malloc(2) ne peut pas passer la compilation. Le compilateur vous dira que les types void et int sont incompatibles (incompatible types in assignement). Pour votre culture gnrale, void est le type adresse mmoire en C. Alors que int est le type adresse mmoire dun e e e e int. Il faut donc dire au compilateur que vous savez ce que vous faites, et que vous tes sr que cest e u bien un int que vous allez mettre dans la variable pointe. Pour ce faire, il convient dectuer ce que e lon appelle un cast, en ajoutant, juste apr`s loprateur daectation, le type de la variable se situant ` e e a gauche de laectation entre parenth`ses. Dans lexemple ci-avant, cela donne : int p = (int)malloc(2). e Voici un exemple illustrant lutilisation de malloc. #include<s t d i o . h> #include<m a l l o c . h> main ( ) { int p ; p = ( int ) m a l l o c ( 2 ) ; p = 2 8 ; p r i n t f ( %d\n , p ) ; } Vous remarquez que nous sommes bien dans un cas o` lon connait ladresse dune variable mais pas son u nom. Le seul moyen de manier la variable alloue dynamiquement est dutiliser un pointeur. e 56

La fonction f ree Lorsque que lon eectue une allocation dynamique, lespace rserv ne peut pas tre allou pour une autre e e e e variable. Une fois que vous nen avez plus besoin, vous devez le librer explicitement si vous souhaitez e quune autre variable puisse y tre stocke. La fonction de libration de la mmoire est f ree. f ree(v) o` e e e e u v est une variable contenant ladresse mmoire de la zone ` librer. A chaque fois que vous allouez une e a e zone mmoire, vous devez la librer ! Un exemple classique dutilisation est : e e #include<s t d i o . h> #include<m a l l o c . h> main ( ) { int p ; p = ( int ) m a l l o c ( 2 ) ; p = 2 8 ; p r i n t f ( %d\n , p ) ; free (p ) ; } Notez bien que la variable p, qui a t alloue au dbut du main, a t libr par le f ree(p). ee e e ee ee La valeur N U LL La pointeur p qui ne pointe aucune adresse a la valeur N U LL. Attention, il nest pas ncessairement e initialis a N U LL, N U LL est la valeur que, conventionnellement, on dcide de donner ` p sil ne pointe e` e a sur aucune zone mmoire valide. Par exemple, la fonction malloc retourne N U LL si aucune zone mmoire e e adquate nest trouve. Il convient, ` chaque malloc, de vrier si la valeur retourne par malloc est e e a e e dirente de N U LL. Par exemple, e #include<s t d i o . h> #include<m a l l o c . h> main ( ) { int p ; p = ( int ) m a l l o c ( 2 ) ; i f ( p == NULL) exit (0); p = 2 8 ; p r i n t f ( %d\n , p ) ; free (p ) ; } Vous remarquez que le test de non nullit de la valeur retourne par malloc est eectu immdiatement e e e e apr`s lallocation dynamique. Vous ne devez jamais utiliser un pointeur sans avoir vri sa validit, e e e e autrement dit, sa non-nullit. Un pointeur contenant une adresse non valide est appel un pointeur fou. e e Vous devrez, dans votre vie de programmeur, les traquer avec hargne ! Lallocation dynamique dun tableau Lors de lallocation dynamique dun tableau, il est ncessaire de dterminer la taille mmoire de la zone e e e de la zone ` occuper. Par exemple, si vous souhaitez allouer dynamiquament un tableau de 10 variables a de type char. Il sut dexcuter linstruction malloc(10), car un tableau de 10 char occupe 10 octets e en mmoire. Si par contre, vous souhaitez allouer dynamiquement un tableau de 10 int, il conviendra e dexcuter malloc(20), car chaque int occupe 2 octets en mmoire. e e Pour se simplier la vie, le compilateur met ` notre disposition la fonction sizeof , qui nous permet a 57

de calculer la place prise en mmoire par la variable dun type donn. Par exemple, soit T un type, la e e valeur sizeof (T ) est la taille prise en mmoire par une variable de type T . Si par exemple on souhaite e allouer dynamiquement un int, il convient dexcuter linstruction malloc(sizeof (int)). Attention, sizeof e prend en param`tre un type ! e Si on souhaite allouer dynamiquement un tableau de n variables de type T , on excute linstruction e malloc(nsizeof (T )). Par exemple, pour allouer un tableau de 10 int, on excute malloc(10sizeof (int)). e Voici une variante du programme dun programme prcdent : e e #include<s t d i o . h> #include<m a l l o c . h> #define N 26 void i n i t T a b ( int k , int n ) { int i ; f o r ( i = 0 ; i < n ; i ++) ( k + i ) = i + 1 ; } void a f f i c h e T a b ( int k , int n ) { int i ; f o r ( i = 0 ; i < n ; i ++) p r i n t f ( %d , ( k + i ) ) ; p r i n t f ( \n ) ; } int main ( ) { int p ; p = ( int ) m a l l o c (N s i z e o f ( int ) ) ; i f ( p == NULL) return 1; initTab (p , N) ; afficheTab (p , N) ; free (p ) ; return 0 ; }

1.10.4

Passage de param`tres par rfrence e ee

Jai dit tout ` lheure : Pour le compilateur, p est la variable pointe par p, cela signie que lon peut, a e pour le moment du moins, utiliser indirement p ou x. En prcisant pour le moment du moins, e e javais dj` lintention de vous montrer des cas dans lesquels ce ntait pas possible. Cest ` dire des cas ea e a dans lesquels on connait ladresse dune variable mais pas son nom. Permutation de deux variables A titre de rappel, observez attentivement le programme suivant : #include<s t d i o . h> void echange ( int x , int y ) { int t = x ; 58

x = y; y = t; } void main ( ) { int a = 1 ; int b = 2 ; p r i n t f ( a = %d , b = %d\n , a , b ) ; echange ( a , b ) ; p r i n t f ( a = %d , b = %d\n , a , b ) ; } A votre avis, ache-t-il a = 1, b = 2 a = 2, b = 1 ou bien a = 1, b = 2 a = 1, b = 2 Mditons quelque peu : la question que lon se pose est Est-ce que le sous-programme echange change e e bien les valeurs des deux variables a et b ? Il va de soi quil change bien les valeurs des deux variables x et e y, mais comme ces deux variables ne sont que des copies de a et b, cette permutation na aucun eet sur a et b. Cela signie que la fonction echange ne fait rien, on aurait pu crire ` la place un sous-programme e a ne contenant aucune instruction, leet aurait t le mme. Ce programme ache donc ee e a = 1, b = 2 a = 1, b = 2 Remarques Ceux dont la mmoire na pas t rinitialis pendant les vacances se souviennent certainement du fait e ee e e quil tait impossible de passer en param`tre des variables scalaires par rfrence. Jai menti, il existe e e ee un moyen de passer des param`tres par rfrence, et vous aviez des indices vous permettant de vous en e ee douter ! Par exemple, linstruction scanf (%d, &x) permet de placer une valeur saisie par lutilisateur dans x, et scanf est un sous-programme... Vous conviendrez donc que la variable x a t passe e e e en param`tre par rfrence. Autrement dit, que la valeur de x est modie dans le sous-programme e ee e scanf , donc que la variable permettant de dsigner x dans le corps de ce sous-programme nest pas une e copie de x, mais la variable x elle-mme, ou plutt un alias de la variable x. e o Vous pouvez dores et dj` retenir que ea nomsousprogramme(. . . , &x, . . .) sert ` passer en param`tre la variable x par rfrence. Et nalement, cest plutt logique, linstruction a e ee o nomsousprogramme(. . . , x, . . .) passe en param`tre la valeur de x, alors que e nomsousprogramme(. . . , &x, . . .) passe en param`tre ladresse de x, cest-`-dire un moyen de retrouver la variable x depuis le souse a programme et de modier sa valeur. Cependant, si vous crivez echange(&a, &b), le programme ne compilera pas... En eet, le sous-programme e echange prend en param`tre des int et si vous lui envoyez des adresses mmoire ` la place, le compilateur e e a ne peut pas comprendre ce que vous voulez faire... Vous allez donc devoir modier le sous-programme echange si vous voulez lui passer des adresses mmoire en param`tre. e e 59

Utilisation de pointeurs On arrive ` la question suivante : dans quel type de variable puis-je mettre ladresse mmoire dune a e variable de type entier ? La rponse est int, un pointeur sur int. Observons le sous-programme suivant, e void echange ( int x , int y ) { int t = x ; x = y ; y = t ; } x et y ne sont pas des int, mais des pointeurs sur int. De ce fait le passage en param`tre des deux e adresses &a et &b fait pointer x sur a et y sur b. Donc x est un alias de a et y est un alias de b. Nous sommes, comme dcrit dans lintroduction de ce chapitre dans un cas dans lequel on connait ladresse e dune variable, mais pas son nom : dans le sous-programme echange, la variable a est inconnue (si vous lcrivez, ca ne compilera pas...), seul le pointeur x permet daccder ` la variable a. e e a Il sut donc, pour crire un sous-programme prenant en param`tre des variables passes par rfrence, e e e ee de les dclarer comme des pointeurs, et dajouter une devant ` chaque utilisation. e a

1.10.5

Pointeurs sur fonction

60

1.11
1.11.1

Fichiers
Dnitions e

Supposons que lon dispose dun programme permettant saisir 10 entiers dans un tableau. #include<s t d i o . h> int main ( ) { int t [ 1 0 ] , i ; f o r ( i = 0 ; i < 10 ; i ++) { p r i n t f ( S a i s i r un e n t i e r : ) ; s c a n f ( %d , t + i ) ; } f o r ( i = 0 ; i < 10 ; i ++) p r i n t f ( %d , t [ i ] ) ; p r i n t f ( \n ) ; return 0 ; } Le probl`me qui se pose est que lorsque lon sort de ce programme, les donnes saisies sont perdues. e e Si lon souhaite les avoir ` disposition pour dune excution ultrieure, il convient dutiler une mmoire a e e e persistante, cest-`-dire qui conserve les donnes entre deux excutions. On utilise pour ce faire un chier. a e e Un chier est une mmoire stocke de faon permanente sur un disque et ` laquelle on acc`de avec un e e c a e nom. Les donnes dans un chier se prsentent de faon squentielle, et donc se lisent ou scrivent du e e c e e dbut vers la n. e Nous survolerons dans ce cours un ensemble de fonctions de stdio.h permettant de manier des chiers. Pour plus dtails, il est tr`s hautement recommand de se reporter ` la documentation. e e e a

1.11.2

Ouverture et fermeture

Pour accder au contenu dun chier en lecture ou en criture, on utilise les deux fonctions fopen et e e fclose. La fonction fopen fopen permet, comme son nom lindique, douvrir un chier. Son prototype est FILE *fopen(const char *path, const char *mode) : path est une cha de caract`re contenant le chemin (relatif ou absolu) et le nom du chier. Si le ne e chier est dans le rpertoire dans lequel sexcute le programme, alors le nom du chier sut. e e mode est une cha de caract`re contenant "r" pour ouvrir le chier en mode lecture, "w" en mode ne e criture, etc. e FILE* est un type permettant de rfrencer un chier ouvert, fopen retourne NULL sil est impossible ee douvrir le chier (par exemple si le nom est incorrect). La valeur retourne devra tre place dans e e e une variable de type FILE*, cest cette valeur qui permettra par la suite daccder au contenu du e chier. La fonction fclose fclose sert ` fermer un chier. Son prototype est int fclose(FILE *fp) : a fp est la variable de type FILE* permettant de rfrencer le chier ` fermer. ee a Cette fonction retourne 0 si la fermeture sest bien passe. Dans le cas contraire, des indications sur e lerreur survenue sont accessibles dans des variables globales.

61

Utilisation Si lon souhaite par exemple lire dans un chier sappelant "toto.txt" : #include<s t d i o . h> int main ( ) { FILE f ; f = fopen ( toto . txt , r ) ; i f ( f == NULL) { p r i n t f ( E r r e u r l o r s de l o u v e r t u r e du f i c h i e r t o t o . t x t \n ) ; return 1; } / L e c t u r e dans l e f i c h i e r ... / i f ( f c l o s e ( f ) != 0 ) { p r i n t f ( E r r e u r l o r s de l a f e r m e t u r e du f i c h i e r t o t o . t x t \n ) ; return 1; } return 0 ; }

1.11.3

Lecture et criture e

Il existe plusieurs faons de lire dans un chier : caract`re par caract`re, ligne par ligne, par paquets c e e de caract`res, etc. Chaque lecture se faisant ` laide dune fonction approprie. Lors dun traitement se e a e faisant ` partir dune lecture dans un chier, on appelle de faon itre une fonction de lecture faisant a c ee avancer un curseur dans un chier jusqu` ce que la n du chier soit atteinte. a Lcriture fonctionne de faon analogue, ` un dtail pr`s : il est inutile dcrire le caract`re de n de e c a e e e e chier, il est ajout automatiquement lors du fclose. e Caract`re par caract`re e e La fonction int fgetc(FILE* stream) retourne un caract`re lu dans le chier f. Bien que le caract`re e e lu soit un octet, il est retourn dans un int. Le caract`re EOF indique que la n du chier a t atteinte. e e ee Par exemple, #include<s t d i o . h> int main ( ) { FILE f ; char c ; f = fopen ( toto . txt , r ) ; i f ( f == NULL) { p r i n t f ( E r r e u r l o r s de l o u v e r t u r e du f i c h i e r t o t o . t x t \n ) ; return 1; } while ( ( c = f g e t c ( f ) ) != EOF) p r i n t f ( c a r a c t e r e l u : %c \n , c ) ;

62

i f ( f c l o s e ( f ) != 0 ) { p r i n t f ( E r r e u r l o r s de l a f e r m e t u r e du f i c h i e r t o t o . t x t \n ) ; return 1; } return 0 ; } On crit un caract`re dans un chier ` laide de la fonction int fputc(int c, FILE* stream). e e a #include<s t d i o . h> int main ( ) { FILE f ; char c [ 7 ] = Toto ! ; int i ; f = f o p e n ( t o t o . t x t , w ) ; i f ( f == NULL) { p r i n t f ( E r r e u r l o r s de l o u v e r t u r e du f i c h i e r t o t o . t x t \n ) ; return 1; } f o r ( i = 0 ; i < 6 ; i ++) fputc ( c [ i ] , f ) ; i f ( f c l o s e ( f ) != 0 ) { p r i n t f ( E r r e u r l o r s de l a f e r m e t u r e du f i c h i e r t o t o . t x t \n ) ; return 1; } return 0 ; } Par cha nes de caract`res e Les deux fonctions char *fgets(char *s, int size, FILE *stream) et int fputs(const char *s, FILE *stream) permettent de lire et dcrire des cha e nes de caract`res dans des chiers, voir la e documentation pour plus de dtails. e Par paquets Les deux fonctions size t fread(void *ptr, size t size, size t nmemb, FILE *stream) et size t fwrite(const void *ptr, size t size, size t nmemb, FILE *stream) sont tr`s utiles lorsque lon e veut sauvegarder un tableau dans un chier, ou recopier un chier dans un tableau (voir la documentation pour plus de dtails). Voici tout de mme deux exemples : e e #include<s t r i n g . h> #include<s t d i o . h> struct p e r s o n n e { char nom [ 3 0 ] ; int age ; }; int main ( int argv , char a r g c )

63

{ FILE f ; struct p e r s o n n e r e p e r t o i r e [ 3 ] = {{ t a t a , 2 } , { t o t o , 8 } , { t i t i , 1}}; f = f o p e n ( t o t o . t x t , w ) ; i f ( f == NULL) return 1 ; f w r i t e ( r e p e r t o i r e , 3 , s i z e o f ( struct p e r s o n n e ) , f ) ; fclose ( f ); return 0 ; } #include<s t r i n g . h> #include<s t d i o . h> struct p e r s o n n e { char nom [ 3 0 ] ; int age ; }; int main ( int argv , char a r g c ) { FILE f ; int i , n = 0 ; struct p e r s o n n e r e p e r t o i r e [ 3 ] ; f = fopen ( toto . txt , r ) ; i f ( f == NULL) return 1 ; while ( f r e a d ( r e p e r t o i r e + n , 1 , s i z e o f ( struct p e r s o n n e ) , f ) ) n++; f o r ( i = 0 ; i < n ; i ++) p r i n t f ( %s %d\n , r e p e r t o i r e [ i ] . nom , r e p e r t o i r e [ i ] . age ) ; fclose ( f ); return 0 ; }

64

1.12
1.12.1

Listes Cha ees n


Le probl`me e

Plusieurs probl`mes surviennent lorsque lon utilise des tableaux pour stocker des valeurs : e En cas de redimensionnement, il faut refaire une allocation dynamique et recopier tout le tableau. En cas dinsertion ou de suppression dun lment, il faut dcaler vers la gauche ou vers la droite ee e tous les successeurs. Concatner ou fusionner des tableaux est une opration lourde au niveau mmoire. e e e Tous les lments doivent tre stocks dans des zones contiges, lallocation est donc un lourd travail ee e e u lorsque la mmoire est fragmente. e e Bref, de nombreuses oprations sont lourdes en temps dexcution. e e Nous dnirons dans ce cours un autre moyen de stocker les donnes en formant un ensemble ordonn, e e e le listes cha ees. n

1.12.2

Pointeurs et structures

Soit T un type structur dni comme suit : e e typedef struct T { int i ; char c ; }T ; Si p est un pointeur de type T , alors p contient ladresse mmoire dun lment de type T . Soit t une e ee variable de type T , et soit laectation p = &t. Alors, p pointe sur t. De ce fait p et t sont des alias, et nous pourrons indirement utiliser t.i (resp. t.c) et (p).i (resp (p).c). Par exemple, recrivons le e e programme de lexemple du cours sur les structures : #include<s t d i o . h> #include<m a l l o c . h> #include<s t d l i b . h> #define N 10 / / typedef struct p o i n t { double abs ; double ord ; } point ; / / point nextPoint ( point previous ) { point r e s u l t ; r e s u l t . ord = ( p r e v i o u s ) . ord + 1 . ; r e s u l t . abs = ( p r e v i o u s ) . abs + 2 . ; return r e s u l t ; } / / void i n i t T a b l e a u P o i n t s ( p o i n t p , int n ) 65

{ int i ; ( p ) . ord = 0 ; ( p ) . abs = 1 ; f o r ( i = 1 ; i < n ; i ++) (p + i ) = nextPoint (p + i 1 ) ; } / / void a f f i c h e P o i n t ( p o i n t p ) { p r i n t f ( (%f , %f ) , ( p ) . abs , ( p ) . ord ) ; } / / void a f f i c h e T a b l e a u P o i n t s ( p o i n t p , int n ) { int i ; f o r ( i = 1 ; i < n ; i ++) { p r i n t f ( p[%d ] = , i ) ; affichePoint (p + i ) ; p r i n t f ( \n ) ; } } / / int main ( ) { point p ; p = ( p o i n t ) m a l l o c (N s i z e o f ( p o i n t ) ) ; i f ( p == NULL) exit (0); initTableauPoints (p , N) ; a f f i c h e T a b l e a u P o i n t s (p , N) ; free (p ) ; return 0 ; } Lcriture (p).i permet de dsigner le champ i de la variable pointe par p. Cette criture, peu commode, e e e e peut tre remplace par p > i, par exemple : e e #include<s t d i o . h> #include<m a l l o c . h> #include<s t d l i b . h> #define N 10 / / typedef struct p o i n t { double abs ; 66

double ord ; } point ; / / point nextPoint ( point previous ) { point r e s u l t ; r e s u l t . ord = p r e v i o u s >ord + 1 . ; r e s u l t . abs = p r e v i o u s >abs + 2 . ; return r e s u l t ; } / / void i n i t T a b l e a u P o i n t s ( p o i n t p , int n ) { int i ; p>ord = 0 ; p>abs = 1 ; f o r ( i = 1 ; i < n ; i ++) (p + i ) = nextPoint (p + i 1 ) ; } / / void a f f i c h e P o i n t ( p o i n t p ) { p r i n t f ( (%f , %f ) , p>abs , p>ord ) ; } / / void a f f i c h e T a b l e a u P o i n t s ( p o i n t p , int n ) { int i ; f o r ( i = 1 ; i < n ; i ++) { p r i n t f ( p[%d ] = , i ) ; affichePoint (p + i ) ; p r i n t f ( \n ) ; } } / / main ( ) { point p ; p = ( p o i n t ) m a l l o c (N s i z e o f ( p o i n t ) ) ; i f ( p == NULL) exit (0); initTableauPoints (p , N) ; a f f i c h e T a b l e a u P o i n t s (p , N) ;

67

free (p ) ; } Attention ! Les oprateurs dacc`s aux champs . et -> ont une priorit suprieure ` celles de tous les autres e e e e a oprateurs du langage ! Si vous manipulez un tableau de structures t et que vous souhaitez accder au e e champ t du i-`me lment, est-il intelligent dcrire *(i + t).c ? Absolument pas ! . est prioritaire sur e ee e *, donc le parenth`sage implicite est *((i + t).c), essayez de vous reprsenter ce que cela fait, et vous e e comprendrez pourquoi votre programme plante ! En crivant (i + t)->c, vous obtenez une expression e quivalente ` (*(i + t)).c, qui est dj` bien plus proche de ce que lon souhaite faire. e a ea

1.12.3

Un premier exemple

Considrons le type suivant : e typedef struct m a i l l o n { int data ; struct m a i l l o n next ; } maillon ; On appelle cette forme de type un type rcursif, cest-`-dire qui contient un pointeur vers un lment du e a ee mme type. Observons lexemple suivant : e #include<s t d i o . h> / / typedef struct m a i l l o n { int data ; struct m a i l l o n next ; } maillon ; / / int main ( ) { m a i l l o n m, p ; maillon ptr ; m. data = 1 ; m. next = &p ; p . data = 2 ; p . next = NULL; f o r ( p t r = & ; p t r != NULL ; p t r = ptr>next ) m p r i n t f ( data = %d\n , ptr>data ) ; return 0 ; } m et p sont deux maillons, et m->next pointe vers p, cela signie que lorsque lon initialise ptr ` &m, a alors ptr pointe sur m. Donc, lors de la premi`re itration de la boucle for, la valeur prt->data est e e m.data, ` savoir 1. Lorsque le pas de la boucle est excut, ptr reoit la valeur ptr->next, qui nest a e e c autre que m->next, ou encore &p. Donc ptr pointe maintenant sur p. Dans la deuxi`me itration de la e e boucle, ptr->data est la valeur p.data, ` savoir 2. Ensuite le pas de la boucle est excut, et ptr prend a e e la valeur ptr->next, ` savoir p->next, ou encore NULL. Comme ptr == NULL, alors la boucle sarrte. a e Ce programme ache donc : data = 1 data = 2 68

1.12.4

Le cha nage

La faon de renseigner les valeurs des pointeurs next observe dans lexemple prcdent sappelle le c e e e cha nage. Une liste de structures telle que chaque variable structure contienne un pointeur vers vers e une autre variable du mme type sappelle une liste cha ee. Utilisons un tableau pour stocker les e n lments dune liste cha ee ` 10 lments. ee n a ee #include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> #define N 10 / / typedef struct m a i l l o n { int data ; struct m a i l l o n next ; } maillon ; / / void p r i n t D a t a ( m a i l l o n p t r ) { f o r ( ; p t r != NULL ; p t r = ptr>next ) p r i n t f ( data = %d\n , ptr>data ) ; } / / int main ( ) { maillon l ; int i ; l = ( m a i l l o n ) m a l l o c (N s i z e o f ( m a i l l o n ) ) ; i f ( l == NULL) exit (0); l >data = 0 ; f o r ( i = 1 ; i < N ; i ++) { ( l + i )>data = i ; ( l + i 1)>next = l + i ; } ( l + N 1)>next = NULL; printData ( l ) ; free ( l ); return 0 ; } Les 10 maillons de la liste cha ee ont t placs dans le tableau l, la premi`re boucle dispose le cha n ee e e nage des lments dans le mme ordre que dans le tableau, lachage de la liste est fait dans le sous-programme ee e printfData, et seul le cha nage y est utilis. Comme le champ data du i-`me lment de la liste contient e e ee la valeur i, alors ce programme ache : data = 0 data = 1 69

data data data data data data data data

= = = = = = = =

2 3 4 5 6 7 8 9

Pour modier lordre de parcours des maillons, il sut de modier le cha nage, par exemple, #include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> #define N 10 / / typedef struct m a i l l o n { int data ; struct m a i l l o n next ; } maillon ; / / void p r i n t D a t a ( m a i l l o n p t r ) { f o r ( ; p t r != NULL ; p t r = ptr>next ) p r i n t f ( data = %d\n , ptr>data ) ; } / / int main ( ) { maillon l ; int i ; l = ( m a i l l o n ) m a l l o c (N s i z e o f ( m a i l l o n ) ) ; i f ( l == NULL) exit (0); l >data = 0 ; ( l + 1)>data = 1 ; ( l + N 2)>next = l + 1 ; ( l + N 1)>next = NULL; f o r ( i = 2 ; i < N ; i +=1) { ( l + i )>data = i ; ( l + i 2)>next = l + i ; } printData ( l ) ; free ( l ); return 0 ; }

70

Ce programme ache data data data data data data data data data data = = = = = = = = = = 0 2 4 6 8 1 3 5 7 9

1.12.5

Utilisation de malloc

Pour le moment, nous avons stock les lments dans un tableau, les maillons taient donc regroups dans e ee e e des zones mmoire contiges. Il est possible de stocker les maillons dans les zones non contiges, tous e u u peuvent tre retrouvs ` laide du cha e e a nage. Par exemple, #include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> #define N 10 / / typedef struct m a i l l o n { int data ; struct m a i l l o n next ; } maillon ; void p r i n t D a t a ( m a i l l o n p t r ) { f o r ( ; p t r != NULL ; p t r = ptr>next ) p r i n t f ( data = %d\n , ptr>data ) ; } / / void f r e e L L ( m a i l l o n l ) { maillon n ; while ( l != NULL) { n = l >next ; free ( l ); l = n; } } / / int main ( ) { 71

maillon l ; maillon current ; maillon previous ; int i ; l = ( maillon ) malloc ( sizeof ( maillon ) ) ; i f ( l == NULL) exit (0); l >data = 0 ; previous = l ; f o r ( i = 1 ; i < N ; i ++) { current = ( maillon ) malloc ( sizeof ( maillon ) ) ; i f ( c u r r e n t == NULL) exit (0); c u r r e n t >data = i ; p r e v i o u s >next = c u r r e n t ; previous = current ; } c u r r e n t >next = NULL; printData ( l ) ; freeLL ( l ) ; return 0 ; } Ce programme ache data data data data data data data data data data = = = = = = = = = = 0 1 2 3 4 5 6 7 8 9

Pour plus de clart, on placera linitialisation de la liste dans une fonction : e #include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> #define N 10 / / typedef struct m a i l l o n { int data ; struct m a i l l o n next ; } maillon ; / / void printLL ( m a i l l o n p t r )

72

{ f o r ( ; p t r != NULL ; p t r = ptr>next ) p r i n t f ( data = %d\n , ptr>data ) ; } / / m a i l l o n i n i t L L ( int n ) { maillon f i r s t ; maillon current ; maillon previous ; int i ; f i r s t = ( maillon ) malloc ( sizeof ( maillon ) ) ; i f ( f i r s t == NULL) exit (0); f i r s t >data = 0 ; previous = f i r s t ; f o r ( i = 1 ; i < n ; i ++) { current = ( maillon ) malloc ( sizeof ( maillon ) ) ; i f ( c u r r e n t == NULL) exit (0); c u r r e n t >data = i ; p r e v i o u s >next = c u r r e n t ; previous = current ; } c u r r e n t >next = NULL; return f i r s t ; } / / void f r e e L L ( m a i l l o n l ) { maillon n ; while ( l != NULL) { n = l >next ; free ( l ); l = n; } } / / int main ( ) { maillon l ; l = i n i t L L (N ) ; printLL ( l ) ; freeLL ( l ) ; return 0 ; }

73

1.12.6

Oprations e

Observons de quelle faon il est possible deectuer certaines oprations sur une liste cha ee. Les sousc e n programmes ci-dessous ont t pens et combins pour tre les plus simples possibles... ee e e e Cration dun maillon e m a i l l o n c r e e M a i l l o n ( int n ) { maillon l ; l = ( maillon ) malloc ( sizeof ( maillon ) ) ; i f ( l == NULL) exit (0); l >data = n ; l >next = NULL; return l ; } Insertion au dbut dune liste cha ee e n m a i l l o n insereDebutLL ( m a i l l o n l , int n ) { maillon f i r s t = creeMaillon (n ) ; f i r s t >next = l ; return f i r s t ; } Cration dune liste cha ee {0, . . . , n 1} e n m a i l l o n i n i t L L ( int n ) { m a i l l o n l = NULL; int i ; f o r ( i = n 1 ; i >= 0 ; i ) l = insereDebut ( l , i ) ; return l ; }

1.12.7

Listes doublement cha ees n

Un maillon dune liste doublement cha ee contient deux pointeurs, un vers le maillon prcdent, et un n e e vers le maillon suivant. typedef struct d m a i l l o n { int data ; struct d m a i l l o n p r e v i o u s ; struct d m a i l l o n next ; } dmaillon ; Aussi paradoxal que cela puisse para tre, bon nombre doprations sont davantage aises sur des listes e e doublement cha ees. Pour se faciliter la tche, nous manipulerons les listes cha ees ` laide de deux n a n a pointeurs, un vers son premier lment, et un vers son dernier : ee typedef struct d L i n k e d L i s t { struct d m a i l l o n f i r s t ; struct d m a i l l o n l a s t ; } dLinkedList ; 74

Le soin decrire les oprations sur ces listes vous est laiss dans le TP... e e

75

Chapitre 2

Exercices
2.1
2.1.1

Variables et oprateurs e
Entiers

Exercice 1 - Saisie et achage Saisir une variable enti`re, acher sa valeur. e Exercice 2 - Permutation de 2 variables Saisir deux variables et les permuter avant de les acher. Exercice 3 - Permutation de 4 valeurs Ecrire un programme demandant ` a de la faon suivante : c noms des variables valeurs avant la permutation valeurs apr`s la permutation e lutilisateur de saisir 4 valeurs A, B, C, D et qui permute les variables A 1 3 B 2 4 C 3 1 D 4 2

Exercice 4 - Permutation de 5 valeurs On consid`re la permutation qui modie cinq valeurs de la faon suivante : e c noms des variables A B C D E valeurs avant la permutation 1 2 3 4 5 valeurs apr`s la permutation 4 3 5 1 2 e Ecrire un programme demandant ` lutilisateur de saisir 5 valeurs que vous placerez dans des variables a appeles A, B, C, D et E. Vous les permuterez ensuite de la faon dcrite ci-dessus. e c e

2.1.2

Flottants

Exercice 5 - Saisie et achage Saisir une variable de type float, acher sa valeur. Exercice 6 - Moyenne arithmtique e Saisir 3 valeurs, acher leur moyenne. Exercice 7 - Surface du rectangle Demander ` lutilisateur de saisir les longueurs et largeurs dun rectangle, acher sa surface. a

76

Exercice 8 - Moyennes arithmtique et gomtrique e e e Demander ` lutilisateur de saisir deux valeurs a et b, acher ensuite la dirence entre la moyenne a e (a + b) arithmtique e et la moyenne gomtrique ab. Pour indication, sqrt(f) est la racine carre du e e e 2 ottant f, cette fonction est disponible en important #include<math.h>. Exercice 9 - Cartons et camions Nous souhaitons ranger des cartons pesant chacun k kilos dans un camion pouvant transporter M kilos de marchandises. Ecrire un programme C demandant ` lutilisateur de saisir M et k, que vous reprsenterez a e avec des nombres ottants, et achant le nombre (entier) de cartons quil est possible de placer dans le camion. Noubliez pas que lorsque lon aecte une valeur ottante ` une variable enti`re, les dcimales a e e sont tronques. e

2.1.3

Caract`res e

Exercice 10 - Prise en main Aectez le caract`re a ` une variable de type char, achez ce caract`re ainsi que son code ASCII. e a e Exercice 11 - Successeur Ecrivez un programme qui saisit un caract`re et qui ache son successeur dans la table des codes ASCII. e Exercice 12 - Casse Ecrivez un programme qui saisit un caract`re miniscule et qui lache en majuscule. e Exercice 13 - Codes ASCII Quels sont les codes ASCII des caract`res 0, 1, . . ., 9 e

2.1.4

Oprations sur les bits (diciles) e

Exercice 14 - Codage dadresses IP Une adresse IP est constitue de 4 valeurs de 0 ` 255 spares par des points, par exemple 192.168.0.1, e a e e chacun de ces nombres peut se coder sur 1 octet. Comme une variable de type long occupe 4 octets en mmoire, il est possible de sen servir pour stocker une adresse IP enti`re. Ecrivez un programme qui e e saisit dans des unsigned short les 4 valeurs dune adresse IP, et place chacune delle sur un octet dune variable de type long. Ensuite vous extrairez de cet entier les 4 nombres de ladresse IP et les acherez en les sparant par des points. e Exercice 15 - Permutation circulaire des bits Eectuez une permutation circulaire vers la droite des bits dune variable b de type unsigned short, faites de mme vers la droite. e Exercice 16 - Permutation de 2 octets Permutez les deux octets dune variable de type unsigned short saisie par lutilisateur. Exercice 17 - Inversion de lordre de 4 octets Inversez lordre des 4 octets dune variable de type long saisie par lutilisateur. Utilisez le code du programme sur les adresses IP pour tester votre programme.

77

2.1.5

Morceaux choisis (diciles)

Exercice 18 - Pi`ces de monnaie e Nous disposons dun nombre illimit de pi`ces de 0.5, 0.2, 0.1, 0.05, 0.02 et 0.01 euros. Nous souhaitons, e e tant donn une somme S, savoir avec quelles pi`ces la payer de sorte que le nombre de pi`ces utilise e e e e e soit minimal. Par exemple, la somme de 0.96 euros se paie avec une pi`ce de 0.5 euros, deux pi`ces de 0.2 e e euros, une pi`ce de 0.05 euros et une pi`ce de 0.01 euros. e e 1. Le fait que la solution donne pour lexemple est minimal est justi par une ide plutt intuitive. e e e o Expliquez ce principe sans exc`s de formalisme. e 2. Ecrire un programme demandant a lutilisateur de saisir une valeur comprise entre 0 et 0.99. Ensuite, ` achez le dtail des pi`ces ` utiliser pour constituer la somme saisie avec un nombre minimal de e e a pi`ces. e Exercice 19 - Modication du dernier bit Modiez le dernier bit dune variable a saisie par lutilisateur. Exercice 20 - Associativit de laddition ottante e Lensemble des ottants nest pas associatif, cela signie quil existe trois ottants a, b et c, tels que (a + b) + c = a + (b + c). Trouvez de tels ottants et vriez-le dans un programme. e Exercice 21 - Permutation sans variable temporaire Permutez deux variables a et b sans utiliser de variables temporaires.

78

2.2
2.2.1

Traitements conditionnels
Prise en main

Exercice 1 - Majorit e Saisir lge de lutilisateur et lui dire sil est majeur. a Exercice 2 - Valeur Absolue Saisir une valeur, acher sa valeur absolue. Exercice 3 - Admissions Saisir une note, acher ajourn si la note est infrieure ` 8, rattrapage entre 8 et 10, admis dessus e e a de 10. Exercice 4 - Assurances Une compagnie dassurance eectue des remboursements sur lesquels est ponctionne une franchise core respondant ` 10% du montant ` rembourser. Cependant, cette franchise ne doit pas excder 4000 euros. a a e Demander ` lutilisateur de saisir le montant des dommages, acher ensuite le montant qui sera rembours a e ainsi que la franchise. Exercice 5 - Valeurs distinctes parmi 2 Acher sur deux valeurs saisies le nombre de valeurs disctinctes. Exercice 6 - Plus petite valeur parmi 3 Acher sur trois valeurs saisies la plus petite. Exercice 7 - Recherche de doublons Ecrire un algorithme qui demande ` lutilisateur de saisir trois valeurs et qui lui dit sil sy trouve un a doublon. Exercice 8 - Valeurs distinctes parmi 3 Acher sur trois valeurs saisies le nombre de valeurs disctinctes. Exercice 9 - ax + b = 0 Saisir les coecients a et b et acher la solution de lquation ax + b = 0. e Exercice 10 - ax2 + bx + c = 0 Saisir les coecients a, b et c, acher la solution de lquation ax2 + bx + c = 0. e

2.2.2

Switch

Dans le probl`me suivant, vous serez confront au probl`me dit de saisie buerise (ce nologisme est tr`s e e e e e e vilain). Explication : lorsque vous saisissez des valeurs au clavier, elles sont places dans le tampon de e saisie (buer). Une fois que vous avez saisi entre, (le caract`re \n), les donnes sont lues directement e e e dans le buer par scanf. Mais cette fonction ne lira que le caract`re qui a t saisi, et le \n qui a valid e ee e la saisie restera dans le buer jusqu` la prochaine saisie dun caract`re. Linstruction getchar() ; lit un a e octet dans le buer. Donc, ` chaque fois que vous avez plac un \n dans le buer, pensez ` le vider a e a avec un getchar() ;.

79

Exercice 11 - Calculatrice Ecrire un programme demandant ` lutilisateur de saisir a deux valeurs a et b, de type int ; un oprateur op de type char, vriez quil sagit delune des valeurs suivantes : +, , , /. e e Puis achez le rsultat de lopration a op b. e e

2.2.3

Lchiquier e

On indice les cases dun chiquer avec deux indices i et j variant tous deux de 1 ` 8. La case (i, j) est sur e a la ligne i et la colonne j. Par convention, la case (1, 1) est noire. Exercice 12 - Couleurs Ecrire un programme demandant ` lutilisateur de saisir les deux coordonnes i et j dune case, et lui a e disant sil sagit dune case blanche ou noire. Exercice 13 - Cavaliers Ecrire un programme demandant ` lutilisateur de saisir les coordonnes (i, j) dune premi`re case et les a e e coordonnes (i , j ) dune deuxi`me case. Dites-lui ensuite sil est possible de dplacer un cavalier de (i, j) e e e a ` (i , j ). Exercice 14 - Autres pi`ces e Mme exercice avec la tour, le fou, la dame et le roi. Utilisez un switch et prsentez le programme de la e e sorte : Quelle piece souhaitez-vous deplacer ? 0 = Cavalier 1 = Tour 2 = Fou 3 = Dame 4 = Roi 3 Saisissez les coordonnees de la case de depart : A = 2 A = 1 Saisissez les coordonnees de la case darrivee : A = 6 A = 5 Le mouvement (2, 1) -> (6, 5) est valide.

2.2.4

Heures et dates

Exercice 15 - Oprations sur les heures e Ecrire un programme qui demande ` lutilisateur de saisir une heure de dbut (heures + minutes) et une a e heure de n (heures + minutes aussi). Ce programme doit ensuite calculer en heures + minutes le temps coul entre lheure de dbut et lheure de n. Si lutilisateur saisit 10h30 et 12h15, le programme doit lui e e e acher que le temps coul entre lheure de dbut et celle de n est 1h45. On suppose que les deux heures e e e se trouvent dans la mme journe, si celle de dbut se trouve apr`s celle de n, un message derreur doit e e e e sacher. Lors la saisie des heures, sparez les heures des minutes en demandant ` lutilisateur de saisir : e a heures de dbut e minutes de dbut e heures de n minutes de n 80

Exercice 16 - Le jour dapr`s e Ecrire un programme permettant de saisir une date (jour, mois, anne), et achant la date du lendemain. e Saisissez les trois donnes sparment (comme dans lexercice prcdent). Prenez garde aux nombre de e e e e e jours que comporte chaque mois, et au fait que le mois de fvrier comporte 29 jours les annes bissextiles. e e Allez sur http://fr.wikipedia.org/wiki/Ann\%C3\%A9e_bissextilepourconnatrelesrglesexactes, je vous avais dit que les annes taient bissextiles si et seulement si elles taient divisible par 4, apr`s e e e e vrication, jai constat que ctait lg`rement plus complexe. Je vous laisse vous documenter et retranse e e e e crire ces r`gles de la faon la plus simple possible. e c

2.2.5

Intervalles et rectangles

Exercice 17 - Intervalles bien forms e Demandez ` lutilisateur de saisir les deux bornes a et b dun intervalle [a, b]. Contrler les valeurs saisies. a o Exercice 18 - Appartenance Demandez-lui ensuite de saisir une valeur x, dites-lui si x [a, b] Exercice 19 - Intersections Demandez-lui ensuite de saisir les bornes dun autre intervalle [a , b ]. Contrlez la saisie. Dites-lui ensuite o si [a, b] [a , b ] [a , b ] [a, b] [a , b ] [a, b] = . Exercice 20 - Rectangles Nous reprsenterons un rectangle R aux cots parall`les aux axes des abscisses et ordonnes ` laide e e e e a des coordonnes de deux points diamtralement opposs, le point en haut ` gauche, de coordonnes e e e a e (xHautGauche, yHautGauche), et le point en bas ` droite, de coordonnes (xBasDroite, yBasDroite). a e Demander ` lutilisateur de saisir ces 4 valeurs, contrlez la saisie. a o Exercice 21 - Appartenance Demandez ` lutilisateur de saisir les 2 coordonnes dun point (x, y) et dites ` lutilisateur si ce point se a e a trouve dans le rectangle R. Exercice 22 - Intersection Demandez ` lutilisateur de saisir les 4 valeurs a (xHautGauche , yHautGauche , xBasDroite , yBasDroite ) permettant de spcier un deuxi`me rectangle R . Prcisez ensuite si e e e RR R R RR =

2.2.6

Prprocesseur e

Exercice 23 - Lchiquer e Mme exercice mais en utilisant le plus possible les spcications suivantes : e e

81

#include<s t d i o . h> #include<s t d l i b . h> / / #d e f i n e #d e f i n e #d e f i n e #d e f i n e #d e f i n e CAVALIER 0 TOUR 1 FOU 2 DAME 3 ROI 4

/ / #d e f i n e MAIN i n t main ( ) \ { / / #d e f i n e FINMAIN return 0 ; \ } / / #d e f i n e S I i f ( / / #d e f i n e ALORS ) { / / #d e f i n e SINON } e l s e { / / #d e f i n e FINSI } / / #d e f i n e SUIVANT( v a r ) switch ( v a r ) { / / #d e f i n e FINSUIVANT( d e f ) d e f a u l t : def }

/ / #d e f i n e CAS( v a l e u r , i n s t r u c t i o n s ) case v a l e u r break ; : instructions \

/ / \ #d e f i n e PIECES LIST p r i n t f ( %hu = C a v a l i e r \n , CAVALIER ) ; \ p r i n t f ( %hu = Tour \n , TOUR) ; \ p r i n t f ( %hu = Fou\n , FOU) ; \ p r i n t f ( %hu = Dame\n , DAME) ; \ p r i n t f ( %hu = Roi \n , ROI ) / / #d e f i n e CHECK COORD( i ) \ S I i <1 | | i >8 ALORS \ p r i n t f ( c o o r d o n n e e i n v a l i d e \n ) ; \ return 1 ; \ FINSI / / #d e f i n e GET VAR(A, B) \ p r i n t f ( A = ) ; \ s c a n f ( %hu , &B ) ; \ CHECK COORD(B ) ; / / #d e f i n e PRINT VALID p r i n t f ( v a l i d e ) / / #d e f i n e PRINT INVALID p r i n t f ( i n v a l i d e )

82

/ / #d e f i n e FATAL ERROR p r i n t f ( System E r r o r . I t i s recommended t h a t \ you f o r m a t your hard d i s k . ) ; \ return 1 ; / / #d e f i n e S I cond PRINT SINON \ PRINT FINSI CONDITIONAL PRINT( cond ) \ ALORS \ VALID ; \ INVALID ; \

2.2.7

Nombres et lettres

Exercice 24 - conversion numrique franais (tr`s dicile) e c e Ecrire un programme saisissant un unsigned long et achant sa valeur en toutes lettres. Rappelons que 20 et 100 saccordent en nombre sils ne sont pas suivis dun autre mot (ex. : quatre-vingts, quatre-vingtun). Mille est invariable (ex. : dix mille) mais pas million (ex. : deux millions) et milliard (ex. : deux milliards). Depuis 1990, tous les mots sont spars de traits dunion (ex. : quatre-vingt-quatre), sauf autour e e des mots mille, millions et milliard (ex. : deux mille deux-cent-quarante-quatre, deux millions quatre-cent mille deux-cents). (source : http://www.leconjugueur.com/frlesnombres.php). Par exemple, Saisissez un nombre = 1034002054 1034002054 : un milliard trente-quatre millions deux mille cinquante-quatre Vous prendrez soin de respecter les espacements, les tirets, et de ne pas faire de fautes dorthographe. Vous userez et abuserez de macros-instructions pour simplier le plus possible votre code.

83

2.3
2.3.1

Boucles
Comprhension e

Exercice 1 Quache le programme suivant ? #include<s t d i o . h> #define N 5 int main ( ) { int a = 1 , b = 0 ; while ( a <= N) b += a++; p r i n t f ( %d , %d\n , a , b ) ; return 0 ; } Exercice 2 Quache le programme suivant ? #include<s t d i o . h> #define M 3 #define N 4 int main ( ) { int a , b , c = 0 , d ; f o r ( a = 0 ; a < M ; a++) { d = 0; f o r ( b = 0 ; b < N ; b++) d+=b ; c += d } p r i n t f ( a = %d , b = %d , c = %d , d = %d , a , b , c , d ) ; return 0 ; } Exercice 3 Quache le programme suivant ? #include<s t d i o . h> int main ( ) { int a , b , c , d ; a = 1; b = 2; c = a /b ; d = ( a==b ) ? 3 : 4 ; p r i n t f ( c = %d , d = %d\n , c , d ) ; a = ++b ; b %= 3 ; 84

p r i n t f ( a = %d , b = %d\n , a , b ) ; b = 1; f o r ( a = 0 ; a <= 10 ; a++) c = ++b ; p r i n t f ( a = %d , b = %d , c = %d , d = %d\n , a , b , c , d ) ; return 0 ; }

2.3.2

Utilisation de toutes les boucles

Les exercices suivants seront rdigs avec les trois types de boucle : tant que, rpter jusqu` et pour. e e e e a Exercice 4 - Compte ` rebours a Ecrire un programme demandant ` lutilisateur de saisir une valeur numrique positive n et achant a e toutes les valeurs n, n 1, . . . , 2, 1, 0. Exercice 5 - Factorielle Ecrire un programme calculant la factorielle (factorielle n = n! = 1 2 . . . n et 0! = 1) dun nombre saisi par lutilisateur.

2.3.3

Choix de la boucle la plus approprie e

Pour les exercices suivants, vous choisirez la boucle la plus simple et la plus lisible. Exercice 6 - Table de multiplication Ecrire un programme achant la table de multiplication dun nombre saisi par lutilisateur. Exercice 7 - Tables de multiplications Ecrire un programme achant les tables de multiplications des nombres de 1 ` 10 dans un tableau ` deux a a entres. e Exercice 8 - Puissance Ecrire un programme demandant ` lutilisateur de saisir deux valeurs numriques b et n (vrier que n a e e est positif) et achant la valeur bn .

2.3.4

Morceaux choisis
+

Exercice 9 - Approximation de 2 par une srie e 1 . Eectuer cette approximation en calculant un grand 2i i=0 nombre de terme de cette srie. Lapproximation est-elle de bonne qualit ? e e On approche le nombre 2 ` laide de la srie a e Exercice 10 - Approximation de e par une srie e
+

Mmes questions qu` lexercice prcdent en e ` laide de la srie e a e e a e


i=0

1 . i!

85

Exercice 11 - Approximation de ex par une srie e


+

Calculer une approximation de ex ` laide de la srie ex = a e


i=0

xi . i!

Exercice 12 - Conversion dentiers en binaire Ecrire un programme qui ache un unsigned short en binaire. Vous utiliserez linstruction sizeof(unsigned short), qui donne en octets la taille de la reprsentation en mmoire dun unsigned short. e e Exercice 13 - Conversion de dcimales en binaire e Ecrire un programme qui ache les dcimales dun double en binaire. e Exercice 14 - Inversion de lordre des bits Ecrire un programme qui saisit une valeur de type unsigned short et qui inverse lordre des bits. Vous testerez ce programme en utilisant le prcdent. e e Exercice 15 - Joli carr e Ecrire un programme qui saisit une valeur n et qui ache le carr suivant (n = 5 dans lexemple) : e n = 5 X X X X X X X X X X X X X X X X X X X X X X X X X

Exercice 16 - Racine carre par dichotomie e Ecrire un algorithme demandant ` lutilisateur de saisir deux valeurs numriques x et p et achant x a e avec une prcision p. On utilisera une mthode par dichotomie : ` la k-`me itration, on cherche x dans e e a e e lintervalle [min, sup], on calcule le milieu m de cet intervalle (` vous de trouver comment le calculer). a Si intervalle est susament petit (` vous de trouver quel crit`re utiliser), acher m. Sinon, vriez cet a e e si x se trouve dans [inf, m] ou dans [m, sup], et modiez les variables inf et sup en consquence. Par e exemple, calculons la racine carre de 10 avec une prcision 0.5, e e Commenons par la chercher dans [0, 10], on a m = 5, comme 52 > 10, alors 5 > 10, donc 10 se c trouve dans lintervalle [0, 5]. 52 On recommence, m = 2.5, comme 2 = 25 < 10, alors 5 < 10, on poursuit la recherche dans [ 5 , 5] 4 2 2 On a m = 3.75, comme 3.752 > 10, alors 3.75 > 10 et 10 [2.5, 3.75] On a m = 3.125, comme 3.1252 < 10, alors 3.125 < 10 et 10 [3.125, 3.75] Comme ltendue de lintervalle [3.125, 3.75] est infrieure 2 0.5, alors m = 3.4375 est une approxie e mattion ` 0.5 pr`s de 10. a e

2.3.5

Extension de la calculatrice

Une calculatrice de poche prend de faon alterne la saisie dun oprateur et dune oprande. Si lutilisateur c e e e saisit 3, + et 2, cette calculatrice ache 5, lutilisateur a ensuite la possibilit de se servir de 5 comme e dune oprande gauche dans un calcul ultrieur. Si lutilisateur saisit par la suite et 4, la calculatrice e e ache 20. La saisie de la touche = met n au calcul et ache un rsultat nal. e

86

Exercice 17 - Calculatrice de poche Implmentez le comportement dcrit ci-dessus. e e Exercice 18 - Puissance Ajoutez loprateur $ qui calcule ab , vous vous restreindrez ` des valeurs de b enti`res et positives. e a e Exercice 19 - Oprations unaires e Ajoutez les oprations unaires racine carre et factorielle. e e

87

2.4
2.4.1

Tableaux
Exercices de comprhension e

Quachent les programmes suivants ? Exercice 1 char C [ 4 ] ; int k ; C[ 0 ] = a ; C[ 3 ] = J ; C[ 2 ] = k ; C [ 1 ] = R ; f o r ( k = 0 ; k < 4 ; k++) p r i n t f ( %c \n , C [ k ] ) ; f o r ( k = 0 ; k < 4 ; k++) C [ k]++; f o r ( k = 0 ; k < 4 ; k++) p r i n t f ( %c \n , C [ k ] ) ; Exercice 2 int K[ 1 0 ] , i , j ; K[ 0 ] = 1 ; f o r ( i = 1 ; i < 10 ; i ++) K[ i ] = 0 ; f o r ( j = 1 ; j <= 3 ; j ++) f o r ( i = 1 ; i < 10 ; i ++) K[ i ] += K[ i 1 ] ; f o r ( i = 0 ; i < 10 ; i ++) p r i n t f ( %d\n , K[ i ] ) ; Exercice 3 int K[ 1 0 ] , i , j ; K[ 0 ] = 1 ; K[ 1 ] = 1 ; f o r ( i = 2 ; i < 10 ; i ++) K[ i ] = 0 ; f o r ( j = 1 ; j <= 3 ; j ++) f o r ( i = 1 ; i < 10 ; i ++) K[ i ] += K[ i 1 ] ; f o r ( i = 0 ; i < 10 ; i ++) p r i n t f ( %d\n , K[ i ] ) ;

2.4.2

Prise en main

Exercice 4 - Initialisation et achage Ecrire un programme plaant dans un tableau int T[10] ; les valeurs 1, 2, . . . , 10, puis achant ce c tableau. Vous initialiserez le tableau ` la dclaration. a e Exercice 5 - Initialisation avec une boucle Mme exercice en initialisant le tableau avec une boucle. e

88

Exercice 6 - somme Achez la somme des n lments du tableau T . ee Exercice 7 - recherche Demandez ` lutilisateur de saisir un int et dites-lui si ce nombre se trouve dans T . a

2.4.3

Indices

Exercice 8 - permutation circulaire Eectuez une permutation circulaire vers la droite des lments de T en utilisant un deuxi`me tableau. ee e Exercice 9 - permutation circulaire sans deuxi`me tableau e Mme exercice mais sans utiliser de deuxi`me tableau. e e Exercice 10 - miroir Inversez lordre des lments de T sans utiliser de deuxi`me tableau. ee e

2.4.4

Recherche squentielle e

Exercice 11 - modication du tableau Etendez le tableau T ` 20 lments. Placez dans T[i] le reste modulo 17 de i2 . a ee Exercice 12 - min/max Achez les valeurs du plus petit et du plus grand lment de T. ee Exercice 13 - recherche squentielle e Demandez ` lutilisateur de saisir une valeur x et donnez-lui la liste des indices i tels que T[i] a la valeur a x. Exercice 14 - recherche squentielle avec stockage des indices e Mme exercice que prcdemment, mais vous en achant La valeur ... se trouve aux indices suivants : e e e ... si x se trouve dans T, et La valeur ... na pas t trouve si x ne se trouve pas dans T. e e e

2.4.5

Morceaux choisis

Exercice 15 - pi`ces de monnaie e Reprennez lexercice sur les pi`ces de monnaie en utilisant deux tableaux, un pour stocker les valeurs des e pi`ces dans lordre dcroissant, lautre pour stocker le nombre de chaque pi`ce. e e e Exercice 16 - recherche de la tranche minimale en O(n3 ) Une tranche est dlimite par deux indices i et j tels que i j, la valeur dune tranche est ti + . . . + tj . e e Ecrire un programme de recherche de la plus petite tranche dun tableau, vous utiliserez trois boucles imbriques. Vous testerez votre algorithme sur un tableau T ` 20 lments alatoires (utilisez la fonction e a ee e random de stdlib.h) de signes quelconques. Exercice 17 - recherche de la tranche minimale en O(n2 ) Mme exercice mais en utilisant deux boucles imbriques. e e

89

Exercice 18 - recherche de la tranche minimale en O(n) (dicile) Mme exercice mais en utilisant une seule boucle. e

90

2.5
2.5.1

Cha nes de caract`res e


Prise en main

Question 1 - Achage Crer une cha de caract`res contenant la valeur Les framboises sont perchees sur le tabouret de mon e ne e grand-pere. et achez-la avec %s. Vous donnerez au tableau la plus petite taille possible. Question 2 - Achage sans %s Mme exercice mais sans utiliser %s. e Question 3 - Longueur Ecrire un programme saisissant proprement une cha de caract`re (sans dbordement dindice, avec le ne e e caract`re nul et en faisant le mnage dans le buer) et calculant sans strlen la taille de cha (nombre e e ne de caract`res sans compter le caract`re nul). e e Question 4 - Longueur sans retour chariot Mme exercice mais en supprimant de la cha lventuel caract`re de validation de la saisie (retour ` la e ne e e a ligne). Question 5 - Extraction Ecrire un programme saisissant proprement une cha de caract`re t, deux indices i et j et recopiant ne e dans une deuxi`me cha t la tranche [ti , . . . , tj ]. e ne Question 6 - Substitution Ecrire un programme saisissant proprement une cha de caract`re t, deux caract`res a et b et substituant ne e e des a ` toutes les occurrences de b. a

2.5.2

Les fonctions de string.h

Pour chacun des exercices suivants, vous vous documenterez sur les fonctions de string.h utiles et vous vous en servirez de faon convenable. Et ne faites pas de salets ! c e Question 7 - Comparaisons Saisissez deux cha nes de caract`res, dterminez la plus grande selon lordre lexicographique. e e Question 8 - Longueur Saisissez deux cha nes de caract`res, dterminez la plus longue des deux.. e e Question 9 - Copie Saisissez une cha de caract`res, copiez-l` dans une deuxi`me cha ne e a e ne. Question 10 - Concatnation e Saisissez deux cha nes de caract`res, achez la concatnation de la premi`re ` la suite de la deuxi`me. e e e a e

91

2.5.3

Morceaux choisis

Question 11 - Extensions Ecrire un programme saisissant un nom de chier et achant sparment le nom du chier et lextension. e e Vous prvoirez le cas o` plusieurs extensions sont concatnes, par exemple : langageCCC.tar.gz. e u e e Question 12 - Expressions arithmtiques e Ecrire un programme saisissant une expression arithmtique totalement parenthse, (par exemple 3 + 4, e ee ((3 2) + (7/3))) et disant ` lutilisateur si lexpression est correctement parenthse. a ee

92

2.6
2.6.1

Fonctions
Gomtrie e e

Ecrire un programme demandant ` lutilisateur de saisir une valeur numrique positive n et achant un a e carr, une croix et un losange, tous de cot n. Par exemple, si n = 10, lexcution donne e e e Saisissez la taille 10 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * des figures

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

93

* *

* *

Vous dnirez des sous-programmes de quelques lignes et au plus deux niveaux dimbrication. Vous ferez e attention ` ne jamais crire deux fois les mmes instructions. Pour ce faire, compltez le code source a e e e suivant :
#include<s t d i o . h> / Affiche le caractere c / void a f f i c h e C a r a c t e r e ( char c ) { } / / / a f f i c h e n f o i s l e c a r a c t e r e c , ne r e v i e n t pas a l a l i g n e apres l e dernier caractere . / void l i g n e S a n s R e t u r n ( i n t n , char c ) { } / / / a f f i c h e n f o i s l e caractere c , r e v i e n t a l a l i g n e apres le dernier caractere . / void l i g n e A v e c R e t u r n ( i n t n , char c ) { } / / / Affiche n espaces . / void e s p a c e s ( i n t n ) { } / / / A f f i c h e l e caractere c a l a colonne i , ne r e v i e n t pas a l a l i g n e a p r e s . / void u n C a r a c t e r e S a n s R e t u r n ( i n t i , char c ) { } / / / A f f i c h e l e caractere c a l a colonne i , r e v i e n t a l a l i g n e apres . / void u n C a r a c t e r e A v e c R e t u r n ( i n t i , char c ) { } / / / A f f i c h e l e c a r a c t e r e c aux c o l o n n e s i e t j , r e v i e n t a l a l i g n e apres . / void d e u x C a r a c t e r e s ( i n t i , i n t j , char c ) {

94

} / / / A f f i c h e un c a r r e de c o t e n . / void c a r r e ( i n t n ) { } / / / A f f i c h e un chapeau dont l a p o i n t e non a f f i c h e e e s t s u r l a c o l o n n e c e n t r e , ave c l e s c a r a c t e r e s c . / void chapeau ( i n t c e n t r e , char c ) { } / / / A f f i c h e un chapeau a l e n v e r s a vec d e s c a r a c t e r e s c , l a p o i n t e non a f f i c h e e e s t a l a c o l o n n e c e n t r e / void c h a p e a u I n v e r s e ( i n t c e n t r e , char c ) { } / / / A f f i c h e un l o s a n g e de c o t e n . / void l o s a n g e ( i n t n ) { } / / / A f f i c h e une c r o i x de c o t e n / void c r o i x ( i n t n ) { } / / main ( ) { int t a i l l e ; printf ( Saisissez la t a i l l e s c a n f ( %d , & t a i l l e ) ; carre ( t a i l l e ); losange ( t a i l l e ) ; croix ( t a i l l e ); } d e s f i g u r e s \n ) ;

2.6.2

Arithmtique e

Exercice 1 - chires et nombres Rapellons que a % b est le reste de la division enti`re de a par b. e 1. Ecrire la fonction int unites(int n) retournant le chire des units du nombre n. e 2. Ecrire la fonction int dizaines(int n) retournant le chire des dizaines du nombre n. 3. Ecrire la fonction int extrait(int n, int p) retourant le p-`me chire de reprsentation dcimale e e e de n en partant des units. e

95

4. Ecrire la fonction int nbChiffres(int n) retournant le nombre de chires que comporte la reprsentation e dcimale de n. e 5. Ecrire la fonction int sommeChiffres(int n) retournant la somme des chires de n. Exercice 2 - Nombres amis Soient a et b deux entiers strictement positifs. a est un diviseur strict de b si a divise b et a = b. Par exemple, 3 est un diviseur strict de 6. Mais 6 nest pas un diviseur strict 6. a et b sont des nombres amis si la somme des diviseurs stricts de a est b et si la somme des diviseurs de b est a. Le plus petit couple de nombres amis connu est 220 et 284. 1. Ecrire une fonction int sommeDiviseursStricts(int n), elle doit renvoyer la somme des diviseurs stricts de n. 2. Ecrire une fonction int sontAmis(int a, int b), elle doit renvoyer 1 si a et b sont amis, 0 sinon. Exercice 3 - Nombres parfaits Un nombre parfait est un nombre gal ` la somme de ses diviseurs stricts. Par exemple, 6 a pour diviseurs e a stricts 1, 2 et 3, comme 1 + 2 + 3 = 6, alors 6 est parfait. 1. Est-ce que 18 est parfait ? 2. Est-ce que 28 est parfait ? 3. Que dire dun nombre ami avec lui-mme ? e 4. Ecrire la fonction int estParfait(int n), elle doit retourner 1 si n est un nombre parfait, 0 sinon. Exercice 4 - Nombres de Kaprekar Un nombre n est un nombre de Kaprekar en base 10, si la reprsentation dcimale de n2 peut tre spare e e e e e en une partie gauche u et une partie droite v tel que u + v = n. 452 = 2025, comme 20 + 25 = 45, 45 est aussi un nombre de Kaprekar. 48792 = 23804641, comme 238 + 04641 = 4879 (le 0 de 046641 est inutile, je lai juste plac pour viter toute confusion), alors 4879 est encore un nombre de Kaprekar. e e 1. Est-ce que 9 est un nombre de Kaprekar ? 2. Ecrire la fonction int sommeParties(int n, int p) qui dcoupe n est deux nombres dont le e deuxi`me comporte p chires, et aui retourne leur somme. Par exemple, e sommeP arties(12540, 2) = 125 + 40 = 165 3. Ecrire la fonction int estKaprekar(int n)

2.6.3

Passage de tableaux en param`tre e

Exercice 5 - somme Ecrire une fonction int somme(int T[], int n) retournant la somme des n lments du tableau T . ee Exercice 6 - minimum Ecrire une fonction int min(int T[], int n) retournant la valeur du plus petit lment du tableau T . ee Exercice 7 - recherche Ecrire une fonction int existe(int T[], int n, int k) retournant 1 si k est un des n lments du ee tableau T , 0 sinon.

96

Exercice 8 - Somme des lments pairs ee Ecrivez le corps de la fonction int sommePairs(int T[], int n), sommeP airs(T, n) retourne la somme des lments pairs du tableau T ` n lments. Noubliez pas que a%b est le reste de la division enti`re de ee a ee e a par b, et que vous tes tenu dutiliser au mieux les boolens. e e Exercice 9 - Vrication e Ecrivez le corps de la fonction int estTrie(int T[], int n), estT rie(T, n) retourne vrai si et seulement si le tableau T , ` n lments, est tri dans lordre croissant. a ee e Exercice 10 - permutation circulaire Ecrire une fonction void permutation(int T[], int n) eectuant une permutation circulaire vers la droite des lments de T . ee Exercice 11 - miroir Ecrire une fonction void miroir(int T[], int n) inversant lordre des lments de T . ee

2.6.4

Dcomposition en facteurs premiers e

On pose ici N = 25, vous utiliserez un #define N 25 dans toute cette partie. On rappelle quun nombre est premier sil nest divisible que par 1 et par lui-mme. Par convention, 1 nest pas premier. e Exercice 12 Ecrivez une fonction int estPremier(int n, int T[], int k) retournant 1 si n est premier, 0 sinon. Vous vrierez la primarit de n en examinant les restes des divisions de n par les k premiers lments e e ee de T . On suppose que k est toujours suprieur ou gal ` 1. e e a Exercice 13 Modiez la fonction prcdente en tenant compte du fait que si aucun diviseur premier de n infrieur ` e e e a n na t trouv, alors n est premier ee e Exercice 14 Ecrivez une fonction void trouvePremiers(int T[], int n) plaant dans le tableau T les n premiers c nombres premiers. Exercice 15 Ecrivez une fonction void dcompose(int n, int T[], int K[]) plaant dans le tableau K la dcomposition e c e en facteurs premiers du nombre n, sachant que T contient les N premiers nombres premiers. Par exemple, si n = 108108, alors on dcompose n en produit de facteurs premiers de la sorte e 108108 = 2 2 3 3 3 7 11 13 = 22 33 50 71 111 131 170 190 . . . Z 0 (o` Z est le N -i`me nombre premier). On reprsente donc n de faon unique par le tableau K ` N u e e c a lments ee {2, 3, 0, 1, 1, 1, 0, 0, 0, . . . , 0} Exercice 16 Ecrivez une fonction int recompose(int T[], int K[]) eectuant lopration rciproque de celle dcrite e e e ci-dessus.

97

Exercice 17 Ecrivez une fonction void pgcd(int T[], int K[], int P[]) prenant en param`tre les dcompositions e e en facteurs premiers T et K de deux nombres, et plaant dans P la dcomposition en facteurs premiers c e du plus grand commun diviseur de ces deux nombres. Exercice 18 Ecrivez une fonction int pgcd(int i, int j) prenant en param`tres deux nombres i et j, et combinant e les fonctions prcdentes pour retourner le pgcd de i et j. e e

2.6.5

Statistiques

Nous souhaitons faire des statistiques sur les connexions des clients dun site Web. Le tableau C, ` n a lments, contient les identiants des clients qui se sont connects. Ainsi C[i] contient lidentiant du i-`me ee e e client ` stre connect, notez bien que si un client se connecte plusieurs fois, son identiant appara a e e tra plusieurs fois dans le tableau C. Le tableau D contient les dures de connexion. Ainsi D[i] est le temps e de connexion de la i-`me connexion. Le but est de dterminer, pour chaque, client, son temps total de e e connexion. Exercice 19 Ecrire le corps du sous-programme void decalageGauche(int T[], int a, int b), ce sous-programme dcale la tranche e T [a] T [a + 1] . . . T [b] dune case vers la gauche. Exercice 20 Ecrivez le corps de la fonction int calculeTempsTotalConnexionClient(int C[], int D[], int n, int i). calculeTempsTotalConnexionClient(C, D, n, i) retourne le temps total de connexion du client didentiant C[i], on suppose que i est lindice de la premi`re occurence de C[i] dans C. e Exercice 21 Ecrivez le corps de la fonction int supprimeDoublons(int C[], int D[], int n, int i). supprimeDoublons(C, D, n, i) supprime toutes les occurences (dindices strictement suprieurs ` i) du client didentiant C[i] e a dans C et D et retourne le nombre dlments supprims. Vous devrez utiliser decalageGauche. ee e Exercice 22

Ecrivez le corps de la fonction int tempsTotalDeConnexion(int C[], int D[], int n, int i). tempsTotalDeConn D, n, i) place dans D[i] le temps total de connexion du client C[i] et limine de C et de D toutes les e autres occurences de ce client. Cette fonction doit retourner le nombre dlments supprims. Vous devrez ee e utiliser calculeTempsTotalConnexionClient et supprimeDoublons. Exercice 23

Ecrire le corps du sous-programme int tempsTotauxDeConnexion(int C[], int D[], int n). tempsTotauxDeConne D, n) additionne les temps de connexions de chaque visiteur. Vous devrez modier C et D de sorte que chaque client nappara sse quune fois dans C et que D contienne pour chaque client son temps total. Cette fonction retourne le nombre dlments signicatifs dans C et D. Vous devrez utiliser ee tempsTotalDeConnexion.

98

2.6.6

Cha nes de caract`res e

Question 24 - achage Ecrivez une fonction void afficheChaine(char s[]) qui ache la cha de caract`re s sans utiliser ne e de %s. Question 25 - longueur Ecrivez une fonction int longueur(char s[]) qui retourne la longueur de la cha de caract`re s sans ne e utiliser strlen. Question 26 - extraction Ecrivez une fonction char extrait(char s[], int n) qui retourne le n-`me caract`re de s, vous considrerez e e e que les indices commencent ` 1. a Question 27 - substitution Ecrivez une fonction void subs(char s[], int n, char a) qui remplace le n-`me caract`re de s par e e a, vous considrerez que les indices commencent ` 1. e a

2.6.7

Programmation dun Pendu

Cette section a pour but la programmation dun pendu, vous tes invits ` utiliser les fonctions dnies e e a e ci-dessus. Question 28 - initialisation Ecrire une fonction void initialise(char t[], int n) qui place dans t n caract`res . e Question 29 - vrication e Ecrire une fonction void verifie(char t[], char k[], char c) qui recherche toutes les occurences du caract`re c dans t, soit i lindice dune occurrence de c dans t, alors cette fonction remplace le ie `me caract`re de k par c. Par exemple, si on invoque verifie(bonjour", b j r", o), alors k e e prendra la valeur "bo jo r. Question 30 - Le jeu Programmez un pendu, faites le plus simplement possible, et utilisez les fonctions ci-dessus..

2.6.8

Tris

Exercice 31 - Tri ` bulle a 1. Ecrivez le corps de la fonction void echange(int T[], int a, int b), echange(T, a, b) change e les lments T [a] et T [b]. ee 2. Ecrivez le corps de la fonction void ordonne(int T[], int a, int b), ordonne(T, a, b) change e les lments T [a] et T [b] si T [a] > T [b]. Vous utliserez le sous-programme echange. ee 3. Ecrivez le corps de la fonction void bulle(int T[], int a, int b), bulle(T, a, b) place le plus grand lment de la tranche T [a] T [a + 1] . . . T [b] dans T [b]. Vous utiliserez le sous-programme ee ordonne. 4. Ecrivez le corps de la fonction void triBulle(int T[], int n), triBulle(T, n) tri le tableau T ` a n lments. Vous utiliserez le sous-programme bulle. ee

99

Exercice 32 - Tri par slection e 1. Implmentez la fonction int indiceDuMin(int T[], int i, int j) retournant lindice du plus e petit lment de T(i), ..., T(j), cest-`-dire de tous les lments du tableau dont lindice est ee a ee compris entre i et j. 2. Implmentez le sous-programme void placeMin(int T[], int i, int j, int k) changeant avec e e T(k) le plus petit lment de T dont lindice est compris entre i et j. ee 3. Le tri par slection est une mthode consistant ` rechercher dans un tableau T ` n lments le e e a a ee plus petit lment du tableau et a lchanger avec le T (1). Puis ` chercher dans T (2), . . . , T (N ) le ee ` e a deuxi`me plus petit lment et a lchanger avec T (2), etc. Une fois un tri par slection achev, e ee ` e e e les lments du tableau doivent tre disposs par ordre croissant. Ecrivez le sous-programme void ee e e triParSelection(int T[], int N).

100

2.7
2.7.1

Structures
Prise en main

Exercice 1 Crez un type structur st contenant un char appel c et un int appel i. e e e e Exercice 2 Crez deux variables k et l de type st. Aectez-leur les valeurs ( a , 1) et ( b , 2). e Exercice 3 Achez les valeurs de tous les champs de ces deux variables.

2.7.2

Heures de la journe e

Nous utiliserons pour reprsenter des heures de la journe au format hh : mm le type e e typedef struct { int h e u r e ; int minute ; } heure t ; Le champ heure devra contenir une valeur de {0, 1, . . . , 11} et le champ minute une valeur de {0, 1, 2, . . . , 59}. Compltez le code source suivant : e
#include<s t d i o . h> typedef s t r u c t { int heure ; i n t minute ; } heure t ; / / / Retourne uen s t r u c t u r e i n i t i a l i s e e ave c l e s v a l e u r s h e u r e s e t minutes . / h e u r e t creerHeure ( int heures , int minutes ) { h e u r e t r e s u l t = {0 , 0}; return r e s u l t ; } / / / C o n v e r t i t t en minutes . / i n t enMinu tes ( h e u r e t t ) { return 0 ; } / / / C o n v e r t i t l a duree t en h e u r e t . / h e u r e t enHeures ( int t ) { h e u r e t r e s u l t = {0 , 0}; return r e s u l t ; }

101

/ / / A f f i c h e x au format hh :mm / void a f f i c h e H e u r e ( h e u r e t x ) { } / / / Additionne a e t b . / heure t additionneHeures ( heure t a , { h e u r e t r e s u l t = {0 , 0}; return r e s u l t ; } heure t b)

/ / / Retourne l a v a l e u r a a j o u t e r a x pour o b t e n i r 0 0 : 0 0 . / heure t inverseHeure ( heure t x) { h e u r e t r e s u l t = {0 , 0}; return r e s u l t ; } / / / Soustrait b a a . / heure t soustraitHeures ( heure t a , { h e u r e t r e s u l t = {0 , 0}; return r e s u l t ; } heure t b)

/ / / Retourne 1 s i a > b , 1 s i a < b , 0 s i a = b . / i n t compareHeures ( h e u r e t a , { return 0 ; } heure t b)

/ / / Retourne l a p l u s / h e u r e t minHeure ( h e u r e t a , { h e u r e t r e s u l t = {0 , 0}; return r e s u l t ; } heure t b) p e t i t e des heures a e t b .

/ / / Pour t e s t e r / i n t main ( ) { return 0 ; } les fonctions . . .

102

2.7.3

Rpertoire tlphonique e ee

Nous considrons les dclarations suivantes : e e #include<s t d i o . h> #include<s t d l i b . h> #include<s t r i n g . h> #define TAILLE NOM 50 #define TAILLE TEL 10 #define NB MAX NOMS 500 struct p e r s o n n e { char nom [ TAILLE NOM+ 1 ] ; char t e l [ TAILLE TEL + 1 ] ; }; Il vous est demand de programmer un rpertoire tlphonique en stockant les entres du rpertoire dans e e e e e un tableau de structpersonne. Les entres devront tre tries, il devra tre possible de rechercher des e e e e entres avec le prxe du nom, insrer et supprimer des entres. Prvoyez aussi la possibilit dacher e e e e e e toutes les entres du rpertoire les unes ` la suite des autres. Bon courage. e e a

103

2.8
2.8.1

Pointeurs
Aliasing

Exercice 1 Ecrivez un programme dclarant une variable i de type int et une variable p de type pointeur sur int. e Achez les dix premiers nombres entiers en : nincrmentant que i e nachant que p Exercice 2 Mme exercice en e nincrmentant que p e nachant que i Exercice 3 Dterminez ce quache ce programme, excutez-ensuite pour vrier. e e e #include<s t d i o . h> main ( ) { int i = 4 ; int j = 1 0 ; int p ; int q ; p = &i ; q = &j ; p r i n t f ( i = %d , p = p + q ; p r i n t f ( i = %d , p = &j ; p r i n t f ( i = %d , q = q + p ; p r i n t f ( i = %d , q = &i ; p r i n t f ( i = %d , i = 4; p r i n t f ( i = %d , q = q + 1 ; p r i n t f ( i = %d , }

j = %d , p = %d , q = %d\n , i , j , p , q ) ; j = %d , p = %d , q = %d\n , i , j , p , q ) ; j = %d , p = %d , q = %d\n , i , j , p , q ) ; j = %d , p = %d , q = %d\n , i , j , p , q ) ; j = %d , p = %d , q = %d\n , i , j , p , q ) ; j = %d , p = %d , q = %d\n , i , j , p , q ) ; j = %d , p = %d , q = %d\n , i , j , p , q ) ;

2.8.2

Tableaux

Exercice 4 - prise en main Ecrire un programme qui place dans un tableau t les N premiers nombres impairs, puis qui ache le tableau. Vous accderez ` llment dindice i de t avec lexpression (t + i). e a ee Exercice 5 - Tri ` bulle a Ecrire un sous-programme triant un tableau t avec la mthode du tri ` bulle. Vous accderez ` llment e a e a ee dindice i de t avec lexpression (t + i).

104

2.8.3

Exercices sans sous-programmes

Exercice 6 - Tableaux de carrs e Ecrire un programme qui demande ` lutilisateur de saisir un nombre n, et qui place les n premiers a nombres impairs dans un tableau t. Utilisez ensuite le fait que k 2 est la somme des k premiers nombres impairs pour calculer puis acher les n premiers nombres carrs. e Exercice 7 - Matrices et pointeurs de pointeurs Ecrivez un programme qui demande ` lutilisateur de saisir un nombre n et qui cre une matrice T de a e dimensions n n avec un tableau de n tableaux de chacun n lments. Nous noterons tij le j-`me lment ee e ee du i-`me tableau. Vous initialiserez T de la sorte : pour tous i, j, tij = 1 si i = j (les lments de la e ee diagonale) et tij = 0 si i = j (les autres lments). Puis vous acherez T . ee Exercice 8 - Copie de cha nes de caract`res e Ecrivez un programme qui saisit proprement une cha de caract`re s et qui la recopie dans un tableau ne e cre avec malloc et de contenance correspondant exactement ` la longueur de s. Vous nutiliserez ni e a strlen, ni strcpy. Exercice 9 - Tableau de cha nes Reprennez le programme prcdent en saissisant successivement 4 cha e e nes de caract`res et en les stockant e dans un tableau de cha nes de caract`res. e

2.8.4

Allocation dynamique

Exercice 10 - Prise en main Crez dynamiquement un int, aectez-y la valeur 5, achez-le, librez la mmoire. e e e Exercice 11 - Tableaux sur mesure Demandez ` lutilisateur la taille du tableau quil souhaite crer, allouez dynamiquement lespace ncessaire a e e et placez-y les valeurs {0, . . . n 1}, achez-le et librez la mmoire. e e

2.8.5

Pointeurs et pointeurs de pointeurs

Exercice 12 - Tableaux sur mesure Quache le programme suivant : #include<s t d i o . h> int main ( ) { long A, B, C, D; long p1 , p2 , p3 ; long pp ; A = 10 ; B = 20 ; C = 30 ; D = 40; p1 = &A; p2 = &B ; p3 = &B ; p1 = ( p1 + 1 ) ;

105

p3 = ( p2 + D) ; p3 = &C ; p3 = ( p2 + D) ; p r i n t f ( A = %ld , B = %ld , C = %ld , D = %l d \n , A, B, C, D) ; pp = &p3 ; p r i n t f ( %l d \n , pp ) ; return 0 ; }

2.8.6

Passages de param`tres par rfrence e ee

Exercice 13 Dterminez ce quache ce programme, excutez-ensuite pour vrier. e e e #include<s t d i o . h> void a f f i c h e 2 i n t ( int a , int b ) { p r i n t f ( %d , %d\n , a , b ) ; } void i n c r 1 ( int x ) { x = x + 1; } void i n c r 2 ( int x ) { x = x + 1 ; } void d e c r 1 ( int x ) { x = x 1; } void d e c r 2 ( int x ) { x = x 1 ; } main ( ) { int i = 1 ; int j = 1 ; affiche2int (i , i n c r 2 (& i ) ; affiche2int (i , d e c r 1 (& j ) ; affiche2int (i , d e c r 2 (& j ) ; affiche2int (i , while ( i != j ) {

j ); j ); j ); j );

106

incr1 ( j ); d e c r 2 (& i ) ; } affiche2int (i , j ); } Exercice 14 Ecrivez le corps du sous-programme additionne, celui-ci doit placer dans res la valeur i + j. #include<s t d i o . h> void a d d i t i o n n e ( int a , int b , int r e s ) { / E c r i v e z l e c o r p s du sousprogramme i c i /

} main ( ) { int i = 2 ; int j = 3 ; int k ; a d d i t i o n n e ( i , j , &k ) ; p r i n t f ( k = %d\n , k ) ; // d o i t a f f i c h e r k = 5 } Exercice 15 Ecrivez le sous-programme void puissance(int b, int n, int* res), qui place dans la variable pointe e par res le rsultat de bn . e Exercice 16 Ecrivez le sous-programme void tri(int* a, int* b, int* c) qui permute les valeurs de a, b et c de sorte que a b c. Vous utiliserez le sous-programme void echange(int* x, int* y).

2.8.7

Les pointeurs sans toile e

Le but de cet exercice est dencapsuler les acc`s ` la mmoire par le biais des pointeurs dans des fonctions. e a e Ecrivez le corps des fonctions suivantes : 1. int getIntVal(int* p) retourne la valeur se trouvant ` ladresse p. a 2. void setIntVal(int* p, int val) aecte la valeur val ` la variable pointe par p. a e 3. int* getTiAdr(int* t, int i) retourne ladresse de llment T [i] ee 4. int getTiVal(int* t, int i) retourne la valeur de llment T [i], vous utiliserez getTiAdr et ee getIntVal 5. void setTiVal(int* t, int i, int val) aecte ` T [i] la valeur val, vous utiliserez getTiAdr a et setIntVal. 6. void swapInt(int* a, int* b) change les valeurs des variables pointes par a et b. Vous utilie e serez getIntVal et setIntVal. 7. void swapTij(int* t, int i, int j) change les valeurs T [i] et T [j], vous utiliserez swapInt et e getTiAdr. Ecrivez le corps de la fonction de tri void sort(int* t, int n) de votre choix en utilisant au mieux les fonctions ci-dessus. 107

2.8.8

Tableau de tableaux

Le but de cet exercice est de crer n tableaux de chacun m lments, de placer les n pointeurs ainsi e ee obtenus dans un tableau de pointeurs T de type int et de manier T comme un tableau ` deux indices. a Ecrivez les corps des fonctions suivantes : 1. int** getTi Adr(int** T, int i) retourne ladresse du pointeur vers le i-`me tableau dint de e T. e 2. int* getTi (int** T, int i) retourne le i-`me tableau dint de T , vous utiliserez getTi Adr. e 3. void setT Adr(int** T, int* p) place dans la variable pointe par T le pointeur p. 4. void setTi (int** T, int i, int* p) fait de p le i-`me tableau de T , vous utiliserez getT Adr e et setTi Adr ee 5. void createT (int** T, int n, int m) fait pointer chacun des n lments de T vers un tableau a ` m lments. Vous utiliserez setTi Adr. ee Nous noterons Tij le j-`me lment du tableau T [i]. Pour tous (i, j) {1, . . . , 10}2 , le but est de placer e ee dans tij la valeur 10i+j. Vous utiliserez les fonctions int getIntVal(int* p), void setIntVal(int* p, int val), int* getTiAdr(int* t, int i), int getTiVal(int* t, int i) et void setTiVal(int* t, int i, int val) pour crire les corps des sous-programmes ci-dessous : e 1. int* getTijAdr(int** t, int i, int j) retourne ladresse de Tij 2. int getTijVal(int** t, int i, int j) retourne la valeur de Tij 3. void setTijVal(int** t, int i, int j, int val) aecte ` Tij la valeur val. a

2.8.9

Triangle de Pascal

En utilisant les sous-programmes ci-dessus, ecrire un programme qui demande ` lutilisateur un nombre a n, puis qui cre un triangle de Pascal ` n + 1 lignes, et qui pour nir ache ce triangle de Pascal. Vous e a utiliserez les sous-programmes dnis dans les questions prcdentes et rdigerez des sous-programmes e e e e les plus simples possibles (courts, le moins dtoiles possible). e

2.8.10

Pointeurs et rcursivit e e

Vous rdigerez toutes les fonctions suivantes sous forme itrative, puis rcursive. e e e 1. Ecrire une fonction void initTab(int* t, int n) plaant dans le tableau t les lments 1, 2, . . . , n. c ee 2. Ecrire une fonction void printTab(int* t, int n) achant les n lments du tableau t. ee 3. Ecrire une fonction int sommeTab(int* t, int n) retournant la somme des n lments du tableau ee t. 4. Ecrire une fonction (ni rcursive, ni itrative) void swap(int* t, int i, int j)changeant les e e e lments dindices i et j du tableau t. ee 5. Ecrire une fonction void mirrorTab(int* t, int n) inversant lordre des lments du tableau t. ee 6. Ecrire une fonction int find(int* t, int n, int x) retournant 1 si x se trouve dans le tableau t ` n lments, 0 sinon. a ee 7. Ecrire une fonction int distinctValues(int* t, int n) retournant le nombre de valeurs distinctes du tableau t ` n lments. Le nombre de valeurs distinctes sobtient en comptant une seule a ee fois chaque valeur du tableau si elle appara plusieurs fois. Par exemple, les valeurs distinctes de t {1, 2, 2, 3, 9, 4, 3, 7} sont {1, 2, 3, 4, 7, 9} et il y en a 6. En utilisant les exercices sur les heures dans la section structures, vous rdigerez les fonctions suivantes e sous forme rcursive. e 1. Ecrire une fonction void afficheTabHeures(heure t* t, int n) achant les n heures de t. 2. Ecrire une fonction void initTabHeures(heure t* t, int n, heure t depart, heure t pas) initialisant le tableau t ` n lments comme suit : la premi`re heure est depart et chaque heure a ee e sobtient ` additionnant pas ` la prcdente. a a e e 108

3. Ecrire une fonction heure t sommeTabHeures(heure t* t, int n) retournant la somme des n heures du tableau t. 4. Ecrire une fonction heure t minTabHeure(heure t* t, int n) retournant la plus petite des n heures du tableau t.

2.8.11

Tri fusion

Compltez le code suivant : e


#include<s t d i o . h> #include<s t d l i b . h> #include<t i m e . h> #d e f i n e MOD 10000 / / / Affiche / void p r i n t T a b ( i n t t , i n t n ) { i f (n > 0) { p r i n t f ( %d , t ) ; printTab ( t + 1 , n 1 ) ; } else p r i n t f ( \n ) ; } / / / P l a c e n e l e m e n t s a l e a t o i r e s de v a l e u r s maximales MOD 1 dans l e t a b l e a u t . / void i n i t T a b ( i n t t , i n t n ) { i f (n > 0) { t = rand ()%MOD; initTab ( t + 1 , n 1 ) ; } } / / / Retourne un t a b l e a u de n e l e m e n t s a l l o u e dynamiquement . / int createTab ( int n) { int t = ( int ) malloc ( sizeof ( int )n ) ; i f ( t == NULL) { p r i n t f ( no memory a v a l a i b l e \n ) ; exit (0); } return t ; } / / / L i b e r e l a zone memoire p o i n t e e par t e t met ce p o i n t e u r a NULL. / void d e s t r o y T a b ( i n t t ) { f r e e ( t ) ; t = NULL ; } l e s n e l e m e n t s du t a b l e a u t .

109

/ / / ( Recursive ) Retourne l i n d i c e du p l u s p e t i t e l e m e n t du t a b l e a u t a n e l e m e n t s . A f f i c h e une e r r e u r s i l e t a b l e a u e s t v i d e . / i n t indexOfMin ( i n t t , i n t n ) { return 0 ; } / / / Echange l e s e l e m e n t s x e t y . / void swap ( i n t x , i n t y ) { i n t temp = x ; x = y ; y = temp ; } / / / Echange l e p l u s p e t i t e l e m e n t du t a b l e a u t a n e l e m e n t s a vec l e premier . / void swapMin ( i n t t , i n t n ) { } / / / ( Recursive ) Trie l e t a b l e a u t a n e l e m e n t s ave c l a methode du t r i par s e l e c t i o n . / void s e l e c t i o n S o r t ( i n t t , i n t n ) { } / / / ( Recursive ) Recopie l e s n e l e m e n t s du t a b l e a u s o u r c e a l adresse dest . / void copyTab ( i n t s o u r c e , i n t d e s t , i n t n ) { } / / / ( Recursive ) I n t e r c l a s s e l e s n1 e l e m e n t s de s o u r c e 1 ave c l e s n2 e l e m e n t s de s o u r c e 2 . source1 e t source2 sont supposes t r i e s . L in ter clas sem ent se f a i t en d i s p o s a n t c e s e l e m e n t s dans l o r d r e dans l e t a b l e a u d e s t . / void s h u f f l e T a b ( i n t s o u r c e 1 , i n t s o u r c e 2 , i n t d e s t , i n t n1 , i n t n2 ) { } / / / Trie l e s n e l e m e n t s de t ave c l a methode du t r i fusion .

110

/ void f u s i o n S o r t ( i n t t , i n t n ) { } / / / Compare l e s performances en temps de c a l c u l d e s t r i s par s e l e c t i o n e t par f u s i o n . / int compareSorts ( int f i r s t V a l u e , int lastValue , int step ) { int i ; int s t ar t , stop ; i n t t , q ; s r a n d ( t i m e (NULL ) ) ; f o r ( i = f i r s t V a l u e ; i <= l a s t V a l u e ; i += s t e p ) { p r i n t f ( w i t h %d e l e m e n t s : \n , i ) ; t = createTab ( i ) ; q = createTab ( i ) ; initTab ( t , i ) ; copyTab ( t , q , i ) ; s t a r t = t i m e (NULL ) ; selectionSort (t , i ); s t o p = t i m e (NULL ) ; p r i n t f ( s e l e c t i o n s o r t : %d\n , s t o p s t a r t ) ; d e s t r o y T a b (& t ) ; s t a r t = t i m e (NULL ) ; fusionSort (q , i ) ; s t o p = t i m e (NULL ) ; p r i n t f ( f u s i o n s o r t : %d\n , s t o p s t a r t ) ; d e s t r o y T a b (&q ) ; } return 0 ; } / / / Pour t e s t e r ecrites . . . / i n t main ( ) { compareSorts (10000 , 500000 , 1 0 0 0 ) ; return 0 ; } les f o n c t i o n s au f u r e t a mesure qu e l l e s sont

111

2.9
2.9.1

Fichiers
Ouverture et fermeture

Exercice 1 - touch La commande shell touch permet de crer un chier vide. Ecrire un programme prenant le nom dun e chier en ligne de commande et le crant. e

2.9.2

Lecture

Exercice 2 - more La commande shell more permet dacher le contenu dun chier. Ecrire un programme prenant le nom dun chier en ligne de commande et achant son contenu.

2.9.3

Ecriture

Exercice 3 - Alphabet Ecrire un programme C alphabet permettant de crer un chier. Le nom du chier cre sera pass e e e en ligne de commande et le chier contiendra lalphabet. Exercice 4 - Initialiser un chier Ecrire un programme C createFile permettant de crer un chier. Le nom du chier cre sera le e e premier des arguments, tous les arguments suivants seront crits dans le chier. Par exemple, la commande e ./createFile toto.txt ceci est le contenu de mon fichier doit crer un chier appel toto.txt e e et contenant le texte ceci est le contenu de mon fichier

2.9.4

Lecture et criture e

Exercice 5 - cp La commande shell cp permet dacher le contenu dun chier. Ecrire un programme prenant en ligne de commande le nom dun chier source et celui dun chier de destination, et recopiant le contenu du chier source dans celui de destination. Exercice 6 - Liste de noms Ecrire deux programmes storeNames et getNames. storeNames demande ` lutilisateur de saisir une a liste de noms et les enregistre au fur et ` mesure quils sont saisis dans un chier dont le nom a t pass a ee e en ligne de commande au lancement du programme. On arrte le programme en saisissant 1. getNames e ache la liste des noms stocke dans le chier dont le nom est pass en ligne de commande. e e

2.9.5

Enigma

Complter le chier source suivant : e


#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e NB ROTORS 5 #d e f i n e NB LETTERS 26 #d e f i n e FORWARD 1 #d e f i n e BACKWARD 2 / / typedef s t r u c t r o t o r

112

{ char p e r m u t a t i o n [ NB LETTERS ] ; char p e r m u t a t i o n I n v e r s e [ NB LETTERS ] ; char p o s i t i o n ; } rotor ; / / typedef s t r u c t enigma { r o t o r r o t o r s [ NB ROTORS ] ; char m i r r o r [ NB LETTERS ] ; } enigma ; / / / Dispose tous l e s / void i n i t i a l i s e R o t o r s ( enigma e ) { } / / / L i b e r e l a memoire occupee par e . / void e n i g m a D e s t r o y ( enigma e ) { } / / / A l l o u e l a memoire e t / enigma e n i g m a C r e a t e ( ) { return NULL ; } / / / Retourne l e rang de l e t t e r dans l a l p h a b e t , en i n d i c a n t a p a r t i r de 0 . / char i n d e x O f L e t t e r ( char l e t t e r ) { return 0 ; } / / / Retourne l a l e t t r e d i n d i c e i n d e x dans l a l p h a b e t , a est d indice 0. / char l e t t e r O f I n d e x ( char i n d e x ) { return 0 ; } / / / F a i t de l a l e t t r e c i p h e r L e t t e r l image de l a l e t t r e d i n d i c e c l e a r I n d e x par un p a s s a g e dans l e r o t o r d i n d i c e r o t o r I n d e x de e . / void s e t I m a g e ( enigma e , i n t r o t o r I n d e x , i n t c l e a r I n d e x , char c i p h e r L e t t e r ) { } initialise l e s champs . r o t o r s dans l e u r p o s i t i o n de d e p a r t .

113

/ / / F a i t de f i r s t L e t t e r / le r e f l e t de s e c o n d L e t t e r .

void s e t M i r r o r ( enigma e , char f i r s t L e t t e r , char s e c o n d L e t t e r ) { } / / / Retourne v r a i s i e t s e u l e m e n t s i de l a l p h a b e t . / i n t i s E n c r y p t a b l e ( char l e t t e r ) { return 0 ; } / / / Affiche / void e n i g m a P r i n t ( enigma e ) { } / / / F a i t p i v o t e r l e r o t o r d i n d i c e indexOfRotor de e en m o d i f i a n t sa p o s i t i o n de d e p a r t . Retourne v r a i s s i l e r o t o r e s t revenu dans sa p o s i t i o n initiale . / i n t r o t a t e R o t o r ( enigma e , i n t i n d e x O f R o t o r ) { return 0 ; } / / / Fait pivoter / void r o t a t e R o t o r s ( enigma e ) { } / / / I n d i c e d e n t r e e de l a l e t t r e d i n d i c e i n d e x O f L e t t e r dans l e r o t o r r , en t e n a n t compte de l a p o s i t i o n de ce r o t o r . / int inputIndex ( r o t o r r , int indexOfLetter ) { return 0 ; } / / / I n d i c e de l a l e t t r e s o r t i e a l i n d i c e i n d e x O f L e t t e r du r o t o r r , en t e n a n t compte de l a p o s i t i o n de ce r o t o r . / int outputIndex ( r o t o r r , int indexOfLetter ) { return 0 ; } l e j e u de r o t o r s de e d une p o s i t i o n . les r o t o r s e t l e m i r o i r de e . letter e s t une m i n u s c u l e

114

/ / / F a i t p a s s e r l a l e t t r e d i n d i c e i n d e x O f L e t t e r dans r dans l a d i r e c t i o n d i r e c t i o n (FORWARD ou BACKWARD) . / i n t r o t o r E n c r y p t ( r o t o r r , i n t i n d e x O f L e t t e r , char d i r e c t i o n ) { return 0 ; } / / / F a i t p a s s e r l a l e t t r e d i n d i c e i n d e x O f L e t t e r dans l e m i r o i r de e . / i n t m i r r o r E n c r y p t ( enigma e , i n t i n d e x O f L e t t e r ) { return 0 ; } / / / Chiffre de e . . / char enigmaEncrypt ( enigma e , char l e t t e r ) { return 0 ; } / / / C h i f f r e l e f i c h i e r clearFName av ec e , dans cipherFName . / void e n c r y p t F i l e ( enigma e , char clearFName , char cipherFName ) { } / / / I n i t i l i a l i s e l e s NB ROTORS r o t o r s de e av ec deux e c r i t s dans l e f i c h i e r r o t o r s . / void l o a d R o t o r s ( enigma e , FILE r o t o r s ) { } / / / Initilialise / l e m i r o i r de e av ec une l i g n e du f i c h i e r rotors . ecrit le resultat l e t t e r a vec e , fait ensuite pivoter les rotors

void l o a d M i r r o r ( enigma e , FILE r o t o r s ) { } / / / Cree une machine enigma i n i t i a l i s e e av ec l e contenu du f i c h i e r rotorFileName . / enigma l o a d F i l e ( char r o t o r F i l e N a m e ) { return NULL ; }

115

/ / / C h i f f r e l e f i c h i e r c l e a r a vec l a machine enigma d e c r i t e dans r o t o r s , e c r i t l e r e s u l t a t dans c i p h e r . / void enigmaRun ( char c l e a r , char c i p h e r , char r o t o r s ) { enigma e = l o a d F i l e ( r o t o r s ) ; encryptFile (e , clear , cipher ) ; enigmaDestroy ( e ) ; } / / i n t main ( i n t a r g c , char a r g v [ ] ) { i f ( a r g c == 4 ) enigmaRun ( a r g v [ 1 ] , a r g v [ 2 ] , a r g v [ 3 ] ) ; else p r i n t f ( u s a g e : . / enigma s o u r c e c i p h e r return 0 ; } klmnopqvwxyzgabcdefhijrstu uvwxystzabcdejklmnopqrfghi klmnopqabcdvwxyzgstuefhijr zgabcdefklmnopqvhijrstuwxy tuklmnopqvwxyzgabcdefhijrs wzgabchijrmdefynopqvstuklx

r o t o r f i l e \n ) ;

Que contient le message suivant ? (attention, les accents sachent mal...)


Bobuq , u y n l myck i p y v p zA c mjbA c l r l p k n zvw e y w b o v t s s i !

116

2.10

Matrices

Exercice 1 - identite Ecrire une fonction initialisant une matrice identite dordre n. Exercice 2 - somme Ecrire une fonction calculant la somme de deux matrices. Exercice 3 - transposition Ecrire une fonction calculant la matrice transpose dune matrice N M passe en param`tre. e e e Exercice 4 - produit Ecrire une fonction calculant le produit de deux matrices N M et M P passes en param`tre. e e Exercice 5 - triangle de Pascal Un triangle de Pascal peut tre plac dans une matrice contenant des 1 sur la premi`re colonne et la e e e diagonale, et tel que chaque lment m[i][j] de la matrice soit la somme des lments m[i 1][j 1] et ee ee m[i1][j]. Seule la partie triangulaire infrieure dun triangle de Pascal contient des valeurs signicatives. e Ecrire une fonction initialisant un triangle de Pascal ` n lignes. a Exercice 6 - Matrice marrante Ecrire une fonction plaant dans chaque emplacement dindices (i, j) dune matrice la valeur (i + 1)j . c Vous utiliserez le fait que (i + 1)j = P (0, j)i0 + P (1, j)i1 + P (1, j)i1 + . . . + P (k, j)ik + . . . + P (j, j)ij o` P (a, b) est llment se trouvant ` la colonne a et ` la ligne b du triangle de Pascal. u ee a a

117

2.11
2.11.1

Listes Cha ees n


Pointeurs et structures

Exercice 1 Crer un type st contenant un champ i de type int et un champ c de type char. Dclarez une variable e e p de type st*, allouez dynamiquement une variable de type st et faites pointer p dessus. Aectez ` cette a variable les valeurs 5 et a. Achez-les, librez la mmoire. e e

2.11.2

Maniement du cha nage

Exercice 2 - prise en main Etant donn le programme e #include<s t d i o . h> / / typedef struct m a i l l o n { int data ; struct m a i l l o n next ; } maillon ; / / int main ( ) { m a i l l o n m, p ; maillon ptr ; m. data = 1 ; m. next = &p ; p . data = 2 ; p . next = NULL; f o r ( p t r = & ; p t r != NULL ; p t r = ptr>next ) m p r i n t f ( data = %d\n , ptr>data ) ; return 0 ; } Reprennez ce programme : crez deux maillons q et r en renseignant les champ data aux valeurs respectives e 3 et 4, renseignez les valeurs next des maillons de sorte que la boucle f or ache data data data data = = = = 1 2 3 4

Exercice 3 - tableaux Reprennez le programme #include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> #define N 10

118

/ / typedef struct m a i l l o n { int data ; struct m a i l l o n next ; } maillon ; / / void p r i n t D a t a ( m a i l l o n p t r ) { f o r ( ; p t r != NULL ; p t r = ptr>next ) p r i n t f ( data = %d\n , ptr>data ) ; } / / int main ( ) { maillon l ; int i ; l = ( m a i l l o n ) m a l l o c (N s i z e o f ( m a i l l o n ) ) ; i f ( l == NULL) exit (0); l >data = 0 ; f o r ( i = 1 ; i < N ; i ++) { ( l + i )>data = i ; ( l + i 1)>next = l + i ; } ( l + N 1)>next = NULL; printData ( l ) ; free ( l ); return 0 ; } Modiez le cha nage de sorte que les maillons soient disposs dans lordre inverse et que, par consquent, e e ce programme ache : data data data data data data data data data data = = = = = = = = = = 9 8 7 6 5 3 4 2 1 0

119

2.11.3

Oprations sur les listes cha ees e n

Exercice 4 - ajout dun lment ` la n ee a Erire le corps de la fonction suivante : m a i l l o n i n s e r e F i n L L ( m a i l l o n l , int n ) Vous insrerez un maillon contenant la valeur n ` la n de la liste dont le premier lment est point par e a ee e l. Vous retournerez un pointeur vers le premier lment de la liste. ee Exercice 5 - copie dune liste cha ee n Erire le corps de la fonction suivante : m a i l l o n copyLL ( m a i l l o n s o u r c e ) Vous copierez la liste l et retournerez un pointeur vers le premier lment de la copie. Vous avez le droit ee dutiliser insereFinLL. Exercice 6 - inversion de lordre des lments ee Ecrivez un sous-programme qui inverse lordre des lments dune liste cha ee, et qui retourne un pointeur ee n sur le premier lment de la liste nouvellement forme. ee e

2.11.4

Listes doublement cha ees n

Nous dnissons comme suit une liste doublement cha ee e n #include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> #define N 10 / / typedef struct d m a i l l o n { int data ; struct d m a i l l o n p r e v i o u s ; struct d m a i l l o n next ; } dmaillon ; / / typedef struct d L i n k e d L i s t { struct d m a i l l o n f i r s t ; struct d m a i l l o n l a s t ; } dLinkedList ; Implmentez les fonctions suivantes : e 1. void printDLL(dLinkedList* dl) ache les lments dune liste cha ee. ee n 2. void freeDLL(dLinkedList* dl) lib`re tous les maillons, puis lib`re dl. e e 3. dLinkedList* makeDLL() alloue la mmoire pour une dLinkedList, initialise les pointeurs ` NULL e a 4. dmaillon* makeDMaillon(int n) cre un maillon contenant la valeur n. e

120

5. void appendDMaillonDLL(dLinkedList* dl, dmaillon* m) accroche le maillon m ` la n de la a liste cha ee dl n 6. void pushDMaillonDLL(dLinkedList* dl, dmaillon* m) accroche le maillon m au dbut de la e liste cha ee dl n 7. void appendIntDLL(dLinkedList* dl, int n) ajoute ` la n de dl un maillon contenant la a valeur n. 8. void pushIntDLL(dLinkedList* dl, int n) ajoute au dbut de dl un maillon contenant la valeur e n. 9. void initDLL(dLinkedList* dl, int n) place dans la liste doublement cha ee les valeurs {0, ..., n n 1} 10. void reverseDLL(dLinkedList* dl) inverse lordre des lments de dl. ee 11. dLinkedList* copyDLL(dLinkedList* source) retourne une copie de source. 12. void concatDLL(dLinkedList* debut, dLinkedList* fin) concat`ne fin ` la suite de debut, e a vide la liste fin .

2.11.5

Fonctions rcursives et listes cha ees e n

Compltez le code sources suivant. Les boucles sont interdites ! e


#include<s t d i o . h> / Dans t o u t e s l e s f o n c t i o n s A p a r t i r d i n s e r e , i l e s t i n t e r d i t de creer des maillons , t o u t e s ces operations doivent se f a i r e par m o d i f i c a t i o n du c h a i n a g e e t non par r e c o p i e . / typedef s t r u c t l l s { int data ; struct l l s next ; }ll ; / / / A l l o u e dynamiquement e t i n i t i a l i s e un m a i l l o n a vec l e s v a l e u r s d a t a e t next , r e t o u r n e son a d r e s s e . / l l c r e e r ( i n t data , { return NULL ; } l l next )

/ / / Affiche l e maillon l / void a f f i c h e ( l l l ) { } / / / A f f i c h e , dans l ordre , t o u s l e s m a i l l o n s de l a / void a f f i c h e T o u t ( l l l ) { } / / / A f f i c h e en p a r t a n t de l a f i n t o u s l e s m a i l l o n s de l a l i s t e l . / liste l.

121

void a f f i c h e A L E n v e r s ( l l l ) { } / / / D e t r u i t t o u s l e s m a i l l o n s de l a a NULL. / void d e t r u i t ( l l l ) { } / / / Retourne l a / l l entiersALEnvers ( int n) { return NULL ; } / / / Retourne l a / l l e n t i e r s ( int n) { return NULL ; } / / / I n s e r e l e m a i l l o n x dans l a / l l insere ( l l l , { return NULL ; } l l x) liste l , supposee t r i e e . l i s t e 1 > 2 > . . . > n l i s t e n > n1 > . . . > 2 > 1 l i s t e l , met ce p o i n t e u r

/ / / Tri l a l i s t e l av ec l a methode du t r i par i n s e r t i o n , r e t o u r n e l a d r e s s e du premier e l e m e n t de l a l i s t e t r i e e . / ll triInsertion ( ll l ) { return NULL ; } / / / R e p a r t i t l e s e l e m e n t s de l e n t r e l e s l i s t e s ex : l = 1 > 2 > 3 > 4 > 5 nous donne l 1 = 5 > 3 > 1 e t l 2 = 4 > 2 / void s p l i t ( l l l , { } l l l 1 , l l l 2 ) l1 et l2 .

/ / / Retourne l i n t e r c l a s s e m e n t d e s / l l i n t e r c l a s s e ( l l l1 , { l l l2 ) listes l 1 et l2 , supposees t r i e e s .

122

return NULL ; } / / / Trie l ave c l a methode du t r i f u s i o n , r e t o r u n e l a d r e s s e du premier e l e m e n t de l a l i s t e t r i e e . / l l triFusion ( l l l ) { return NULL ; } / / / Pour t e s t e r / i n t main ( ) { return 0 ; } les fonctions . . .

123

Annexe A

Quelques corrigs e
A.1
A.1.1

Variables et oprateurs e
Entiers

Saisie et achage
#include<s t d i o . h> i n t main ( ) { int a ; p r i n t f ( S a i s s i s s e z une v a l e u r : ) ; s c a n f ( %d , &a ) ; p r i n t f ( Vous a v e z s a i s i l a v a l e u r %d\n , a ) ; return 0 ; }

Permutation de 2 variables
#include<s t d i o . h> i n t main ( ) { i n t a , b , temp ; p r i n t f ( S a i s s i s s e z l e s v a l e u r s de 2 v a r i a b l e s : \ nA = ) ; s c a n f ( %d , &a ) ; p r i n t f ( B = ) ; s c a n f ( %d , &b ) ; temp = a ; a = b; b = temp ; p r i n t f ( Apres p e r m u t a t i o n , l e s v a l e u r s d e s v a r i a b l e s s o n t : \nA = %d\nB = %d\n , a , b ) ; return 0 ; }

Permutation de 4 valeurs
#include<s t d i o . h> i n t main ( ) { i n t a , b , c , d , temp ; printf ( Saississez les s c a n f ( %d , &a ) ; p r i n t f ( B = ) ; s c a n f ( %d , &b ) ; p r i n t f ( C = ) ; s c a n f ( %d , &c ) ; p r i n t f ( D = ) ; s c a n f ( %d , &d ) ; temp = a ; a = c; c = temp ; temp = b ;

v a l e u r s de 4 v a r i a b l e s

: \ nA = ) ;

124

b = d; d = temp ; p r i n t f ( Apres p e r m u t a t i o n , l e s v a l e u r s d e s v a r i a b l e s s o n t : \nA = %d\nB = %d\nC = %d\nD = %d\n , a , b , c , d ) ; return 0 ; }

Permutation de 5 valeurs
#include<s t d i o . h> i n t main ( ) { i n t a , b , c , d , e , temp ; p r i n t f ( S a i s s i s s e z l e s v a l e u r s de 5 v a r i a b l e s : \ nA = ) ; s c a n f ( %d , &a ) ; p r i n t f ( B = ) ; s c a n f ( %d , &b ) ; p r i n t f ( C = ) ; s c a n f ( %d , &c ) ; p r i n t f ( D = ) ; s c a n f ( %d , &d ) ; p r i n t f ( E = ) ; s c a n f ( %d , &e ) ; temp = d ; d = a; a = temp ; temp = b ; b = c; c = e; e = temp ; p r i n t f ( Apres p e r m u t a t i o n , l e s v a l e u r s d e s v a r i a b l e s s o n t : \nA = %d\nB = %d\nC = %d\nD = %d\nE = %d\n , a, b, c , d, e ); return 0 ; }

A.1.2

Flottants

Saisie et achage
#include<s t d i o . h> i n t main ( ) { float a ; p r i n t f ( S a i s s i s s e z une v a l e u r : ) ; s c a n f ( %f , &a ) ; p r i n t f ( Vous a v e z s a i s i l a v a l e u r %f \n , a ) ; return 0 ; }

Moyenne arithmtique e
#include<s t d i o . h> i n t main ( ) { f l o a t a , b , c , moyenne ; p r i n t f ( S a i s s i s s e z 3 v a l e u r s : \ n1 : ) ; s c a n f ( %f , &a ) ; p r i n t f ( 2 : ) ; s c a n f ( %f , &b ) ; p r i n t f ( 3 : ) ; s c a n f ( %f , &c ) ; moyenne = ( a + b + c ) / 3 . ; p r i n t f ( La moyenne de c e s t r o i s v a l e u r s return 0 ; }

e s t %f . \ n , moyenne ) ;

Surface du rectangle
#include<s t d i o . h> i n t main ( ) { float largeur , longueur , printf ( largeur : );

surface ;

125

s c a n f ( %f , &l a r g e u r ) ; p r i n t f ( longueur : ) ; s c a n f ( %f , &l o n g u e u r ) ; surface = largeur longueur ; p r i n t f ( La s u r f a c e de c e r e c t a n g l e return 0 ; }

e s t %f . \ n , s u r f a c e ) ;

Moyennes arithmtique et gomtrique e e e


#include<s t d i o . h> #include<math . h> i n t main ( ) { float a , b , arithmetique , geometrique ; p r i n t f ( S a i s s e z deux v a l e u r s : \ nA : ) ; s c a n f ( %f , &a ) ; p r i n t f ( B : ) ; s c a n f ( %f , &b ) ; arithmetique = (a + b )/2; geometrique = sqrt ( a b ) ; p r i n t f ( La moyenne a r i t h m e t i q u e de c e s deux v a l e u r s e s t %f . \ nLa moyenne g e o m e t r i q e %f \nLa d i f f e r e n c e e n t r e c e s deux v a l e u r s %f . \ n , a r i t h m e t i q u e , g e o m e t r i q u e , arithmetique geometrique ) ; return 0 ; }

A.1.3

Caract`res e

Prise en main
#include<s t d i o . h> i n t main ( ) { char a ; p r i n t f ( S a i s s i s s e z un c a r a c t e r e : ) ; s c a n f ( %c , &a ) ; p r i n t f ( Vous a v e z s a i s i l a v a l e u r %c , son c o d e ASCII e s t %d . \ n , a , a ) ; return 0 ; }

Successeur
#include<s t d i o . h> i n t main ( ) { char a ; p r i n t f ( S a i s s i s s e z un c a r a c t e r e : ) ; s c a n f ( %c , &a ) ; a = a + 1; p r i n t f ( Le c a r a c t e r e s u i v a n t e s t %c \n , a ) ; return 0 ; }

Casse
#include<s t d i o . h> i n t main ( ) { char a ; p r i n t f ( S a i s s i s s e z une m i n u s c u l e : ) ; s c a n f ( %c , &a ) ; p r i n t f ( C e t t e l e t t r e a pour m a j u s c u l e %c . \ n , a + A a ) ; return 0 ; }

Codes ASCII
#include<s t d i o . h> i n t main ( ) {

126

char c = 0 ; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour c++; p r i n t f ( %c a pour return 0 ; }

c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ; c o d e ASCII %d\n , c , c ) ;

A.1.4

Oprations binaires e

Codage dadresses IP
#include<s t d i o . h> i n t main ( ) { unsigned long i p = 0 , masque = 2 5 5 ; unsigned short o c t e t 1 , o c t e t 2 , o c t e t 3 , o c t e t 4 ; p r i n t f ( S a i s s i s s e z l e s q u a t r e c h i f f r e s de l a d r e s s e IP \n Premiere valeur : ) ; s c a n f ( %hu , &o c t e t 1 ) ; ip = octet1 ; ip < <= 8 ; p r i n t f ( Deuxieme v a l e u r : ) ; s c a n f ( %hu , &o c t e t 2 ) ; i p |= o c t e t 2 ; ip < <= 8 ; p r i n t f ( Troisieme valeur : ) ; s c a n f ( %hu , &o c t e t 3 ) ; i p |= o c t e t 3 ; ip < <= 8 ; p r i n t f ( Quatrieme v a l e u r : ) ; s c a n f ( %hu , &o c t e t 4 ) ; i p |= o c t e t 4 ; p r i n t f ( C e t t e IP s e c o d e en l o n g s o u s l a f o r m e %l u . \ n , i p ) ; p r i n t f ( Vous r em arq ue z qu i l e s t p o s s i b l e de l a r e t r o u v e r : ) ; o c t e t 4 = i p & masque ; ip > >= 8 ; o c t e t 3 = i p & masque ; ip > >= 8 ; o c t e t 2 = i p & masque ; ip > >= 8 ; o c t e t 1 = i p & masque ; p r i n t f ( %hu.%hu.%hu.%hu\n , o c t e t 1 , o c t e t 2 , o c t e t 3 , o c t e t 4 ) ; return 0 ; }

Permutation circulaire des bits


#include<s t d i o . h> i n t main ( ) { unsigned short s , f i r s t B i t ; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %hu , &s ) ; f i r s t B i t = s & 1; s > >= 1 ; f i r s t B i t <<=7; s |= f i r s t B i t ; p r i n t f ( Apres p e r m u t a t i o n c i r c u l a i r e %hu\n , s ) ; return 0 ; }

des bits ,

cette valeur est

127

Permutation de 2 octets
#include<s t d i o . h> i n t main ( ) { unsigned i n t u , temp ; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %u , &u ) ; temp = u & 2 5 5 ; temp < <= 8 ; u > >= 8 ; u |= temp ; p r i n t f ( Apres p e r m u t a t i o n c i r c u l a i r e %u\n , u ) ; return 0 ; }

des octets ,

cette valeur est

Permutation de 4 octets
#include<s t d i o . h> i n t main ( ) { unsigned long l ; unsigned short o c t e t 1 , o c t e t 2 , o c t e t 3 , o c t e t 4 ; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %l u , &l ) ; o c t e t 4 = 255 & l ; l > >= 8 ; o c t e t 3 = 255 & l ; l > >= 8 ; o c t e t 2 = 255 & l ; l > >= 8 ; o c t e t 1 = 255 & l ; l = octet4 ; l < <= 8 ; l |= o c t e t 3 ; l < <= 8 ; l |= o c t e t 2 ; l < <= 8 ; l |= o c t e t 1 ; p r i n t f ( Apres p e r m u t a t i o n c i r c u l a i r e d e s o c t e t s , %l u \n , l ) ; return 0 ; }

cette valeur est

A.1.5

Morceaux choisis

Pi`ces de monnaie e
#include<s t d i o . h> #d e f i n e EPS 0 . 0 0 1 i n t main ( ) { float valeur ; int nbPieces ; p r i n t f ( S a i s s e z l a somme : ) ; s c a n f ( %f , &v a l e u r ) ; p r i n t f ( Pour l a payer , vous a u r e z b e s o i n de : \ n ) ; // n b P i e c e s = ( v a l e u r + EPS) / 0 . 5 ; p r i n t f ( %d p i e c e ( s ) de 0 . 5 e u r o s \n , n b P i e c e s ) ; v a l e u r = n b P i e c e s 0 . 5 ; // n b P i e c e s = ( v a l e u r + EPS) / 0 . 2 ; p r i n t f ( %d p i e c e ( s ) de 0 . 2 e u r o s \n , n b P i e c e s ) ; v a l e u r = n b P i e c e s 0 . 2 ; // n b P i e c e s = ( v a l e u r + EPS) / 0 . 1 ; p r i n t f ( %d p i e c e ( s ) de 0 . 1 e u r o s \n , n b P i e c e s ) ; v a l e u r = n b P i e c e s 0 . 1 ; // n b P i e c e s = ( v a l e u r + EPS) / 0 . 0 5 ; p r i n t f ( %d p i e c e ( s ) de 0 . 0 5 e u r o s \n , n b P i e c e s ) ; v a l e u r = n b P i e c e s 0 . 0 5 ; //

128

n b P i e c e s = ( v a l e u r + EPS) / p r i n t f ( %d p i e c e ( s ) de 0 . 0 2 v a l e u r = n b P i e c e s 0 . 0 2 ; // n b P i e c e s = ( v a l e u r + EPS) / p r i n t f ( %d p i e c e ( s ) de 0 . 0 1 v a l e u r = n b P i e c e s 0 . 0 1 ; return 0 ; }

0.02; e u r o s \n , n b P i e c e s ) ;

0.01; e u r o s \n , n b P i e c e s ) ;

Dernier bit
#include<s t d i o . h> i n t main ( ) { unsigned short s , s S a n s D e r n i e r B i t , d e r n i e r B i t ; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %hu , &s ) ; sSansDernierBit = ( s & 254); dernierBit = ( s & 1); dernierBit = dernierBit & 1; s = sSansDernierBit | dernierBit ; p r i n t f ( Apres m o d i f i c a t i o n du d e r n i e r b i t , c e t t e v a l e u r e s t %hu\n , s ) ; return 0 ; }

Permutation sans variable temporaire


#include<s t d i o . h> i n t main ( ) { int a , b ; p r i n t f ( S a i s s i s s e z l e s v a l e u r s de 2 v a r i a b l e s : \ nA = ) ; s c a n f ( %d , &a ) ; // notons x c e t t e v a l e u r , a = x p r i n t f ( B = ) ; s c a n f ( %d , &b ) ; // notons y c e t t e v a l e u r , b = y a = b ; // a = x y , b = y b = a ; // a = x y , b = ya = y x y = x a = b ; // a = x y x = y , b = y p r i n t f ( Apres p e r m u t a t i o n , l e s v a l e u r s d e s v a r i a b l e s s o n t : \nA = %d\nB = %d\n , a , b ) ; return 0 ; }

129

A.2
A.2.1

Traitements conditionnel
Prise en Main

Majorit e
#include<s t d i o . h> i n t main ( ) { unsigned short a g e ; p r i n t f ( T a s q u e l a g e ?\ n ) ; s c a n f ( %hu , &a g e ) ; i f ( a g e >= 1 8 ) p r i n t f ( T e s majeur . ) ; else p r i n t f ( T e s mineur . ) ; p r i n t f ( \n ) ; return 0 ; }

Valeur absolue
#include<s t d i o . h> i n t main ( ) { float a ; p r i n t f ( S a i s i s s e z une v a l e u r \n ) ; s c a n f ( %f , &a ) ; p r i n t f ( La v a l e u r a b s o l u e de %f e s t , a ) ; i f ( a < 0) a = a ; p r i n t f ( %f . \ n , a ) ; return 0 ; }

Admissions
#include<s t d i o . h> i n t main ( ) { float note ; p r i n t f ( S a i s i s s e z v o t r e n o t e \n ) ; s c a n f ( %f , &n o t e ) ; i f ( note < 8) p r i n t f ( Ajourne ) ; i f ( n o t e >= 8 && n o t e < 1 0 ) p r i n t f ( Rattrapage ) ; i f ( n o t e >= 1 0 ) p r i n t f ( Admis ) ; p r i n t f ( \n ) ; return 0 ; }

Assurance
#include<s t d i o . h> i n t main ( ) { f l o a t dommages , f r a n c h i s e , remboursement ; p r i n t f ( S a i s i s s e z l e montant d e s dommages\n ) ; s c a n f ( %f , &dommages ) ; f r a n c h i s e = dommages 0 . 1 ; i f ( f r a n c h i s e > 4000) franchise = 4000; remboursement = dommages f r a n c h i s e ; p r i n t f ( Montant de l a f r a n c h i s e : %.2 f \n , f r a n c h i s e ) ; p r i n t f ( Montant r e m b o u r s e : %.2 f \n , remboursement ) ; return 0 ; }

Valeurs distinctes parmi 2

130

#include<s t d i o . h> i n t main ( ) { int a , b ; p r i n t f ( S a i s i s s e z deux v a l e u r s : \ na = ) ; s c a n f ( %d , &a ) ; p r i n t f ( b = ) ; s c a n f ( %d , &b ) ; i f ( a == b ) p r i n t f ( Vous a v e z s a i s i deux f o i s l a meme v a l e u r . ) ; else p r i n t f ( Vous a v e z s a i s i deux v a l e u r s d i s t i n c t e s . ) ; p r i n t f ( \n ) ; return 0 ; }

Plus petite valeur parmi 3


#include<s t d i o . h> i n t main ( ) { i n t a , b , c , min ; p r i n t f ( S a i s i s s e z t r o i s v a l e u r s : \ na = ) ; s c a n f ( %d , &a ) ; p r i n t f ( b = ) ; s c a n f ( %d , &b ) ; printf (c = ) ; s c a n f ( %d , &c ) ; min = a ; i f ( b < min ) min = b ; i f ( c < min ) min = c ; p r i n t f ( La p l u s p e t i t e de c e s v a l e u r s e s t %d . , min ) ; p r i n t f ( \n ) ; return 0 ; }

Recherche de doublons
#include<s t d i o . h> i n t main ( ) { int a , b , c ; p r i n t f ( S a i s i s s e z t r o i s v a l e u r s : \ na = ) ; s c a n f ( %d , &a ) ; p r i n t f ( b = ) ; s c a n f ( %d , &b ) ; printf (c = ) ; s c a n f ( %d , &c ) ; i f ( a == b | | a == c | | b == c ) p r i n t f ( I l y a d e s d o u b l o n s dans l e s v a l e u r s que vous a v e z else p r i n t f ( Vous a v e z s a i s i t r o i s v a l e u r s d i s t i n c t e s ) ; p r i n t f ( \n ) ; return 0 ; }

saisies );

Valeurs distinctes parmi 3


#include<s t d i o . h> i n t main ( ) { i n t a , b , c , nbd ; p r i n t f ( S a i s i s s e z t r o i s v a l e u r s : \ na = ) ; s c a n f ( %d , &a ) ; p r i n t f ( b = ) ; s c a n f ( %d , &b ) ; printf (c = ) ; s c a n f ( %d , &c ) ; i f ( a == b && a == c ) nbd = 1 ; else i f ( a == b | | a == c | | b == c ) nbd = 2 ;

131

else nbd = 3 ; p r i n t f ( I l y a %d v a l e u r ( s ) d i s t i n c t e ( s ) . \ n , nbd ) ; return 0 ; }

ax + b = 0
#include<s t d i o . h> i n t main ( ) { double a , b , x ; p r i n t f ( S a i s i s s e z l e s c o e f f i c i e n t s de l e q u a t i o n (E) : ax + b = 0\ na = ) ; s c a n f ( % l f , &a ) ; p r i n t f ( b = ) ; s c a n f ( % l f , &b ) ; i f ( a != 0 ) { x = b/ a ; p r i n t f ( La s o l u t i o n de (E) e s t x = % l f , x ) ; } else { i f ( b == 0 ) p r i n t f ( Tout r e e l e s t s o l u t i o n de (E) ) ; else p r i n t f ( (E) n a pas de s o l u t i o n ) ; } p r i n t f ( . \ n ) ; return 0 ; }

ax2 + bx + c = 0
#include<s t d i o . h> #include<math . h> i n t main ( ) { double a , b , c , x1 , x2 , d e l t a ; p r i n t f ( S a i s i s s e z l e s c o e f f i c i e n t s de l e q u a t i o n (E) : ax 2 + bx + c = 0\ na = ) ; s c a n f ( % l f , &a ) ; p r i n t f ( b = ) ; s c a n f ( % l f , &b ) ; printf (c = ) ; s c a n f ( % l f , &c ) ; i f ( a != 0 ) { d e l t a = bb 4 a c ; i f ( d e l t a > 0) { x1 = ( s q r t ( d e l t a ) b ) / ( 2 a ) ; x2 = ( s q r t ( d e l t a ) b ) / ( 2 a ) ; p r i n t f ( Les s o l u t i o n s de (E) s o n t % l f e t %f , x1 , x2 ) ; } else { i f ( d e l t a == 0 ) { x1 = ( b ) / ( 2 a ) ; p r i n t f ( La s o l u t i o n de (E) e s t x = % l f , x1 ) ; } else p r i n t f ( (E) n a pas de s o l u t i o n r e e l l e ) ; } } else { i f ( b != 0 ) { x1 = c /b ; p r i n t f ( La s o l u t i o n de (E) e s t x = % l f , x1 ) ; } else { i f ( c == 0 ) p r i n t f ( Tout r e e l e s t s o l u t i o n de (E) ) ; else

132

p r i n t f ( (E) n a pas de s o l u t i o n ) ; } } p r i n t f ( . \ n ) ; return 0 ; }

A.2.2

Switch

Calculatrice
#include<s t d i o . h> #include<s t d l i b . h> i n t main ( ) { f l o a t gauche , d r o i t e , r e s u l t a t ; int e r r e u r = 0 ; char o p e r a t e u r ; p r i n t f ( Operande gauche : ) ; s c a n f ( %f , &gauche ) ; getchar ( ) ; p r i n t f ( Operateur : ) ; s c a n f ( %c , &o p e r a t e u r ) ; p r i n t f ( Operande d r o i t : ) ; s c a n f ( %f , &d r o i t e ) ; getchar ( ) ; switch ( o p e r a t e u r ) { case + : r e s u l t a t = gauche + d r o i t e ; break ; case : r e s u l t a t = gauche d r o i t e ; break ; case / : r e s u l t a t = gauche / d r o i t e ; break ; case : r e s u l t a t = gauche d r o i t e ; break ; default : e r r e u r = 1 ; } if ( erreur ) p r i n t f ( S a i s i e e r r o n n e e . \ n ) ; else p r i n t f ( %.2 f%c %.2 f = %f \n , gauche , o p e r a t e u r , return 0 ; }

droite ,

resultat );

A.2.3

Heures et dates

Oprations sur les heures e


#include<s t d i o . h> i n t main ( ) { i n t heureDebut , h e u r e F i n , minuteDebut , minuteFin , heureEcart , minuteEcart ; p r i n t f ( Heure debut ( hh :mm) ? ) ; s c a n f ( %d:%d , &heureDebut , &minuteDebut ) ; p r i n t f ( Heure f i n ( hh :mm) ? ) ; s c a n f ( %d:%d , &h e u r e F i n , &minuteFin ) ; h e u r e E c a r t = h e u r e F i n heureDebut ; m i n u t e E c a r t = minuteFin minuteDebut ; i f ( minuteEcart < 0) { h e u r e E c a r t ; m i n u t e E c a r t += 6 0 ; } p r i n t f ( Duree de l i n t e r v a l l e : %2.2d : % 2 . 2 d\n , heureEcart , minuteEcart ) ; return 0 ; }

Le jour dapr`s e
#include<s t d i o . h> i n t main ( ) { i n t j o u r , mois , annee , nbJours , erreur = 0; p r i n t f ( S a i s i s s e z l a d a t e : ( j j /mm/ aaaa ) ) ; s c a n f ( %d/%d/%d , &j o u r , &mois , &annee ) ;

133

switch ( mois ) { case 1 : case 3 : case 5 : case 7 : case 8 : case 10 : case 1 2 : n b J o u r s = 3 1 ; break ; case 4 : case 6 : case 9 : case 11 : n b J o u r s = 3 0 ; break ; case 2 : i f ( annee % 4 | | ! ( annee % 1 0 0 ) ) nbJours = 2 8 ; else nbJours = 2 9 ; break ; default : erreur = 1; } if ( erreur ) { p r i n t f ( S a i s i e e r r o n n e e : %2.2d /%2.2 d /%4.4 d\n , j o u r , mois , annee ) ; return 1; } p r i n t f ( Le l e n d e m a i n du %2.2d /%2.2 d /%4.4 d e s t l e , j o u r , mois , annee ) ; j o u r ++; i f ( j o u r == n b J o u r s + 1 ) { jour = 1; mois++; i f ( mois == 1 3 ) { mois = 1 ; annee++; } } p r i n t f ( e s t l e %2.2d /%2.2 d /%4.4 d . \ n , j o u r , mois , annee ) ; return 0 ; }

A.2.4

Echiquier

Couleurs des cases


#include<s t d i o . h> i n t main ( ) { unsigned short i , j ; p r i n t f ( S a i s i s s e z l e s c o o r d o n n e e s de l a c a s e : \ n ) ; printf ( i = ); s c a n f ( %hu , &i ) ; printf (j = ); s c a n f ( %hu , &j ) ; p r i n t f ( La c a s e (%hu , %hu ) e s t , i , j ) ; i f ( ( i + j ) % 2 == 0 ) printf ( noire ); else p r i n t f ( blanche ) ; p r i n t f ( . \ n ) ; return 0 ; }

Cavalier
#include<s t d i o . h> #include<s t d l i b . h> i n t main ( ) { unsigned short iD , jD , iA , jA ; p r i n t f ( S a i s i s s e z l e s c o o r d o n n e e s de l a c a s e de d e p a r t : \n ) ; printf ( i = ); s c a n f ( %hu , &iD ) ; printf (j = ); s c a n f ( %hu , &jD ) ; p r i n t f ( S a i s i s s e z l e s c o o r d o n n e e s de l a c a s e de l a c a s e d a r r i v e e printf ( i = ); s c a n f ( %hu , &iA ) ; printf (j = ); s c a n f ( %hu , &jA ) ;

: \n ) ;

134

p r i n t f ( Le mouvement de c a v a l i e r (%hu , %hu ) > (%hu , %hu ) e s t , iD , jD , iA , jA ) ; i f ( ( ab s ( iA iD ) == 1 && abs ( jA jD ) == 2 ) | | ( abs ( iA iD ) == 2 && abs ( jA jD ) == 1 ) ) printf ( valide ); else printf ( invalide ); p r i n t f ( . \ n ) ; return 0 ; }

Autres pi`ces e
#include<s t d i o . h> #include<s t d l i b . h> i n t main ( ) { unsigned short iD , jD , iA , jA , p i e c e ; p r i n t f ( Q u e l l e p i e c e s o u h a i t e z vous d e p l a c e r ?n ) ; p r i n t f ( 0 = C a v a l i e r \n ) ; p r i n t f ( 1 = Tour \n ) ; p r i n t f ( 2 = Fou\n ) ; p r i n t f ( 3 = Damen ) ; p r i n t f ( 4 = Roi \n ) ; s c a n f ( %hu , &p i e c e ) ; p r i n t f ( S a i s i s s e z l e s c o o r d o n n e e s de l a c a s e de d e p a r t : \n ) ; printf ( i = ); s c a n f ( %hu , &iD ) ; i f ( iD<1 | | iD >8) { p r i n t f ( c o o r d o n n e e i n v a l i d e \n ) ; return 1 ; } printf (j = ); s c a n f ( %hu , &jD ) ; i f ( jD<1 | | jD >8) { p r i n t f ( c o o r d o n n e e i n v a l i d e \n ) ; return 1 ; } p r i n t f ( S a i s i s s e z l e s c o o r d o n n e e s de l a c a s e d a r r i v e e : \n ) ; printf ( i = ); s c a n f ( %hu , &iA ) ; i f ( iA<1 | | iA >8) { p r i n t f ( c o o r d o n n e e i n v a l i d e \n ) ; return 1 ; } printf (j = ); s c a n f ( %hu , &jD ) ; i f ( jD<1 | | jD >8) { p r i n t f ( c o o r d o n n e e i n v a l i d e \n ) ; return 1 ; } p r i n t f ( Le mouvement (%hu , %hu ) > (%hu , %hu ) e s t , iD , jD , iA , jA ) ; switch ( p i e c e ) { case 0 : i f ( ( ab s ( iA iD ) == 1 && abs ( jA jD ) == 2 ) | | ( abs ( iA iD ) == 2 && abs ( jA jD ) == 1 ) ) printf ( valide ); else printf ( invalide ); case 1 : i f ( iA == iD | | jA == jD ) printf ( valide ); else printf ( invalide ); case 2 : i f ( abs ( iA iD ) == ab s ( jA jD ) ) printf ( valide ); else printf ( invalide ); case 3 : i f ( iA == iD | | jA == jD | | abs ( iA iD ) == abs ( jA jD ) ) printf ( valide );

135

else printf ( invalide ); case 4 : i f ( abs ( iA iD ) <= 1 && a bs ( jA jD ) <= 1 ) printf ( valide ); else printf ( invalide ); d e f a u l t : p r i n t f ( System E r r o r . I t i s recommended t h a t you f o r m a t your hard d i s k . ) ; return 1 ; } p r i n t f ( . \ n ) ; return 0 ; }

A.2.5

Intervalles et rectangles

Intervalles bien forms e


#include<s t d i o . h> i n t main ( ) { f l o a t i n f , sup ; p r i n t f ( S a i s i r un i n t e r v a l l e ( [ xx , xx ] ) s c a n f ( %f , %f ] , &i n f , &sup ) ; p r i n t f ( Cet i n t e r v a l l e e s t ) ; i f ( i n f > sup ) p r i n t f ( mal ) ; else p r i n t f ( bien ) ; p r i n t f ( f o r m e . \ n ) ; return 0 ; }

[);

Appartenance ` un intervalle a
#include<s t d i o . h> i n t main ( ) { f l o a t i n f , sup , v a l e u r ; p r i n t f ( S a i s i r un i n t e r v a l l e ( [ xx , xx ] ) s c a n f ( %f , %f ] , &i n f , &sup ) ; if { p r i n t f ( Cet i n t e r v a l l e return 1; e s t mal f o r m e . \ n ) ; } p r i n t f ( S a i s i r une v a l e u r : ) ; s c a n f ( %f , &v a l e u r ) ; p r i n t f ( %f , v a l e u r ) ; i f ( i n f <= v a l e u r && v a l e u r <= sup ) printf ( appartient ) ; else p r i n t f ( n a p p a r t i e n t pa s ) ; p r i n t f ( a l i n t e r v a l l e [% f , %f ] . \ n , i n f , sup ) ; return 0 ; } ( i n f > sup )

[);

Intersections dintervalles
#include<s t d i o . h> AFFICHE INT ( i n f , sup ) \ p r i n t f ( [% f , %f ] , i n f , sup ) i n t main ( ) { f l o a t i n f 1 , sup1 , i n f 2 , sup2 , infIntersection , supIntersection ; int i n c l u s i o n 1 , i n c l u s i o n 2 , intersectionNonVide ; p r i n t f ( S a i s i r un i n t e r v a l l e ( [ xx , xx ] ) [ ) ; s c a n f ( %f , %f ] , &i n f 1 , &sup1 ) ; i f ( i n f 1 > sup1 ) { p r i n t f ( Cet i n t e r v a l l e e s t mal f o r m e . \ n ) ;

136

return 1; } p r i n t f ( S a i s i r un i n t e r v a l l e ( [ xx , xx ] ) [ ) ; s c a n f ( %f , %f ] , &i n f 2 , &sup2 ) ; i f ( i n f 2 > sup2 ) { p r i n t f ( Cet i n t e r v a l l e e s t mal f o r m e . \ n ) ; return 1; } i n c l u s i o n 1 = i n f 2 < i n f 1 && sup1 < sup2 ; i n c l u s i o n 2 = i n f 1 < i n f 2 && sup2 < sup1 ; infIntersection = ( inf1 > inf2 ) ? inf1 : inf2 ; s u p I n t e r s e c t i o n = ( sup1 < sup2 ) ? sup1 : sup2 ; intersectionNonVide = i n f I n t e r s e c t i o n < supIntersection ; AFFICHE INT ( i n f 1 , sup1 ) ; if ( inclusion1 ) prinftf ( est ); else p r i n f t f ( n e s t p as ) ; p r i n f t f ( i n c l u s dans ) ; AFFICHE INT ( i n f 2 , sup2 ) ; p r i n t f ( \n ) ; AFFICHE INT ( i n f 2 , sup2 ) ; if ( inclusion2 ) prinftf ( est ); else p r i n f t f ( n e s t p as ) ; p r i n f t f ( i n c l u s dans ) ; AFFICHE INT ( i n f 1 , sup1 ) ; p r i n t f ( \nL i n t e r s e c t i o n de ) ; AFFICHE INT ( i n f 1 , sup1 ) ; p r i n t f ( e t de ) ; AFFICHE INT ( i n f 2 , sup2 ) ; printf ( est ); i f ( intersectionNonVide ) p r i n f t f ( non ) ; p r i n t f ( v i d e . \ n ) ; return 0 ; }

Prprocesseur e
#include<s t d i o . h> #include<s t d l i b . h> / / #d e f i n e #d e f i n e #d e f i n e #d e f i n e #d e f i n e CAVALIER 0 TOUR 1 FOU 2 DAME 3 ROI 4

/ / #d e f i n e MAIN i n t main ( ) \ { / / #d e f i n e FINMAIN return 0 ; \ } / / #d e f i n e S I i f ( / / #d e f i n e ALORS ) { / / #d e f i n e SINON } e l s e { / / #d e f i n e FINSI } / / #d e f i n e SUIVANT( v a r ) switch ( v a r ) {

137

/ / #d e f i n e FINSUIVANT( d e f ) d e f a u l t : def }

/ / #d e f i n e CAS( v a l e u r , i n s t r u c t i o n s ) case v a l e u r break ; : instructions \

/ / \ #d e f i n e PIECES LIST p r i n t f ( %hu = C a v a l i e r \n , CAVALIER ) ; \ p r i n t f ( %hu = Tour \n , TOUR) ; \ p r i n t f ( %hu = Fou\n , FOU) ; \ p r i n t f ( %hu = Dame\n , DAME) ; \ p r i n t f ( %hu = Roi \n , ROI ) / / #d e f i n e CHECK COORD( i ) \ S I i <1 | | i >8 ALORS \ p r i n t f ( c o o r d o n n e e i n v a l i d e \n ) ; \ return 1 ; \ FINSI / / #d e f i n e GET VAR(A, B) \ p r i n t f ( A = ) ; \ s c a n f ( %hu , &B ) ; \ CHECK COORD(B ) ; / / #d e f i n e PRINT VALID p r i n t f ( v a l i d e ) / / #d e f i n e PRINT INVALID p r i n t f ( i n v a l i d e ) / / #d e f i n e FATAL ERROR p r i n t f ( System E r r o r . I t i s recommended t h a t \ you f o r m a t your hard d i s k . ) ; \ return 1 ; / / #d e f i n e S I cond PRINT SINON \ PRINT FINSI CONDITIONAL PRINT( cond ) \ ALORS \ VALID ; \ INVALID ; \

/ / MAIN unsigned short iD , jD , iA , jA , p i e c e ; p r i n t f ( Q u e l l e p i e c e s o u h a i t e z vous d e p l a c e r ?\ n ) ; PIECES LIST ; s c a n f ( %hu , &p i e c e ) ; p r i n t f ( S a i s i s s e z l e s c o o r d o n n e e s de l a c a s e de d e p a r t : \n ) ; GET VAR( i , iD ) ; GET VAR( j , jD ) ; p r i n t f ( S a i s i s s e z l e s c o o r d o n n e e s de l a c a s e d a r r i v e e : \n ) ; GET VAR( i , iA ) ; GET VAR( j , jA ) ; p r i n t f ( Le mouvement (%hu , %hu ) > (%hu , %hu ) e s t , iD , jD , iA , jA ) ; SUIVANT( p i e c e ) CAS(CAVALIER, CONDITIONAL PRINT( ( abs ( iA iD ) == 1 && abs ( jA jD ) == 2 ) | | ( abs ( iA iD ) == 2 && abs ( jA jD ) == 1 ) ) ; ) CAS(TOUR, CONDITIONAL PRINT( iA == iD | | jA == jD ) ; ) CAS(FOU,

138

CONDITIONAL PRINT ( abs ( iA iD ) == abs ( jA jD ) ) ; ) CAS(DAME, CONDITIONAL PRINT( iA == iD | | jA == jD | | abs ( iA iD ) == ab s ( jA jD ) ) ; ) CAS( ROI , CONDITIONAL PRINT ( abs ( iA iD ) <= 1 && a bs ( jA jD ) <= 1 ) ; ) FINSUIVANT(FATAL ERROR ; ) p r i n t f ( . \ n ) ; FINMAIN

A.2.6

Nombres et lettres

Conversion numrique franais e c


#include<s t d i o . h> #d e f i n e AFFICHE UNITE( i ) \ i f ( i == 1 ) p r i n t f ( un ) ; \ i f ( i == 2 ) p r i n t f ( deux ) ; \ i f ( i == 3 ) p r i n t f ( t r o i s ) ; \ i f ( i == 4 ) p r i n t f ( q u a t r e ) ; \ i f ( i == 5 ) p r i n t f ( c i n q ) ; \ i f ( i == 6 ) p r i n t f ( s i x ) ; \ i f ( i == 7 ) p r i n t f ( s e p t ) ; \ i f ( i == 8 ) p r i n t f ( h u i t ) ; \ i f ( i == 9 ) p r i n t f ( n e u f ) ; \ i f ( i == 1 0 ) p r i n t f ( d i x ) ; \ i f ( i == 1 1 ) p r i n t f ( o n z e ) ; \ i f ( i == 1 2 ) p r i n t f ( douze ) ; \ i f ( i == 1 3 ) p r i n t f ( t r e i z e ) ; \ i f ( i == 1 4 ) p r i n t f ( q u a t o r z e ) ; \ i f ( i == 1 5 ) p r i n t f ( q u i n z e ) ; \ i f ( i == 1 6 ) p r i n t f ( s e i z e ) ; \ i f ( i == 1 7 ) p r i n t f ( di xs e p t ) ; \ i f ( i == 1 8 ) p r i n t f ( di xh u i t ) ; \ i f ( i == 1 9 ) p r i n t f ( di xn e u f ) #d e f i n e AFFICHE DIZAINE ( i ) \ i f ( i == 2 ) p r i n t f ( v i n g t ) ; \ i f ( i == 3 ) p r i n t f ( t r e n t e ) ; \ i f ( i == 4 ) p r i n t f ( q u a r a n t e ) ; \ i f ( i == 5 ) p r i n t f ( c i n q u a n t e ) ; \ i f ( i == 6 ) p r i n t f ( s o i x a n t e ) ; \ i f ( i == 7 ) p r i n t f ( s o i x a n t e ) ; \ i f ( i == 8 ) p r i n t f ( q u a t r e v i n g t ) ; \ i f ( i == 9 ) p r i n t f ( q u a t r e v i n g t ) #d e f i n e AFFICHE TROIS CHIFFRES ( nb ) \ { \ unsigned long u n i t e s , d i z a i n e s , c e n t a i n e s , d e u x D e r n i e r s ; \ u n i t e s = ( nb ) % 1 0 ; \ d i z a i n e s = ( ( nb ) u n i t e s ) / 10 % 1 0 ; \ d e u x D e r n i e r s = 10 d i z a i n e s + u n i t e s ; \ c e n t a i n e s = ( ( nb ) ( nb )%100) / 100 % 1 0 ; \ i f ( c e n t a i n e s >= 2 ) \ {\ AFFICHE UNITE( c e n t a i n e s ) ; \ p r i n t f ( ) ; \ }\ i f ( c e n t a i n e s > 0)\ p r i n t f ( cent ) ; \ i f ( d e u x D e r n i e r s == 0 && c e n t a i n e s > 1 ) \ printf (s );\ i f ( c e n t a i n e s > 0 && d e u x D e r n i e r s != 0 ) \ p r i n t f ( ) ; \ i f ( d i z a i n e s > 1)\ {\ AFFICHE DIZAINE ( d i z a i n e s ) ; \ }\ i f ( d i z a i n e s == 8 && u n i t e s == 0 ) \ printf (s );\ i f ( ( d i z a i n e s > 1 && u n i t e s != 0 ) \ | | d i z a i n e s == 7 | | d i z a i n e s == 9 ) \ p r i n t f ( ) ; \ i f ( u n i t e s == 1 && \

139

d i z a i n e s < 7 && d i z a i n e s > 1 ) \ p r i n t f ( e t ) ; \ i f ( d i z a i n e s == 7 ) \ {\ \ AFFICHE UNITE( d e u x D e r n i e r s 6 0 ) ; }\ else \ i f ( d i z a i n e s == 9 ) \ {\ \ AFFICHE UNITE( d e u x D e r n i e r s 8 0 ) ; }\ else \ i f ( d i z a i n e s == 1 ) \ {\ AFFICHE UNITE( d e u x D e r n i e r s ) ; \ }\ else \ {\ AFFICHE UNITE( u n i t e s ) ; \ }\ } #d e f i n e AFFICHE TROIS CHIFFRES UNITE ( c , nom unite , v a l e u r u n i t e ) \ { \ i f ( c%( v a l e u r u n i t e m i l l e ) / v a l e u r u n i t e >= 2 ) \ {\ AFFICHE TROIS CHIFFRES ( c / v a l e u r u n i t e /%m i l l e / ) ; \ printf ( );\ p r i n t f ( %s s , n o m u n i t e ) ; \ }\ i f ( c%( v a l e u r u n i t e m i l l e ) >= v a l e u r u n i t e && c%( v a l e u r u n i t e m i l l e ) < 2 v a l e u r u n i t e ) \ {\ p r i n t f ( un %s , n o m u n i t e ) ; \ }\ } i n t main ( ) { unsigned long i = 2 0 1 0 0 0 0 0 0 1 , m i l l e = 1 0 0 0 ; p r i n t f ( S a i s i s s e z un nombre = ) ; s c a n f ( %l u , &i ) ; p r i n t f ( %10 l u : , i ) ; AFFICHE TROIS CHIFFRES UNITE ( i , m i l l i a r d , ( unsigned long ) 1 e9 ) ; AFFICHE TROIS CHIFFRES UNITE ( i , m i l l i o n , ( unsigned long ) 1 e6 ) ; i f ( i %( m i l l e m i l l e ) / m i l l e >= 2 ) { AFFICHE TROIS CHIFFRES ( i / m i l l e%m i l l e ) ; printf ( ); } i f ( i %( m i l l e m i l l e ) >= m i l l e ) printf ( mille ); AFFICHE TROIS CHIFFRES ( i%m i l l e ) ; i f ( i == 0 ) printf ( zero ) ; p r i n t f ( \n ) ; return 0 ; }

140

A.3
A.3.1

Boucles
Utilisation de toutes les boucles

Compte ` rebours (Tant que) a


#include<s t d i o . h> i n t main ( ) { unsigned i n t i ; p r i n t f ( S a i s i s s e z un nombre p o s i t i f s c a n f ( %u , &i ) ; while ( i > 0 ) { p r i n t f ( %u\n , i ) ; i ; } p r i n t f ( 0\n ) ; return 0 ; }

: );

Compte ` rebours (Rpter . . . jusqu`) a e e a


#include<s t d i o . h> i n t main ( ) { unsigned i n t i ; p r i n t f ( S a i s i s s e z un nombre p o s i t i f s c a n f ( %u , &i ) ; do { p r i n t f ( %u\n , i ) ; i ; } while ( i != 0 ) ; p r i n t f ( 0\n ) ; return 0 ; }

: );

Compte ` rebours (Pour) a


#include<s t d i o . h> i n t main ( ) { unsigned i n t i ; p r i n t f ( S a i s i s s e z un nombre p o s i t i f s c a n f ( %u , &i ) ; f o r ( ; i > 0 ; i ) p r i n t f ( %u\n , i ) ; p r i n t f ( 0\n ) ; return 0 ; }

: );

Factorielle (Tant que)


#include<s t d i o . h> i n t main ( ) { unsigned long n , i , r e s ; p r i n t f ( S a i s i s s e z un nombre p o s i t i f s c a n f ( %l u , &n ) ; res = 1; i = 1; while ( i <= n ) r e s = i ++; p r i n t f ( %l u ! = %l u \n , n , r e s ) ; return 0 ; }

: );

Factorielle (Rpter . . . jusqu`) e e a

141

#include<s t d i o . h> i n t main ( ) { unsigned long n , i , r e s ; p r i n t f ( S a i s i s s e z un nombre p o s i t i f s c a n f ( %l u , &n ) ; res = 1; i = 2; i f ( n != 0 ) do { r e s = i ; i ++; } while ( i <= n ) ; p r i n t f ( %l u ! = %l u \n , n , r e s ) ; return 0 ; }

: );

Factorielle (Pour)
#include<s t d i o . h> i n t main ( ) { unsigned long n , i , r e s ; p r i n t f ( S a i s i s s e z un nombre p o s i t i f s c a n f ( %l u , &n ) ; res = 1; f o r ( i = 1 ; i <= n ; i ++) r e s = i ; p r i n t f ( %l u ! = %l u \n , n , r e s ) ; return 0 ; }

: );

A.3.2

Choix de la boucle la plus approprie e

Table de Multiplication
#include<s t d i o . h> i n t main ( ) { unsigned short s , i ; p r i n t f ( S a i s i s s e z une v a l e u r p o s i t i v e : ) ; s c a n f ( %hu , &s ) ; f o r ( i = 1 ; i <= 10 ; i ++) p r i n t f ( %2.hu %2.hu = %2.hu\n , i , s , s i ) ; return 0 ; }

Tables de Multiplications
#include<s t d i o . h> i n t main ( ) { unsigned short i , j ; f o r ( i = 1 ; i <= 10 ; i ++) { f o r ( j = 1 ; j <= 10 ; j ++) p r i n t f ( %3.hu , i j ) ; p r i n t f ( \n ) ; } return 0 ; }

bn
#include<s t d i o . h> i n t main ( ) { double b , r e s ; unsigned short n ; p r i n t f ( S a i s i s s e z un nombre r e e l s c a n f ( % l f , &b ) ;

: );

142

p r i n t f ( S a i s i s s e z un nombre e n t i e r s c a n f ( %hu , &n ) ; p r i n t f ( % l f %hu = , b , n ) ; res = 1; while ( n > 0 ) { r e s = b ; n; } p r i n t f ( % l f \n , r e s ) ; return 0 ; }

positif

: );

A.3.3

Morceaux choisis

Approximation de 2
#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e EPS 1 e 20 #d e f i n e ABS( i ) ( ( i > 0 . ) ? i : i )

i n t main ( ) { double terme = 1 , s e r i e = 0 ; while (ABS( terme ) > EPS) { s e r i e += terme ; terme = 0 . 5 ; } p r i n t f ( 2 = %.12 l f a %.12 l f p r e s . \ n , s e r i e , EPS ) ; return 0 ; }

Approximation de e
#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e EPS 1 e 20 #d e f i n e ABS( i ) ( ( i > 0 . ) ? i : i )

i n t main ( ) { double terme = 1 . , s e r i e = 0 . , f a c t e u r = 1 . ; while (ABS( terme ) > EPS) { s e r i e += terme ; terme /= f a c t e u r ; f a c t e u r += 1 . ; } p r i n t f ( e = %.12 l f a %.12 l f p r e s . \ n , s e r i e , EPS ) ; return 0 ; }

Approximation de ex
#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e EPS 1 e 10 #d e f i n e ABS( i ) ( ( i > 0 . ) ? i : i )

i n t main ( ) { double terme = 1 . , s e r i e = 0 . , f a c t e u r = 1 . , x ; p r i n t f ( x = ) ; s c a n f ( % l f , &x ) ; while (ABS( terme ) > EPS) { s e r i e += terme ; terme = ( x/ f a c t e u r ) ; f a c t e u r += 1 . ; } p r i n t f ( e = %.12 l f a %.12 l f p r e s . \ n , s e r i e , EPS ) ;

143

return 0 ; }

Conversion dentiers en binaire


#include<s t d i o . h> i n t main ( ) { unsigned short s , i , mask = 1 , n b B i t s = s i z e o f ( unsigned short ) 8 ; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %hu , &s ) ; p r i n t f ( Sa r e p r A c s e n t a t i o n b i n a i r e e s t [ ) ; mask < <= n b B i t s 1 ; f o r ( i = n b B i t s ; i >= 1 ; i ) { i f ( ( i n b B i t s ) && ! ( i %8)) p r i n t f ( . ) ; p r i n t f ( %hu , ( s&mask ) ! = 0 ) ; mask>>=1; } p r i n t f ( ] \ n ) ; return 0 ; }

Converssion de dcimales en binaire e


#include<s t d i o . h> i n t main ( ) { double d ; p r i n t f ( S a i s i s s e z une v a l e u r e n t r e 0 e t 1 : ) ; s c a n f ( % l f , &d ) ; p r i n t f ( Sa r e p r A c s e n t a t i o n b i n a i r e e s t [ 0 . ) ; while ( d != 0 ) { d =2 ; p r i n t f ( %d , ( i n t ) ( d ) ) ; d = ( d>=1); } p r i n t f ( ] \ n ) ; return 0 ; }

Inversion de lordre des bits


#include<s t d i o . h> i n t main ( ) { short s , k ; unsigned short n b B i t s = s i z e o f ( unsigned short ) 8 , f i r s t M a s k = 1<<(n b B i t s 1) , l a s t M a s k =1 , firstBit , lastBit , result = 0; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %hu , &s ) ; f o r ( k = n b B i t s 1 ; k >= 1 ; k=2) { f i r s t B i t = firstMask & s ; l a s t B i t = lastMask & s ; firstBit > >= k ; lastBit < <= k ; r e s u l t |= f i r s t B i t | l a s t B i t ; f i r s t M a s k >>=1; l a s t M a s k <<=1; } p r i n t f ( Apr As i n v e r s i o n de l o r d r e d e s b i t s , l a v a l e u r que vous a v e z s a i s i e s t %hu . \ n , r e s u l t ) ; return 0 ; }

Joli carr e
#include<s t d i o . h> i n t main ( ) {

144

unsigned i n t i , j , n ; p r i n t f ( n = ) ; s c a n f ( %u , &n ) ; f o r ( i = 1 ; i <= n ; i ++) { f o r ( j = 1 ; j <= n ; j ++) p r i n t f ( X ) ; p r i n t f ( \n ) ; i f ( i != n ) p r i n t f ( \n ) ; } return 0 ; }

Racine carre par dichotomie e


#include<s t d i o . h> #d e f i n e EPS 1 e 10 i n t main ( ) { double x , i n f , sup , mid ; do { p r i n t f ( S a i s i s s e z une v a l e u r p o s i t i v e ou n u l l e : ) ; s c a n f ( % l f , &x ) ; } while ( x < 0 ) ; inf = 0; sup = x ; while ( sup i n f > EPS) { mid = ( i n f + sup ) / 2 ; i f ( midmid > x ) sup = mid ; else i n f = mid ; } p r i n t f ( La r a c i n e c a r r e de %.10 l f e s t %.10 l f ( e r r e u r +%.10 l f ) . \ n , x , ( i n f + sup ) / 2 , EPS ) ; return 0 ; }

145

A.4
A.4.1

Tableaux
Prise en main

Initialisation et Achage
#include<s t d i o . h> #d e f i n e n 10 i n t main ( ) { i n t T [N ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0 } ; int i ; f o r ( i = 0 ; i < N ; i ++) p r i n t f ( T[%d ] = %d\n , i , T [ i ] ) ; return 0 ; }

Initialisation avec une boucle


#include<s t d i o . h> #d e f i n e N 10 i n t main ( ) { i n t T [N ] ; int i ; f o r ( i = 0 ; i < N ; i ++) T[ i ] = i + 1 ; f o r ( i = 0 ; i < N ; i ++) p r i n t f ( T[%d ] = %d\n , i , T [ i ] ) ; return 0 ; }

Somme
#include<s t d i o . h> #d e f i n e N 10 i n t main ( ) { i n t T [N ] ; i n t i , somme = 0 ; f o r ( i = 0 ; i < N ; i ++) T[ i ] = i ; f o r ( i = 0 ; i < N ; i ++) somme += T [ i ] ; p r i n t f ( La somme d e s e l e m e n t s du t a b l e a u e s t %d\n , somme ) ; return 0 ; }

Recherche
#include<s t d i o . h> #d e f i n e N 10 i n t main ( ) { i n t T [N ] ; int i , t ; f o r ( i = 0 ; i < N ; i ++) T[ i ] = i ; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %d , &t ) ; i = 0; while ( i < N && T [ i ] != t ) i ++; i f ( i == N) p r i n t f ( %d ne s e t r o u v e pas dans l e t a b l e a u . \ n , t ) ; else p r i n t f ( %d s e t r o u v e dans l e t a b l e a u a l i n d i c e %d . \ n , t , return 0 ; }

i );

146

A.4.2

Indices

Permutation circulaire
#include<s t d i o . h> #d e f i n e N 10 i n t main ( ) { i n t T [N ] ; i n t i , temp ; for ( i = 0 ; i < T[ i ] = i + 1 ; temp = T [ 9 ] ; for ( i = N 1 ; T[ i ] = T[ i T [ 0 ] = temp ; for ( i = 0 ; i < p r i n t f ( T[%d ] return 0 ; }

N ;

i ++)

i >= 1 ; i ) 1]; N ; i ++) = %d\n , i , T [ i ] ) ;

Permutation circulaire sans deuxi`me tableau e


#include<s t d i o . h> #d e f i n e N 10 i n t main ( ) { i n t T [N ] , Q[ N ] ; int i ; f o r ( i = 0 ; i < N ; i ++) T[ i ] = i + 1 ; Q[ 0 ] = T[N 1 ] ; f o r ( i = 1 ; i < N ; i ++) Q[ i ] = T [ i 1 ] ; f o r ( i = 0 ; i < N ; i ++) p r i n t f ( Q[%d ] = %d\n , i , Q[ i ] ) ; return 0 ; }

Miroir
#include<s t d i o . h> #d e f i n e N 10 i n t main ( ) { i n t T [N ] ; i n t i , j , temp ; f o r ( i = 0 ; i < N ; i ++) T[ i ] = i + 1 ; i = 0 ; j = N 1; while ( i < j ) { temp = T [ i ] ; T[ i ] = T[ j ] ; T [ j ] = temp ; i ++; j ; } f o r ( i = 0 ; i < N ; i ++) p r i n t f ( T[%d ] = %d\n , i , T [ i ] ) ; return 0 ; }

A.4.3

Recherche squentielle e

Modication du tableau
#include<s t d i o . h> #d e f i n e N 20

147

i n t main ( ) { i n t T [N ] , i ; for ( i = 0 ; i < T[ i ] = i i % for ( i = 0 ; i < p r i n t f ( T[%d ] return 0 ; }

N ; i ++) 17; N ; i ++) = %d\n , i , T [ i ] ) ;

Min/max
#include<s t d i o . h> #d e f i n e N 20 i n t main ( ) { i n t T [N ] , i , min , max ; f o r ( i = 0 ; i < N ; i ++) T[ i ] = i i % 17; min = max = T [ 0 ] ; f o r ( i = 1 ; i < N ; i ++) { i f (T [ i ] > max ) max = T [ i ] ; i f (T [ i ] < min ) min = T [ i ] ; } p r i n t f ( Le p l u s p e t i t e l e m e n t e s t %d , return 0 ; }

le

p l u s grand e s t %d . \ n , min , max ) ;

Recherche squentielle e
#include<s t d i o . h> #d e f i n e N 20 i n t main ( ) { i n t T [N ] , i , t ; f o r ( i = 0 ; i < N ; i ++) T[ i ] = i i % 17; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %d , &t ) ; p r i n t f ( V o i c i l a l i s t e d e s i n d i c e s d e s o c c u r r e n c e s de %d dans l e t a b l e a u : \ n , t ) ; f o r ( i = 0 ; i < N ; i ++) i f (T [ i ] == t ) p r i n t f ( %d\n , i ) ; return 0 ; }

Recherche squentielle avec stockage des indices e


#include<s t d i o . h> #d e f i n e N 20 i n t main ( ) { i n t T [N ] , I [ N ] , i , t , nbV = 0 ; f o r ( i = 0 ; i < N ; i ++) T[ i ] = i i % 17; p r i n t f ( S a i s i s s e z une v a l e u r : ) ; s c a n f ( %d , &t ) ; f o r ( i = 0 ; i < N ; i ++) i f (T [ i ] == t ) I [ nbV++] = i ; i f ( nbV == 0 ) p r i n t f ( %d n e s t pas dans l e t a b l e a u . \ n , t ) ; else { p r i n t f ( %d a p p a r a i t dans l e t a b l e a u aux i n d i c e s f o r ( i = 0 ; i < nbV ; i ++) p r i n t f ( %d\n , I [ i ] ) ; } return 0 ; }

s u i v a n t s : \ n , t ) ;

148

A.4.4

Morceaux choisis

Pi`ces de monnaie e
#include<s t d i o . h> #d e f i n e N 6 #d e f i n e EPS 0 . 0 0 1 i n t main ( ) { f l o a t p i e c e s [ N ] = { 0 . 5 , 0 . 2 , 0 . 1 , 0 . 0 5 , 0 . 0 2 , 0 . 0 1 } , somme , r e s t e ; int i , nbPieces [N ] ; do { p r i n t f ( S a i s i s s e z une somme s t r i c t e m e n t p o s i t i v e : ) ; s c a n f ( %f , &somme ) ; } while ( somme <= 0 ) ; r e s t e = somme ; f o r ( i = 0 ; i < N ; i ++) { n b P i e c e s [ i ] = ( r e s t e+EPS) / p i e c e s [ i ] ; r e s t e = n b P i e c e s [ i ] p i e c e s [ i ] ; } p r i n t f ( Pour p a y e r c e t t e somme a v e c d e s p i e c e s , i l vous f a u d r a : ) ; f o r ( i = 0 ; i < N ; i ++) i f ( n b P i e c e s [ i ] != 0 ) p r i n t f ( %d p i e c e%s de %.2 f e u r o s \n , nbPieces [ i ] , ( ( nbPieces [ i ] > 1) ? s : ) , p i e c e s [ i ] ) ; return 0 ; }

Recherche de la tranche minimale en O(n3 )


#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e N 20 i n t main ( ) { i n t T [N ] , i , j , k ; i n t valeurTrancheMin , debutTrancheMin , finTrancheMin , v a l e u r T r a n c h e ; f o r ( i = 0 ; i < N ; i ++) { T [ i ] = random ()%27 1 1 ; p r i n t f ( T[%d ] = %d\n , i , T [ i ] ) ; } valeurTrancheMin = T [ 0 ] ; debutTrancheMin = 0 ; finTrancheMin = 0 ; for ( i = 0 ; i < N ; i ++) f o r ( j = i ; j < N ; j ++) { valeurTranche = 0 ; f o r ( k = i ; k <= j ; k++) v a l e u r T r a n c h e += T [ k ] ; i f ( valeurTranche < valeurTrancheMin ) { valeurTrancheMin = valeurTranche ; debutTrancheMin = i ; finTrancheMin = j ; } } p r i n t f ( La t r a n c h e m i n i m a l e e s t s i t u e e e n t r e l e s i n d i c e s %d e t %d\n , debutTrancheMin , f i n T r a n c h e M i n ) ; return 0 ; }

Recherche de la tranche minimale en O(n2 )


#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e N 20 i n t main ( ) { i n t T [N ] , i , j ; i n t valeurTrancheMin , debutTrancheMin , finTrancheMin , v a l e u r T r a n c h e ;

149

f o r ( i = 0 ; i < N ; i ++) { T [ i ] = random ()%27 1 1 ; p r i n t f ( T[%d ] = %d\n , i , T [ i ] ) ; } valeurTrancheMin = T [ 0 ] ; debutTrancheMin = 0 ; finTrancheMin = 0 ; for ( i = 0 ; i < N ; i ++) { valeurTranche = 0 ; f o r ( j = i ; j < N ; j ++) { v a l e u r T r a n c h e += T [ j ] ; i f ( valeurTranche < valeurTrancheMin ) { valeurTrancheMin = valeurTranche ; debutTrancheMin = i ; finTrancheMin = j ; } } } p r i n t f ( La t r a n c h e m i n i m a l e e s t s i t u e e e n t r e l e s debutTrancheMin , f i n T r a n c h e M i n ) ; return 0 ; }

i n d i c e s %d e t %d\n ,

Recherche de la tranche minimale en O(n)


#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e N 20 i n t main ( ) { i n t T [N ] , i ; i n t valeurTrancheMin , debutTrancheMin , f i n T r a n c h e M i n ; i n t va le u r T r a n c h e M i n A v e c I , debutTrancheMinAvecI , f i n T r a n c h e M i n A v e c I ; f o r ( i = 0 ; i < N ; i ++) { T [ i ] = random ()%27 1 1 ; p r i n t f ( T[%d ] = %d\n , i , T [ i ] ) ; } valeurTrancheMin = T [ 0 ] ; debutTrancheMin = 0 ; finTrancheMin = 0 ; valeurTrancheMinAvecI = T [ 0 ] ; debutTrancheMinAvecI = 0 ; finTrancheMinAvecI = 0 ; for ( i = 1 ; i < N ; i ++) { i f ( valeurTrancheMinAvecI > 0) { valeurTrancheMinAvecI = T[ i ] ; debutTrancheMinAvecI = i ; finTrancheMinAvecI = i ; } else { v a l e u r T r a n c h e M i n A v e c I += T [ i ] ; finTrancheMinAvecI = i ; } i f ( valeurTrancheMinAvecI < valeurTrancheMin ) { valeurTrancheMin = valeurTrancheMinAvecI ; debutTrancheMin = debutTrancheMinAvecI ; finTrancheMin = finTrancheMinAvecI ; } } p r i n t f ( La t r a n c h e m i n i m a l e e s t s i t u e e e n t r e l e s i n d i c e s %d e t %d\n , debutTrancheMin , f i n T r a n c h e M i n ) ; return 0 ; }

150

A.5
A.5.1

Cha nes de caract`res e


Prise en main

Achage
#include<s t d i o . h> i n t main ( ) { char s [ 6 4 ] = Les f r a m b o i s e s s o n t p e r c h e e s s u r l e t a b o u r e t de mon grandp e r e . ; p r i n t f ( %s \n , s ) ; return 0 ; }

Achage sans %s
#include<s t d i o . h> i n t main ( ) { char s [ 6 4 ] = Les f r a m b o i s e s s o n t p e r c h e e s s u r l e t a b o u r e t de mon grandp e r e . ; int i = 0 ; while ( s [ i ] != 0 ) p r i n t f ( %c , s [ i ++]); p r i n t f ( \n ) ; return 0 ; }

Longueur
#include<s t d i o . h> #d e f i n e BUFFER SIZE 150 #d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) i n t main ( ) { char s [ BUFFER SIZE ] ; int i = 0 ; f g e t s ( s , BUFFER SIZE , s t d i n ) ; while ( s [ i ] != 0 ) i ++; i f ( s [ i 1 ] != \n ) CLEAR BUFFER ; p r i n t f ( l o n g u e u r = %d\n , i ) ; return 0 ; }

Longueur sans retour chariot


#include<s t d i o . h> #d e f i n e BUFFER SIZE 150 #d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) i n t main ( ) { char s [ BUFFER SIZE ] ; int i = 0 ; f g e t s ( s , BUFFER SIZE , s t d i n ) ; while ( s [ i ] != 0 ) i ++; i f ( s [ i 1 ] != \n ) CLEAR BUFFER ; else { s [ i 1] = 0; i ; } p r i n t f ( l o n g u e u r = %d\n , i ) ; return 0 ; }

151

A.5.2
strcmp.c

Les fonctions de string.h

#include<s t d i o . h> #include<s t r i n g . h> #d e f i n e BUFFER SIZE 30 #d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) i n t main ( ) { char s [ BUFFER SIZE ] , t [ BUFFER SIZE ] ; int r ; p r i n t f ( S a i s i r une chaA R ne : \n ) ; f g e t s ( s , BUFFER SIZE , s t d i n ) ; i f ( s [ s t r l e n ( s ) 1 ] != \n ) CLEAR BUFFER ; else s [ strlen ( s ) 1] = 0; p r i n t f ( S a i s i r une a u t r e chaA R ne : \n ) ; f g e t s ( t , BUFFER SIZE , s t d i n ) ; i f ( t [ s t r l e n ( t ) 1 ] != \n ) CLEAR BUFFER ; t [ strlen ( t ) 1] = 0; p r i n t f ( %s , s ) ; r = strcmp ( s , t ) ; i f ( r == 0 ) p r i n t f ( = ) ; else i f ( r < 0) p r i n t f ( < ) ; else p r i n t f ( > ) ; p r i n t f ( %s \n , t ) ; return 0 ; }

strlen.c
#include<s t d i o . h> #include<s t r i n g . h> #d e f i n e BUFFER SIZE 30 #d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) i n t main ( ) { char s [ BUFFER SIZE ] , t [ BUFFER SIZE ] ; int r ; p r i n t f ( S a i s i r une chaA R ne : \n ) ; f g e t s ( s , BUFFER SIZE , s t d i n ) ; i f ( s [ s t r l e n ( s ) 1 ] != \n ) CLEAR BUFFER ; else s [ strlen ( s ) 1] = 0; p r i n t f ( S a i s i r une a u t r e chaA R ne : \n ) ; f g e t s ( t , BUFFER SIZE , s t d i n ) ; i f ( t [ s t r l e n ( t ) 1 ] != \n ) CLEAR BUFFER ; t [ strlen ( t ) 1] = 0; p r i n t f ( %s e s t , s ) ; r = strlen (s) strlen (t ); i f ( r == 0 ) printf ( aussi ); else i f ( r > 0) p r i n t f ( plus ) ; else p r i n t f ( moins ) ; p r i n t f ( l o n g u e que %s \n , t ) ; return 0 ; }

A.5.3

Morceaux choisis

Extensions
#include<s t d i o . h> #include<s t r i n g . h>

152

#d e f i n e BUFFER SIZE 100 #d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) i n t main ( ) { char s [ BUFFER SIZE ] ; int k , i ; p r i n t f ( S a i s i r une chaA R ne : \n ) ; f g e t s ( s , BUFFER SIZE , s t d i n ) ; i f ( s [ s t r l e n ( s ) 1 ] != \n ) CLEAR BUFFER ; else s [ strlen ( s ) 1] = 0; i = 1; k = 0; p r i n t f ( nom du f i c h i e r : ) ; while ( s [ k ] != 0 ) { i f ( s [ k ] == . ) p r i n t f ( \n%deme e x t e n s i o n : , i ++); else p r i n t f ( %c , s [ k ] ) ; k++; } p r i n t f ( \n ) ; return 0 ; }

Parenth`ses e
#include<s t d i o . h> #include<s t r i n g . h> #d e f i n e BUFFER SIZE 30 #d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) i n t main ( ) { char s [ BUFFER SIZE ] ; int k , i ; p r i n t f ( S a i s i r une c h a i n e : \n ) ; f g e t s ( s , BUFFER SIZE , s t d i n ) ; i f ( s [ s t r l e n ( s ) 1 ] != \n ) CLEAR BUFFER ; else s [ strlen ( s ) 1] = 0; k = 0; i = 0; while ( s [ k ] != 0 ) { i f ( s [ k ] == ( ) i ++; i f ( s [ k ] == ) ) i ; i f ( i < 0) { p r i n t f ( E x p r e s s i o n mal p a r e n t h e s e e ! \ n ) ; return 1; } k++; } i f ( i != 0 ) { p r i n t f ( E x p r e s s i o n mal p a r e n t h e s e e ! \ n ) ; return 1; } p r i n t f ( L e x p r e s s i o n e s t c o r r e c t e m e n t p a r e n t h e s e e ! \ n ) ; return 0 ; }

153

A.6
A.6.1
/

Fonctions
Gomtrie e e

#include<s t d i o . h>

Affiche le caractere c / void a f f i c h e C a r a c t e r e ( char c ) { p r i n t f ( %c , c ) ; } / / / a f f i c h e n f o i s l e c a r a c t e r e c , ne r e v i e n t pas a l a l i g n e apres l e dernier caractere . / void l i g n e S a n s R e t u r n ( i n t n , char c ) { int i ; f o r ( i = 1 ; i <= n ; i ++) afficheCaractere (c ); } / / / a f f i c h e n f o i s l e caractere c , r e v i e n t a l a l i g n e apres le dernier caractere . / void l i g n e A v e c R e t u r n ( i n t n , char c ) { ligneSansReturn (n , c ) ; p r i n t f ( \n ) ; } / / / Affiche n espaces . / void e s p a c e s ( i n t n ) { ligneSansReturn (n , }

);

/ / / A f f i c h e l e caractere c a l a colonne i , ne r e v i e n t pas a l a l i g n e a p r e s . / void u n C a r a c t e r e S a n s R e t u r n ( i n t i , char c ) { espaces ( i 1); p r i n t f ( %c , c ) ; } / / / A f f i c h e l e caractere c a l a colonne i , r e v i e n t a l a l i g n e apres . / void u n C a r a c t e r e A v e c R e t u r n ( i n t i , char c ) { unCaractereSansReturn ( i , c ) ; p r i n t f ( \n ) ; } / /

154

/ A f f i c h e l e c a r a c t e r e c aux c o l o n n e s i e t j , r e v i e n t a l a l i g n e apres . / void d e u x C a r a c t e r e s ( i n t i , i n t j , char c ) { int k ; if ( i > j ) deuxCaracteres ( j , i , c ) ; else { i f ( i != j ) { unCaractereSansReturn ( i , c ) ; unCaractereAvecReturn ( j i , c ) ; } else unCaractereAvecReturn ( i , c ) ; } } / / / A f f i c h e un c a r r e de c o t e n . / void c a r r e ( i n t n ) { int k ; ligneAvecReturn (n , ) ; f o r ( k = 2 ; k <= n 1 ; k++) deuxCaracteres (1 , n , ) ; ligneAvecReturn (n , ) ; } / / / A f f i c h e un chapeau dont l a p o i n t e non a f f i c h e e e s t s u r l a c o l o n n e c e n t r e , ave c l e s c a r a c t e r e s c . / void chapeau ( i n t c e n t r e , char c ) { int k ; int d e l t a ; f o r ( k = 2 ; k <= c e n t r e 1 ; k++) { delta = k 1; deuxCaracteres ( centre delta , centre + delta , } } / / / A f f i c h e un chapeau a l e n v e r s a vec d e s c a r a c t e r e s c , l a p o i n t e non a f f i c h e e e s t a l a c o l o n n e c e n t r e / void c h a p e a u I n v e r s e ( i n t c e n t r e , char c ) { int k ; int d e l t a ; f o r ( k = c e n t r e 1 ; k >= 2 ; k) { delta = k 1; deuxCaracteres ( centre delta , centre + delta , } } / / / A f f i c h e un l o s a n g e de c o t e n . / void l o s a n g e ( i n t n )

);

);

155

{ unCaractereAvecReturn (n , ) ; chapeau ( n , ) ; d e u x C a r a c t e r e s ( 1 , 2n 1 , ) ; chapeauInverse (n , ) ; unCaractereAvecReturn (n , ) ; } / / / A f f i c h e une c r o i x de c o t e n / void c r o i x ( i n t n ) { d e u x C a r a c t e r e s ( 1 , 2n 1 , ) ; chapeauInverse (n , ) ; unCaractereAvecReturn (n , ) ; chapeau ( n , ) ; d e u x C a r a c t e r e s ( 1 , 2n 1 , ) ; } / / main ( ) { int t a i l l e ; printf ( Saisissez la t a i l l e s c a n f ( %d , & t a i l l e ) ; carre ( t a i l l e ); losange ( t a i l l e ) ; croix ( t a i l l e ); } d e s f i g u r e s \n ) ;

A.6.2

Arithmtique e

#include<s t d i o . h> / / int u n i t e s ( int n) { return n%10; } / / int d i z a i n e s ( int n) { return u n i t e s ( n / 1 0 ) ; } / / int e x t r a i t ( int n , int k ) { while ( k > 1 ) n /= 1 0 ; return u n i t e s ( n ) ; } / / int n b C h i f f r e s ( int n) { int i = 0 ; while ( n != 0 ) { i ++; n /= 1 0 ; } return i ; } / / int sommeChiffres ( int n) { int s = 0 ; while ( n != 0 )

156

{ s += u n i t e s ( n ) ; n /= 1 0 ; } return s ; } / / int sommeDiviseursStricts ( int n) { int i = 1 ; i n t sommeDiv = 0 ; while ( i <= n / 2 ) { if ( ! ( n % i )) sommeDiv += i ; i ++; } return sommeDiv ; } / / i n t sontAmis ( i n t a , i n t b ) { return s o m m e D i v i s e u r s S t r i c t s ( a ) == s o m m e D i v i s e u r s S t r i c t s ( b ) ; } / / int e s t P a r f a i t ( int n) { return s o m m e D i v i s e u r s S t r i c t s ( n ) == n ; } / / int puissance ( int b , int n) { int r e s = 1 , i ; f o r ( i = 1 ; i <= n ; i ++) r e s = b ; return r e s ; } / / i n t sommeParties ( i n t n , i n t k ) { i n t u = n%p u i s s a n c e ( 1 0 , k ) ; i n t v = n/ p u i s s a n c e ( 1 0 , k ) ; return u + v ; } / / int estKaprekar ( int n) { int i ; int squarredN = p u i s s a n c e ( n , 2 ) ; i n t nbC = n b C h i f f r e s ( s q u a r r e d N ) ; f o r ( i = 0 ; i <= nbC ; i ++) { i f ( sommeParties ( squarredN , i ) == n ) ; { return 1 ; } } return 0 ; } / / i n t main ( ) { p r i n t f ( %d , e s t K a p r e k a r ( 4 6 ) ) ; return 1 ; }

157

A.6.3

Passage de tableaux en param`tre e

#include<s t d i o . h> / / void a f f i c h e T a b l e a u ( i n t t [ ] , i n t n ) { int i ; f o r ( i = 0 ; i < n ; i ++) p r i n t f ( %d , t [ i ] ) ; p r i n t f ( \n ) ; } / / i n t somme ( i n t t [ ] , i n t n ) { int s = 0 , i ; for ( i = 0 ; i < n ; s += t [ i ] ; return s ; }

i ++)

/ / i n t min ( i n t t [ ] , i n t n ) { int m = t [ 0 ] , i = 0 ; while(++ i < n ) m = (m < t [ i ] ) ? m : t [ i ] ; return m; } / / int e x i s t e ( int t [ ] , int n , int k ) { int i ; f o r ( i = 0 ; i < n ; i ++) i f ( t [ i ] == k ) return 1 ; return 0 ; } / / i n t sommePairs ( i n t t [ ] , i n t n ) { int s = 0 , i ; f o r ( i = 0 ; i < n ; i ++) i f ( t [ i ] % 2 == 0 ) s += t [ i ] ; return s ; } / / int e s t T r i e ( int t [ ] , int n) { int i ; f o r ( i = 1 ; i < n ; i ++) if ( t [ i 1] > t [ i ]) return 0 ; return 1 ; } / / void p e r m u t a t i o n ( i n t t [ ] , i n t n ) { int d e r n i e r = t [ n 1 ] , i ; f o r ( i = n1 ; i > 0 ; i ) t [ i ] = t [ i 1]; t [0] = dernier ; } / / void e c h a n g e ( i n t t [ ] , { int i , int j )

158

i n t temp = t [ i ] ; t[ i ] = t[ j ]; t [ j ] = temp ; } / / void m i r o i r ( i n t t [ ] , i n t n ) { i n t i = 0 , j = n 1; while ( i < j ) e c h a n g e ( t , i ++, j ); }

A.6.4

Dcomposition en facteurs premiers e

#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e SIZE TAB 50 / / int d i v i s e ( int a , int b) { return b % a == 0 ; } / / i n t power ( i n t b , i n t n ) { i f ( n == 0 ) return 1 ; return b power ( b , n 1 ) ; } / / int estPremier ( int n , int T[ ] , int k ) { int i ; f o r ( i = 0 ; i < k ; i ++) { i f ( power (T [ i ] , 2 ) > n ) return 1 ; i f ( d i v i s e (T [ i ] , n ) ) return 0 ; } return 1 ; } / / void t r o u v e P r e m i e r s ( i n t T [ ] , i n t n ) { int i ; int j ; T[ 0 ] = 2; f o r ( i = 1 ; i < n ; i ++) { j = T[ i 1 ] + 1 ; while ( ! e s t P r e m i e r ( j , T, i 1 ) ) j ++; T[ i ] = j ; } } / / void a f f i c h e T a b ( i n t T [ ] , i n t n ) { int i ; f o r ( i = 0 ; i < n ; i ++) p r i n t f ( %d , T [ i ] ) ; } / / void i n i t T a b ( i n t T [ ] , { int n , int val )

159

int i ; for ( i = 0 ; i < n ; T [ i ]= v a l ; }

i ++)

/ / void decompose ( i n t n , i n t K [ ] , i n t T [ ] ) { int i ; i n i t T a b (K, SIZE TAB , 0 ) ; while ( n != 1 ) { i = 0; while ( ! d i v i s e (T [ i ] , n ) ) i ++; K[ i ]++; n /= T [ i ] ; } } / / int recompose ( int K[ ] , int T [ ] , int n ) { int r e s = 1 ; int i ; for ( i = 0 ; i < n ; i ++) { r e s = power (T [ i ] , K[ i ] ) ; } return r e s ; } / / i n t min ( i n t a , i n t b ) { i f (a < b) return a ; return b ; } / / void pgcdTab ( i n t A [ ] , i n t B [ ] , i n t r e s [ ] , { int i ; f o r ( i = 0 ; i < n ; i ++) r e s [ i ] = min (A [ i ] , B [ i ] ) ; } int n)

/ / i n t pgcd ( i n t a , i n t b ) { i n t A [ SIZE TAB ] ; i n t B [ SIZE TAB ] ; i n t T [ SIZE TAB ] ; i n t P [ SIZE TAB ] ; t r o u v e P r e m i e r s (T, SIZE TAB ) ; decompose ( a , A, T ) ; decompose ( b , B , T ) ; pgcdTab (A, B , P , SIZE TAB ) ; return r e c o m p o s e (P , T, SIZE TAB ) ; } / / main ( ) { int a = 90; int b = 108; p r i n t f ( pgcd(%d , %d ) = %d , a , b , pgcd ( a , b ) ) ; getch ( ) ; }

A.6.5

Statistiques
int a , int b)

void d e c a l a g e G a u c h e ( i n t T [ ] , {

160

int i ; f o r ( i = a ; i <= b ; i ++) { T[ i 1 ] = T[ i ] ; } } / / int calculeTempsTotalConnexionClient ( int C[ ] , { i n t j , sum = 0 ; f o r ( j = i ; j < n ; j ++) i f (C [ j ] == C [ i ] ) sum += D[ j ] ; return sum ; } int D[ ] , int n , int i )

/ / i n t sup pri m e D o u b l o n s ( i n t C [ ] , i n t D [ ] , i n t n , i n t i ) { i n t nbSuppr = 0 , j = i +1; while ( j < n nbSuppr ) i f (C [ j ] == C [ i ] ) { d e c a l a g e G a u c h e (C, j + 1 , n nbSuppr 1 ) ; d e c a l a g e G a u c h e (D, j + 1 , n nbSuppr 1 ) ; nbSuppr++; } else j ++; return nbSuppr ; } / / i n t tempsTotalDeConnexion ( i n t C [ ] , i n t D [ ] , i n t n , i n t i ) { D[ i ] = c a l c u l e T e m p s T o t a l C o n n e x i o n C l i e n t (C, D, n , i ) ; return s u p p r i m e D o u b l o n s (C, D, n , i ) ; } / / i n t tempsTotauxDeConnexion ( i n t C [ ] , i n t D [ ] , i n t n ) { int i = 0 ; while ( i < n ) n = tempsTotalDeConnexion (C, D, n , i ++); return n ; }

A.6.6

Chaines de caract`res e

void a f f i c h e C h a i n e ( char s [ ] ) { int i = 0 ; while ( s [ i ] != 0 ) p r i n t f ( %c , s [ i ++]); } / / i n t l o n g u e u r ( char s [ ] ) { int l = 0 ; while ( s [ l ++] != 0 ) ; return l ; } / / char e x t r a i t ( char s [ ] , i n t n ) { return s [ n 1 ] ; } / / void s u b s ( char s [ ] , i n t n , char a )

161

{ s [ n 1] = a ; }

A.6.7

Programmation dun pendu

#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e N 30 / / void i n i t i a l i s e ( char t [ ] , i n t n ) { int i ; f o r ( i = 0 ; i < n ; i ++) t[i] = ; t [ n ] = 0; } / / int { v e r i f i e ( char t [ ] , char k [ ] , char c ) int i , occ = 0 ; f o r ( i = 0 ; t [ i ] != 0 ; i ++) { i f ( t [ i ] == c && k [ i ] == { k[ i ] = c; o c c ++; } } return o c c ; } / / i n t terminePendu ( char t [ ] ) { int i = 0 ; while ( t [ i ] != && t [ i ] != 0 ) i ++; return t [ i ] == 0 ; } / / i n t i t e r a t i o n P e n d u ( char t [ ] , char k [ ] ) { char l e t t r e , l e t t r e s T r o u v e e s ; p r i n t f ( S a i s s e z une l e t t r e : ) ; s c a n f ( %c , & l e t t r e ) ; getchar ( ) ; lettresTrouvees = v e r i f i e (t , k , lettre ); p r i n t f ( %d o c c u r r e n c e ( s ) de %c t r o u v e e ( s ) \ n , l e t t r e s T r o u v e e s , afficheChaine (k ); p r i n t f ( \n ) ; return l e t t r e s T r o u v e e s ; } / / i n t t r o u v e r P e n d u ( char t [ ] , i n t n b E s s a i s ) { char k [ N ] ; int lettresATrouver = longueur ( t ) 1 ; i n i t i a l i s e (k , lettresATrouver ) ; while ( n b E s s a i s > 0 && l e t t r e s A T r o u v e r > 0 ) l e t t r e s A T r o u v e r = i t e r a t i o n P e n d u ( t , k ) ; return ( ! l e t t r e s A T r o u v e r ) ; } / / void s a i s i e C h a i n e ( char t [ ] , i n t n ) { int i = 0 ; fgets (t , n , stdin ); while ( t [ i ] ! = 0 ) i ++;

lettre );

162

( t [ i 1] == \n ) t [ i 1] = 0 ; else while ( g e t c h a r ( ) != \n ) ; if } / / void j o u e r P e n d u ( ) { char t [ N ] ; p r i n t f ( S a i s s e z l e mot A t r o u v e r : ) ; s a i s i e C h a i n e ( t , N) ; i f ( t r o u v e r P e n d u ( t , N) ) p r i n t f ( You win ! \ n ) ; else { p r i n t f ( You l o s e . . . \ nLe mot e s t afficheChaine ( t ); p r i n t f ( \n ) ; } }

: );

A.6.8

Tris

#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e N 30 / / void e c h a n g e ( i n t t [ ] , i n t i , i n t j ) { i n t temp = t [ i ] ; t[ i ] = t[ j ]; t [ j ] = temp ; } / / void ordonn e ( i n t T [ ] , i n t a , i n t b ) { i f (T [ a ] > T [ b ] ) e c h a n g e (T, a , b ) ; } / / void b u l l e ( i n t T [ ] , i n t a , i n t b ) { int i ; f o r ( i = a + 1 ; i <= b ; i ++) o rd on n e (T, i 1 , i ) ; } / / void t r i B u l l e ( i n t T [ ] , i n t n ) { int i ; f o r ( i = n1 ; i > 0 ; i ) b u l l e (T, 0 , i ) ; } / / i n t indiceDuMin ( i n t T [ ] , i n t i , i n t j ) { i n t iMin = i , k ; f o r ( k = i + 1 ; k <= j ; k++) iMin = (T [ iMin ] <= T [ k ] ) ? iMin : k ; return iMin ; } / / void p l a c e M i n ( i n t T [ ] , i n t i , i n t j , i n t k ) { e c h a n g e (T, k , indiceDuMin (T, i , j ) ) ; }

163

/ / void t r i P a r S e l e c t i o n ( i n t T [ ] , i n t n ) { int i ; f o r ( i = 0 ; i < n 1 ; i ++) p l a c e M i n (T, i , n1 , i ) ; } / / i n t main ( ) { int T[N ] ; int i ; f o r ( i = 0 ; i < N ; i ++) T [ i ] = rand ( ) % 1 0 0 ; a f f i c h e T a b l e a u (T, N ) ; t r i B u l l e (T, N ) ; a f f i c h e T a b l e a u (T, N ) ; m i r o i r (T, N ) ; a f f i c h e T a b l e a u (T, N ) ; t r i P a r S e l e c t i o n (T, N ) ; a f f i c h e T a b l e a u (T, N ) ; return 0 ; }

164

A.7
A.7.1

Structures
Heures

#include<s t d i o . h> typedef s t r u c t { int heure ; i n t minute ; } heure t ; / / / Retourne uen s t r u c t u r e i n i t i a l i s e e ave c l e s v a l e u r s h e u r e s e t minutes . / h e u r e t creerHeure ( int heures , int minutes ) { h e u r e t x = { heures , minutes } ; return x ; } / / / C o n v e r t i t t en minutes . / i n t enMinu tes ( h e u r e t t ) { return 60 t . h e u r e + t . minute ; } / / / C o n v e r t i t l a duree t en h e u r e t . / h e u r e t enHeures ( int t ) { h e u r e t x = { t /60%12 , t %60}; return x ; } / / / A f f i c h e x au format hh :mm / void a f f i c h e H e u r e ( h e u r e t x ) { p r i n t f ( %02d:%02d , x . heure , x . minute ) ; } / / / Additionne a e t b . / heure t additionneHeures ( heure t a , heure t b) { return e n H e u r e s ( enMinutes ( a ) + e nMinutes ( b ) ) ; } / / / Retourne l a v a l e u r a a j o u t e r a x pour o b t e n i r 0 0 : 0 0 . / heure t inverseHeure ( heure t x) { return e n H e u r e s ( enMinutes ( c r e e r H e u r e ( 1 2 , 0 ) ) enMin utes ( x ) ) ;

165

} / / / Soustrait b a a . / heure t soustraitHeures ( heure t a , heure t b) { return a d d i t i o n n e H e u r e s ( a , i n v e r s e H e u r e ( b ) ) ; } / / / Retourne 1 s i a > b , 1 s i a < b , 0 s i a = b . / i n t compareHeures ( h e u r e t a , { i f ( a . heure < b . heure ) return 1; i f ( a . heure > b . heure ) return 1 ; i f ( a . minute < b . minute ) return 1; i f ( a . minute > b . minute ) return 1 ; return 0 ; } heure t b)

/ / / Retourne l a p l u s / h e u r e t minHeure ( h e u r e t a , h e u r e t b ) { i f ( compareHeures ( a , b ) <= 0 ) return a ; else return b ; } / / / Pour t e s t e r / i n t main ( ) { return 0 ; } les fonctions . . . p e t i t e des heures a e t b .

A.7.2

Rpertoire tlphonique e ee

#include<s t d i o . h> #include<s t d l i b . h> #include<s t r i n g . h> #d e f i n e TAILLE NOM 50 #d e f i n e TAILLE TEL 10 #d e f i n e NB MAX NOMS 500 / / struct personne { char nom [ TAILLE NOM+ 1 ] ; char t e l [ TAILLE TEL + 1 ] ; }; / / void a f f i c h e P e r s o n n e ( s t r u c t p e r s o n n e p ) { p r i n t f ( %s : %s \n , p . nom , p . t e l ) ; }

166

/ / // A f f i c h e t o u t e s l e s entr A c es dont l e nom ne commence pas // par un c a r a c t A r e n u l . void a f f i c h e R e p e r t o i r e ( s t r u c t p e r s o n n e r [ ] ) { int i = 0 ; while ( i < NB MAX NOMS && r [ i ] . nom [ 0 ] != 0 ) { p r i n t f ( %d , i ) ; affichePersonne ( r [ i ] ) ; i ++; } } / / // Un e n r e g i s t r e m e n t e s t v i d e s i l e nom commence par l e c a r a c t A r e n u l . // C e t t e f o n c t i o n i n i t i a l i s e l e r A c pertoire . void i n i t R e p e r t o i r e ( s t r u c t p e r s o n n e r e p [ ] ) { int i ; f o r ( i = 0 ; i < NB MAX NOMS ; i ++) r e p [ i ] . nom [ 0 ] = 0 ; } / / // r e t o u r n e un nombre p o s i t i f s i l a premi Are personne a une clA c // sup A c rieure A c e l l e de l a deuxi Ame personne . int comparePersonnes ( struct personne p , struct personne q ) { return strncmp ( p . nom , q . nom , TAILLE NOM ) ; } / / void d e c a l a g e D r o i t e ( s t r u c t p e r s o n n e r e p [ ] , { int i ; f o r ( i = sup ; i >= i n f ; i ) r e p [ i +1] = r e p [ i ] ; } i n t i n f , i n t sup )

/ / void d e c a l a g e G a u c h e ( s t r u c t p e r s o n n e r e p [ ] , { int i ; f o r ( i = i n f ; i <= sup ; i ++) r e p [ i 1] = r e p [ i ] ; } i n t i n f , i n t sup )

/ / // Retourne l i n d i c e du premier A c lA c ment d i s p o n i b l e dans l e t a b l e a u . 1 s i int trouveFin ( struct personne rep [ ] ) { int i = 0 ; while ( i < NB MAX NOMS && r e p [ i ] . nom [ 0 ] != 0 ) i ++; i f ( i != NB MAX NOMS) return i ; return 1; } / / // Ajoute une personne au r A c pertoire , l e m a i n t i e n t triA c . int a j o u t e S t r u c t P e r s o n n e ( struct personne rep [ ] , struct personne p ) { i n t sup = t r o u v e F i n ( r e p ) ; int i n f = 0 ; i f ( sup == 1) return 1; while ( i n f < sup && ( c o m p a r e P e r s o n n e s ( p , r e p [ i n f ] ) > 0 ) ) i n f ++; d e c a l a g e D r o i t e ( rep , i n f , sup 1 ) ; l e r A c pertoire e s t p l e i n .

167

rep [ i n f ] = p ; return 1 ; } / / // Ajoute une personne au r A c pertoire . i n t a j o u t e P e r s o n n e ( s t r u c t p e r s o n n e r [ ] , char nom [ ] , char t e l [ ] ) { struct personne p ; s t r n c p y ( p . nom , nom , TAILLE NOM ) ; s t r n c p y ( p . t e l , t e l , TAILLE TEL ) ; p . nom [ TAILLE NOM ] = 0 ; p . t e l [ TAILLE TEL ] = 0 ; return a j o u t e S t r u c t P e r s o n n e ( r , p ) ; } / / // A f f i c h e t o u t e s l e s p e r s o n n e s dont l e nom commence par dA c butNom . void t r o u v e P e r s o n n e s ( s t r u c t p e r s o n n e r [ ] , char debutNom [ ] ) { int i ; f o r ( i = 0 ; i < NB MAX NOMS ; i ++) i f ( r [ i ] . nom [ 0 ] != 0 && ! strncmp ( r [ i ] . nom , debutNom , s t r l e n ( debutNom ) ) ) { p r i n t f ( %d , i ) ; affichePersonne ( r [ i ] ) ; } } / / // Echange l e s e n r e g i s t r e m e n t d i n d i c e s i e t j . void e c h a n g e P e r s o n n e s ( s t r u c t p e r s o n n e r [ ] , i n t i , i n t j ) { struct personne p ; p = r[ i ]; r[ i ] = r[ j ]; r [ j ] = p; } / / // En c a s de changement de nom, permute l A c lA c ment d i n d i c e i ave c s e s v o i s i n s // j u s q u A ce que l e t a b l e a u s o i t triA c . void t r i L o c a l ( s t r u c t p e r s o n n e r [ ] , i n t i n d i c e ) { i f ( i n d i c e > 0 && c o m p a r e P e r s o n n e s ( r [ i n d i c e 1 ] , r [ i n d i c e ] ) > 0 ) { echangePersonnes ( r , i n d i c e 1 , i n d i c e ) ; triLocal (r , indice 1); } i f ( i n d i c e < NB MAX NOMS 1 && r [ i n d i c e + 1 ] . nom [ 0 ] ! = 0 && c o m p a r e P e r s o n n e s ( r [ i n d i c e ] , r [ i n d i c e + 1 ] ) > 0 ) { echangePersonnes ( r , indice , i n d i c e + 1 ) ; triLocal (r , indice + 1); } } / / // Remplace l e nom d i n d i c e i n d i c e par nouveauNom , p u i s t r i e l e t a b l e a u . void changeNom ( s t r u c t p e r s o n n e r [ ] , i n t i n d i c e , char nouveauNom [ ] ) { s t r n c p y ( r [ i n d i c e ] . nom , nouveauNom , TAILLE NOM ) ; r [ i n d i c e ] . nom [ TAILLE NOM ] = 0 ; triLocal (r , indice ); } / / // Remplace l e numA c ro d i n d i c e i n d i c e par nouveauNumA c ro . void changeNumero ( s t r u c t p e r s o n n e r [ ] , i n t i n d i c e , char nouveauTel [ ] ) { s t r n c p y ( r [ i n d i c e ] . t e l , nouveauTel , TAILLE TEL ) ; r [ i n d i c e ] . t e l [ TAILLE TEL ] = 0 ; }

168

/ / // Supprime l a personne d i n d i c e i n d i c e , dA c cale l e s A c lA c ments s u i v a n t s pour // A c viter l e s t r o u s dans l e t a b l e a u . void s u p p r i m e P e r s o n n e ( s t r u c t p e r s o n n e r [ ] , i n t i n d i c e ) { i n t sup = t r o u v e F i n ( r ) ; int i n f = i n d i c e ; d e c a l a g e G a u c h e ( r , i n f + 1 , sup 1 ) ; r [ sup 1 ] . nom [ 0 ] = 0 ; } / / main ( ) { s t r u c t p e r s o n n e r e p e r t o i r e [NB MAX NOMS ] ; initRepertoire ( repertoire ); ajoutePersonne ( r e p e r t o i r e , t o t o , 0123456789 ) ; ajoutePersonne ( r e p e r t o i r e , tyty , 0123456789 ) ; ajoutePersonne ( r e p e r t o i r e , t i t i , 0123456789 ) ; ajoutePersonne ( r e p e r t o i r e , t a t a , 0123456789 ) ; ajoutePersonne ( r e p e r t o i r e , tutu , 0123456789 ) ; afficheRepertoire ( repertoire ); supprimePersonne ( r e p e r t o i r e , 2 ) ; afficheRepertoire ( repertoire ); getch ( ) ; }

169

A.8
A.8.1

Pointeurs
Exercices sans sous-programmes

Tableau de carrs e
#include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> i n t main ( ) { int t ; int k , n ; p r i n t f ( Q u e l l e e s t l a t a i l l e du t a b l e a u ? ) ; s c a n f ( %d , &n ) ; t = ( int ) malloc (n sizeof ( int ) ) ; i f ( t == NULL) exit (0); t = 1; f o r ( k = 1 ; k < n ; k++) ( t + k ) = ( t + k 1) + 2 ; p r i n t f ( %d p r e m i e r s nombres i m p a i r s : \n , n ) ; f o r ( k = 0 ; k < n ; k++) p r i n t f ( %d , ( t + k ) ) ; p r i n t f ( \n ) ; f o r ( k = 1 ; k < n ; k++) ( t + k ) += ( t + k 1 ) ; p r i n t f ( %d p r e m i e r s c a r r e s : \n , n ) ; f o r ( k = 0 ; k < n ; k++) p r i n t f ( %d , ( t + k ) ) ; p r i n t f ( \n ) ; free (t ); return 0 ; }

Matrices et pointeurs de pointeurs


#include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> i n t main ( ) { i n t T ; int i , j , n ; p r i n t f ( V a l e u r de n ? ) ; s c a n f ( %d , &n ) ; T = ( int ) malloc ( n s i z e o f ( int ) ) ; i f (T == NULL) exit (0); f o r ( i = 0 ; i < n ; i ++) { (T + i ) = ( i n t ) m a l l o c ( n s i z e o f ( i n t ) ) ; i f ( (T + i ) == NULL) exit (0); f o r ( j = 0 ; j < n ; j ++) ( (T + i ) + j ) = 0 ; ( (T + i ) + i ) = 1 ; } f o r ( i = 0 ; i < n ; i ++) { f o r ( j = 0 ; j < n ; j ++) p r i n t f ( %d , ( (T + i ) + j ) ) ; p r i n t f ( \n ) ; } f o r ( i = 0 ; i < n ; i ++) f r e e ( (T + i ) ) ; f r e e (T ) ; return 0 ; }

Copie de cha nes de caract`res e


#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e B SIZE 10

170

#d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) i n t main ( ) { char b u f f e r [ B SIZE ] , c o p i e ; int len = 0 , i ; p r i n t f ( S a i s i s s e z une c h a i n e de c a r a c t A r e : \n ) ; f g e t s ( b u f f e r , B SIZE , s t d i n ) ; while ( b u f f e r [ l e n ] != 0 ) l e n ++; i f ( b u f f e r [ l e n 1 ] != \n ) CLEAR BUFFER ; else l e n ; c o p i e = ( char ) m a l l o c ( s i z e o f ( char ) ( l e n + 1 ) ) ; f o r ( i = 0 ; i < l e n ; i ++) ( c o p i e + i ) = b u f f e r [ i ] ; ( c o p i e + l e n ) = 0 ; i = 0; while ( ( c o p i e + i ) != 0 ) p r i n t f ( %c , ( c o p i e + i ++)); p r i n t f ( \n ) ; free ( copie ) ; return 0 ; }

Tableau de cha nes


#include<s t d i o . h> #include<s t d l i b . h> #d e f i n e B SIZE 10 #d e f i n e NB S 4 #d e f i n e CLEAR BUFFER while ( g e t c h a r ( ) != \n ) i n t main ( ) { char b u f f e r [ B SIZE ] , c o p i e s ; int len = 0 , j , i ; c o p i e s = ( char ) m a l l o c ( NB S s i z e o f ( char ) ) ; f o r ( j = 0 ; j < NB S ; j ++) { p r i n t f ( S a i s i s s e z une c h a i n e de c a r a c t A r e : \n ) ; f g e t s ( b u f f e r , B SIZE , s t d i n ) ; while ( b u f f e r [ l e n ] != 0 ) l e n ++; i f ( b u f f e r [ l e n 1 ] != \n ) CLEAR BUFFER ; else l e n ; ( c o p i e s + j ) = ( char ) m a l l o c ( s i z e o f ( char ) ( l e n + 1 ) ) ; f o r ( i = 0 ; i < l e n ; i ++) (( copies + j ) + i ) = buffer [ i ] ; (( copies + j ) + len ) = 0; } f o r ( j = 0 ; j < NB S ; j ++) { i = 0; while ( ( ( c o p i e s + j ) + i ) != 0 ) p r i n t f ( %c , ( ( c o p i e s + j ) + i ++)); p r i n t f ( \n ) ; free (( copies + j ) ) ; } free ( copies ); return 0 ; }

A.8.2

Pointeurs sans toiles et triangle de Pascal e

#include<s t d i o . h> #include<m a l l o c . h> #include<s t d l i b . h> int getIntVal ( int p) { return p ; } void s e t I n t V a l ( i n t p , i n t v a l ) {

171

p = v a l ; } i n t getTiAdr ( i n t t , i n t i ) { return t + i ; } int getTiVal ( int t , int i ) { return g e t I n t V a l ( getTiAdr ( t , }

i ));

void s e t T i V a l ( i n t t , i n t i , i n t v a l ) { s e t I n t V a l ( getTiAdr ( t , i ) , v a l ) ; } void s w a p I n t ( i n t a , i n t b ) { i n t temp ; s e t I n t V a l (&temp , g e t I n t V a l ( a ) ) ; setIntVal (a , getIntVal (b ) ) ; s e t I n t V a l ( b , temp ) ; } void s w a p T i j ( i n t t , i n t i , i n t j ) { s w a p I n t ( getTiAdr ( t , i ) , getTiAdr ( t , } i n t g e t T i A d r ( i n t T, i n t i ) { return (T + i ) ; } i n t g e t T i ( i n t T, i n t i ) { return g e t T i A d r (T, i ) ; } void s e t T { t = p; } A d r ( i n t t , i n t p )

j ));

void s e t T i ( i n t t , i n t i , i n t p ) { setT Adr ( getTi Adr ( t , i ) , p ) ; } void c r e a t e T ( i n t T, i n t n , i n t m) { int i ; f o r ( i = 0 ; i < n ; i ++) { s e t T i (T, i , ( i n t ) m a l l o c (m s i z e o f ( i n t ) ) ) ; i f ( g e t T i (T, i ) == NULL) { p r i n t f ( Heap o v e r f l o w \n ) ; e x i t ( 1); } } } i n t g e t T i j A d r ( i n t t , i n t i , i n t j ) { return getTiAdr ( g e t T i ( t , i ) , j ) ; } i n t g e t T i j V a l ( i n t t , i n t i , i n t j ) { return g e t I n t V a l ( g e t T i j A d r ( t , i , j ) ) ; } void s e t T i j V a l ( i n t t , i n t i , i n t j , i n t v a l ) { setTiVal ( getTi ( t , i ) , j , val ) ; // ou b i e n s e t I n t A d r ( g e t T i j A d r ( t , i , j ) , v a l ) }

172

i n t C j i ( i n t t , i n t i , i n t j ) { i f ( j == 0 | | i == j ) return 1 ; return g e t T i j V a l ( t , i 1 , j 1) + g e t T i j V a l ( t , i 1 , j ) ; } void m a l l o c P a s c a l ( i n t p , i n t n ) { int i ; f o r ( i = 0 ; i <= n ; i ++) { s e t T i (p , i , ( int ) malloc ( ( i + 1) sizeof ( int ) ) ) ; i f ( g e t T i ( p , i ) == NULL) { p r i n t f ( Heap o v e r f l o w \n ) ; e x i t ( 1); } } } void s e t C j i ( i n t t , i n t n ) { int i , j ; f o r ( i = 0 ; i <= n ; i ++) f o r ( j = 0 ; j <= i ; j ++) setTijVal ( t , i , j , C j i ( t , i , }

j ));

i n t p a s c a l ( i n t n ) { i n t p ; p = ( int ) malloc ( n s i z e o f ( int ) ) ; i f ( p == NULL) { p r i n t f ( Heap o v e r f l o w \n ) ; e x i t ( 1); } mallocPascal (p , n ) ; s e t C j i (p , n ) ; return p ; } void p r i n t P a s c a l ( i n t p , i n t n ) { int i , j ; f o r ( i = 0 ; i <= n ; i ++) { f o r ( j = 0 ; j <= i ; j ++) p r i n t f ( %d , g e t T i j V a l ( p , i , p r i n t f ( \n ) ; } } void f r e e P a s c a l ( i n t p , i n t n ) { int i ; f o r ( i = 0 ; i <= n ; i ++) { f r e e ( getTi (p , i ) ) ; } free (p ) ; } main ( ) { i n t p = p a s c a l ( 1 5 ) ; printPascal (p , 15); }

j ));

A.8.3

Fonctions rcursives e

#include<s t d i o . h> typedef s t r u c t { int heure ; i n t minute ; } heure t ; / /

173

i n t sommeTab ( i n t t , i n t n ) { int i , s = 0 ; f o r ( i = 0 ; i < n ; i ++) s += ( t + i ) ; return s ; } / / i n t sommeTabRec ( i n t t , i n t n ) { i f (n > 0) return t + sommeTabRec ( t + 1 , n 1 ) ; return 0 ; } / / void i n i t T a b ( i n t t , i n t n ) { int i ; f o r ( i = 0 ; i < n ; i ++) ( t + i ) = i + 1 ; } / / void i n i t T a b R e c ( i n t t , i n t n ) { i f (n > 0) { ( t + n 1) = n ; initTabRec ( t , n 1 ) ; } } / / void p r i n t T a b ( i n t t , i n t n ) { int i ; f o r ( i = 0 ; i < n ; i ++) p r i n t f ( %d , ( t + i ) ) ; p r i n t f ( \n ) ; } / / void printTabRec ( i n t t , i n t n ) { i f (n > 0) { p r i n t f ( %d , t ) ; printTabRec ( t + 1 , n 1 ) ; } else { p r i n t f ( \n ) ; } } / / void swap ( i n t t , i n t i , i n t j ) { i n t temp = ( t + i ) ; ( t + i ) = ( t + j ) ; ( t + j ) = temp ; } / / void mirrorTab ( i n t t , i n t n ) { i n t i = 0 , j = n 1; while ( i < j ) { swap ( t , i , j ) ; i ++;

174

j ; } } / / void mirrorTabRec ( i n t t , i n t n ) { i f (n > 0) { swap ( t , 0 , n 1 ) ; mirrorTabRec ( t + 1 , n 2 ) ; } } / / int f i n d ( int t , int n , int x ) { int i ; f o r ( i = 0 ; i < n ; i ++) i f ( ( t + i ) == x ) return 1 ; return 0 ; } / / int findRec ( int t , int n , int x ) { i f ( n == 0 ) return 0 ; i f ( t == x ) return 1 ; return f i n d R e c ( t + 1 , n 1 , x ) ; } / / int d i s t i n c t V a l u e s ( int t , int n) { i n t i , dv = 1 ; f o r ( i = 0 ; i < n 1 ; i ++) dv += ! f i n d ( t + i + 1 , n 1 i , ( t + i ) ) ; return dv ; } / / int distinctValuesRec ( int t , int n) { i f ( n == 0 ) return 0 ; return d i s t i n c t V a l u e s R e c ( t + 1 , n 1 ) + ( findRec ( t + 1 , n 1 , t ))? 0 : 1 ; } / / h e u r e t creerHeure ( int heures , int minutes ) { h e u r e t x = { heures , minutes } ; return x ; } / / i n t enMinu tes ( h e u r e t t ) { return 60 t . h e u r e + t . minute ; } / / h e u r e t enHeures ( int t ) { h e u r e t x = { t /60%12 , t %60}; return x ; } / /

175

void a f f i c h e H e u r e ( h e u r e t x ) { p r i n t f ( %02d:%02d , x . heure , x . minute ) ; } / / heure t additionneHeures ( heure t a , heure t b) { return e n H e u r e s ( enMinutes ( a ) + e nMinutes ( b ) ) ; } / / heure t inverseHeure ( heure t x) { return e n H e u r e s ( enMinutes ( c r e e r H e u r e ( 1 2 , 0 ) ) enMin utes ( x ) ) ; } / / heure t soustraitHeures ( heure t a , heure t b) { return a d d i t i o n n e H e u r e s ( a , i n v e r s e H e u r e ( b ) ) ; } / / i n t compareHeures ( h e u r e t a , { i f ( a . heure < b . heure ) return 1; i f ( a . heure > b . heure ) return 1 ; i f ( a . minute < b . minute ) return 1; i f ( a . minute > b . minute ) return 1 ; return 0 ; } heure t b)

/ / h e u r e t minHeure ( h e u r e t a , h e u r e t b ) { i f ( compareHeures ( a , b ) <= 0 ) return a ; else return b ; } / / void a f f i c h e T a b H e u r e s ( h e u r e t t , i n t n ) { i f (n > 0) { a f f i c h e H e u r e ( t ) ; printf ( ); afficheTabHeures ( t + 1 , n 1 ) ; } } / / void i n i t T a b H e u r e s ( h e u r e t t , i n t n , h e u r e t d e p a r t , { i f (n > 0) { t = depart ; initTabHeures ( t + 1 , n 1 , a d d i t i o n n e H e u r e s ( d e p a r t , pas ) , pas ) ; } } / / h e u r e t sommeTabHeures ( h e u r e t t , i n t n ) h e u r e t pas )

176

{ int i ; heure t res = creerHeure (0 , 0 ) ; f o r ( i = 0 ; i < n ; i ++) r e s = additionneHeures ( res , ( t + i ) ) ; return r e s ; } / / h e u r e t sommeTabHeuresRec ( h e u r e t t , i n t n ) { i f ( n == 0 ) return c r e e r H e u r e ( 0 , 0 ) ; return a d d i t i o n n e H e u r e s ( t , sommeTabHeuresRec ( t + 1 , n 1 ) ) ; } / / h e u r e t minTabHeure ( h e u r e t t , i n t n ) { i f ( n == 1 ) return t ; else return minHeure ( t , minTabHeure ( t + 1 , n 1 ) ) ; }

A.8.4

Tri fusion

#include<s t d i o . h> #include<s t d l i b . h> #include<t i m e . h> #d e f i n e MOD 10000 / / / Affiche / void p r i n t T a b ( i n t t , i n t n ) { i f (n > 0) { p r i n t f ( %d , t ) ; printTab ( t + 1 , n 1 ) ; } else p r i n t f ( \n ) ; } / / / P l a c e n e l e m e n t s a l e a t o i r e s de v a l e u r s maximales MOD 1 dans l e t a b l e a u t . / void i n i t T a b ( i n t t , i n t n ) { i f (n > 0) { t = rand ()%MOD; initTab ( t + 1 , n 1 ) ; } } / / / Retourne un t a b l e a u de n e l e m e n t s a l l o u e dynamiquement . / int createTab ( int n) { int t = ( int ) malloc ( sizeof ( int )n ) ; i f ( t == NULL) { p r i n t f ( no memory a v a l a i b l e \n ) ; l e s n e l e m e n t s du t a b l e a u t .

177

exit (0); } return t ; } / / / L i b e r e l a zone memoire p o i n t e e par t e t met ce p o i n t e u r a NULL. / void d e s t r o y T a b ( i n t t ) { f r e e ( t ) ; t = NULL ; } / / / ( recursive ) Retourne l i n d i c e du p l u s p e t i t e l e m e n t du t a b l e a u t a n e l e m e n t s . A f f i c h e une e r r e u r s i l e t a b l e a u e s t v i d e . / i n t indexOfMin ( i n t t , i n t n ) { i f ( n == 1 ) return 0 ; i f (n > 1) { i n t r e c = indexOfMin ( t + 1 , n 1 ) + 1 ; return ( t < ( t + r e c ) ) ? 0 : r e c ; } p r i n t f ( E r r e u r dans l a f o n c t i o n i n d i c e du Min\n ) ; return 1; } / / / Echange l e s e l e m e n t s x e t y . / void swap ( i n t x , i n t y ) { i n t temp = x ; x = y ; y = temp ; } / / / Echange l e p l u s p e t i t e l e m e n t du t a b l e a u t a n e l e m e n t s a vec l e premier . / void swapMin ( i n t t , i n t n ) { swap ( t , t + indexOfMin ( t , n ) ) ; } / / / ( recursive ) Tri l e t a b l e a u t a n e l e m e n t s ave c l a methode du t r i par s e l e c t i o n . / void s e l e c t i o n S o r t ( i n t t , i n t n ) { i f (n > 0) { swapMin ( t , n ) ; selectionSort ( t + 1 , n 1); } }

178

/ / / ( Recursive ) Recopie l e s n e l e m e n t s du t a b l e a u s o u r c e a l adresse dest . / void copyTab ( i n t s o u r c e , i n t d e s t , i n t n ) { i f (n > 0) { dest = source ; copyTab ( s o u r c e + 1 , d e s t + 1 , n 1 ) ; } } / / / ( Recursive ) I n t e r c l a s s e l e s n1 e l e m e n t s de s o u r c e 1 ave c l e s n2 e l e m e n t s de s o u r c e 2 . source1 e t source2 sont supposes t r i e s . L in ter clas sem ent se f a i t en d i s p o s a n t c e s e l e m e n t s dans l o r d r e dans l e t a b l e a u d e s t . / void s h u f f l e T a b ( i n t s o u r c e 1 , i n t s o u r c e 2 , i n t d e s t , i n t n1 , i n t n2 ) { i f ( n1 > 0 | | n2 > 0 ) { i f ( n1 == 0 | | ( n2 > 0 && s o u r c e 2 < s o u r c e 1 ) ) { dest = source2 ; s h u f f l e T a b ( s o u r c e 1 , s o u r c e 2 + 1 , d e s t + 1 , n1 , n2 1 ) ; } else { dest = source1 ; s h u f f l e T a b ( s o u r c e 1 + 1 , s o u r c e 2 , d e s t + 1 , n1 1 , n2 ) ; } } } / / / Trie l e s n e l e m e n t s de t ave c l a methode du t r i / void f u s i o n S o r t ( i n t t , i n t n ) { i f (n > 1) { i n t m = n / 2 , q , r ; q = c r e a t e T a b (m) ; r = t + m; copyTab ( t , q , m) ; f u s i o n S o r t ( q , m) ; f u s i o n S o r t ( r , n m) ; s h u f f l e T a b ( q , r , t , m, n m) ; d e s t r o y T a b (&q ) ; } } / / / Compare l e s performances en temps de c a l c u l d e s t r i s par s e l e c t i o n e t par f u s i o n . / int compareSorts ( int f i r s t V a l u e , int lastValue , int step ) { int i ; int s t ar t , stop ; i n t t , q ; s r a n d ( t i m e (NULL ) ) ; f o r ( i = f i r s t V a l u e ; i <= l a s t V a l u e ; i += s t e p ) { fusion .

179

p r i n t f ( w i t h %d e l e m e n t s : \n , i ) ; t = createTab ( i ) ; q = createTab ( i ) ; initTab ( t , i ) ; copyTab ( t , q , i ) ; s t a r t = t i m e (NULL ) ; selectionSort (t , i ); s t o p = t i m e (NULL ) ; p r i n t f ( s e l e c t i o n s o r t : %d\n , s t o p s t a r t ) ; d e s t r o y T a b (& t ) ; s t a r t = t i m e (NULL ) ; fusionSort (q , i ) ; s t o p = t i m e (NULL ) ; p r i n t f ( f u s i o n s o r t : %d\n , s t o p s t a r t ) ; d e s t r o y T a b (&q ) ; } return 0 ; } / / / Pour t e s t e r ecrites . . . / i n t main ( ) { compareSorts (10000 , 500000 , 1 0 0 0 ) ; return 0 ; } les f o n c t i o n s au f u r e t a mesure qu e l l e s sont

180

A.9
A.9.1
touch

Fichiers
Ouverture et fermeture

#include<s t d i o . h> i n t main ( i n t a r g c , char a r g v [ ] ) { FILE f ; i f ( a r g c != 2 ) { p r i n t f ( Syntax : . / t o u c h fname \ nwhere fname i s a s t r i n g w i t h o u t \ s p a c e o r s p e c i a l c h a r a c t e r \n ) ; return 1; } f = f o p e n ( ( a r g v + 1 ) , w ) ; i f ( f == NULL) { p r i n t f ( E r r e u r l o r s de l o u v e r t u r e du f i c h i e r %s \n , ( argv + 1 ) ) ; return 1; } i f ( f c l o s e ( f ) != 0 ) { p r i n t f ( E r r e u r l o r s de l a f e r m e t u r e du f i c h i e r %s \n , ( argv + 1 ) ) ; return 1; } return 0 ; }

A.9.2
more

Lecture

#include<s t d i o . h> i n t main ( i n t argv , char a r g c ) { FILE f ; int c ; i f ( a r g v == 1 ) f = fopen ( toto , r ) ; else f = fopen (( argc + 1) , r ) ; i f ( f == NULL) return 1 ; c = getc ( f ) ; while ( c != EOF) { p r i n t f ( %c , c ) ; c = getc ( f ) ; } p r i n t f ( \n ) ; fclose ( f ); return 0 ; }

A.9.3

Ecriture

Alphabet
#include<s t d i o . h> i n t main ( i n t a r g c , char a r g v [ ] ) { FILE f ; char c ; i f ( a r g c != 2 ) { p r i n t f ( Syntax : . / t o u c h fname c o n t e n t s \n \ where fname i s a s t r i n g w i t h o u t \ s p a c e o r s p e c i a l c h a r a c t e r \n ) ; return 1; }

181

f = f o p e n ( ( a r g v + 1 ) , w ) ; i f ( f == NULL) { p r i n t f ( E r r e u r l o r s de l o u v e r t u r e du f i c h i e r %s \n , ( argv + 1 ) ) ; return 1; } f o r ( c = a ; c <= z ; c++) fputc (c , f ) ; i f ( f c l o s e ( f ) != 0 ) { p r i n t f ( E r r e u r l o r s de l a f e r m e t u r e du f i c h i e r %s \n , ( argv + 1 ) ) ; return 1; } return 0 ; }

Initialiser un chier
#include<s t d i o . h> i n t main ( i n t a r g c , char a r g v [ ] ) { FILE f ; int i ; i f ( argc < 2) { p r i n t f ( Syntax : . / t o u c h fname c o n t e n t s \n \ where : \n fname i s a s t r i n g w i t h o u t \ s p a c e o r s p e c i a l c h a r a c t e r \n \ c o n t e n t s i s a s t r i n g w i t h o u t \ s p e c i a l c h a r a c t e r \n ) ; return 1; } f = f o p e n ( ( a r g v + 1 ) , w ) ; i f ( f == NULL) { p r i n t f ( E r r e u r l o r s de l o u v e r t u r e du f i c h i e r %s \n , ( argv + 1 ) ) ; return 1; } f o r ( i = 2 ; i < a r g c ; i ++) { f p u t s ( ( argv + i ) , f ) ; i f ( i != a r g c 1 ) fputc ( , f ) ; } i f ( f c l o s e ( f ) != 0 ) { p r i n t f ( E r r e u r l o r s de l a f e r m e t u r e du f i c h i e r %s \n , ( argv + 1 ) ) ; return 1; } return 0 ; }

A.9.4
cp

Lecture et criture e

#include<s t d i o . h> i n t main ( i n t argv , char a r g c ) { FILE s o u r c e ; FILE d e s t ; int c ; source = fopen (( argc + 1) , r ) ; d e s t = f o p e n ( ( a r g c + 2 ) , w ) ; i f ( s o u r c e == NULL | | d e s t == NULL) return 1 ; while ( ( c = g e t c ( s o u r c e ) ) ! = EOF) { fputc (c , dest ) ; } f c l o s e ( source ) ; f c l o s e ( dest ) ; return 0 ; }

182

Liste de noms
#include<s t r i n g . h> #include<s t d i o . h> i n t main ( i n t argv , char a r g c ) { FILE f ; char b u f f e r [ 2 5 0 ] ; f = f o p e n ( ( a r g c + 1 ) , w ) ; i f ( f == NULL) return 1 ; gets ( buffer ) ; while ( strcmp ( 1 , b u f f e r ) ) { fputs ( buffer , f ) ; f p u t c ( \n , f ) ; gets ( buffer ) ; } fclose ( f ); return 0 ; } #include<s t r i n g . h> #include<s t d i o . h> i n t main ( i n t argv , char a r g c ) { FILE f ; char b u f f e r [ 2 5 0 ] ; f = fopen (( argc + 1) , r ) ; i f ( f == NULL) return 1 ; while ( f g e t s ( b u f f e r , 2 4 9 , f ) ) { p r i n t f ( %s , b u f f e r ) ; } fclose ( f ); return 0 ; }

183

A.10
A.10.1

Listes Cha ees n


Pointeurs et structures

#include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> typedef s t r u c t { int i ; char c ; } st ; i n t main ( ) { st p ; p = ( s t ) malloc ( sizeof ( s t ) ) ; p >i = 5 ; p >c = a ; p r i n t f ( p = (%d , %c ) \ n , p , p ) ; >i >c free (p ) ; return 0 ; }

A.10.2

Maniement du cha nage

Prise en main
#include<s t d i o . h> / / typedef s t r u c t m a i l l o n { int data ; struct maillon next ; } maillon ; / / i n t main ( ) { m a i l l o n m, p , q , r ; maillon ptr ; m. d a t a = 1 ; p . data = 2 ; q . data = 3 ; r . data = 4 ; m. n e x t = &p ; p . n e x t = &q ; q . n e x t = &r ; r . n e x t = NULL ; f o r ( p t r = & ; p t r != NULL ; p t r = p t r e x t ) m >n p r i n t f ( d a t a = %d\n , p t r a t a ) ; >d return 0 ; }

Tableaux
#include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> #d e f i n e N 10 / / typedef s t r u c t m a i l l o n { int data ; struct maillon next ; } maillon ; / / void p r i n t D a t a ( m a i l l o n p t r ) { f o r ( ; p t r != NULL ; p t r = p t r e x t ) >n

184

p r i n t f ( d a t a = %d\n , p t r a t a ) ; >d } / / i n t main ( ) { maillon l ; int i ; l = ( m a i l l o n ) m a l l o c (N s i z e o f ( m a i l l o n ) ) ; i f ( l == NULL) exit (0); l ata = 0 ; >d l e x t = NULL ; >n f o r ( i = 1 ; i < N ; i ++) { ( l + i )>d a t a = i ; ( l + i )>n e x t = l + i 1 ; } printData ( l + N 1 ) ; free ( l ); return 0 ; }

Oprations sur les listes cha ees e n


#include<s t d i o . h> #include<s t d l i b . h> #include<m a l l o c . h> #d e f i n e N 10 / / typedef s t r u c t m a i l l o n { int data ; struct maillon next ; } maillon ; / / void p r i n t L L ( m a i l l o n p t r ) { f o r ( ; p t r != NULL ; p t r = p t r e x t ) >n p r i n t f ( d a t a = %d\n , p t r a t a ) ; >d } / / maillon creeMaillon ( int n) { maillon l ; l = ( maillon ) malloc ( sizeof ( maillon ) ) ; i f ( l == NULL) exit (0); l ata = n ; >d l e x t = NULL ; >n return l ; } / / maillon insereFinLL ( maillon l , int n) { maillon l a s t = creeMaillon (n ) ; maillon f i r s t = l ; i f ( l == NULL) return l a s t ; else { while ( l e x t != NULL) >n l = l ext ; >n l ext = l a s t ; >n } return f i r s t ; } / / m a i l l o n copyLL ( m a i l l o n s o u r c e )

185

{ maillon copie ; maillon maillonCopie ; i f ( s o u r c e == NULL) return NULL ; c o p i e = c r e e M a i l l o n ( source ata ) ; >d maillonCopie = copie ; source = source ext ; >n while ( s o u r c e != NULL) { maillonCopie ext = c r e e M a i l l o n ( source ata ) ; >n >d maillonCopie = maillonCopie ext ; >n source = source ext ; >n } m a i l l o n C o p i e e x t = NULL ; >n return c o p i e ; } / / maillon reverseLL ( maillon l ) { maillon previous ; maillon current ; maillon next ; i f ( l == NULL) return NULL ; c u r r e n t = l ext ; >n l e x t = NULL ; >n previous = l ; next = c u r r e n t ; while ( c u r r e n t != NULL) { i f ( n e x t != NULL) n e x t = next e x t ; >n current ext = p r e v i o u s ; >n previous = current ; c u r r e n t = next ; } return p r e v i o u s ; } / / maillon insereDebutLL ( maillon l , int n ) { maillon f i r s t = creeMaillon (n ) ; f i r s t ext = l ; >n return f i r s t ; } / / maillon initLL ( int n) { m a i l l o n l = NULL ; int i ; f o r ( i = n 1 ; i >= 0 ; i ) l = insereDebutLL ( l , i ) ; return l ; } / / void f r e e L L ( m a i l l o n l ) { maillon n ; while ( l != NULL) { n = l ext ; >n free ( l ); l = n; } } / / i n t main ( ) { maillon l ; maillon k ;

186

l = i n i t L L (N ) ; printLL ( l ) ; k = copyLL ( l ) ; k = reverseLL (k ) ; printLL ( k ) ; freeLL ( l ) ; freeLL (k ) ; return 0 ; }

A.10.3

Listes doublement cha ees n

#include<s t d i o . h> #include<m a l l o c . h> #include<s t d l i b . h> #d e f i n e N 10 / /

typedef s t r u c t d m a i l l o n { int data ; struct dmaillon p r e v i o u s ; struct dmaillon next ; } dmaillon ; / / typedef s t r u c t d L i n k e d L i s t { struct dmaillon f i r s t ; struct dmaillon l a s t ; } dLinkedList ; / / / Affiche / l e s e l e m e n t s d une l i s t e chainee .

void printDLL ( d L i n k e d L i s t d l ) { dmaillon m ; f o r (m = d l f i r s t ; m != NULL ; m = m >n e x t ) > p r i n t f ( %d > , m >d a t a ) ; p r i n t f ( \n ) ; } / / / Libere tous l e s maillons , puis l i b e r e / dl .

void freeDLL ( d L i n k e d L i s t d l ) { d m a i l l o n m; dmaillon next ; f o r (m = d l f i r s t ; m != NULL ; m = n e x t ) > { n e x t = m >n e x t ; f r e e (m) ; } f r e e ( dl ) ; } / / / A l l o u e l a memoire pour une d L i n k e d L i s t , i n i t i a l i s e l e s p o i n t e u r s a NULL / d L i n k e d L i s t makeDLL ( ) { dLinkedList l ; l = ( dLinkedList ) malloc ( sizeof ( dLinkedList ) ) ; i f ( l == NULL) exit (0);

187

l f i r s t = NULL ; > l a s t = NULL ; >l return l ; } / / / Cree un m a i l l o n c o n t e n a n t l a v a l e u r n . / d m a i l l o n makeDMaillon ( i n t n ) { dmaillon d ; d = ( dmaillon ) malloc ( sizeof ( dmaillon ) ) ; i f ( d == NULL) exit (0); d r e v i o u s = NULL ; >p d e x t = NULL ; >n d a t a = n ; >d return d ; } / / / Accroche l e m a i l l o n m a l a f i n de l a / liste chainee d l

void appendDMaillonDLL ( d L i n k e d L i s t d l , d m a i l l o n m) { i f ( d l a s t == NULL) >l { d l f i r s t = m; > d l a s t = m; >l } else { d l a s t e x t = m; >l >n m >p r e v i o u s = d l a s t ; >l d l a s t = m; >l } d l i r s t r e v i o u s = NULL ; >f >p d l a s t e x t = NULL ; >l >n } / / / Accroche l e m a i l l o n m au d e b u t de l a / liste chainee d l

void pushDMaillonDLL ( d L i n k e d L i s t d l , d m a i l l o n m) { i f ( d l a s t == NULL) >l { d l f i r s t = m; > d l a s t = m; >l } else { d l i r s t r e v i o u s = m; >f >p m >n e x t = d l f i r s t ; > d l f i r s t = m; > } d l i r s t r e v i o u s = NULL ; >f >p d l a s t e x t = NULL ; >l >n } / / / Ajoute a l a f i n de d l un m a i l l o n c o n t e n a n t l a v a l e u r n . / void appendIntDLL ( d L i n k e d L i s t d l , i n t n ) { appendDMaillonDLL ( d l , makeDMaillon ( n ) ) ; }

188

/ / / Ajoute au d e b u t de d l un m a i l l o n c o n t e n a n t l a v a l e u r n . / void pushIntDLL ( d L i n k e d L i s t d l , i n t n ) { pushDMaillonDLL ( d l , makeDMaillon ( n ) ) ; } / / / P l a c e dans l a l i s t e doublement c h a i n e e l e s v a l e u r s {0 , . . . , n} / void initDLL ( d L i n k e d L i s t d l , i n t n ) { int i ; f o r ( i = 0 ; i < n ; i ++) appendIntDLL ( d l , i ) ; } / / / Inverse / l o r d r e d e s e l e m e n t s de d l .

void reverseD LL ( d L i n k e d L i s t d l ) { dmaillon m ; d m a i l l o n temp ; i f ( d l f i r s t != NULL) > { f o r (m = d l f i r s t ; m != NULL ; m = m >p r e v i o u s ) > { temp = m >p r e v i o u s ; m >p r e v i o u s = m >n e x t ; m >n e x t = temp ; } } temp = d l f i r s t ; > dl f i r s t = dl a s t ; > >l d l a s t = temp ; >l } / / / Retourne une c o p i e de s o u r c e . / d L i n k e d L i s t copyDLL ( d L i n k e d L i s t s o u r c e ) { d L i n k e d L i s t d e s t = makeDLL ( ) ; dmaillon sourceMaillon ; f o r ( s o u r c e M a i l l o n = s o u r c e f i r s t ; s o u r c e M a i l l o n != NULL ; > s o u r c e M a i l l o n = sourceMaillon ext ) >n appendIntDLL ( d e s t , s o u r c e M a i l l o n a t a ) ; >d return d e s t ; } / / / Concatene f i n a l a s u i t e de debut , v i d e l a / liste fin .

void concatDLL ( d L i n k e d L i s t debut , d L i n k e d L i s t f i n ) { i f ( debut f i r s t == NULL) > { debut f i r s t = f i n f i r s t ; > > debut a s t = f i n a s t ; >l >l } else { debut a s t e x t = f i n f i r s t ; >l >n >

189

( f i n f i r s t != NULL) > f i n i r s t r e v i o u s = debut a s t ; >f >p >l debut a s t = f i n a s t ; >l >l if } f i n f i r s t = NULL ; > f i n a s t = NULL ; >l } / / i n t main ( ) { d L i n k e d L i s t d l = makeDLL ( ) ; d L i n k e d L i s t cp ; initDLL ( d l , N ) ; printDLL ( d l ) ; cp = copyDLL ( d l ) ; printDLL ( cp ) ; reverseDLL ( cp ) ; printDLL ( cp ) ; concatDLL ( d l , cp ) ; printDLL ( d l ) ; freeDLL ( d l ) ; freeDLL ( cp ) ; return 0 ; }

A.10.4

Fonctions rcursives et listes cha ees e n

#include<s t d i o . h> #include<m a l l o c . h> #include<s t d l i b . h> / Dans t o u t e s l e s f o n c t i o n s a p a r t i r d i n s e r e , i l e s t i n t e r d i t de creer des maillons , t o u t e s ces operations doivent se f a i r e par m o d i f i c a t i o n du c h a i n a g e e t non par r e c o p i e . / typedef s t r u c t l l s { int data ; struct l l s next ; }ll ; / / / A l l o u e dynamiquement e t i n i t i a l i s e un m a i l l o n a vec l e s v a l e u r s d a t a e t next , r e t o u r n e son a d r e s s e . / l l c r e e r ( i n t data , l l n e x t ) { l l l = ( l l ) malloc ( sizeof ( l l ) ) ; i f ( l == NULL) { p r i n t f ( heap o v e r f l o w \n , ) ; exit (0); } l ata = data ; >d l ext = next ; >n return l ; } / / / Affiche l e maillon l / void a f f i c h e ( l l l ) { i f ( l != NULL) p r i n t f ( %d > , l a t a ) ; >d } / / / A f f i c h e , dans l ordre , t o u s l e s m a i l l o n s de l a liste l.

190

/ void a f f i c h e T o u t ( l l l ) { i f ( l != NULL) { affiche ( l ); a f f i c h e T o u t ( l ext ) ; >n } else p r i n t f ( \n ) ; } / / / A f f i c h e en p a r t a n t de l a f i n t o u s l e s m a i l l o n s de l a l i s t e l . / void a f f i c h e A L E n v e r s ( l l l ) { i f ( l != NULL) { afficheALEnvers ( l ext ) ; >n affiche ( l ); } } / / / D e t r u i t t o u s l e s m a i l l o n s de l a a NULL. / void d e t r u i t ( l l l ) { i f ( l != NULL) { d e t r u i t ( & ( ( l )>n e x t ) ) ; f r e e ( l ) ; l = NULL ; } } / / / Retourne l a / l l e n t i e r s A L E n v e r s ( long n ) { i f (n > 0) return c r e e r ( n , e n t i e r s A L E n v e r s ( n 1 ) ) ; else return NULL ; } / / / Pour l a f o n c t i o n s u i v a n t e . . . . / l l e n t i e r s T ( long n , l l a c c ) { i f (n > 0) return e n t i e r s T ( n 1 , c r e e r ( n , a c c ) ) ; else return a c c ; } / Retourne l a / l l e n t i e r s ( long n ) { return e n t i e r s T ( n , NULL ) ; l i s t e 1 > 2 > . . . > n l i s t e n > n1 > . . . > 2 > 1 l i s t e l , met ce p o i n t e u r

191

} / / / I n s e r e l e m a i l l o n x dans l a / l l insere ( l l l , l l x) { i f ( l == NULL | | x a t a <= l a t a ) >d >d { x e x t = l ; >n return x ; } l ext = i n s e r e ( l >n >next , x ) ; return l ; } / / / Tri l a l i s t e l av ec l a methode du t r i par i n s e r t i o n , r e t o u r n e l a d r e s s e du premier e l e m e n t de l a l i s t e t r i e e . / ll triInsertion ( ll l ) { i f ( l == NULL) return NULL ; return i n s e r e ( t r i I n s e r t i o n ( l e x t ) , >n } liste l , supposee t r i e e .

l );

/ / / R e p a r t i t l e s e l e m e n t s de l e n t r e l e s l i s t e s ex : l = 1 > 2 > 3 > 4 > 5 nous donne l 1 = 1 > 3 > 5 e t l 2 = 2 > 4 / void s p l i t ( l l l , l l l 1 , l l l 2 ) { i f ( l != NULL) { s p l i t ( l >next , l 2 , l 1 ) ; l ext = l 1 ; >n l1 = l ; } } / / / Retourne l i n t e r c l a s s e m e n t d e s / l l i n t e r c l a s s e ( l l l1 , l l l 2 ) { i f ( l 1 == NULL) return l 2 ; i f ( l 2 == NULL) return l 1 ; i f ( l1 ata < l2 ata ) >d >d { l1 ext = i n t e r c l a s s e ( l1 >n >next , l 2 ) ; return l 1 ; } else { l2 ext = i n t e r c l a s s e ( l1 , l2 ext ) ; >n >n return l 2 ; } } / / / Trie l ave c l a methode du t r i f u s i o n , r e t o r u n e l a d r e s s e du premier e l e m e n t de l a l i s t e t r i e e . / listes l 1 et l2 , supposees t r i e e s . l1 et l2 .

192

l l triFusion ( l l l ) { i f ( l == NULL | | l e x t == NULL) >n return l ; else { l l l 1 = NULL, l 2 = NULL ; s p l i t ( l , &l 1 , &l 2 ) ; l1 = triFusion ( l1 ); l2 = triFusion ( l2 ); return i n t e r c l a s s e ( l 1 , l 2 ) ; } } / / / Pour t e s t e r / i n t main ( ) { long n = 5 0 0 0 0 ; l l l = e n t i e r s A L E n v e r s ( n ) , m = e n t i e r s A L E n v e r s ( n ) ; p r i n t f ( t r i f u s i o n \n ) ; l = triFusion ( l ); p r i n t f ( ok \n ) ; d e t r u i t (& l ) ; p r i n t f ( t r i i n s e r t i o n \n ) ; m = t r i I n s e r t i o n (m) ; p r i n t f ( ok \n ) ; d e t r u i t (&m) ; return 0 ; } les fonctions . . .

193

Annexe B

Projets
B.1 Agenda (pour les PPAs)

Construisez un agenda en mode console fournissant les fonctionnalits suivantes : e Edition des (date + heure de dbut + dure + libell) e e e Sauvegarde sur chier(s) Dtection des collisions (quand deux entres de lagenda se chevauchent) e e Vous rdigerez un dossier dans lequel vous expliquerez succinctement la faon vous avez procd et e c e e placerez le code source. Vous imprimerez le dossier vous-mme et ne me le rendrez pas sous forme de e feuilles volantes, date : le 30 juin. Vous menverrez le code source par mail, avant le 29 juin ` minuit. a Votre code doit tre portable ! Cela signie que je dois pouvoir le compiler sous Linux en moins de 30 e secondes (donc pas de conio.h ou de fonctionnalit spcique ` une plate-forme particuli`re). Sil est e e a e dcoup en plusieurs chiers, joignez imprativement un makele. Votre code doit aussi tre lisible : ceste e e e a `-dire form de petites fonctions dont on comprend le fonctionnement ` la premi`re lecture, portant des e a e noms dcrivant explicitement ce quelles font (vous avez droit ` 256 caract`res), et ne faisant pas appel ` e a e a des variables globales. Vous disposerez toujours une fonction appele avant la fonction appelante (pour e ne pas avoir de warnings et parce que cest plus facile ` lire quand on parcourt votre code en commenant a c par le dbut et en terminant par la n). Vous commenterez votre code et expliquerez dans le rapport e tous les points dlicats (qui ne me sembleront pas vident ` la premi`re lecture). La noblesse, la clart, e e a e e la simplicit et la lisibilit de votre code prendront une part tr`s importante dans la notation ! e e e Le dialogue avec lutilisateur peut tre rduit au minimum (commencez par quelque chose de simple). e e Faites toutefois en sorte que le dialogue soit intuitif (que je comprenne le fonctionnement de votre application sans avoir ` lire de notice) et que votre code soit stable (soignez les saisies, indices, etc.) : si un a projet ne fonctionne pas, je ne perdrai pas de temps ` le dbugger, je passerai au suivant ! Bref : faites a e quelque chose de simple, mais clair et soign. e La transmission dinformations entre les tudiants nest pas interdite, et est mme encourage. Par contre e e e votre code doit tre personnel, en cas de pompage, copier/coller, etc, les notes du projet source et du e projet copie seront 0 (thor`me de Sananes). e e

194

Annexe A

Mthodologie e
A.1 Le probl`me e

D`s que lon code un programme dune certaine envergure, bon nombre de probl`mes se posent. e e 1. Le dbogage peut devenir un cauchemar sans n. e 2. Ensuite le code crit peut tre une bouillie lisible que par son auteur. e e 3. Le code peut contenir des redondances qui nen facilite ni la lecture, ni le dbogage. e Je passe les nombreuses dicults et laideurs pouvant rsulter dun dveloppement htif. Retenez que e e e a sans mthode, vous ne parviendrez pas ` dvelopper un projet important, tout simplement parce que le e a e temps de dbogage sera prohibitif, et parce que votre code, apr`s les multiples bidouillages auxquels vous e e soumettrez pour dboguer sera un gros pav bordlique et illisible. e e e

A.2

Les r`gles dor e

La solution au probl`me mentionn ci-avant rside dans lapplication des r`gles dor suivantes : e e e e

A.2.1

Gnralits e e e

Avant toute chose, rappelons quelques vidences : e 1. indentez votre code, on doit pouvoir trouver, pour chaque accolade ouvrante, o` se trouve laccolade u fermante qui lui correspond en moins dun quart de seconde. 2. utilisez des noms de variable explicites, le nom de la variable doit tre susant pour pouvoir e comprendre ` quoi elle sert. a

A.2.2

Fonctions

Commencez par dcouper votre tr`s gros probl`me en plein de petits probl`mes que vous traiterez indie e e e viduellement avec des fonctions. Chaque fonction devra : 1. porter un nom explicite : vous avez droit ` 256 caract`res... a e 2. tre prcde dun commentaire dcrivant clairement et sans paraphraser le code ce que fait e e e e e la fonction. 3. tenir sur une page : il faut que vous puissiez voir toute la fonction sans avoir ` utiliser lascenseur, a et comprendre aisment ce quelle fait. e 4. contenir au maximum trois niveaux dimbrication : si vous avez plus de trois blocs (boucles, conditions, etc.) imbriqus, placez tout ce qui dborde dans une autre fonction. e e 5. ne jamais utiliser de variables globales : lutilisation des variables globales est rserve ` e e a certains cas tr`s prcis. Dans tous les autres cas, vos fonctions doivent utiliser les passages de e e param`tres (par adresse si ncessaire) et les valeurs de retour. e e 195

6. tre prcde de toutes les fonctions quelle appelle : dune part un lecteur parcourant votre e e e e code le comprendra plus aisment si pour chaque appel de fonction, il a dj` vu la dnition de e ea e cette fonction. Ainsi on pourra lire votre code dans lordre et viter de slalomer entre les fonctions. e Dautre part, cela vous vitera davoir ` crire les prototypes des fonctions en dbut de chier. e a e e Vous rserverez aux cas o` il et impossible (ou laid) de faire autrement les fonctions qui sinvoquent e u mutuellement.

A.2.3

Compilation spare e e

Un chier contenant plusieurs centaines de fonctions est impossible ` lire, en plus dtre dune laideur aca e cablante. Vous prendrez donc soin de regrouper vos fonctions dans des chiers, de les compiler sparment e e et de les linker avec un makele.

A.3

Dbogage e

Vous tes probablement dj` conscients du fait que le dbogage occupe une partie tr`s signicative du e ea e e temps de dveloppement. Aussi est-il apprciable de la diminuer autant que possible. e e 1. Dune part parce que lorsque ce temps devient prohibitif, il constitue une perte de temps fort malvenue. 2. Dautre part parce que les multiples bidouilles opres pour corriger les erreurs ne font souvent que ee nuire ` la lisibilit du code a e 3. Et enn parce quun temps anormalement lev est en gnral une consquence dune analyse et e e e e e dun codage htifs. a Aussi est-il gnralement plus ecace de passer un peu plus de temps ` coder, et beaucoup moins de e e a temps ` dboguer. Pour ce faire : a e 1. Notez bien que tous les conseils noncs prcdemment sont encore dactualit. En particulier ceux e e e e e sur les fonctions. 2. Construisez les fonctions dans lordre inverse de lordre dinvocation, et testez-les une par une. Les bugs sont beaucoup plus facile ` trouver quand on les cherche dans une dizaine de lignes que dans a une dizaine de pages. Et en assemblant des fonctions qui marchent correctement, vous aurez plus de chances de rdiger un programme correct. e 3. Nhsitez pas ` utiliser des logiciels comme valgrind. valgrind examine lexcution de votre code e a e et vous rapporte bon nombre dutilisation irrguli`re de la mmoire (pointeurs fous, zones non e e e libres, etc.) ee

A.4

Dure de vie du code e

Si vous ne voulez pas quun jour un dveloppeur fasse un slectionner/supprimer sur votre code, e e vous devez avoir en tte lide que quand quelquun reprend ou utilise votre code vous devez rduire au e e e minimum ` la fois le temps quil mettra ` le comprendre et le nombre de modications quil devra faire. a a

A.4.1

Le code doit tre rutilisable e e

Cela signie quun autre programmeur doit pouvoir poursuivre votre projet en faisant un minimum de modications. Autrement dit, un autre programmeur doit pouvoir appeler vos fonctions aveuglment et sans e mme regarder ce quil y a dedans. Les noms des fonctions et les commentaires dcrivant leurs comportee e ment doivent tre clairs, prcis, et bien videmment exempt de bugs. Sinon, un slectionner/supprimer e e e e mettra n ` la courte vie de votre code. Notez bien par ailleurs que si vous avez rparti votre code dans a e des chiers spars de faon intelligente, votre code sera bien plus simple ` rutiliser. e e c a e

196

A.4.2

Le code doit tre adaptable e

Supposons que pour les besoins dun projet, un autre dveloppeur veuille partir de votre code, par e exemple utiliser des listes cha ees au lieu de tableau, ou encore ajouter une sauvegarde sur chier, n etc. Si votre code est bien dcoup, il naura que quelques fonctions ` modier. Si par contre, vous avez e e a mlang achage, saisies, calculs, sauvegardes, etc. Notre dveloppeur devra passer un temps considrable e e e e a ` bidouiller votre code, et cela sans aucune certitude quand ` la qualit du rsultat. Il fera donc un a e e slectionner/supprimer et recodera tout lui-mme. e e

A.5

Exemple : le carnet de contacts

Je me suis eorc, autant que possible, de suivre mes propres conseils et de vous donner un exemple. e Je vous laisse ` la fois observer mes recommandations dans le code qui suit, et traquer les ventuelles a e eractions que jaurais pu commettre.

A.5.1

util.h

#i f n d e f UTIL H #d e f i n e UTIL H / S a i s i t une c h a i n e de c a r a c t e r e s de l o n g u e u r sizeMax a l a d r e s s e adr , e l i m i n e l e c a r a c t e r e de r e t o u r a l a l i g n e e t v i d e s i n e c e s s a i r e t o u s l e s c a r a c t e r e s s u p p l e m e n t a i r e s du tampon de s a i s i e . / void g e t S t r i n g ( char adr , i n t siz eMa x ) ;

/ / / S a i s i t un e n t i e r . / int g e t I n t ( ) ; / / / Echange l e s c h a i n e s de c a r a c t e r e s s1 e t s2 , de t a i l l e s maximales sizeMax . / void s w a p S t r i n g s ( char s1 , char s2 , i n t siz eMa x ) ; #e n d i f

A.5.2

util.c

#include<s t d i o . h> #include<s t d l i b . h> #include<s t r i n g . h> void g e t S t r i n g ( char adr , i n t siz eMa x ) { int len ; f g e t s ( adr , sizeMax , s t d i n ) ; l e n = s t r l e n ( adr ) ; i f ( ( a d r + l e n 1 ) == \n ) ( adr + l e n 1) = 0 ; else while ( g e t c h a r ( ) != \n ) ; } / / int g e t I n t ( ) { char t a b [ 1 0 ] ; g e t S t r i n g ( tab , 1 0 ) ; return a t o i ( t a b ) ; }

197

/ / void s w a p S t r i n g s ( char s1 , char s2 , i n t siz eMa x ) { char temp [ siz eMa x ] ; s t r n c p y ( temp , s1 , s ize Max ) ; s t r n c p y ( s1 , s2 , s ize Max ) ; s t r n c p y ( s2 , temp , s ize Max ) ; ( s 1 + s ize Max 1 ) = 0 ; ( s 2 + s ize Max 1 ) = 0 ; }

A.5.3

tableau.h

#i f n d e f TABLEAU H #d e f i n e TABLEAU H #d e f i n e SIZE MAIL 30 #d e f i n e NB MAILS 6 / Implemente un c a r n e t de c o n t a c t s a l a i d e d un t a b l e a u . Une c a s e i n o c c u p e e e s t r e p r e s e n t e e par une c h a i n e v i d e , t o u t e s l e s a d r e s s e s s o n t d i s p o s e e s par o r d r e a l p h a b e t i q u e au d e b u t du t a b l e a u . / / / / A f f i c h e l e c a r n e t de c o n t a c t s . / void a f f i c h e M a i l s ( char m a i l s ) ; / / / Retourne l a d r e s s e du i eme mai l . / char g e t M a i l ( char m a i l s , i n t i ) ; / / / Retourne l e nombre de c o n t a c t s . / i n t nombreMails ( char m a i l s ) ; / / / Creee un t a b l e a u de d em a i l s e t l e r e t o u r n e . Ce t a b l e a u c o n t i e n t NB MAILS c h a i n e s de c a p a c i t e s l o n g u e u r SIZE MAIL i n i t i a l i s e s avec d e s c h a i n e s v i d e s . / char c r e e r M a i l s ( ) ; / / / L i b e r e l a memoire / void d e t r u i t M a i l s ( char m a i l s ) ; / / / Supprime l a d r e s s e dont l i n d i c e e s t p a s s e en parametre . / void s u p p r i m e M a i l ( char m a i l s , i n t i n d i c e ) ; / / /

198

Ajoute l e m ail mai l dans l e t a b l e a u m a i l s . / void a j o u t e M a i l ( char m a i l s , char m a i l ) ; / / / Remplace l e i n d i c e eme mai l du t a b l e a u m a i l s par ma il . L i n d i c e e s t suppose v a l i d e . / void c h a n g e M a i l ( char m a i l s , char mail , i n t i n d i c e ) ; / / / E c r i t t o u s l e s c o n t a c t s de m a i l s dans l e / void s a u v e g a r d e M a i l s ( char m a i l s , char n o m F i c h i e r ) ; / / / L i t t o u s l e s c o n t a c t s de m a i l s dans l e / void r e s t a u r e M a i l s ( char m a i l s , char n o m F i c h i e r ) ; #e n d i f f i c h i e r nomFichier . f i c h i e r nomFichier .

A.5.4

tableau.c

#include<s t d i o . h> #include<m a l l o c . h> #include<s t r i n g . h> #include<s t d l i b . h> #include u t i l . h #include t a b l e a u . h / / void a f f i c h e M a i l s ( char m a i l s ) { int i n d i c e = 0 ; p r i n t f ( L i s t e d e s c o n t a c t s : \n ) ; while ( i n d i c e < NB MAILS && g e t M a i l ( m a i l s , i n d i c e ) ) { p r i n t f ( %d : %s \n , i n d i c e + 1 , g e t M a i l ( m a i l s , i n d i c e ) ) ; i n d i c e ++; } } / / char g e t M a i l ( char m a i l s , i n t i ) { return m a i l s + i SIZE MAIL ; } / / i n t nombreMails ( char m a i l s ) { int i n d i c e = 0 ; while ( i n d i c e < NB MAILS && g e t M a i l ( m a i l s , i n d i c e ++; return i n d i c e ; }

indice ))

/ / char c r e e r M a i l s ( ) { char a d r = ( char ) m a l l o c ( s i z e o f ( char ) SIZE MAIL NB MAILS ) ; int i ; i f ( a d r == NULL) { p r i n t f ( Heap o v e r f l o w ) ; exit (0);

199

} f o r ( i = 0 ; i < NB MAILS ; g e t M a i l ( adr , i ) = 0 ; return a d r ; }

i ++)

/ / void d e t r u i t M a i l s ( char m a i l s ) { f r e e ( mails ) ; } / / void s u p p r i m e M a i l ( char m a i l s , i n t i n d i c e ) { while ( i n d i c e < NB MAILS && g e t M a i l ( m a i l s , { strncpy ( getMail ( mails , i n d i c e ) , getMail ( mails , i n d i c e + 1) , SIZE MAIL ) ; i n d i c e ++; } i f ( i n d i c e < NB MAILS) getMail ( mails , i n d i c e ) = 0 ; }

indice + 1))

/ / / Retourne l i n d i c e du premier emplacement l i b r e dans l e t a b l e a u m a i l s c o n t e n a n t nbMax a d r e s s e s . On s u p p o s e que l e t a b l e a u n e s t pas p l e i n . / i n t i n d i c e P r e m i e r e C h a i n e V i d e ( char m a i l s , i n t i n d i c e M a x ) { int mi lie u ; i f ( i n d i c e M a x == 0 ) return 0 ; m i l i e u = indiceMax / 2 ; i f ( ! getMail ( mails , m i l i e u ) ) return i n d i c e P r e m i e r e C h a i n e V i d e ( m a i l s , m i l i e u ) ; else return m i l i e u + 1 + indicePremiereChaineVide ( getMail ( mails , m i l i e u + 1) , indiceMax ( m i l i e u + 1 ) ) ; } / / / Trie l e t a b l e a u m a i l s c o n t e n a n t ( i n d i c e + 1) e l e m e n t s , ne f o n c t i o n n e que s i t o u s l e s a u t r e s e l e m e n t s sont t r i e s . / void p l a c e M a i l ( char m a i l s , i n t i n d i c e ) { i f ( i n d i c e > 0 && i n d i c e < NB MAILS && strncmp ( g e t M a i l ( m a i l s , i n d i c e ) , getMail ( mails , i n d i c e 1) , SIZE MAIL ) < 0 ) { swapStrings ( getMail ( mails , i n d i c e ) , getMail ( mails , i n d i c e 1) , SIZE MAIL ) ; placeMail ( mails , i n d i c e 1 ) ; } else i f ( i n d i c e >= 0 && i n d i c e < NB MAILS 1 && g e t M a i l ( m a i l s , i n d i c e + 1 ) && strncmp ( g e t M a i l ( m a i l s , i n d i c e ) , getMail ( mails , i n d i c e + 1) , SIZE MAIL ) > 0 ) { swapStrings ( getMail ( mails , i n d i c e ) , getMail ( mails , i n d i c e + 1) , SIZE MAIL ) ; placeMail ( mails , i n d i c e + 1 ) ;

200

} } / / void a j o u t e M a i l ( char m a i l s , char m a i l ) { int i n d i c e ; i f ( g e t M a i l ( m a i l s , NB MAILS 1 ) ) { p r i n t f ( Carnet de c o n t a c t p l e i n . \ n ) ; } else { i n d i c e = i n d i c e P r e m i e r e C h a i n e V i d e ( m a i l s , NB MAILS 1 ) ; s t r n c p y ( g e t M a i l ( m a i l s , i n d i c e ) , mail , SIZE MAIL ) ; ( g e t M a i l ( m a i l s , i n d i c e ) + SIZE MAIL 1 ) = 0 ; placeMail ( mails , i n d i c e ) ; } } / / void c h a n g e M a i l ( char m a i l s , char mail , i n t i n d i c e ) { s t r n c p y ( g e t M a i l ( m a i l s , i n d i c e ) , mail , SIZE MAIL ) ; ( g e t M a i l ( m a i l s , i n d i c e ) + SIZE MAIL 1 ) = 0 ; placeMail ( mails , i n d i c e ) ; } / / void s a u v e g a r d e M a i l s ( char m a i l s , char n o m F i c h i e r ) { FILE f = f o p e n ( n o m F i c h i e r , w ) ; int i ; i f ( f == NULL) p r i n t f ( I m p o s s i b l e d o u v r i r l e f i c h i e r %s , n o m F i c h i e r ) ; else f o r ( i = 0 ; i < NB MAILS && g e t M a i l ( m a i l s , i ) ; i ++) f w r i t e ( g e t M a i l ( m a i l s , i ) , s i z e o f ( char ) , SIZE MAIL , f ) ; fclose ( f ); } / / void r e s t a u r e M a i l s ( char m a i l s , char n o m F i c h i e r ) { FILE f = f o p e n ( n o m F i c h i e r , r ) ; int i , r e t = 1 ; i f ( f == NULL) p r i n t f ( I m p o s s i b l e d o u v r i r l e f i c h i e r %s , n o m F i c h i e r ) ; else f o r ( i = 0 ; i < NB MAILS && r e t ; i ++) r e t = f r e a d ( g e t M a i l ( m a i l s , i ) , s i z e o f ( char ) , SIZE MAIL , fclose ( f ); }

f );

A.5.5

eMails.c

#include<s t d i o . h> #include<s t d l i b . h> #include u t i l . h #include t a b l e a u . h #d e f i n e #d e f i n e #d e f i n e #d e f i n e #d e f i n e #d e f i n e AFFICHER OPTION 1 SUPPRIMER OPTION 2 MODIFIER OPTION 3 AJOUTER OPTION 4 QUITTER OPTION 5 NB OPTIONS 5

#d e f i n e F NAME . a d r e s s e s M a i l s . t x t / / / A f f i c h e l e menu p r i n c i p a l . /

201

void a f f i c h e M e n u ( ) { p r i n t f ( \ n O p t i o n s d i s p o n i b l e s : \ n %d a f f i c h e r l e s c o n t a c t s \n %d s u p p r i m e r un c o n t a c t \n %d m o d i f i e r un c o n t a c t \n %d a j o u t e r un c o n t a c t \n %d q u i t t e r \n , AFFICHER OPTION, SUPPRIMER OPTION, MODIFIER OPTION , AJOUTER OPTION, QUITTER OPTION ) ; } / / / A f f i c h e l e menu p r i n c i p a l , r e t o u r n e l a v a l e u r s a i s i e par l utilisateur . / int choisitOptionMenu ( ) { int option ; do { afficheMenu ( ) ; p r i n t f ( C h o i s i s s e z une o p t i o n en s a i s i s s a n t son numero : ) ; option = getInt ( ) ; i f ( o p t i o n <= 0 && o p t i o n > NB OPTIONS) p r i n t f ( o p t i o n i n v a l i d e \n ) ; } while ( o p t i o n <= 0 && o p t i o n > NB OPTIONS ) ; return o p t i o n ; } / / / Demande a l u t i l i s a t e u r de s a i s i r un mail , a l a d r e s s e adr . / void s a i s i t M a i l ( char a d r ) { p r i n t f ( V e u i l l e z s a i s i r l a d r e s s e em a i l de v o t r e c o n t a c t do { g e t S t r i n g ( adr , SIZE MAIL ) ; i f ( ! adr ) p r i n t f ( Vous d e v e z s a i s i r une a d r e s s e ) ; } while ( ! a d r ) ; } / / / A f f i c h e l a l i s t e de mai ls , l un d eux . / i n t c h o i s i t M a i l ( char m a i l s ) { int i , nbMails ; n b M a i l s = nombreMails ( m a i l s ) ; afficheMails ( mails ) ; do { p r i n t f ( C h o i s i s s e z un m a i l en s a i s i s s a n t s on numero : ) ; i = getInt ( ) ; i f ( i <= 0 && i > n b M a i l s ) p r i n t f ( Cet i n d i c e n e x i s t e p as ! \n ) ; } while ( i <= 0 && i > n b M a i l s ) ; return i 1 ; } / / saisit e t r e t o u r n e l e numero de le place

: );

202

/ S a i s i t un mai l m e t un i n d i c e i , p u i s remplace l e i eme mai l de m a i l s par m. / void m o d i f i e r O p t i o n ( char m a i l s ) { int i ; char m[ SIZE MAIL ] ; p r i n t f ( M o d i f i c a t i o n d un c o n t a c t i = choisitMail ( mails ) ; s a i s i t M a i l (m) ; c h a n g e M a i l ( m a i l s , m, i ) ; }

: \n ) ;

/ / / S a i s i t un mai l m e t un i n d i c e i , p u i s remplace l e i eme mai l de m a i l s par m. / void a j o u t e r O p t i o n ( char m a i l s ) { char m[ SIZE MAIL ] ; p r i n t f ( Ajout d un c o n t a c t : \n ) ; s a i s i t M a i l (m) ; a j o u t e M a i l ( m a i l s , m) ; } / / / S a i s i t un i n d i c e i , p u i s supprime l e i eme mai l dans m a i l s . / void s u p p r i m e r O p t i o n ( char m a i l s ) { int i ; p r i n t f ( S u p p r e s s i o n d un c o n t a c t i = choisitMail ( mails ) ; supprimeMail ( mails , i ) ; }

: \n ) ;

/ / / Sauve l e s m a i l s dans l e d adieu . / void q u i t t e r O p t i o n ( char m a i l s ) { s a u v e g a r d e M a i l s ( m a i l s , F NAME ) ; p r i n t f ( Au r e v o i r ! \ n ) ; } / / / A f f i c h e l e menu p r i n c i p a l , traitement necessaire . / void executeMenu ( char m a i l s ) { int option ; do { option = choisitOptionMenu ( ) ; switch ( o p t i o n ) { case AFFICHER OPTION : afficheMails ( mails ) ; break ; case AJOUTER OPTION : ajouterOption ( mails ) ; break ; case MODIFIER OPTION : modifierOption ( mails ) ; break ; s a i s i t une o p t i o n , e t e f f e c t u e le f i c h i e r F NAME e t a f f i c h e un message

203

case SUPPRIMER OPTION : supprimerOption ( mails ) ; break ; case QUITTER OPTION : quitterOption ( mails ) ; break ; default : break ; } } while ( o p t i o n != QUITTER OPTION ) ; } / / i n t main ( ) { char m a i l s = c r e e r M a i l s ( ) ; r e s t a u r e M a i l s ( m a i l s , F NAME ) ; executeMenu ( m a i l s ) ; detruitMails ( mails ) ; return 0 ; }

A.5.6
all util .o:

makele
util . c util .h g c c Wall c u t i l . c

: eMails eMails . tgz

tableau . o : tableau . c tableau . h u t i l . h g c c Wall c t a b l e a u . c eMails . o : eMails . c tableau . h u t i l . h g c c Wall c e M a i l s . c eMails : u t i l . o tableau . o eMails . o g c c o e M a i l s Wall u t i l . o t a b l e a u . o e M a i l s . o

eMails . tgz : u t i l . h u t i l . c tableau . h tableau . c eMails . c makefile tar cvfz eMails . tgz u t i l . h u t i l . c tableau . h tableau . c eMails . c makefile

204

You might also like