Vous êtes sur la page 1sur 209

Initiation au Langage C

Alexandre Mesl e 7 f evrier 2012

Table des mati` eres


1 Notes de cours 1.1 Introduction . . . . . . . . . . . . . . 1.1.1 D enitions et terminologie . . 1.1.2 Hello World ! . . . . . . . . . 1.1.3 Structure dun programme C 1.1.4 Commentaires . . . . . . . . 1.2 Variables . . . . . . . . . . . . . . . 1.2.1 D eclaration . . . . . . . . . . 1.2.2 Aectation . . . . . . . . . . 1.2.3 Saisie . . . . . . . . . . . . . 1.2.4 Achage . . . . . . . . . . . 1.2.5 Entiers . . . . . . . . . . . . . 1.2.6 Flottants . . . . . . . . . . . 1.2.7 Caract` eres . . . . . . . . . . . 1.2.8 Constantes . . . . . . . . . . 1.3 Op erateurs . . . . . . . . . . . . . . 1.3.1 G en eralit es . . . . . . . . . . 1.3.2 Les op erateurs unaires . . . . 1.3.3 Les op erateurs binaires . . . . 1.3.4 Formes contract ees . . . . . . 1.3.5 Op erations h et erog` enes . . . 1.3.6 Les priorit es . . . . . . . . . . 1.4 Traitements conditionnels . . . . . . 1.4.1 Si ... Alors . . . . . . . . . . . 1.4.2 Switch . . . . . . . . . . . . . 1.4.3 Bool eens . . . . . . . . . . . . 1.4.4 Les priorit es . . . . . . . . . . 1.4.5 Pr eprocesseur . . . . . . . . . 1.5 Boucles . . . . . . . . . . . . . . . . 1.5.1 D enitions et terminologie . . 1.5.2 while . . . . . . . . . . . . . 1.5.3 do ... while . . . . . . . . 1.5.4 for . . . . . . . . . . . . . . 1.5.5 Accolades superues . . . . . 1.6 Tableaux . . . . . . . . . . . . . . . 1.6.1 D enitions . . . . . . . . . . 1.6.2 D eclaration . . . . . . . . . . 1.6.3 Initialisation . . . . . . . . . 1.6.4 Acc` es aux el ements . . . . . . 1.6.5 Exemple . . . . . . . . . . . . 1.7 Cha nes de caract` eres . . . . . . . . 1.7.1 Exemple . . . . . . . . . . . . 1.7.2 D enition . . . . . . . . . . . 6 6 6 7 7 8 9 9 9 10 10 11 12 12 12 14 14 14 15 16 17 18 19 19 22 22 23 23 26 26 26 27 27 28 29 29 29 29 30 30 33 33 33

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1.7.3 D eclaration . . . . . . . . . . . . . . 1.7.4 Initialisation . . . . . . . . . . . . . 1.7.5 Acc` es aux el ements . . . . . . . . . . 1.7.6 Achage . . . . . . . . . . . . . . . 1.7.7 Saisie . . . . . . . . . . . . . . . . . 1.7.8 Probl` emes li es ` a la saisie bueris ee . 1.7.9 La biblioth` eque string.h . . . . . . 1.7.10 Exemple . . . . . . . . . . . . . . . . 1.8 Fonctions . . . . . . . . . . . . . . . . . . . 1.8.1 Les proc edures . . . . . . . . . . . . 1.8.2 Variables locales . . . . . . . . . . . 1.8.3 Passage de param` etres . . . . . . . . 1.8.4 Les fonctions . . . . . . . . . . . . . 1.8.5 Passages de param` etre par r ef erence 1.9 Structures . . . . . . . . . . . . . . . . . . . 1.9.1 D enition . . . . . . . . . . . . . . . 1.9.2 D eclaration . . . . . . . . . . . . . . 1.9.3 Acc` es aux champs . . . . . . . . . . 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 m emoire 1.10.4 Passage de param` etres par r ef erence 1.10.5 Pointeurs sur fonction . . . . . . . . 1.11 Fichiers . . . . . . . . . . . . . . . . . . . . 1.11.1 D enitions . . . . . . . . . . . . . . 1.11.2 Ouverture et fermeture . . . . . . . 1.11.3 Lecture et ecriture . . . . . . . . . . 1.12 Listes Cha n ees . . . . . . . . . . . . . . . . 1.12.1 Le probl` eme . . . . . . . . . . . . . . 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 Op erations . . . . . . . . . . . . . . 1.12.7 Listes doublement cha n ees . . . . . 2 Exercices 2.1 Variables et op erateurs . . . . . . . . . . 2.1.1 Entiers . . . . . . . . . . . . . . . 2.1.2 Flottants . . . . . . . . . . . . . 2.1.3 Caract` eres . . . . . . . . . . . . . 2.1.4 Op erations sur les bits (diciles) 2.1.5 Morceaux choisis (diciles) . . . 2.2 Traitements conditionnels . . . . . . . . 2.2.1 Prise en main . . . . . . . . . . . 2.2.2 Switch . . . . . . . . . . . . . . . 2.2.3 L echiquier . . . . . . . . . . . . 2.2.4 Heures et dates . . . . . . . . . . 2.2.5 Intervalles et rectangles . . . . . 2.2.6 Pr eprocesseur . . . . . . . . . . . 2.2.7 Nombres et lettres . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

33 33 34 34 34 36 36 36 38 38 40 41 44 45 46 46 46 46 47 47 48 51 51 53 56 59 61 62 62 62 63 66 66 66 69 70 72 75 75 77 77 77 77 78 78 79 80 80 80 81 81 82 82 84

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Boucles . . . . . . . . . . . . . . . . . . . . . 2.3.1 Compr ehension . . . . . . . . . . . . . 2.3.2 Utilisation de toutes les boucles . . . . 2.3.3 Choix de la boucle la plus appropri ee 2.3.4 Morceaux choisis . . . . . . . . . . . . 2.3.5 Extension de la calculatrice . . . . . . 2.4 Tableaux . . . . . . . . . . . . . . . . . . . . 2.4.1 Exercices de compr ehension . . . . . . 2.4.2 Prise en main . . . . . . . . . . . . . . 2.4.3 Indices . . . . . . . . . . . . . . . . . . 2.4.4 Recherche s equentielle . . . . . . . . . 2.4.5 Morceaux choisis . . . . . . . . . . . . 2.5 Cha nes de caract` eres . . . . . . . . . . . . . 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 G eom etrie . . . . . . . . . . . . . . . . 2.6.2 Arithm etique . . . . . . . . . . . . . . 2.6.3 Passage de tableaux en param` etre . . 2.6.4 D ecomposition en facteurs premiers . 2.6.5 Statistiques . . . . . . . . . . . . . . . 2.6.6 Cha nes de caract` eres . . . . . . . . . 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 journ ee . . . . . . . . . . 2.7.3 R epertoire t el ephonique . . . . . . . . 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` etres par r ef erence . 2.8.7 Les pointeurs sans etoile . . . . . . . . 2.8.8 Tableau de tableaux . . . . . . . . . . 2.8.9 Triangle de Pascal . . . . . . . . . . . 2.8.10 Pointeurs et r ecursivit 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 ecriture . . . . . . . . . . . 2.9.5 Enigma . . . . . . . . . . . . . . . . . 2.10 Matrices . . . . . . . . . . . . . . . . . . . . . 2.11 Listes Cha n ees . . . . . . . . . . . . . . . . . 2.11.1 Pointeurs et structures . . . . . . . . . 2.11.2 Maniement du cha nage . . . . . . . . 2.11.3 Op erations sur les listes cha n ees . . . 2.11.4 Listes doublement cha n ees . . . . . . 2.11.5 Fonctions r ecursives et listes cha n ees

2.3

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

85 85 86 86 86 87 89 89 89 90 90 90 92 92 92 93 94 94 96 97 98 99 100 100 100 102 102 102 104 105 105 105 106 106 106 107 108 109 109 109 110 113 113 113 113 113 113 118 119 119 119 121 121 122

A Quelques corrig es A.1 Variables et op erateurs . . . . . . . . . . . . . . . . A.1.1 Entiers . . . . . . . . . . . . . . . . . . . . . A.1.2 Flottants . . . . . . . . . . . . . . . . . . . A.1.3 Caract` eres . . . . . . . . . . . . . . . . . . . A.1.4 Op erations binaires . . . . . . . . . . . . . . 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 appropri ee . . . A.3.3 Morceaux choisis . . . . . . . . . . . . . . . A.4 Tableaux . . . . . . . . . . . . . . . . . . . . . . . A.4.1 Prise en main . . . . . . . . . . . . . . . . . A.4.2 Indices . . . . . . . . . . . . . . . . . . . . . A.4.3 Recherche s equentielle . . . . . . . . . . . . A.4.4 Morceaux choisis . . . . . . . . . . . . . . . A.5 Cha nes de caract` eres . . . . . . . . . . . . . . . . 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 G eom etrie . . . . . . . . . . . . . . . . . . . A.6.2 Arithm etique . . . . . . . . . . . . . . . . . A.6.3 Passage de tableaux en param` etre . . . . . A.6.4 D ecomposition en facteurs premiers . . . . A.6.5 Statistiques . . . . . . . . . . . . . . . . . . A.6.6 Chaines de caract` eres . . . . . . . . . . . . A.6.7 Programmation dun pendu . . . . . . . . . A.6.8 Tris . . . . . . . . . . . . . . . . . . . . . . A.7 Structures . . . . . . . . . . . . . . . . . . . . . . . A.7.1 Heures . . . . . . . . . . . . . . . . . . . . . A.7.2 R epertoire t el ephonique . . . . . . . . . . . A.8 Pointeurs . . . . . . . . . . . . . . . . . . . . . . . A.8.1 Exercices sans sous-programmes . . . . . . A.8.2 Pointeurs sans etoiles et triangle de Pascal . A.8.3 Fonctions r ecursives . . . . . . . . . . . . . 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 ecriture . . . . . . . . . . . . . . A.10 Listes Cha n ees . . . . . . . . . . . . . . . . . . . . A.10.1 Pointeurs et structures . . . . . . . . . . . . A.10.2 Maniement du cha nage . . . . . . . . . . . A.10.3 Listes doublement cha n ees . . . . . . . . . A.10.4 Fonctions r ecursives et listes cha n ees . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

125 125 125 126 127 128 130 132 132 135 135 136 138 141 144 144 145 146 149 149 150 151 152 155 155 156 157 159 159 161 163 164 166 166 167 168 170 170 171 175 175 176 179 182 186 186 186 186 187 189 189 189 192 195

A M ethodologie A.1 Le probl` eme . . . . . . . . . . . . . . A.2 Les r` egles dor . . . . . . . . . . . . . A.2.1 G en eralit es . . . . . . . . . . A.2.2 Fonctions . . . . . . . . . . . A.2.3 Compilation s epar ee . . . . . A.3 D ebogage . . . . . . . . . . . . . . . A.4 Dur ee de vie du code . . . . . . . . . A.4.1 Le code doit etre r eutilisable A.4.2 Le code doit etre adaptable . 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 . . . . . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

199 199 199 199 199 200 200 200 200 201 201 201 201 202 203 205 208

Chapitre 1

Notes de cours
1.1
1.1.1

Introduction
D enitions et terminologie

Un programme ex ecutable est une suite dinstructions ex ecut ee par le processeur. Ces instructions sont tr` es dicile ` a comprendre, si par exemple, vous ouvrez avec un editeur de texte (notepad, emacs, etc) un chier ex ecutable, vous verrez sacher un charabia incompr ehensible : 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 cr eer des programmes en ecrivant des suites de chires et de lettres. Nous allons donc utiliser des langages de programmation pour ce faire. Un programme C est un ensemble dinstructions qui se saisit dans un chier .c ` a laide dun editeur

(ex. : Notepad), ce type de chier sappelle une source. Les instructions qui y sont ecrites sappellent du code ou encore le code source. Un compilateur est un logiciel qui lit le code source et le convertit en un code ex ecutable, cest-` a-dire un ensemble dinstructions compr ehensible par le processeur. La compilation dune source se fait en deux etapes : la compilation proprement dite et le linkage. On utilise en g en eral le terme compilation en englobant les deux etapes pr ec edemment cit ees. La compilation ` a proprement parler produit un chier objet, dont lextension est .obj. Les sources peuvent etre r eparties dans plusieurs chiers, ceux-ci doivent tous etre compil es s epar ement. Ensuite, le linkage des di erents chiers objets est assemblage produisant un ex ecutable .exe. Certains environnement de d eveloppement servent d editeur, et prennent en charge la compilation et le linkage (eclipse, dev-C++).

1.1.2

Hello World !

Allez sur http://www.01net.com/telecharger/windows/Programmation/langage/fiches/2327.html, cliquez sur t el echarger. Installez Dev-C++. Ouvrez un nouveau chier source. Copiez-collez le code cidessous dans l editeur : #include < s t d i o . h> #include < c o n i o . h> int main ( ) { printf ( H e l l o World ! \ n ) ; getch ( ) ; return 0 ; } Sauvegardez ce chier sous le nom helloWorld.c. Dans le menu Ex ecuter, cliquez sur Compiler. Remarquez que la compilation a produit un chier helloWorld.exe. Vous avez deux fa cons de lex ecuter : double-cliquez directement sur helloWorld.exe Dans le menu Ex ecuter, cliquez sur ex ecuter.

1.1.3

Structure dun programme C

Importation des biblioth` eques #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 di erentes fonctions. Celles-ci sont disponibles dans des biblioth` eques. Par exemple : stdio.h propose des fonctions de saisie et dachage conio.h propose dautre fonctions dentr ees-sorties Corps du programme int main ( ) { printf ( H e l l o w o r l d ! ) ; getch ( ) ; return 0 ; } On place dans les accolades du main les instructions que lon souhaite voir sex ecuter :

int main ( ) { <instructionsAExecuter > return 0 ; } Remarquez que chaque ligne se termine par un points-virgule. Pour acher une variable de type aphanum erique en C, on utilise printf(<valeur ` a afficher>);. Les litt eraux de type alphanum eriques en C s ecrivent entre doubles quotes. getch(); nous sert ` a suspendre lex ecution du programme jusqu` a ce que lutilisateur appuie sur une touche.

1.1.4

Commentaires

Un commentaire est une s equence de caract` eres ignor ee par le compilateur, on sen sert pour expliquer des portions de code. Alors ayez une pens ee pour les pauvres programmeurs qui vont reprendre votre code apr` es vous, le pauvre correcteur qui va essayer de comprendre votre pens ee profonde, ou bien plus simplement ` a vous-m eme au bout de six mois, quand vous aurez compl` etement oubli e ce que vous aviez dans la t ete en codant. On d elimite un commentaire par /* et */. Par exemple, 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 e s par l e c o m p i l a t e u r . / printf ( H e l l o w o r l d ! \ n ) ; return 0 ; }

1.2

Variables

Une variable est un emplacement de la m emoire dans lequel est stock ee une valeur. Chaque variable porte une nom et cest ce nom qui sert ` a identier lemplacement de la m emoire repr esent e par cette variable. Pour utiliser une variable, la premi` ere etape est la d eclaration.

1.2.1

D eclaration

D eclarer une variable, cest pr evenir le compilateur quun nom va etre utilis e pour d esigner un emplacement de la m emoire. En C, on d eclare les variables juste apr` es laccolade suivant main() (pour le moment). On place les instructions ` a ex ecuter ` a la suite de la d eclaration de variables. main ( ) { <declaration de variables > <instructions a executer > } Nous ne travaillerons pour le moment que sur les variables de type num erique entier. Le type qui y correspond, en C, est int. On d eclare les variables enti` eres de la mani` ere suivante : int <var_1 > , <var_2 > , . . . , <var_n > ; Cette instruction d eclare les variables var 1, var 2, ..., var n de type entier. Par exemple, #include < s t d i o . h> int main ( ) { int variable1 , variable2 ; int autrevariable1 , autrevariable2 ; return 0 ; } On appelle bloc le contenu des accolades du main.

1.2.2

Aectation

Si on souhaite aecter ` a la variable v une valeur, on utilise lop erateur =. Par exemple, int main ( ) { int v ; v = 5; return 0 ; } Ce programme d eclare une variable de type entier que lon appelle v, puis lui aecte la valeur 5. Comme vous venez de le voir, il est possible d ecrire directement dans le code une valeur que lon donne ` a une variable. Notez labscence de include, ce programme neectue aucune entr ee-sortie, il nest donc pas n ecessaire dimporter les biblioth` eques dentr ees/sorties. Les op erations arihm etiques disponibles sont laddition (+), la soustraction (-), la multiplication (*), la division enti` ere dans lensemble des entiers relatifs (quotient : /, reste : %). int main ( ) { int v , w , z ;

v = 5; w = v + 1; 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 r ecup erer la saisie dun utilisateur et la placer dans une variable <variable>, on utilise linstruction suivante : scanf ( %d , &<variable > ); scanf suspend lex ecution du programme jusqu` a ce que lutilisateur ait saisi une valeur et press e la touche return. La valeur saisie est alors aet ee ` a la variable <variable>. Noubliez surtout pas le &, 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. printf ( %d , <variable > ); Cette instruction ache la valeur contenue dans la variable variable (ne vous laissez pas impressionner par lapparente complexit e de cette instruction !). Nous avons etendu, en algorithmique, linstruction Afficher en intercalant des valeurs de variables entre les messages ach es. Il est possible de faire de m eme en C : printf ( 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 ` a %d la valeur de la variable v. Il est possible de l etendre ` a volont e: printf ( 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 ` a chaque %d les valeurs des trois variables x, y et z. Par exemple, le programme suivant #include < s t d i o . h> int main ( ) { int a , b , c ; a = 1; b = 2; c = 3 printf ( 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.

10

1.2.5

Entiers

Trois types de base servent ` a repr esenter les entiers : nom taille (t) nombre de valeurs (28t ) cha ne de format 8 short 1 octet 2 valeurs %hd int 2 octets 216 valeurs %d long 4 octets 232 valeurs %ld Entiers non sign es Par d efaut, les entiers permettent de stocker des valeurs de signe quelconque. Si on pr exe un type entier par unsigned, on le restreint ` a des valeurs uniquement positives. Dans ce cas, on 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, encod ee en binaire, est {0000 0000, 0000 0001, 0000 0010, 0000 0011, . . . , 1111 1110, 1111 1111} Entiers sign es Si par contre les donn ees sont sign ees, on a comme plage de valeurs 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, encod ee en binaire, est aussi plus grande valeur 27 1 215 1 231 1

{0000 0000, 0000 0001, 0000 0010, 0000 0011, . . . , 1111 1110, 1111 1111} M eme si les codages sont les m emes, la signication ne lest pas, les nombres entiers positifs sont cod es sur lintervalle : {0000 0000, 0000 0001, 0000 0010, 0000 0011, . . . , 0111 1100, 0111 1101, 0111 1110, 0111 1111} Et les nombres n egatifs sur lintervalle {1000 0000, 1000 0001, 1000 0010, 1000 0011, . . . , 1111 1100, 1111 1101, 1111 1110, 1111 1111} Les nombres n egatifs sont dispos es du plus grand jusquau plus petit, lintervalle pr ec edent code les valeurs : {27 , (27 1), (27 2), (27 3), . . . , 4, 3, 2, 1} Les op erations arithm etiques sont ex ecut ees assez b etement, si vous calculez 0111 1111 + 0000 0001, ce qui correspond ` a (27 1) + 1, le r esultat math ematique est 27 , ce qui se code 1000 0000, ce qui est le codage de 27 . Soyez donc attentifs, en cas de d epassement de capacit e dun nombre entier, vous vous retrouverez avec des nombres qui ne veulent rien dire. Si vous souhaitez faire des calculs sur des r eels, un type ottant sera davantage adapt e.

11

1.2.6

Flottants

Les ottants servent ` a repr esenter les r eels. Leur nom vient du fait quon les repr esente de fa con scientique : un nombre d ecimal (` a virgule) muni dun exposant (un d ecalage de la virgule). Trois types de base servent ` a repr esenter les ottants : nom taille cha ne de format float 4 octet %f double 8 octets %f long double 10 octets %Lf Il est conventionel d ecrire des litt eraux ottants avec un point, par exemple lapproximation ` a 102 pr` es de secrit 3.14. Il est aussi possible dutiliser la notation scientique, par exemple le d ecimal 1 000 s ecrit 1e3, ` a savoir 1.103 .Nous nous limiterons ` a la description du type float, les autres types ob eissent a des r` ` egles similaires. Repr esentation en m emoire dun float Le codage dun nombre de type float (32 bits) est d ecoup e en trois parties : 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 ` a 0, n egatif si le bit de signe est ` a 1. La mantisse et lexposant m sont cod es en binaire, la valeur absolue dun ottant de mantisse m et dexposant e est 23 .2e . Le plus 2 (223 1) , le plus grand exposant est 27 , donc grand entier quil est possible de coder sur 23 octets est 223 (223 1) (27 ) (223 1) (27 ) . 2 , donc le plus petit est .2 . le plus grand ottant est 223 223

1.2.7

Caract` eres

Un char sert ` a repr esenter le code ASCII dun caract` ere, il est donc cod e sur 1 octet. Il est possible daecter ` a une telle variable toute valeur du code ASCII entour ee de simples quotes. Par exemple, laectation suivante place dans a le code ASCII du caract` ere B. char a ; a = B ; De la m eme fa con que lon code des nombres entiers sur 1 octet avec un short, un char contient avant tout un nombre cod e sur 1 octet. Pour acher le caract` ere corrspondant au code ASCII stock e dans un char, on utilise la cha ne de format %c, et pour acher le code ASCII lui-m eme on utilise la cha ne de 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 n egatifs. Par cons equent, les caract` eres de code ASCII 255 et 128 correspondent aux unsigned char de valeurs 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 typ ees, on les d enit dans lent ete de la source, juste en dessous des #include. enit une La syntaxe est #define <NOM CONSTANTE> <valeurConstante>, par exemple #define N 25 d constante N qui a la valeur 25. Au d ebut de la compilation, un programme appel e pr eprocesseur eectue un rechercher/remplacer et substitue ` a toutes les occurences de <NOM CONSTANTE> la valeur <valeurConstante>. Faites donc tr` es attention au fait que dans lexemple pr esent, le pr eprocesseur va remplacer tous les N par des 25. Donc si une variable sappelle N , le pr eprocesseur va le remplacer par un 25 ! Si par exemple vous ecrivez

12

#include < s t d i o . h> #define N 25 int main ( ) { int N ; N = 12; printf ( N = %d , N ) ; return 0 ; } Le pr eprocesseur va le transformer en #include < s t d i o . h> #define N 25 int main ( ) { int 2 5 ; 25 = 1 2 ; printf ( N = %d , 2 5 ) ; return 0 ; } Vous remarquez que les seules exceptions sont les valeurs d elimit ees par des ".

13

1.3
1.3.1

Op erateurs
G en eralit es

Op erandes et arit e Lorsque vous eectuez une op eration, par exemple 3 + 4, le + est un op erateur, 3 et 4 sont des op erandes. Si lop erateur sapplique ` a 2 op erandes, on dit quil sagit dun op erateur binaire, ou bien darit e 2. Un op erateur darit e 1, dit aussi unaire, sapplique ` a un seul op erande, par exemple -x, le x est lop erande et le - unaire est lop erateur qui, appliqu e ` a x, nous donne loppos e de celui-ci, cest-` a-dire le nombre quil faut additionner ` a x pour obtenir 0. Il ne faut pas le confondre avec le - binaire, qui appliqu e` a x et y , additionne ` a x loppos e de y . En C, les op erateurs sont unaires ou binaires, et il existe un seul op erateur ternaire. Associativit e Si vous ecrivez une expression de la forme a + b + c, o` u a, b et c sont des variables enti` eres, vous appliquez deux fois lop erateur binaire + pour calculer la somme de 3 nombres a, b et c. Dans quel ordre ces op erations sont-elles eectu ees ? Est-ce que lon a (a + b) + c ou a + (b + c) ? Cela importe peu, car le + entier est associatif, ce qui signie quil est possible de modier le parenth` esage dune somme dentiers sans en changer le r esultat. Attention : lassociativit e est une raret e ! Peu dop erateurs sont associatifs, une bonne connaissance des r` egles sur les priorit es et le parenth` esage par d efaut est donc requise. Formes pr exes, postxes, inxes Un op erateur unaire est pr exe sil se place avant son op erande, postxe sil se place apr` es. Un op erateur binaire est inxe sil se place entre ses deux op erandes (a + b), pr exe sil se place avant (+ a b), postxe sil se place apr` es (a b +). Vous rencontrez en C des op erateurs unaires pr exes et dautres postxes (on imagine dicilement un op erateur unaire inxe), par contre tous les op erateurs binaires seront inxe. Priorit es Les r` egles des priorit es en C sont nombreuses et complexes, nous ne ferons ici que les esquisser. Nous appelerons parenth` esage implicite le parenth` esage adopt e par d efaut par le C, cest ` a dire lordre dans lequel il eectue les op erations. La premi` ere r` egle ` a retenir est quun op erateur unaire est toujours prioritaire sur un op erateur binaire.

1.3.2

Les op erateurs unaires

N egation arithm etique La n egation arithm etique est lop erateur - qui ` a une op erande x, associe loppos e de x, cest-` a-dire le nombre quil faut additionner ` a x pour obtenir 0. N egation binaire La n egation binaire ~ agit directement sur les bits de son op erande, tous les bits ` a 0 deviennent 1, et vice-versa. Par exemple, ~127 (tous les bits ` a 1 sauf le premier) est egal ` a 128 (le premier bit ` a 1 et tous les autres ` a 0). Priorit es Tous les op erateurs unaires sont de priorit e equivalente, le parenth` esage implicite est fait le plus ` a droite possible, on dit que ces op erateurs sont associatifs ` a droite. Par exemple, le parenth` esage implicite de lexpression ~-~i est ~(-(~i)). Cest plut ot logique : si vous parvenez ` a placer les parenth` eses di erement, prevenez-moi parce que je ne vois pas comment faire... 14

1.3.3

Les op erateurs binaires

Op erations de d ecalages de bits Lop eration a >> 1 eectue un d ecalage des bits de la repr esentation binaire de a vers la droite. Tous les bits sont d ecal es dun cran vers la droite, le dernier bit dispara t, le premier prend la valeur 0. Lop eration a << 1 eectue un d ecalage des bits de la repr esentation binaire de a vers la gauche. Tous les bits sont d ecal es dun cran vers la gauche, le premier bit dispara t et le dernier devient 0. Par exemple, 32 << 2 associe ` a 0010 0000 << 2 la valeur dont la repr esentation binaire 1000 0000 et 32 >> 3 associe ` a 0010 0000 >> 3 la valeur dont la repr esentation binaire 0000 0100. Op erations logiques sur la repr esentation binaire Lop erateur & associe ` a deux op erandes le ET logique de leurs repr esentations binaires par exemple 60 & 15 donne 12, autrement formul e 0011 1100 ET 0000 1111 = 0000 1100. Lop erateur | associe ` a deux op erandes le OU logique de leurs repr esentations binaires par exemple 60 | 15 donne 63, autrement formul e 0011 1100 OU 0000 1111 = 0011 1111. Lop erateur ^ associe ` a deux op erandes le OU exclusif logique de leurs repr esentations binaires par exemple 60 ^ 15 donne 51, autrement formul e 0011 1100 OU EXCLUSIF 0000 1111 = 0011 0011. Deux ^ successifs sannulent, en dautres termes a^b^b=a. Aectation Ne vous en d eplaise, le = est bien un op erateur binaire. Celui-ci aecte ` a lop erande de gauche (appel ee Lvalue par le compilateur), qui doit etre une variable, une valeur calcul ee ` a laide dune expression, qui est lop erande de droite. Attention, il est possible deectuer une aectation pendant l evaluation dune expression. Par exemple, a = b + (c = 3); Cette expression aecte ` a c la valeur 3, puis aecte ` a a la valeur b + c. Priorit es Tous les op erateurs binaires ne sont pas de priorit es equivalentes. Ceux de priorit e la plus forte sont les op erateurs arithm etiques (*, /, %, +, -), puis les op erateus de d ecalage de bit (<<, >>), les op erateurs de bit (&, ^, |), et enn laectation =. Repr esentons dans une tableau les op erateurs en fonction de leur priorit e, pla cons les plus prioritaire en haut et les moins prioritaires en bas. Parmi les op erateurs arithm etiques, les multiplications et divisions sont prioritaires sur les sommes et di erence : noms op erateurs produit *, /, % sommes +, Les deux op erateurs de d ecalage sont de priorit e equivalente : noms op erateurs d ecalage binaire >>, << Lop erateur & est assimil e` a un produit, | ` a une somme. Donc , & est prioritaire sur |. Comme ^ se trouve entre les deux, on a noms op erateurs ET binaire & OU Exlusif binaire ^ OU binaire | Il ne nous reste plus qu` a assembler les tableaux :

15

noms op erateurs produit *, /, % somme +, d ecalage binaire >>, << ET binaire & OU Exlusif binaire ^ OU binaire | aectation = Quand deux op erateurs sont de m eme priorit e le parenth` esage implicite est fait le plus ` a gauche possible, on dit que ces op erateurs sont associatifs ` a gauche. Par exemple, le parenth` esage implicite de lexpression a - b - c est (a b) c et certainement pas a - (b - c). Ayez donc cela en t ete lorsque vous manipulez des op erateurs non associatifs ! La seule exception est le =, qui est associatif ` a droite. Par exemple, a = b = c; se d ecompose en b = c suivi de a = b.

1.3.4

Formes contract ees

Le C etant un langage de paresseux, tout ` a et e fait pour que les programmeurs aient le moins de caract` eres possible ` a saisir. Je vous pr eviens : jai plac e ce chapitre pour que soyez capable de d ecrypter la bouillie que pondent certains programmeurs, pas pour que vous les imitiez ! Alors vous allez me faire le plaisir de faire usage des formes contract ees avec parcimonie, noubliez pas quil est tr` es important que votre code soit lisible. Unaires Il est possible dincr ementer (augmenter de 1) la valeur dune variable i en ecrivant i++, ou bien ++i. De la m eme fa con on peut d ecr ementer (diminuer de 1) i en ecrivant i-- (forme postxe), ou bien --i (forme pr exe). Vous pouvez d ecider dincr ementer (ou de d ecr ementer) la valeur dune variable pendant un calcul, par exemple, a = 1; b = ( a++) + a ; evalue successivement les deux op erandes a++ et a, puis aecte leur somme ` a b. Lop erande a++ est evalu ee ` a 1, puis est incr ement ee, donc lorsque la deuxi` eme op erande a est evalu ee, sa valeur est 2. Donc la valeur de b apr` es lincr ementation est 3. Lincr ementation contract ee sous forme postxe sappelle une post-incr ementation. Si lon ecrit, a = 1; b = (++a ) + a ; On op` ere une pr e-incr ementation, ++a donne lieu ` a une incr ementation avant l evaluation de a, donc la valeur 4 est aect ee ` a b. On peut de fa con analogue eectuer une pr e-decr ementation ou a postdecr ementation. Soyez tr` es attentifs au fait que ce code nest pas portable, il existe des compilateurs qui evaluent les op erandes dans le d esordre ou di` erent les incr ementations, donnant ainsi des r esultats autres que les r esultats th eoriques expos es pr ec edement. Vous nutiliserez donc les incr ementation et decr ementation contract ees que lorsque vous serez certain que lordre d evaluation des op erandes ne pourra pas inuer sur le r esultat.

16

Binaires Toutes les aectations de la forme variable = variable operateurBinaire expression peuvent etre contract ees sous la forme variable operateurBinaire= expression. Par exemple, avant apr` es a = a + b a += b a = a - b a -= b a = a * b a *= b a = a / b a /= b a = a % b a %= b a = a & b a &= b a = a ^ b a ^= b a = a | b a |= b Vous vous douterez que l egalit e ne peut pas etre contract ee...

1.3.5

Op erations h et erog` enes

Le fonctionnement par d efaut Nous ordonnons de fa con grossi` ere les types de la fa con suivante : long double > double > float > unsigned long > long > unsigned int > int > unsigned short > short > char. Dans un calcul o` u les op erandes sont de types h et erog` enes, lop erande dont le type T est de niveau le plus el ev e (conform ement ` a lordre enonc e ci-avant) est s electionn e et lautre est converti dans le type T . Le probl` eme 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 ; printf ( L i n v e r s e de %d e s t %d , i , 1/ i ) ; Vous constaterez que r esultat est inint eressant au possible. En eet, comme i et 1 sont tout deux de type entier, cest la division enti` ere est eectu ee, et de toute evidence le r esultat est 0. Changer la cha ne de format int i = 4 ; printf ( L i n v e r s e de %d e s t %f \ n , i , 1/ i ) ; se r ev` elera aussi dune inecacit e notoire : non seulement vous vous taperez un warning, mais en plus printf lira un entier en croyant que cest un ottant. Alors comment on se sort de l` a ? Ici la bidouille est simple, il sut d ecrire le 1 avec un point : int i = 4 ; printf ( L i n v e r s e de %d e s t %f \ n , i , 1 . / i ) ; Le compilateur, voyant un op erande de type ottant, convertit lors du calcul lautre op erande, i, en ottant. De ce fait, cest une division ottante et non enti` ere qui est eectu ee. Allons plus loin : comment faire pour appliquer une division ottante ` a deux entiers ? Par exemple : int i = 4 , j= 5 ; printf ( 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` u vous voudrez, vous narriverez pas ` a vous d ebarasser du warning et ce programme persistera ` a vous dire que ce quotient est -0.000000 ! Une solution particuli` erement crade serait de recopier i et j dans des variables ottantes avant de faire la division, une autre m ethode de bourrin est de calculer (i + 0.)/j. Mais jesp` ere que vous r ealisez que seuls les boeufs proc` edent de la sorte.

17

Le cast Le seul moyen de vous sortir de l` a est deectuer un cast, cest ` a dire une conversion de type sur commande. On caste en pla cant entre parenth` ese le type dans lequel on veut convertir juste avant lop erande que lon veut convertir. Par exemple, int i = 4 , j= 5 ; printf ( 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, ca fonctionne. La variable valeur contenue dans i est convertie en float et de ce fait, lautre op erande, j, est aussi convertie en float. La division est donc une division ottante. Notez bien que le cast est un op erateur unaire, donc prioritaire sur la division qui est un op erateur binaire, cest pour ca que la conversion de i a lieu avant la division. Mais si jamais il vous vient lid ee saugrenue d ecrire int i = 4 , j= 5 ; printf ( 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` es rapidement que cest une alternative peu intelligente. En eet, le r esulat est ottant, mais comme la division a lieu avant toute conversion, cest le r esultat dune division enti` ere qui est converti en ottant, vous avez donc le m eme r esultat que si vous naviez pas du tout cast e.

1.3.6

Les priorit es

Ajoutons le cast au tableau des priorit es de nos op erateurs : noms op erateurs op erateurs unaires cast, -, ~, ++, -produit *, /, % somme +, d ecalage binaire >>, << ET binaire & OU Exlusif binaire ^ OU binaire | aectation =

18

1.4

Traitements conditionnels

On appelle traitement conditionnel un portion de code qui nest pas ex ecut ee syst ematiquement, cest ` a dire des instructions dont lex ecution est conditionn ee par le succ` es dun test.

1.4.1

Si ... Alors

Principe En algorithmique un traitement conditionnel se r edige de la sorte : Si condition alors instructions n si Si la condition est v eri ee, alors les instructions sont ex ecut ees, sinon, elles ne sont pas ex ecut ees. Lex ecution de lalgorithme se poursuit alors en ignorant les instructions se trouvant entre le alors et le finSi. Un traitement conditionnel se code de la sorte : i f (< condition >) { <instructions > } Notez bien quil ny a pas de point-virgule apr` es la parenth` ese du if. Comparaisons La formulation dune condition se fait souvent ` a laide des op erateurs de comparaison. Les op erateurs de comparaison disponibles sont : == : egalit e != : non- egalit e <, <= : inf erieur ` a, respectivement strict et large >, >= : sup erieur ` a, respectivement strict et large Par exemple, la condition a == b est v eri ee si et seulement si a et b ont la m eme valeur au moment o` u le test est evalu e. Par exemple, #include < s t d i o . h> int main ( ) { int i ; printf ( S a i s i s s e z une v a l e u r : ) ; scanf ( %d , &i ) ; i f ( i == 0 ) { printf ( Vous a v e z s a i s i une v a l e u r n u l l e \ n . ) ; } printf ( Adios ! ) ; return 0 ; } Si au moment o` u le test i == 0 est evalu e, la valeur de i est bien 0, alors le test sera v eri e et linstruction printf("Vous avez saisi une valeur nulle\n.") sera bien ex ecut ee. Si le test nest pas v eri e, les instructions du bloc ... suivant le if sont ignor ees.

19

Si ... Alors ... Sinon Il existe une forme etendue de traitement conditionnel, on la note en algorithmique de la fa con suivante : Si condition alors instructions sinon autresinstructions n si Les instructions d elimit ees par alors et sinon sont ex ecut ees si le test est v eri e, et les instructions d elimit ees par sinon et finSi sont ex ecut ees si le test nest pas v eri e. On traduit le traitement conditionnel etendu de la sorte : i f (< condition >) { <instructions1 > } else { <instructions2 > } Par exemple, #include < s t d i o . h> int main ( ) { int i ; printf ( S a i s i s s e z une v a l e u r : ) ; scanf ( %d , &i ) ; i f ( i == 0 ) { printf ( Vous a v e z s a i s i une v a l e u r n u l l e \ n . ) ; } else { printf ( 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 pr esence de lop erateur de comparaison ==. Nutilisez jamais = pour comparer deux valeurs !. Connecteurs logiques On formule des conditions davantage elabor ees en utilisant des connecteurs et et ou. La condition A et B est v eri ee si les deux conditions A et B sont v eri ees simultan ement. La condition A ou B est v eri ee si au moins une des deux conditions A et B est v eri ee. Le et s ecrit && et le ou s ecrit ||. Par exemple, voici un programme C qui nous donne le signe de i j sans les multiplier. #include < s t d i o . h> int main ( ) {

20

int i , j ; printf ( S a i s i s s e z deux v a l e u r s : ) ; scanf ( %d %d , &i , &j ) ; printf ( 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 ) ) { printf ( p o s i t i f \ n . ) ; } else { printf ( n egatif ); } printf ( . \ n ) ; return 0 ; }

Accolades superues Lorsquune seule instruction dun bloc if doit etre ex ecut ee, les accolades ne sont plus n ecessaires. Il est possible par exemple de reformuler le programme pr ec edent de la sorte : #include < s t d i o . h> int main ( ) { int i , j ; printf ( S a i s i s s e z deux v a l e u r s : ) ; scanf ( %d %d , &i , &j ) ; printf ( 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 ) ) printf ( p o s i t i f \ n . ) ; else printf ( n egatif ); printf ( . \ n ) ; return 0 ; }

Op erateur ternaire En pla cant linstruction suivante ` a droite dune aectation, <variable > = (< condition >) ? <valeur> : <autrevaleur > ; on place valeur dans variable si condition est v eri e, autrevaleur sinon. Par exemple, max = ( i>j ) ? i : j ; place la plus grande des deux valeurs i et j dans max. Plus g en eralement on peut utiliser le si ternaire dans nimporte quel calcul, par exemple printf ( %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 ach ee par cette instruction.

21

1.4.2

Switch

Le switch en C s ecrit, avec la syntaxe suivante : switch (< nomvariable >) { case <valeur_1 > : <instructions_1 > ; break ; case <valeur_2 > : <instructions_2 > ; break ; / . . . / case <valeur_n > : <instructions_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 num ero, on ecrit switch ( numeroMois ) { case 1 : printf ( j a n v i e r ) ; break ; case 2 : printf ( f e v r i e r ) ; break ; case 3 : printf ( mars ) ; break ; case 4 : printf ( a v r i l ) ; break ; case 5 : printf ( mai ) ; break ; case 6 : printf ( j u i n ) ; break ; case 7 : printf ( j u i l l e t ) ; break ; case 8 : printf ( a o u t ) ; break ; case 9 : printf ( s e p t e m b r e ) ; break ; case 10 : printf ( o c t o b r e ) ; break ; case 11 : printf ( novembre ) ; break ; case 12 : printf ( decembre ) ; break ; default : printf ( Je c o n n a i s pas ce mois . . . ) ; }

1.4.3

Bool eens

Une variable bool eenne ne peut prendre que deux valeurs : vrai et f aux. Il nexiste pas de type bool een ` proprement parler en C. On utilise des int pour simuler le comportement des bool a eens. On repr esente la valeur bool eenne f aux avec la valeur enti` ere 0, toutes les autres valeurs enti` eres servent ` a repr esenter vrai. Utilisation dans des if Lorsquune condition est evalu ee, par exemple lors dun test, cette condition prend ` a ce moment la valeur vrai si le test est v eri e, f aux dans le cas contraire. La valeur enti` ere 0 repr esente la constante f aux et toutes les autres sont des constantes vrai. Observons le test suivant : i f (8) { // . . . 1 est un litt eral de type entier dont le valeur est non nulle, donc il repr esente le bool een vrai. De ce fait, le test if (8) est toujours v eri e. Par contre le test if (0) nest jamais v eri e. La valeur vrai M eme si tout entier non nul a la valeur vrai, on prend par d efaut la valeur 1. Lorsquune condition est evalu ee, elle prend la valeur 1 si elle est v eri e, 0 dans le cas contraire. par exemple, 22

x = (3 > 2); On remarque que (3>2) est une condition. Pour d ecider quelle valeur doit etre aect ee ` a x, cette condition est evalu ee. Comme dans lexemple ci-dessus la condition est v eri ee, alors elle prend la valeur 1, et cette valeur est aect ee ` a x. Connecteurs logiques binaires Les connecteurs || et && peuvent sappliquer ` a des valeurs (ou variables) enti` eres. Observons lexemple suivant : x = ( 3 && 0 ) | | ( 1 ) ; Il sagit de laectation ` a x de l evaluation de la condition (3 && 0) || (1). Comme 3 est vrai et 0 est faux, alors leur conjonction est fausse. Donc (3 && 0) a pour valeur 0. La condition 0 || 1 est ensuite evalu ee et prend la valeur vrai. Donc la valeur 1 est aect ee ` a x. Op erateur de n egation Parmi les connecteurs logiques se trouve !, dit op erateur de n egation. La n egation dune expression est vraie si lexpression est fausse, fausse si lexpression est vraie. Par exemple, x = !(3==2); Comme 3 == 2 est faux, alors sa n egation !(3 == 2) est vraie. Donc la valeur 1 est aect ee ` a x.

1.4.4

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

Compl` etons notre tableau comparaison : noms op erateurs unaires produit somme d ecalage binaire comparaison egalit e ET binaire OU Exlusif binaire OU binaire connecteurs logiques if ternaire aectations

1.4.5

Pr eprocesseur

Macro-instructions Le C nous permet de placer ` a peu pr` es nimporte quoi dans les constantes. Si par exemple, on est lass e d ecrire des instructions de retour ` a la ligne, il sut de d enir #define RC p r i n t f ( \ n ) Dans ce cas, toutes les occurrences de RC dans le code seront remplac ees par des printf("\n"). Par exemple

23

#include < s t d i o . h> #define BEGIN { #define END } #define #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 ) RETOURNE 0 return 0

int main ( ) BEGIN AFFICHE_DEBUT ; RC ; AFFICHE_MLILIEU ; RC ; AFFICHE_FIN ; RC ; RETOURNE_0 ; END ache Debut Milieu Fin Macros param etr ees Il est possible de param etrer les instructions du pr eprocesseur. Par exemple, #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` eses de la constante. Par exemple #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 ) ; printf ( S a i s i s s e z un e n t i e r : ) ; SAISIR_INT ( k ) ; printf ( Vous a v e z s a i s i ) ; AFFICHER_INT ( k ) ; RC ; return 0 ; }

24

ache Saisissez un entier : 4 Vous avez saisi 4

25

1.5

Boucles

Nous souhaitons cr eer un programme qui nous ache tous les nombres de 1 ` a 10, donc dont lex ecution serait la suivante : 1 2 3 4 5 6 7 8 9 10 Une fa con particuli` erement vilaine de proc eder serait decrire 10 printf successifs, avec la lourdeur des copier/coller que cela impliquerait. Nous allons etudier un moyen de coder ce type de programme avec un peu plus d el egance.

1.5.1

D enitions et terminologie

Une boucle permet dex ecuter plusieurs fois de suite une m eme s equence dinstructions. Cette ensemble dinstructions sappelle le corps de la boucle. Chaque ex ecution du corps dune boucle sappelle une it eration, ou plus informellement un passage dans la boucle. Lorsque lon sappr ete ` a ex ecuter la premi` ere it eration, on dit que lon rentre dans la boucle, lorsque la derni` ere it eration est termin ee, on 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 inconv enients. Nous les passerons en revue ult erieurement.

1.5.2

while

En C, la boucle tant que se code de la fa con suivante : while (< condition >) { <instructions > } Les instructions du corps de la boucle sont d elimit ees par des accolades. La condition est evalu ee avant chaque passage dans la boucle, ` a chaque fois quelle est v eri ee, on ex ecute les instructions de la boucle. Un fois que la condition nest plus v eri ee, lex ecution se poursuit apr` es laccolade fermante. Achons par exemple tous les nombres de 1 ` a 5 dans lordre croissant, #include < s t d i o . h> int main ( ) { int i = 1 ; while ( i <= 5 ) { printf ( %d , i ) ; i++; } printf ( \ n ) ; return 0 ; } Ce programme initialise i ` a 1 et tant que la valeur de i n exc` ede pas 5, cette valeur est ach ee puis incr ement ee. Les instructions se trouvant dans le corps de la boucle sont donc ex ecut ees 5 fois de suite. La variable i sappelle un compteur, on g` ere la boucle par incr ementations successives de i et on sort de la boucle une fois que i a atteint une certaine valeur. Linitialisation du compteur est tr` es importante ! Si vous ninitialisez pas i explicitement, alors cette variable contiendra nimporte quelle valeur et votre programme ne se comportera pas du tout comme pr evu. Notez bien par ailleurs quil ny a pas de point-virgule apr` es le while ! 26

1.5.3

do ... while

Voici la syntaxe de cette boucle : do { <instructions > } while (< condition > ); La fonctionnement est analogue ` a celui de la boucle tant que ` a quelques d etails pr` es : la condition est evalu ee apr` es chaque passage dans la boucle. On ex ecute le corps de la boucle tant que la condition est v erif ee. En C, la boucle r ep eter ... jusqu` a est en fait une boucle r ep eter ... tant que, cest-` a-dire une boucle tant que dans laquelle la condition est evalu ee ` a la n. Une boucle do ... while est donc ex ecut ee donc au moins une fois. Reprennons lexemple pr ec edent avec une boucle do ... while : #include < s t d i o . h> int main ( ) { int i = 1 ; do { printf ( %d , i ) ; i++; } while ( i <= 5 ) ; printf ( \ n ) ; return 0 ; } De la m eme fa con que pour la boucle while, le compteur est initialis e avant le premier passage dans la boucle. Un des usages les plus courant de la boucle do ... while est le contr ole de saisie : #include < s t d i o . h> int main ( ) { int i ; do { printf ( 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 : ) ; scanf ( %d , &i ) ; i f ( i < 0) printf ( 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 d elicate. Commen cons par donner sa syntaxe : f o r (< initialisation > ; <condition > ; <pas >) { 27

<instructions > } L<initialisation> est une instruction ex ecut ee avant le premier passage dans la boucle. La <condition> est evalu ee avant chaque passage dans la boucle, si elle nest pas v eri ee, on ne passe pas dans la boucle et lex ecution de la boucle pour est termin ee. La <pas> est une instruction ex ecut ee apr` es chaque passage dans la boucle. On peut convertir une boucle for en boucle while en proc edant de la sorte : <initialisation > while (< condition >) { <instructions > <pas> } On re- ecrit lache des 5 premiers entiers de la sorte en utilisant le fait que <initialisation> = i = 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++) printf ( %d , i ) ; printf ( \ n ) ; return 0 ; } On utilise une boucle for lorsque lon connait en entrant dans la boucle combien dit erations devront etre faites. Par exemple, nutilisez pas une boucle pour pour contr oler une saisie !

1.5.5

Accolades superues

De la m eme fa con quil est possibl de supprimer des accolades autour dune instruction dun bloc if, on peut supprimer les accolades autour du corps dune boucle si elle ne contient quune seule instruction.

28

1.6

Tableaux

Consid erons un programme dont lex ecution donne : 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` eres valeurs saisies ?

1.6.1

D enitions

Une tableau est un regroupement de variables de m eme type, il est identi e par un nom. Chacune des variables du tableau est num erot ee, ce num ero sappelle un indice. Chaque variable du tableau est donc caract eris ee par le nom du tableau et son indice. Si par exemple, T est un tableau de 10 variables, alors chacune delles sera num erot ee et il sera possible de la retrouver en utilisant simultan ement le nom du tableau et lindice de la variable. Les di erentes variables de T porteront des num eros de 0 ` a 9, et nous appellerons chacune de ces variables un el ement de T . Une variable n etant pas un tableau est appel ee variable scalaire, un tableau par opposition ` a une variable scalaire est une variable non scalaire.

1.6.2

D eclaration

Comme les variables dun tableau doivent etre de m eme type, il convient de pr eciser ce type au moment de la d elaration du tableau. De m eme, on pr ecise lors de la d eclaration du tableau le nombre de variables quil contient. La syntaxe est : <type> <nomdutableau >[< taille > ] ; Par exemple, int T [ 4 ] ; d eclare un tableau T contenant 4 variables de type int.

1.6.3

Initialisation

Il est possible dinitialiser les el ements dun tableau ` a la d eclaration, on fait cela comme pour des variables scalaires : <type> <nom >[< taille > ] = <valeur d initialisation > ; La seule chose qui change est la fa con d ecrire la valeur dinitialisation, on ecrit entre accolades tous les el ements du tableau, on les dispose par ordre dindice croissant en les s eparant par des virgules. La syntaxe g en erale de la valeur dinitialisation est donc : 29

<type> <nom >[< taille > ] = {< valeur_0 > , <valeur_1 > , . . . , <valeur_n 1 >}; Par exemple, on cr ee un tableau contenant les 5 premiers nombres impairs de la sorte : int T [ 5 ] = { 1 , 3 , 5 , 7 , 9 } ;

1.6.4

Acc` es aux el ements

Les el ements dun tableau ` an el ements sont indic es de 0 ` a n 1. On note T[i] l el ement dindice i du tableau T. Les cinq el ements du tableau de lexemple ci-avant sont donc not es T[0], T[1], T[2], T[3] et T[4].

1.6.5

Exemple

Nous pouvons maintenant mettre en place le programme du d ebut du cours. Il est n ecessaire de stocker 10 valeurs de type entier, nous allons donc d eclarer un tableau E de la sorte : int E [ 1 0 ] ; La d eclaration ci-dessus est celle dun tableau de 10 int appel e E. Il convient ensuite deectuer les saisies des 10 valeurs. On peut par exemple proc eder de la sorte : printf ( S a i s i s s e z d i x v a l e u r s : \ n ) ; printf ( 1 ) ; scanf (%d , &E [ 0 ] ) ; p r i n t f ( 2 ) ; s c a n f (%d , &E [ 1 ] ) ; printf ( 3 ) ; scanf (%d , &E [ 2 ] ) ; p r i n t f ( 4 ) ; s c a n f (%d , &E [ 3 ] ) ; printf ( 5 ) ; scanf (%d , &E [ 4 ] ) ; p r i n t f ( 6 ) ; s c a n f (%d , &E [ 5 ] ) ; printf ( 7 ) ; scanf (%d , &E [ 6 ] ) ; p r i n t f ( 8 ) ; s c a n f (%d , &E [ 7 ] ) ; printf ( 9 ) ; scanf (%d , &E [ 8 ] ) ; p r i n t f ( 10 ) ; s c a n f (%d , &E [ 9 ] ) ; Les divers copier/coller nec essaires pour r ediger un tel code sont dune laideur ` a proscrire. Nous proc ederons plus el egament en faisant une boucle : printf ( 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++) { printf ( %d , i +1); scanf ( %d , &E [ i ] ) ; } Ce type de boucle sappelle un parcours de tableau. En r` egle g en erale on utilise des boucles pour manier les tableaux, celles-ci permettent deectuer un traitement sur chaque el ement dun tableau. Ensuite, il faut saisir une valeur ` a rechercher dans le tableau : 30

printf ( S a i s s e z une v a l e u r \ n ) ; scanf ( %d , &t ) ; Nous allons maintenant rechercher la valeur t dans le tableau E. Consid erons pour ce faire la boucle suivante : while ( E [ i ] != t ) i++; Cette boucle parcourt le tableau jusqu` a trouver un el ement de E qui ait la m eme valeur que t. Le probl` eme qui pourrait se poser est que si t ne se trouve pas dans le tableau E, alors la boucle pourrait ne pas sarr eter. Si i prend des valeurs strictement plus grandes que 9, alors il se produira ce que lon appelle un d ebordement dindice. Vous devez toujours veiller ` a ce quil ne se produise pas de d ebordement dindice ! Nous allons donc faire en sorte que la boucle sarr ete si i prend des valeurs strictement sup erieures ` a 9. while ( i < 10 && E [ i ] != t ) i++; Il existe donc deux fa cons de sortir de la boucle : En cas de d ebordement dindice, la condition i < 10 ne sera pas v eri ee. Une fois sorti de la boucle, i aura la valeur 10. Dans le cas o` u t se trouve dans le tableau ` a lindice i, alors la condition E[i] != t ne sera pas v eri ee et on sortira de la boucle. Un fois sorti de la boucle, i aura comme valeur lindice de l el ement de E qui est egal ` a t, donc une valeur comprise entre 0 et 9. On identie donc la fa con dont on est sorti de la boucle en testant la valeur de i : i f ( i == 1 0 ) printf ( %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 printf ( %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 l el ement saisi par lutilisateur ne trouve pas dans le tableau. Dans le cas contraire, t est la i+1-` eme valeur saisie par lutilisateur. On additionne 1` a lindice parce que lutilisateur ne sait pas que dans le tableau les el ements sont indic es ` a partir de 0. R ecapitulons : #include < s t d i o . h> #define N 10 #define SAISIR INT (num , nom) \ { \ printf ( %d : , num ) ; \ scanf ( %d , &( nom ) ) ; \ } int main ( ) { int E [ N ] , i , t ; printf ( 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 ] ) ; printf ( S a i s s e z une v a l e u r \ n ) ; scanf ( %d , &t ) ; i = 0; while ( i < N && E [ i ] != t ) 31

i++; i f ( i == N ) printf ( %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 printf ( %d e s t l a %deme v a l e u r s a i s i e , t , i +1); printf ( \ n ) ; return 0 ; }

32

1.7
1.7.1

Cha nes de caract` eres


Exemple

Etant donn e le programme dont lex ecution est trac ee ci dessous : 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 s equences de caract` eres de la sorte ?

1.7.2

D enition

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

1.7.3

D eclaration

Comme une cha ne de caract` eres est un tableau de char, on le d eclare : char <nom_chaine >[< taille_chaine > ] ; Par exemple, on d eclare une chaine c de 200 caract` eres de la sorte : 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` es le dernier caract` ere de la cha ne un caract` ere nul !

1.7.4

Initialisation

On initialise une cha ne ` a la d eclaration, et seulement ` a la d eclaration de la sorte : char <nom_chaine >[< taille_chaine > ] = <valeur_initialisation > ; O` u la valeur dinitiallisation contient la juxtaposition de caract` eres formant la cha ne entour ee de guillemets (double quotes). Par exemple, char c [ 5 0 ] = Toto ; Cette instruction d eclare une cha ne de carat` eres c initialis ee ` a "Toto". Les 5 premiers el ements du tableau seront occup es par les 4 caract` eres de la cha ne ainsi que par le carat` ere nul, les autres contiendront des valeurs non signicatives. Observez bien lexemple suivant : char c [ 4 ] = Toto ; Cette d eclaration engendrera un warning ` a la compilation et probablement une erreur ` a lex ecution car laectation du caract` ere nul ` a la 5-` eme position du tableau donnera lieu ` a un d ebordement dindice.

33

1.7.5

Acc` es aux el ements

Du fait quune chaine de caract` ere est un tableau, il est ais e den isoler un el ement. Ainsi c[i] est le i+1-` eme el ement de la cha ne c. On teste donc si le premier carat` ere de c est une majuscule de la sorte : i f ( c [ 0 ] >= A && c [ 0 ] <= Z ) printf ( 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 printf ( 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 propri et e permet aussi dacher une cha ne caract` ere par caract` ere : int i = 0 ; while ( c [ i ] != 0 ) printf ( %c , c [ i ++]); Notez que le corps de la boucle while est it er e jusqu` a ce que le caract` ere nul soit rencontr e. Il est donc imp eratif que votre cha ne se termine par le caract` ere nul et que le caract` ere nul se trouve 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 pos ee, vous pouvez pr esumer que ce code nest pas correct. Le fait que chaque el ement du tableau contienne un caract` ere non nul ne peut que corroborer cette pr esomption... Si lon souhaite placer lalphabet dans une cha ne, on proc` ede de la sorte : 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 el ements si lon compte le caract` ere nul, et que celui-ci est plac e` a la n du tableau juste apr` es la boucle.

1.7.6

Achage

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

1.7.7

Saisie

Cest maintenant que les choses se corsent, il faut etre tr` es attentif lors des saisies : tout d ebordement dindice et/ou absence de carat` ere nul peut donner lieu ` a des bugs tr` es diciles ` a trouver ! La plus 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

34

int main ( ) { char chaine [ N ] ; int i ; printf ( S a i s i s s e z une p h r a s e : \ n ) ; gets ( chaine ) ; f o r ( i = 0 ; chaine [ i ] != 0 ; i++) printf ( c h a i n e [%d ] = %c ( code ASCII : %d ) \ n , i , chaine [ i ] , chaine [ i ] ) ; printf ( c h a i n e [%d ] = %c ( code ASCII : %d ) \ n , i , chaine [ i ] , chaine [ 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` ere r eaction du compilateur est une insulte. A-t-il raison ? Testons ce programme : [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 ` a un programme C ! Ne lutilisez sous aucun pr etexte ! Maintenant, nous allons envisager une fa con propre de saisir une cha ne de caract` ere : fgets. La syntaxe est la suivante : fgets (< chaine > , <taille > , stdin ) ; La taille de la cha ne saisie est limit ee par <taille>, caract` ere nul compris. Le r esultat est plac e dans <chaine>. Tous les caract` eres suppl ementaires saisis par lutilisateur ne sont pas plac es dans <chaine>, seuls les (<taille> 1) premiers caract` eres sont r ecup er es par fgets. Nous saisirons donc la phrase de notre programme de la sorte : 35

fgets ( c , 2 0 0 , stdin ) ;

1.7.8

Probl` emes li es ` a la saisie bueris ee

Lorsque vous saisissez des caract` eres avec fgets, les caract` eres ignor es ne sont pas elimin es du buer. Cela signie quils iront parasiter la prochaine saisie. Il convient donc tout dabord de v erier sil reste des caract` eres dans buer et de les eliminer si n ecessaire. Commen cons par le premier point : comment sassurer que tous les caract` eres saisis ont et e lus ? La r eponse est tr` es simple : gr ace au caract` ere d echappement \n. La saisie est valid ee par le carat` ere d echappement, il sagit donc toujours du dernier caract` ere saisi. Le buer a donc et e entir` erement lu si caract` ere d echappement a et e lu. Si ce caract` ere a et e lu, alors il gure juste avant le caract` ere nul dans la cha ne. On le rep` ere donc de la sorte : while ( c [ i ] != 0 ) i++; i f ( c [ i 1] != \ n ) printf ( La s a i s i e e s t i n c o m p l e t e ) ; else printf ( La s a i s i e e s t c o m p l e t e ) ; Si la cha ne c a et e saisie correctement, aucun risque de d ebordement dindice ou de bouclage inni ne peut se pr esenter. La boucle au d ebut de lextrait recherche le caract` ere nul dans la cha ne. On sort de la boucle quand c[i] == 0, donc lindice du carat` ere nul est i. Si lavant dernier caract` ere de la cha ne, donc celui dindice (i 1) est le caract` ere d echappement, alors la saisie a et e compl` ete et le buer est vide. Sinon, cest que des caract` eres ont et e laiss es dans le buer par fgets. Il convient donc, si lon souhaite eectuer dautres saisies par la suite, de vider le buer. getchar est une instruction retournant un caract` ere lu dans le buer. Si le buer est vide, getchar attend une saisie de lutilisateur non valid ee par le caract` ere d echappement ! On vide donc le buer de la sorte : while ( getchar ( ) != \ n ) ; Le point-virgule ` a la n de linstruction indique au compilateur que la boucle na pas de corps. Cette boucle lit le buer jusqu` a ce que le caract` ere d echappement ait et e lu. Pour davantage de lisibilit e, on d enit une macro-instruction vidant le buer : #define CLEAR_BUFFER while ( getchar ( ) != \ n ) V eriez bien avant de lancer cette instruction que le buer nest pas vide, sinon le programme bouclera jusqu` a ce que lutilisateur ait saisi un caract` ere d echappement.

1.7.9

La biblioth` eque string.h

Cette biblioth` eque propose des fonctions de maniement de cha nes de caract` eres, ` a savoir : strcmp : comparer deux cha nes. strlen : longueur dune cha ne de caract` ere strsubs : rechercher une sous-cha ne strcat : concat ener deux cha nes strcpy : copier une cha ne Il vous est conseill e dexaminer de quelle fa con fonctionnent ces fonctions, et comment elles g` erent le caract` ere nul.

1.7.10

Exemple

#include < s t d i o . h> #define N 10 36

#define CLEAR BUFFER while ( g e t c h a r ( ) != \ n ) int main ( ) { char chaine [ N ] ; int i ; printf ( S a i s i s s e z une p h r a s e : \ n ) ; fgets ( chaine , N , stdin ) ; i = 0; while ( chaine [ i ] != 0 ) i++; i f ( i > 0 && chaine [ i 1] != \ n ) CLEAR_BUFFER ; else chaine [ i 1] = 0 ; printf ( Vous a v e z s a i s i : \ n%s \ n , chaine ) ; i f ( chaine [ 0 ] >= A && chaine [ 0 ] <= Z ) printf ( 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 printf ( 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 ( chaine [ i ] != 0 && chaine [ i ] != . ) i++; i f ( chaine [ i ] == . ) i f ( chaine [ i +1] == 0 ) printf ( 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 printf ( Vous a v e z s a i s i p l u s d une p h r a s e . \ n ) ; else printf ( 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 ; }

37

1.8
1.8.1

Fonctions
Les proc edures

Une proc edure est un ensemble dinstructions portant un nom. Pour d enir une proc edure, on utilise la syntaxe : void nomprocedure ( ) { / instructions / } Une proc edure est une nouvelle instruction, il sut pour lex ecuter dutiliser son nom. Par exemple, pour ex ecuter (on dit aussi appeler ou invoquer) une proc edure appel ee pr, il sut d ecrire pr();. Les deux programmes suivants font la m eme chose. Le premier est ecrit sans proc edure : #include < s t d i o . h> int main ( ) { printf ( Bonjour \ n ) ; return 0 ; } Et dans le deuxi` eme, le printf est plac e dans la proc edure afficheBonjour et cette proc edure est appel ee depuis le main. #include < s t d i o . h> void afficheBonjour ( ) { printf ( Bonjour \ n ) ; } int main ( ) { afficheBonjour ( ) ; return 0 ; } Vous pouvez d enir autant de proc edures que vous le voulez et vous pouvez appeler des proc edures depuis des proc edures : #include < s t d i o . h> void afficheBonjour ( ) { printf ( Bonjour \ n ) ; } void afficheUn ( ) { printf ( 1 \ n ) ; } void afficheDeux ( ) 38

{ printf ( 2 \ n ) ; } void afficheUnEtDeux ( ) { afficheUn ( ) ; afficheDeux ( ) ; } void afficheAuRevoir ( ) { printf ( 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 d eterminer ce quil ache. #include < s t d i o . h> void procedure1 ( ) { printf ( d e b u t p r o c e d u r e 1 \ n ) ; printf ( f i n p r o c e d u r e 1 \ n ) ; } void procedure2 ( ) { printf ( d e b u t p r o c e d u r e 2 \ n ) ; procedure1 ( ) ; printf ( f i n p r o c e d u r e 2 \ n ) ; } void procedure3 ( ) { printf ( d e b u t p r o c e d u r e 3 \ n ) ; procedure1 ( ) ; procedure2 ( ) ; printf ( f i n p r o c e d u r e 3 \ n ) ; } int main ( ) 39

{ printf ( d e b u t main \ n ) ; procedure2 ( ) ; procedure3 ( ) ; printf ( f i n main \ n ) ; return 0 ; } La r eponse est 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 proc edure. main est ex ecut ee automatiquement au lancement du programme.

1.8.2

Variables locales

Une proc edure est un bloc dinstructions et est sujette aux m emes r` egles que main. Il donc possible de d eclarer des variables : 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 proc edure, cela signie quelle naissent au moment de leur d eclaration et quelles sont d etruites une fois la derni` ere instruction de la proc edure ex ecut ee. Cest pour cela quon les apelle des variables locales. Une variable locale nest visible quentre sa d eclaration et laccolade fermant la proc edure. Par exemple, ce code est ill egal : #include < s t d i o . h> void maProcedure ( ) { char a = b ; }

int main ( ) 40

{ char b = k ; printf ( %c , %c \ n , a , b ) ; return 0 ; } En eet, la variable b est d eclar ee dans la proc edure main, et nest donc visible que dans cette m eme proc edure. Son utilisation dans maProcedure est donc impossible. De m eme, la variable a est d eclar ee 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++ ) printf ( %d \ n , i ) ; }

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

1.8.3

Passage de param` etres

Il est possible que la valeur dune variable locale dune proc edure ne soit connue quau moment de lappel de la proc edure. Consid erons le programme suivant : int main ( ) { int i ; printf ( V e u i l l e z s a i s i r un e n t i e r : ) ; scanf ( %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 d enir et invoquer une proc edure afficheInt permettant dacher cet entier saisi par lutilisateur ? Vous conviendrez que la proc edure suivante ne passera pas la compilation void afficheInt ( ) { printf ( %d , i ) ; } En eet, la variable i est d eclar ee dans le main, elle nest donc pas visible dans afficheInt. Pour y rem edier, on d enit afficheInt de la sorte : void afficheInt ( int i ) { printf ( %d , i ) ; }

41

i est alors appel e un param` etre, il sagit dune variable dont la valeur sera pr ecis ee lors de lappel de la proc edure. On peut aussi consid erer que i est une valeur inconnue, et quelle est initialis ee lors de linvocation de la proc edure. Pour initialiser la valeur dun param` etre, on place cette valeur entre les parenth` eses lors de lappel de la proc edure, par exemple : afficheInt(4) lance lex ecution de la proc edure afficheInt en initialisant la valeur de i ` a 4. On dit aussi que lon passe en param` etre la valeur 4. La version correcte de notre programme est : #include < s t d i o . h> void afficheInt ( int i ) { printf ( %d , i ) ; } int main ( ) { int i ; printf ( V e u i l l e z s a i s i r un e n t i e r : ) ; scanf ( %d , &i ) ; afficheInt ( i ) ; printf ( \ n ) ; return 0 ; } Attention, notez bien que le i de afficheInt et le i du main sont deux variables di erentes, la seule chose qui les lie vient du fait que linstruction afficheInt(i) initialise le i de afficheInt ` a la valeur du i du main. Il serait tout ` a fait possible d ecrire : #include < s t d i o . h> void afficheInt ( int j ) { printf ( %d , j ) ; } int main ( ) { int i ; printf ( V e u i l l e z s a i s i r un e n t i e r : ) ; scanf ( %d , &i ) ; afficheInt ( i ) ; printf ( \ n ) ; return 0 ; } Dans cette nouvelle version, linstruction afficheInt(i) initialise le j de afficheInt ` a la valeur du i du main. Il est possible de passer plusieurs valeurs en param` etre. Par exemple, la proc edure suivante ache la somme des deux valeurs pass ees en param` etre : void afficheSomme ( int a , int b ) { printf ( %d , a + b ) ; }

42

Linvocation dune telle proc edure se fait en initialisant les param` etres dans le m eme ordre et en s eparant les valeurs par des virgules, par exemple afficheSomme(3, 4) invoque afficheSomme en initialisant a a 3 et b ` ` a 4. Vous devez intialiser tous les param` etres et vous devez placer les valeurs dans lordre. R ecapitulons : #include < s t d i o . h> void afficheSomme ( int a , int b ) { printf ( %d , a + b ) ; } int main ( ) { int i , j ; printf ( V e u i l l e z s a i s i r deux e n t i e r s : \ na = ) ; scanf ( %d , &i ) ; printf ( b = ) ; scanf ( %d , &j ) ; printf ( a + b = ) ; afficheSomme ( i , j ) ; printf ( \ n ) ; return 0 ; } La proc edure ci-avant sex ecute de la fa con suivante : Veuillez saisir deux entiers : a = 3 b = 5 a + b = 8 Lors de lappel afficheInt(r) de la proc edure void afficheInt(int i), r est le param` etre eectif et i le param` etre formel. Notez bien que i et r sont deux variables distinctes. Par exemple, quache le programme suivant ? #include < s t d i o . h> void incr ( int v ) { v++; } main ( ) { int i ; i = 6; incr ( i ) ; printf ( %d \ n , i ) ; } La variable v est initialis ee ` a la valeur de i, mais i et v sont deux variables di erentes. Modier lune naecte pas lautre.

43

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 e de communiquer une valeur au sous-programme appelant ? La r eponse est oui. Une fonction est un sous-programme qui communique une valeur au sous-programme appelant. Cette valeur sappelle valeur de retour, ou valeur retourn ee. Invocation La syntaxe pour appeler une fonction est : v = nomfonction ( parametres ) ; Linstruction ci-dessus place dans la variable v la valeur retourn ee par la fonction nomfonction quand lui passe les param` etres parametres. Nous allons plus loin dans ce cours d enir une fonction carre qui retourne le carr e de valeur qui lui est pass ee en param` etre, alors linstruction v = carre ( 2 ) ; placera dans v le carr e de 2, ` a savoir 4. On d enira aussi une fonction somme qui retourne la somme de ses param` etres, on placera donc la valeur 2 + 3 dans v avec linstruction v = somme ( 2 , 3 ) ;

D enition On d enit une fonction avec la syntaxe suivante : typeValeurDeRetour nomFonction ( listeParametres ) { } La fonction carre sera donc d enie comme suit : int carre ( int i ) { / instructions / } Une fonction ressemble beaucoup ` a une proc edure. Vous remarquez que void est remplac e par int, void signie aucune type de retour, une proc edure est donc une fonction qui ne retourne rien. Un int est adapt e pour repr esenter le carr e dun autre int, jai donc choisi comme type de retour le type int. Nous d enirons la fonction somme comme suit : int somme ( int a , int b ) { / instructions / } Linstruction servant ` a retourner une valeur est return. Cette instruction interrompt lex ecution de la fonction et retourne la valeur plac ee imm ediatement apr` es. Par exemple, la fonction suivante retourne toujours la valeur 1.

44

int un ( ) { return 1 ; } Lorsque lon invoque cette fonction, par exemple v = un ( ) ; La valeur 1, qui est retourn ee par un est aect ee ` a v . On d enit une fonction qui retourne le successeur de son param` etre : int successeur ( int i ) { return i + 1 ; } Cette fonction, si on lui passe la valeur 5 en param` etre, retourne 6. Par exemple, linstruction v = successeur ( 5 ) ; aecte ` a v la valeur 6. Construisons maintenant nos deux fonctions : int carre ( 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 etudiant les pointeurs.

1.8.5

Passages de param` etre par r ef erence

En C, lorsque vous invoquez une fonction, toutes les valeurs des param` etres eectifs sont recopi es dans les param` etres formels. On dit dans ce cas que le passage de param` etre se fait par valeur. Vous ne pouvez 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` etre, la valeur qui est recopi ee dans le param` etre formel est ladresse de ce tableau (ladresse est une valeur scalaire). Par cons equent toute modication eectu ee sur les el ements dun tableau dont ladresse est pass ee en param` etre par valeur sera repercut ee sur le param` etre eectif (i.e. le tableau dorigine). Lorsque les modications faites sur un param` etre formel dans un sous-programme sont rep ercut ees sur le param` etre eectif, on a alors un passage de param` etre par r ef erence. Nous retiendrons donc les trois r` egles dor suivantes : Les variables scalaires se passent en param` etre par valeur Les variables non scalaires se passent en param` etre par r ef erence Une fonction ne peut retourner que des valeurs scalaires

45

1.9
1.9.1

Structures
D enition

Nous avons utilis e des tableaux pour d esigner, avec un nom unique, un ensemble de variables. Par exemple, un tableau T ` an el ements est un ensemble n de variables d esign ees par la lettre T . Dans un tableau, les variables doivent etre de type homog` ene, cela signiant quil nest pas possible de juxtaposer des char et des int dans un tableau. Lorsque lon souhaite faire cohabiter dans une variable non scalaire des types h et erog` enes, on utilise des structures. Une structure, appel e enregistrement dans dautres langages, est une variable contenant plusieurs variables, appel ees champs. Si une structure t contient un char et un int, chacun de ces champs portera un nom, par exemple i et c. Dans ce cas, t.c d esignera le char de t et t.i lint de t.

1.9.2

D eclaration

Pour cr eer un type structur e, on utilise la syntaxe suivante : struct nomdutype { typechamp_1 nomchamp_1; typechamp_2 nomchamp_2; ... typechamp_n nomchamp_n; }; On pr ecise donc le nom de ce type structur e, et entre les accolades, la liste des champs avec pour chacun deux son type. Vous remarquez que le nombre de champs est x e davance. On nacc` ede pas ` a un champ avec un indice mais avec un nom. Consid erons par exemple le type structur e suivant : struct point { double abs ; double ord ; }; Ce type permet de repr esenter un point dans R2 , avec respectivement uns abscisse et une ordonn ee. struct point est maintenant un type, il devient possible de d eclarer un point p comme tout autre variable : struct point p ;

1.9.3

Acc` es aux champs

On acc` ede aux champs dune variable structur ee ` a laide de la notation point ee 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 point { double abs ; double ord ; };

46

main ( ) { struct point p ; p . ord = 2 ; p . abs = p . ord + 1 ; printf ( p = (%f , %f ) \ n , p . abs , p . ord ) ; } Ce programme ache : p = (3.000000, 2.000000) Attention, lop erateur dacc` es au champ . est prioritaire sur tous les autres op erateurs unaires, binaires et ternaires ! Il faudra vous en rappeler quand on etudiera les listes cha n ees.

1.9.4

Typedef

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

main ( ) { point p ; p . ord = 2 ; p . abs = p . ord + 1 ; printf ( 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 emp eche de cr eer des tableaux de structures, par exemple : #include < s t d i o . h> #define N 10 typedef struct point { double abs ; double ord ; } point ;

main ( ) { point p [ N ] ; 47

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 . ; } f o r ( i = 0 ; i < N ; i++) { printf ( 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` etre, les structures se comportent comme des variables scalaires, cela signie quon ne peut les passer en param` etre que par valeur. Par contre, un tableau de structures est n ecessairement pass e en param` etre par r ef erence. R eecrivons le programme pr ec edent avec des sousprogrammes : #include < s t d i o . h> #define N 10 typedef struct point { double abs ; double ord ; } point ; void initTableauPoints ( point 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 . ; } }

48

void affichePoint ( point p ) { printf ( (%f , %f ) , p . abs , p . ord ) ; } void afficheTableauPoints ( point p [ ] , int n ) { int i ; f o r ( i = 0 ; i < n ; i++) { printf ( p[%d ] = , i ) ; affichePoint ( p [ i ] ) ; printf ( \ n ) ; } } main ( ) { point p [ N ] ; initTableauPoints ( p , N ) ; afficheTableauPoints ( 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 point { double abs ; double ord ; } point ; point nextPoint ( point previous ) { point result ; result . ord = previous . ord + 1 . ; result . abs = previous . abs + 2 . ; return result ; } void initTableauPoints ( point 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 affichePoint ( point p ) {

49

printf ( (%f , %f ) , p . abs , p . ord ) ; } void afficheTableauPoints ( point p [ ] , int n ) { int i ; f o r ( i = 0 ; i < n ; i++) { printf ( p[%d ] = , i ) ; affichePoint ( p [ i ] ) ; printf ( \ n ) ; } } main ( ) { point p [ N ] ; initTableauPoints ( p , N ) ; afficheTableauPoints ( p , N ) ; }

50

1.10

Pointeurs

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

1.10.1

Introduction

Un pointeur est une variable qui contient ladresse m emoire dune autre variable. D eclaration T est le type dune variable contenant ladresse m emoire dune variable de type T . Si une variable p de type T contient ladresse m emoire dune variable x de type T , on dit alors que p pointe vers x (ou bien sur x). &x est ladresse m emoire de la variable x. Exposons cela dans un exemple, #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 ` a dire de type pointeur de int, p est donc faite pour contenir ladresse m emoire dun int. &x est ladresse m emoire de la variable x, et laectation p = &x place ladresse m emoire de x dans le pointeur p. A partir de cette aectation, p pointe sur x. Achage La cha ne de format dune adresse m emoire est %X. On ache donc une adresse m emoire (tr` es utile pour d ebugger :-) comme dans lexemple ci-dessous, #include < s t d i o . h> void main ( ) { int x = 3 ; int p ; p = &x ; printf ( 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 ) ; }

51

Acc` es ` a la variable point ee Le lecteur impatient se demande probablement ` a quoi peuvent servir toutes ces etoiles ? Quel peut bien etre lint er et des pointeurs ? Si p pointe sur x, alors il est possible dacc eder ` a la valeur de x en passant par p. Pour le compilateur, p est la variable point ee par p, cela signie que lon peut, pour le moment du moins, utiliser indi erement p ou x. Ce sont deux fa cons de se r ef erer ` a la m eme variable, on appelle cela de laliasing. Explicitons cela sur un exemple, #include < s t d i o . h> void main ( ) { int x = 3 ; int p ; p = &x ; printf ( x = %d \ n , x ) ; p = 4 ; printf ( x = %d \ n , x ) ; } Laectation p = &x fait pointer p sur x. A partir de ce moment, p peut etre utilis e pour d esigner la variable x. De ce fait, laectation x = 4 peut aussi etre ecrite p = 4. Toutes les modications op er ees sur p seront r epercut ees sur la variable point ee par p. Donc ce programme ache x = 3 x = 4 R ecapitulons Quache, ` a votre avis, le programe suivant ? #include < s t d i o . h> void main ( ) { int x = 3 ; int y = 5 ; int p ; p = &x ; printf ( x = %d \ n , x ) ; p = 4 ; printf ( x = %d \ n , x ) ; p = &y ; printf ( p = %d \ n , p ) ; p = p + 1 ; printf ( y = %d \ n , y ) ; } x est initialis e ` a 3 et y est initialis e ` a 5. Laectation p = &x fait pointer p sur x, donc p et x sont deux ecritures di erentes de la m eme variable. Le premier printf ache la valeur de x : plus pr ecis ement x = 3. Ensuite, laectation p = 4 place dans la valeur point ee par p, ` a savoir x, la valeur 4. Donc le deuxi` eme printf ache x = 4. Laectation p = &y fait maintenant pointer p sur y , donc la valeur de p est la valeur de la variable point ee y . le troisi` eme printf ache donc *p = 5. Noubliez pas que comme p pointe sur y , alors p et y sont deux alias pour la m eme variable, de ce fait, linstruction p = p + 1 peut tout ` a fait s ecrire y = y + 1. Cette instruction place donc dans y la valeur 6, le quatri` eme printf ache donc y = 6. Ce programme ache donc : 52

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, eclaircissons quelques points. D emystication (et d emythication) du tableau en C Les el ements dun tableau sont juxtapos es dans la m emoire. Autrement dit, ils sont plac es les uns ` a cot e des autres. Sur le plan de ladressage, cela a une cons equence fort intuitive. Sachant quun int occupe 2 octets en m emoire et que &T [0] est ladresse m emoire du premier el ement du tableau T , quelle est ladresse m emoire de T [1] ? La r eponse est la plus simple : &T [0] + 2 (ne l ecrivez jamais ainsi dans un programme, vous verrez pourquoi plus loin dans le cours...). Cela signie que si lon connait ladresse dun el ement dun tableau (le premier en loccurrence), il devient possible de retrouver les adresses de tous les autres el ements de ce tableau. Jai par ailleurs, une assez mauvaise surprise pour vous. Vous utilisez sans le savoir des pointeurs depuis que vous utilisez des tableaux. Etant donn e la d eclaration int T [50], vous conviendrez que les d esignations {T [0], . . . , T [49]} permettent de se r ef erer aux 50 el ements du tableau T . Mais vous est-il d ej` a arriv e, en passant un tableau en param` etre, d ecrire T sans ecrire dindice entre crochets ? Par exemple, #include < s t d i o . h> void initTab ( int K [ ] , int n ) { int i ; f o r ( i = 0 ; i < n ; i++) K [ i ] = i + 1; } void afficheTab ( int K [ ] , int n ) { int i ; f o r ( i = 0 ; i < n ; i++) printf ( %d \ n , K [ i ] ) ; } int main ( ) { int T [ 5 0 ] ; initTab ( T , 5 0 ) ; afficheTab ( T , 5 0 ) ; return 0 ; } Vous remarquez que lorsque lon passe un tableau en param` etre ` a un sous-programme, on mentionne seulement son nom. En fait, le nom dun tableau, T dans lexemple ci-avant, est ladresse m emoire du premier el ement de ce tableau. Donc, T est une variable contenant une adresse m emoire, T est par cons equent un pointeur. Lorsque dans un sous-programme auquel on a pass e un tableau en param` etre, on mentionne un indice, par exemple K [i], le compilateur calcule ladresse du i-` eme el ement de K pour lire ou ecrire ` a cette adresse.

53

Utilisation des pointeurs Commen cons par observer lexemple suivant : #include < s t d i o . h> main ( ) { char t [ 1 0 ] ; char p ; t [ 0 ] = a ; p = t; printf ( 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 m emoire du premier el ement du tableau t. p est un pointeur de char, donc laectation p = t place dans p ladresse m emoire du premier el ement du tableau t. Comme p pointe vers t[0], on peut indi erement utiliser p ou t[0]. Donc ce programme ache le premier element du tableau est a. Calcul des adresses m emoire Tout dabord, je tiens ` a rappeler quune variable de type char occupe un octet en m emoire. Consid erons maintenant les d eclarations char t[10] ; et char p = t ; Nous savons que si p pointe vers t[0], il est donc ais e dacc eder au premier el ement de t en utilisant le pointeur p. Mais comment acc eder aux autres el ements de t ? Par exemple T [1] ? Souvenez-vous que les el ements dun tableau sont juxtapos es, dans lordre, dans la m emoire. Par cons equent, si p est ladresse m emoire du premier el ement du tableau t, alors (p + 1) est ladresse m emoire du deuxi` eme el ement de ce tableau. Vous etes conviendrez que p est la variable dont ladresse m emoire est contenue dans p. Il est possible, plus g en eralement, d ecrire (p + 1) pour d esigner la variable dont ladresse m emoire est (p + 1), cest ` a dire (la valeur contenue dans p) + 1. Illustrons cela dans un exemple, le programme #include < s t d i o . h> main ( ) { char t [ 1 0 ] ; char p ; t [1] = b ; p = t; printf ( 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` eme element du tableau est b. En eet, p + 1 est ladresse m emoire du deuxi` eme el ement de t, il est donc possible dutiliser indi erement (p + 1) et t[1]. Plus g en eralement, on peut utiliser (p + i) ` a la place de t[i]. En eet, (p + i) est ladresse du i-` eme el ement de t, et (p + i) est la variable dont ladresse m emoire est (p + i). Par exemple,

54

#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++) printf ( %c , ( p + i ) ) ; printf ( \ n ) ; } Ou encore, en utilisant des sous-programmes, #include < s t d i o . h> #define N 26 void initTab ( char k , int n ) { int i ; int v = A ; f o r ( i = 0 ; i < n ; i++) ( k + i ) = v++; } void afficheTab ( char k , int n ) { int i ; f o r ( i = 0 ; i < n ; i++) printf ( %c , ( k + i ) ) ; printf ( \ 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

55

Arithm etique des pointeurs Supposons que le tableau t contienne des int, sachant quun int occupe 2 octets en m emoire. Est-ce que (t + 1) est ladresse du deuxi` eme el ement de t ? Math ematiquement, la r eponse est non, ladresse du deuxi` eme el ement est t +(la taille d un int) = (t +2). Etant donn e un tableau p d el ements occupant chacun n octets en m emoire, ladresse du i-` eme el ement est alors p + i n. Cependant, la pond eration syst ematique de lindice par la taille occup ee en m emoire par chaque el ement est dune part une lourdeur dont on se passerait volontier, et dautre part une source derreurs et de bugs. Pour y rem edier, le compilateur prend cette partie du travail en charge,on ne pond erera donc pas les indices ! Cela signie, plus explicitement, que quel que soit le type des el ements du tableau p, ladresse m emoire du i-` eme el ement de p est p + i. On le v erie exp erimentalement en ex ecutant le programme suivant : #include < s t d i o . h> #define N 30 void initTab ( int k , int n ) { int i ; k = 1 ; f o r ( i = 1 ; i < n ; i++) ( k + i ) = ( k + i 1) + 1 ; } void afficheTab ( int k , int n ) { int i ; f o r ( i = 0 ; i < n ; i++) printf ( %d , ( k + i ) ) ; printf ( \ n ) ; } main ( ) { int t [ N ] ; initTab ( t , N ) ; afficheTab ( t , N ) ; }

1.10.3

Allocation dynamique de la m emoire

La lecture du chapitre pr ec edent, si vous y avez surv ecu, vous a probablement men e` a une question que les el` eves posent souvent : Monsieur pourquoi on fait c a ?. Cest vrai ! Pourquoi on manipulerait les tableaux avec des pointeurs alors que dans les exemples que je vous ai donn e, on peut le faire sans les pointeurs ? Dans la mesure o` u un tableau est un pointeur, on peut, m eme ` a lint erieur dun sous-programme auquel un tableau a et e pass e en param` etre, manipuler ce tableau avec des crochets. Alors dans quel cas utiliserons-nous des pointeurs pour parcourir les tableaux ? De la m eme fa con quil existe des cas dans lesquels on connait ladresse dune variable scalaire mais pas son nom, il existe des tableaux dont on connait ladresse mais pas le nom.

56

Un probl` eme de taille Lorsque lon d eclare un tableau, il est obligatoire de pr eciser sa taille. Cela signie que la taille dun tableau doit etre connue ` a la compilation. Alors que faire si on ne connait pas cette taille ? La seule solution qui se pr esente pour le moment est le surdimensionnement, on donne au tableau une taille tr` es (trop) elev ee de sorte quaucun d ebordement ne se produise. Nous aimerions proc eder autrement, cest ` a dire pr eciser la dimension du tableau au moment de lex ecution. Nous allons pour cela rappeler quelques principes. Lors de la d eclaration dun tableau t, un espace m emoire allou e au stockage de la variable t, cest ` a dire la variable qui contient ladresse m emoire du premier el ement du tableau. Et un autre espace m emoire est allou e au stockage des el ements du tableau. Il y a donc deux zones m emoires utilis ees. La fonction malloc Lorsque vous d eclarez un pointeur p, vous allouez un espace m emoire pour y stocker ladresse m emoire dun entier. Et p, jusqu` a ce quon linitialise, contient nimporte quoi. Vous pouvez ensuite faire pointer p sur ladresse m emoire que vous voulez (choisissez de pr ef erence une zone contenant un int...). Soit cette adresse est celle dune variable qui existe d ej` a. Soit cette adresse est celle dun espace m emoire cr e ee sp ecialement pour loccasion. Vous pouvez demander au syst` eme dexploitation de lespace m emoire pour y stocker des valeurs. La fonction qui permet de r eserver n octets est malloc(n). Si vous ecrivez malloc(10), lOS r eserve 10 octets, cela sappelle une allocation dynamique, cest ` a dire une allocation de la m emoire au cours de lex ecution. Si vous voulez r eserver de lespace m emoire pour stocker un int par exemple, il sut dappeler malloc(2), car un int occupe 2 octets en m emoire. En m eme temps, cest bien joli de r eserver de lespace m emoire, mais ca ne sert pas ` a grand chose si on ne sait pas o` u il se trouve ! Cest pour ca que malloc est une fonction. malloc retourne ladresse m emoire du premier octet de la zone r eserv ee. Par cons equent, si vous voulez cr eer un int, il convient dex ecuter linstruction : p = malloc(2) o` u p est de type int. Le malloc r eserve deux octets, et retourne ladresse m emoire de la zone allou ee. Cette aectation place donc dans p ladresse m emoire du int nouvellement cr e e. 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 g en erale, void est le type adresse m emoire en C. Alors que int est le type adresse m emoire dun int. Il faut donc dire au compilateur que vous savez ce que vous faites, et que vous etes s ur que cest bien un int que vous allez mettre dans la variable point ee. Pour ce faire, il convient dectuer ce que lon appelle un cast, en ajoutant, juste apr` es lop erateur daectation, le type de la variable se situant ` a gauche de laectation entre parenth` eses. Dans lexemple ci-avant, cela donne : int p = (int)malloc(2). 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 ) malloc ( 2 ) ; p = 2 8 ; printf ( %d \ n , p ) ; }

57

Vous remarquez que nous sommes bien dans un cas o` u lon connait ladresse dune variable mais pas son nom. Le seul moyen de manier la variable allou ee dynamiquement est dutiliser un pointeur. La fonction f ree Lorsque que lon eectue une allocation dynamique, lespace r eserv e ne peut pas etre allou e pour une autre variable. Une fois que vous nen avez plus besoin, vous devez le lib erer explicitement si vous souhaitez quune autre variable puisse y etre stock ee. La fonction de lib eration de la m emoire est f ree. f ree(v ) o` u v est une variable contenant ladresse m emoire de la zone ` a lib erer. A chaque fois que vous allouez une zone m emoire, vous devez la lib erer ! Un exemple classique dutilisation est : #include < s t d i o . h> #include <m a l l o c . h> main ( ) { int p ; p = ( int ) malloc ( 2 ) ; p = 2 8 ; printf ( %d \ n , p ) ; free ( p ) ; } Notez bien que la variable p, qui a et e allou ee au d ebut du main, a et e lib er e par le f ree(p). La valeur N U LL La pointeur p qui ne pointe aucune adresse a la valeur N U LL. Attention, il nest pas n ecessairement initialis ea ` N U LL, N U LL est la valeur que, conventionnellement, on d ecide de donner ` a p sil ne pointe sur aucune zone m emoire valide. Par exemple, la fonction malloc retourne N U LL si aucune zone m emoire ad equate nest trouv ee. Il convient, ` a chaque malloc, de v erier si la valeur retourn ee par malloc est di erente de N U LL. Par exemple, #include < s t d i o . h> #include <m a l l o c . h> main ( ) { int p ; p = ( int ) malloc ( 2 ) ; i f ( p == NULL ) exit ( 0 ) ; p = 2 8 ; printf ( %d \ n , p ) ; free ( p ) ; } Vous remarquez que le test de non nullit e de la valeur retourn ee par malloc est eectu e imm ediatement apr` es lallocation dynamique. Vous ne devez jamais utiliser un pointeur sans avoir v eri e sa validit e, autrement dit, sa non-nullit e. Un pointeur contenant une adresse non valide est appel e un pointeur fou. Vous devrez, dans votre vie de programmeur, les traquer avec hargne ! Lallocation dynamique dun tableau Lors de lallocation dynamique dun tableau, il est n ecessaire de d eterminer la taille m emoire de la zone de la zone ` a occuper. Par exemple, si vous souhaitez allouer dynamiquament un tableau de 10 variables de type char. Il sut dex ecuter linstruction malloc(10), car un tableau de 10 char occupe 10 octets 58

en m emoire. Si par contre, vous souhaitez allouer dynamiquement un tableau de 10 int, il conviendra dex ecuter malloc(20), car chaque int occupe 2 octets en m emoire. Pour se simplier la vie, le compilateur met ` a notre disposition la fonction sizeof , qui nous permet de calculer la place prise en m emoire par la variable dun type donn e. Par exemple, soit T un type, la valeur sizeof (T ) est la taille prise en m emoire par une variable de type T . Si par exemple on souhaite allouer dynamiquement un int, il convient dex ecuter linstruction malloc(sizeof (int)). Attention, sizeof prend en param` etre un type ! Si on souhaite allouer dynamiquement un tableau de n variables de type T , on ex ecute linstruction malloc(n sizeof (T )). Par exemple, pour allouer un tableau de 10 int, on ex ecute malloc(10 sizeof (int)). Voici une variante du programme dun programme pr ec edent : #include < s t d i o . h> #include <m a l l o c . h> #define N 26 void initTab ( int k , int n ) { int i ; f o r ( i = 0 ; i < n ; i++) ( k + i ) = i + 1 ; } void afficheTab ( int k , int n ) { int i ; f o r ( i = 0 ; i < n ; i++) printf ( %d , ( k + i ) ) ; printf ( \ n ) ; } int main ( ) { int p ; p = ( int ) malloc ( 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` etres par r ef erence

Jai dit tout ` a lheure : Pour le compilateur, p est la variable point ee par p, cela signie que lon peut, pour le moment du moins, utiliser indi erement p ou x. En pr ecisant pour le moment du moins, javais d ej` a lintention de vous montrer des cas dans lesquels ce n etait pas possible. Cest ` a dire des cas dans lesquels on connait ladresse dune variable mais pas son nom. Permutation de deux variables A titre de rappel, observez attentivement le programme suivant :

59

#include < s t d i o . h> void echange ( int x , int y ) { int t = x ; x = y; y = t; } void main ( ) { int a = 1 ; int b = 2 ; printf ( a = %d , b = %d \ n , a , b ) ; echange ( a , b ) ; printf ( 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 M editons quelque peu : la question que lon se pose est Est-ce que le sous-programme echange echange bien les valeurs des deux variables a et b ? Il va de soi quil echange bien les valeurs des deux variables x et 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 ecrire ` a la place un sous-programme ne contenant aucune instruction, leet aurait et e le m eme. Ce programme ache donc a = 1, b = 2 a = 1, b = 2 Remarques Ceux dont la m emoire na pas et e r einitialis e pendant les vacances se souviennent certainement du fait quil etait impossible de passer en param` etre des variables scalaires par r ef erence. Jai menti, il existe un moyen de passer des param` etres par r ef erence, et vous aviez des indices vous permettant de vous en 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 et e pass ee en param` etre par r ef erence. Autrement dit, que la valeur de x est modi ee dans le sous-programme scanf , donc que la variable permettant de d esigner x dans le corps de ce sous-programme nest pas une copie de x, mais la variable x elle-m eme, ou plut ot un alias de la variable x. Vous pouvez dores et d ej` a retenir que nomsousprogramme(. . . , &x, . . .) sert ` a passer en param` etre la variable x par r ef erence. Et nalement, cest plut ot logique, linstruction nomsousprogramme(. . . , x, . . .)

60

passe en param` etre la valeur de x, alors que nomsousprogramme(. . . , &x, . . .) passe en param` etre ladresse de x, cest-` a-dire un moyen de retrouver la variable x depuis le sousprogramme et de modier sa valeur. Cependant, si vous ecrivez echange(&a, &b), le programme ne compilera pas... En eet, le sous-programme echange prend en param` etre des int et si vous lui envoyez des adresses m emoire ` a la place, le compilateur 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 m emoire en param` etre. Utilisation de pointeurs On arrive ` a la question suivante : dans quel type de variable puis-je mettre ladresse m emoire dune variable de type entier ? La r eponse est int, un pointeur sur int. Observons le sous-programme suivant, 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` etre des deux 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 d ecrit dans lintroduction de ce chapitre dans un cas dans lequel on connait ladresse dune variable, mais pas son nom : dans le sous-programme echange, la variable a est inconnue (si vous l ecrivez, c a ne compilera pas...), seul le pointeur x permet dacc eder ` a la variable a. Il sut donc, pour ecrire un sous-programme prenant en param` etre des variables pass ees par r ef erence, de les d eclarer comme des pointeurs, et dajouter une devant ` a chaque utilisation.

1.10.5

Pointeurs sur fonction

61

1.11
1.11.1

Fichiers
D enitions

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++) { printf ( S a i s i r un e n t i e r : ) ; scanf ( %d , t + i ) ; } f o r ( i = 0 ; i < 10 ; i++) printf ( %d , t [ i ] ) ; printf ( \ n ) ; return 0 ; } Le probl` eme qui se pose est que lorsque lon sort de ce programme, les donn ees saisies sont perdues. Si lon souhaite les avoir ` a disposition pour dune ex ecution ult erieure, il convient dutiler une m emoire persistante, cest-` a-dire qui conserve les donn ees entre deux ex ecutions. On utilise pour ce faire un chier. Un chier est une m emoire stock ee de fa con permanente sur un disque et ` a laquelle on acc` ede avec un nom. Les donn ees dans un chier se pr esentent de fa con s equentielle, et donc se lisent ou s ecrivent du d ebut vers la n. Nous survolerons dans ce cours un ensemble de fonctions de stdio.h permettant de manier des chiers. Pour plus d etails, il est tr` es hautement recommand e de se reporter ` a la documentation.

1.11.2

Ouverture et fermeture

Pour acc eder au contenu dun chier en lecture ou en ecriture, on utilise les deux fonctions fopen et 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 ne de caract` ere contenant le chemin (relatif ou absolu) et le nom du chier. Si le chier est dans le r epertoire dans lequel sex ecute le programme, alors le nom du chier sut. mode est une cha ne de caract` ere contenant "r" pour ouvrir le chier en mode lecture, "w" en mode ecriture, etc. FILE* est un type permettant de r ef erencer un chier ouvert, fopen retourne NULL sil est impossible douvrir le chier (par exemple si le nom est incorrect). La valeur retourn ee devra etre plac ee dans une variable de type FILE*, cest cette valeur qui permettra par la suite dacc eder au contenu du chier. La fonction fclose fclose sert ` a fermer un chier. Son prototype est int fclose(FILE *fp) : fp est la variable de type FILE* permettant de r ef erencer le chier ` a fermer. Cette fonction retourne 0 si la fermeture sest bien pass ee. Dans le cas contraire, des indications sur lerreur survenue sont accessibles dans des variables globales.

62

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 ( t o t o . t x t , r ) ; i f ( f == NULL ) { printf ( Erreur 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 ( fclose ( f ) != 0 ) { printf ( Erreur 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 ecriture

Il existe plusieurs fa cons de lire dans un chier : caract` ere par caract` ere, ligne par ligne, par paquets de caract` eres, etc. Chaque lecture se faisant ` a laide dune fonction appropri ee. Lors dun traitement se faisant ` a partir dune lecture dans un chier, on appelle de fa con it er ee une fonction de lecture faisant avancer un curseur dans un chier jusqu` a ce que la n du chier soit atteinte. L ecriture fonctionne de fa con analogue, ` a un d etail pr` es : il est inutile d ecrire le caract` ere de n de chier, il est ajout e automatiquement lors du fclose. Caract` ere par caract` ere La fonction int fgetc(FILE* stream) retourne un caract` ere lu dans le chier f. Bien que le caract` ere lu soit un octet, il est retourn e dans un int. Le caract` ere EOF indique que la n du chier a et e atteinte. Par exemple, #include < s t d i o . h> int main ( ) { FILE f ; char c ; f = fopen ( t o t o . t x t , r ) ; i f ( f == NULL ) { printf ( Erreur 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 = fgetc ( f ) ) != EOF ) printf ( c a r a c t e r e l u : %c \ n , c ) ; 63

i f ( fclose ( f ) != 0 ) { printf ( Erreur 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 ecrit un caract` ere dans un chier ` a laide de la fonction int fputc(int c, FILE* stream). #include < s t d i o . h> int main ( ) { FILE f ; char c [ 7 ] = Toto ! ; int i ; f = fopen ( t o t o . t x t , w ) ; i f ( f == NULL ) { printf ( Erreur 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 ( fclose ( f ) != 0 ) { printf ( Erreur 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` eres Les deux fonctions char *fgets(char *s, int size, FILE *stream) et int fputs(const char *s, FILE *stream) permettent de lire et d ecrire des cha nes de caract` eres dans des chiers, voir la documentation pour plus de d etails. Par paquets Les deux fonctions size t fread(void *ptr, size t size, size t nmemb, FILE *stream) et size t es utiles lorsque lon fwrite(const void *ptr, size t size, size t nmemb, FILE *stream) sont tr` veut sauvegarder un tableau dans un chier, ou recopier un chier dans un tableau (voir la documentation pour plus de d etails). Voici tout de m eme deux exemples : #include < s t r i n g . h> #include < s t d i o . h> struct personne { char nom [ 3 0 ] ; int age ; }; int main ( int argv , char argc ) 64

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

65

1.12
1.12.1

Listes Cha n ees


Le probl` eme

Plusieurs probl` emes surviennent lorsque lon utilise des tableaux pour stocker des valeurs : En cas de redimensionnement, il faut refaire une allocation dynamique et recopier tout le tableau. En cas dinsertion ou de suppression dun el ement, il faut d ecaler vers la gauche ou vers la droite tous les successeurs. Concat ener ou fusionner des tableaux est une op eration lourde au niveau m emoire. Tous les el ements doivent etre stock es dans des zones contig ues, lallocation est donc un lourd travail lorsque la m emoire est fragment ee. Bref, de nombreuses op erations sont lourdes en temps dex ecution. Nous d enirons dans ce cours un autre moyen de stocker les donn ees en formant un ensemble ordonn e, le listes cha n ees.

1.12.2

Pointeurs et structures

Soit T un type structur e d eni comme suit : typedef struct T { int i ; char c ; }T ; Si p est un pointeur de type T , alors p contient ladresse m emoire dun el ement de type T . Soit t une 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 indi erement utiliser t.i (resp. t.c) et (p).i (resp (p).c). Par exemple, r eecrivons le 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 point { double abs ; double ord ; } point ; / / point nextPoint ( point previous ) { point result ; result . ord = ( previous ) . ord + 1 . ; result . abs = ( previous ) . abs + 2 . ; return result ; } / /

66

void initTableauPoints ( point 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 affichePoint ( point p ) { printf ( (%f , %f ) , ( p ) . abs , ( p ) . ord ) ; } / / void afficheTableauPoints ( point p , int n ) { int i ; f o r ( i = 1 ; i < n ; i++) { printf ( p[%d ] = , i ) ; affichePoint ( p + i ) ; printf ( \ n ) ; } } / / int main ( ) { point p ; p = ( point ) malloc ( N s i z e o f ( point ) ) ; i f ( p == NULL ) exit ( 0 ) ; initTableauPoints ( p , N ) ; afficheTableauPoints ( p , N ) ; free ( p ) ; return 0 ; } L ecriture (p).i permet de d esigner le champ i de la variable point ee par p. Cette ecriture, peu commode, peut etre remplac ee par p > i, par exemple : #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 point

67

{ double abs ; double ord ; } point ; / / point nextPoint ( point previous ) { point result ; result . ord = previous >ord + 1 . ; result . abs = previous >abs + 2 . ; return result ; } / / void initTableauPoints ( point 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 affichePoint ( point p ) { printf ( (%f , %f ) , p>abs , p>ord ) ; } / / void afficheTableauPoints ( point p , int n ) { int i ; f o r ( i = 1 ; i < n ; i++) { printf ( p[%d ] = , i ) ; affichePoint ( p + i ) ; printf ( \ n ) ; } } / / main ( ) { point p ; p = ( point ) malloc ( N s i z e o f ( point ) ) ; i f ( p == NULL ) exit ( 0 ) ;

68

initTableauPoints ( p , N ) ; afficheTableauPoints ( p , N ) ; free ( p ) ; } Attention ! Les op erateurs dacc` es aux champs . et -> ont une priorit e sup erieure ` a celles de tous les autres op erateurs du langage ! Si vous manipulez un tableau de structures t et que vous souhaitez acc eder au champ t du i-` eme el ement, est-il intelligent d ecrire *(i + t).c ? Absolument pas ! . est prioritaire sur *, donc le parenth` esage implicite est *((i + t).c), essayez de vous repr esenter ce que cela fait, et vous comprendrez pourquoi votre programme plante ! En ecrivant (i + t)->c, vous obtenez une expression equivalente ` a (*(i + t)).c, qui est d ej` a bien plus proche de ce que lon souhaite faire.

1.12.3

Un premier exemple

Consid erons le type suivant : typedef struct maillon { int data ; struct maillon next ; } maillon ; On appelle cette forme de type un type r ecursif, cest-` a-dire qui contient un pointeur vers un el ement du m eme type. Observons lexemple suivant : #include < s t d i o . h> / / typedef struct maillon { int data ; struct maillon next ; } maillon ; / / int main ( ) { maillon m , p ; maillon ptr ; m . data = 1 ; m . next = &p ; p . data = 2 ; p . next = NULL ; f o r ( ptr = &m ; ptr != NULL ; ptr = ptr>next ) printf ( d a t a = %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 ` a &m, alors ptr pointe sur m. Donc, lors de la premi` ere it eration de la boucle for, la valeur prt->data est m.data, ` a savoir 1. Lorsque le pas de la boucle est ex ecut e, ptr re coit la valeur ptr->next, qui nest autre que m->next, ou encore &p. Donc ptr pointe maintenant sur p. Dans la deuxi` eme it eration de la boucle, ptr->data est la valeur p.data, ` a savoir 2. Ensuite le pas de la boucle est ex ecut e, et ptr prend la valeur ptr->next, ` a savoir p->next, ou encore NULL. Comme ptr == NULL, alors la boucle sarr ete. Ce programme ache donc : 69

data = 1 data = 2

1.12.4

Le cha nage

La fa con de renseigner les valeurs des pointeurs next observ ee dans lexemple pr ec edent sappelle le cha nage. Une liste de structures telle que chaque variable structur ee contienne un pointeur vers vers une autre variable du m eme type sappelle une liste cha n ee. Utilisons un tableau pour stocker les el ements dune liste cha n ee ` a 10 el ements. #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 maillon { int data ; struct maillon next ; } maillon ; / / void printData ( maillon ptr ) { f o r ( ; ptr != NULL ; ptr = ptr>next ) printf ( d a t a = %d \ n , ptr>data ) ; } / / int main ( ) { maillon l ; int i ; l = ( maillon ) malloc ( N s i z e o f ( maillon ) ) ; 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 n ee ont et e plac es dans le tableau l, la premi` ere boucle dispose le cha nage des el ements dans le m eme ordre que dans le tableau, lachage de la liste est fait dans le sous-programme

70

printfData, et seul le cha nage y est utilis e. Comme le champ data du i-` eme el ement de la liste contient la valeur i, alors ce programme ache : data data data data data data data data data data = = = = = = = = = = 0 1 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 maillon { int data ; struct maillon next ; } maillon ; / / void printData ( maillon ptr ) { f o r ( ; ptr != NULL ; ptr = ptr>next ) printf ( d a t a = %d \ n , ptr>data ) ; } / / int main ( ) { maillon l ; int i ; l = ( maillon ) malloc ( N s i z e o f ( maillon ) ) ; 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 ; } 71

printData ( l ) ; free ( l ) ; return 0 ; } 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 e les el ements dans un tableau, les maillons etaient donc regroup es dans des zones m emoire contig ues. Il est possible de stocker les maillons dans les zones non contig ues, tous peuvent etre retrouv es ` a laide du 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 maillon { int data ; struct maillon next ; } maillon ; void printData ( maillon ptr ) { f o r ( ; ptr != NULL ; ptr = ptr>next ) printf ( d a t a = %d \ n , ptr>data ) ; } / / void freeLL ( maillon l ) { maillon n ; while ( l != NULL ) { n = l>next ; free ( l ) ; l = n; } } 72

/ / int main ( ) { maillon l ; maillon current ; maillon previous ; int i ; l = ( maillon ) malloc ( s i z e o f ( maillon ) ) ; i f ( l == NULL ) exit ( 0 ) ; l>data = 0 ; previous = l ; f o r ( i = 1 ; i < N ; i++) { current = ( maillon ) malloc ( s i z e o f ( maillon ) ) ; i f ( current == NULL ) exit ( 0 ) ; current>data = i ; previous >next = current ; previous = current ; } current>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 e, on placera linitialisation de la liste dans une fonction : #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 maillon { int data ; struct maillon next ; 73

} maillon ; / / void printLL ( maillon ptr ) { f o r ( ; ptr != NULL ; ptr = ptr>next ) printf ( d a t a = %d \ n , ptr>data ) ; } / / maillon initLL ( int n ) { maillon first ; maillon current ; maillon previous ; int i ; first = ( maillon ) malloc ( s i z e o f ( maillon ) ) ; i f ( first == NULL ) exit ( 0 ) ; first>data = 0 ; previous = first ; f o r ( i = 1 ; i < n ; i++) { current = ( maillon ) malloc ( s i z e o f ( maillon ) ) ; i f ( current == NULL ) exit ( 0 ) ; current>data = i ; previous >next = current ; previous = current ; } current>next = NULL ; return first ; } / / void freeLL ( maillon l ) { maillon n ; while ( l != NULL ) { n = l>next ; free ( l ) ; l = n; } } / / int main ( ) { maillon l ;

74

l = initLL ( N ) ; printLL ( l ) ; freeLL ( l ) ; return 0 ; }

1.12.6

Op erations

Observons de quelle fa con il est possible deectuer certaines op erations sur une liste cha n ee. Les sousprogrammes ci-dessous ont et e pens e et combin es pour etre les plus simples possibles... Cr eation dun maillon maillon creeMaillon ( int n ) { maillon l ; l = ( maillon ) malloc ( s i z e o f ( maillon ) ) ; i f ( l == NULL ) exit ( 0 ) ; l>data = n ; l>next = NULL ; return l ; }

Insertion au d ebut dune liste cha n ee maillon insereDebutLL ( maillon l , int n ) { maillon first = creeMaillon ( n ) ; first>next = l ; return first ; }

Cr eation dune liste cha n ee {0, . . . , n 1} maillon initLL ( int n ) { maillon 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 n ees

Un maillon dune liste doublement cha n ee contient deux pointeurs, un vers le maillon pr ec edent, et un vers le maillon suivant. typedef struct dmaillon {

75

int data ; struct dmaillon previous ; struct dmaillon next ; } dmaillon ; Aussi paradoxal que cela puisse para tre, bon nombre dop erations sont davantage ais ees sur des listes doublement cha n ees. Pour se faciliter la t ache, nous manipulerons les listes cha n ees ` a laide de deux pointeurs, un vers son premier el ement, et un vers son dernier : typedef struct dLinkedList { struct dmaillon first ; struct dmaillon last ; } dLinkedList ; Le soin decrire les op erations sur ces listes vous est laiss e dans le TP...

76

Chapitre 2

Exercices
2.1
2.1.1

Variables et op erateurs
Entiers

Exercice 1 - Saisie et achage Saisir une variable enti` ere, acher sa valeur. 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 fa con suivante : noms des variables valeurs avant la permutation valeurs apr` es la permutation 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` ere la permutation qui modie cinq valeurs de la fa con suivante : noms des variables A B C D E valeurs avant la permutation 1 2 3 4 5 valeurs apr` es la permutation 4 3 5 1 2 Ecrire un programme demandant ` a lutilisateur de saisir 5 valeurs que vous placerez dans des variables appel ees A, B , C , D et E . Vous les permuterez ensuite de la fa con d ecrite ci-dessus.

2.1.2

Flottants

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

77

Exercice 8 - Moyennes arithm etique et g eom etrique Demander ` a lutilisateur de saisir deux valeurs a et b, acher ensuite la di erence entre la moyenne (a + b) arithm etique et la moyenne g eom etrique ab. Pour indication, sqrt(f) est la racine carr ee du 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 ` a lutilisateur de saisir M et k , que vous repr esenterez 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 ` a une variable enti` ere, les d ecimales sont tronqu ees.

2.1.3

Caract` eres

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

2.1.4

Op erations sur les bits (diciles)

Exercice 14 - Codage dadresses IP Une adresse IP est constitu ee de 4 valeurs de 0 ` a 255 s epar ees par des points, par exemple 192.168.0.1, chacun de ces nombres peut se coder sur 1 octet. Comme une variable de type long occupe 4 octets en m emoire, il est possible de sen servir pour stocker une adresse IP enti` ere. Ecrivez un programme qui 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 s eparant par des points. Exercice 15 - Permutation circulaire des bits Eectuez une permutation circulaire vers la droite des bits dune variable b de type unsigned short, faites de m eme vers la droite. 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.

78

2.1.5

Morceaux choisis (diciles)

Exercice 18 - Pi` eces de monnaie Nous disposons dun nombre illimit e de pi` eces de 0.5, 0.2, 0.1, 0.05, 0.02 et 0.01 euros. Nous souhaitons, etant donn e une somme S , savoir avec quelles pi` eces la payer de sorte que le nombre de pi` eces utilis ee soit minimal. Par exemple, la somme de 0.96 euros se paie avec une pi` ece de 0.5 euros, deux pi` eces de 0.2 euros, une pi` ece de 0.05 euros et une pi` ece de 0.01 euros. 1. Le fait que la solution donn ee pour lexemple est minimal est justi e par une id ee plut ot intuitive. Expliquez ce principe sans exc` es de formalisme. 2. Ecrire un programme demandant a ` lutilisateur de saisir une valeur comprise entre 0 et 0.99. Ensuite, achez le d etail des pi` eces ` a utiliser pour constituer la somme saisie avec un nombre minimal de pi` eces. Exercice 19 - Modication du dernier bit Modiez le dernier bit dune variable a saisie par lutilisateur. Exercice 20 - Associativit e de laddition ottante 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 v eriez-le dans un programme. Exercice 21 - Permutation sans variable temporaire Permutez deux variables a et b sans utiliser de variables temporaires.

79

2.2
2.2.1

Traitements conditionnels
Prise en main

Exercice 1 - Majorit e Saisir l age de lutilisateur et lui dire sil est majeur. Exercice 2 - Valeur Absolue Saisir une valeur, acher sa valeur absolue. Exercice 3 - Admissions Saisir une note, acher ajourn e si la note est inf erieure ` a 8, rattrapage entre 8 et 10, admis dessus de 10. Exercice 4 - Assurances Une compagnie dassurance eectue des remboursements sur lesquels est ponctionn ee une franchise correspondant ` a 10% du montant ` a rembourser. Cependant, cette franchise ne doit pas exc eder 4000 euros. Demander ` a lutilisateur de saisir le montant des dommages, acher ensuite le montant qui sera rembours 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 ` a lutilisateur de saisir trois valeurs et qui lui dit sil sy trouve un 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 l equation ax + b = 0. Exercice 10 - ax2 + bx + c = 0 Saisir les coecients a, b et c, acher la solution de l equation ax2 + bx + c = 0.

2.2.2

Switch

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

80

Exercice 11 - Calculatrice Ecrire un programme demandant ` a lutilisateur de saisir deux valeurs a et b, de type int ; un op erateur op de type char, v eriez quil sagit delune des valeurs suivantes : +, , , /. Puis achez le r esultat de lop eration a op b.

2.2.3

L echiquier

On indice les cases dun echiquer avec deux indices i et j variant tous deux de 1 ` a 8. La case (i, j ) est sur la ligne i et la colonne j . Par convention, la case (1, 1) est noire. Exercice 12 - Couleurs Ecrire un programme demandant ` a lutilisateur de saisir les deux coordonn ees i et j dune case, et lui disant sil sagit dune case blanche ou noire. Exercice 13 - Cavaliers Ecrire un programme demandant ` a lutilisateur de saisir les coordonn ees (i, j ) dune premi` ere case et les coordonn ees (i , j ) dune deuxi` eme case. Dites-lui ensuite sil est possible de d eplacer un cavalier de (i, j ) a (i , j ). ` Exercice 14 - Autres pi` eces M eme exercice avec la tour, le fou, la dame et le roi. Utilisez un switch et pr esentez le programme de la 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 - Op erations sur les heures Ecrire un programme qui demande ` a lutilisateur de saisir une heure de d ebut (heures + minutes) et une heure de n (heures + minutes aussi). Ce programme doit ensuite calculer en heures + minutes le temps ecoul e entre lheure de d ebut et lheure de n. Si lutilisateur saisit 10h30 et 12h15, le programme doit lui acher que le temps ecoul e entre lheure de d ebut et celle de n est 1h45. On suppose que les deux heures se trouvent dans la m eme journ ee, si celle de d ebut se trouve apr` es celle de n, un message derreur doit sacher. Lors la saisie des heures, s eparez les heures des minutes en demandant ` a lutilisateur de saisir : heures de d ebut minutes de d ebut heures de n minutes de n 81

Exercice 16 - Le jour dapr` es Ecrire un programme permettant de saisir une date (jour, mois, ann ee), et achant la date du lendemain. Saisissez les trois donn ees s epar ement (comme dans lexercice pr ec edent). Prenez garde aux nombre de jours que comporte chaque mois, et au fait que le mois de f evrier comporte 29 jours les ann ees bissextiles. Allez sur http://fr.wikipedia.org/wiki/Ann\%C3\%A9e_bissextilepourconnatrelesrglesexactes, je vous avais dit que les ann ees etaient bissextiles si et seulement si elles etaient divisible par 4, apr` es v erication, jai constat e que c etait l eg` erement plus complexe. Je vous laisse vous documenter et retranscrire ces r` egles de la fa con la plus simple possible.

2.2.5

Intervalles et rectangles

Exercice 17 - Intervalles bien form es Demandez ` a lutilisateur de saisir les deux bornes a et b dun intervalle [a, b]. Contr oler les valeurs saisies. 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 ]. Contr olez la saisie. Dites-lui ensuite si [a, b] [a , b ] [a , b ] [a, b] [a , b ] [a, b] = . Exercice 20 - Rectangles Nous repr esenterons un rectangle R aux cot es parall` eles aux axes des abscisses et ordonn ees ` a laide des coordonn ees de deux points diam etralement oppos es, le point en haut ` a gauche, de coordonn ees (xHautGauche, yHautGauche), et le point en bas ` a droite, de coordonn ees (xBasDroite, yBasDroite). Demander ` a lutilisateur de saisir ces 4 valeurs, contr olez la saisie. Exercice 21 - Appartenance Demandez ` a lutilisateur de saisir les 2 coordonn ees dun point (x, y ) et dites ` a lutilisateur si ce point se trouve dans le rectangle R. Exercice 22 - Intersection Demandez ` a lutilisateur de saisir les 4 valeurs (xHautGauche , yHautGauche , xBasDroite , yBasDroite ) permettant de sp ecier un deuxi` eme rectangle R . Pr ecisez ensuite si RR R R RR =

2.2.6

Pr eprocesseur

Exercice 23 - L echiquer M eme exercice mais en utilisant le plus possible les sp ecications suivantes :

82

#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 , C A V A L I E R ) ; \ p r i n t f ( %hu = Tour \ n , T O U R ) ; \ p r i n t f ( %hu = Fou \ n , F O U ) ; \ p r i n t f ( %hu = Dame\ n , D A M E ) ; \ p r i n t f ( %hu = Roi \ n , R O I ) / / #d e f i n e CHECK COORD( i ) \ S I i <1 | | i >8 A L O R S \ p r i n t f ( coordonnee 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 )

83

/ / #d e f i n e FATAL ERROR p r i n t f ( System Error . I t i s recommended t h a t \ you format your hard d i s k . ) ; \ return 1 ; / / #d e f i n e CONDITIONAL PRINT( cond ) \ SI cond ALORS \ PRINT_VALID ; \ SINON \ PRINT_INVALID ; \ FINSI

2.2.7

Nombres et lettres

Exercice 24 - conversion num erique fran cais (tr` es dicile) 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 s epar es de traits dunion (ex. : quatre-vingt-quatre), sauf autour 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.

84

2.3
2.3.1

Boucles
Compr ehension

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++; printf ( %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 } printf ( 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 ; printf ( c = %d , d = %d \ n , c , d ) ; a = ++b ; 85

b %= 3 ; printf ( a = %d , b = %d \ n , a , b ) ; b = 1; f o r ( a = 0 ; a <= 10 ; a++) c = ++b ; printf ( 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 r edig es avec les trois types de boucle : tant que, r ep eter jusqu` a et pour. Exercice 4 - Compte ` a rebours Ecrire un programme demandant ` a lutilisateur de saisir une valeur num erique positive n et achant 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 appropri ee

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 ` a 10 dans un tableau ` a deux entr ees. Exercice 8 - Puissance Ecrire un programme demandant ` a lutilisateur de saisir deux valeurs num eriques b et n (v erier que n est positif) et achant la valeur bn .

2.3.4

Morceaux choisis
+

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

M emes questions qu` a lexercice pr ec edent en e ` a laide de la s erie


i=0

1 . i!

86

Exercice 11 - Approximation de ex par une s erie


+

Calculer une approximation de ex ` a laide de la s erie ex =


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 repr esentation en m emoire dun unsigned short. Exercice 13 - Conversion de d ecimales en binaire Ecrire un programme qui ache les d ecimales dun double en binaire. 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 pr ec edent. Exercice 15 - Joli carr e Ecrire un programme qui saisit une valeur n et qui ache le carr e suivant (n = 5 dans lexemple) : 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 carr ee par dichotomie Ecrire un algorithme demandant ` a lutilisateur de saisir deux valeurs num eriques x et p et achant x avec une pr ecision p. On utilisera une m ethode par dichotomie : ` a la k -` eme it eration, on cherche x dans lintervalle [min, sup], on calcule le milieu m de cet intervalle (` a vous de trouver comment le calculer). Si cet intervalle est susament petit (` a vous de trouver quel crit` ere utiliser), acher m. Sinon, v eriez si x se trouve dans [inf, m] ou dans [m, sup], et modiez les variables inf et sup en cons equence. Par exemple, calculons la racine carr ee de 10 avec une pr ecision 0.5, Commen cons par la chercher dans [0, 10], on a m = 5, comme 52 > 10, alors 5 > 10, donc 10 se trouve dans lintervalle [0, 5]. 52 On recommence, m = 2.5, comme 2 = 25 alors 5 < 10, on poursuit la recherche dans [ 5 4 < 10, 2 2 , 5] 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 l etendue de lintervalle [3.125, 3.75] est inf erieure 2 0.5, alors m = 3.4375 est une approxi mattion ` a 0.5 pr` es de 10.

2.3.5

Extension de la calculatrice

Une calculatrice de poche prend de fa con altern ee la saisie dun op erateur et dune op erande. Si lutilisateur saisit 3, + et 2, cette calculatrice ache 5, lutilisateur a ensuite la possibilit e de se servir de 5 comme dune op erande gauche dans un calcul ult erieur. Si lutilisateur saisit par la suite et 4, la calculatrice ache 20. La saisie de la touche = met n au calcul et ache un r esultat nal.

87

Exercice 17 - Calculatrice de poche Impl ementez le comportement d ecrit ci-dessus. Exercice 18 - Puissance Ajoutez lop erateur $ qui calcule ab , vous vous restreindrez ` a des valeurs de b enti` eres et positives. Exercice 19 - Op erations unaires Ajoutez les op erations unaires racine carr ee et factorielle.

88

2.4
2.4.1

Tableaux
Exercices de compr ehension

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++) printf ( %c \ n , C [ k ] ) ; f o r ( k = 0 ; k < 4 ; k++) C [ k ]++; f o r ( k = 0 ; k < 4 ; k++) printf ( %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++) printf ( %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++) printf ( %d \ n , K [ i ] ) ;

2.4.2

Prise en main

Exercice 4 - Initialisation et achage Ecrire un programme pla cant dans un tableau int T[10]; les valeurs 1, 2, . . . , 10, puis achant ce tableau. Vous initialiserez le tableau ` a la d eclaration.

89

Exercice 5 - Initialisation avec une boucle M eme exercice en initialisant le tableau avec une boucle. Exercice 6 - somme Achez la somme des n el ements du tableau T . Exercice 7 - recherche Demandez ` a lutilisateur de saisir un int et dites-lui si ce nombre se trouve dans T .

2.4.3

Indices

Exercice 8 - permutation circulaire Eectuez une permutation circulaire vers la droite des el ements de T en utilisant un deuxi` eme tableau. Exercice 9 - permutation circulaire sans deuxi` eme tableau M eme exercice mais sans utiliser de deuxi` eme tableau. Exercice 10 - miroir Inversez lordre des el ements de T sans utiliser de deuxi` eme tableau.

2.4.4

Recherche s equentielle

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

2.4.5

Morceaux choisis

Exercice 15 - pi` eces de monnaie Reprennez lexercice sur les pi` eces de monnaie en utilisant deux tableaux, un pour stocker les valeurs des pi` eces dans lordre d ecroissant, lautre pour stocker le nombre de chaque pi` ece. Exercice 16 - recherche de la tranche minimale en O(n3 ) Une tranche est d elimit ee par deux indices i et j tels que i j , la valeur dune tranche est ti + . . . + tj . Ecrire un programme de recherche de la plus petite tranche dun tableau, vous utiliserez trois boucles imbriqu ees. Vous testerez votre algorithme sur un tableau T ` a 20 el ements al eatoires (utilisez la fonction random de stdlib.h) de signes quelconques.

90

Exercice 17 - recherche de la tranche minimale en O(n2 ) M eme exercice mais en utilisant deux boucles imbriqu ees. Exercice 18 - recherche de la tranche minimale en O(n) (dicile) M eme exercice mais en utilisant une seule boucle.

91

2.5
2.5.1

Cha nes de caract` eres


Prise en main

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

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 fa con convenable. Et ne faites pas de salet es ! Question 7 - Comparaisons Saisissez deux cha nes de caract` eres, d eterminez la plus grande selon lordre lexicographique. Question 8 - Longueur Saisissez deux cha nes de caract` eres, d eterminez la plus longue des deux.. Question 9 - Copie Saisissez une cha ne de caract` eres, copiez-l` a dans une deuxi` eme cha ne. Question 10 - Concat enation Saisissez deux cha nes de caract` eres, achez la concat enation de la premi` ere ` a la suite de la deuxi` eme.

92

2.5.3

Morceaux choisis

Question 11 - Extensions Ecrire un programme saisissant un nom de chier et achant s epar ement le nom du chier et lextension. Vous pr evoirez le cas o` u plusieurs extensions sont concat en ees, par exemple : langageCCC.tar.gz. Question 12 - Expressions arithm etiques Ecrire un programme saisissant une expression arithm etique totalement parenth es ee, (par exemple 3 + 4, ((3 2) + (7/3))) et disant ` a lutilisateur si lexpression est correctement parenth es ee.

93

2.6
2.6.1

Fonctions
G eom etrie

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

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

94

* *

* *

Vous d enirez des sous-programmes de quelques lignes et au plus deux niveaux dimbrication. Vous ferez attention ` a ne jamais ecrire deux fois les m emes instructions. Pour ce faire, compl etez le code source 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 ) {

95

} / / / 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 c h a p e a u ( 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 taille ; printf ( Saisissez la t a i l l e s c a n f ( %d , & t a i l l e ) ; carre ( taille ) ; losange ( taille ) ; croix ( taille ) ; } d e s f i g u r e s \ n ) ;

2.6.2

Arithm etique

Exercice 1 - chires et nombres Rapellons que a % b est le reste de la division enti` ere de a par b. 1. Ecrire la fonction int unites(int n) retournant le chire des unit es du nombre n. 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-` eme chire de repr esentation d ecimale de n en partant des unit es. 96

4. Ecrire la fonction int nbChiffres(int n) retournant le nombre de chires que comporte la repr esentation d ecimale de n. 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 egal ` a la somme de ses diviseurs stricts. Par exemple, 6 a pour diviseurs 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-m eme ? 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 repr esentation d ecimale de n2 peut etre s epar ee 2 en une partie gauche u et une partie droite v tel que u + v = n. 45 = 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 e pour eviter toute confusion), alors 4879 est encore un nombre de Kaprekar. 1. Est-ce que 9 est un nombre de Kaprekar ? 2. Ecrire la fonction int sommeParties(int n, int p) qui d ecoupe n est deux nombres dont le deuxi` eme comporte p chires, et aui retourne leur somme. Par exemple, sommeP arties(12540, 2) = 125 + 40 = 165 3. Ecrire la fonction int estKaprekar(int n)

2.6.3

Passage de tableaux en param` etre

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

97

Exercice 8 - Somme des el ements pairs Ecrivez le corps de la fonction int sommePairs(int T[], int n), sommeP airs(T, n) retourne la somme des el ements pairs du tableau T ` an el ements. Noubliez pas que a%b est le reste de la division enti` ere de a par b, et que vous etes tenu dutiliser au mieux les bool eens. Exercice 9 - V erication 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 , ` an el ements, est tri e dans lordre croissant. Exercice 10 - permutation circulaire Ecrire une fonction void permutation(int T[], int n) eectuant une permutation circulaire vers la droite des el ements de T . Exercice 11 - miroir Ecrire une fonction void miroir(int T[], int n) inversant lordre des el ements de T .

2.6.4

D ecomposition en facteurs premiers

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-m eme. Par convention, 1 nest pas premier. Exercice 12 Ecrivez une fonction int estPremier(int n, int T[], int k) retournant 1 si n est premier, 0 sinon. Vous v erierez la primarit e de n en examinant les restes des divisions de n par les k premiers el ements de T . On suppose que k est toujours sup erieur ou egal ` a 1. Exercice 13 Modiez la fonction pr ec edente en tenant compte du fait que si aucun diviseur premier de n inf erieur ` a n na et e trouv e, alors n est premier Exercice 14 Ecrivez une fonction void trouvePremiers(int T[], int n) pla cant dans le tableau T les n premiers nombres premiers. Exercice 15 Ecrivez une fonction void d ecompose(int n, int T[], int K[]) pla cant dans le tableau K la d ecomposition en facteurs premiers du nombre n, sachant que T contient les N premiers nombres premiers. Par exemple, si n = 108108, alors on d ecompose n en produit de facteurs premiers de la sorte 108108 = 2 2 3 3 3 7 11 13 = 22 33 50 71 111 131 170 190 . . . Z 0 (o` u Z est le N -i` eme nombre premier). On repr esente donc n de fa con unique par le tableau K ` a N el ements {2, 3, 0, 1, 1, 1, 0, 0, 0, . . . , 0} Exercice 16 Ecrivez une fonction int recompose(int T[], int K[]) eectuant lop eration r eciproque de celle d ecrite ci-dessus.

98

Exercice 17 Ecrivez une fonction void pgcd(int T[], int K[], int P[]) prenant en param` etre les d ecompositions en facteurs premiers T et K de deux nombres, et pla cant dans P la d ecomposition en facteurs premiers du plus grand commun diviseur de ces deux nombres. Exercice 18 Ecrivez une fonction int pgcd(int i, int j) prenant en param` etres deux nombres i et j , et combinant les fonctions pr ec edentes pour retourner le pgcd de i et j .

2.6.5

Statistiques

Nous souhaitons faire des statistiques sur les connexions des clients dun site Web. Le tableau C , ` a n el ements, contient les identiants des clients qui se sont connect es. Ainsi C [i] contient lidentiant du i-` eme client ` a s etre connect e, notez bien que si un client se connecte plusieurs fois, son identiant appara tra plusieurs fois dans le tableau C . Le tableau D contient les dur ees de connexion. Ainsi D[i] est le temps de connexion de la i-` eme connexion. Le but est de d eterminer, pour chaque, client, son temps total de connexion. Exercice 19 Ecrire le corps du sous-programme void decalageGauche(int T[], int a, int b), ce sous-programme d ecale la tranche 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` ere occurence de C [i] dans C . 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 sup erieurs ` a i) du client didentiant C [i] dans C et D et retourne le nombre d el ements supprim es. Vous devrez utiliser decalageGauche. 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 elimine de C et de D toutes les autres occurences de ce client. Cette fonction doit retourner le nombre d el ements supprim es. Vous devrez 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 d el ements signicatifs dans C et D. Vous devrez utiliser tempsTotalDeConnexion.

99

2.6.6

Cha nes de caract` eres

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

2.6.7

Programmation dun Pendu

Cette section a pour but la programmation dun pendu, vous etes invit es ` a utiliser les fonctions d enies ci-dessus. Question 28 - initialisation Ecrire une fonction void initialise(char t[], int n) qui place dans t n caract` eres . Question 29 - v erication Ecrire une fonction void verifie(char t[], char k[], char c) qui recherche toutes les occurences du caract` ere c dans t, soit i lindice dune occurrence de c dans t, alors cette fonction remplace le i` eme caract` ere de k par c. Par exemple, si on invoque verifie(bonjour", b j r", o), alors k 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 ` a bulle 1. Ecrivez le corps de la fonction void echange(int T[], int a, int b), echange(T, a, b) echange les el ements T [a] et T [b]. 2. Ecrivez le corps de la fonction void ordonne(int T[], int a, int b), ordonne(T, a, b) echange les el ements T [a] et T [b] si T [a] > T [b]. Vous utliserez le sous-programme echange. 3. Ecrivez le corps de la fonction void bulle(int T[], int a, int b), bulle(T, a, b) place le plus grand el ement de la tranche T [a] T [a + 1] . . . T [b] dans T [b]. Vous utiliserez le sous-programme ordonne. 4. Ecrivez le corps de la fonction void triBulle(int T[], int n), triBulle(T, n) tri le tableau T ` a n el ements. Vous utiliserez le sous-programme bulle.

100

Exercice 32 - Tri par s election 1. Impl ementez la fonction int indiceDuMin(int T[], int i, int j) retournant lindice du plus petit el ement de T(i), ..., T(j), cest-` a-dire de tous les el ements du tableau dont lindice est compris entre i et j . 2. Impl ementez le sous-programme void placeMin(int T[], int i, int j, int k) echangeant avec T(k) le plus petit el ement de T dont lindice est compris entre i et j . 3. Le tri par s election est une m ethode consistant ` a rechercher dans un tableau T ` a n el ements le plus petit el ement du tableau et a ` l echanger avec le T (1). Puis ` a chercher dans T (2), . . . , T (N ) le deuxi` eme plus petit el ement et a ` l echanger avec T (2), etc. Une fois un tri par s election achev e, les el ements du tableau doivent etre dispos es par ordre croissant. Ecrivez le sous-programme void triParSelection(int T[], int N).

101

2.7
2.7.1

Structures
Prise en main

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

2.7.2

Heures de la journ ee

Nous utiliserons pour repr esenter des heures de la journ ee au format hh : mm le type typedef struct { int heure ; 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}. Compl etez le code source suivant :
#include < s t d i o . h> typedef s t r u c t { int heure ; int 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 . / heure_t creerHeure ( int heures , int minutes ) { heure_t result = {0 , 0}; return r e s u l t ; } / / / C o n v e r t i t t en minutes . / int enMinutes ( heure_t t ) { return 0 ; } / / / C o n v e r t i t l a duree t en h e u r e t . / heure_t enHeures ( int t ) { heure_t result = {0 , 0}; return r e s u l t ; }

102

/ / / 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 , heure_t b ) { heure_t result = {0 , 0}; return r e s u l t ; } / / / 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 ) { heure_t result = {0 , 0}; return r e s u l t ; } / / / Soustrait b a a . / heure_t soustraitHeures ( heure_t a , heure_t b ) { heure_t result = {0 , 0}; return r e s u l t ; } / / / Retourne 1 s i a > b , 1 s i a < b , 0 s i a = b . / int compareHeures ( heure_t a , heure_t b ) { return 0 ; } / / / Retourne l a p l u s / heure_t minHeure ( heure_t a , heure_t b ) { heure_t result = {0 , 0}; return r e s u l t ; } / / / Pour t e s t e r / int main ( ) { return 0 ; } les fonctions . . . p e t i t e des heures a e t b .

103

2.7.3

R epertoire t el ephonique

Nous consid erons les d eclarations suivantes : #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 personne { char nom [ TAILLE_NOM + 1 ] ; char tel [ TAILLE_TEL + 1 ] ; }; Il vous est demand e de programmer un r epertoire t elphonique en stockant les entr ees du r epertoire dans un tableau de structpersonne. Les entr ees devront etre tri ees, il devra etre possible de rechercher des entr ees avec le pr exe du nom, ins erer et supprimer des entr ees. Pr evoyez aussi la possibilit e dacher toutes les entr ees du r epertoire les unes ` a la suite des autres. Bon courage.

104

2.8
2.8.1

Pointeurs
Aliasing

Exercice 1 Ecrivez un programme d eclarant une variable i de type int et une variable p de type pointeur sur int. Achez les dix premiers nombres entiers en : nincr ementant que i nachant que p Exercice 2 M eme exercice en nincr ementant que p nachant que i Exercice 3 D eterminez ce quache ce programme, ex ecutez-ensuite pour v erier. #include < s t d i o . h> main ( ) { int i = 4 ; int j = 1 0 ; int p ; int q ; p = &i ; q = &j ; printf ( i = %d , p = p + q ; printf ( i = %d , p = &j ; printf ( i = %d , q = q + p ; printf ( i = %d , q = &i ; printf ( i = %d , i = 4; printf ( i = %d , q = q + 1 ; printf ( 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 acc ederez ` a l el ement dindice i de t avec lexpression (t + i). Exercice 5 - Tri ` a bulle Ecrire un sous-programme triant un tableau t avec la m ethode du tri ` a bulle. Vous acc ederez ` a l el ement dindice i de t avec lexpression (t + i). 105

2.8.3

Exercices sans sous-programmes

Exercice 6 - Tableaux de carr es Ecrire un programme qui demande ` a lutilisateur de saisir un nombre n, et qui place les n premiers 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 carr es. Exercice 7 - Matrices et pointeurs de pointeurs Ecrivez un programme qui demande ` a lutilisateur de saisir un nombre n et qui cr ee une matrice T de dimensions n n avec un tableau de n tableaux de chacun n el ements. Nous noterons tij le j -` eme el ement du i-` eme tableau. Vous initialiserez T de la sorte : pour tous i, j , tij = 1 si i = j (les el ements de la diagonale) et tij = 0 si i = j (les autres el ements). Puis vous acherez T . Exercice 8 - Copie de cha nes de caract` eres Ecrivez un programme qui saisit proprement une cha ne de caract` ere s et qui la recopie dans un tableau cr ee avec malloc et de contenance correspondant exactement ` a la longueur de s. Vous nutiliserez ni strlen, ni strcpy. Exercice 9 - Tableau de cha nes Reprennez le programme pr ec edent en saissisant successivement 4 cha nes de caract` eres et en les stockant dans un tableau de cha nes de caract` eres.

2.8.4

Allocation dynamique

Exercice 10 - Prise en main Cr eez dynamiquement un int, aectez-y la valeur 5, achez-le, lib erez la m emoire. Exercice 11 - Tableaux sur mesure Demandez ` a lutilisateur la taille du tableau quil souhaite cr eer, allouez dynamiquement lespace n ecessaire et placez-y les valeurs {0, . . . n 1}, achez-le et lib erez la m emoire.

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

106

p3 = ( p2 + D ) ; p3 = &C ; p3 = ( p2 + D ) ; printf ( A = %l d , B = %l d , C = %l d , D = %l d \ n , A , B , C , D ) ; pp = &p3 ; printf ( %l d \ n , pp ) ; return 0 ; }

2.8.6

Passages de param` etres par r ef erence

Exercice 13 D eterminez ce quache ce programme, ex ecutez-ensuite pour v erier. #include < s t d i o . h> void affiche2int ( int a , int b ) { printf ( %d , %d \ n , a , b ) ; } void incr1 ( int x ) { x = x + 1; } void incr2 ( int x ) { x = x + 1 ; } void decr1 ( int x ) { x = x 1; } void decr2 ( int x ) { x = x 1 ; } main ( ) { int i = 1 ; int j = 1 ; affiche2int ( i , incr2 (& i ) ; affiche2int ( i , decr1 (& j ) ; affiche2int ( i , decr2 (& j ) ; affiche2int ( i , while ( i != j ) {

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

107

incr1 ( j ) ; decr2 (& 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 additionne ( int a , int b , int res ) { / E c r i v e z l e c o r p s du sous programme i c i /

} main ( ) { int i = 2 ; int j = 3 ; int k ; additionne ( i , j , &k ) ; printf ( 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 point ee par res le r esultat de bn . 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 etoile

Le but de cet exercice est dencapsuler les acc` es ` a la m emoire par le biais des pointeurs dans des fonctions. Ecrivez le corps des fonctions suivantes : 1. int getIntVal(int* p) retourne la valeur se trouvant ` a ladresse p. 2. void setIntVal(int* p, int val) aecte la valeur val ` a la variable point ee par p. 3. int* getTiAdr(int* t, int i) retourne ladresse de l el ement T [i] 4. int getTiVal(int* t, int i) retourne la valeur de l el ement T [i], vous utiliserez getTiAdr et getIntVal 5. void setTiVal(int* t, int i, int val) aecte ` a T [i] la valeur val, vous utiliserez getTiAdr et setIntVal. 6. void swapInt(int* a, int* b) echange les valeurs des variables point ees par a et b. Vous utiliserez getIntVal et setIntVal. 7. void swapTij(int* t, int i, int j) echange les valeurs T [i] et T [j ], vous utiliserez swapInt et getTiAdr. 108

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.

2.8.8

Tableau de tableaux

Le but de cet exercice est de cr eer n tableaux de chacun m el ements, de placer les n pointeurs ainsi obtenus dans un tableau de pointeurs T de type int et de manier T comme un tableau ` a deux indices. Ecrivez les corps des fonctions suivantes : eme tableau dint de 1. int** getTi Adr(int** T, int i) retourne ladresse du pointeur vers le i-` T. 2. int* getTi (int** T, int i) retourne le i-` eme tableau dint de T , vous utiliserez getTi Adr. 3. void setT Adr(int** T, int* p) place dans la variable point ee par T le pointeur p. eme tableau de T , vous utiliserez getT Adr 4. void setTi (int** T, int i, int* p) fait de p le i-` et setTi Adr el ements de T vers un tableau 5. void createT (int** T, int n, int m) fait pointer chacun des n am ` el ements. Vous utiliserez setTi Adr. Nous noterons Tij le j -` eme el ement du tableau T [i]. Pour tous (i, j ) {1, . . . , 10}2 , le but est de placer 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 ecrire les corps des sous-programmes ci-dessous : 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 ` a Tij la valeur val.

2.8.9

Triangle de Pascal

En utilisant les sous-programmes ci-dessus, ecrire un programme qui demande ` a lutilisateur un nombre n, puis qui cr ee un triangle de Pascal ` a n + 1 lignes, et qui pour nir ache ce triangle de Pascal. Vous utiliserez les sous-programmes d enis dans les questions pr ec edentes et r edigerez des sous-programmes les plus simples possibles (courts, le moins d etoiles possible).

2.8.10

Pointeurs et r ecursivit e

Vous r edigerez toutes les fonctions suivantes sous forme it erative, puis r ecursive. 1. Ecrire une fonction void initTab(int* t, int n) pla cant dans le tableau t les el ements 1, 2, . . . , n. 2. Ecrire une fonction void printTab(int* t, int n) achant les n el ements du tableau t. 3. Ecrire une fonction int sommeTab(int* t, int n) retournant la somme des n el ements du tableau t. 4. Ecrire une fonction (ni r ecursive, ni it erative) void swap(int* t, int i, int j) echangeant les el ements dindices i et j du tableau t. 5. Ecrire une fonction void mirrorTab(int* t, int n) inversant lordre des el ements du tableau t. 6. Ecrire une fonction int find(int* t, int n, int x) retournant 1 si x se trouve dans le tableau t` an el ements, 0 sinon. 7. Ecrire une fonction int distinctValues(int* t, int n) retournant le nombre de valeurs distinctes du tableau t ` an el ements. Le nombre de valeurs distinctes sobtient en comptant une seule fois chaque valeur du tableau si elle appara t plusieurs fois. Par exemple, les valeurs distinctes de {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 r edigerez les fonctions suivantes sous forme r ecursive. 1. Ecrire une fonction void afficheTabHeures(heure t* t, int n) achant les n heures de t. 109

2. Ecrire une fonction void initTabHeures(heure t* t, int n, heure t depart, heure t pas) initialisant le tableau t ` a n el ements comme suit : la premi` ere heure est depart et chaque heure sobtient ` a additionnant pas ` a la pr ec edente. 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

Compl etez le code suivant :


#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 = r a n d ()% M O D ; 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 == N U L L ) { 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. / l e s n e l e m e n t s du t a b l e a u t .

110

void d e s t r o y T a b ( i n t t ) { free ( 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 . / int indexOfMin ( int t , int n ) { return 0 ; } / / / Echange l e s e l e m e n t s x e t y . / void s w a p ( i n t x , i n t y ) { int 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 av ec l e premier . / void s w a p M i n ( 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 c o p y T a b ( 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 n 2 ) { }

111

/ / / 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 ) { } / / / 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 firstValue , int lastValue , int step ) { int i ; int start , stop ; int t , q ; srand ( time ( 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 ) ; start = time ( NULL ) ; selectionSort (t , i ) ; stop = time ( 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 ) ; start = time ( NULL ) ; fusionSort (q , i ) ; stop = time ( 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 . . . / int 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 fusion .

112

2.9
2.9.1

Fichiers
Ouverture et fermeture

Exercice 1 - touch La commande shell touch permet de cr eer un chier vide. Ecrire un programme prenant le nom dun chier en ligne de commande et le cr eant.

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 cr eer un chier. Le nom du chier cr ee sera pass e en ligne de commande et le chier contiendra lalphabet. Exercice 4 - Initialiser un chier Ecrire un programme C createFile permettant de cr eer un chier. Le nom du chier cr ee sera le premier des arguments, tous les arguments suivants seront ecrits dans le chier. Par exemple, la commande ./createFile toto.txt ceci est le contenu de mon fichier doit cr eer un chier appel e toto.txt et contenant le texte ceci est le contenu de mon fichier

2.9.4

Lecture et ecriture

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 ` a lutilisateur de saisir une liste de noms et les enregistre au fur et ` a mesure quils sont saisis dans un chier dont le nom a et e pass e en ligne de commande au lancement du programme. On arr ete le programme en saisissant 1. getNames ache la liste des noms stock ee dans le chier dont le nom est pass e en ligne de commande.

2.9.5

Enigma

Compl eter le chier source suivant :


#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

113

{ char p e r m u t a t i o n [ N B _ L E T T E R S ] ; char p e r m u t a t i o n I n v e r s e [ N B _ L E T T E R S ] ; char p o s i t i o n ; } rotor ; / / typedef s t r u c t e n i g m a { rotor rotors [ NB_ROTORS ] ; char m i r r o r [ N B _ L E T T E R S ] ; } enigma ; / / / Dispose tous l e s / void i n i t i a l i s e R o t o r s ( e n i g m a 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 ( e n i g m a e ) { } / / / A l l o u e l a memoire e t / enigma enigmaCreate () { return N U L L ; } / / / 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 ( e n i g m a 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 .

114

/ / / 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 ( e n i g m a 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 ( e n i g m a 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 . / int rotateRotor ( enigma e , int indexOfRotor ) { return 0 ; } / / / Fait pivoter / void r o t a t e R o t o r s ( e n i g m a 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 ( rotor 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 ( rotor 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

115

/ / / 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 . / int mirrorEncrypt ( enigma e , int indexOfLetter ) { return 0 ; } / / / Chiffre de e . . / char e n i g m a E n c r y p t ( e n i g m a 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 ( e n i g m a e , char c l e a r F N a m e , char c i p h e r F N a m e ) { } / / / 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 ( e n i g m a e , F I L E 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 ( e n i g m a e , F I L E 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 . / e n i g m a l o a d F i l e ( char r o t o r F i l e N a m e ) { return N U L L ; }

116

/ / / 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 e n i g m a R u n ( char c l e a r , char c i p h e r , char r o t o r s ) { enigma e = loadFile ( rotors ) ; encryptFile ( e , clear , cipher ) ; enigmaDestroy ( e ) ; } / / i n t m a i n ( i n t a r g c , char a r g v [ ] ) { i f ( a r g c == 4 ) enigmaRun ( argv [ 1 ] , argv [ 2 ] , argv [ 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 ; }

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

klmnopqvwxyzgabcdefhijrstu uvwxystzabcdejklmnopqrfghi klmnopqabcdvwxyzgstuefhijr zgabcdefklmnopqvhijrstuwxy tuklmnopqvwxyzgabcdefhijrs wzgabchijrmdefynopqvstuklx

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


B o b u q , u y n l m y c k i p y v p z~ A c mjb~ Ac lr lpkn zvw e y w b o v t s s i !

117

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 transpos ee dune matrice N M pass ee en param` etre. Exercice 4 - produit Ecrire une fonction calculant le produit de deux matrices N M et M P pass ees en param` etre. Exercice 5 - triangle de Pascal Un triangle de Pascal peut etre plac e dans une matrice contenant des 1 sur la premi` ere colonne et la diagonale, et tel que chaque el ement m[i][j ] de la matrice soit la somme des el ements m[i 1][j 1] et m[i 1][j ]. Seule la partie triangulaire inf erieure dun triangle de Pascal contient des valeurs signicatives. Ecrire une fonction initialisant un triangle de Pascal ` a n lignes. Exercice 6 - Matrice marrante Ecrire une fonction pla cant dans chaque emplacement dindices (i, j ) dune matrice la valeur (i + 1)j . 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` u P (a, b) est l el ement se trouvant ` a la colonne a et ` a la ligne b du triangle de Pascal.

118

2.11
2.11.1

Listes Cha n ees


Pointeurs et structures

Exercice 1 Cr eer un type st contenant un champ i de type int et un champ c de type char. D eclarez une variable p de type st*, allouez dynamiquement une variable de type st et faites pointer p dessus. Aectez ` a cette variable les valeurs 5 et a. Achez-les, lib erez la m emoire.

2.11.2

Maniement du cha nage

Exercice 2 - prise en main Etant donn e le programme #include < s t d i o . h> / / typedef struct maillon { int data ; struct maillon next ; } maillon ; / / int main ( ) { maillon m , p ; maillon ptr ; m . data = 1 ; m . next = &p ; p . data = 2 ; p . next = NULL ; f o r ( ptr = &m ; ptr != NULL ; ptr = ptr>next ) printf ( d a t a = %d \ n , ptr>data ) ; return 0 ; } Reprennez ce programme : cr eez deux maillons q et r en renseignant les champ data aux valeurs respectives 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 119

/ / typedef struct maillon { int data ; struct maillon next ; } maillon ; / / void printData ( maillon ptr ) { f o r ( ; ptr != NULL ; ptr = ptr>next ) printf ( d a t a = %d \ n , ptr>data ) ; } / / int main ( ) { maillon l ; int i ; l = ( maillon ) malloc ( N s i z e o f ( maillon ) ) ; 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 dispos es dans lordre inverse et que, par cons equent, ce programme ache : data data data data data data data data data data = = = = = = = = = = 9 8 7 6 5 3 4 2 1 0

120

2.11.3

Op erations sur les listes cha n ees

Exercice 4 - ajout dun el ement ` a la n Erire le corps de la fonction suivante : maillon insereFinLL ( maillon l , int n ) Vous ins ererez un maillon contenant la valeur n ` a la n de la liste dont le premier el ement est point e par l. Vous retournerez un pointeur vers le premier el ement de la liste. Exercice 5 - copie dune liste cha n ee Erire le corps de la fonction suivante : maillon copyLL ( maillon source ) Vous copierez la liste l et retournerez un pointeur vers le premier el ement de la copie. Vous avez le droit dutiliser insereFinLL. Exercice 6 - inversion de lordre des el ements Ecrivez un sous-programme qui inverse lordre des el ements dune liste cha n ee, et qui retourne un pointeur sur le premier el ement de la liste nouvellement form ee.

2.11.4

Listes doublement cha n ees

Nous d enissons comme suit une liste doublement cha n 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 dmaillon { int data ; struct dmaillon previous ; struct dmaillon next ; } dmaillon ; / / typedef struct dLinkedList { struct dmaillon first ; struct dmaillon last ; } dLinkedList ; Impl ementez les fonctions suivantes : 1. void printDLL(dLinkedList* dl) ache les el ements dune liste cha n ee. 2. void freeDLL(dLinkedList* dl) lib` ere tous les maillons, puis lib` ere dl. 3. dLinkedList* makeDLL() alloue la m emoire pour une dLinkedList, initialise les pointeurs ` a NULL 4. dmaillon* makeDMaillon(int n) cr ee un maillon contenant la valeur n. 121

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

2.11.5

Fonctions r ecursives et listes cha n ees

Compl etez le code sources suivant. Les boucles sont interdites !


#include < s t d i o . h> / 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 Dans t o u t e s l e s f o n c t i o n s A 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 lls 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 . / ll creer ( int data , ll next ) { return N U L L ; } / / / 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.

122

/ 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 / ll e n t i e r s A L E n v e r s ( int n ) { return N U L L ; } / / / Retourne l a / ll e n t i e r s ( int n ) { return N U L L ; } / / / I n s e r e l e m a i l l o n x dans l a / ll insere ( ll l , ll x ) { return N U L 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 t r i I n s e r t i o n ( ll l ) { return N U L 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 = 5 > 3 > 1 e t l 2 = 4 > 2 / void s p l i t ( l l l , l l l1 , l l l 2 ) { } / / / 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 ) listes l 1 et l2 , supposees t r i e e s . l1 et l2 . 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

123

{ return N U L L ; } / / / 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 . / ll t r i F u s i o n ( ll l ) { return N U L L ; } / / / Pour t e s t e r / int main ( ) { return 0 ; } les fonctions . . .

124

Annexe A

Quelques corrig es
A.1
A.1.1

Variables et op erateurs
Entiers

Saisie et achage
#include < s t d i o . h> int 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> int main ( ) { int 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 permutation , 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> int main ( ) { int a , b , c , d , temp ; printf ( Saississez l e s 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 ) ;

v a l e u r s de 4 v a r i a b l e s : \ nA = ) ;

125

temp = a ; a = c; c = temp ; temp = b ; b = d; d = temp ; p r i n t f ( Apres permutation , 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> int main ( ) { int 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 permutation , 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> int 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 arithm etique


#include < s t d i o . h> int main ( ) { float 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 e s t %f . \ n , m o y e n n e ) ; return 0 ; }

126

Surface du rectangle
#include < s t d i o . h> int main ( ) { float largeur , longueur , surface ; printf ( largeur : ) ; s c a n f ( %f , & l a r g e u r ) ; printf ( 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 ce r e c t a n g l e e s t %f . \ n , s u r f a c e ) ; return 0 ; }

Moyennes arithm etique et g eom etrique


#include < s t d i o . h> #include <math . h> int 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` eres

Prise en main
#include < s t d i o . h> int 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 code ASCII e s t %d . \ n , a , a ) ; return 0 ; }

Successeur
#include < s t d i o . h> int 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 ; }

127

Casse
#include < s t d i o . h> int 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> int main ( ) { 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 ; }

code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ; code ASCII %d \ n , c , c ) ;

A.1.4

Op erations binaires

Codage dadresses IP
#include < s t d i o . h> int main ( ) { unsigned long i p = 0 , m a s q u e = 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 v a l e u r : ) ; 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 v a l e u r : ) ; 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 code en l o n g s o u s l a forme %l u . \ n , i p ) ; p r i n t f ( Vous remarquez 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 : ) ; octet4 = ip & masque ; ip > >= 8 ; octet3 = ip & masque ; ip > >= 8 ;

128

octet2 = ip & masque ; ip > >= 8 ; octet1 = ip & 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> int 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 ) ; firstBit = 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 d e s b i t s , %hu \ n , s ) ; return 0 ; }

cette valeur est

Permutation de 2 octets
#include < s t d i o . h> int main ( ) { unsigned i n t u , t e m p ; 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 & 255; temp < <= 8 ; u > >= 8 ; u |= t e m p ; 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 , %u \ n , u ) ; return 0 ; }

cette valeur est

Permutation de 4 octets
#include < s t d i o . h> int 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

129

A.1.5

Morceaux choisis

Pi` eces de monnaie


#include < s t d i o . h> #d e f i n e EPS 0 . 0 0 1 int 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 ) ; / / nbPieces = ( valeur + 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 ; / / nbPieces = ( valeur + 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 ; / / nbPieces = ( valeur + 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 ; / / nbPieces = ( valeur + 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 ; / / nbPieces = ( valeur + EPS )/ 0 . 0 2 ; p r i n t f ( %d p i e c e ( s ) de 0 . 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 . 0 2 ; / / nbPieces = ( valeur + EPS )/ 0 . 0 1 ; p r i n t f ( %d p i e c e ( s ) de 0 . 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 . 0 1 ; return 0 ; }

Dernier bit
#include < s t d i o . h> int 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> int 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

130

p r i n t f ( Apres permutation , 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 ; }

131

A.2
A.2.1

Traitements conditionnel
Prise en Main

Majorit e
#include < s t d i o . h> int main ( ) { unsigned short a g e ; p r i n t f ( T as q u e l age ? \ 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> int 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> int 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 ) printf ( 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> int main ( ) { float dommages , franchise , 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 , & d o m m a g e s ) ; franchise = dommages 0 . 1 ; i f ( franchise > 4000) franchise = 4000; remboursement = dommages franchise ; 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 ) ;

132

p r i n t f ( Montant rembourse : %.2 f \ n , r e m b o u r s e m e n t ) ; return 0 ; }

Valeurs distinctes parmi 2


#include < s t d i o . h> int 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 ) ; printf ( 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> int main ( ) { int 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 ) ; printf ( 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 . , m i n ) ; p r i n t f ( \ n ) ; return 0 ; }

Recherche de doublons
#include < s t d i o . h> int 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 ) ; printf ( 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 s a i s i e s ) ; 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 ; }

133

Valeurs distinctes parmi 3


#include < s t d i o . h> int main ( ) { int 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 ) ; printf ( 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 ; 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 , n b d ) ; return 0 ; }

ax + b = 0
#include < s t d i o . h> int 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 ) ; printf ( 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> int 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 ) ; printf ( 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 = b b 4 a c ; i f ( delta > 0) { x1 = ( sqrt ( delta ) b ) / ( 2 a ) ; x 2 = ( 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 , x 2 ) ; }

134

else { if { x 1 = ( 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 , x 1 ) ; } else p r i n t f ( (E) n a pas de s o l u t i o n } } else { i f ( b != 0 ) { x 1 = 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 , x 1 ) ; } 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 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 ; } ( d e l t a == 0 )

reelle);

A.2.2

Switch

Calculatrice
#include < s t d i o . h> #include < s t d l i b . h> int main ( ) { float gauche , droite , resultat ; int erreur = 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 , & g a u c h e ) ; 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 = g a u c h e + d r o i t e ; break ; case : r e s u l t a t = g a u c h e d r o i t e ; break ; case / : r e s u l t a t = g a u c h e / d r o i t e ; break ; case : r e s u l t a t = g a u c h e d r o i t e ; break ; default : erreur = 1 ; } i f ( 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 , g a u c h e , o p e r a t e u r , d r o i t e , r e s u l t a t ) ; return 0 ; }

A.2.3

Heures et dates

Op erations sur les heures


#include < s t d i o . h> int main ( ) { int heureDebut , heureFin , minuteDebut , minuteFin ,

135

heureEcart , minuteEcart ; p r i n t f ( Heure d e b u t ( hh :mm) ? ) ; s c a n f ( %d:%d , &h e u r e D e b u t , & m i n u t e D e b u t ) ; 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 , & m i n u t e F i n ) ; heureEcart = heureFin heureDebut ; minuteEcart = 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` es
#include < s t d i o . h> int main ( ) { int jour , 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 , &m o i s , & a n n e e ) ; switch ( m o i s ) { 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 % 100)) nbJours = 28; else nbJours = 29; break ; default : erreur = 1; } i f ( erreur ) { p r i n t f ( S a i s i e e r r o n n e e : %2.2d/%2.2d/%4.4d \ n , jour , mois , annee ) ; return 1; } p r i n t f ( Le lendemain du %2.2d/%2.2d/%4.4d e s t l e , jour , mois , annee ) ; j o u r ++; i f ( j o u r == n b J o u r s + 1 ) { jour = 1 ; m o i s ++; i f ( m o i s == 1 3 ) { mois = 1 ; a n n e e ++; } } p r i n t f ( e s t l e %2.2d/%2.2d/%4.4d . \ n , jour , mois , annee ) ; return 0 ; }

A.2.4

Echiquier

Couleurs des cases


#include < s t d i o . h> int main ( ) { unsigned short i , j ;

136

p r i n t f ( S a i s i s s e z l e s coordonnees 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 printf ( 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> int main ( ) { unsigned short iD , jD , iA , j A ; p r i n t f ( S a i s i s s e z l e s coordonnees de l a c a s e de d e p a r t : \ n ) ; printf ( i = ) ; s c a n f ( %hu , &i D ) ; printf ( j = ) ; s c a n f ( %hu , &j D ) ; p r i n t f ( S a i s i s s e z l e s coordonnees de l a c a s e de l a c a s e d a r r i v e e : \ n ) ; printf ( i = ) ; s c a n f ( %hu , &i A ) ; printf ( j = ) ; s c a n f ( %hu , &j A ) ; 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 , j A ) ; i f ( ( a b s ( i A i D ) == 1 && a b s ( j A j D ) == 2 ) | | ( a b s ( i A i D ) == 2 && a b s ( j A j D ) == 1 ) ) printf ( valide ) ; else printf ( invalide ) ; p r i n t f ( . \ n ) ; return 0 ; }

Autres pi` eces


#include < s t d i o . h> #include < s t d l i b . h> int 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 coordonnees de l a c a s e de d e p a r t : \ n ) ; printf ( i = ) ; s c a n f ( %hu , &i D ) ; i f ( iD <1 | | iD > 8) { p r i n t f ( coordonnee i n v a l i d e \ n ) ; return 1 ; } printf ( j = ) ; s c a n f ( %hu , &j D ) ; i f ( jD <1 | | jD > 8) { p r i n t f ( coordonnee 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 coordonnees de l a c a s e d a r r i v e e : \ n ) ; printf ( i = ) ; s c a n f ( %hu , &i A ) ;

137

if {

( iA <1 | | iA > 8) p r i n t f ( coordonnee i n v a l i d e \ n ) ; return 1 ;

} printf ( j = ) ; s c a n f ( %hu , &j D ) ; i f ( jD <1 | | jD > 8) { p r i n t f ( coordonnee 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 , j A ) ; switch ( p i e c e ) { case 0 : i f ( ( a b s ( i A i D ) == 1 && a b s ( j A j D ) == 2 ) | | ( a b s ( i A i D ) == 2 && a b s ( j A j D ) == 1 ) ) printf ( valide ) ; else printf ( invalide ) ; case 1 : i f ( i A == i D | | j A == j D ) printf ( valide ) ; else printf ( invalide ) ; case 2 : i f ( a b s ( i A i D ) == a b s ( j A j D ) ) printf ( valide ) ; else printf ( invalide ) ; case 3 : i f ( i A == i D | | j A == j D | | a b s ( i A i D ) == a b s ( j A j D ) ) printf ( valide ) ; else printf ( invalide ) ; case 4 : i f ( a b s ( i A i D ) <= 1 && a b s ( j A j D ) <= 1 ) printf ( valide ) ; else printf ( invalide ) ; d e f a u l t : p r i n t f ( System Error . I t i s recommended t h a t you format 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 form es


#include < s t d i o . h> int main ( ) { f l o a t inf , s u p ; 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 ] , &inf , &s u p ) ; p r i n t f ( Cet i n t e r v a l l e e s t ) ; i f ( inf > sup ) p r i n t f ( mal ) ; else printf ( bien ) ; p r i n t f ( forme . \ n ) ; return 0 ; }

[);

Appartenance ` a un intervalle

138

#include < s t d i o . h> int main ( ) { f l o a t inf , 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 ] , &inf , &s u p ) ; if { p r i n t f ( Cet i n t e r v a l l e return 1; e s t mal forme . \ 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 <= s u p ) printf ( appartient ) ; else p r i n t f ( n a p p a r t i e n t pas ) ; p r i n t f ( a l i n t e r v a l l e [% f , %f ] . \ n , inf , s u p ) ; return 0 ; } ( inf > sup )

[);

Intersections dintervalles
#include < s t d i o . h> A F F I C H E _ I N T ( inf , s u p ) \ p r i n t f ( [% f , %f ] , inf , s u p ) int main ( ) { f l o a t inf1 , sup1 , inf2 , sup2 , infIntersection , supIntersection ; int inclusion1 , inclusion2 , 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 , &s u p 1 ) ; i f ( inf1 > sup1 ) { p r i n t f ( Cet i n t e r v a l l e e s t mal forme . \ n ) ; 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 , &s u p 2 ) ; i f ( inf2 > sup2 ) { p r i n t f ( Cet i n t e r v a l l e e s t mal forme . \ n ) ; return 1; } i n c l u s i o n 1 = i n f 2 < i n f 1 && s u p 1 < s u p 2 ; i n c l u s i o n 2 = i n f 1 < i n f 2 && s u p 2 < s u p 1 ; infIntersection = ( inf1 > inf2 ) ? inf1 : inf2 ; supIntersection = ( sup1 < sup2 ) ? sup1 : sup2 ; intersectionNonVide = infIntersection < supIntersection ; A F F I C H E _ I N T ( inf1 , sup1 ) ; i f ( inclusion1 ) prinftf ( est ) ; else p r i n f t f ( n e s t pas ) ; p r i n f t f ( i n c l u s dans ) ; A F F I C H E _ I N T ( inf2 , sup2 ) ; p r i n t f ( \ n ) ; A F F I C H E _ I N T ( inf2 , sup2 ) ; i f ( inclusion2 ) prinftf ( est ) ; else p r i n f t f ( n e s t pas ) ; p r i n f t f ( i n c l u s dans ) ; A F F I C H E _ I N T ( inf1 , sup1 ) ; p r i n t f ( \ nL i n t e r s e c t i o n de ) ; A F F I C H E _ I N T ( inf1 , sup1 ) ; p r i n t f ( e t de ) ; A F F I C H E _ I N T ( inf2 , 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 ) ;

139

return 0 ; }

Pr eprocesseur
#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 , C A V A L I E R ) ; \ p r i n t f ( %hu = Tour \ n , T O U R ) ; \ p r i n t f ( %hu = Fou \ n , F O U ) ; \ p r i n t f ( %hu = Dame\ n , D A M E ) ; \ p r i n t f ( %hu = Roi \ n , R O I ) / / #d e f i n e CHECK COORD( i ) \ S I i <1 | | i >8 A L O R S \ p r i n t f ( coordonnee 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 ) ; / /

140

#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 Error . I t i s recommended t h a t \ you format your hard d i s k . ) ; \ return 1 ; / / #d e f i n e CONDITIONAL PRINT( cond ) \ SI cond ALORS \ PRINT_VALID ; \ SINON \ PRINT_INVALID ; \ FINSI / / 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 coordonnees de l a c a s e de d e p a r t : \ n ) ; G E T _ V A R ( i , iD ) ; G E T _ V A R ( j , jD ) ; p r i n t f ( S a i s i s s e z l e s coordonnees de l a c a s e d a r r i v e e : \ n ) ; G E T _ V A R ( i , iA ) ; G E T _ V A R ( j , jA ) ; p r i n t f ( Le mouvement (%hu , %hu ) > (%hu , %hu ) e s t , iD , jD , iA , j A ) ; SUIVANT ( piece ) CAS ( CAVALIER , C O N D I T I O N A L _ P R I N T ( ( a b s ( i A i D ) == 1 && a b s ( j A j D ) == 2 ) | | ( a b s ( i A i D ) == 2 && a b s ( j A j D ) == 1 ) ) ; ) CAS ( TOUR , C O N D I T I O N A L _ P R I N T ( i A == i D | | j A == j D ) ; ) C A S ( FOU , C O N D I T I O N A L _ P R I N T ( a b s ( i A i D ) == a b s ( j A j D ) ) ; ) CAS ( DAME , C O N D I T I O N A L _ P R I N T ( i A == i D | | j A == j D | | a b s ( i A i D ) == a b s ( j A j D ) ) ; ) C A S ( ROI , C O N D I T I O N A L _ P R I N T ( a b s ( i A i D ) <= 1 && a b s ( j A j D ) <= 1 ) ; ) FINSUIVANT ( FATAL_ERROR ; ) p r i n t f ( . \ n ) ; FINMAIN

A.2.6

Nombres et lettres

Conversion num erique fran cais


#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 ) ; \

141

if if if if if if if if if

(i (i (i (i (i (i (i (i (i

== == == == == == == == ==

11) 12) 13) 14) 15) 16) 17) 18) 19)

p r i n t f ( onze ) ; \ p r i n t f ( douze ) ; \ printf ( t r e i z e ) ; \ printf ( quatorze ) ; \ printf ( quinze ) ; \ printf ( seize ) ; \ p r i n t f ( d i x s e p t ) ; \ p r i n t f ( d i x h u i t ) ; \ p r i n t f ( d i x n 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 ; \ unites = ( nb ) % 1 0 ; \ d i z a i n e s = ( ( n b ) 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 = ( ( n b ) ( n b )%100) / 100 % 1 0 ; \ i f ( c e n t a i n e s >= 2 ) \ {\ AFFICHE_UNITE ( centaines );\ p r i n t f ( ) ; \ }\ i f ( centaines > 0)\ printf ( 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 ( dizaines > 1)\ {\ AFFICHE_DIZAINE ( dizaines ) ; \ }\ 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 && \ 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 ( deuxDerniers 60); \ }\ else \ i f ( d i z a i n e s == 9 ) \ {\ AFFICHE_UNITE ( deuxDerniers 80); \ }\ else \ i f ( d i z a i n e s == 1 ) \ {\ AFFICHE_UNITE ( deuxDerniers );\ }\ else \ {\ AFFICHE_UNITE ( unites ) ; \ }\ } #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 ) \ {\ A F F I C H E _ T R O I S _ C H I F F R E S ( 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 ) ; \

142

}\ } int 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 ) ; A F F I C H E _ T R O I S _ C H I F F R E S _ U N I T E ( i , m i l l i a r d , ( unsigned long ) 1 e 9 ) ; A F F I C H E _ T R O I S _ C H I F F R E S _ U N I T E ( i , m i l l i o n , ( unsigned long ) 1 e 6 ) ; i f ( i %( m i l l e m i l l e ) / m i l l e >= 2 ) { A F F I C H E _ T R O I S _ C H I F F R E S ( 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 ) ; A F F I C H E _ T R O I S _ C H I F F R E S ( i%m i l l e ) ; i f ( i == 0 ) printf ( zero ) ; p r i n t f ( \ n ) ; return 0 ; }

143

A.3
A.3.1

Boucles
Utilisation de toutes les boucles

Compte ` a rebours (Tant que)


#include < s t d i o . h> int 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 ` a rebours (R ep eter . . . jusqu` a)


#include < s t d i o . h> int 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 ` a rebours (Pour)


#include < s t d i o . h> int 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> int 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 ) ;

: );

144

return 0 ; }

Factorielle (R ep eter . . . jusqu` a)


#include < s t d i o . h> int 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> int 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 appropri ee

Table de Multiplication
#include < s t d i o . h> int 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> int 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 ) ;

145

} return 0 ; }

bn
#include < s t d i o . h> int 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 ) ; p r i n t f ( S a i s i s s e z un nombre e n t i e r p o s i t i f 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 ; }

: );

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 )

int main ( ) { double t e r m e = 1 , s e r i e = 0 ; while ( A B S ( t e r m e ) > E P S ) { s e r i e += t e r m e ; t e r m e = 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 , E P S ) ; 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 )

int main ( ) { double t e r m e = 1 . , s e r i e = 0 . , f a c t e u r = 1 . ; while ( A B S ( t e r m e ) > E P S ) { s e r i e += t e r m e ; t e r m e /= 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 , E P S ) ; return 0 ; }

146

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 )

int main ( ) { double t e r m e = 1 . , s e r i e = 0 . , f a c t e u r = 1 . , x ; printf ( x = ) ; s c a n f ( %l f , &x ) ; while ( A B S ( t e r m e ) > E P S ) { s e r i e += t e r m e ; t e r m e = ( 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 , E P S ) ; return 0 ; }

Conversion dentiers en binaire


#include < s t d i o . h> int main ( ) { unsigned short s , i , m a s k = 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 ) ; c sentation b i n a i r e e s t [ ) ; p r i n t f ( Sa repr A 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&m a s k ) ! = 0 ) ; m a s k >>=1; } p r i n t f ( ] \ n ) ; return 0 ; }

Converssion de d ecimales en binaire


#include < s t d i o . h> int 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 ) ; c sentation b i n a i r e e s t [ 0 . ) ; p r i n t f ( Sa repr A 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> int main ( ) {

147

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) { firstBit = firstMask & s ; lastBit = 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 ( AprAs 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> int main ( ) { 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 carr ee par dichotomie


#include < s t d i o . h> #d e f i n e EPS 1 e 10 int main ( ) { double x , inf , sup , m i d ; 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 ( s u p i n f > E P S ) { mid = ( inf + sup ) / 2 ; i f ( mid mid > x ) sup = mid ; else inf = 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 , ( inf + sup )/2 , EPS ) ; return 0 ; }

148

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 int main ( ) { int T [ N ] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10}; 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 int main ( ) { int 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 int main ( ) { int T [ N ] ; int i , somme = 0 ; f o r ( i = 0 ; i < N ; i ++) T[i] = i; f o r ( i = 0 ; i < N ; i ++) s o m m e += 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 , s o m m e ) ; return 0 ; }

Recherche
#include < s t d i o . h> #d e f i n e N 10 int main ( ) { int 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 )

149

i ++; ( 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 , i ) ; return 0 ; if }

A.4.2

Indices

Permutation circulaire
#include < s t d i o . h> #d e f i n e N 10 int main ( ) { int T [ N ] ; int 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` eme tableau


#include < s t d i o . h> #d e f i n e N 10 int main ( ) { int 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 int main ( ) { int T [ N ] ; int 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 ;

150

} 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 s equentielle

Modication du tableau
#include < s t d i o . h> #d e f i n e N 20 int main ( ) { int 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 int main ( ) { i n t T [ N ] , i , min , m a x ; 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 ; }

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

Recherche s equentielle
#include < s t d i o . h> #d e f i n e N 20 int main ( ) { int 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 ; }

151

Recherche s equentielle avec stockage des indices


#include < s t d i o . h> #d e f i n e N 20 int main ( ) { int 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 [ n b V ++] = i ; i f ( n b V == 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 s u i v a n t s : \ n , t ) ; f o r ( i = 0 ; i < n b V ; i ++) p r i n t f ( %d \ n , I [ i ] ) ; } return 0 ; }

A.4.4

Morceaux choisis

Pi` eces de monnaie


#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 int main ( ) { f l o a t pieces [ N ] = { 0 . 5 , 0 . 2 , 0 . 1 , 0 . 0 5 , 0 . 0 2 , 0 . 0 1 } , somme , reste ; 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 , &s o m m e ) ; } while ( s o m m e <= 0 ) ; reste = somme ; f o r ( i = 0 ; i < N ; i ++) { n b P i e c e s [ i ] = ( r e s t e +E P S ) / 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 payer c e t t e somme a vec 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 , n b P i e c e s [ i ] , ( ( n b P i e c e s [ 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 int main ( ) { int T [ N ] , i , j , k ; int valeurTrancheMin , debutTrancheMin , finTrancheMin , f o r ( i = 0 ; i < N ; i ++) { T [ i ] = r a n d o m ()%27 1 1 ; p r i n t f ( T[%d ] = %d \ n , i , T [ i ] ) ;

valeurTranche

152

} 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 minimale e s t s i t u e e e n t r e l e s debutTrancheMin , finTrancheMin ) ; return 0 ; }

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

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 int main ( ) { int T [ N ] , i , j ; int valeurTrancheMin , debutTrancheMin , finTrancheMin , valeurTranche ; f o r ( i = 0 ; i < N ; i ++) { T [ i ] = r a n d o m ()%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 minimale 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 , finTrancheMin ) ; return 0 ; }

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 int main ( ) { int T [ N ] , i ; int valeurTrancheMin , debutTrancheMin , finTrancheMin ; int valeurTrancheMinAvecI , debutTrancheMinAvecI , finTrancheMinAvecI ; f o r ( i = 0 ; i < N ; i ++) { T [ i ] = r a n d o m ()%27 1 1 ; p r i n t f ( T[%d ] = %d \ n , i , T [ i ] ) ; } valeurTrancheMin = T [ 0 ] ;

153

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 minimale 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 , finTrancheMin ) ; return 0 ; }

154

A.5
A.5.1

Cha nes de caract` eres


Prise en main

Achage
#include < s t d i o . h> int 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 grand p e r e . ; p r i n t f ( %s \ n , s ) ; return 0 ; }

Achage sans %s
#include < s t d i o . h> int 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 grand p 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 ) int main ( ) { char s [ B U F F E R _ S I Z E ] ; int i = 0 ; fgets ( s , BUFFER_SIZE , stdin ) ; 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 ) int main ( ) { char s [ B U F F E R _ S I Z E ] ; int i = 0 ; fgets ( s , BUFFER_SIZE , stdin ) ; while ( s [ i ] != 0 ) i ++; i f ( s [ i 1 ] != \ n ) CLEAR_BUFFER ; else { s [ i 1] = 0;

155

i ; } p r i n t f ( l o n g u e u r = %d \ n , i ) ; return 0 ; }

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 ) int main ( ) { char s [ B U F F E R _ S I Z E ] , t [ B U F F E R _ S I Z E ] ; int r ; R ne : \ n ) ; p r i n t f ( S a i s i r une chaA fgets ( s , BUFFER_SIZE , stdin ) ; i f ( s [ s t r l e n ( s ) 1 ] != \ n ) CLEAR_BUFFER ; else s [ strlen ( s ) 1] = 0; R ne : \ n ) ; p r i n t f ( S a i s i r une a u t r e chaA fgets ( t , BUFFER_SIZE , stdin ) ; 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 ) int main ( ) { char s [ B U F F E R _ S I Z E ] , t [ B U F F E R _ S I Z E ] ; int r ; R ne : \ n ) ; p r i n t f ( S a i s i r une chaA fgets ( s , BUFFER_SIZE , stdin ) ; i f ( s [ s t r l e n ( s ) 1 ] != \ n ) CLEAR_BUFFER ; else s [ strlen ( s ) 1] = 0; R ne : \ n ) ; p r i n t f ( S a i s i r une a u t r e chaA fgets ( t , BUFFER_SIZE , stdin ) ; 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) printf ( 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 ) ;

156

return 0 ; }

A.5.3

Morceaux choisis

Extensions
#include < s t d i o . h> #include < s t r i n g . h> #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 ) int main ( ) { char s [ B U F F E R _ S I Z E ] ; int k , i ; R ne : \ n ) ; p r i n t f ( S a i s i r une chaA fgets ( s , BUFFER_SIZE , stdin ) ; 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` eses
#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 ) int main ( ) { char s [ B U F F E R _ S I Z E ] ; int k , i ; p r i n t f ( S a i s i r une c h a i n e : \ n ) ; fgets ( s , BUFFER_SIZE , stdin ) ; 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;

157

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

158

A.6
A.6.1

Fonctions
G eom etrie

#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 ) ; } / /

159

/ 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 c h a p e a u ( i n t c e n t r e , char c ) { int k ; int delta ; f o r ( k = 2 ; k <= c e n t r e 1 ; k ++) { delta = k 1; d e u x C a r a c t e r e s ( 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 delta ; f o r ( k = c e n t r e 1 ; k >= 2 ; k ) { delta = k 1; d e u x C a r a c t e r e s ( 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 )

);

);

160

{ unCaractereAvecReturn (n , ) ; chapeau (n , ) ; d e u x C a r a c t e r e s ( 1 , 2 n 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 , 2 n 1 , ) ; chapeauInverse (n , ) ; unCaractereAvecReturn (n , ) ; chapeau (n , ) ; d e u x C a r a c t e r e s ( 1 , 2 n 1 , ) ; } / / main ( ) { int taille ; printf ( Saisissez la t a i l l e s c a n f ( %d , & t a i l l e ) ; carre ( taille ) ; losange ( taille ) ; croix ( taille ) ; } d e s f i g u r e s \ n ) ;

A.6.2

Arithm etique

#include < s t d i o . h> / / int unites ( int n ) { return n %10; } / / int dizaines ( int n ) { return u n i t e s ( n / 1 0 ) ; } / / int extrait ( int n , int k ) { while ( k > 1) n /= 1 0 ; return u n i t e s ( n ) ; } / / int nbChiffres ( int n ) { int i = 0 ; while ( n != 0 ) { i ++; n /= 1 0 ; } return i ; } / / int sommeChiffres ( int n )

161

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

162

A.6.3

Passage de tableaux en param` etre

#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 ) ; } / / int somme ( int t [ ] , int n ) { int s = 0 , i ; f o r ( i = 0 ; i < n ; i ++) s += t [ i ] ; return s ; } / / int min ( int t [ ] , int n ) { int m = t [ 0 ] , i = 0 ; while (++ i < n ) m = (m < t [ i ]) ? m : t [ i ]; return m ; } / / int existe ( 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 ; } / / int sommePairs ( int t [ ] , int 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 estTrie ( 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 dernier = t [ n 1 ] , i ; f o r ( i = n 1 ; i > 0 ; i ) t[i] = t[i 1]; t [ 0 ] = dernier ; }

163

/ / void e c h a n g e ( i n t t [ ] , i n t i , i n t j ) { int 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

D ecomposition en facteurs premiers

#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 divise ( int a , int b ) { return b % a == 0 ; } / / int power ( int b , int n ) { i f ( n == 0 ) return 1 ; return b p o w e r ( 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 ( divise ( 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 [ ] , { int i ; int n )

164

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 [ ] , i n t n , i n t v a l ) { int i ; f o r ( i = 0 ; i < n ; i ++) T [ i ]= v a l ; } / / void d e c o m p o s e ( i n t n , i n t K [ ] , i n t T [ ] ) { int i ; initTab ( 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 res = 1 ; int i ; for ( i = 0 ; i < n ; i ++) { r e s = p o w e r ( T [ i ] , K [ i ] ) ; } return r e s ; } / / int min ( int a , int b ) { if (a < b) return a ; return b ; } / / void p g c d T a b ( i n t A [ ] , i n t B [ ] , i n t r e s [ ] , { int i ; f o r ( i = 0 ; i < n ; i ++) res [ i ] = min ( A [ i ] , B [ i ] ) ; } int n )

/ / int pgcd ( int a , int b ) { int A [ SIZE_TAB ] ; int B [ SIZE_TAB ] ; int T [ SIZE_TAB ] ; int P [ SIZE_TAB ] ; trouvePremiers (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 , S I Z E _ T A B ) ; } / / main ( ) { int a = 90; int b = 108;

165

p r i n t f ( pgcd(%d , %d ) = %d , a , b , p g c d ( a , b ) ) ; getch ( ) ; }

A.6.5

Statistiques

void d e c a l a g e G a u c h e ( i n t T [ ] , i n t a , i n t b ) { int i ; f o r ( i = a ; i <= b ; i ++) { T [ i 1] = T [ i ] ; } } / / int calculeTempsTotalConnexionClient ( int C [ ] , { int j , sum = 0 ; f o r ( j = i ; j < n ; j ++) i f ( C [ j ] == C [ i ] ) s u m += D [ j ] ; return s u m ; } int D [ ] , int n , int i )

/ / int supprimeDoublons ( int C [ ] , int D [ ] , int n , int i ) { i n t n b S u p p r = 0 , j = i +1; while ( j < n n b S u p p r ) i f ( C [ j ] == C [ i ] ) { decalageGauche (C , j + 1 , n nbSuppr 1 ) ; decalageGauche (D , j + 1 , n nbSuppr 1 ) ; n b S u p p r ++; } else j ++; return n b S u p p r ; } / / int tempsTotalDeConnexion ( int C [ ] , int D [ ] , int n , int i ) { D [ i ] = calculeTempsTotalConnexionClient (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 ) ; } / / int tempsTotauxDeConnexion ( int C [ ] , int D [ ] , int n ) { int i = 0 ; while ( i < n ) n = t e m p s T o t a l D e C o n n e x i o n ( C , D , n , i ++); return n ; }

A.6.6

Chaines de caract` eres

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 ;

166

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 ) { 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; } / / i n t 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 t e r m i n e P e n d u ( 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 = verifie ( 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 , l e t t r e ) ; 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 [ ] , int nbEssais )

167

{ char k [ N ] ; int lettresATrouver = longueur ( t ) 1 ; initialise (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 ++; i f ( t [ i 1] == \ n ) t [ i 1] = 0 ; else while ( g e t c h a r ( ) != \ n ) ; } / / void j o u e r P e n d u ( ) { char t [ N ] ; trouver : ) ; p r i n t f ( S a i s s e z l e mot A saisieChaine (t , N ) ; i f ( trouverPendu (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 ) { int temp = t [ i ] ; t[i] = t[j ]; t [ j ] = temp ; } / / void o r d o n n e ( i n t T [ ] , i n t a , i n t b ) { if (T [ a ] > T [ b ]) echange (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 r d o n 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 = n 1 ; i > 0 ; i )

168

bulle ( T , 0 , i ) ; } / / int indiceDuMin ( int T [ ] , int i , int j ) { int iMin = i , k ; f o r ( k = i + 1 ; k <= j ; k ++) i M i n = ( T [ i M i n ] <= T [ k ] ) ? i M i n : k ; return i M i n ; } / / 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 ) { echange (T , k , indiceDuMin (T , i , j ) ) ; } / / 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 , n 1 , i ) ; } / / int main ( ) { int T [ N ] ; int i ; f o r ( i = 0 ; i < N ; i ++) T [ i ] = rand ()%100; afficheTableau (T , N ) ; triBulle (T , N ) ; afficheTableau (T , N ) ; miroir ( T , N ) ; afficheTableau (T , N ) ; triParSelection (T , N ) ; afficheTableau (T , N ) ; return 0 ; }

169

A.7
A.7.1

Structures
Heures

#include < s t d i o . h> typedef s t r u c t { int heure ; int 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 . / heure_t creerHeure ( int heures , int minutes ) { heure_t x = { heures , minutes } ; return x ; } / / / C o n v e r t i t t en minutes . / int enMinutes ( heure_t t ) { return 60 t . h e u r e + t . m i n u t e ; } / / / C o n v e r t i t l a duree t en h e u r e t . / heure_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 . h e u r e , x . m i n u t e ) ; } / / / Additionne a e t b . / heure_t additionneHeures ( heure_t a , heure_t b ) { return e n H e u r e s ( e n M i n u t e s ( a ) + e n M i n u t e s ( 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 ( e n M i n u t e s ( c r e e r H e u r e ( 1 2 , 0 ) ) enMinutes ( x ) ) ;

170

} / / / 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 . / int compareHeures ( heure_t a , heure_t b ) { 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 ; } / / / Retourne l a p l u s / heure_t minHeure ( heure_t a , heure_t b ) { i f ( c o m p a r e H e u r e s ( a , b ) <= 0 ) return a ; else return b ; } / / / Pour t e s t e r / int main ( ) { return 0 ; } les fonctions . . . p e t i t e des heures a e t b .

A.7.2

R epertoire t el ephonique

#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 n o m [ T A I L L E _ N O M + 1 ] ; char t e l [ T A I L L E _ T E L + 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 )

171

{ p r i n t f ( %s : %s \ n , p . nom , p . t e l ) ; } / / c es dont l e nom ne commence pas // A f f i c h e t o u t e s l e s entr A re nul . // par un c a r a c t A 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 < N B _ M A X _ N O M S && r [ i ] . n o m [ 0 ] != 0 ) { p r i n t f ( %d , i ) ; affichePersonne ( r [ i ] ) ; i ++; } } / / re nul . // 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 c pertoire . // 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 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 < N B _ M A X _ N O M S ; i ++) rep [ i ] . nom [ 0 ] = 0 ; } / / c // 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 rieure A c e l l e de l a deuxi Ame // sup A personne . int c o m p a r e P e r s o n n e s ( struct personne p , struct personne q ) { return s t r n c m p ( p . nom , q . nom , T A I L L E _ N O M ) ; } / / 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 = s u p ; i >= i n f ; i ) r e p [ i +1] = r e p [ i ] ; } i n t inf , i n t s u p )

/ / 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 <= s u p ; i ++) r e p [ i 1] = r e p [ i ] ; } i n t inf , i n t s u p )

/ / 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 // Retourne l i n d i c e du premier A int trouveFin ( struct personne rep [ ] ) { int i = 0 ; while ( i < N B _ M A X _ N O M S && r e p [ i ] . n o m [ 0 ] != 0 ) i ++; i f ( i != N B _ M A X _ N O M S ) return i ; return 1; } / / c pertoire , l e m a i n t i e n t triA c . // Ajoute une personne au r A 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 ) { int sup = trouveFin ( rep ) ; int inf = 0 ; i f ( s u p == 1) return 1; while ( i n f < s u p && ( c o m p a r e P e r s o n n e s ( p , r e p [ i n f ] ) > 0 ) ) c pertoire e s t p l e i n . l e rA

172

i n f ++; d e c a l a g e D r o i t e ( rep , inf , s u p 1 ) ; rep [ inf ] = p ; return 1 ; } / / c pertoire . // Ajoute une personne au r A 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 n o m [ ] , char t e l [ ] ) { struct personne p ; s t r n c p y ( p . nom , nom , T A I L L E _ N O M ) ; s t r n c p y ( p . tel , tel , T A I L L E _ T E L ) ; p . nom [ TAILLE_NOM ] = 0 ; p . tel [ 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 ) ; } / / c butNom . // 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 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 d e b u t N o m [ ] ) { int i ; f o r ( i = 0 ; i < N B _ M A X _ N O M S ; i ++) i f ( r [ i ] . n o m [ 0 ] != 0 && ! s t r n c m p ( r [ i ] . nom , d e b u t N o m , s t r l e n ( d e b u t N o m ) ) ) { 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; } / / c ment d i n d i c e i ave c s e s v o i s i n s c lA // En c a s de changement de nom, permute l A ce que l e t a b l e a u s o i t triA c . // j u s q u A 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 , indice 1 , indice ) ; triLocal ( r , indice 1 ) ; } i f ( i n d i c e < N B _ M A X _ N O M S 1 && r [ i n d i c e + 1 ] . n o m [ 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 , indice + 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 c h a n g e N o m ( 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 n o u v e a u N o m [ ] ) { s t r n c p y ( r [ i n d i c e ] . nom , n o u v e a u N o m , T A I L L E _ N O M ) ; r [ indice ] . nom [ TAILLE_NOM ] = 0 ; triLocal ( r , indice ) ; } / / c ro d i n d i c e i n d i c e par nouveauNumA c ro . // Remplace l e numA void c h a n g e N u m e r o ( 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 n o u v e a u T e l [ ] ) { s t r n c p y ( r [ i n d i c e ] . tel , n o u v e a u T e l , T A I L L E _ T E L ) ; r [ indice ] . tel [ TAILLE_TEL ] = 0 ;

173

} / / c cale l e s A c lA c ments s u i v a n t s pour // Supprime l a personne d i n d i c e i n d i c e , dA c viter l e s t r o u s dans l e t a b l e a u . // A 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 ) { int sup = trouveFin ( r ) ; int inf = indice ; decalageGauche ( r , inf + 1 , sup 1 ) ; r [ sup 1 ] . nom [ 0 ] = 0 ; } / / main ( ) { struct personne repertoire [ NB _MA X_ NOM S ] ; initRepertoire ( repertoire ) ; a j o u t e P e r s o n n e ( r e p e r t o i r e , t o t o , 0123456789 ) ; a j o u t e P e r s o n n e ( r e p e r t o i r e , t y t y , 0123456789 ) ; a j o u t e P e r s o n n e ( r e p e r t o i r e , t i t i , 0123456789 ) ; a j o u t e P e r s o n n e ( r e p e r t o i r e , t a t a , 0123456789 ) ; a j o u t e P e r s o n n e ( r e p e r t o i r e , t u t u , 0123456789 ) ; afficheRepertoire ( repertoire ) ; supprimePersonne ( repertoire , 2 ) ; afficheRepertoire ( repertoire ) ; getch ( ) ; }

174

A.8
A.8.1

Pointeurs
Exercices sans sous-programmes

Tableau de carr es
#include < s t d i o . h> #include < s t d l i b . h> #include <m a l l o c . h> int 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 == N U L L ) 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> int main ( ) { i n t T ; int i , j , n ; p r i n t f ( Valeur de n ? ) ; s c a n f ( %d , &n ) ; T = ( int ) malloc ( n s i z e o f ( int ) ) ; i f ( T == N U L L ) exit ( 0 ) ; f o r ( i = 0 ; i < n ; i ++) { ( T + i ) = ( int ) malloc ( n sizeof ( int ) ) ; i f ( ( T + i ) == N U L L ) 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 ++) free (( T + i ) ) ; free ( T ) ; return 0 ; }

Copie de cha nes de caract` eres

175

#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 CLEAR BUFFER while ( g e t c h a r ( ) != \ n ) int main ( ) { char b u f f e r [ B _ S I Z E ] , c o p i e ; int len = 0 , i ; r e : \ n ) ; 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 fgets ( buffer , B_SIZE , stdin ) ; 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 len ; 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 ++) ( copie + i ) = buffer [ i ] ; ( copie + len ) = 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 ) int main ( ) { char b u f f e r [ B _ S I Z E ] , c o p i e s ; int len = 0 , j , i ; c o p i e s = ( char ) m a l l o c ( N B _ S s i z e o f ( char ) ) ; f o r ( j = 0 ; j < N B _ S ; j ++) { r e : \ n ) ; 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 fgets ( buffer , B_SIZE , stdin ) ; 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 len ; ( 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 < N B _ 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 etoiles et triangle de Pascal

#include < s t d i o . h>

176

#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 ) { p = val ; } int getTiAdr ( int t , int i ) { return t + i ; } int getTiVal ( int t , int i ) { return g e t I n t V a l ( g e t T i A d r ( 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 ) { setIntVal ( getTiAdr ( t , i ) , val ) ; } void s w a p I n t ( i n t a , i n t b ) { int temp ; s e t I n t V a l (& t e m p , g e t I n t V a l ( a ) ) ; setIntVal (a , getIntVal ( b ) ) ; setIntVal ( b , temp ) ; } void s w a p T i j ( i n t t , i n t i , i n t j ) { swapInt ( getTiAdr (t , i ) , getTiAdr (t , j ) ) ; } 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 _ _ A d r ( i n t t , i n t p ) { t = p ; } 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 ++) { setTi_ ( T , i , ( int ) malloc ( m sizeof ( int ) ) ) ; i f ( g e t T i _ ( T , i ) == N U L L ) { p r i n t f ( Heap o v e r f l o w \ n ) ; exit ( 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 g e t T i A d r ( 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 )

177

{ 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 ) } 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 ++) { setTi_ ( p , i , ( int ) malloc ( ( i + 1) sizeof ( int ) ) ) ; i f ( g e t T i _ ( p , i ) == N U L L ) { p r i n t f ( Heap o v e r f l o w \ n ) ; exit ( 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 == N U L L ) { p r i n t f ( Heap o v e r f l o w \ n ) ; exit ( 1); } mallocPascal (p , n ) ; setC_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 , j ) ) ; 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 ++) { free ( getTi_ ( p , i ) ) ; } free ( p ) ; } main ( ) { i n t p = p a s c a l ( 1 5 ) ; printPascal (p , 15); }

178

A.8.3

Fonctions r ecursives

#include < s t d i o . h> typedef s t r u c t { int heure ; int minute ; } heure_t ; / / int sommeTab ( int t , int n ) { int i , s = 0 ; f o r ( i = 0 ; i < n ; i ++) s += ( t + i ) ; return s ; } / / int sommeTabRec ( int t , int n ) { i f ( n > 0) return t + s o m m e T a b R e c ( 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 p r i n t T a b R e c ( 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 s w a p ( i n t t , i n t i , i n t j ) { int temp = ( t + i ) ; ( t + i ) = ( t + j ) ; ( t + j ) = temp ;

179

} / / void m i r r o r T a b ( i n t t , i n t n ) { i n t i = 0 , j = n 1; while ( i < j ) { swap ( t , i , j ) ; i ++; j ; } } / / void m i r r o r T a b R e c ( i n t t , i n t n ) { i f ( n > 0) { swap ( t , 0 , n 1); mirrorTabRec ( t + 1 , n 2); } } / / int find ( 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 distinctValues ( int t , int n ) { int i , dv = 1 ; f o r ( i = 0 ; i < n 1 ; i ++) d v += ! f i n d ( t + i + 1 , n 1 i , ( t + i ) ) ; return d v ; } / / 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 ; } / / heure_t creerHeure ( int heures , int minutes ) { heure_t x = { heures , minutes } ; return x ; } / / int enMinutes ( heure_t t ) { return 60 t . h e u r e + t . m i n u t e ;

180

} / / heure_t enHeures ( int t ) { h e u r e _ t x = { t /60%12 , t %60 } ; return x ; } / / 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 . h e u r e , x . m i n u t e ) ; } / / heure_t additionneHeures ( heure_t a , heure_t b ) { return e n H e u r e s ( e n M i n u t e s ( a ) + e n M i n u t e s ( b ) ) ; } / / heure_t inverseHeure ( heure_t x ) { return e n H e u r e s ( e n M i n u t e s ( c r e e r H e u r e ( 1 2 , 0 ) ) enMinutes ( 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 ) ) ; } / / int compareHeures ( heure_t a , heure_t b ) { 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 minHeure ( heure_t a , heure_t b ) { i f ( c o m p a r e H e u r e s ( 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) { afficheHeure ( 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 , h e u r e _ t p a s ) { i f ( n > 0)

181

{ t = depart ; initTabHeures ( t + 1 , n 1 , additionneHeures ( depart , pas ) , pas ) ; } } / / heure_t sommeTabHeures ( heure_t t , int n ) { int i ; heure_t res = creerHeure (0 , 0 ) ; f o r ( i = 0 ; i < n ; i ++) r e s = a d d i t i o n n e H e u r e s ( res , ( t + i ) ) ; return r e s ; } / / heure_t sommeTabHeuresRec ( heure_t t , int 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 , s o m m e T a b H e u r e s R e c ( t + 1 , n 1 ) ) ; } / / heure_t minTabHeure ( heure_t t , int n ) { i f ( n == 1 ) return t ; else return m i n H e u r e ( t , m i n T a b H e u r e ( 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 = r a n d ()% M O D ; initTab ( t + 1 , n 1 ) ; } } l e s n e l e m e n t s du t a b l e a u t .

182

/ / / 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 == N U L L ) { 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 ) { free ( 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 . / int indexOfMin ( int t , int n ) { i f ( n == 1 ) return 0 ; i f ( n > 1) { int rec = indexOfMin ( t + 1 , n 1) + 1 ; return ( t < ( t + r e c ) ) ? 0 : r e c ; } p r i n t f ( Erreur 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 s w a p ( i n t x , i n t y ) { int 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 av ec l e premier . / void s w a p M i n ( i n t t , i n t n ) { swap ( t , t + indexOfMin ( t , n ) ) ; } / /

183

/ ( 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); } } / / / ( 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 c o p y T a b ( 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 ( source + 1 , dest + 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 n 2 ) { i f ( n1 > 0 | | n2 > 0) { i f ( n 1 == 0 | | ( n 2 > 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 , n 2 1 ) ; } else { dest = source1 ; s h u f f l e T a b ( s o u r c e 1 + 1 , source2 , dest + 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) { int m = n /2 , q , r ; q = createTab ( m ) ; r = t + m; copyTab (t , q , m ) ; fusionSort (q , m ) ; fusionSort (r , n m ) ; shuffleTab (q , r , t , m , n m ) ; d e s t r o y T a b (& q ) ; } } / / fusion .

184

/ 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 firstValue , int lastValue , int step ) { int i ; int start , stop ; int t , q ; srand ( time ( 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 ) ; start = time ( NULL ) ; selectionSort (t , i ) ; stop = time ( 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 ) ; start = time ( NULL ) ; fusionSort (q , i ) ; stop = time ( 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 . . . / int 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

185

A.9
A.9.1
touch

Fichiers
Ouverture et fermeture

#include < s t d i o . h> i n t m a i n ( 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 or 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 == N U L L ) { p r i n t f ( Erreur 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 ( Erreur 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 m a i n ( i n t a r g v , 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 == N U L L ) return 1 ; c = getc ( f ) ; while ( c != E O F ) { 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 m a i n ( i n t a r g c , char a r g v [ ] ) { FILE f ; char c ; i f ( a r g c != 2 ) {

186

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 or 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 == N U L L ) { p r i n t f ( Erreur 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 ( Erreur 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 m a i n ( 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 or 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 == N U L L ) { p r i n t f ( Erreur 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 ++) { fputs (( 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 ( Erreur 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 ecriture

#include < s t d i o . h> i n t m a i n ( i n t a r g v , char a r g c ) { FILE source ; FILE dest ; int c ; source = fopen (( argc + 1) , r ) ; d e s t = f o p e n ( ( a r g c + 2 ) , w ) ;

187

( s o u r c e == N U L L | | d e s t == N U L L ) return 1 ; while ( ( c = g e t c ( s o u r c e ) ) ! = E O F ) { fputc ( c , dest ) ; } fclose ( source ) ; fclose ( dest ) ; return 0 ; if }

Liste de noms
#include < s t r i n g . h> #include < s t d i o . h> i n t m a i n ( i n t a r g v , 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 == N U L L ) return 1 ; gets ( buffer ) ; while ( s t r c m p ( 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 m a i n ( i n t a r g v , 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 == N U L L ) 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 ; }

188

A.10
A.10.1

Listes Cha n ees


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 ; int main ( ) { st p ; p = ( st ) malloc ( s i z e o f ( st ) ) ; p >i = 5 ; p >c = a ; p r i n t f ( p = (%d , %c ) \ n , p >i , p >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 ; / / int main ( ) { maillon m , p , q , r ; maillon ptr ; m . data = 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 . next = NULL ; f o r ( p t r = &m ; p t r != N U L L ; p t r = ptr >n e x t ) p r i n t f ( d a t a = %d \ n , ptr >d a t a ) ; 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 ;

189

/ / 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 != N U L L ; p t r = ptr >n e x t ) p r i n t f ( d a t a = %d \ n , ptr >d a t a ) ; } / / int main ( ) { maillon l ; int i ; l = ( maillon ) malloc ( N sizeof ( maillon ) ) ; i f ( l == N U L L ) exit ( 0 ) ; l >d a t a = 0 ; l >n e x t = N U L L ; 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 ; }

Op erations sur les listes cha n ees


#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 != N U L L ; p t r = ptr >n e x t ) p r i n t f ( d a t a = %d \ n , ptr >d a t a ) ; } / / maillon creeMaillon ( int n ) { maillon l ; l = ( maillon ) malloc ( sizeof ( maillon ) ) ; i f ( l == N U L L ) exit ( 0 ) ; l >d a t a = n ; l >n e x t = N U L L ; return l ; } / / maillon insereFinLL ( maillon l , int n ) { maillon last = creeMaillon ( n ) ; maillon first = l ; i f ( l == N U L L ) return l a s t ; else { while ( l >n e x t != N U L L ) l = l >n e x t ; l >n e x t = l a s t ;

190

} return f i r s t ; } / / maillon copyLL ( maillon source ) { maillon copie ; maillon maillonCopie ; i f ( s o u r c e == N U L L ) return N U L L ; copie = creeMaillon ( source >d a t a ) ; maillonCopie = copie ; source = source >n e x t ; while ( s o u r c e != N U L L ) { maillonCopie >n e x t = c r e e M a i l l o n ( s o u r c e >d a t a ) ; maillonCopie = maillonCopie >n e x t ; source = source >n e x t ; } maillonCopie >n e x t = N U L L ; return c o p i e ; } / / maillon reverseLL ( maillon l ) { maillon previous ; maillon current ; maillon next ; i f ( l == N U L L ) return N U L L ; c u r r e n t = l >n e x t ; l >n e x t = N U L L ; previous = l ; next = current ; while ( c u r r e n t != N U L L ) { i f ( n e x t != N U L L ) next = next >n e x t ; current >n e x t = p r e v i o u s ; previous = current ; current = next ; } return p r e v i o u s ; } / / maillon insereDebutLL ( maillon l , int n ) { maillon first = creeMaillon ( n ) ; first >n e x t = l ; return f i r s t ; } / / maillon initLL ( int n ) { maillon 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 != N U L L ) { n = l >n e x t ; free ( l ) ; l = n; } }

191

/ / int main ( ) { maillon l ; maillon k ; l = initLL ( N ) ; printLL ( l ) ; k = copyLL ( l ) ; k = reverseLL ( k ) ; printLL ( k ) ; freeLL ( l ) ; freeLL ( k ) ; return 0 ; }

A.10.3

Listes doublement cha n ees

#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 previous ; struct dmaillon next ; } dmaillon ; / / typedef s t r u c t d L i n k e d L i s t { struct dmaillon first ; struct dmaillon last ; } dLinkedList ; / / / Affiche / l e s e l e m e n t s d une l i s t e chainee .

void p r i n t D L L ( d L i n k e d L i s t d l ) { dmaillon m ; f o r ( m = dl >f i r s t ; m != N U L L ; 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 f r e e D L L ( d L i n k e d L i s t d l ) { dmaillon m ; dmaillon next ; f o r ( m = dl >f i r s t ; m != N U L L ; m = n e x t ) { n e x t = m >n e x t ; free ( m ) ; } free ( dl ) ; } / / /

192

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 / dLinkedList makeDLL () { dLinkedList l ; l = ( dLinkedList ) malloc ( sizeof ( dLinkedList ) ) ; i f ( l == N U L L ) exit ( 0 ) ; l >f i r s t = N U L L ; l >l a s t = N U L 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 . / dmaillon makeDMaillon ( int n ) { dmaillon d ; d = ( dmaillon ) malloc ( sizeof ( dmaillon ) ) ; i f ( d == N U L L ) exit ( 0 ) ; d >p r e v i o u s = N U L L ; d >n e x t = N U L L ; d >d a t a = n ; 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 a p p e n d D M a i l l o n D L L ( d L i n k e d L i s t dl , d m a i l l o n m ) { i f ( dl >l a s t == N U L L ) { dl >f i r s t = m ; dl >l a s t = m ; } else { dl >l a s t >n e x t = m ; m > p r e v i o u s = dl >l a s t ; dl >l a s t = m ; } dl >f i r s t >p r e v i o u s = N U L L ; dl >l a s t >n e x t = N U L L ; } / / / 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 p u s h D M a i l l o n D L L ( d L i n k e d L i s t dl , d m a i l l o n m ) { i f ( dl >l a s t == N U L L ) { dl >f i r s t = m ; dl >l a s t = m ; } else { dl >f i r s t >p r e v i o u s = m ; m >n e x t = dl >f i r s t ; dl >f i r s t = m ; } dl >f i r s t >p r e v i o u s = N U L L ; dl >l a s t >n e x t = N U L L ; } / /

193

/ 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 a p p e n d I n t D L L ( d L i n k e d L i s t dl , i n t n ) { a p p e n d D M a i l l o n D L L ( dl , m a k e D M a i l l o n ( n ) ) ; } / / / 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 p u s h I n t D L L ( d L i n k e d L i s t dl , i n t n ) { p u s h D M a i l l o n D L L ( dl , m a k e D M a i l l o n ( 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 i n i t D L L ( d L i n k e d L i s t dl , i n t n ) { int i ; f o r ( i = 0 ; i < n ; i ++) a p p e n d I n t D L L ( dl , i ) ; } / / / Inverse / l o r d r e d e s e l e m e n t s de d l .

void r e v e r s e D L L ( d L i n k e d L i s t d l ) { dmaillon m ; dmaillon temp ; i f ( dl >f i r s t != N U L L ) { f o r ( m = dl >f i r s t ; m != N U L L ; m = m >p r e v i o u s ) { t e m p = 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 = t e m p ; } } t e m p = dl >f i r s t ; dl >f i r s t = dl >l a s t ; dl >l a s t = t e m p ; } / / / Retourne une c o p i e de s o u r c e . / dLinkedList copyDLL ( dLinkedList source ) { dLinkedList dest = makeDLL ( ) ; dmaillon sourceMaillon ; for ( sourceMaillon = source >f i r s t ; s o u r c e M a i l l o n != N U L L ; sourceMaillon = sourceMaillon >n e x t ) a p p e n d I n t D L L ( dest , s o ur c e Ma i l l on >d a t a ) ; 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 .

194

void c o n c a t D L L ( d L i n k e d L i s t d e b u t , d L i n k e d L i s t f i n ) { i f ( debut >f i r s t == N U L L ) { debut >f i r s t = fin >f i r s t ; debut >l a s t = fin >l a s t ; } else { debut >l a s t >n e x t = fin >f i r s t ; i f ( fin >f i r s t != N U L L ) fin >f i r s t >p r e v i o u s = d e b u t >l a s t ; debut >l a s t = fin >l a s t ; } fin >f i r s t = N U L L ; fin >l a s t = N U L L ; } / / int main ( ) { d L i n k e d L i s t dl = m a k e D L L ( ) ; d L i n k e d L i s t cp ; i n i t D L L ( dl , N ) ; p r i n t D L L ( dl ) ; cp = c o p y D L L ( dl ) ; p r i n t D L L ( cp ) ; r e v e r s e D L L ( cp ) ; p r i n t D L L ( cp ) ; c o n c a t D L L ( dl , c p ) ; p r i n t D L L ( dl ) ; f r e e D L L ( dl ) ; f r e e D L L ( cp ) ; return 0 ; }

A.10.4

Fonctions r ecursives et listes cha n ees

#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 lls 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 . / ll creer ( int data , ll next ) { ll l = ( ll ) malloc ( s i z e o f ( ll ) ) ; i f ( l == N U L L ) { p r i n t f ( heap o v e r f l o w \ n , ) ; exit ( 0 ) ; } l >d a t a = d a t a ; l >n e x t = n e x t ; return l ; } / / /

195

Affiche l e maillon l / void a f f i c h e ( l l l ) { i f ( l != N U L L ) p r i n t f ( %d > , l >d a t a ) ; } / / / 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 ) { i f ( l != N U L L ) { affiche ( l ) ; a f f i c h e T o u t ( l >n e x t ) ; } 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 != N U L L ) { a f f i c h e A L E n v e r s ( l >n e x t ) ; 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 != N U L L ) { d e t r u i t ( & ( ( l )> n e x t ) ) ; free ( 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 N U L L ; } / / / 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 ) { 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 liste l.

196

( 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 , N U L L ) ; } / / / I n s e r e l e m a i l l o n x dans l a / ll insere ( ll l , ll x ) { i f ( l == N U L L | | x >d a t a <= l >d a t a ) { x >n e x t = l ; return x ; } l >n e x t = i n s e r e ( l >n e x t , 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 t r i I n s e r t i o n ( ll l ) { i f ( l == N U L L ) return N U L L ; return i n s e r e ( t r i I n s e r t i o n ( l >n e x t ) , 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 l1 , l l l 2 ) { i f ( l != N U L L ) { s p l i t ( l >n e x t , l2 , l 1 ) ; l >n e x t = l 1 ; 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 == N U L L ) return l 2 ; i f ( l 2 == N U L L ) return l 1 ; i f ( l1 >d a t a < l2 >d a t a ) { l1 >n e x t = i n t e r c l a s s e ( l1 >n e x t , l 2 ) ; return l 1 ; } listes l 1 et l2 , supposees t r i e e s . l1 et l2 . liste l , supposee t r i e e . l i s t e 1 > 2 > . . . > n

if

197

else { l2 >n e x t = i n t e r c l a s s e ( l1 , l2 >n e x t ) ; 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 . / ll t r i F u s i o n ( ll l ) { i f ( l == N U L L | | l >n e x t == N U L L ) return l ; else { ll l1 = NULL , l2 = NULL ; s p l i t ( l , &l1 , &l 2 ) ; l1 = t r i F u s i o n ( l1 ) ; l2 = t r i F u s i o n ( l2 ) ; return i n t e r c l a s s e ( l1 , l 2 ) ; } } / / / Pour t e s t e r / int main ( ) { long n = 5 0 0 0 0 ; ll 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 = triInsertion ( m ) ; p r i n t f ( ok \ n ) ; d e t r u i t (& m ) ; return 0 ; } les fonctions . . .

198

Annexe A

M ethodologie
A.1 Le probl` eme

D` es que lon code un programme dune certaine envergure, bon nombre de probl` emes se posent. 1. Le d ebogage peut devenir un cauchemar sans n. 2. Ensuite le code ecrit peut etre une bouillie lisible que par son auteur. 3. Le code peut contenir des redondances qui nen facilite ni la lecture, ni le d ebogage. Je passe les nombreuses dicult es et laideurs pouvant r esulter dun d eveloppement h atif. Retenez que sans m ethode, vous ne parviendrez pas ` a d evelopper un projet important, tout simplement parce que le temps de d ebogage sera prohibitif, et parce que votre code, apr` es les multiples bidouillages auxquels vous soumettrez pour d eboguer sera un gros pav e bord elique et illisible.

A.2

Les r` egles dor

La solution au probl` eme mentionn e ci-avant r eside dans lapplication des r` egles dor suivantes :

A.2.1

G en eralit es

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

A.2.2

Fonctions

Commencez par d ecouper votre tr` es gros probl` eme en plein de petits probl` emes que vous traiterez individuellement avec des fonctions. Chaque fonction devra : 1. porter un nom explicite : vous avez droit ` a 256 caract` eres... 2. etre pr ec ed ee dun commentaire d ecrivant clairement et sans paraphraser le code ce que fait la fonction. 3. tenir sur une page : il faut que vous puissiez voir toute la fonction sans avoir ` a utiliser lascenseur, et comprendre ais ement ce quelle fait. 4. contenir au maximum trois niveaux dimbrication : si vous avez plus de trois blocs (boucles, conditions, etc.) imbriqu es, placez tout ce qui d eborde dans une autre fonction. 5. ne jamais utiliser de variables globales : lutilisation des variables globales est r eserv ee ` a certains cas tr` es pr ecis. Dans tous les autres cas, vos fonctions doivent utiliser les passages de param` etres (par adresse si n ecessaire) et les valeurs de retour. 199

6. etre pr ec ed ee de toutes les fonctions quelle appelle : dune part un lecteur parcourant votre code le comprendra plus ais ement si pour chaque appel de fonction, il a d ej` a vu la d enition de cette fonction. Ainsi on pourra lire votre code dans lordre et eviter de slalomer entre les fonctions. Dautre part, cela vous evitera davoir ` a ecrire les prototypes des fonctions en d ebut de chier. Vous r eserverez aux cas o` u il et impossible (ou laid) de faire autrement les fonctions qui sinvoquent mutuellement.

A.2.3

Compilation s epar ee

Un chier contenant plusieurs centaines de fonctions est impossible ` a lire, en plus d etre dune laideur accablante. Vous prendrez donc soin de regrouper vos fonctions dans des chiers, de les compiler s epar ement et de les linker avec un makele.

A.3

D ebogage

Vous etes probablement d ej` a conscients du fait que le d ebogage occupe une partie tr` es signicative du temps de d eveloppement. Aussi est-il appr eciable de la diminuer autant que possible. 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 op er ees pour corriger les erreurs ne font souvent que nuire ` a la lisibilit e du code 3. Et enn parce quun temps anormalement elev e est en g en eral une cons equence dune analyse et dun codage h atifs. Aussi est-il g en eralement plus ecace de passer un peu plus de temps ` a coder, et beaucoup moins de temps ` a d eboguer. Pour ce faire : 1. Notez bien que tous les conseils enonc es pr ec edemment sont encore dactualit e. En particulier ceux 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 ` a trouver quand on les cherche dans une dizaine de lignes que dans une dizaine de pages. Et en assemblant des fonctions qui marchent correctement, vous aurez plus de chances de r ediger un programme correct. 3. Nh esitez pas ` a utiliser des logiciels comme valgrind. valgrind examine lex ecution de votre code et vous rapporte bon nombre dutilisation irr eguli` ere de la m emoire (pointeurs fous, zones non lib er ees, etc.)

A.4

Dur ee de vie du code

Si vous ne voulez pas quun jour un d eveloppeur fasse un s electionner/supprimer sur votre code, vous devez avoir en t ete lid ee que quand quelquun reprend ou utilise votre code vous devez r eduire au minimum ` a la fois le temps quil mettra ` a le comprendre et le nombre de modications quil devra faire.

A.4.1

Le code doit etre r eutilisable

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 aveugl ement et sans m eme regarder ce quil y a dedans. Les noms des fonctions et les commentaires d ecrivant leurs comportement doivent etre clairs, pr ecis, et bien evidemment exempt de bugs. Sinon, un s electionner/supprimer mettra n ` a la courte vie de votre code. Notez bien par ailleurs que si vous avez r eparti votre code dans des chiers s epar es de fa con intelligente, votre code sera bien plus simple ` a r eutiliser.

200

A.4.2

Le code doit etre adaptable

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

A.5

Exemple : le carnet de contacts

Je me suis eorc e, autant que possible, de suivre mes propres conseils et de vous donner un exemple. Je vous laisse ` a la fois observer mes recommandations dans le code qui suit, et traquer les eventuelles 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 , int sizeMax ) ;

/ / / S a i s i t un e n t i e r . / int getInt ( ) ; / / / 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 s i z e M a 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 , int sizeMax ) { int len ; f g e t s ( adr , s i z e M a x , s t d i n ) ; len = strlen ( adr ) ; i f ( ( a d r + l e n 1 ) == \ n ) ( adr + len 1) = 0 ; else while ( g e t c h a r ( ) != \ n ) ; } / / int getInt ( ) { char t a b [ 1 0 ] ;

201

g e t S t r i n g ( tab , 1 0 ) ; return a t o i ( t a b ) ; } / / void s w a p S t r i n g s ( char s1 , char s2 , i n t s i z e M a x ) { char t e m p [ s i z e M a x ] ; s t r n c p y ( t e m p , s1 , s i z e M a x ) ; s t r n c p y ( s1 , s2 , s i z e M a x ) ; s t r n c p y ( s2 , t e m p , s i z e M a x ) ; ( s1 + s i z e M a x 1) = 0 ; ( s2 + s i z e M a x 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 ma il . / 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 n o m b r e M a i l s ( 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 . /

202

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 ) ; / / / 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 m a i l , 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 indice = 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 < N B _ M A I L S && 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 S I Z E _ M A I L ; } / / i n t n o m b r e M a i l s ( char m a i l s ) { int indice = 0 ; while ( i n d i c e < N B _ M A I L S && g e t M a i l ( m a i l s , i n d i c e ) ) i n d i c e ++; return i n d i c e ; } / /

203

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 ) S I Z E _ M A I L N B _ M A I L S ) ; int i ; i f ( a d r == N U L L ) { p r i n t f ( Heap o v e r f l o w ) ; exit ( 0 ) ; } f o r ( i = 0 ; i < N B _ M A I L S ; i ++) g e t M a i l ( adr , i ) = 0 ; return a d r ; } / / void d e t r u i t M a i l s ( char m a i l s ) { free ( 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 < N B _ M A I L S && g e t M a i l ( m a i l s , i n d i c e + 1 ) ) { strncpy ( getMail ( mails , indice ) , getMail ( mails , indice + 1 ) , SIZE_MAIL ) ; i n d i c e ++; } i f ( indice < NB_MAILS ) getMail ( mails , indice ) = 0 ; } / / / 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 milieu ; i f ( i n d i c e M a x == 0 ) return 0 ; milieu = indiceMax / 2; i f ( ! getMail ( mails , milieu ) ) 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 + i n d i c e P r e m i e r e C h a i n e V i d e ( getMail ( mails , milieu + 1 ) , indiceMax ( milieu + 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 < N B _ M A I L S && strncmp ( getMail ( mails , indice ) , getMail ( mails , indice 1 ) , SIZE_MAIL ) < 0) { swapStrings ( getMail ( mails , indice ) , getMail ( mails , indice 1 ) , SIZE_MAIL ) ; placeMail ( mails , indice 1 ) ; } else i f ( i n d i c e >= 0 && i n d i c e < N B _ M A I L S 1 &&

204

g e t M a i l ( m a i l s , i n d i c e + 1 ) && strncmp ( getMail ( mails , indice ) , getMail ( mails , indice + 1 ) , SIZE_MAIL ) > 0) { swapStrings ( getMail ( mails , indice ) , getMail ( mails , indice + 1 ) , SIZE_MAIL ) ; placeMail ( mails , indice + 1 ) ; } } / / void a j o u t e M a i l ( char m a i l s , char m a i l ) { int indice ; i f ( getMail ( mails , 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 { indice = i n d i c e P r e m i e r e C h a i n e V i d e ( mails , NB_MAILS 1 ) ; s t r n c p y ( g e t M a i l ( mails , indice ) , mail , S I Z E _ M A I L ) ; ( getMail ( mails , indice ) + SIZE_MAIL 1) = 0 ; placeMail ( mails , indice ) ; } } / / void c h a n g e M a i l ( char m a i l s , char m a i l , i n t i n d i c e ) { s t r n c p y ( g e t M a i l ( mails , indice ) , mail , S I Z E _ M A I L ) ; ( getMail ( mails , indice ) + SIZE_MAIL 1) = 0 ; placeMail ( mails , indice ) ; } / / 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 ) { F I L E f = f o p e n ( n o m F i c h i e r , w ) ; int i ; i f ( f == N U L L ) 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 < N B _ M A I L S && 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 ) , S I Z E _ M A I L , 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 = fopen ( nomFichier , r ) ; int i , ret = 1 ; i f ( f == N U L L ) 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 < N B _ M A I L S && 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 ) , S I Z E _ M A I L , f ) ; fclose ( 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 AFFICHER OPTION 1 #d e f i n e SUPPRIMER OPTION 2 #d e f i n e MODIFIER OPTION 3

205

#d e f i n e AJOUTER OPTION 4 #d e f i n e QUITTER OPTION 5 #d e f i n e 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 . / void a f f i c h e M e n u ( ) { p r i n t f ( \ nOptions 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 supprimer 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 > N B _ O P T I O N S ) 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 > N B _ O P T I O N S ) ; 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 ema il de v o t r e c o n t a c t : ) ; do { g e t S t r i n g ( adr , S I Z E _ M A I L ) ; 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 ; nbMails = nombreMails ( mails ) ; afficheMails ( mails ) ; do saisit e t r e t o u r n e l e numero de le place

206

{ p r i n t f ( C h o i s i s s e z un m ail en s a i s i s s a n t son 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 pas ! \ n ) ; } while ( i <= 0 && i > n b M a i l s ) ; return i 1 ; } / / / 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 [ S I Z E _ M A I L ] ; 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 : \ n ) ; i = choisitMail ( mails ) ; saisitMail ( m ) ; changeMail ( mails , m , i ) ; } / / / 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 [ S I Z E _ M A I L ] ; p r i n t f ( Ajout d un c o n t a c t : \ n ) ; saisitMail ( m ) ; ajouteMail ( mails , 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 : \ n ) ; i = choisitMail ( mails ) ; su ppr ime Ma il ( mails , i ) ; } / / / 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 ( mails , 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 e x e c u t e M e n u ( char m a i l s ) { int option ; do { 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

207

option = choisitOptionMenu ( ) ; switch ( o p t i o n ) { case A F F I C H E R _ O P T I O N : afficheMails ( mails ) ; break ; case A J O U T E R _ O P T I O N : ajouterOption ( mails ) ; break ; case M O D I F I E R _ O P T I O N : modifierOption ( mails ) ; break ; case S U P P R I M E R _ O P T I O N : supprimerOption ( mails ) ; break ; case Q U I T T E R _ O P T I O N : quitterOption ( mails ) ; break ; default : break ; } } while ( o p t i o n != Q U I T T E R _ O P T I O N ) ; } / / int 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 ( mails , F_NAME ) ; executeMenu ( mails ) ; detruitMails ( mails ) ; return 0 ; }

A.5.6

makele

all : eMails eMails . tgz util . o : util . c util . h g c c W a l l c u t i l . c tableau . o : tableau . c tableau . h util . h g c c W a l l c t a b l e a u . c eMails . o : eMails . c tableau . h util . h g c c W a l l c e M a i l s . c eMails : util . o tableau . o eMails . o g c c o e M a i l s W a l l u t i l . o t a b l e a u . o e M a i l s . o eMails . tgz : util . h util . c tableau . h tableau . c eMails . c makefile tar cvfz eMails . tgz util . h util . c tableau . h tableau . c eMails . c makefile

208