Vous êtes sur la page 1sur 343

LA PROGRAMMATION POUR...

les lves ingnieurs


. . . ou les collgiens
dbutants
. . . ou conrms
Cours de lcole des Ponts ParisTech - 2012/2013
Renaud Keriven et Pascal Monasse
IMAGINE - cole des Ponts ParisTech
{keriven,monasse}@imagine.enpc.fr
Version lectronique et programmes :
http://imagine.enpc.fr/~monasse/Info/
"Ne traitez pas vos ordinateurs comme des tres vivants...
Ils naiment pas a !"
"Cet ordinateur ne fait pas du tout ce que je veux !"
"Exact... Il fait ce que tu lui demandes de faire !"
TABLE DES MATIRES TABLE DES MATIRES
Table des matires
1 Prambule 9
1.1 Pourquoi savoir programmer ? . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2 Comment apprendre ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.2.1 Choix du langage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.2.2 Choix de lenvironnement . . . . . . . . . . . . . . . . . . . . . . . 13
1.2.3 Principes et conseils . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2 Bonjour, Monde ! 15
2.1 Lordinateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.1.1 Le micro-processeur . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.1.2 La mmoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.1.3 Autres Composants . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2 Systme dexploitation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3 La Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.4 Lenvironnement de programmation . . . . . . . . . . . . . . . . . . . . . 24
2.4.1 Noms de chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.2 Debuggeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.3 TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3 Premiers programmes 27
3.1 Tout dans le main()! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1.1 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1.2 Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.1.3 Boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1.4 Rcrations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.2.1 Retour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.2.2 Paramtres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.2.3 Passage par rfrence . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.2.4 Porte, Dclaration, Dnition . . . . . . . . . . . . . . . . . . . . 44
3.2.5 Variables locales et globales . . . . . . . . . . . . . . . . . . . . . . 45
3.2.6 Surcharge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.3 TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.4 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4 Les tableaux 51
4.1 Premiers tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.2 Initialisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
4.3 Spcicits des tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
TABLE DES MATIRES TABLE DES MATIRES
4.3.1 Tableaux et fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . 54
4.3.2 Affectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
4.4 Rcrations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
4.4.1 Multi-balles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
4.4.2 Avec des chocs ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.4.3 Mlanger les lettres . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4.5 TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.6 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
5 Les structures 67
5.1 Rvisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5.1.1 Erreurs classiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5.1.2 Erreurs originales . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5.1.3 Conseils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
5.2 Les structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
5.2.1 Dnition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
5.2.2 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
5.3 Rcration : TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
5.4 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
6 Plusieurs chiers ! 75
6.1 Fichiers spars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
6.1.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
6.1.2 Avantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
6.1.3 Utilisation dans un autre projet . . . . . . . . . . . . . . . . . . . . 78
6.1.4 Fichiers den-ttes . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
6.1.5 A ne pas faire... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
6.1.6 Implmentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
6.1.7 Inclusions mutuelles . . . . . . . . . . . . . . . . . . . . . . . . . . 82
6.2 Oprateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
6.3 Rcration : TP suite et n . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
6.4 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
7 La mmoire 87
7.1 Lappel dune fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
7.1.1 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
7.1.2 Pile des appels et dbuggeur . . . . . . . . . . . . . . . . . . . . . 89
7.2 Variables Locales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
7.2.1 Paramtres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
7.2.2 La pile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
7.3 Fonctions rcursives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
7.3.1 Pourquoi a marche ? . . . . . . . . . . . . . . . . . . . . . . . . . . 93
7.3.2 Efcacit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
7.4 Le tas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
7.4.1 Limites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
7.4.2 Tableaux de taille variable . . . . . . . . . . . . . . . . . . . . . . . 95
7.4.3 Essai dexplication . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
7.5 Loptimiseur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
7.6 Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
2
TABLE DES MATIRES TABLE DES MATIRES
7.7 TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
7.8 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
7.9 Examens sur machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
8 Allocation dynamique 103
8.1 Tableaux bidimensionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
8.1.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
8.1.2 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
8.1.3 Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
8.2 Allocation dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
8.2.1 Pourquoi a marche ? . . . . . . . . . . . . . . . . . . . . . . . . . . 106
8.2.2 Erreurs classiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
8.2.3 Consquences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
8.3 Structures et allocation dynamique . . . . . . . . . . . . . . . . . . . . . . 109
8.4 Boucles et continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
8.5 TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
8.6 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
9 Premiers objets 117
9.1 Philosophie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
9.2 Exemple simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
9.3 Visibilit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
9.4 Exemple des matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
9.5 Cas des oprateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
9.6 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
9.7 Protection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
9.7.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
9.7.2 Structures vs Classes . . . . . . . . . . . . . . . . . . . . . . . . . . 127
9.7.3 Accesseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
9.8 TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
9.9 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
10 Constructeurs et Destructeurs 133
10.1 Le problme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
10.2 La solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
10.3 Cas gnral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
10.3.1 Constructeur vide . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
10.3.2 Plusieurs constructeurs . . . . . . . . . . . . . . . . . . . . . . . . 136
10.3.3 Tableaux dobjets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
10.4 Objets temporaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
10.5 TP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
10.6 Rfrences Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
10.6.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
10.6.2 Mthodes constantes . . . . . . . . . . . . . . . . . . . . . . . . . . 140
10.7 Destructeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
10.8 Destructeurs et tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
10.9 Constructeur de copie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
10.10Affectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
10.11Objets avec allocation dynamique . . . . . . . . . . . . . . . . . . . . . . . 146
3
TABLE DES MATIRES TABLE DES MATIRES
10.11.1 Construction et destruction . . . . . . . . . . . . . . . . . . . . . . 146
10.11.2 Problmes ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
10.11.3 Solution! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
10.12Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
10.13Devoir crit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
11 En vrac... 155
11.1 Chanes de caratres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
11.2 Fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
11.2.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
11.2.2 Chanes et chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
11.2.3 Objets et chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
11.3 Valeurs par dfaut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
11.3.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
11.3.2 Utilit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
11.3.3 Erreurs frquentes . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
11.4 Accesseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
11.4.1 Rfrence comme type de retour . . . . . . . . . . . . . . . . . . . 161
11.4.2 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
11.4.3 operator() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
11.4.4 Surcharge et mthode constante . . . . . . . . . . . . . . . . . . . 162
11.4.5 "inline" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
11.5 Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
11.6 Types numrs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
11.7 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
12 En vrac (suite) ... 171
12.1 Oprateur binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
12.2 Valeur conditionnelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
12.3 Boucles et break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
12.4 Variables statiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
12.5 const et tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
12.6 template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
12.6.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
12.6.2 template et chiers . . . . . . . . . . . . . . . . . . . . . . . . . . 177
12.6.3 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
12.6.4 STL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
12.7 Fiche de rfrence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
12.8 Devoir nal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
13 Structure de donnes 189
13.1 Rappels sur les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
13.2 La complexit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
13.2.1 Mais quest-ce donc que la complexit ? . . . . . . . . . . . . . . . 190
13.2.2 Comment la mesure-t-on? . . . . . . . . . . . . . . . . . . . . . . . 191
13.2.3 La notation O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
13.2.4 P et NP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
13.2.5 Pourquoi est-ce important ? . . . . . . . . . . . . . . . . . . . . . . 192
13.3 Le vecteur : un tableau encapsul dans une classe . . . . . . . . . . . . . 192
4
TABLE DES MATIRES TABLE DES MATIRES
13.3.1 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
13.3.2 Complexit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
13.3.3 Gestion mmoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
13.4 La pile, Last In First Out (LIFO) . . . . . . . . . . . . . . . . . . . . . . . . 193
13.5 La le, First In First Out (FIFO) . . . . . . . . . . . . . . . . . . . . . . . . 194
13.6 La liste chane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
13.7 Rcapitulatif des complexits . . . . . . . . . . . . . . . . . . . . . . . . . 197
13.8 Les itrateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
13.9 Autres structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
14 Algorithmes de tri 199
14.1 Complexit minimale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
14.2 Algorithmes quadratiques . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
14.3 QuickSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
14.4 File de priorit et HeapSort . . . . . . . . . . . . . . . . . . . . . . . . . . 202
14.4.1 Insertion dans la le de priorit (push) . . . . . . . . . . . . . . . 202
14.4.2 Retrait de la le de priorit (pop) . . . . . . . . . . . . . . . . . . . 203
14.4.3 Stockage de la le de priorit . . . . . . . . . . . . . . . . . . . . . 203
14.4.4 HeapSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
14.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
A Travaux Pratiques 205
A.1 Lenvironnement de programmation . . . . . . . . . . . . . . . . . . . . . 205
A.1.1 Bonjour, Monde ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
A.1.2 Premires erreurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
A.1.3 Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
A.1.4 Sil reste du temps . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
A.1.5 Installer Imagine++ chez soi . . . . . . . . . . . . . . . . . . . . . . 210
A.2 Variables, boucles, conditions, fonctions . . . . . . . . . . . . . . . . . . . 211
A.2.1 Premier programme avec fonctions . . . . . . . . . . . . . . . . . 211
A.2.2 Premier programme graphique avec Imagine++ . . . . . . . . . . 211
A.2.3 Jeu de Tennis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
A.3 Tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
A.3.1 Mastermind Texte . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
A.3.2 Mastermind Graphique . . . . . . . . . . . . . . . . . . . . . . . . 217
A.4 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
A.4.1 Etapes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
A.4.2 Aide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
A.4.3 Thorie physique . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
A.5 Fichiers spars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
A.5.1 Fonctions outils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
A.5.2 Vecteurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
A.5.3 Balle part . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
A.5.4 Retour la physique . . . . . . . . . . . . . . . . . . . . . . . . . . 225
A.6 Les tris . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
A.6.1 Mlanger un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . 227
A.6.2 Tris quadratiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
A.6.3 Quicksort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
A.6.4 Gros tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
5
TABLE DES MATIRES TABLE DES MATIRES
A.7 Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
A.7.1 Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
A.7.2 Tableaux statiques . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
A.7.3 Tableaux dynamiques . . . . . . . . . . . . . . . . . . . . . . . . . 232
A.7.4 Charger un chier . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
A.7.5 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
A.7.6 Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
A.7.7 Suite et n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
A.8 Premiers objets et dessins de fractales . . . . . . . . . . . . . . . . . . . . 234
A.8.1 Le triangle de Sierpinski . . . . . . . . . . . . . . . . . . . . . . . . 234
A.8.2 Une classe plutt quune structure . . . . . . . . . . . . . . . . . . 235
A.8.3 Changer dimplmentation . . . . . . . . . . . . . . . . . . . . . . 235
A.8.4 Le ocon de neige . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
A.9 Tron . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
A.9.1 Serpent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
A.9.2 Tron . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
A.9.3 Graphismes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
B Examens 241
B.1 Examen sur machine 2011 : nonc . . . . . . . . . . . . . . . . . . . . . . 241
B.1.1 Automate cellulaire . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
B.1.2 Travail demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
B.2 Examen sur machine 2010 : nonc . . . . . . . . . . . . . . . . . . . . . . 244
B.2.1 Visualisation 3D par z-buffer . . . . . . . . . . . . . . . . . . . . . 244
B.2.2 Travail demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
B.2.3 Annexe : les formules . . . . . . . . . . . . . . . . . . . . . . . . . 247
B.3 Examen sur machine 2009 : nonc . . . . . . . . . . . . . . . . . . . . . . 249
B.3.1 Spirale dUlam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
B.3.2 Travail demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
B.4 Examen sur machine 2008 : nonc . . . . . . . . . . . . . . . . . . . . . . 251
B.4.1 Ensemble de Mandelbrot . . . . . . . . . . . . . . . . . . . . . . . 251
B.4.2 Travail demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
B.5 Examen sur machine 2007 : nonc . . . . . . . . . . . . . . . . . . . . . . 253
B.5.1 Chemins entre deux points . . . . . . . . . . . . . . . . . . . . . . 253
B.5.2 Travail demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
B.6 Examen sur machine 2006 : nonc . . . . . . . . . . . . . . . . . . . . . . 254
B.6.1 Voyageur de commerce par recuit simul . . . . . . . . . . . . . . 254
B.6.2 Travail demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
B.7 Examen sur machine 2005 : nonc . . . . . . . . . . . . . . . . . . . . . . 256
B.7.1 Construction du Modle 3D . . . . . . . . . . . . . . . . . . . . . . 256
B.7.2 Projection : du 3D au 2D . . . . . . . . . . . . . . . . . . . . . . . . 256
B.7.3 Afchage lcran . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
B.7.4 Animation du ttradre . . . . . . . . . . . . . . . . . . . . . . . . 257
B.7.5 Un modle plus labor . . . . . . . . . . . . . . . . . . . . . . . . 258
B.8 Examen sur machine 2004 : nonc . . . . . . . . . . . . . . . . . . . . . . 259
B.8.1 Calcul de lexponentielle dun nombre complexe . . . . . . . . . . 259
B.8.2 Compression RLE . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
B.9 Examen sur machine 2003 : nonc . . . . . . . . . . . . . . . . . . . . . . 263
B.9.1 Crible dratosthne . . . . . . . . . . . . . . . . . . . . . . . . . . 263
6
TABLE DES MATIRES TABLE DES MATIRES
B.9.2 Calcul de par la mthode de Monte Carlo . . . . . . . . . . . . . 263
B.9.3 Serpent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
B.10 Devoir maison 2007 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . . 267
B.11 Devoir maison 2006 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . . 269
B.11.1 Enonc Tours de Hanoi . . . . . . . . . . . . . . . . . . . . . . . 269
B.12 Devoir maison 2004 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . . 272
B.12.1 Tableau dexcution . . . . . . . . . . . . . . . . . . . . . . . . . . 272
B.12.2 Constructeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
B.12.3 Le compte est bon . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
B.13 Devoir maison 2003 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . . 278
B.13.1 Tableau dexcution . . . . . . . . . . . . . . . . . . . . . . . . . . 278
B.13.2 Grands entiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
B.13.3 Constructeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
B.14 Devoir surveill 2011 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 282
B.14.1 Liste avec sauts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
B.14.2 Travail demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
B.15 Devoir surveill 2010 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 286
B.15.1 Programmation : machine registres . . . . . . . . . . . . . . . . . 286
B.15.2 Algorithmique : ensemble sans doublon . . . . . . . . . . . . . . . 288
B.16 Devoir surveill 2009 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 290
B.16.1 Quafche ce programme ? . . . . . . . . . . . . . . . . . . . . . . 290
B.16.2 Programmation : enrichir la classe polynme . . . . . . . . . . . . 293
B.16.3 Algorithmie : problme de slection . . . . . . . . . . . . . . . . . 293
B.17 Devoir surveill 2008 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 294
B.17.1 Erreurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
B.17.2 Problme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
B.18 Devoir surveill 2007 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 298
B.18.1 Groupes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
B.18.2 Anniversaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
B.19 Devoir surveill 2006 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 301
B.19.1 Erreurs corriger . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
B.19.2 Quafche ce programme ? . . . . . . . . . . . . . . . . . . . . . . 302
B.19.3 Tableau dexcution . . . . . . . . . . . . . . . . . . . . . . . . . . 304
B.19.4 Huit dames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
B.20 Devoir surveill 2005 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 308
B.20.1 Erreurs corriger . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
B.20.2 Quafche ce programme ? . . . . . . . . . . . . . . . . . . . . . . 308
B.20.3 Tableau dexcution . . . . . . . . . . . . . . . . . . . . . . . . . . 310
B.20.4 Rsolveur de Sudoku . . . . . . . . . . . . . . . . . . . . . . . . . . 311
B.21 Devoir surveill 2004 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 314
B.21.1 Erreurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
B.21.2 Quafche ce programme ? . . . . . . . . . . . . . . . . . . . . . . 315
B.21.3 Chemins dans un graphe . . . . . . . . . . . . . . . . . . . . . . . 318
B.21.4 Tours de Hano . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
B.21.5 Table de hachage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
B.22 Devoir surveill 2003 : nonc . . . . . . . . . . . . . . . . . . . . . . . . . 324
B.22.1 Tableau dexcution . . . . . . . . . . . . . . . . . . . . . . . . . . 324
B.22.2 Erreurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
B.22.3 Quafche ce programme ? . . . . . . . . . . . . . . . . . . . . . . 326
7
TABLE DES MATIRES TABLE DES MATIRES
B.22.4 Le jeu du Pendu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
B.22.5 Programme mystre . . . . . . . . . . . . . . . . . . . . . . . . . . 329
C Imagine++ 331
C.1 Common . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
C.2 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
C.3 Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
C.4 LinAlg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
D Fiche de rfrence nale 335
8
1. Prambule
Chapitre 1
Prambule
Note : Ce premier chapitre maladroit correspond ltat desprit dans lequel ce
cours a dbut en 2003, dans une priode o lInformatique avait mauvaise presse
lcole des Ponts. Nous le maintenons ici en tant que tmoin de ce quil faillait faire
alors pour amener les lves ne pas ngliger lInformatique. Si lon ignore la navet
de cette premire rdaction (et le fait que Star Wars nest plus autant la mode !),
lanalyse et les conseils qui suivent restent dactualit.

(Ce premier chapitre tente surtout de motiver les lves ingnieurs dans leur apprentissage
de la programmation. Les enfants qui se trouveraient ici pour apprendre programmer sont
srement dj motivs et peuvent sauter au chapitre suivant ! Protons-en pour tenir des propos
qui ne les concernent pas...)

Le Matre Programmeur
1
: "Rassure-toi ! Les ordinateurs sont stupides ! Program-
mer est donc facile."
LApprenti Programmeur
2
: "Matre, les ordinateurs ne sont certes que des ma-
chines et les dominer devrait tre ma porte. Et pourtant... Leur manque din-
telligence fait justement quil mest pnible den faire ce que je veux. Programmer
exige de la prcision et la moindre erreur est sanctionne par un message incom-
prhensible, un bug
3
ou mme un crash de la machine. Pourquoi doit-on tre
aussi... prcis ?" Programmer rend maniaque ! Dailleurs, les informaticiens sont tous
maniaques. Et je nai pas envie de devenir comme a...
1. Permettez ce terme ouvertement Lucasien. Il semble plus appropri que lhabituel Gourou souvent
utilis pour dcrire lexpert informaticien. Nous parlons bien ici dun savoir-faire transmettre de Matre
Apprenti et non dune secte...
2. Le jeune Padawan, donc, pour ceux qui connaissent...
3. Je naurai aucun remord dans ce polycopi utiliser les termes habituels des informaticiens... en
essayant videmment de ne pas oublier de les expliquer au passage. Anglicismes souvent incompr-
hensibles, ils constituent en ralit un argot propre au mtier dinformaticien, argot que doit bien vi-
demment accepter et faire sien lApprenti sous peine de ne rien comprendre au discours de ses collgues
dune part, et demployer des adaptations franaises ridicules ou peu usites dautre part. Naviguer sur
la toile, envoyer un courriel ou avoir un bogue commencent peut-tre devenir des expressions com-
prhensibles. Mais demandez-donc votre voisin sil reoit beaucoup de pourriels (terme propos pour
traduire "Spams") !
1. Prambule
M.P. : "La prcision est indispensable pour communiquer avec une machine. Cest
lHomme de sadapter. Tu dois faire un effort. En contre-partie tu deviendras
son matre. Rjouis-toi. Bientt, tu pourras crer ces tres obissants que sont les
programmes."
A.P. : "Bien, Matre..." Quel vieux fou! Pour un peu, il se prendrait pour Dieu. La vrit,
cest quil parle aux machines parce quil ne sait pas parler aux hommes. Il comble avec
ses ordinateurs son manque de contact humain. Linformaticien type... Il ne lui manque
plus que des grosses lunettes et les cheveux gras
4
. "Matre, je ne suis pas sr den avoir
envie. Je ny arriverai pas. Ne le prenez pas mal, mais je crois tre davantage dou
pour les Mathmatiques ! Et puis, quoi savoir programmer me servira-t-il ?"
M.P. : "Les vrais problmes qui se poseront toi, tu ne pourras toujours les r-
soudre par les Mathmatiques. Savoir programmer, tu devras !"
A.P. : "Jessaierai..." Je me demande sil a vraiment raison ! Je suis sr quil doit tre nul
en Maths. Voil la vrit !
...

Oublions l ce dialogue aussi caricatural que maladroit. Il montre pourtant claire-


ment la situation. Rsumons :
Pour celui qui sait, programmer :
est un jeu denfant.
est indispensable.
est une activit cratrice et panouissante.
Pour celui qui apprend, programmer :
est difcile.
ne sert rien.
est une activit ingrate qui favorise le renfermement
5
sur soi-mme.
Dans le cas o llve est ingnieur, nous pouvons complter le tableau :
Pour le professeur, apprendre programmer :
devrait tre simple et rapide pour un lve ingnieur.
est plus utile quapprendre davantage de Mathmatiques.
Pour llve, programmer :
est un travail de "technicien
6
" quil naura jamais faire lui-mme.
nest pas aussi noble que les Mathmatiques, bref, nest pas digne de lui.
En fait, les torts sont partags :
Le professeur :
ne ralise pas que ses lves ont un niveau avanc en maths parce quils en
font depuis plus de dix ans, et quil leur faudra du temps pour apprendre ne
serait-ce que les bases de la programmation. Du temps... et de la pratique, car,
si programmer est effectivement simple en regard de ce que ses lves savent
faire en maths, il ncessite une tournure desprit compltement diffrente et
beaucoup de travail personnel devant la machine.
4. Toute ressemblance avec des personnages rels ou imaginaires, etc.
5. Utiliser un ordinateur pour programmer a tout aussi mauvaise presse que de jouer aux jeux vido.
Programmer est pourtant souvent un travail dquipe.
6. avec tout le sens pjoratif que ce terme peut avoir pour lui.
10
1. Prambule 1.1. Pourquoi savoir programmer ?
oublie quil a le plus souvent appris seul quand il tait plus jeune, en program-
mant des choses simples et ludiques
7
. Il devrait donc faire venir ses lves
la programmation par le ct ludique, et non avec les mmes sempiternels
exemples
8
.
Llve :
ne se rend pas compte que savoir programmer lui sera utile. Il sagit pourtant
dune base qui se retrouve dans tous les langages et mme dans la plupart des
logiciels modernes
9
. Et puis, considr comme "le jeune" donc le moins "al-
lergique" aux ordinateurs, il se verra vraisemblablement coner son premier
poste la ralisation de quelques petits programmes en plus de ses attributions
normales.
sarrange un peu trop facilement dun mpris de bon ton pour la programma-
tion. Il lui est plus ais dapprendre une n-ime branche des mathmatiques
que de faire leffort dacqurir par la pratique une nouvelle tournure desprit.
On laura compris, il est la fois facile et difcile dapprendre programmer. Pour
lingnieur, cela demandera de la motivation et un peu deffort : essentiellement de
mettre ses maths de ct et de retrouver le got des choses basiques. Pour un coll-
gien, motivation et got de leffort seront au rendez-vous. Il lui restera malgr tout
acqurir quelques bases darithmtique et de gomtrie. Comme annonc par le titre
de ce cours, collgien et ingnieur en sont au mme point pour lapprentissage de la
programmation. De plus, et cest un phnomne relativement nouveau, il en est de
mme pour le dbutant et le "geek
10
". Expliquons-nous : le passionn dinformatique
a aujourdhui tellement de choses faire avec son ordinateur quil sera en gnral in-
collable sur les jeux, internet, les logiciels graphiques ou musicaux, linstallation ou
la conguration de son systme, lachat du dernier gadget USB la mode, etc. mais
quen contrepartie il sera mauvais programmeur. Il y a quelques annes, il y avait peu
faire avec son ordinateur sinon programmer. Programmer pour combler le manque
de possibilits de lordinateur. Aujourdhui, faire le tour de toutes les possibilits dun
ordinateur est une occupation plein temps ! Ainsi, le "fana info" passe-t-il sa jour-
ne se tenir au courant des nouveaux logiciels
11
et en oublie quil pourrait lui aussi
en crer. En conclusion, collgiens ou ingnieurs, dbutants ou passionns, tous les
lves sont galit. Cest donc sans complexe que lingnieur pourra apprendre
programmer en mme temps que le ls de la voisine.
1.1 Pourquoi savoir programmer ?
Nous venons partiellement de le dire. Rsumons et compltons :
7. Cest une erreur frquente de croire quil intressera ses lves en leur faisant faire des pro-
grammes centrs sur les mathmatiques ou le calcul scientique. De tels programmes leur seront peut-
tre utiles plus tard, mais ne sont pas forcment motivants. Lalgbre linaire ou lanalyse numrique
sont des domaines passionnants tudier... mais certainement pas programmer. Il faut admettre sans
complexe que programmer un ipper, un master-mind ou un labyrinthe 3D est tout aussi formateur et
plus motivant quinverser une matrice creuse.
8. La liste est longue, mais tellement vraie : quel cours de programmation ne rabche pas les clbres
"factorielle", "suites de Fibonacci", "Quick Sort", etc ?
9. Savoir programmer ne sert pas seulement faire du C++ ou du Java, ni mme du Scilab, du Matlab
ou du Maple : une utilisation avance dExcel ou du Word demande parfois de la programmation!
10. Une rcompense qui me trouve un substitut satisfaisant cette expression consacre.
11. Sans mme dailleurs avoir le temps den creuser convenablement un seul !
11
1.2. Comment apprendre ? 1. Prambule
1. Cest la base. Apprendre un langage prcis nest pas du temps perdu car les
mmes concepts se retrouvent dans la plupart des langages. De plus, les logiciels
courants eux-mmes peuvent se programmer.
2. Il est frquent quun stage ou quune embauche en premier poste comporte un
peu de programmation, mme, et peut-tre surtout, dans les milieux o peu de
gens programment.
3. Savoir programmer, cest mieux connatre le matriel et les logiciels, ce qui est
possible techniquement et ce qui ne lest pas. Mme un poste non technique,
cest important pour prendre les bonnes dcisions.
1.2 Comment apprendre ?
1.2.1 Choix du langage
Il faut dabord choisir un langage de programmation. Un ingnieur pourrait vi-
demment tre tent dapprendre programmer en Maple, Matlab, Scilab ou autre. Il
faut quil comprenne quil sagit l doutils spcialiss pour mathmaticien ou ing-
nieur qui lui seront utiles et qui, certes, se programment, mais pas proprement parler
de langages gnralistes complets. Sans argumenter sur les dfauts respectifs des lan-
gages qui en font partie, il nous semble vident quil ne sagit pas du bon choix pour
lapprentissage de la programmation.
En pratique, le choix actuel se fait souvent entre C++ et Java. Bien que Java aie t
conu, entre autres, dans un soucis de simplication du C++
12
, nous prfrerons C++
pour des raisons pdagogiques :
1. C++ est plus complexe dans son ensemble mais nen connatre que les bases est
dj bien sufsant. Nous ne verrons donc dans ce cours quun sous ensemble du
C++, sufsant en pratique.
2. Plus complet, C++ permet une programmation de haut niveau mais aussi une
programmation simple, adapte au dbutant
13
. C++ permet galement une pro-
grammation proche de la machine, ce qui est important pour le spcialiste mais
aussi pour le dbutant, car seule une bonne comprhension de la machine aboutit
une programmation convenable et efcace
14
.
3. C++ est souvent incontournable dans certains milieux, par exemple en nance.
4. Enn, certains aspects pratiques et pourtant simples de C++ ont disparu dans
Java
15
.
Encore une fois, rptons que le choix du langage nest pas le plus important et que
lessentiel est dapprendre programmer.
12. Nous ne rduisons videmment pas Java un sous ensemble de C++. Il lui est suprieur sur
certains aspects mais il est dexpressivit plus rduite.
13. Java force un cadre de programmation objet, droutant pour le dbutant.
14. Ne pas comprendre ce que la machine doit faire pour excuter un programme, conduit des pro-
grammes inconsidrment gourmands en temps ou mmoire.
15. Les oprateurs par exemple.
12
1. Prambule 1.2. Comment apprendre ?
1.2.2 Choix de lenvironnement
Windows et Linux ont leurs partisans, souvent farouchement opposs, tel point
que certains nadmettent pas quil est possible dtre partisan des deux systmes la
fois. Conscients des avantages et des inconvnients de chacun des deux systmes, nous
nen prnons aucun en particulier
16
. Ceci dit, pour des raisons pdagogiques, nous
pensons quun environnement de programmation intgr, cest dire un logiciel unique
permettant de programmer, est prfrable lutilisation de multiples logiciels (diteur,
compilateur, debuggeur, etc.). Cest vrai pour le programmeur conrm, qui trouve
en gnral dans cet environnement des outils puissants, mais cest encore plus crucial
pour le dbutant. Un environnement de programmation, cest :
Toutes les tapes de la programmation regroupes en un seul outil de faon co-
hrente.
Editer ses chiers, les transformer en programme, passer en revue ses erreurs,
dtecter les bugs, parcourir la documentation, etc. tout cela avec un seul outil
ergonomique.
Sans arrire pense de principe, nous avons opt pour lenvironnement de Microsoft,
Visual Studio, la fois simple et puissant. Il est le plus utilis des produits commer-
ciaux. Il en existe quelques quivalents gratuits sous linux, mais pas encore sufsam-
ment aboutis pour nous faire hsiter. Cest donc le choix de Visual Studio et ce choix
seul qui est la raison de lutilisation de Windows au dtriment de linux... Mieux en-
core, il existe maintenant une version de Visual gratuite : Visual Express. Comme pour
le choix du langage, le choix de lenvironnement nest pas limitant et en connatre un
permet de sadapter facilement nimporte quel autre.
1.2.3 Principes et conseils
Au niveau auquel nous prtendons lenseigner, la programmation ne requiert ni
grande thorie, ni connaissances encyclopdiques. Les concepts utiliss sont rudimen-
taires mais cest leur mise en oeuvre qui est dlicate. Sil ny avait quun seul conseil
donner, ce serait la rgle des trois "P" :
1. Programmer
2. Programmer
3. Programmer
La pratique est effectivement essentielle. Cest ce qui fait quun enfant a plus de facili-
ts, puisquil a plus de temps. Ajoutons quand mme quelques conseils de base :
1. Samuser. Cest une vidence en matire de pdagogie. Mais cest tellement facile
dans le cas de la programmation, quil serait dommage de passer ct ! Au pire,
si programmer nest pas toujours une partie de plaisir pour tout le monde, il vaut
mieux que le programme obtenu dans la douleur soit intressant pour celui qui
la fait !
2. Bricoler. Ce que nous voulons dire par l, cest quil ne faut pas hsiter tton-
ner, tester, fouiller, faire, dfaire, casser, etc. Lordinateur est un outil exprimen-
tal. Mais sa programmation est elle aussi une activit exprimentale la base.
Mme si le programmeur aguerri trouvera la bonne solution du premier jet, il
16. Lidal est en fait davoir les deux "sous la main".
13
1.2. Comment apprendre ? 1. Prambule
est important pour le dbutant dapprendre connatre le langage et loutil de
programmation en jouant avec eux.
3. Faire volontairement des erreurs. Provoquer les erreurs pendant la phase dap-
prentissage pour mieux les connatre est le meilleur moyen de comprendre beau-
coup de choses et aussi de reprer ces erreurs quand elles ne seront plus volon-
taires.
4. Rester (le) matre
17
(de la machine et de son programme). Que programmer soit
exprimental ne signie pas pour autant quil faille faire nimporte quoi jusqu
ce que a marche plus ou moins. Il faut avancer progressivement, mthodique-
ment, en testant au fur et mesure, sans laisser passer la moindre erreur ou im-
prcision.
5. Debugger. Souvent, la connaissance du debuggeur (loutil pour rechercher les
bugs) est nglige et son apprentissage est repouss au stade avanc. Il sagit
pourtant dun outil essentiel pour comprendre ce qui se passe dans un programme,
mme dpourvu de bugs. Il faut donc le considrer comme essentiel et faisant
partie intgrante de la conception dun programme. L encore, un bon environ-
nement de programmation facilite la tche.

Gardons bien prsents ces quelques principes car il est maintenant temps de...
passer notre premier programme !
17. Le vocabulaire nest pas choisi au hasard : un programme est une suite dordres, de commandes ou
dinstructions. On voit bien qui est le chef !
14
2. Bonjour, Monde !
Chapitre 2
Bonjour, Monde !
(Si certains collgiens sont arrivs ici, ils sont bien courageux ! Lorsque je disais tout
lheure quils pouvaient facilement apprendre programmer, je le pensais vraiment. Par contre,
cest avec un peu doptimisme que jai prtendu quils pouvaient le faire en lisant un polycopi
destin des ingnieurs. Enn, je suis pris mon propre pige ! Alors, tout hasard, je vais
tenter dexpliquer au passage les mathmatiques qui pourraient leur poser problme.)

Si lon en croit de nombreux manuels de programmation, un premier programme


doit toujours ressembler a :
# i ncl ude <i ostream>
usi ng namespace st d ;
i nt main ( )
{
cout << " Hello , World ! " << endl ;
ret urn 0;
}
Eh bien, allons-y ! Dcortiquons-le ! Dans ce programme, qui afche lcran
1
le texte
"Hello, World!", les lignes 1 et 2 sont des instructions magiques
2
qui servent pou-
voir utiliser dans la suite cout et endl. La ligne 4 int main() dnit une fonction appele
main(), qui renvoie
3
un nombre entier. Cette fonction est spciale car cest la fonction
principale dun programme C++, celle qui est appele automatiquement
4
quand le
1. Cette expression, vestige de lpoque o les ordinateurs taient dots dun cran capable de naf-
cher que des caractres et non des graphiques (courbes, dessins, etc.), signie aujourdhui que lafchage
se fera dans une fentre simulant lcran dun ordinateur de cette poque. Cette fentre est appele ter-
minal, console, fentre de commande, fentre DOS, xterm, etc. suivant les cas. Souvenons nous avec
un minimum de respect que ctait dj un progrs par rapport la gnration prcdente, dpourvue
dcran et qui utilisait une imprimante pour communiquer avec lhomme... ce qui tait relativement peu
interactif !
2. Entendons par l des instructions que nous nexpliquons pas pour linstant. Il ny a (mal ?)-
heureusement rien de magique dans la programmation.
3. On dit aussi retourne. A qui renvoie-t-elle cet entier ? Mais celui qui la appele, voyons !
4. Voil, maintenant vous savez qui appelle main(). Dans un programme, les fonctions sappellent
les unes les autres. Mais main() nest appele par personne puisque cest la premire de toutes. (Du
moins en apparence car en ralit le programme a plein de choses faire avant darriver dans main()
et il commence par plusieurs autres fonctions que le programmeur na pas connatre et qui nissent
par appeler main(). Dailleurs, si personne ne lappelait, qui main() retournerait-elle un entier ?)
2. Bonjour, Monde !
programme est lanc
5
. Dlimite par les accolades ({ ligne 5 et } ligne 8), la fonction
main() se termine ligne 7 par return 0; qui lui ordonne de retourner lentier 0. Notons
au passage que toutes les instructions se terminent par un point-virgule ;. Enn, la
ligne 6, seule ligne "intressante", cout << "Hello, World!"<< endl; afche, grce la
variable
6
cout qui correspond la sortie console
7
, des donnes spares par des <<. La
premire de ces donnes est la chane de caractres
8
"Hello, World!". La deuxime, endl,
est un retour la ligne
9
.
Ouf ! Que de termes en italique. Que de concepts essayer dexpliquer ! Et pour
un programme aussi simple ! Mais l nest pas le problme. Commencer par expliquer
ce programme, cest tre encore dans le vide, dans le magique, dans labstrait, dans
lapproximatif. Nous ne sommes pas rellement matres de la machine. Taper des ins-
tructions et voir ce qui se passe sans comprendre ce qui se passe nest pas raisonnable.
En fait, cest mme trs dommageable pour la suite. On ne donne pas efcacement
dordre quelquun sans comprendre comment il fonctionne ni ce que les ordres don-
ns entranent comme travail. De mme,
on ne programme pas convenablement sans comprendre ce que lordinateur
aura exactement besoin de faire pour excuter ce programme.
Cest toute cette approche qui est nglige quand on commence comme nous venons
de le faire. Donc...
Stop! Stop! Stop! Faux dpart ! On reprend le :
5. Je savais bien que vouloir expliquer tous les barbarismes propres aux informaticiens minterrom-
prait souvent. Mais bon. Donc, un programme dmarre ou est lanc. Aprs quoi, il sexcute ou tourne.
Enn, il se termine ou meurt.
6. Les donnes sont ranges ou stockes dans des variables qui mmorisent des valeurs. Ces variables ne
sont dailleurs pas toujours variables au sens usuel, puisque certaines sont constantes !
7. Quest-ce que je disais ! On afche dans une fentre console !
8. En clair, un texte.
9. Ce qui signie que la suite de lafchage sur la console se fera sur une nouvelle ligne.
16
2. Bonjour, Monde! 2.1. Lordinateur
Chapitre 2 (deuxime essai)
Comment a marche ?
Le problme avec le programme prcdent est quil est trs loin de ce quun ordi-
nateur sait faire naturellement. En fait, un ordinateur ne sait pas faire de C++. Il ne
sait que calculer
10
, transformer des nombres en autres nombres. Bien que peu compr-
hensible pour le dbutant, un programme en C++ se veut le plus proche possible de
lHomme, tout en restant videmment accessible
11
la machine. Le C++ est un lan-
gage trs complet, peut-tre mme trop. Il peut tre relativement proche de la machine
si ncessaire et au contraire de "haut niveau" quand il le faut. La largeur de son spectre
est une des raisons de son succs. Cest aussi ce qui fait que son apprentissage complet
demande un long travail et nous ne verrons ici quun partie restreinte du C++!
2.1 Lordinateur
Pour savoir ce quun ordinateur sait vraiment faire, il faut commencer par son or-
gane principal : le micro-processeur.
2.1.1 Le micro-processeur
Quel quil soit
12
et quelle que soit sa vitesse
13
, un micro-processeur ne sait faire que
des choses relativement basiques. Sans tre exhaustif, retenons juste ceci :
Il sait excuter une suite ordonne dinstructions.
Il possde un petit nombre de mmoires internes appeles registres.
Il dialogue avec le monde extrieur via de la mmoire
14
en plus grande quantit
que ses registres.
Cette mmoire contient, sous forme de nombres, les instructions excuter et les
donnes sur lesquelles travailler.
Les instructions sont typiquement :
Lire ou crire un nombre dans un registre ou en mmoire.
Effectuer des calculs simples : addition, multiplication, etc.
Tester ou comparer des valeurs et dcider ventuellement de sauter une autre
partie de la suite dinstructions.
Voici par exemple ce que doit faire le micro-processeur quand on lui demande
dexcuter "c=3a+2b;" en C++, o a,b,c sont trois variables entires :
10. Un computer, quoi !
11. Cette notion est videmment dpendante de notre savoir faire informatique linstant prsent.
Les premiers langages taient plus loigns de lHomme car plus proches de la machine qui tait alors
rudimentaire, et lon peut envisager que les futurs langages seront plus proches de lHomme.
12. Pentium ou autre
13. Plus exactement la frquence laquelle il excute ses instructions. Aujourdhui lhorloge va envi-
ron 3GHz. (Mais attention : une instruction demande plus dun cycle dhorloge !)
14. Aujourdhui, typiquement 1Go (giga-octets), soit 102410241024 mmoires de 8 bits (mmoires
pouvant stocker des nombres entre 0 et 255).
17
2.1. Lordinateur 2. Bonjour, Monde !
00415A61 mov eax,dword ptr [a] // mettre dans le registre eax
// le contenu de ladresse o
// est mmorise la variable a
00415A64 imul eax,eax,3 // effectuer eax=eax
*
3
00415A67 mov ecx,dword ptr [b] // idem mais b dans ecx
00415A6A lea edx,[eax+ecx
*
2] // effectuer edx=eax+ecx
*
2
00415A6D mov dword ptr [c],edx // mettre le contenu du registre edx
// ladresse o est mmorise la
// variable c
Sous lenvironnement Visual Studio que nous utiliserons, ce programme est dsi-
gn comme du Code Machine. Le nombre au dbut de chaque ligne est une adresse.
Nous allons en reparler. A part lui, le reste est relativement lisible pour lHomme (at-
tention, cest moi qui ai ajout les remarques sur le cot droit !). Ceci parce quil sagit
dun programme en langage assembleur, cest--dire un langage o chaque instruc-
tion est vraiment une instruction du micro-processeur, mais o le nom de ces instruc-
tions ainsi que leurs arguments sont explicites. En ralit, le micro-processeur ne com-
prend pas lassembleur. Comprendre "mov eax,dword ptr [a]" lui demanderait
non seulement de dcoder cette suite de symboles, mais aussi de savoir o est range
la variable a. Le vrai langage du micro-processeur est le langage machine, dans lequel
les instructions sont des nombres. Voici ce que a donne pour notre "c=3a+2b;" :
00415A61 8B 45 F8
00415A64 6B C0 03
00415A67 8B 4D EC
00415A6A 8D 14 48
00415A6D 89 55 E0
A part encore une fois la colonne de gauche, chaque suite de nombres
15
correspond
videmment une instruction prcise. Cest tout de suite moins comprhensible
16
!
Notons que chaque micro-processeur son jeu dinstructions ce qui veut dire que la tra-
duction de c=3a+2b; en la suite de nombres 8B45F86BC0038B4DEC8D14488955E0
est propre au Pentium que nous avons utilis pour notre exemple :
Une fois traduit en langage machine pour un micro-processeur donn, un
programme C++ na de sens que pour ce micro-processeur.
Remarquons aussi que les concepteurs du Pentium ont dcid de crer une instruction
spcique pour calculer edx=eax+ecx2 en une seule fois car elle est trs frquente. Si
on avait demand c=3a+3b;, notre programme serait devenu :
00415A61 8B 45 F8 mov eax,dword ptr [a]
00415A64 6B C0 03 imul eax,eax,3
00415A67 8B 4D EC mov ecx,dword ptr [b]
00415A6A 6B C9 03 imul ecx,ecx,3
00415A6D 03 C1 add eax,ecx
00415A6F 89 45 E0 mov dword ptr [c],eax
car "lea edx,[eax+ecx
*
3]" nexiste pas !
Mais revenons nos nombres...
15. Nombres un peu bizarres, certes, puisquil contiennent des lettres. Patience, jeune Padawan! Nous
en reparlons aussi tout de suite !
16. Et pourtant, les informaticiens programmaient comme cela il ny a pas si longtemps. Ctait dj
trs bien par rapport lpoque antrieure o il fallait programmer en base 2... et beaucoup moins bien
que lorsquon a pu enn programmer en assembleur !
18
2. Bonjour, Monde ! 2.1. Lordinateur
2.1.2 La mmoire
La mmoire interne du micro-processeur est gre comme des registres, un peu
comme les variables du C++, mais en nombre prdni. Pour stocker
17
la suite dins-
tructions lui fournir, on utilise de la mmoire en quantit bien plus importante, d-
signe en gnral par la mmoire de lordinateur. Il sagit des fameuses "barrettes"
18
de
mmoire que lon achte pour augmenter la capacit de sa machine et dont les prix
uctuent assez fortement par rapport au reste des composants dun ordinateur. Cette
mmoire est dcoupe en octets. Un octet
19
correspond un nombre binaire de 8 bits
20
,
soit 2
8
= 256 valeurs possibles. Pour se reprer dans la mmoire, il nest pas ques-
tion de donner des noms chaque octet. On numrote simplement les octets et on
obtient ainsi des adresses mmoire. Les nombres 00415A61, etc. vus plus haut sont des
adresses ! Au dbut, ces nombres taient crits en binaire, ce qui tait exactement ce
que comprenait le micro-processeur. Cest devenu draisonnable quand la taille de
la mmoire a dpass les quelques centaines doctets. Le contenu dun octet de m-
moire tant lui aussi donn sous la forme dun nombre, on a opt pour un systme
adapt au fait que ces nombres sont sur 8 bits : plutt que dcrire les nombre en bi-
naire, le choix de la base 16 permettait de reprsenter le contenu dun octet sur deux
chiffres (0,1,...,9,A,B,C,D,E,F). Le systme hexadcimal
21
tait adopt... Les conversions
de binaire hexadcimal sont trs simples, chaque chiffre hexadcimal valant pour un
paquet de 4 bits, alors quentre binaire et dcimal, cest moins immdiat. Il est aujour-
dhui encore utilis quand on dsigne le contenu dun octet ou une adresse
22
. Ainsi,
notre fameux c=3a+2b; devient en mmoire :
adresse mmoire contenu reprsente
00415A61 8B
00415A62 45 mov eax,dword ptr [a]
00415A63 F8
00415A64 6B
00415A65 C0 imul eax,eax,3
... ...
17. Encore un anglicisme...
18. Aujourdhui, typiquement une ou plusieurs barrettes pour un total de 1 ou 2Go, on la dj dit.
Souvenons nous avec une larme loeil des premiers PC qui avaient 640Ko (kilo-octet soit 1024 octets),
voire pour les plus ags dentre nous des premiers ordinateurs personnels avec 4Ko, ou mme des
premires cartes programmables avec 256 octets !
19. byte en anglais. Attention donc ne pas confondre byte et bit, surtout dans des abrviations comme
512kb/s donnes pour le dbit dun accs internet... b=bit, B=byte=8 bits
20. Le coin des collgiens : en binaire, ou base 2, on compte avec deux chiffres au lieu de dix dha-
bitude (cest dire en dcimal ou base 10). Cela donne : 0, 1, 10, 11, 100, 101, 110, 111, ... Ainsi, 111 en
binaire vaut 7 . Chaque chiffre sappelle un bit. On voit facilement quavec un chiffre on compte de 0
1 soit deux nombres possibles ; avec deux chiffres, de 0 3, soit 4 = 2 2 nombres ; avec 3 chiffres, de
0 7, soit 8 = 2 2 2 nombres. Bref avec n bits, on peut coder 2
n
(2 multipli par lui-mme n fois)
nombres. Je me souviens avoir appris la base 2 en grande section de maternelle avec des cubes en bois !
trange programme scolaire. Et je ne dis pas a pour me trouver une excuse dtre devenu informaticien.
Quoique...
21. Coin des collgiens (suite) : en base 16, ou hexadcimal, on compte avec 16 chiffres. Il faut inven-
ter des chiffres au del de 9 et on prend A,B,C,D,E,F. Quand on compte, cela donne : 0, 1, 2, ..., 9, A, B,
C, D, E, F, 10, 11, 12, 13, ..., 19, 1A, 1B, 1C, ... Ainsi 1F en hexadcimal vaut 31. Avec 1 chiffre, on compte
de 0 15 soit 16 nombres possibles ; avec 2 chiffres, de 0 255 soit 256 = 16 16 nombres possibles, etc.
Un octet peut scrire avec 8 bits en binaire, ou 2 nombres en hexadcimal et va de 0 255, ou 11111111
en binaire, ou FF en hexadcimal.
22. Dans ce cas, sur plus de 2 chiffres : 8 pour les processeurs 32 bits, 16 pour les processeurs 64 bits.
19
2.1. Lordinateur 2. Bonjour, Monde !
La mmoire ne sert pas uniquement stocker la suite dinstructions excuter mais
aussi toutes les variables et donnes du programme, les registres du micro-processeur
tant insufsants. Ainsi nos variables a, b,c sont stockes quelque part en mmoire sur
un nombre doctets sufsant
23
pour reprsenter des nombres entiers (ici 4 octets) et
dans un endroit dcid par le C++, de tel sorte que linstruction 8B45F8 aille bien
chercher la variable a ! Cest un travail pnible, que le C++ fait pour nous et que les
programmeurs faisaient autrefois la main
24
. Bref, on a en plus
25
:
adresse mmoire contenu reprsente
... ...
00500000 a
1
00500001 a
2
a
00500002 a
3
00500003 a
4
00500004 b
1
00500005 b
2
b
00500006 b
3
00500007 b
4
... ...
o les octets a
1
, ..., a
4
combins donnent lentier a sur 32 bits. Certains processeurs (dits
big-endian)
26
dcident a = a
1
a
2
a
3
a
4
, dautres (little-endian)
27
que a = a
4
a
3
a
2
a
1
. Cela
signie que :
Tout comme pour les instructions, un nombre stock par un micro-
processeur dans un chier peut ne pas tre comprhensible par un autre
micro-processeur qui relit le chier !
2.1.3 Autres Composants
Micro-processeur et mmoire : nous avons vu le principal. Compltons le tableau
avec quelques autres lments importants de lordinateur.
23. Les variables ayant plus de 256 valeurs possibles sont forcment stockes sur plusieurs octets.
Ainsi, avec 4 octets on peut compter en binaire sur 4 8 = 32 bits, soit 2
32
valeurs possibles (plus de 4
milliards).
24. Ce qui tait le plus pnible ntait pas de dcider o il fallait ranger les variables en mmoire, mais
dajuster les instructions en consquence. Si on se trompait, on risquait dcrire au mauvais endroit de
la mmoire. Au mieux, cela effaait une autre variable ce comportement est encore possible de nos
jours au pire, cela effaait des instructions et le programme pouvait faire de "grosses btises" ceci
est aujourdhui impossible sous Windows ou Linux, et ne concerne plus que certains systmes.
25. Nous faisons ici un horrible mensonge des ns simplicatrices. Dans notre cas, les variables
taient des variables locales la fonction main() donc stockes dans la pile. Elles ne sont pas une
adresse mmoire dnie lavance de manire absolue mais une adresse relative lemplacement
o la fonction rangera ses variables locales en fonction de ce que le programme aura fait avant. Cela
explique la simplicit de linstruction mov eax,dword ptr [a] dans notre cas. Nous verrons tout
cela plus tard.
26. Comme les PowerPC des vieux Macs
27. Comme les processeurs Intel et AMD
20
2. Bonjour, Monde ! 2.1. Lordinateur
Types de mmoire
La mmoire dont nous parlions jusquici est de la mmoire vive ou RAM. Elle est
rapide
28
mais a la mauvaise ide de seffacer quand on teint lordinateur. Il faut donc
aussi de la mmoire morte ou ROM, cest--dire de la mmoire conservant ses donnes
quand lordinateur est teint mais qui en contre-partie ne peut tre modie
29
. Cette
mmoire contient en gnral le minimum pour que lordinateur dmarre et excute
une tche prdnie. Initialement, on y stockait les instructions ncessaires pour que le
programmeur puisse remplir ensuite la RAM avec les instructions de son programme.
Il fallait retaper le programme chaque fois
30
! On a donc rapidement eu recours des
moyens de stockage pour sauver programmes et donnes lextinction de lordinateur. Il
sufsait alors de mettre en ROM le ncessaire pour grer ces moyens de stockages.
Moyens de stockage
Certains permettent de lire des donnes, dautres den crire, dautres les deux
la fois. Certains ne dlivrent les donnes que dans lordre, de manire squentielle,
dautres, dans lordre que lon veut, de manire alatoire. Ils sont en gnral bien plus
lents que la mmoire et cest srement ce quil faut surtout retenir ! On recopie donc en
RAM la partie des moyens de stockage sur laquelle on travaille.
Faire travailler le micro-processeur avec le disque dur est BEAUCOUP plus
lent quavec la mmoire (1000 fois plus lent en temps daccs, 100 fois plus
en dbit)
a
a. Rajoutez un facteur 50 supplmentaire entre la mmoire et la mmoire cache du proces-
seur !
Au dbut, les moyens de stockages taient mcaniques : cartes ou bandes perfo-
res. Puis ils devinrent magntiques : mini-cassettes
31
, disquettes
32
, disques durs
33
ou
bandes magntiques. Aujourdhui, on peut rajouter les CD, DVD, les cartes mmoire,
les "cls USB", etc, etc.
Priphriques
On appelle encore priphriques diffrents appareils relis lordinateur : clavier,
souris, cran, imprimante, modem, scanner, etc. Ils taient initialement l pour servir
dinterface avec lHomme, comme des entres et des sorties entre le micro-processeur
et la ralit. Maintenant, il est difcile de voir encore les choses de cette faon. Ainsi
28. Moins que les registres, ou mme que le cache mmoire du processeur, dont nous ne parlerons pas
ici.
29. Il est pnible quune ROM ne puisse tre modie. Alors, une poque, on utilisait des mmoires
modiables malgr tout, mais avec du matriel spcialis (EPROMS). Maintenant, on a souvent recours
de la mmoire pouvant se modier de faon logicielle (mmoire "ashable") ou, pour de trs petites
quantits de donnes, une mmoire consommant peu (CMOS) et complte par une petite pile. Dans
un PC, la mmoire qui sert dmarrer sappelle le BIOS. Il est ashable et ses paramtres de rglage
sont en CMOS. Attention lusure de la pile !
30. A chaque fois quon allumait lordinateur mais aussi chaque fois que le programme plantait et
seffaait lui-mme, cest--dire la plupart du temps !
31. Trs lent et trs peu able, mais le quotidien des ordinateurs personnels.
32. Le luxe. Un lecteur de 40Ko cotait 5000F !
33. Les premiers taient de vritables moteurs de voiture, rservs aux importants centres de calcul.
21
2.2. Systme dexploitation 2. Bonjour, Monde !
les cartes graphiques, qui pouvaient tre considres comme un priphrique allant
avec lcran, sont-elles devenues une partie essentielle de lordinateur, vritables puis-
sances de calcul, tel point que certains programmeur les utilisent pour faire des cal-
culs sans mme afcher quoi que ce soit. Plus encore, cest lordinateur qui est parfois
juste considr comme maillon entre diffrents appareils. Qui appellerait priphrique
un camscope quon relie un ordinateur pour envoyer des vidos sur internet ou les
transfrer sur un DVD? Ce serait presque lordinateur qui serait un priphrique du
camscope !
2.2 Systme dexploitation
Notre vision jusquici est donc la suivante :
1. Le processeur dmarre avec les instructions prsentes en ROM.
2. Ces instructions lui permettent de lire dautres instructions prsentes sur le disque
dur et quil recopie en RAM.
3. Il excute les instructions en question pour il lire des donnes (entres) prsentes
elles-aussi sur le disque dur et gnrer de nouvelles donnes (sorties). A moins
que les entres ou les sorties ne soient changes via les priphriques.
Assez vite, ce principe a volu :
1. Le contenu du disque dur a t organis en chiers. Certains chiers reprsen-
taient des donnes
34
, dautres des programmes
35
, dautres encore contenaient
eux-mmes des chiers
36
.
2. Les processeurs devenant plus rapides et les capacits du disque dur plus impor-
tantes, on a eu envie de grer plusieurs programmes et den excuter plusieurs :
lun aprs lautre, puis plusieurs en mme temps (multi-tches), puis pour plu-
sieurs utilisateurs en mme temps (multi-utilisateurs)
37
, enn avec plusieurs pro-
cesseurs par machine.
Pour grer tout cela, sest dgag le concept de systme dexploitation
38
. Windows, Unix
(dont linux) et MAC/OS sont les plus rpandus. Le systme dexploitation est aujour-
dhui responsable de grer les chiers, les interfaces avec les priphriques ou les uti-
lisateurs
39
, mais son rle le plus dlicat est de grer les programmes (ou tches ou
process) en train de sexcuter. Il doit pour cela essentiellement faire face deux pro-
blmes
40
:
34. Les plus courantes taient les textes, o chaque octet reprsentait un caractre. Ctait le clbre
code ASCII (65 pour A, 66 pour B, etc.). A lre du multimdia, les formats sont aujourdhui nombreux,
concurrents, et plus ou moins normaliss.
35. On parle de chier excutable...
36. Les rpertoires.
37. Aujourdhui, cest pire. Un programme est souvent lui mme en plusieurs parties sexcutant en
mme temps (les threads). Quant au processeur, il excute en permanence plusieurs instructions en mme
temps (on dit quil est super-scalaire) !
38. Operating System
39. Esprons quun jour les utilisateurs ne seront pas eux-aussi des priphriques !
40. Les processeurs ont videmment volu pour aider le systme dexploitation faire cela
efcacement.
22
2. Bonjour, Monde ! 2.3. La Compilation
1. Faire travailler le processeur successivement par petites tranches sur les diff-
rents programmes. Il sagit de donner la main de manire intelligente et qui-
table, mais aussi de replacer un process interrompu dans la situation quil avait
quitte lors de son interruption.
2. Grer la mmoire ddie chaque process. En pratique, une partie ajustable de
la mmoire est rserve chaque process. La mmoire dun process devient m-
moire virtuelle : si un process est dplac un autre endroit de la mmoire physique
(la RAM), il ne sen rend pas compte. On en prote mme pour mettre tempo-
rairement hors RAM (donc sur disque dur) un process en veille. On peut aussi
utiliser le disque dur pour quun process utilise plus de mmoire que la mmoire
physique : mais attention, le disque tant trs lent, ce process risque de devenir
lui aussi trs lent.
Lorsquun process besoin de trop de mmoire, il utilise, sans prve-
nir, le disque dur la place de la mmoire et peut devenir trs lent.
On dit quil swappe (ou pagine). Seule sa lenteur (et le bruit du disque
dur !) permet en gnral de sen rendre compte (on peut alors sen as-
surer avec le gestionnaire de tche du systme).
Autre progrs : on gre maintenant la mmoire virtuelle de faon sparer les
process entre eux et, au sein dun mme process, la mmoire contenant les ins-
tructions de celle contenant les donnes. Il est rigoureusement impossible quun
process bugg puisse modier ses instructions ou la mmoire dun autre process
en crivant un mauvais endroit de la mmoire
41
.
Avec larrive des systmes dexploitation, les chiers excutables ont du sadapter
pour de nombreuse raisons de gestion et de partage de la mmoire. En pratique, un
programme excutable linux ne tournera pas sous Windows et rciproquement, mme
sils contiennent tous les deux des instructions pour le mme processeur.
Un chier excutable est spcique, non seulement un processeur donn,
mais aussi un systme dexploitation donn.
Au mieux, tout comme les versions successives dune famille de processeur essaient
de continuer comprendre les instructions de leurs prdcesseurs, tout comme les
versions successives dun logiciel essaient de pouvoir lire les donnes produites avec
les versions prcdentes, les diffrentes versions dun systme dexploitation essaient
de pouvoir excuter les programmes faits pour les versions prcdentes. Cest la com-
patibilit ascendante, que lon paye souvent au prix dune complexit et dune lenteur
accrues.
2.3 La Compilation
Tout en essayant de comprendre ce qui se passe en dessous pour en tirer des infor-
mations utiles comme la gestion de la mmoire, nous avons entrevu que transformer
un programme C++ en un chier excutable est un travail difcile mais utile. Cer-
tains logiciels disposant dun langage de programmation comme Maple ou Scilab ne
transforment pas leurs programmes en langage machine. Le travail de traduction est
41. Il se contente de modier anarchiquement ses donnes, ce qui est dj pas mal !
23
2.4. Lenvironnement de programmation 2. Bonjour, Monde !
fait lexcution du programme qui est alors analys au fur et mesure
42
: on parle
alors de langage interprt. Lexcution alors est videmment trs lente. Dautres lan-
gages, comme Java, dcident de rsoudre les problmes de portabilit, cest--dire de
dpendance au processeur et au systme, en plaant une couche intermdiaire entre
le processeur et le programme : la machine virtuelle. Cette machine, videmment crite
pour un processeur et un systme donns, peut excuter des programmes dans un
langage machine virtuel
43
, le "byte code". Un programme Java est alors traduit en son
quivalent dans ce langage machine. Le rsultat peut tre excut sur nimporte quelle
machine virtuelle Java. La contrepartie de cette portabilit est videmment une perte
defcacit.
La traduction en code natif ou en byte code dun programme sappelle la compila-
tion
44
. Un langage compil est alors opposer un langage interprt. Dans le cas du C++
et de la plupart des langages compils (Fortran, C, etc), la compilation se fait vers du
code natif. On transforme un chier source, le programme C++, en un chier objet, suite
dinstructions en langage machine.
Cependant, le chier objet ne se suft pas lui-mme. Des instructions supplmen-
taires sont ncessaires pour former un chier excutable complet :
de quoi lancer le main() ! Plus prcisment, tout ce que le process doit faire avant
et aprs lexcution de main().
des fonctions ou variables faisant partie du langage et que le programmeur utilise
sans les reprogrammer lui-mme, comme cout, cout|min()|, etc. Lensemble de
ces instructions constitue ce quon appelle une bibliothque
45
.
des fonctions ou variables programmes par le programmeur lui-mme dans
dautres chiers source compils par ailleurs en dautres chiers objet, mais quil
veut utiliser dans son programme actuel.
La synthse de ces chiers en un chier excutable sappelle ldition des liens. Le pro-
gramme qui ralise cette opration est plus souvent appel linker quditeur de liens...
En rsum, la production du chier excutable se fait de la faon suivante :
1. Compilation : chier source chier objet.
2. Link : chier objet + autres chiers objets + bibliothque standard ou
autres chier excutable.
2.4 Lenvironnement de programmation
Lenvironnement de programmation est le logiciel permettant de programmer. Dans
notre cas il sagit de Visual Studio Express. Dans dautres cas, il peut simplement sagir
dun ensemble de programmes. Un environnement contient au minimum un diteur
pour crer les chiers sources, un compilateur/linker pour crer les excutables, un de-
42. mme sil est parfois pr-trait pour acclrer lexcution.
43. Par opposition, le "vrai" langage machine du processeur est alors appel code natif.
44. Les principes de la compilation sont une des matires de base de linformatique, traditionnelle et
trs formatrice. Quand on sait programmer un compilateur, on sait tout programmer (videmment, un
compilateur est un programme ! On le programme avec le compilateur prcdent ! Mme chose pour les
systmes dexploitation...). Elle ncessite un cours part entire et nous nen parlerons pas ici !
45. Une bibliothque est en fait un ensemble de chiers objets pr-existants regroups en un seul -
chier. Il peut sagir de la bibliothque des fonctions faisant partie de C++, appele bibliothque standard,
mais aussi dune bibliothque supplmentaire fournie par un tiers.
24
2. Bonjour, Monde ! 2.4. Lenvironnement de programmation
buggeur pour traquer les erreurs de programmation, et un gestionnaire de projet pour
grer les diffrents chiers sources et excutables avec lesquels on travaille.
Nous reportons ici le lecteur au texte du premier TP. En plus de quelques notions
rudimentaires de C++ que nous verrons au chapitre suivant, quelques informations
supplmentaires sont utiles pour le suivre.
2.4.1 Noms de chiers
Sous Windows, lextension (le sufxe) sert se reprer dans les types de chier :
Un chier source C++ se terminera par .cpp
46
.
Un chier objet sera en .obj
Un chier excutable en .exe
Nous verrons aussi plus loin dans le cours :
Les "en-tte" C++ ou headers servant tre inclus dans un chier source : chiers
.h
Les bibliothques (ensembles de chiers objets archivs en un seul chier) : chier
.lib ou .dll
2.4.2 Debuggeur
Lorsquun programme ne fait pas ce quil faut, on peut essayer de comprendre ce
qui ne va pas en truffant son source dinstructions pour imprimer la valeur de certaines
donnes ou simplement pour suivre son droulement. Ca nest videmment pas trs
pratique. Il est mieux de pouvoir suivre son droulement instruction par instruction et
dafcher la demande la valeur des variables. Cest le rle du debuggeur
47
.
Lorsquun langage est interprt, il est relativement simple de le faire sexcute pas
pas car cest le langage lui-mme qui excute le programme. Dans le cas dun langage
compil, cest le micro-processeur qui excute le programme et on ne peut pas larrter
chaque instruction! Il faut alors mettre en place des points darrt en modiant tem-
porairement le code machine du programme pour que le processeur sarrte lorsquil
atteint linstruction correspondant la ligne de source debugger. Si cest compliqu
mettre au point, cest trs simple utiliser, surtout dans un environnement de pro-
grammation graphique.
Nous verrons au fur et mesure des TP comment le debuggeur peut aussi inspecter
les appels de fonctions, espionner la modication dune variable, etc.
2.4.3 TP
Vous devriez maintenant aller faire le TP en annexe A.1. Si la pratique est essen-
tielle, en retenir quelque chose est indispensable ! Vous y trouverez aussi comment
installer Visual sur votre ordinateur (lien http://imagine.enpc.fr/~monasse/
Imagine++ mentionn la n du TP). Voici donc ce quil faut retenir du TP :
46. Un chier en .c sera considr comme du C. Diffrence avec linux : un chier en .C sera aussi
trait comme du C et non comme du C++!
47. Dbogueur en franais !
25
2.4. Lenvironnement de programmation 2. Bonjour, Monde !
1. Toujours travailler en local et sauvegarder sur le disque partag, cl
USB, etc.
2. Type de projet utilis : Imagine++ Project
3. Nettoyer ses solutions quand on quitte.
4. Lancer directement une excution sauve et gnre automatiquement.
Attention toutefois de ne pas conrmer lexcution si la gnration
sest mal passe.
5. Double-cliquer sur un message derreur positionne lditeur sur ler-
reur.
6. Toujours bien indenter.
7. Ne pas laisser passer des warnings !
8. Savoir utiliser le debuggeur.
9. Touches utiles :
F7 = = Build
F5 = = Start debugging
F10 = = Step over
F11 = = Step inside
Ctrl+K,Ctrl+F = Indent selection

Nous en savons maintenant assez pour apprendre un peu de C++...


26
3. Premiers programmes
Chapitre 3
Premiers programmes
Pars exprimenter au fur et mesure avec notre environnement de programmation, il est
temps dapprendre les premiers rudiments du C++. Nous allons commencer par programmer
nimporte comment... puis nous ajouterons un minimum dorganisation en apprenant faire
des fonctions.

On organise souvent un manuel de programmation de faon logique par rapport


au langage, en diffrents points successifs : les expressions, les fonctions, les variables,
les instructions, etc. Le rsultat est indigeste car il faut alors tre exhaustif sur chaque
point. Nous allons plutt ici essayer de voir les choses telles quelles se prsentent
quand on apprend : progressivement et sur un peu tous les sujets la fois
1
! Ainsi, ce
nest que dans un autre chapitre que nous verrons la faon dont les fonctions mmo-
risent leurs variables dans la "pile".
3.1 Tout dans le main()!
Rien dans les mains, rien dans les poches... mais tout dans le main(). Voici comment
un dbutant programme
2
.
Cest dj une tape importante que de programmer au kilomtre, en plaant
lintgralit du programme dans la fonction main(). Lessentiel est avant
tout de faire un programme qui marche !
3.1.1 Variables
Types
Les variables sont des mmoires dans lesquelles sont stockes des valeurs (ou don-
nes). Une donne ne pouvant tre stocke nimporte comment, il faut chaque fois d-
cider de la place prise en mmoire (nombre doctets) et du format, cest--dire de la faon
dont les octets utiliss vont reprsenter les valeurs prises par la variable. Nous avons
dj rencontr les int qui sont le plus souvent aujourdhui stocks sur quatre octets,
1. La contre-partie de cette prsentation est que ce polycopi, sil est fait pour tre lu dans lordre, est
peut-tre moins adapt servir de manuel de rfrence. .
2. Et bien des lves, ds que le professeur nest plus derrire !
3.1. Tout dans le main()! 3. Premiers programmes
soit 32 bits, et pouvant prendre 2
32
= 4294967296 valeurs possibles
3
. Par convention,
les int stockent les nombres entiers relatifs
4
, avec autant de nombres ngatifs que de
nombres positifs
5
, soit, dans le cas de 32 bits
6
, de 2147483648 2147483647 suivant
une certaine correspondance avec le binaire
7
.
Dire quune variable est un int, cest prciser son type. Certains langages nont pas
la notion de type ou essaient de deviner les types des variables. En C++, cest initia-
lement pour prciser la mmoire et le format des variables quelles sont types. Nous
verrons que le compilateur se livre un certain nombre de vrications de cohrence
de type entre les diffrentes parties dun programme. Ces vrications, pourtant bien
pratiques, ntaient pas faites dans les premires versions du C, petit frre du C++, car
avant tout, rptons-le :
Prciser un type, cest prciser la place mmoire et le format dune variable.
Le compilateur, sil pourra mettre cette information prot pour dtecter
des erreurs de programmation, en a avant tout besoin pour traduire le source
C++ en langage machine.
Dnition, Affectation, Initialisation, Constantes
Avant de voir dautres types de variables, regardons sur un exemple la syntaxe
utiliser :
1 i nt i ; / / D f i n i t i o n
2 i =2; / / Af f e c t a t i o n
3 cout << i << " " ;
4 i nt j ;
5 j =i ;
6 i =1; / / Ne mo d i f i e que i , pas j !
7 cout << i << " " << j << " " ;
8 i nt k , l ,m; / / D f i n i t i o n mul t i p l e
9 k=l =3; / / Af f e c t a t i o n mul t i p l e
10 m=4;
11 cout << k << " " << l << " " << m << " " ;
12 i nt n=5 , o=n , p=INT_MAX; / / I n i t i a l i s a t i o n s
13 cout << n << " " << o << " " << p << endl ;
14 i nt q=r =4; / / Er r e ur !
15 const i nt s =12;
16 s =13; / / Er r e ur !
Dans ce programme :
3. Nous avons aussi vu que cette simple ide donne dj lieu deux faons dutiliser les 4 octets :
big-endian ou little-endian.
4. Coin des collgiens : cest dire 0, 1, 2, ... mais aussi 1, 2, 3, ...
5. un prs !
6. En fait, les int sadaptent au processeur et un programme compil sur un processeur 64 bits aura
des int sur 64 bits ! Si lon a besoin de savoir dans quel cas on est, le C++ fournit les constantes INT_MIN
et INT_MAX qui sont les valeurs minimales et maximales prises par les int.
7. L, tout le monde fait pareil ! On compte en binaire partir de 0, et arriv 2147483647,
le suivant est -2147483648, puis -2147483647 et ainsi de suite jusqu -1. On a par exemple :
0 = 000...000, 1 = 000...001, 2147483647 = 011...111, 2147483648 = 100...000, 2147483647 =
100..001, 2 = 111...110, 1 = 111...111
28
3. Premiers programmes 3.1. Tout dans le main()!
Les lignes 1 et 2 dnissent une variable nomme i
8
de type int puis affecte
2 cette variable. La reprsentation binaire de 2 est donc stocke en mmoire
l o le compilateur dcide de placer i. Ce qui suit le "double slash" ( // ) est une
remarque : le compilateur ignore toute la n de la ligne, ce qui permet de mettre
des commentaires aidant la comprhension du programme.
La ligne 3 afche la valeur de i puis un espace (sans aller la ligne)
Les lignes 4, 5 et 6 dnissent un int nomm j , recopie la valeur de i, soit 2,
dans j , puis mmorise 1 dans i. Notez bien que i et j sont bien deux variables
diffrentes : i passe 1 mais j reste 2 !
La ligne 8 nous montre comment dnir simultanment plusieurs variables du
mme type.
La ligne 9 nous apprend que lon peut affecter des variables simultanment une
mme valeur.
A la ligne 12, des variables sont dnies et affectes en mme temps. En fait,
on parle plutt de variables initialises : elles prennent une valeur initiale en
mme temps quelles sont dnies. Notez que, pour des raisons defcacit, les
variables ne sont pas initialises par dfaut : tant quon ne leur a pas affect une
valeur et si elles nont pas t initialises, elles valent nimporte quoi
9
!
Attention toutefois, il est inutile de tenter une initialisation simultane. Cest in-
terdit. La ligne 14 provoque une erreur.
Enn, on peut rajouter const devant le type dune variable : celle-ci devient alors
constante et on ne peut modier son contenu. La ligne 15 dnit une telle variable
et la ligne 16 est une erreur.
En rsum, une fois les lignes 14 et 16 supprimes, ce (passionnant !) programme af-
che
10
:
2 1 2 3 3 4 5 5 2147483647
Les noms de variable sont composs uniquement des caractres a z (et majus-
cules), chiffres et underscore _ (vitez celui-ci, il nest pas trs esthtique), mais ne
peuvent pas commencer par un chiffre. Nutilisez pas de caractres accentus, car cela
pose des problmes de portabilit.
Porte
Dans lexemple prcdent, les variables ont t dnies au fur et mesure des be-
soins. Ce nest pas une vidence. Par exemple, le Cne permettait de dnir les variables
que toutes dun coup au dbut du main(). En C++, on peut dnir les variables en cours
de route, ce qui permet davantage de clart. Mais attention :
8. Le nom dune variable est aussi appel identicateur. Les messages derreur du compilateur utilise-
ront plutt ce vocabulaire !
9. Ainsi, un entier ne vaut pas 0 lorsquil est cr et les octets o il est mmoris gardent la valeur quil
avaient avant dtre rquisitionns pour stocker lentier en question. Cest une mauvaise ide dutiliser
la valeur dune variable qui vaut nimporte quoi et un compilateur mettra gnralement un warning si
on utilise une variable avant de lui fournir une valeur !
10. du moins sur une machine 32 bits, cf. remarque prcdente sur INT_MAX
29
3.1. Tout dans le main()! 3. Premiers programmes
les variables "nexistent" (et ne sont donc utilisables) qu partir de la ligne
o elles sont dnies. Elles ont une dure de vie limite et meurent ds que
lon sort du bloc limit par des accolades auquel elles appartiennent
a
. Cest
ce quon appelle la porte dune variable.
a. Cest un peu plus compliqu pour les variables globales. Nous verrons a aussi...
Ainsi, en prenant un peu davance sur la syntaxe des tests, que nous allons voir tout
de suite, le programme suivant provoque des erreurs de porte aux lignes 2 et 8 :
i nt i ;
i =j ; / / Er r e ur : j n e x i s t e pas e nc o r e !
i nt j =2;
i f ( j >1) {
i nt k=3;
j =k ;
}
i =k ; / / Er r e ur : k n e x i s t e pl us .
Autres types
Nous verrons les diffrents types au fur et mesure. Voici malgr tout les plus
courants :
i nt i =3; / / Ent i e r r e l a t i f
double x =12. 3; / / Nombre r e l ( do ubl e p r c i s i o n )
char c= A ; / / Ca r a c t r e
s t r i ng s=" hop" ; / / Cha ne de c a r a c t r e s
bool t =t r ue ; / / Bo o l e n ( v r a i ou f aux )
Les nombres rels sont en gnral approchs par des variables de type double ("double
prcision", ici sur 8 octets). Les caractres sont reprsents par un entier sur un oc-
tet (sur certaines machines de -128 127, sur dautres de 0 255), la correspondance
caractre/entier tant celle du code ASCII (65 pour A, 66 pour B, etc.), quil nest heu-
reusement pas besoin de connatre puisque la syntaxe A entre simples guillemets est
traduite en 65 par le compilateur, etc. Les doubles guillemets sont eux rservs aux
"chanes" de caractres
11
. Enn, les boolens sont des variables qui valent vrai (true)
ou faux ( false).
Voici, pour information, quelques types supplmentaires :
f l o a t y=1. 2 f ; / / Nombre r e l s i mpl e p r c i s i o n
unsigned i nt j =4; / / Ent i e r na t ur e l
si gned char d=128; / / Ent i e r r e l a t i f un o c t e t
unsigned char d=254; / / Ent i e r na t ur e l un o c t e t
complex<double> z ( 2 , 3 ) ; / / Nombre c ompl e xe
o lon trouve :
les oat , nombres rels moins prcis mais plus courts que les double, ici sur
4 octets (Les curieux pourront explorer la documentation de Visual et voir que
11. Attention, lutilisation des string ncessite un #include<string> au dbut du programme.
30
3. Premiers programmes 3.1. Tout dans le main()!
les oat valent au plus FLT\_MAX (ici, environ 3.4e+38
12
) et que leur valeur la
plus petite strictement positive est FLT\_MIN (ici, environ 1.2e38), de mme
que pour les double les constantes DBL\_MAX et DBL\_MIN valent ici environ
1.8e+308 et 2.2e308),
les unsigned int, entiers positifs utiliss pour aller plus loin que les int dans les
positifs (de 0 UINT_MAX, soit 4294967295 dans notre cas),
les unsigned char, qui vont de 0 255,
les signed char, qui vont de -128 127,
et enn les nombres complexes
13
.
3.1.2 Tests
Tests simples
Les tests servent excuter telle ou telle instruction en fonction de la valeur dune
ou de plusieurs variables. Ils sont toujours entre parenthses. Le et scrit &&, le
ou ||, la ngation ! , lgalit ==, la non-galit !=, et les ingalits >, >=, < et <=.
Si plusieurs instructions doivent tre excutes quand un test est vrai ( if ) ou faux
(else), on utilise des accolades pour les regrouper. Tout cela se comprend facilement
sur lexemple suivant :
i f ( i ==0) / / i e s t i l nul ?
cout << " i es t nul " << endl ;
. . .
i f ( i >2) / / i e s t i l pl us grand que 2?
j =3;
e l s e
j =5; / / Si on e s t i c i , c e s t que i <=2
. . .
/ / Cas pl us c ompl i qu !
i f ( i ! =3 || ( j ==2 && k! =3) || ! ( i >j && i >k ) ) {
/ / I c i , i e s t d i f f r e n t de 3 ou a l o r s
/ / j vaut 2 e t k e s t d i f f r e n t de 3 ou a l o r s
/ / on n a pas i pl us grand a l a f o i s de j e t de k
cout << "Une premi re i ns t r uc t i on " << endl ;
cout << "Une deuxime i ns t r uc t i on " << endl ;
}
Les variables de type boolen servent mmoriser le rsultat dun test :
bool t = ( ( i ==3)||( j ==4) ) ;
i f ( t )
k=5;
12. Coin des collgiens : 10
38
ou 1e+38 vaut 1 suivi de 38 zros, 10
38
ou 1e38 vaut 0.000...01 avec
37 zros avant le 1. En compliquant : 3.4e+38 vaut 34 suivis de 37 zros (38 chiffres aprs le 3) et 1.2e38
vaut 0.00...012 toujours avec 37 zros entre la virgule et le 1 (le 1 est la place 38).
13. Il est trop tt pour comprendre la syntaxe "objet" de cette dnition mais il nous parait important
de mentionner ds maintenant que les complexes existent en C++.
Coin des collgiens : pas de panique ! Vous apprendrez ce que sont les nombres complexes plus tard.
Ils ne seront pas utiliss dans ce livre.
31
3.1. Tout dans le main()! 3. Premiers programmes
Enn, une dernire chose trs importante : penser utiliser == et non = sous peine
davoir des surprises
14
. Cest peut-tre lerreur la plus frquente chez les dbutants.
Elle est heureusement signale aujourdhui par un warning...
Attention : utiliser if ( i==3) ... et non if ( i=3) ... !
Le "switch"
On a parfois besoin de faire telle ou telle chose en fonction des valeurs possibles
dune variable. On utilise alors souvent linstruction switch pour des raisons de clart
de prsentation. Chaque cas possible pour les valeurs de la variable est prcis avec
case et doit se terminer par break
15
. Plusieurs case peuvent tre utiliss pour prciser
un cas multiple. Enn, le mot cl default, placer en dernier, correspond aux cas non
prciss. Le programme suivant
16
ragit aux touches tapes au clavier et utilise un
switch pour afcher des commentaires passionnants !
1 # i ncl ude <i ostream>
2 usi ng namespace st d ;
3 # i ncl ude <coni o . h> / / Non s t a nda r d !
4
5 i nt main ( )
6 {
7 bool f i n i =f a l s e ;
8 char c ;
9 do {
10 c=_get ch ( ) ; / / Non s t a nda r d !
11 swi t ch ( c ) {
12 case a :
13 cout << " Vous avez t ap a ! " << endl ;
14 break ;
15 case f :
16 cout << " Vous avez t ap f . Au r evoi r ! " << endl ;
17 f i n i =t r ue ;
18 break ;
19 case e :
20 case i :
21 case o :
22 case u :
23 case y :
24 cout << " Vous avez t ap une aut re voyel l e ! " << endl ;
25 break ;
14. Faire if ( i=3) ... affecte 3 i puis renvoie 3 comme rsultat du test, ce qui est considr comme
vrai car la convention est quun boolen est en fait un entier, faux sil est nul et vrai sil est non nul !
15. Cest une erreur grave et frquente doublier le break. Sans lui, le programme excute aussi les
instructions du cas suivant !
16. Attention, un cin >> c, instruction que nous verrons plus loin, lit bien un caractre au clavier
mais ne ragit pas chaque touche : il attend quon appuie sur la touche Entre pour lire dun coup
toutes les touches frappes ! Rcuprer juste une touche la console nest malheureusement pas stan-
dard et nest plus trs utilis dans notre monde dinterfaces graphiques. Sous Windows, il faudra utiliser
_getch() aprs avoir fait un #include <conio.h> (cf. lignes 3 et 10) et sous Unix getch() aprs avoir fait
un #include <curses.h>.
32
3. Premiers programmes 3.1. Tout dans le main()!
26 def aul t :
27 cout << " Vous avez t ap aut re chose ! " << endl ;
28 break ;
29 }
30 } while ( ! f i n i ) ;
31 ret urn 0;
32 }
Si vous avez tout compris, le switch prcdant ceci est quivalent
17
:
i f ( c== a )
cout << " Vous avez t ap a ! " << endl ;
e l s e i f ( c== f ) {
cout << " Vous avez t ap f . Au r evoi r ! " << endl ;
f i n i =t r ue ;
} e l s e i f ( c== e || c== i || c== o || c== u || c== y )
cout << " Vous avez t ap une aut re voyel l e ! " << endl ;
e l s e
cout << " Vous avez t ap aut re chose ! " << endl ;
Avant tout, rappelons la principale source derreur du switch :
Dans un switch, ne pas oublier les break!
Vous avez pu remarquer cette ligne 2 un peu cryptique. Un namespace est un pr-
xe pour certains objets. Le prxe des objets standard du langage est std. Ainsi cout
et endl ont pour nom complet std :: cout et std :: endl. La ligne 2 permet domettre ce
prxe.
3.1.3 Boucles
Il est difcile de faire un programme qui fait quelque chose sans avoir la possibilit
dexcuter plusieurs fois la mme instruction. Cest le rle des boucles. La plus utili-
se est le for () , mais a nest pas la plus simple comprendre. Commenons par le
do ... while, qui "tourne en rond" tant quun test est vrai. Le programme suivant attend
que lutilisateur tape au clavier un entier entre 1 et 10, et lui ritre sa question jusqu
obtenir un nombre correct :
1 # i ncl ude <i ostream>
2 usi ng namespace st d ;
3
4 i nt main ( )
5 {
6 i nt i ;
7 do { / / Dbut de l a b o uc l e
8 cout << "Un nombre ent r e 1 et 10 , SVP: " ;
9 ci n >> i ;
10 } while ( i <1 || i >10) ; / / On r e t o ur ne au d but de l a b o uc l e s i
17. On voit bien que le switch nest pas toujours plus clair ni plus court. Cest comme tout, il faut
lutiliser bon escient... Et plus nous connatrons de C++, plus nous devrons nous rappeler cette rgle
et viter de faire des fonctions pour tout, des structures de donnes pour tout, des objets pour tout, des
chiers spars pour tout, etc.
33
3.1. Tout dans le main()! 3. Premiers programmes
11 / / c e t e s t e s t v r a i
12 cout << " Merci ! Vous avez t ap " << i << endl ;
13 ret urn 0;
14 }
Notez la ligne 9 qui met dans i un nombre tap au clavier. La variable cin est le pendant
en entre ("console in") de la sortie cout.
Vient ensuite le while qui vrie le test au dbut de la boucle. Le programme sui-
vant afche les entiers de 1 100 :
i nt i =1;
whi le ( i <=100) {
cout << i << endl ;
i =i +1;
}
Enn, on a cre une boucle spciale tant elle est frquente : le for () qui excute
une instruction avant de dmarrer, effectue un test au dbut de chaque tour, comme le
while, et excute une instruction la n de chaque boucle. Instruction initiale, test et
instruction nale sont spares par un ; , ce qui donne le programme suivant, absolu-
ment quivalent au prcdent :
i nt i ;
f or ( i =1; i <=100; i =i +1) {
cout << i << endl ;
}
En gnral, le for () est utilis comme dans lexemple prcdent pour effectuer une
boucle avec une variable (un indice) qui prend une srie de valeurs dans un certain
intervalle. On trouvera en fait plutt :
f or ( i nt i =1; i <=100; i ++)
cout << i << endl ;
quand on sait que :
On peut dnir la variable dans la premire partie du for () . Attention, cette va-
riable admet le for () pour porte : elle nest plus utilisable en dehors du for ()
18
.
i++ est une abbrviation de i=i+1
Puisquil ny a ici quune seule instruction dans la boucle, les accolades taient
inutiles.
On utilise aussi la virgule , pour mettre plusieurs instructions
19
dans linstruction -
nale du for. Ainsi, le programme suivant part de i=1 et j=100, et augmente i de 2 et
diminue j de 3 chaque tour jusqu ce que leurs valeurs se croisent
20
:
f or ( i nt i =1 , j =100; j >i ; i =i +2 , j =j 3)
cout << i << " " << j << endl ;
Notez aussi quon peut abrger i=i+2 en i+=2 et j =j3 en j =3.
18. Les vieux C++ ne permettaient pas de dnir la variable dans la premire partie du for () . Des C++
un peu moins anciens permettaient de le faire mais la variable survivait au for () !
19. Pour les curieux : a na en fait rien dextraordinaire, car plusieurs instructions spares par une
virgule deviennent en C++ une seule instruction qui consiste excuter lune aprs lautre les diffrentes
instructions ainsi rassembles.
20. Toujours pour les curieux, il sarrte pour i=39 et j=43.
34
3. Premiers programmes 3.1. Tout dans le main()!
3.1.4 Rcrations
Nous pouvons dj faire de nombreux programmes. Par exemple, jouer au juste
prix. Le programme choisit le prix, et lutilisateur devine :
1 # i ncl ude <i ostream>
2 # i ncl ude <c s t dl i b >
3 usi ng namespace st d ;
4
5 i nt main ( )
6 {
7 i nt n=rand( ) %100; / / nombre de vi ne r e nt r e 0 e t 99
8 i nt i ;
9 do {
10 cout << " Votre pr i x : " ;
11 ci n >> i ;
12 i f ( i >n)
13 cout << "C es t moins " << endl ;
14 e l s e i f ( i <n)
15 cout << "C es t pl us " << endl ;
16 e l s e
17 cout << " Gagne ! " << endl ;
18 } while ( i ! =n ) ;
19 ret urn 0;
20 }
Seule la ligne 7 a besoin dexplications :
la fonction rand() fournit un nombre entier au hasard entre 0 et RAND_MAX. On
a besoin de rajouter #include <cstdlib> pour lutiliser
% est la fonction modulo
21
.
Cest videmment plus intressant, surtout programmer, quand cest le programme
qui devine. Pour cela, il va procder par dichotomie, an de trouver au plus vite :
1 #i ncl ude <i ostream>
2 usi ng namespace st d ;
3
4 i nt main ( )
5 {
6 cout << " Choi si ssez un nombre ent r e 1 et 100 " << endl ;
7 cout << " Repondez par +, ou =" << endl ;
8 i nt a=1 , b=100; / / Val e ur s e xt r me s
9 bool t rouve=f a l s e ;
10 do {
11 i nt c =( a+b ) /2; / / On pr o po s e l e mi l i e u
12 cout << " Ser ai t ce " << c << " ? : " ;
13 char r ;
14 do
15 ci n >> r ;
21. Coin des collgiens : compter "modulo N", cest retomber 0 quand on atteint N. Modulo 4, cela
donne : 0,1,2,3,0,1,2,3,0,.... Par exemple 12%10 vaut 2 et 11%3 aussi ! Ici, le modulo 100 sert retomber
entre 0 et 99.
35
3.1. Tout dans le main()! 3. Premiers programmes
16 while ( r ! = = && r ! = + && r ! = ) ;
17 i f ( r== = )
18 t rouve=t r ue ;
19 e l s e i f ( r== )
20 b=c 1; / / C e s t moins , on e s s a i e e nt r e a e t c1
21 e l s e
22 a=c +1; / / C e s t pl us , on e s s a i e e nt r e c +1 e t b
23 } while ( ! t rouve && ( a<=b ) ) ;
24 i f ( t rouve )
25 cout << " Quel boss j e s ui s ! " << endl ;
26 e l s e
27 cout << " Vous avez t r i c h ! " << endl ;
28 ret urn 0;
29 }
On peut aussi complter le programme "supplmentaire" du TP de lannexe A.1. Il
sagissait dune balle rebondissant dans un carr. (Voir lannexe C pour les instructions
graphiques...)
1 # i ncl ude <Imagine/Graphi cs . h>
2 usi ng namespace Imagine ;
3
4 i nt main ( )
5 {
6 i nt w=300 , h=210;
7 openWindow(w, h ) ; / / Fe n t r e gr a phi que
8 i nt i =0 , j =0; / / Po s i t i o n
9 i nt di =2 , dj =3; / / Vi t e s s e
10 while ( t r ue ) {
11 f i l l Re c t ( i , j , 4 , 4 , RED) ; / / De s s i n de l a b a l l e
12 mi l l i Sl ee p ( 1 0 ) ; / / On a t t e nd un peu . . .
13 i f ( i +di >w || i +di <0) {
14 di=di ; / / Rebond h o r i z o n t a l s i on s o r t
15 }
16 i nt ni =i +di ; / / Nouve l l e p o s i t i o n
17 i f ( j +dj >h || j +dj <0) {
18 dj =dj ; / / Rebond v e r t i c a l s i on s o r t
19 }
20 i nt nj =j +dj ;
21 f i l l Re c t ( i , j , 4 , 4 , WHITE) ; / / Ef f a c e me nt
22 i =ni ; / / On change de p o s i t i o n
23 j =nj ;
24 }
25 endGraphics ( ) ;
26 ret urn 0;
27 }
Notez ce endGraphics() dont la fonction est dattendre un clic de lutilisateur avant
de terminer le programme, de manire laisser la fentre visible le temps ncessaire.
Cette fonction nest pas standard, et elle est dans le namespace Imagine. La ligne 2
permet de lappeler sans utiliser son nom complet Imagine::endGraphics(). Les autres
36
3. Premiers programmes 3.2. Fonctions
FIGURE 3.1 Traits et cercles au hasard...
fonctions appeles dans ce petit programme (openWindow, llRect et milliSleep) sont
aussi fournies par Imagine.
3.2 Fonctions
Lorsquon met tout dans le main() on ralise trs vite que lon fait souvent des
copier/coller de bouts de programmes. Si des lignes de programmes commencent se
ressembler, cest quon est vraisemblablement devant loccasion de faire des fonctions.
On le fait pour des raisons de clart, mais aussi pour faire des conomies de frappe au
clavier !
Il faut regrouper les passages identiques en fonctions :
pour obtenir un programme clair...
et pour moins se fatiguer !
Attention bien comprendre quand faire une fonction et ne pas simple-
ment dcouper un programme en petits morceaux sans aucune logique
a
.
a. ou juste pour faire plaisir au professeur. Mal dcouper un programme est la meilleure
faon de ne plus avoir envie de le faire la fois suivante. Encore une fois, le bon critre est ici
que la bonne solution est gnralement la moins fatiguante.
En fait, pouvoir rutiliser le travail dj fait est le l conducteur dune bonne program-
mation. Pour linstant, nous nous contentons, grce aux fonctions, de rutiliser ce que
nous venons de taper quelques lignes plus haut. Plus tard, nous aurons envie de ruti-
liser ce qui aura t fait dans dautres programmes, ou longtemps auparavant, ou dans
les programmes dautres personnes, ... et nous verrons alors comment faire.
Prenons le programme suivant, qui dessine des traits et des cercles au hasard, et
dont la gure 3.1 montre un rsultat :
1 # i ncl ude <Imagine/Graphi cs . h>
2 usi ng namespace Imagine ;
3 # i ncl ude <c s t dl i b >
4 usi ng namespace st d ;
37
3.2. Fonctions 3. Premiers programmes
5
6 i nt main ( )
7 {
8 openWindow( 3 0 0 , 2 0 0 ) ;
9 f or ( i nt i =0; i <150; i ++) {
10 i nt x1=rand( ) %300; / / Poi nt i n i t i a l
11 i nt y1=rand( ) %200;
12 i nt x2=rand( ) %300; / / Poi nt f i n a l
13 i nt y2=rand( ) %200;
14 Color c=Color ( rand( ) %256 , rand( ) %256 , rand ( ) %256) ; / / RVB
15 drawLine ( x1 , y1 , x2 , y2 , c ) ; / / Tr ac de segment
16 i nt xc=rand( ) %300; / / Ce nt r e du c e r c l e
17 i nt yc=rand( ) %200;
18 i nt r c=rand( ) %10; / / Rayon
19 Color cc=Color ( rand( ) %256 , rand( ) %256 , rand ( ) %256) ; / / RVB
20 f i l l Ci r c l e ( xc , yc , rc , cc ) ; / / Ce r c l e
21 }
22 endGraphics ( ) ;
23 ret urn 0;
24 }
La premire chose qui choque
22
, cest lappel rpt rand() et modulo pour tirer
un nombre au hasard. On aura souvent besoin de tirer des nombres au hasard dans
un certain intervalle et il est naturel de le faire avec une fonction. Au passage, nous
corrigeons une deuxime chose qui choque : les entiers 300 et 200 reviennent souvent.
Si nous voulons changer les dimensions de la fentre, il faudra remplacer dans le pro-
gramme tous les 300 et tous les 200. Il vaudrait mieux mettre ces valeurs dans des
variables et faire dpendre le reste du programme de ces variables. Cest un dfaut
constant de tous les dbutants et il faut le corriger tout de suite.
Il faut ds le dbut dun programme reprer les paramtres constants uti-
liss plusieurs reprises et les placer dans des variables dont dpendra le
programme. On gagne alors beaucoup de temps
a
quand on veut les modi-
er par la suite.
a. Encore la rgle du moindre effort... Si on fait trop de copier/coller ou de remplacer avec
lditeur, cest mauvais signe !
Bref, notre programme devient :
/ / Nombre e nt r e 0 e t n1
i nt hasard ( i nt n)
{
ret urn rand()%n ;
}
i nt main ( )
{
const i nt w=300 , h=200;
22. part videmment la syntaxe "objet" des variables de type Color pour lesquelles on se permet un
Color(r,v,b) bien en avance sur ce que nous sommes censs savoir faire...
38
3. Premiers programmes 3.2. Fonctions
openWindow(w, h ) ;
f or ( i nt i =0; i <150; i ++) {
i nt x1=hasard (w) , y1=hasard ( h ) ; / / Poi nt i n i t i a l
i nt x2=hasard (w) , y2=hasard ( h ) ; / / Poi nt f i n a l
Color c=Color ( hasard ( 256) , hasard ( 256) , hasard ( 2 5 6 ) ) ;
drawLine ( x1 , y1 , x2 , y2 , c ) ; / / Tr ac de segment
i nt xc=hasard (w) , yc=hasard ( h ) ; / / Ce nt r e du c e r c l e
i nt r c=hasard (w/20) ; / / Rayon
Color cc=Color ( hasard ( 256) , hasard ( 256) , hasard ( 2 5 6 ) ) ;
f i l l Ci r c l e ( xc , yc , rc , cc ) ; / / Ce r c l e
}
endGraphics ( ) ;
ret urn 0;
}
On pourrait penser que hasard(w) est aussi long taper que rand()%w et que notre
fonction est inutile. Cest un peu vrai. Mais en pratique, nous navons alors plus
nous souvenir de lexistence de la fonction rand() ni de comment on fait un modulo.
Cest mme mieux que a : nous devenons indpendant de ces deux fonctions, et si
vous voulions tirer des nombres au hasard avec une autre fonction
23
, nous naurions
plus qu modier la fonction hasard(). Cest encore une rgle importante.
On doit galement faire une fonction quand on veut sparer et factoriser
le travail. Il est ensuite plus facile
a
de modier la fonction que toutes les
lignes quelle a remplaces !
a. Moindre effort, toujours !
3.2.1 Retour
Nous venons de dnir sans lexpliquer une fonction hasard() qui prend un para-
mtre n de type int et qui retourne un rsultat, de type int lui aussi. Il ny a pas grand
chose savoir de plus, si ce nest que :
1. Une fonction peut ne rien renvoyer. Son type de retour est alors void et il ny a
pas de return la n. Par exemple :
void di s_bonj our_a_l a_dame ( s t r i ng nom_de_la_dame ) {
cout << " Bonj our , Mme " << nom_de_la_dame << " ! " << endl ;
}
. . .
di s_bonj our_a_l a_dame ( " Germaine " ) ;
di s_bonj our_a_l a_dame ( " Fi t zger al d " ) ;
. . .
23. Pourquoi vouloir le faire ? Dans notre cas parce que la fonction rand() utilise est sufsante pour
des applications courantes mais pas assez prcise pour des applications mathmatiques. Par exemple,
faire un modulo ne rpartit pas vraiment quitablement les nombres tirs. Enn, nous avons oubli
dinitialiser le gnrateur alatoire. Si vous le permettez, nous verrons une autre fois ce que cela signie
et comment le faire en modiant juste la fonction hasard().
39
3.2. Fonctions 3. Premiers programmes
2. Une fonction peut comporter plusieurs instructions return
24
. Cela permet de sor-
tir quand on en a envie, ce qui est bien plus clair et plus proche de notre faon de
penser :
i nt si gne_avec_un_seul _ret urn ( double x ) {
i nt s ;
i f ( x==0)
s =0;
e l s e i f ( x<0)
s =1;
e l s e
s =1;
ret urn s ;
}
i nt si gne_pl us_si mpl e ( double x ) {
i f ( x<0)
ret urn 1;
i f ( x>0) / / Not ez l a b s e nc e de e l s e , devenu i n u t i l e !
ret urn 1;
ret urn 0;
}
3. Pour une fonction void, on utilise return sans rien derrire pour un retour en
cours de fonction :
void t el ephoner_avec_un_seul _ret urn ( s t r i ng nom) {
i f ( j _ai _l e_t el ephone ) {
i f (mon telephone_marche ) {
i f ( est _dans_l _annuai re (nom) ) {
i nt numero=numero_telephone (nom) ;
composer ( numero ) ;
i f ( ca_decroche ) {
par l er ( ) ;
r accr ocher ( ) ;
}
}
}
}
}
void t el ephoner_pl us_si mpl e ( s t r i ng nom) {
i f ( ! j _ai _l e_t el ephone )
ret urn ;
i f ( ! mon telephone_marche )
ret urn ;
i f ( ! est _dans_l _annuai re (nom) )
ret urn ;
i nt numero=numero_telephone (nom) ;
composer ( numero ) ;
24. Contrairement certains vieux langages, comme le Pascal
40
3. Premiers programmes 3.2. Fonctions
i f ( ! ca_decroche )
ret urn ;
par l er ( ) ;
r accr ocher ( ) ;
}
3.2.2 Paramtres
Nous navons vu que des fonctions un seul paramtre. Voici comment faire pour
en passer plusieurs ou nen passer aucun :
/ / Nombre e nt r e a e t b
i nt hasard2 ( i nt a , i nt b)
{
ret urn a+( rand( ) %( ba +1 ) ) ;
}
/ / Nombre e nt r e 0 e t 1
double hasard3 ( )
{
ret urn rand ( ) / double (RAND_MAX) ;
}
. . .
i nt a=hasard2 ( 1 , 1 0 ) ;
double x=hasard3 ( ) ;
. . .
Attention bien utiliser x=hasard3() et non simplement x=hasard3 pour appeler cette
fonction sans paramtre. Ce simple programme est aussi loccasion de parler dune
erreur trs frquente : la division de deux nombres entiers donne un nombre entier !
Ainsi, crire double x=1/3; est une erreur car le C++ commence par calculer 1/3 avec
des entiers, ce qui donne 0, puis convertit 0 en double pour le ranger dans x. Il ne sait
pas au moment de calculer 1/3 quon va mettre le rsultat dans un double ! Il faut alors faire
en sorte que le 1 ou le 3 soit une double et crire double x=1.0/3; ou double x=1/3.0;.
Si, comme dans notre cas, on a affaire deux variables de type int, il suft de convertir
une de ces variables en double avec la syntaxe double (...) que nous verrons plus tard.
1. Fonction sans paramtre : x=hop(); et non x=hop;.
2. Division entire :
double x=1.0/3; et non double x=1/3;
double x=double(i)/j; et non double x=i/j;, ni mme
double x=double(i/j);
a
a. Cette conversion en double arrive trop tard!
3.2.3 Passage par rfrence
Lorsquune fonction modie la valeur dun de ses paramtres, et si ce paramtre
tait une variable dans la fonction appelante, alors la variable en question nest pas
modie. Plus clairement, le programme suivant choue :
41
3.2. Fonctions 3. Premiers programmes
void t r i pl e ( i nt x ) {
x=x 3;
}
. . .
i nt a =2;
t r i pl e ( a ) ;
cout << a << endl ;
Il afche 2 et non 6. En fait, le paramtre x de la fonction triple vaut bien 2, puis 6.
Mais son passage 6 ne modie pas a. Nous verrons plus loin que x est mmoris
un endroit diffrent de a, ce qui explique tout ! Cest la valeur de a qui est passe
la fonction triple () et non pas la variable a ! On parle de passage par valeur. On
peut toutefois faire en sorte que la fonction puisse vraiment modier son paramtre.
On sagit alors dun passage par rfrence (ou par variable). Il suft de rajouter un &
derrire le type du paramtre :
void t r i pl e ( i nt& x ) {
x=x 3;
}
Gnralement, on choisit lexemple suivant pour justier le besoin des rfrences :
void echanger1 ( i nt x , i nt y) {
i nt t =x ;
x=y ;
y=t ;
}
void echanger2 ( i nt& x , i nt& y) {
i nt t =x ;
x=y ;
y=t ;
}
. . .
i nt a=2 , b=3;
echanger1 ( a , b ) ;
cout << a << " " << b << " " ;
echanger2 ( a , b ) ;
cout << a << " " << b << endl ;
. . .
Ce programme afche 2 3 3 2, echanger1() ne marchant pas.
Une bonne faon de comprendre le passage par rfrence est de considrer que les
variables x et y de echanger1 sont des variables vraiment indpendantes du a et du
b de la fonction appelante, alors quau moment de lappel echanger2, le x et le y
de echanger2 deviennent des "liens" avec a et b. A chaque fois que lon utilise x dans
echanger2, cest en fait a qui est utilise. Pour encore mieux comprendre allez voir le
premier exercice du TP 2 (A.2.1) et sa solution.
En pratique,
on utilise aussi les rfrences pour faire des fonctions retournant plusieurs
valeurs la fois,
et ce, de la faon suivante :
42
3. Premiers programmes 3.2. Fonctions
void un_point ( i nt& x , i nt& y) {
x = . . . ;
y = . . . ;
}
. . .
i nt a , b ;
un_point ( a , b ) ;
. . .
Ainsi, notre programme de dessin alatoire deviendrait :
1 # i ncl ude <Imagine/Graphi cs . h>
2 usi ng namespace Imagine ;
3 # i ncl ude <c s t dl i b >
4 usi ng namespace st d ;
5
6 / / Nombre e nt r e 0 e t n1
7 i nt hasard ( i nt n)
8 {
9 ret urn rand()%n ;
10 }
11
12 Color une_coul eur ( ) {
13 ret urn Color ( hasard ( 256) , hasard ( 256) , hasard ( 2 5 6 ) ) ;
14 }
15
16 void un_point ( i nt w, i nt h , i nt& x , i nt& y ) {
17 x=hasard (w) ;
18 y=hasard ( h ) ;
19 }
20
21 i nt main ( )
22 {
23 const i nt w=300 , h=200;
24 openWindow(w, h ) ;
25 f or ( i nt i =0; i <150; i ++) {
26 i nt x1 , y1 ; / / Poi nt i n i t i a l
27 un_point (w, h , x1 , y1 ) ;
28 i nt x2 , y2 ; / / Poi nt f i n a l
29 un_point (w, h , x2 , y2 ) ;
30 Color c=une_coul eur ( ) ;
31 drawLine ( x1 , y1 , x2 , y2 , c ) ; / / Tr ac de segment
32 i nt xc , yc ; / / Ce nt r e du c e r c l e
33 un_point (w, h , xc , yc ) ;
34 i nt r c=hasard (w/20) ; / / Rayon
35 Color cc=une_coul eur ( ) ;
36 f i l l Ci r c l e ( xc , yc , rc , cc ) ; / / Ce r c l e
37 }
38 endGraphics ( ) ;
39 ret urn 0;
43
3.2. Fonctions 3. Premiers programmes
40 }
Avec le conseil suivant :
penser utiliser directement le rsultat dune fonction et ne pas le mmori-
ser dans une variable lorsque cest inutile.
Il devient mme :
26 i nt x1 , y1 ; / / Poi nt i n i t i a l
27 un_point (w, h , x1 , y1 ) ;
28 i nt x2 , y2 ; / / Poi nt f i n a l
29 un_point (w, h , x2 , y2 ) ;
30 drawLine ( x1 , y1 , x2 , y2 , une_coul eur ( ) ) ; / / Tr ac de segment
31 i nt xc , yc ; / / Ce nt r e du c e r c l e
32 un_point (w, h , xc , yc ) ;
33 i nt r c=hasard (w/20) ; / / Rayon
34 f i l l Ci r c l e ( xc , yc , rc , une_coul eur ( ) ) ; / / Ce r c l e
3.2.4 Porte, Dclaration, Dnition
Depuis le dbut, nous crons des fonctions en les dnissant. Il est parfois utile de
ne connatre que le type de retour et les paramtres dune fonction sans pour autant
savoir comment elle est programme, cest--dire sans connatre le corps de la fonction.
Une des raisons de ce besoin est que :
comme les variables, les fonctions ont une porte et ne sont connues que
dans les lignes de source qui lui succdent.
Ainsi, le programme suivant ne compile pas :
1 i nt main ( )
2 {
3 f ( ) ;
4 ret urn 0 ;
5 }
6 void f ( ) {
7 }
car la ligne 3, f () nest pas connue. Il suft ici de mettre les lignes 6 et 7 avant le main()
pour que le programme compile. Par contre, il est plus difcile de faire compiler :
void f ( )
{
g ( ) ; / / Er r e ur : g ( ) i nconnue
}
void g ( ) {
f ( ) ;
}
puisque les deux fonctions on besoin lune de lautre, et quaucun ordre ne conviendra.
Il faut alors connatre la rgle suivante :
44
3. Premiers programmes 3.2. Fonctions
Remplacer le corps dune fonction par un; sappelle dclarer la fonction.
Dclarer une fonction suft au compilateur, qui peut "patienter"
a
jusqu
sa dnition.
a. En ralit, le compilateur na besoin que de la dclaration. Cest le linker qui devra trou-
ver quelque part la dnition de la fonction, ou plus exactement le rsultat de la compilation
de sa dnition!
Notre programme prcdent peut donc se compiler avec une ligne de plus :
void g ( ) ; / / D c l a r a t i o n de g
void f ( )
{
g ( ) ; / / OK: f o n c t i o n d c l a r e
}
void g ( ) { / / D f i n i t i o n de g
f ( ) ;
}
3.2.5 Variables locales et globales
Nous avons vu section 3.1.1 la porte des variables. La rgle des accolades sap-
plique videmment aux accolades du corps dune fonction.
Les variables dune fonction sont donc inconnues en dehors de la fonction
On parle alors de variables locales la fonction. Ainsi, le programme suivant est in-
terdit :
void f ( )
{
i nt x ;
x=3;
}
void g ( ) {
i nt y ;
y=x ; / / Er r e ur : x i nconnu
}
Si vraiment deux fonctions doivent utiliser des variables communes, il faut alors
les "sortir" des fonctions. Elles deviennent alors des variables globales, dont voici un
exemple :
1 i nt z ; / / g l o b a l e
2
3 void f ( )
4 {
5 i nt x ; / / l o c a l e
6 . . .
45
3.2. Fonctions 3. Premiers programmes
7 i f ( x<z )
8 . . .
9 }
10
11 void g ( )
12 {
13 i nt y ; / / l o c a l e
14 . . .
15 z=y ;
16 . . .
17 }
Lutilisation de variables globales est tolre et parfois justie. Mais elle constitue une
solution de facilit dont les dbutants abusent et il faut combattre cette tentation ds le
dbut :
les variables globales sont viter au maximum car
elles permettent parfois des communications abusives entre fonctions,
sources de bugs
a
.
les fonctions qui les utilisent sont souvent peu rutilisables dans des
contextes diffrents.
En gnral, elles sont le signe dune mauvaise faon de traiter le problme.
a. Cest pourquoi les variables globales non constantes ne sont pas tolres chez le dbu-
tant. Voir le programme prcdent o g() parle f () au travers de z.
3.2.6 Surcharge
Il est parfois utile davoir une fonction qui fait des choses diffrentes suivant le type
dargument quon lui passe. Pour cela on peut utiliser la surcharge :
Deux fonctions qui ont des listes de paramtres diffrentes peuvent avoir le
mme nom
a
. Attention : deux fonctions aux types de retour diffrents mais
aux paramtres identiques ne peuvent avoir le mme nom
b
.
a. Car alors la faon de les appeler permettra au compilateur de savoir laquelle des fonc-
tions on veut utiliser
b. Car alors le compilateur ne pourra diffrencier leurs appels.
Ainsi, nos fonctions "hasard" de tout lheure peuvent trs bien scrire :
1 / / Nombre e nt r e 0 e t n1
2 i nt hasard ( i nt n) {
3 ret urn rand()%n ;
4 }
5 / / Nombre e nt r e a e t b
6 i nt hasard ( i nt a , i nt b) {
7 ret urn a+( rand( ) %( ba +1 ) ) ;
8 }
9 / / Nombre e nt r e 0 e t 1
10 double hasard ( ) {
11 ret urn rand ( ) / double (RAND_MAX) ;
46
3. Premiers programmes 3.3. TP
FIGURE 3.2 Mini tennis...
12 }
13 . . .
14 i nt i =hasard ( 3 ) ; / / e nt r e 0 e t 2
15 i nt j =hasard ( 2 , 4 ) / / e nt r e 2 e t 4
16 double k=hasard ( ) ; / / e nt r e 0 e t 1
17 . . .
3.3 TP
Nous pouvons maintenant aller faire le deuxime TP donn en annexe A.2 an de
mieux comprendre les fonctions et aussi pour obtenir un mini jeu de tennis (gure 3.2).
3.4 Fiche de rfrence
Nous commenons maintenant nous fabriquer une "che de rfrence" qui servira
daide mmoire lorsquon est devant la machine. Nous la complterons aprs chaque
chapitre avec ce qui est vu dans le chapitre, mais aussi pendant le TP correspondant.
Les nouveauts par rapport la che prcdente seront en rouge. La che nale est en
annexe D.
47
3.4. Fiche de rfrence 3. Premiers programmes
Fiche de rfrence (1/2)
Variables
Dnition :
int i;
int k,l,m;
Affectation :
i=2;
j=i;
k=l=3;
Initialisation :
int n=5,o=n;
Constantes :
const int s=12;
Porte :
int i;
// i=j; interdit!
int j=2;
i=j; // OK!
if (j>1) {
int k=3;
j=k; // OK!
}
//i=k; interdit!
Types :
int i=3;
double x=12.3;
char c=A;
string s="hop";
bool t=true;
float y=1.2f;
unsigned int j=4;
signed char d=-128;
unsigned char d=254;
complex<double> z(2,3);
Variables globales :
int n;
const int m=12;
void f() {
n=10; // OK
int i=m; // OK
...
Conversion :
int i=int(x);
int i,j;
double x=double(i)/j;
Tests
Comparaison :
== != < > <= >=
Ngation : !
Combinaisons : && ||
if (i==0)
j=1;
if (i==0)
j=1;
else
j=2;
if (i==0) {
j=1;
k=2;
}
bool t=(i==0);
if (t)
j=1;
switch (i) {
case 1:
...;
...;
break;
case 2:
case 3:
...;
break;
default:
...;
}
Boucles
do {
...
} while (!ok);
int i=1;
while (i<=100) {
...
i=i+1;
}
for (int i=1;i<=10;i++)
...
for (int i=1,j=10;j>i;
i=i+2,j=j-3)
...
Fonctions
Dnition :
int plus(int a,int b) {
int c=a+b;
return c;
}
void affiche(int a) {
cout << a << endl;
}
Dclaration :
int plus(int a,int b);
Retour :
int signe(double x) {
if (x<0)
return -1;
if (x>0)
return 1;
return 0;
}
void afficher(int x,
int y) {
if (x<0 || y<0)
return;
if (x>=w || y>=h)
return;
DrawPoint(x,y,RED);
}
Appel :
int f(int a) { ... }
int g() { ... }
...
int i=f(2),j=g();
Rfrences :
void swap(int& a,
int& b){
int tmp=a;
a=b;b=tmp;
}
...
int x=3,y=2;
swap(x,y);
Surcharge :
int hasard(int n);
int hasard(int a,
int b);
double hasard();
Divers
i++;
i--;
i-=2;
j+=3;
j=i%n; // Modulo
#include <cstdlib>
...
i=rand()%n;
x=rand()/
double(RAND_MAX);
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
Erreurs frquentes
Pas de dnition de fonction
dans une fonction!
int q=r=4; // NON!
if (i=2) // NON!
if i==2 // NON!
if (i==2) then // NON!
for (int i=0,i<100,i++)
// NON!
int f() {...}
...
int i=f; // NON!
double x=1/3; // NON!
int i,j;
double x;
x=i/j; // NON!
x=double(i/j); //NON!
48
3. Premiers programmes 3.4. Fiche de rfrence
Fiche de rfrence (2/2)
Imagine++
Voir documentation...
Clavier
Build : F7
Debug : F5
Step over : F10
Step inside : F11
Indent : Ctrl+K,Ctrl+F
Conseils
Travailler en local
Imagine++ Project
Nettoyer en quittant.
Erreurs et warnings : cliquer.
Indenter.
Ne pas laisser de warning.
Utiliser le debuggeur.
Faire des fonctions.
49
4. Les tableaux
Chapitre 4
Les tableaux
Tout en continuant utiliser les fonctions pour les assimiler, nous allons rajouter les ta-
bleaux qui, sinon, nous manqueraient rapidement. Nous nirons pas trop vite et ne verrons
pour linstant que les tableaux une dimension et de taille xe. Nous tudierons dans un autre
chapitre les tableaux de taille variable et les questions de mmoire ("pile" et "tas").

4.1 Premiers tableaux


De mme quon a tout de suite ressenti le besoin davoir des boucles pour faire
plusieurs fois de suite la mme chose, il a t rapidement utile de faire plusieurs fois
la mme chose mais sur des variables diffrentes. Do les tableaux... Ainsi, le pro-
gramme suivant :
i nt x1 , y1 , u1 , v1 ; / / Ba l l e 1
i nt x2 , y2 , u2 , v2 ; / / Ba l l e 2
i nt x3 , y3 , u3 , v3 ; / / Ba l l e 3
i nt x4 , y4 , u4 , v4 ; / / Ba l l e 4
. . .
BougeBal l e ( x1 , y1 , u1 , v1 ) ;
BougeBal l e ( x2 , y2 , u2 , v2 ) ;
BougeBal l e ( x3 , y3 , u3 , v3 ) ;
BougeBal l e ( x4 , y4 , u4 , v4 ) ;
. . .
pourra avantageusement tre remplac par :
i nt x [ 4 ] , y [ 4 ] , u[ 4 ] , v [ 4 ] ; / / Ba l l e s
. . .
f or ( i nt i =0; i <4; i ++)
BougeBal l e ( x [ i ] , y[ i ] , u[ i ] , v[ i ] ) ;
. . .
dans lequel int x[4] dnit un tableau de 4 variables de type int : x[0], x[1], x[2] et
x[3]. En pratique, le compilateur rserve quelque part en mmoire de quoi stocker les
4 variables en question et gre de quoi faire en sorte que x[ i ] dsigne la bonne variable.
Un autre exemple pour mieux comprendre, qui additionne des double deux par
deux en mmorisant les rsultats :
4.1. Premiers tableaux 4. Les tableaux
double x [ 100] , y [ 100] , z [ 1 0 0 ] ;
. . .
. . . / / i c i , l e s x [ i ] e t y [ i ] pr e nne nt de s v a l e ur s
. . .
f or ( i nt i =0; i <100; i ++)
z [ i ]=x [ i ]+y[ i ] ;
. . .
. . . / / i c i , on u t i l i s e l e s z [ i ]
. . .
Il y deux choses essentielles retenir.
1. Dabord :
les indices dun tableau t de taille n vont de 0 n-1. Tout accs t[n]
peut provoquer une erreur grave pendant lexcution du programme.
CEST UNE DES ERREURS LES PLUS FRQUENTES EN C++. Soit on va
lire ou crire dans un endroit utilis pour une autre variable
a
, soit on
accde une zone mmoire illgale et le programme peut "planter"
b
.
a. Dans lexemple ci-dessus, si on remplaait la boucle pour que i aille de 1 100,
x[100] irait certainement chercher y[0] la place. De mme, z[100] irait peut-tre
chercher la variable i de la boucle, ce qui risquerait de faire ensuite des choses tranges,
i valant nimporte quoi !
b. Ci-dessus, z[i] avec nimporte quoi pour i irait crire en dehors de la zone r-
serve aux donnes, ce qui stopperait le programme plus ou moins dlicatement !
Dans le dernier exemple, on utilise x[0] x[99]. Lhabitude est de faire une boucle
avec i<100 comme test, plutt que i<=99, ce qui est plus lisible. Mais attention
ne pas mettre i<=100 !
2. Ensuite :
un tableau doit avoir une taille xe connue la compilation. Cette taille
peut tre un nombre ou une variable constante, mais pas une variable.
Mme si on pense que le compilateur pourrait connatre la taille, il joue au plus
idiot et naccepte que des constantes :
1 double x [ 1 0 ] , y [ 4 ] , z [ 5 ] ; / / OK
2 const i nt n=5;
3 i nt i [ n] , j [ 2n] , k[ n+1] ; / / OK
4 i nt n1 ; / / n1 n a mme pas de va l e ur
5 i nt t 1 [ n1 ] ; / / donc ERREUR
6 i nt n2 ;
7 ci n >> n2 ; / / n2 prend une val e ur , mai s connue
8 / / uni quement l e x c ut i o n
9 i nt t 2 [ n2 ] ; / / donc ERREUR
10 i nt n3 ;
11 n3=5; / / n3 prend une val e ur , connue
12 / / l e x c ut i o n , mai s . . . non c o ns t a nt e
13 i nt t 3 [ n3 ] ; / / donc ERREUR ( SI ! )
Connaissant ces deux points, on peut trs facilement utiliser des tableaux. Attention
toutefois :
52
4. Les tableaux 4.2. Initialisation
ne pas utiliser de tableau quand cest inutile, notamment quand on traduit
une formule mathmatique.
Je mexplique. Si vous devez calculer s =

100
i=1
f(i) pour f donne
1
, par exemple
f(i) = 3i + 4, nallez pas crire, comme on le voit parfois :
1 double f [ 1 0 0 ] ;
2 f or ( i nt i =1; i <=100; i ++)
3 f [ i ]=3 i +4;
4 double s ;
5 f or ( i nt i =1; i <=100; i ++)
6 s=s+f [ i ] ;
ni, mme, ayant corrig vos bugs :
5 double f [ 1 0 0 ] ; / / St o c k e f ( i ) dans f [ i 1]
6 f or ( i nt i =1; i <=100; i ++)
7 f [ i 1]=3 i +4; / / At t e nt i o n aux i n d i c e s !
8 double s =0; / / Ca va mieux comme ca !
9 f or ( i nt i =1; i <=100; i ++)
10 s=s+f [ i 1] ;
mais plutt directement sans tableau :
5 double s =0;
6 f or ( i nt i =1; i <=100; i ++)
7 s=s +(3 i +4) ;
ce qui pargnera, la machine, un tableau (donc de la mmoire et des calculs), et
vous des bugs (donc vos nerfs !).
4.2 Initialisation
Tout comme une variable, un tableau peut tre initialis :
i nt t [ 4 ] ={ 1 , 2 , 3 , 4 } ;
s t r i ng s [ 2] ={ " hip " , " hop" } ;
Attention, la syntaxe utilise pour linitialisation ne marche pas pour une affecta-
tion
2
:
i nt t [ 2 ] ;
t ={ 1 , 2 } ; / / Er r e ur !
4.3 Spcicits des tableaux
Les tableaux sont des variables un peu spciales. Ils ne se comportent pas toujours
comme les autres variables
3
...
1. Coin des collgiens : cest--dire s = f(1) + f(2) + ... + f(100).
2. Nous verrons plus bas que laffectation ne marche mme pas entre deux tableaux ! Tout ceci sar-
rangera avec les objets...
3. Il est du coup de plus en plus frquent que les programmeurs utilisent directement des variables
de type vector qui sont des objets implmentant les fonctionnalits des tableaux tout en se comportant
53
4.3. Spcicits des tableaux 4. Les tableaux
4.3.1 Tableaux et fonctions
Tout comme les variables, on a besoin de passer les tableaux en paramtres des
fonctions. La syntaxe utiliser est simple :
void a f f i c he ( i nt s [ 4 ] ) {
f or ( i nt i =0; i <4; i ++)
cout << s [ i ] << endl ;
}
. . .
i nt t [ 4 ] ={ 1 , 2 , 3 , 4 } ;
a f f i c he ( t ) ;
mais il faut savoir deux choses :
Un tableau est toujours pass par rfrence bien quon nutilise pas le &
a
.
Une fonction ne peut pas retourner un tableau
b
.
a. Un void f(int& t[4]) ou toute autre syntaxe est une erreur.
b. On comprendra plus tard pourquoi, par soucis defcacit, les concepteurs du C++ ont
voulu quun tableau ne soit ni pass par valeur, ni retourn.
donc :
1 / / Rappe l : c e c i ne marche pas
2 void a f f e c t e 1 ( i nt x , i nt val ) {
3 x=val ;
4 }
5 / / Rappe l : c e s t c e c i qui marche !
6 void a f f e c t e 2 ( i nt& x , i nt val ) {
7 x=val ;
8 }
9 / / Une f o n c t i o n qui marche s ans &
10 void rempl i t ( i nt s [ 4 ] , i nt val ) {
11 f or ( i nt i =0; i <4; i ++)
12 s [ i ]= val ;
13 }
14 . . .
15 i nt a =1;
16 a f f e c t e 1 ( a , 0 ) ; / / a ne s e r a pas mi s 0
17 cout << a << endl ; / / v r i f i c a t i o n
18 a f f e c t e 2 ( a , 0 ) ; / / a s e r a b i e n mi s 0
19 cout << a << endl ; / / v r i f i c a t i o n
20 i nt t [ 4 ] ;
21 rempl i t ( t , 0 ) ; / / Met l e s t [ i ] 0
22 a f f i c he ( t ) ; / / V r i f i e que l e s t [ i ] v a l e nt 0
et aussi :
davantage comme des variables standard. Nous prfrons ne pas parler ds maintenant des vector
car leur comprhension ncessite celle des objets et celle des "template". Nous pensons aussi que la
connaissance des tableaux, mme si elle demande un petit effort, est incontournable et aide la compr-
hension de la gestion de la mmoire.
54
4. Les tableaux 4.3. Spcicits des tableaux
1 / / Somme de deux t a b l e a ux qui ne c o mpi l e mme pas
2 / / Pour r e t o ur ne r un t a b l e a u
3 i nt somme1( i nt x [ 4 ] , i nt y [ 4 ] ) [ 4 ] { / / on pe ut i magi ne r me t t r e l e
4 / / [ 4 ] i c i ou a i l l e u r s :
5 / / r i e n n y f a i t !
6 i nt z [ 4 ] ;
7 f or ( i nt i =0; i <4; i ++)
8 z [ i ]=x [ i ]+y[ i ] ;
9 ret urn z ;
10 }
11 / / En pr a t i q ue , on f e r a donc comme a !
12 / / Somme de deux t a b l e a ux qui marche
13 void somme2( i nt x [ 4 ] , i nt y [ 4 ] , i nt z [ 4 ] )
14 f or ( i nt i =0; i <4; i ++)
15 z [ i ]=x [ i ]+y[ i ] ; / / OK: z e s t pa s s par r f r e n c e !
16 }
17
18 i nt a [ 4 ] , b [ 4 ] ;
19 . . . / / r e mp l i s s a g e de a e t b
20 i nt c [ 4 ] ;
21 c=somme1( a , b ) ; / / ERREUR
22 somme2( a , b , c ) ; / / OK
Enn, et cest utilis tout le temps,
Une fonction nest pas tenue de travailler sur une taille de tableau unique...
mais il est impossible de demander un tableau sa taille !
On utilise la syntaxe int t [] dans les paramtres pour un tableau dont on ne prcise
pas la taille. Comme il faut bien parcourir le tableau dans la fonction et quon ne peut
retrouver sa taille, on la passe en paramtre en plus du tableau :
1 / / Une f o n c t i o n qui ne marche pas
2 void af f i c he 1 ( i nt t [ ] ) {
3 f or ( i nt i =0; i <TAILLE( t ) ; i ++) / / TAILLE( t ) n e x i s t e pas ! ????
4 cout << t [ i ] << endl ;
5 }
6 / / Comment on f a i t en p r a t i q ue
7 void af f i c he 2 ( i nt t [ ] , i nt n) {
8 f or ( i nt i =0; i <n ; i ++)
9 cout << t [ i ] << endl ;
10 }
11 . . .
12 i nt t 1 [ 2 ] ={ 1 , 2 } ;
13 i nt t 2 [ 3 ] ={ 3 , 4 , 5 } ;
14 af f i c he 2 ( t1 , 2 ) ; / / OK
15 af f i c he 2 ( t2 , 3 ) ; / / OK
4.3.2 Affectation
Cest simple :
55
4.4. Rcrations 4. Les tableaux
Affecter un tableau ne marche pas ! Il faut traiter les lments du tableau un
par un...
Ainsi, le programme :
i nt s [ 4 ] ={ 1 , 2 , 3 , 4 } , t [ 4 ] ;
t =s ; / / ERREUR de c o mp i l a t i o n
ne marche pas et on est oblig de faire :
i nt s [ 4 ] ={ 1 , 2 , 3 , 4 } , t [ 4 ] ;
f or ( i nt i =0; i <4; i ++)
t [ i ]=s [ i ] ; / / OK
Le problme, cest que :
Affecter un tableau ne marche jamais mais ne gnre pas toujours une er-
reur de compilation, ni mme un warning. Cest le cas entre deux para-
mtres de fonction. Nous comprendrons plus tard pourquoi et leffet exact
dune telle affectation...
.
1 / / Fo nc t i o n qui ne marche pas
2 / / Mais qui c o mpi l e t r s b i e n !
3 void s et 1 ( i nt s [ 4 ] , i nt t [ 4 ] ) {
4 t =s ; / / Ne f a i t pas c e qu i l f a ut !
5 / / mai s c o mpi l e s ans warni ng !
6 }
7 / / Fo nc t i o n qui marche ( e t qui c o mpi l e ! )
8 void s et 2 ( i nt s [ 4 ] , i nt t [ 4 ] ) {
9 f or ( i nt i =0; i <4; i ++)
10 t [ i ]=s [ i ] ; / / OK
11 }
12 . . .
13 i nt s [ 4 ] ={ 1 , 2 , 3 , 4 } , t [ 4 ] ;
14 s et 1 ( s , t ) ; / / Sans e f f e t
15 s et 2 ( s , t ) ; / / OK
16 . . .
4.4 Rcrations
4.4.1 Multi-balles
Nous pouvons maintenant reprendre le programme de la balle qui rebondit, donn
la section 3.1.4, puis amlior avec des fonctions et de constantes lors du TP de lan-
nexe A.2. Grce aux tableaux, il est facile de faire se dplacer plusieurs balles la fois.
Nous tirons aussi la couleur et la position et la vitesse initiales des balles au hasard.
Plusieurs fonctions devraient vous tre inconnues :
Linitialisation du gnrateur alatoire avec srand((unsigned int)time(0)), qui est
explique dans le TP 3 (annexe A.3)
Les fonctions noRefreshBegin et noRefreshEnd qui servent acclrer lafchage
de toutes les balles (voir documentation de Imagine++ annexe C).
56
4. Les tableaux 4.4. Rcrations
FIGURE 4.1 Des balles qui rebondissent... (momentanment ges ! Allez sur la page
du cours pour un programme anim !)
Voici le listing du programme (exemple dafchage (malheureusement statique !) -
gure 4.1) :
1 # i ncl ude <Imagine/Graphi cs . h>
2 usi ng namespace Imagine ;
3 # i ncl ude <c s t dl i b >
4 # i ncl ude <ctime >
5 usi ng namespace st d ;
6 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
7 / / Co ns t a nt e s du programme
8 const i nt width=256; / / Lar ge ur de l a f e n e t r e
9 const i nt hei ght =256; / / Hauteur de l a f e n e t r e
10 const i nt ba l l _ s i z e =4; / / Rayon de l a b a l l e
11 const i nt nb_bal l s =30; / / Nombre de b a l l e s
12 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
13 / / Ge ne r at e ur a l e a t o i r e
14 / / A n a p p e l e r qu une f o i s , avant Random ( )
15 void InitRandom ( )
16 {
17 srand ( ( unsigned i nt ) time ( 0 ) ) ;
18 }
19 / / Ent r e a e t b
20 i nt Random( i nt a , i nt b)
21 {
22 ret urn a+( rand( ) %( ba +1 ) ) ;
23 }
24 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
25 / / Po s i t i o n e t v i t e s s e a l e a t o i r e
26 void I ni t Ba l l e ( i nt &x , i nt &y , i nt &u, i nt &v , Color &c ) {
27 x=Random( bal l _s i ze , widthba l l _ s i z e ) ;
28 y=Random( bal l _s i ze , hei ght ba l l _ s i z e ) ;
29 u=Random( 0 , 4 ) ;
57
4.4. Rcrations 4. Les tableaux
30 v=Random( 0 , 4 ) ;
31 c=Color ( byte ( Random( 0 , 2 5 5 ) ) ,
32 byte ( Random( 0 , 2 5 5 ) ) ,
33 byte ( Random( 0 , 2 5 5 ) ) ) ;
34 }
35 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
36 / / Af f i c h a g e d une b a l l e
37 void Dessi neBal l e ( i nt x , i nt y , Color col ) {
38 f i l l Re c t ( xbal l _s i ze , ybal l _s i ze , 2 ba l l _ s i z e +1 , 2 ba l l _ s i z e +1 , col ) ;
39 }
40 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
41 / / Depl acement d une b a l l e
42 void BougeBal l e ( i nt &x , i nt &y , i nt &u, i nt &v) {
43 / / Rebond sur l e s bo r ds gauche e t d r o i t
44 i f ( x+u>widthba l l _ s i z e || x+u<ba l l _ s i z e )
45 u=u;
46 / / Rebond sur l e s bo r ds haut e t bas e t compt age du s c o r e
47 i f ( y+v<ba l l _ s i z e || y+v>hei ght ba l l _ s i z e )
48 v=v ;
49 / / Mise a j o ur de l a p o s i t i o n
50 x+=u;
51 y+=v ;
52 }
53 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
54 / / Fo nc t i o n p r i n c i p a l e
55 i nt main ( )
56 {
57 / / Ouvert ure de l a f e n e t r e
58 openWindow( width , hei ght ) ;
59 / / Po s i t i o n e t v i t e s s e de s b a l l e s
60 i nt xb [ nb_bal l s ] , yb[ nb_bal l s ] , ub[ nb_bal l s ] , vb[ nb_bal l s ] ;
61 Color cb [ nb_bal l s ] ; / / Coul e ur s de s b a l l e s
62 InitRandom ( ) ;
63 f or ( i nt i =0; i <nb_bal l s ; i ++) {
64 I ni t Ba l l e ( xb [ i ] , yb[ i ] , ub[ i ] , vb[ i ] , cb [ i ] ) ;
65 Dessi neBal l e ( xb [ i ] , yb[ i ] , cb [ i ] ) ;
66 }
67 / / Bouc l e p r i n c i p a l e
68 while ( t r ue ) {
69 mi l l i Sl ee p ( 2 5 ) ;
70 noRefreshBegi n ( ) ;
71 f or ( i nt i =0; i <nb_bal l s ; i ++) {
72 Dessi neBal l e ( xb [ i ] , yb[ i ] , White ) ;
73 BougeBal l e ( xb [ i ] , yb[ i ] , ub[ i ] , vb[ i ] ) ;
74 Dessi neBal l e ( xb [ i ] , yb[ i ] , cb [ i ] ) ;
75 }
76 noRefreshEnd ( ) ;
77 }
78 endGraphics ( ) ;
58
4. Les tableaux 4.4. Rcrations
79 ret urn 0;
80 }
4.4.2 Avec des chocs !
Il nest ensuite pas trs compliqu de modier le programme prcdent pour que
les balles rebondissent entre-elles. Le listing ci-aprs a t construit comme suit :
1. Lorsquune balle se dplace, on regarde aussi si elle rencontre une autre balle. Il
faut donc que BougeBalle connaisse les positions des autres balles. On modie
donc BougeBalle en passant les tableaux complets des positions et des vitesses,
et en prcisant juste lindice de la balle dplacer (lignes 71 et 110). La boucle
de la ligne 78 vrie ensuite via le test de la ligne 81 si lune des autres balles est
heurte par la balle courante. Auquel cas, on appelle ChocBalles qui modie les
vitesses des deux balles. Notez les lignes 79 et 80 qui vitent de considrer le choc
dune balle avec elle-mme (nous verrons linstruction continue une autre fois).
2. Les formules du choc de deux balles peuvent se trouver facilement dans un cours
de prpa... ou sur le web. La fonction ChocBalles implmente ces formules. (No-
tez linclusion du chier <cmath> pour avoir accs la racine carr sqrt () , aux
sinus et cosinus cos() et sin() , et larc-cosinus acos().
3. On ralise ensuite que les variables entires qui stockent positions et vitesses font
que les erreurs darrondis saccumulent et que les vitesses deviennent nulles ! On
bascule alors toutes les variables concernes en double, en pensant bien les
reconvertir en int lors de lafchage (ligne 37).
Le tout donne un programme bien plus anim. On ne peut videmment constater la
diffrence sur une gure dans un livre. Tlchargez donc le programme sur la page du
cours !
23 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
24 / / Po s i t i o n e t v i t e s s e a l e a t o i r e
25 void I ni t Ba l l e ( double &x , double &y , double &u, double &v , Color &c ) {
26 x=Random( bal l _s i ze , widthba l l _ s i z e ) ;
27 y=Random( bal l _s i ze , hei ght ba l l _ s i z e ) ;
28 u=Random( 0 , 4 ) ;
29 v=Random( 0 , 4 ) ;
30 c=Color ( byte ( Random( 0 , 2 5 5 ) ) ,
31 byte ( Random( 0 , 2 5 5 ) ) ,
32 byte ( Random( 0 , 2 5 5 ) ) ) ;
33 }
34 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
35 / / Af f i c h a g e d une b a l l e
36 void Dessi neBal l e ( double x , double y , Color col ) {
37 f i l l Re c t ( i nt ( x)bal l _s i ze , i nt ( y)bal l _s i ze ,
38 2 ba l l _ s i z e +1 , 2 ba l l _ s i z e +1 , col ) ;
39 }
40 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
41 / / Choc e l a s t i q u e de deux b a l l e s s p h e r i q ue s
42 / / c f l a b o . nt i c . or g
43 # i ncl ude <cmath>
59
4.4. Rcrations 4. Les tableaux
44 void ChocBal l es ( double&x1 , double&y1 , double&u1 , double&v1 ,
45 double&x2 , double&y2 , double&u2 , double&v2 )
46 {
47 / / Di s t a nc e
48 double o2o1x=x1x2 , o2o1y=y1y2 ;
49 double d=s qr t ( o2o1xo2o1x+o2o1yo2o1y ) ;
50 i f ( d==0) ret urn ; / / Mme c e nt r e ?
51 / / Re p r e ( o2 , x , y )
52 double Vx=u1u2 , Vy=v1v2 ;
53 double V=s qr t ( VxVx+VyVy ) ;
54 i f (V==0) ret urn ; / / Mme v i t e s s e
55 / / Re p r e s ui va nt V ( o2 , i , j )
56 double i x=Vx/V, i y=Vy/V, j x=i y , j y=i x ;
57 / / Hauteur d a t t a q ue
58 double H=o2o1x j x+o2o1y j y ;
59 / / Angl e
60 double th=acos (H/d) , c=cos ( th ) , s=si n ( th ) ;
61 / / Vi t e s s e a pr s c hoc dans ( o2 , i , j )
62 double v1i =Vcc , v1j =Vcs , v2i =Vs s , v2j =v1j ;
63 / / Dans r e p r e d o r i g i n e (O, x , y )
64 u1=v1i i x+v1j j x+u2 ;
65 v1=v1i i y+v1j j y+v2 ;
66 u2+=v2i i x+v2j j x ;
67 v2+=v2i i y+v2j j y ;
68 }
69 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
70 / / Depl acement d une b a l l e
71 void BougeBal l e ( double x [ ] , double y [ ] , double u[ ] , double v [ ] , i nt i ) {
72 / / Rebond sur l e s bo r ds gauche e t d r o i t
73 i f ( x [ i ]+u[ i ] >widthba l l _ s i z e || x [ i ]+u[ i ] < ba l l _ s i z e )
74 u[ i ]=u[ i ] ;
75 / / Rebond sur l e s bo r ds haut e t bas e t compt age du s c o r e
76 i f ( y[ i ]+v[ i ] < ba l l _ s i z e || y[ i ]+v[ i ] >hei ght ba l l _ s i z e )
77 v[ i ]=v[ i ] ;
78 f or ( i nt j =0; j <nb_bal l s ; j ++) {
79 i f ( j ==i )
80 cont i nue ;
81 i f ( abs ( x [ i ]+u[ i ]x [ j ] ) <2 ba l l _ s i z e
82 && abs ( y[ i ]+v[ i ]y[ j ] ) <2 ba l l _ s i z e ) {
83 ChocBal l es ( x [ i ] , y[ i ] , u[ i ] , v[ i ] , x [ j ] , y[ j ] , u[ j ] , v[ j ] ) ;
84 }
85 }
86 / / Mise a j o ur de l a p o s i t i o n
87 x [ i ]+=u[ i ] ;
88 y[ i ]+=v[ i ] ;
89 }
90 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
91 / / Fo nc t i o n p r i n c i p a l e
92 i nt main ( )
60
4. Les tableaux 4.4. Rcrations
93 {
94 / / Ouvert ure de l a f e n e t r e
95 openWindow( width , hei ght ) ;
96 / / Po s i t i o n e t v i t e s s e de s b a l l e s
97 double xb [ nb_bal l s ] , yb[ nb_bal l s ] , ub[ nb_bal l s ] , vb[ nb_bal l s ] ;
98 Color cb [ nb_bal l s ] ; / / Coul e ur s de s b a l l e s
99 InitRandom ( ) ;
100 f or ( i nt i =0; i <nb_bal l s ; i ++) {
101 I ni t Ba l l e ( xb [ i ] , yb[ i ] , ub[ i ] , vb[ i ] , cb [ i ] ) ;
102 Dessi neBal l e ( xb [ i ] , yb[ i ] , cb [ i ] ) ;
103 }
104 / / Bouc l e p r i n c i p a l e
105 while ( t r ue ) {
106 mi l l i Sl e ep ( 2 5 ) ;
107 noRefreshBegi n ( ) ;
108 f or ( i nt i =0; i <nb_bal l s ; i ++) {
109 Dessi neBal l e ( xb [ i ] , yb[ i ] , White ) ;
110 BougeBal l e ( xb , yb , ub , vb , i ) ;
111 Dessi neBal l e ( xb [ i ] , yb[ i ] , cb [ i ] ) ;
112 }
113 noRefreshEnd ( ) ;
114 }
115 endGraphics ( ) ;
116 ret urn 0 ;
117 }
4.4.3 Mlanger les lettres
Le programme suivant considre une phrase et permute alatoirement les lettres
intrieures de chaque mot (cest--dire sans toucher aux extrmits des mots). Il utilise
pour cela le type string, chane de caractre, pour lequel s[ i ] renvoie le i-me caractre
de la chane s, et s. size () le nombre de caractres de s (nous expliquerons plus tard la
notation "objet" de cette fonction). La phrase considre ici devient par exemple :
Ctete pteite psahre dreviat erte ecorne libslie puor vorte parvue ceeravu
Lavez vous comprise ? Peu importe ! Cest le listing que vous devez comprendre :
1 # i ncl ude <i ostream>
2 # i ncl ude <s t r i ng >
3 # i ncl ude <c s t dl i b >
4 # i ncl ude <ctime >
5 usi ng namespace st d ;
6
7 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
8 / / Ge ne r at e ur a l e a t o i r e
9 / / A n a p p e l e r qu une f o i s , avant Random ( )
10 void InitRandom ( )
11 {
12 srand ( ( unsigned i nt ) time ( 0 ) ) ;
61
4.5. TP 4. Les tableaux
13 }
14 / / Ent r e a e t b
15 i nt Random( i nt a , i nt b)
16 {
17 ret urn a+( rand( ) %( ba +1 ) ) ;
18 }
19
20 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
21 / / Permut er l e s l e t t r e s i n t e r i e u r e s de s n f o i s
22 s t r i ng Melanger ( s t r i ng s , i nt n)
23 {
24 i nt l =i nt ( s . s i ze ( ) ) ;
25 i f ( l <=3)
26 ret urn s ;
27 s t r i ng t =s ;
28 f or ( i nt i =0; i <n ; i ++) {
29 i nt a=Random( 1 , l 2) ;
30 i nt b ;
31 do
32 b=Random( 1 , l 2) ;
33 while ( a==b ) ;
34 char c=t [ a ] ;
35 t [ a]= t [ b ] ; t [ b]=c ;
36 }
37 ret urn t ;
38 }
39
40 i nt main ( )
41 {
42 const i nt n=11;
43 s t r i ng phrase [ n] ={ " Cet t e " , " pe t i t e " , " phrase " , " devr ai t " , " e t r e " ,
44 " encore " , " l i s i b l e " , " pour " , " vot re " , " pauvre " ,
45 " cerveau " } ;
46
47 InitRandom ( ) ;
48 f or ( i nt i =0; i <n ; i ++)
49 cout << Melanger ( phrase [ i ] , 3 ) << " " ;
50 cout << endl ;
51
52 ret urn 0;
53 }
4.5 TP
Nous pouvons maintenant aller faire le troisime TP donn en annexe A.3 an de
mieux comprendre les tableaux et aussi pour obtenir un master mind (voir gure 4.2
le rsultat dune partie intressante !).
62
4. Les tableaux 4.6. Fiche de rfrence
FIGURE 4.2 Master mind...
4.6 Fiche de rfrence
Comme promis, nous compltons, en rouge, la "che de rfrence" avec ce qui a t
vu pendant ce chapitre et son TP.
Fiche de rfrence (1/3)
Variables
Dnition :
int i;
int k,l,m;
Affectation :
i=2;
j=i;
k=l=3;
Initialisation :
int n=5,o=n;
Constantes :
const int s=12;
Porte :
int i;
// i=j; interdit!
int j=2;
i=j; // OK!
if (j>1) {
int k=3;
j=k; // OK!
}
//i=k; interdit!
Types :
int i=3;
double x=12.3;
char c=A;
string s="hop";
bool t=true;
float y=1.2f;
unsigned int j=4;
signed char d=-128;
unsigned char d=254;
complex<double> z(2,3);
Variables globales :
int n;
const int m=12;
void f() {
n=10; // OK
int i=m; // OK
...
Conversion :
int i=int(x);
int i,j;
double x=double(i)/j;
63
4.6. Fiche de rfrence 4. Les tableaux
Fiche de rfrence (2/3)
Tests
Comparaison :
== != < > <= >=
Ngation : !
Combinaisons : && ||
if (i==0)
j=1;
if (i==0)
j=1;
else
j=2;
if (i==0) {
j=1;
k=2;
}
bool t=(i==0);
if (t)
j=1;
switch (i) {
case 1:
...;
...;
break;
case 2:
case 3:
...;
break;
default:
...;
}
Tableaux
Dnition :
double x[10],y[10];
for(int i=0;i<10;i++)
y[i]=2
*
x[i];
const int n=5;
int i[n],j[2
*
n]; //OK
Initialisation :
int t[4]={1,2,3,4};
string s[2]={"ab","c"};
Affectation :
int s[3]={1,2,3},t[3];
for (int i=0;i<3;i++)
t[i]=s[i];
En paramtre :
void init(int t[4]) {
for(int i=0;i<4;i++)
t[i]=0;
}
void init(int t[],
int n) {
for(int i=0;i<n;i++)
t[i]=0;
}
Boucles
do {
...
} while (!ok);
int i=1;
while (i<=100) {
...
i=i+1;
}
for (int i=1;i<=10;i++)
...
for (int i=1,j=10;j>i;
i=i+2,j=j-3)
...
Fonctions
Dnition :
int plus(int a,int b) {
int c=a+b;
return c;
}
void affiche(int a) {
cout << a << endl;
}
Dclaration :
int plus(int a,int b);
Retour :
int signe(double x) {
if (x<0)
return -1;
if (x>0)
return 1;
return 0;
}
void afficher(int x,
int y) {
if (x<0 || y<0)
return;
if (x>=w || y>=h)
return;
DrawPoint(x,y,RED);
}
Appel :
int f(int a) { ... }
int g() { ... }
...
int i=f(2),j=g();
Rfrences :
void swap(int& a,
int& b){
int tmp=a;
a=b;b=tmp;
}
...
int x=3,y=2;
swap(x,y);
Surcharge :
int hasard(int n);
int hasard(int a,
int b);
double hasard();
Divers
i++;
i--;
i-=2;
j+=3;
j=i%n; // Modulo
#include <cstdlib>
...
i=rand()%n;
x=rand()/
double(RAND_MAX);
#include <ctime>
...
srand((unsigned int)
time(0));
#include <cmath>
double sqrt(double x);
double cos(double x);
double sin(double x);
double acos(double x);
#include <string>
using namespace std;
string s="hop";
char c=s[0];
int l=s.size();
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
64
4. Les tableaux 4.6. Fiche de rfrence
Fiche de rfrence (3/3)
Erreurs frquentes
Pas de dnition de fonction
dans une fonction!
int q=r=4; // NON!
if (i=2) // NON!
if i==2 // NON!
if (i==2) then // NON!
for (int i=0,i<100,i++)
// NON!
int f() {...}
...
int i=f; // NON!
double x=1/3; // NON!
int i,j;
double x;
x=i/j; // NON!
x=double(i/j); //NON!
double x[10],y[10];
for (int i=1;i<=10;i++)
y[i]=2
*
x[i]; //NON
int n=5;
int t[n]; // NON
int f()[4] { // NON!
int t[4];
...
return t; // NON!
}
int t[4]; t=f();
int s[3]={1,2,3},t[3];
t=s; // NON!
int t[2];
t={1,2}; // NON!
Imagine++
Voir documentation...
Clavier
Build : F7
Debug : F5
Step over : F10
Step inside : F11
Indent : Ctrl+K,Ctrl+F
Conseils
Travailler en local
Imagine++ Project
Nettoyer en quittant.
Erreurs et warnings : cliquer.
Indenter.
Ne pas laisser de warning.
Utiliser le debuggeur.
Faire des fonctions.
Tableaux : pas pour transcrire
une formule mathmatique !
65
5. Les structures
Chapitre 5
Les structures
Les fonctions et les boucles nous ont permis de regrouper des instructions identiques. Les
tableaux permettent de grouper des variables de mme type, mais pour manipuler plusieurs va-
riables simultanment, il est tout aussi indispensable des fabriquer des structures de donnes...

5.1 Rvisions
Avant cela, il est utile de nous livrer une petite rvision, qui prendra la forme dun
inventaire des erreurs classiques commises par de nombreux dbutants... et mme de
celles, plus rares mais plus originales, constates chez certains ! Enn, nous rpterons,
encore et toujours, les mmes conseils.
5.1.1 Erreurs classiques
En vrac :
Mettre un seul = dans les tests : if ( i=2)
Oublier les parenthses : if i==2
Utiliser then : if ( i==2) then
Mettre des virgules dans un for : for ( int i=0, i<100,i++)
Oublier les parenthses quand on appelle une fonction sans paramtre :
i nt f ( ) { . . . }
. . .
i nt i =f ;
Vouloir affecter un tableau un autre :
i nt s [ 4 ] ={ 1 , 2 , 3 , 4 } , t [ 4 ] ;
t =s ;
5.1.2 Erreurs originales
L, le dbutant ne se trompe plus : il invente carrment avec sans doute le fol espoir
que a existe peut-tre. Souvent, non seulement a nexiste pas, mais en plus a ne colle
ni aux grands principes de la syntaxe du C++, ni mme ce quun compilateur peut
comprendre ! Deux exemples :
5.1. Rvisions 5. Les structures
Mlanger la syntaxe (si peu!) :
void s et ( i nt t [ 5 ] ) {
. . .
}
. . .
i nt s [ 5 ] ; / / J us que l , t o ut va b i e n !
s et ( i nt s [ 5 ] ) ; / / L , c e s t quand mme n i mpo r t e quoi !
alors quil suft dun :
s et ( s ) ;
Vouloir faire plusieurs choses la fois, ou ne pas comprendre quun programme
est une suite dinstructions excuter lune aprs lautre et non pas une for-
mule
1
. Par exemple, croire que le for est un symbole mathmatique comme

n
1
ou

n
1
. Ainsi, pour excuter une instruction quand tous les ok(i ) sont vrais, on a
dj vu tenter un :
i f ( f or ( i nt i =0; i <n ; i ++) ok ( i ) ) / / Du grand a r t . . .
. . .
alors quil faut faire :
bool al l ok=t r ue ;
f or ( i nt i =0; i <n ; i ++)
al l ok =( al l ok && ok ( i ) ) ;
i f ( al l ok )
. . .
ou mme mieux (voyez-vous la diffrence ?) :
bool al l ok=t r ue ;
f or ( i nt i =0; i <n && al l ok ; i ++)
al l ok =( al l ok && ok ( i ) ) ;
i f ( al l ok )
. . .
quon peut nalement simplier en :
bool al l ok=t r ue ;
f or ( i nt i =0; i <n && al l ok ; i ++)
al l ok=ok ( i ) ;
i f ( al l ok )
. . .
Il est comprhensible que le dbutant puisse tre victime de son manque de savoir,
dune mauvaise assimilation des leons prcdentes, de la confusion avec un autre
langage, ou de son imagination dbordante ! Toutefois, il faut bien comprendre quun
langage est nalement lui aussi un programme, limit et conu pour faire des choses
bien prcises. En consquence, il est plus raisonnable dadopter la conduite suivante :
Tout ce qui na pas t annonc comme possible est impossible !
1. Ne me fates pas dire ce que je nai pas dit ! Les informaticiens thoriques considrent parfois les
programmes comme des formules, mais a na rien voir !
68
5. Les structures 5.2. Les structures
5.1.3 Conseils
Indenter. Indenter. Indenter !
Cliquer sur les messages derreurs et de warnings pour aller directement la
bonne ligne !
Ne pas laisser de warning.
Utiliser le debuggeur.
5.2 Les structures
5.2.1 Dnition
Si les tableaux permettent de manipuler plusieurs variables dun mme type, les
structures sont utilises pour regrouper plusieurs variables an de les manipuler comme
une seule. On cre un nouveau type, dont les variables en question deviennent des
"sous-variables" appeles champs de la structure. Voici par exemple un type Point pos-
sdant deux champs de type double nomms x et y :
s t r uc t Poi nt {
double x , y ;
} ;
Les champs se dnissent avec la syntaxe des variables locales dune fonction. Atten-
tion par contre
Ne pas oublier le point virgule aprs laccolade qui ferme la dnition de la
structure !
Lutilisation est alors simple. La structure est un nouveau type qui se manipule exacte-
ment comme les autres, avec la particularit supplmentaire quon accde aux champs
avec un point :
Poi nt a ;
a . x =2. 3;
a . y =3. 4;
On peut videmment dnir des champs de diffrents types, et mme des structures
dans des structures :
s t r uc t Cercl e {
Poi nt cent r e ;
double rayon ;
Color coul eur ;
} ;
Cercl e C;
C. cent r e . x =12. ;
C. cent r e . y =13. ;
C. rayon =10. 4;
C. coul eur=Red ;
Lintrt des structures est vident et il faut
69
5.2. Les structures 5. Les structures
Regrouper dans des structures des variables ds quon repre quelles sont
logiquement lies. Si un programme devient pnible parce quon passe
systmatiquement plusieurs paramtres identiques de nombreuses fonc-
tions, alors il est vraisemblable que les paramtres en question puissent
tre avantageusement regroups en une structure. Ce sera plus simple et
plus clair.
5.2.2 Utilisation
Les structures se manipulent comme les autres types
2
. La dnition, laffectation,
linitialisation, le passage en paramtre, le retour dune fonction : tout est semblable
au comportement des types de base. Seule nouveaut : on utilise des accolades pour
prciser les valeurs des champs en cas dinitialisation
3
. On peut videmment faire
des tableaux de structures... et mme dnir un champ de type tableau! Ainsi, les
lignes suivantes se comprennent facilement :
Poi nt a ={ 2 . 3 , 3 . 4 } , b=a , c ; / / I n i t i a l i s a t i o n s
c=a ; / / Af f e c t a t i o n s
Cercl e C={ { 1 2 , 1 3 } , 1 0 . 4 , Red } ; / / I n i t i a l i s a t i o n
. . .
double di st ance ( Poi nt a , Poi nt b) { / / Pas s age par va l e ur
ret urn s qr t ( ( a . xb . x ) ( a . xb . x ) +( a . yb . y ) ( a . yb . y ) ) ;
}
void agrandi r ( Cercl e& C, double e c he l l e ) { / / Par r f r e n c e
C. rayon=C. rayon e c he l l e ; / / Mo di f i e l e rayon
}
Poi nt mi l i eu ( Poi nt a , Poi nt b) { / / r e t o ur
Poi nt M;
M. x=( a . x+b . x ) /2;
M. y=( a . y+b . y) /2;
ret urn M;
}
. . .
Poi nt P[ 1 0 ] ; / / Tabl e au de s t r u c t u r e s
f or ( i nt i =0; i <10; i ++) {
P[ i ] . x=i ;
P[ i ] . y=f ( i ) ;
}
. . .
/ / Un d but de j e u de Yam s
s t r uc t Ti rage { / /
i nt de [ 5 ] ; / / champ de t ype t a b l e a u
} ;
Ti rage l ancer ( ) {
Ti rage t ;
f or ( i nt i =0; i <5; i ++)
2. Dailleurs, nous avions bien promis que seuls les tableaux avaient des particularits (passage par
rfrence, pas de retour possible et pas daffectation.
3. Comme pour un tableau!
70
5. Les structures 5.3. Rcration : TP
FIGURE 5.1 Corps clestes et duel...
t . de [ i ]=1+rand ( ) %6; / / Un d de 1 6
ret urn t ;
}
. . .
Ti rage t ;
t =l ancer ( ) ;
. . .
Attention, tout comme pour les tableaux, la syntaxe utilise pour linitialisation ne
marche pas pour une affectation
4
:
Poi nt P;
P={ 1 , 2 } ; / / Er r e ur !
Dailleurs, rptons-le :
Tout ce qui na pas t annonc comme possible est impossible !
5.3 Rcration : TP
Nous pouvons maintenant aller faire le TP donn en annexe A.4 an de mieux com-
prendre les structures. Nous ferons mme des tableaux de structures
5
! Nous obtien-
drons un projectile naviguant au milieu des toiles puis un duel dans lespace (gure
5.1) !
4. La situation samliorera avec les objets.
5. Coin des collgiens : il y a dans ce TP des mathmatiques et de la physique pour tudiant de
lenseignement suprieur... mais on peut trs bien faire les programmes en ignorant tout a !
71
5.4. Fiche de rfrence 5. Les structures
5.4 Fiche de rfrence
Encore une fois, nous compltons, en rouge, la "che de rfrence" avec ce qui a t
vu pendant ce chapitre et son TP.
Fiche de rfrence (1/2)
Variables
Dnition :
int i;
int k,l,m;
Affectation :
i=2;
j=i;
k=l=3;
Initialisation :
int n=5,o=n;
Constantes :
const int s=12;
Porte :
int i;
// i=j; interdit!
int j=2;
i=j; // OK!
if (j>1) {
int k=3;
j=k; // OK!
}
//i=k; interdit!
Types :
int i=3;
double x=12.3;
char c=A;
string s="hop";
bool t=true;
float y=1.2f;
unsigned int j=4;
signed char d=-128;
unsigned char d=254;
complex<double> z(2,3);
Variables globales :
int n;
const int m=12;
void f() {
n=10; // OK
int i=m; // OK
...
Conversion :
int i=int(x);
int i,j;
double x=double(i)/j;
Tests
Comparaison :
== != < > <= >=
Ngation : !
Combinaisons : && ||
if (i==0)
j=1;
if (i==0)
j=1;
else
j=2;
if (i==0) {
j=1;
k=2;
}
bool t=(i==0);
if (t)
j=1;
switch (i) {
case 1:
...;
...;
break;
case 2:
case 3:
...;
break;
default:
...;
}
Boucles
do {
...
} while (!ok);
int i=1;
while (i<=100) {
...
i=i+1;
}
for (int i=1;i<=10;i++)
...
for (int i=1,j=10;j>i;
i=i+2,j=j-3)
...
Fonctions
Dnition :
int plus(int a,int b) {
int c=a+b;
return c;
}
void affiche(int a) {
cout << a << endl;
}
Dclaration :
int plus(int a,int b);
Retour :
int signe(double x) {
if (x<0)
return -1;
if (x>0)
return 1;
return 0;
}
void afficher(int x,
int y) {
if (x<0 || y<0)
return;
if (x>=w || y>=h)
return;
DrawPoint(x,y,RED);
}
Appel :
int f(int a) { ... }
int g() { ... }
...
int i=f(2),j=g();
Rfrences :
void swap(int& a,
int& b){
int tmp=a;
a=b;b=tmp;
}
...
int x=3,y=2;
swap(x,y);
Surcharge :
int hasard(int n);
int hasard(int a,
int b);
double hasard();
72
5. Les structures 5.4. Fiche de rfrence
Fiche de rfrence (2/2)
Tableaux
Dnition :
double x[10],y[10];
for(int i=0;i<10;i++)
y[i]=2
*
x[i];
const int n=5;
int i[n],j[2
*
n]; //OK
Initialisation :
int t[4]={1,2,3,4};
string s[2]={"ab","c"};
Affectation :
int s[3]={1,2,3},t[3];
for (int i=0;i<3;i++)
t[i]=s[i];
En paramtre :
void init(int t[4]) {
for(int i=0;i<4;i++)
t[i]=0;
}
void init(int t[],
int n) {
for(int i=0;i<n;i++)
t[i]=0;
}
Structures
struct Point {
double x,y;
Color c;
};
...
Point a;
a.x=2.3; a.y=3.4;
a.c=Red;
Point b={1,2.5,Blue};
Divers
i++;
i--;
i-=2;
j+=3;
j=i%n; // Modulo
#include <cstdlib>
...
i=rand()%n;
x=rand()/
double(RAND_MAX);
#include <ctime>
...
srand((unsigned int)
time(0));
#include <cmath>
double sqrt(double x);
double cos(double x);
double sin(double x);
double acos(double x);
#include <string>
using namespace std;
string s="hop";
char c=s[0];
int l=s.size();
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
Erreurs frquentes
Pas de dnition de fonction
dans une fonction!
int q=r=4; // NON!
if (i=2) // NON!
if i==2 // NON!
if (i==2) then // NON!
for (int i=0,i<100,i++)
// NON!
int f() {...}
...
int i=f; // NON!
double x=1/3; // NON!
int i,j;
double x;
x=i/j; // NON!
x=double(i/j); //NON!
double x[10],y[10];
for (int i=1;i<=10;i++)
y[i]=2
*
x[i]; //NON
int n=5;
int t[n]; // NON
int f()[4] { // NON!
int t[4];
...
return t; // NON!
}
int t[4]; t=f();
int s[3]={1,2,3},t[3];
t=s; // NON!
int t[2];
t={1,2}; // NON!
struct Point {
double x,y;
} // NON!
Point a;
a={1,2}; // NON!
Imagine++
Voir documentation...
Clavier
Build : F7
Debug : F5
Step over : F10
Step inside : F11
Indent : Ctrl+K,Ctrl+F
Conseils
Travailler en local
Imagine++ Project
Nettoyer en quittant.
Erreurs et warnings : cliquer.
Indenter.
Ne pas laisser de warning.
Utiliser le debuggeur.
Faire des fonctions.
Tableaux : pas pour transcrire
une formule mathmatique !
Faire des structures.
73
6. Plusieurs chiers !
Chapitre 6
Plusieurs chiers !
Lors du dernier TP, nous avons ralis deux projets quasiment similaires dont seuls les
main() taient diffrents. Modier aprs coup une des fonctions de la partie commune aux
deux projets ncessiterait daller la modier dans les deux projets. Nous allons voir maintenant
comment factoriser cette partie commune dans un seul chier, de faon en simplier les ven-
tuelles futures modications. Au passage
1
nous verrons comment dnir un oprateur sur de
nouveaux types.

Rsumons notre progression dans le savoir-faire du programmeur :


1. Tout programmer dans le main() : cest un dbut et cest dj bien!
2. Faire des fonctions : pour tre plus lisible et ne pas se rpter ! (Axe des instruc-
tions)
3. Faire des tableaux et des structures : pour manipuler plusieurs variables la fois.
(Axe des donnes)
Nous rajoutons maintenant :
4. Faire plusieurs chiers : pour utiliser des parties communes dans diffrents pro-
jets ou solutions. (A nouveau, axe des instructions)
FIGURE 6.1 Plusieurs chiers sources...
1. Toujours cette ide que nous explorons les diffrentes composantes du langages quand le besoin
sen fait sentir.
6.1. Fichiers spars 6. Plusieurs chiers !
6.1 Fichiers spars
Nous allons rpartir notre code source dans plusieurs chiers. Mais avant toute
chose :
Pour un maximum de portabilit du code, choisir des noms de chiers avec
seulement des caractres standard (pas de lettres accentues ni despace)
Dailleurs il est aussi prfrable dviter les accents pour les noms de variables et de
fonctions, tant pis pour la correction du franais...
6.1.1 Principe
Jusqu prsent un seul chier source contenait notre programme C++. Ce chier
source tait transform en chier objet par le compilateur puis le linker compltait le
chier objet avec les bibliothques du C++ pour en faire un chier excutable. En fait,
un projet peut contenir plusieurs chiers sources. Il suft pour cela de rajouter un
chier .cpp la liste des sources du projet :
Ouvrir le menu Project/Add New Item ou faire Ctrl+Maj+A ou cliquer sur
Choisir lajout dun chier Visual C++/Code/C++ le et en prciser le nom
(sans quil soit besoin de prciser .cpp dans le nom)
Ainsi, en rajoutant un chier C++ hop un projet contenant dj main.cpp, on se
retrouve avec une structure de projet identique celle de la gure 6.1.
Aprs cela, chaque gnration du projet consistera en :
1. Compilation : chaque chier source est transform en un chier objet (de mme
nom mais de sufxe .obj). Les chiers sources sont donc compils indpendam-
ment les uns des autres.
2. Link : les diffrents chiers objets sont runis (et complts avec les bibliothques
du C++) en un seul chier excutable (de mme nom que le projet).
Une partie des instructions du chier principal (celui qui contient main()) peut donc
tre dporte dans un autre chier. Cette partie sera compile sparment et rintgre
pendant ldition des liens. Se pose alors le problme suivant : comment utiliser dans
le chier principal ce qui ce trouve dans les autres chiers ? En effet, nous savions
(cf section 3.2.4) quune fonction ntait "connue" que dans les lignes qui suivaient
sa dnition ou son ventuelle dclaration. Par "connue", il faut comprendre que le
compilateur sait quil existe ailleurs une fonction de tel nom avec tel type de retour et
tels paramtres. Malheureusement
2
:
une fonction nest pas "connue" en dehors de son chier. Pour lutiliser dans
un autre chier, il faut donc ly dclarer !
En clair, nous allons devoir procder ainsi :
Fichier hop.cpp :
2. Heureusement, en fait, car lorsque lon runit des chiers de provenances multiples, il est prf-
rable que ce qui se trouve dans les diffrents chiers ne se mlange pas de faon anarchique...
76
6. Plusieurs chiers ! 6.1. Fichiers spars
/ / D f i n i t i o n s
void f ( i nt x ) {
. . .
}
i nt g ( ) {
. . .
}
/ / Aut r e s f o n c t i o n s
. . .
Fichier main.cpp :
/ / D c l a r a t i o ns
void f ( i nt x ) ;
i nt g ( ) ;
. . .
i nt main ( ) {
. . .
/ / Ut i l i s a t i o n
i nt a=g ( ) ;
f ( a ) ;
. . .
Nous pourrions aussi videmment dclarer dans hop.cpp certaines fonctions de main.cpp
pour pouvoir les utiliser. Attention toutefois : si des chiers sutilisent de faon croise,
cest peut-tre que nous sommes en train de ne pas dcouper les sources convenable-
ment.
6.1.2 Avantages
Notre motivation initiale tait de mettre une partie du code dans un chier spar
pour lutiliser dans un autre projet. En fait, dcouper son code en plusieurs chiers a
dautres intrts :
Rendre le code plus lisible et vitant les chiers trop longs et en regroupant les
fonctions de faon structure.
Acclrer la compilation. Lorsquun programme devient long et complexe, le
temps de compilation nest plus ngligeable. Or, lorsque lon rgnre un projet,
lenvironnement de programmation ne recompile que les chiers sources qui ont
t modis depuis la gnration prcdente. Il serait en effet inutile de recompi-
ler un chier source non modi pour ainsi obtenir le mme chier objet
3
! Donc
changer quelques lignes dans un chier nentranera pas la compilation de tout
le programme mais seulement du chier concern
4
.
Attention toutefois ne pas sparer en de trop nombreux chiers ! Il devient alors plus
compliqu de sy retrouver et de naviguer parmi ces chiers.
3. Cest en ralit un peu plus compliqu : un source peu dpendre, via des inclusions (cf section
6.1.4), dautres chiers, qui, eux, peuvent avoir t modis ! Il faut alors recompiler un chier dont une
dpendance a t modie. Visual gre automatiquement ces dpendances (Cest plus compliqu, mais
possible aussi, sous linux...)
4. En fait, Visual est mme capable de ne recompiler que certaines parties du chier quand les modi-
cations apportes sont simples...
77
6.1. Fichiers spars 6. Plusieurs chiers !
FIGURE 6.2 Mme source dans deux projets
6.1.3 Utilisation dans un autre projet
Pour utiliser dans un projet 2 un chier source dun projet 1, il suft de rajouter le
source en question dans la liste des sources du projet 2 ! Pour cela, aprs avoir slec-
tionn le projet 2 :
Choisir le menu Project/Add Existing Item (ou Alt+Maj+A ou )
Slectionner le chier source.
ou plus simplement :
Avec la souris, glisser/dplacer le chier entre les deux projets
5
en maintenant
la touche Ctrl enfonce (un + apparat).
On obtient le rsultat gure 6.2.
Attention : il faut bien comprendre que
le chier ainsi partag reste dans le rpertoire du premier projet
comme le conrme lafchage de ses proprits ( droite gure 6.2). Dans notre exemple,
chaque projet a son propre chier principal, main.cpp ou main2.cpp, mais il y a un
seul hop.cpp. Modier le contenu de ce chier aura des consquences sur les deux
projets la fois. Cest ce que nous voulions !
6.1.4 Fichiers den-ttes
Le chier spar nous permet de factoriser une partie du source. Toutefois, il faut
taper les dclarations de toutes les fonctions utilises dans chaque chier principal les
utilisant. Nous pouvons mieux faire
6
. Pour cela, il est temps dexpliquer ce que fait
linstruction #include que nous rencontrons depuis nos dbuts :
La ligne #include "nom" est automatiquement remplace par le contenu
du chier nom avant de procder la compilation.
Il sagit bien de remplacer par le texte complet du chier nom comme avec un simple
copier/coller. Cette opration est faite avant la compilation par un programme dont
nous navions pas parl : le pr-processeur. La plupart des lignes commenant par un #
lui seront destines. Nous en verrons dautres. Attention : jusquici nous utilisions une
5. On peut aussi glisser/dplacer le chier depuis lexplorateur Windows
6. Toujours le moindre effort...
78
6. Plusieurs chiers ! 6.1. Fichiers spars
forme lgrement diffrente : #include <nom>, qui va chercher le chier nom dans les
rpertoires des bibliothques C++
7
.
Grce cette possibilit du pr-processeur, il nous suft de mettre les dclarations
se rapportant au chier spar dans un troisime chier et de linclure dans les -
chiers principaux. Il est dusage de prendre pour ce chier supplmentaire le mme
nom que le chier spar, mais avec lextension .h : on appelle ce chier un chier
den-tte
8
. Pour crer ce chier, faire comme pour le source, mais en choisissant "Vi-
sual C++/Code/Header le" au lieu de "Visual C++/Code/C++ le". Voila ce que cela
donne :
Fichier hop.cpp :
/ / D f i n i t i o n s
void f ( i nt x ) {
. . .
}
i nt g ( ) {
. . .
}
/ / Aut r e s f o n c t i o n s
. . .
Fichier hop.h :
/ / D c l a r a t i o ns
void f ( i nt x ) ;
i nt g ( ) ;
Fichier main.cpp du premier projet :
# i ncl ude " hop . h"
. . .
i nt main ( ) {
. . .
/ / Ut i l i s a t i o n
i nt a=g ( ) ;
f ( a ) ;
. . .
Fichier main2.cpp du deuxime projet (il faut prciser lemplacement complet
de len-tte, qui se trouve dans le rpertoire du premier projet
9
) :
# i ncl ude " . . / Pr oj ec t 1/hop . h"
. . .
i nt main ( ) {
. . .
/ / Ut i l i s a t i o n
f ( 1 2 ) ;
7. Les chiers den-tte iostream, etc. sont parfois appels en-ttes systme. Leur nom ne se termine
pas toujours par .h (voir aprs)
8. .h comme header.
9. On peut aussi prciser au compilateur une liste de rpertoires o il peut aller chercher les chiers
den-tte. Utiliser pour cela les proprits du projet, option "C/C++ / General / Additional
Include Directories" en prcisant "../Project1" comme rpertoire. Aprs quoi, un #include
"hop.h" suft.
79
6.1. Fichiers spars 6. Plusieurs chiers !
i nt b=g ( ) ;
. . .
En fait, pour tre sur que les fonctions dnies dans hop.cpp sont cohrentes avec
leur dclaration dans hop.h, et bien que a soit pas obligatoire, on inclut aussi len-
tte dans le source, ce qui donne :
Fichier hop.cpp :
# i ncl ude " hop . h"
. . .
/ / D f i n i t i o n s
void f ( i nt x ) {
. . .
}
i nt g ( ) {
. . .
}
/ / Aut r e s f o n c t i o n s
. . .
En pratique, le chier den-tte ne contient pas seulement les dclarations des fonc-
tions mais aussi les dnitions des nouveaux types (comme les structures) utiliss par
le chier spar. En effet, ces nouveaux types doivent tre connus du chier spar,
mais aussi du chier principal. Il faut donc vraiment :
1. Mettre dans len-tte les dclarations des fonctions et les dnitions
des nouveaux types.
2. Inclure len-tte dans le chier principal mais aussi dans le chier s-
par.
Cela donne par exemple :
Fichier vect.h :
/ / Types
s t r uc t Vecteur {
double x , y ;
} ;
/ / D c l a r a t i o ns
double norme ( Vecteur V) ;
Vecteur pl us ( Vecteur A, Vecteur B ) ;
Fichier vect.cpp :
# i ncl ude " vect . h" / / Fo nc t i o ns e t t ype s
/ / D f i n i t i o n s
double norme ( Vecteur V) {
. . .
}
Vecteur pl us ( Vecteur A, Vecteur B) {
. . .
}
/ / Aut r e s f o n c t i o n s
. . .
80
6. Plusieurs chiers ! 6.1. Fichiers spars
Fichier main.cpp du premier :
# i ncl ude " vect . h"
. . .
i nt main ( ) {
. . .
/ / Ut i l i s a t i o n
Vecteur C=pl us (A, B ) ;
double n=norme (C) ;
. . .
6.1.5 A ne pas faire...
Il est "fortement" conseill de :
1. ne pas dclarer dans len-tte toutes les fonctions du chier spar mais seule-
ment celles qui seront utilises par le chier principal. Les fonctions secondaires
nont pas apparatre
10
.
2. ne jamais inclure un chier spar lui-mme ! Cest gnralement une "grosse
btise"
11
. Donc
pas de #include "vect.cpp"!
6.1.6 Implmentation
Finalement, la philosophie de ce systme est que
Le chier spar et son en-tte forment un tout cohrent, implmentant
un certain nombre de fonctionnalits.
Celui qui les utilise, qui nest pas ncessairement celui qui les a program-
mes, se contente de rajouter ces chiers son projet, dinclure len-tte
dans ses sources et de proter de ce que len-tte dclare.
Le chier den-tte doit tre sufsamment clair et informatif pour que
lutilisateur nait pas regarder le chier spar lui-mme
a
.
a. Dailleurs, si lutilisateur le regarde, il peut tre tent de tirer prot de ce qui sy trouve et
dutiliser plus que ce que len-tte dclare. Or, le crateur du chier spar et de len-tte peut
par la suite tre amen changer dans son source la faon dont il a programm les fonctions
sans pour autant changer leurs fonctionnalits. Lutilisateur qui a "trich" en allant regarder
dans le chier spar peut alors voir ses programmes ne plus marcher. Il na pas respect la
rgle du jeu qui tait de nutiliser que les fonctions de len-tte sans savoir comment elles sont
implmentes. Nous reparlerons de tout a avec les objets. Nous pourrons alors faire en sorte
que lutilisateur ne triche pas... De toute faon, notre niveau actuel, le crateur et lutilisateur
sont une seule et mme personne. A elle de ne pas tricher !
10. On devrait mme tout faire pour bien les cacher et pour interdire au chier principal de les utiliser.
Il serait possible de le faire ds maintenant, mais nous en reparlerons plutt quand nous aborderons les
objets...
11. Une mme fonction peut alors se retrouver dnie plusieurs fois : dans le chier spar et dans le
chier principal qui linclut. Or, sil est possible de dclarer autant de fois que ncessaire une fonction, il
est interdit de la dnir plusieurs fois (ne pas confondre avec la surcharge qui rend possible lexistence
de fonctions diffrentes sous le mme nom - cf section 3.2.6)
81
6.2. Oprateurs 6. Plusieurs chiers !
6.1.7 Inclusions mutuelles
En passant laction, le dbutant dcouvre souvent des problmes non prvus lors
du cours. Il est mme en gnral imbattable pour cela ! Le problme le plus frquent
qui survient avec les chiers den-tte est celui de linclusion mutuelle. Il arrive que les
chiers den-tte aient besoin den inclure dautres eux-mmes. Or, si le chier A.h
inclut B.h et si B.h inclut A.h alors toute inclusion de A.h ou de B.h se solde par une
phnomne dinclusions sans n qui provoque une erreur
12
. Pour viter cela, on utilise
une instruction du pr-processeur signalant quun chier dj inclus ne doit plus ltre
nouveau : on ajoute
#pragma once au dbut de chaque chier den-tte.
Certains compilateurs peuvent ne pas connatre #pragma once. On utilise alors une
astuce que nous donnons sans explication :
Choisir un nom unique propre au chier den-tte. Par exemple VECT_H pour le
chier vect.h.
Placer #ifndef VECT_Het #dene VECT_Hau dbut du chier vect.h et #endif
la n.
6.2 Oprateurs
Le C++ permet de dnir les oprateurs +, -, etc. quand les oprandes sont de nou-
veaux types. Voici trs succinctement comment faire. Nous laissons au lecteur le soin
de dcouvrir seul quels sont les oprateurs quil est possible de dnir.
Considrons lexemple suivant qui dnit un vecteur
13
2D et en implmente lad-
dition :
s t r uc t vect {
double x , y ;
} ;
vect pl us ( vect m, vect n) {
vect p={m. x+n . x ,m. y+n . y } ;
ret urn p;
}
i nt main ( ) {
vect a ={ 1 , 2} , b ={ 3 , 4 } ;
vect c=pl us ( a , b ) ;
ret urn 0;
}
Voici comment dnir le + entre deux vect et ainsi remplacer la fonction plus() :
s t r uc t vect {
double x , y ;
} ;
vect operat or +( vect m, vect n) {
12. Les pr-processeurs savent heureusement dtecter ce cas de gure.
13. Coin des collgiens : vous ne savez pas ce quest un vecteur... mais vous tes plus forts en pro-
grammation que les "vieux". Alors regardez les sources qui suivent et vous saurez ce quest un vecteur
2D!
82
6. Plusieurs chiers ! 6.3. Rcration : TP suite et n
vect p={m. x+n . x ,m. y+n . y } ;
ret urn p;
}
i nt main ( ) {
vect a ={ 1 , 2} , b ={ 3 , 4 } ;
vect c=a+b ;
ret urn 0;
}
Nous pouvons aussi dnir un produit par un scalaire, un produit scalaire
14
, etc
15
.
/ / Pr o dui t par un s c a l a i r e
vect operat or ( double s , vect m) {
vect p={ s m. x , s m. y } ;
ret urn p;
}
/ / Pr o dui t s c a l a i r e
double operat or ( vect m, vect n) {
ret urn m. xn . x+m. yn . y ;
}
i nt main ( ) {
vect a ={ 1 , 2} , b ={ 3 , 4 } ;
vect c=2a ;
double s=ab ;
ret urn 0;
}
Remarquez que les deux fonctions ainsi dnies sont diffrentes bien que de mme
nom(operator) car elles prennent des paramtres diffrents (cf surcharge section 3.2.6).
6.3 Rcration : TP suite et n
Le programme du TP prcdent tant un exemple parfait de besoin de chiers spa-
rs (structures bien identies, partages par deux projets), nous vous proposons, dans
le TP A.5 de convertir (et terminer ?) notre programme de simulation de gravitation et
de duel dans lespace !
6.4 Fiche de rfrence
La che habituelle...
14. Dans ce cas, on utilise a
*
b et non a.b, le point ntant pas dnissable car rserv laccs aux
champs de la structure
15. On peut en fait dnir ce qui existe dj sur les types de base. Attention, il est impossible de
rednir les oprations des types de base ! Pas question de donner un sens diffrent 1+1.
83
6.4. Fiche de rfrence 6. Plusieurs chiers !
Fiche de rfrence (1/2)
Variables
Dnition :
int i;
int k,l,m;
Affectation :
i=2;
j=i;
k=l=3;
Initialisation :
int n=5,o=n;
Constantes :
const int s=12;
Porte :
int i;
// i=j; interdit!
int j=2;
i=j; // OK!
if (j>1) {
int k=3;
j=k; // OK!
}
//i=k; interdit!
Types :
int i=3;
double x=12.3;
char c=A;
string s="hop";
bool t=true;
float y=1.2f;
unsigned int j=4;
signed char d=-128;
unsigned char d=254;
complex<double> z(2,3);
Variables globales :
int n;
const int m=12;
void f() {
n=10; // OK
int i=m; // OK
...
Conversion :
int i=int(x);
int i,j;
double x=double(i)/j;
Tests
Comparaison :
== != < > <= >=
Ngation : !
Combinaisons : && ||
if (i==0)
j=1;
if (i==0)
j=1;
else
j=2;
if (i==0) {
j=1;
k=2;
}
bool t=(i==0);
if (t)
j=1;
switch (i) {
case 1:
...;
...;
break;
case 2:
case 3:
...;
break;
default:
...;
}
Boucles
do {
...
} while (!ok);
int i=1;
while (i<=100) {
...
i=i+1;
}
for (int i=1;i<=10;i++)
...
for (int i=1,j=10;j>i;
i=i+2,j=j-3)
...
Fonctions
Dnition :
int plus(int a,int b) {
int c=a+b;
return c;
}
void affiche(int a) {
cout << a << endl;
}
Dclaration :
int plus(int a,int b);
Retour :
int signe(double x) {
if (x<0)
return -1;
if (x>0)
return 1;
return 0;
}
void afficher(int x,
int y) {
if (x<0 || y<0)
return;
if (x>=w || y>=h)
return;
DrawPoint(x,y,RED);
}
Appel :
int f(int a) { ... }
int g() { ... }
...
int i=f(2),j=g();
Rfrences :
void swap(int& a,
int& b){
int tmp=a;
a=b;b=tmp;
}
...
int x=3,y=2;
swap(x,y);
Surcharge :
int hasard(int n);
int hasard(int a,
int b);
double hasard();
Oprateurs :
vect operator+(
vect A,vect B) {
...
}
...
vect C=A+B;
84
6. Plusieurs chiers ! 6.4. Fiche de rfrence
Fiche de rfrence (2/2)
Tableaux
Dnition :
double x[10],y[10];
for(int i=0;i<10;i++)
y[i]=2
*
x[i];
const int n=5;
int i[n],j[2
*
n]; //OK
Initialisation :
int t[4]={1,2,3,4};
string s[2]={"ab","c"};
Affectation :
int s[3]={1,2,3},t[3];
for (int i=0;i<3;i++)
t[i]=s[i];
En paramtre :
void init(int t[4]) {
for(int i=0;i<4;i++)
t[i]=0;
}
void init(int t[],
int n) {
for(int i=0;i<n;i++)
t[i]=0;
}
Structures
struct Point {
double x,y;
Color c;
};
...
Point a;
a.x=2.3; a.y=3.4;
a.c=Red;
Point b={1,2.5,Blue};
Compilation spare
#include "vect.h", y
compris dans vect.cpp
Fonctions : dclarations dans
le .h, dnitions dans le .cpp
Types : dnitions dans le .h
Ne dclarer dans le .h que les
fonctions utiles.
#pragma once au dbut du
chier.
Ne pas trop dcouper...
Divers
i++;
i--;
i-=2;
j+=3;
j=i%n; // Modulo
#include <cstdlib>
...
i=rand()%n;
x=rand()/
double(RAND_MAX);
#include <ctime>
...
srand((unsigned int)
time(0));
#include <cmath>
double sqrt(double x);
double cos(double x);
double sin(double x);
double acos(double x);
#include <string>
using namespace std;
string s="hop";
char c=s[0];
int l=s.size();
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
Erreurs frquentes
Pas de dnition de fonction
dans une fonction!
int q=r=4; // NON!
if (i=2) // NON!
if i==2 // NON!
if (i==2) then // NON!
for (int i=0,i<100,i++)
// NON!
int f() {...}
...
int i=f; // NON!
double x=1/3; // NON!
int i,j;
double x;
x=i/j; // NON!
x=double(i/j); //NON!
double x[10],y[10];
for (int i=1;i<=10;i++)
y[i]=2
*
x[i]; //NON
int n=5;
int t[n]; // NON
int f()[4] { // NON!
int t[4];
...
return t; // NON!
}
int t[4]; t=f();
int s[3]={1,2,3},t[3];
t=s; // NON!
int t[2];
t={1,2}; // NON!
struct Point {
double x,y;
} // NON!
Point a;
a={1,2}; // NON!
#include "vec.cpp"//NON
Imagine++
Voir documentation...
Clavier
Build : F7
Debug : F5
Step over : F10
Step inside : F11
Indent : Ctrl+K,Ctrl+F
Add New It. : Ctrl+Maj+A
Add Exist. It. : Alt+Maj+A
Conseils
Travailler en local
Imagine++ Project
Nettoyer en quittant.
Erreurs et warnings : cliquer.
Indenter.
Ne pas laisser de warning.
Utiliser le debuggeur.
Faire des fonctions.
Tableaux : pas pour transcrire
une formule mathmatique !
Faire des structures.
Faire des chiers spars.
Le .h doit sufre lutilisa-
teur (qui ne doit pas regarder
le .cpp)
85
7. La mmoire
Chapitre 7
La mmoire
Il est grand temps de revenir sur la mmoire et son utilisation. Nous pourrons alors mieux
comprendre les variables locales, comment marche exactement lappel dune fonction, les fonc-
tions rcursives, etc. Aprs cela, nous pourrons enn utiliser des tableaux de taille variable
(sans pour autant rentrer vraiment dans la notion dlicate de pointeur).

7.1 Lappel dune fonction


Il sagit l dune nouvelle occasion pour vous de comprendre enn ce qui se passe
dans un programme...
7.1.1 Exemple
Considrons le programme suivant :
1 # i ncl ude <i ostream>
2 usi ng namespace st d ;
3
4 void v e r i f i e ( i nt p, i nt q , i nt quo , i nt r es ) {
5 i f ( res <0 || res >=q || qquo+r es ! =p)
6 cout << " Tiens , c es t bi zar r e ! " << endl ;
7 }
8
9 i nt di vi s e ( i nt a , i nt b , i nt& r ) {
10 i nt q ;
11 q=a/b ;
12 r=aqb ;
13 v e r i f i e ( a , b , q , r ) ;
14 ret urn q ;
15 }
16 i nt main ( )
17 {
18 i nt num, denom;
19 do {
20 cout << " Ent rez deux e nt i e r s po s i t i f s : " ;
7.1. Lappel dune fonction 7. La mmoire
21 ci n >> num >> denom;
22 } while (num<=0 || denom<=0) ;
23 i nt quot i ent , r e s t e ;
24 quot i ent =di vi s e (num, denom, r e s t e ) ;
25 cout << num << "/" << denom << " = " << quot i ent
26 << " ( I l r e s t e " << r e s t e << " ) " << endl ;
27 ret urn 0;
28 }
Calculant le quotient et le reste dune division entire, et vriant quils sont corrects,
il nest pas passionnant et surtout inutilement long (en fait, ce sont juste les lignes 11
et 12 qui font tout !). Il sagit par contre dun bon exemple pour illustrer notre propos.
Une bonne faon dexpliquer exhaustivement son droulement est de remplir le ta-
bleau suivant, dj rencontr au TP A.2. En ne mettant que les lignes o les variables
changent, en supposant que lutilisateur rentre 23 et 3 au clavier, et en indiant avec
des lettres les diffrentes tapes dune mme ligne
1
, cela donne :
Ligne num denom quotient reste a b r q
d
ret
d
p
v
q
v
quo res
18 ? ?
21 23 3
23 23 3 ? ?
24a 23 3 ? ?
9 23 3 ? ? 23 3 [reste]
10 23 3 ? ? 23 3 [reste] ?
11 23 3 ? ? 23 3 [reste] 7
12 23 3 ? 2 23 3 [reste] 7
13a 23 3 ? 2 23 3 [reste] 7
4 23 3 ? 2 23 3 [reste] 7 23 3 7 2
5 23 3 ? 2 23 3 [reste] 7 23 3 7 2
7 23 3 ? 2 23 3 [reste] 7
13b 23 3 ? 2 23 3 [reste] 7
14 23 3 ? 2 23 3 [reste] 7 7
15 23 3 ? 2 7
24b 23 3 7 2 7
25 23 3 7 2
28
A posteriori, on constate quon a implicitement suppos que lorsque le programme
est en train dexcuter divise() , la fonction main() et ses variables existent encore et
quelles attendent simplement la n de divise() . Autrement dit :
Un appel de fonction est un mcanisme qui permet de partir excuter mo-
mentanment cette fonction puis de retrouver la suite des instructions et les
variables quon avait provisoirement quittes.
Les fonctions sappelant les unes les autres, on se retrouve avec des appels de fonc-
tions imbriqus les uns dans les autres : main() appelle divise() qui lui-mme appelle
verie ()
2
. Plus prcisment, cette imbrication est un empilement et on parle de pile
des appels. Pour mieux comprendre cette pile, nous allons utiliser le debuggeur. Avant
cela, prcisons ce quun informaticien entend par pile.
1. par exemple 24a et 24b
2. Et dailleurs main() a lui-mme t appel par une fonction a laquelle il renvoie un int.
88
7. La mmoire 7.1. Lappel dune fonction
Pile/File
Une pile est une structure permettant de mmoriser des donnes dans laquelle
celles-ci sempilent de telle sorte que celui qui est rang en dernier dans la pile en
est extrait en premier. En anglais, une pile (stack) est aussi appele LIFO (last in
rst out
3
). On y empile (push) et on y dpile (pop) les donnes. Par exemple, aprs
un push(1), un push(2) et un push(3), le premier pop() donnera 3, le deuxime
pop() donnera 2 et un dernier pop() donnera 1.
Pour une le (en anglais queue), cest la mme chose mais le premier arriv est
le premier sorti (FIFO). Par exemple, aprs un push(1), un push(2) et un push(3),
le premier pop() donnera 1, le deuxime pop() donnera 2 et un dernier pop()
donnera 3.
7.1.2 Pile des appels et dbuggeur
Observons donc la gure 7.1 obtenue en lanant notre programme dexemple sous
debuggeur. En regardant la partie gauche de chaque tape, nous pouvons voir la pile
des appels. La partie droite afche le contenu des variables, paramtres et valeurs de
retour dont nous pouvons constater la cohrence avec le tableau prcdent.
(a) Comme lindique la pile des appels, nous sommes ligne 24 de la fonction main(),
qui se trouve en haut de la pile. Plus profond dans la pile, nous voyons que
main() a t appel par une fonction mainCRTStartup() elle-mme appele par
un trange kernel32.dll
4
. Vriez aussi les variables et le fait quelles valent
nimporte quoi (ici -858993460 !) tant quelles ne sont pas initialises ou affectes.
(b) Avanons en pas--pas dtaill (touche F11) jusqu la ligne 12. Nous sommes
dans la fonction divise() , q vient de valoir 7, et la ligne 24 de main() est descendue
dun cran dans la pile des appels.
(c) Nous sommes maintenant la ligne 5 dans verie () . La pile des appels un ni-
veau de plus, divise() est en attente la ligne 13 et main() toujours en 24. Vriez
au passage que la variable q afche est bien celle de verie () , qui vaut 3 et non
pas celle de divise() .
(d) Ici, lexcution du programme na pas progress et nous en sommes toujours
la ligne 5. Simplement, Visual offre la possibilit en double-cliquant sur la pile
dappel de regarder ce qui se passe un des niveaux infrieurs, notamment pour
afcher les instructions et les variables de ce niveau. Ici, en cliquant sur la ligne
de divise() dans la fentre de la ligne dappel, nous voyons apparatre la ligne
13 et ses variables dans leur tat alors que le programme est en 5. Entre autres,
le q afch est celui de divise() et vaut 7.
(e) Toujours sans avancer, voici ltat du main() et de ses variables (entre autres, reste
est bien pass 2 depuis la ligne 12 de divise() .
(f) Nous excutons maintenant la suite jusqu nous retrouver en ligne 24 au re-
tour de divise() . Pour cela, on peut faire du pas--pas dtaill, ou simplement
3. Dernier rentr, premier sorti.
4. Ces deux fonctions sont respectivement : (i) la fonction que le compilateur cre pour faire un
certain nombre de choses avant et aprs main() et (ii) la partie de Windows qui lance le programme
lui-mme.
89
7.1. Lappel dune fonction 7. La mmoire
(a)
(b)
(c)
(d)
(e)
(f)
(g)
FIGURE 7.1 Appels de fontions
90
7. La mmoire 7.2. Variables Locales
pile variable valeur
place libre
top a 23
b 3
q
d
7
r [reste]
denom 3
num 23
quotient ?
reste ?
pris par les ...
les fonctions ...
avant main() ...
pile variable valeur
place libre
top p
v
23
q
v
3
quo 7
res 2
a 23
b 3
q
d
7
r [reste]
denom 3
num 23
quotient ?
reste 2
pris par les ...
les fonctions ...
avant main() ...
pile variable valeur
place libre
top denom 3
num 23
quotient 7
reste 2
pris par les ...
les fonctions ...
avant main() ...
FIGURE 7.2 Pile et variables locales. De gauche droite : tape (b) (ligne 12), tape (c)
(ligne 5) et tape (g) (ligne 25/26).
deux fois de suite un pas--pas sortant
5
(Maj-F11) pour relancer jusqu sortir de
verie () , puis jusqu sortir de divise() . On voit bien quotient, qui est encore
non dni, et aussi la valeur de retour de divise() , non encore affecte quotient.
(g) Un pas--pas de plus et nous sommes en 25/26. La variable quotient vaut enn
7.
7.2 Variables Locales
Il va tre important pour la suite de savoir comment les paramtres et les variables
locales sont stocks en mmoire.
5. Step Out ou Maj-F11 ou . Notez aussi possibilit de continuer le programme jusqu une certaine
ligne sans avoir besoin de mettre un point darrt temporaire sur cette ligne mais simplement en cliquant
sur la ligne avec le bouton de droite et en choisissant "excuter jusqu cette ligne" ( )
91
7.3. Fonctions rcursives 7. La mmoire
7.2.1 Paramtres
Pour les paramtres, cest simple :
Les paramtres sont en fait des variables locales ! Leur seule spcicit est
dtre initialiss ds le dbut de la fonction avec les valeurs passes lappel
de la fonction.
7.2.2 La pile
Les variables locales (et donc les paramtres) ne sont pas mmorises des adresses
xes en mmoire
6
, dcides la compilation. Si on faisait a, les adresses mmoire
en question devraient tre rserves pendant toute lexcution du programme : on ne
pourrait y ranger les variables locales dautres fonctions. La solution retenue est beau-
coup plus conome en mmoire
7
:
Les variables locales sont mmorises dans un pile :
Quand une variables locale est cre, elle est rajoute en haut de cette
pile.
Quand elle meurt (en gnral quand on quitte sa fonction) elle est sortie
de la pile.
Ainsi, au fur et mesure des appels, les variables locales sempilent : la mmoire est
utilise juste pendant le temps ncessaire. La gure 7.2 montre trois tapes de la pile
pendant lexcution de notre exemple.
7.3 Fonctions rcursives
Un fonction rcursive est une fonction qui sappelle elle-mme. La fonction la plus
classique pour illustrer la rcursivit est la factorielle
8
. Voici une faon simple et rcur-
sive de la programmer :
5 i nt f ac t 1 ( i nt n)
6 {
7 i f ( n==1)
8 ret urn 1;
9 ret urn n f ac t 1 ( n1) ;
10 }
On remarque videmment que les fonctions rcursives contiennent (en gnral au d-
but, et en tout cas avant lappel rcursif !) une condition darrt : ici si n vaut 1, la fonction
retourne directement 1 sans sappeler elle-mme
9
.
6. Souvenons-nous du chapitre 2.
7. Et permettra de faire des fonctions rcursives, cf section suivante !
8. Coin des collgiens : La factorielle dun nombre entier n scrit n! et vaut n! = 1 2 ... n.
9. Le fait de pouvoir mettre des return au milieu des fonctions est ici bien commode !
92
7. La mmoire 7.3. Fonctions rcursives
7.3.1 Pourquoi a marche ?
Si les fonctions avaient mmoris leurs variables locales des adresses xes, la
rcursivit naurait pas pu marcher : lappel rcursif aurait cras les valeurs des va-
riables. Par exemple, fact1 (3) aurait cras la valeur 3 mmorise dans n par un 2 en
appelant fact1 (2) ! Cest justement grce la pile que le n de fact1 (2) nest pas le mme
que celui de fact1 (3). Ainsi, lappel fact1 (3) donne-til le tableau suivant :
Ligne n
fact1(3)
ret
fact1(3)
n
fact1(2)
ret
fact1(2)
n
fact1(1)
ret
fact1(1)
5
fact1(3)
3
9a
fact1(3)
3
5
fact1(2)
3 2
9a
fact1(2)
3 2
5
fact1(1)
3 2 1
8
fact1(1)
3 2 1 1
10
fact1(1)
3 2 1
9b
fact1(2)
3 2 2 1
10
fact1(2)
3 2
9b
fact1(3)
3 6 2
10
fact1(3)
6
Ce tableau devient difcile crire maintenant quon sait que les variables locales ne
dpendent pas que de la fonction mais changent chaque appel ! On est aussi oblig
de prciser, pour chaque numro de ligne, quel appel de fonction est concern. Si on
visualise la pile, on comprend mieux pourquoi a marche. Ainsi, arrivs en ligne 8 de
fact1 (1) pour un appel initial fact1 (3), la pile ressemble :
pile variable valeur
place libre
top n
fact1(1)
1
n
fact1(2)
2
n
fact1(3)
3
ce que lon peut aisment vrier avec le dbuggeur. Finalement :
Les fonctions rcursives ne sont pas diffrentes des autres. Cest le systme
dappel des fonctions en gnral qui rend la rcursivit possible.
7.3.2 Efcacit
Une fonction rcursive est simple et lgante crire quand le problme sy prte
10
.
Nous venons de voir quelle nest toujours pas facile suivre ou debugger. Il faut
aussi savoir que
la pile des appels nest pas innie et mme relativement limite.
Ainsi, le programme suivant
22 / / Fa i t d b o r de r l a p i l e
23 i nt f ac t 3 ( i nt n)
24 {
10. Cest une erreur classique de dbutant que de vouloir abuser du rcursif.
93
7.3. Fonctions rcursives 7. La mmoire
25 i f ( n==1)
26 ret urn 1;
27 ret urn n f ac t 3 ( n+1) ; / / e r r e ur !
28 }
dans lequel une erreur sest glisse va sappeler thoriquement linni et en pratique
sarrtera avec une erreur de dpassement de la pile des appels
11
. Mais la vraie raison
qui fait quon vite parfois le rcursif est qu
appeler une fonction est un mcanisme coteux !
Lorsque le corps dune fonction est sufsamment petit pour que le fait dappeler cette
fonction ne soit pas ngligeable devant le temps pass excuter la fonction elle-mme,
il est prfrable dviter ce mcanisme dappel
12
. Dans le cas dune fonction rcursive,
on essaie donc sil est ncessaire dcrire une version drcursive (ou itrative) de la
fonction. Pour notre factorielle, cela donne :
/ / Ve r s i on i t r a t i v e
i nt f ac t 2 ( i nt n)
{
i nt f =1;
f or ( i nt i =2; i <=n ; i ++)
f = i ;
ret urn f ;
}
ce qui aprs tout nest pas si terrible.
Enn, il arrive qucrire une fonction sous forme rcursive ne soit pas utilisable
pour des raisons de complexit. Une exemple classique est la suite de Fibonacci dnie
par :
_
f
0
= f
1
= 1
f
n
= f
n1
+ f
n2
et qui donne : 1, 1, 2, 3, 5, 8,... En version rcursive :
32 / / Tr s l e n t !
33 i nt f i b1 ( i nt n) {
34 i f ( n<2)
35 ret urn 1;
36 ret urn f i b1 ( n2)+ f i b1 ( n1) ;
37 }
cette fonction a la mauvaise ide de sappeler trs souvent : n = 10 appelle n = 9
et n = 8, mais n = 9 appelle lui aussi n = 8 de son ct en plus de n = 7, n = 7
qui lui-mme est appel par tous les n = 8 lancs, etc. Bref, cette fonction devient
rapidement trs lente. Ainsi, pour n = 40, elle sappelle dj 300.000.000 de fois elle-
mme, ce qui prend un certain temps ! Il est donc raisonnable den programmer une
version drcursive :
39 / / D r c ur s i v e
40 i nt f i b2 ( i nt n) {
11. Sous Visual, il sarrte pour n = 5000 environ.
12. Nous verrons dans un autre chapitre les fonctions inline qui rpondent ce problme.
94
7. La mmoire 7.4. Le tas
41 i nt fnm2=1 , fnm1=1;
42 f or ( i nt i =2; i <=n ; i ++) {
43 i nt fn=fnm2+fnm1 ;
44 fnm2=fnm1 ;
45 fnm1=fn ;
46 }
47 ret urn fnm1 ;
48 }
Mentionnons aussi quil existe des fonctions sufsamment tordues pour que leur ver-
sion rcursive ne se contente pas de sappeler un grand nombre de fois en tout, mais
un grand nombre de fois en mme temps, ce qui fait quindpendamment des questions
defcacit, leur version rcursive fait dborder la pile dappels !
7.4 Le tas
La pile nest pas la seule zone de mmoire utilise par les programmes. Il y a aussi
le tas (heap en anglais).
7.4.1 Limites
La pile est limite en taille. La pile dappel ntant pas innie et les variables locales
ntant pas en nombre illimit, il est raisonnable de rserver une pile de relativement
petite taille. Essayez donc le programme :
32 i nt main ( )
33 {
34 const i nt n=500000;
35 i nt t [ n ] ;
36 . . .
37 }
Il sexcute avec une erreur : "stack overow". La variable locale t nest pas trop grande
pour lordinateur
13
: elle est trop grande pour tenir dans la pile. Jusqu prsent, on
savait quon tait limit aux tableaux de taille constante. En ralit, on est aussi limit
aux petits tableaux. Il est donc grand temps dapprendre utiliser le tas !
7.4.2 Tableaux de taille variable
Nous fournissons ici une rgle appliquer en aveugle. Sa comprhension viendra plus tard
si ncessaire.
Lorsquon veut utiliser un tableau de taille variable, il ny a que deux choses faire,
mais elle sont essentielles toutes les deux
14
:
13. 500000x4 soit 2Mo seulement !
14. Et le dbutant oublie toujours la deuxime, ce qui a pour consquence des programmes qui gros-
sissent en quantit de mmoire occupe...
95
7.4. Le tas 7. La mmoire
1. Remplacer int t[n] par int
*
t=new int[n] (ou lquivalent pour
un autre type que int)
2. Lorsque le tableau doit mourir (en gnral en n de fonction), rajouter
la ligne delete[] t;
Le non respect de la rgle 2 fait que le tableau reste en mmoire jusqu la n du pro-
gramme, ce qui entraine en gnral une croissance anarchique de la mmoire utilise
(on parle de fuite de mmoire). Pour le reste, on ne change rien. Programmer un tableau
de cette faon fait quil est mmoris dans le tas et non plus dans la pile. On fait donc
ainsi :
1. Pour les tableaux de taille variable.
2. Pour les tableaux de grande taille.
Voici ce que cela donne sur un petit programme :
1 # i ncl ude <i ostream>
2 usi ng namespace st d ;
3
4 void rempl i t ( i nt t [ ] , i nt n)
5 {
6 f or ( i nt i =0; i <n ; i ++)
7 t [ i ]= i +1;
8 }
9
10 i nt somme( i nt t [ ] , i nt n)
11 {
12 i nt s =0;
13 f or ( i nt i =0; i <n ; i ++)
14 s+=t [ i ] ;
15 ret urn s ;
16 }
17
18 void f i x e ( )
19 {
20 const i nt n=5000;
21 i nt t [ n ] ;
22 rempl i t ( t , n ) ;
23 i nt s=somme( t , n ) ;
24 cout << s << " devr ai t val oi r " << n( n+1)/2 << endl ;
25 }
26
27 void var i abl e ( )
28 {
29 i nt n ;
30 cout << "Un e nt i e r SVP: " ;
31 ci n >> n ;
32 i nt t =new i nt [ n ] ; / / Al l o c a t i o n
33 rempl i t ( t , n ) ;
34 i nt s=somme( t , n ) ;
96
7. La mmoire 7.5. Loptimiseur
35 cout << s << " devr ai t val oi r " << n( n+1)/2 << endl ;
36 del et e [ ] t ; / / De s a l l o c a t i o n : ne pas o u b l i e r !
37 }
38
39 i nt main ( )
40 {
41 f i x e ( ) ;
42 var i abl e ( ) ;
43 ret urn 0;
44 }
7.4.3 Essai dexplication
Ce qui suit nest pas essentiel pour un dbutant mais peut ventuellement rpondre ses
interrogations. Sil comprend, tant mieux, sinon, quil oublie et se contente pour linstant de la
rgle prcdente !
Pour avoir accs toute la mmoire de lordinateur
15
, on utilise le tas. Le tas est une
zone mmoire que le programme possde et qui peut crotre sil en fait la demande au
systme dexploitation (et sil reste de la mmoire de libre videmment). Pour utiliser le
tas, on appelle une fonction dallocation laquelle on demande de rserver en mmoire
de la place pour un certain nombre de variables. Cest ce que fait new int[n].
Cette fonction retourne ladresse de lemplacement mmoire quelle a rserv. Nous
navons jamais rencontr de type de variable capable de mmoriser une adresse. Il
sagit des pointeurs dont nous reparlerons plus tard. Un pointeur vers de la mmoire
stockant des int est de type int. Do le int t pour mmoriser le retour du new.
Ensuite, un pointeur peut sutiliser comme un tableau, y compris comme paramtre
dune fonction.
Enn, il ne faut pas oublier de librer la mmoire au moment o le tableau de taille
constante aurait disparu : cest ce que fait la fonction delete[] t qui libre la mmoire
pointe par t.
7.5 Loptimiseur
Mentionnons ici un point important qui tait nglig jusquici, mais que nous allons
utiliser en TP.
Il y a plusieurs faons de traduire en langage machine un source C++. Le rsultat
de la compilation peut donc tre diffrent dun compilateur lautre. Au moment de
compiler, on peut aussi rechercher produire un excutable le plus rapide possible :
on dit que le compilateur optimise le code. En gnral, loptimisation ncessite un plus
grand travail mais aussi des transformations qui font que le code produit nest plus
facilement dbuggable. On choisit donc en pratique entre un code debuggable et un
code optimis.
Jusquici, nous utilisions toujours le compilateur en mode "Debug". Lorsquun pro-
gramme est au point (et seulement lorsquil lest), on peut basculer le compilateur en
15. Plus exactement ce que le systme dexploitation veut bien attribuer au maximum chaque pro-
gramme, ce qui est en gnral rglable mais en tout cas moins que la mmoire totale, bien que beaucoup
plus que la taille de la pile.
97
7.6. Assertions 7. La mmoire
mode "Release" pour avoir un programme plus performant. Dans certains cas, les gains
peuvent tre considrables. Un programmeur expriment fait mme en sorte que lop-
timiseur puisse efcacement faire son travail. Ceci dit, il faut respecter certaines rgles :
Ne pas debugger quand on est en mode Release ( !)
Rester en mode Debug le plus longtemps possible pour bien mettre au point le
programme.
Savoir que les modes Debug et Release crent des chiers objets et excutables
dans des rpertoires diffrents et donc que lorsquon nettoie les solutions, il faut
le faire pour chacun des deux modes.
7.6 Assertions
Voici une fonction trs utile pour faire des programmes moins buggs ! La fonction
assert () prvient quand un test est faux. Elle prcise le chier et le numro de ligne o
elle se trouve, offre la possibilit de debugger le programme, etc. Elle ne ralentit pas
les programmes car elle disparat la compilation en mode Release. Cest une fonction
peu connue des dbutants, et cest bien dommage ! Par exemple :
# i ncl ude <c as s er t >
. . .
i nt n ;
ci n >> n ;
as s e r t ( n>0) ;
i nt t =new i nt [ n ] ; / / Al l o c a t i o n
Si lutilisateur entre une valeur ngative ou nulle, les consquences pourraient tre f-
cheuses. En particulier une valeur ngative de n serait interprte comme un grand
entier (car le [] attend un entier non sign, ainsi -1 serait compris comme le plus grand
int possible) et le new serait probablement un chec. A noter que si n==0, un tableau
nul, lallocation marche. Mais dans ce cas t [0] nexiste mme pas ! La seule chose quon
peut donc faire avec un tableau nul cest le dsallouer avec delete[] t ; . Il est toujours
utile de se prmunir contre une telle exception en vriant que la valeur est raison-
nable.
7.7 TP
Le TP que nous proposons en A.6 est une illustration des fonctions rcursive et des
tableaux de taille variable. Il consiste en la programmation de quelques faons de trier
des donnes : tri bulle, Quicksort, etc. An de rendre le tout plus attrayant, le tri sera
visualis graphiquement et chronomtr (gure 7.3).
98
7. La mmoire 7.8. Fiche de rfrence
FIGURE 7.3 Deux tris en cours dexcution : tri bulle et Quicksort...
7.8 Fiche de rfrence
Fiche de rfrence (1/3)
Variables
Dnition :
int i;
int k,l,m;
Affectation :
i=2;
j=i;
k=l=3;
Initialisation :
int n=5,o=n;
Constantes :
const int s=12;
Porte :
int i;
// i=j; interdit!
int j=2;
i=j; // OK!
if (j>1) {
int k=3;
j=k; // OK!
}
//i=k; interdit!
Types :
int i=3;
double x=12.3;
char c=A;
string s="hop";
bool t=true;
float y=1.2f;
unsigned int j=4;
signed char d=-128;
unsigned char d=254;
complex<double> z(2,3);
Variables globales :
int n;
const int m=12;
void f() {
n=10; // OK
int i=m; // OK
...
Conversion :
int i=int(x);
int i,j;
double x=double(i)/j;
Pile/Tas
Tests
Comparaison :
== != < > <= >=
Ngation : !
Combinaisons : && ||
if (i==0)
j=1;
if (i==0)
j=1;
else
j=2;
if (i==0) {
j=1;
k=2;
}
bool t=(i==0);
if (t)
j=1;
switch (i) {
case 1:
...;
...;
break;
case 2:
case 3:
...;
break;
default:
...;
}
Boucles
do {
...
} while (!ok);
int i=1;
while (i<=100) {
...
i=i+1;
}
for (int i=1;i<=10;i++)
...
for (int i=1,j=10;j>i;
i=i+2,j=j-3)
...
99
7.8. Fiche de rfrence 7. La mmoire
Fiche de rfrence (2/3)
Fonctions
Dnition :
int plus(int a,int b) {
int c=a+b;
return c;
}
void affiche(int a) {
cout << a << endl;
}
Dclaration :
int plus(int a,int b);
Retour :
int signe(double x) {
if (x<0)
return -1;
if (x>0)
return 1;
return 0;
}
void afficher(int x,
int y) {
if (x<0 || y<0)
return;
if (x>=w || y>=h)
return;
DrawPoint(x,y,RED);
}
Appel :
int f(int a) { ... }
int g() { ... }
...
int i=f(2),j=g();
Rfrences :
void swap(int& a,
int& b){
int tmp=a;
a=b;b=tmp;
}
...
int x=3,y=2;
swap(x,y);
Surcharge :
int hasard(int n);
int hasard(int a,
int b);
double hasard();
Oprateurs :
vect operator+(
vect A,vect B) {
...
}
...
vect C=A+B;
Pile des appels
Itratif/Rcursif
Tableaux
Dnition :
double x[10],y[10];
for(int i=0;i<10;i++)
y[i]=2
*
x[i];
const int n=5;
int i[n],j[2
*
n]; //OK
Initialisation :
int t[4]={1,2,3,4};
string s[2]={"ab","c"};
Affectation :
int s[3]={1,2,3},t[3];
for (int i=0;i<3;i++)
t[i]=s[i];
En paramtre :
void init(int t[4]) {
for(int i=0;i<4;i++)
t[i]=0;
}
void init(int t[],
int n) {
for(int i=0;i<n;i++)
t[i]=0;
}
Taille variable :
int
*
t=new int[n];
...
delete[] t;
Structures
struct Point {
double x,y;
Color c;
};
...
Point a;
a.x=2.3; a.y=3.4;
a.c=Red;
Point b={1,2.5,Blue};
Compilation spare
#include "vect.h", y
compris dans vect.cpp
Fonctions : dclarations dans
le .h, dnitions dans le .cpp
Types : dnitions dans le .h
Ne dclarer dans le .h que les
fonctions utiles.
#pragma once au dbut du
chier.
Ne pas trop dcouper...
Divers
i++;
i--;
i-=2;
j+=3;
j=i%n; // Modulo
#include <cstdlib>
...
i=rand()%n;
x=rand()/
double(RAND_MAX);
#include <ctime>
...
srand((unsigned int)
time(0));
#include <cmath>
double sqrt(double x);
double cos(double x);
double sin(double x);
double acos(double x);
#include <string>
using namespace std;
string s="hop";
char c=s[0];
int l=s.size();
#include <ctime>
s=double(clock())
/CLOCKS_PER_SEC;
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
Clavier
Build : F7
Debug : F5
Step over : F10
Step inside : F11
Indent : Ctrl+K,Ctrl+F
Add New It. : Ctrl+Maj+A
Add Exist. It. : Alt+Maj+A
Step out : Maj+F11
Run to curs. : Click droit
Compltion : Alt+
100
7. La mmoire 7.9. Examens sur machine
Fiche de rfrence (3/3)
Erreurs frquentes
Pas de dnition de fonction
dans une fonction!
int q=r=4; // NON!
if (i=2) // NON!
if i==2 // NON!
if (i==2) then // NON!
for (int i=0,i<100,i++)
// NON!
int f() {...}
...
int i=f; // NON!
double x=1/3; // NON!
int i,j;
double x;
x=i/j; // NON!
x=double(i/j); //NON!
double x[10],y[10];
for (int i=1;i<=10;i++)
y[i]=2
*
x[i]; //NON
int n=5;
int t[n]; // NON
int f()[4] { // NON!
int t[4];
...
return t; // NON!
}
int t[4]; t=f();
int s[3]={1,2,3},t[3];
t=s; // NON!
int t[2];
t={1,2}; // NON!
struct Point {
double x,y;
} // NON!
Point a;
a={1,2}; // NON!
#include "vec.cpp"//NON
Imagine++
Voir documentation...
Conseils
Travailler en local
Imagine++ Project
Nettoyer en quittant.
Erreurs et warnings : cliquer.
Indenter.
Ne pas laisser de warning.
Utiliser le debuggeur.
Faire des fonctions.
Tableaux : pas pour transcrire
une formule mathmatique !
Faire des structures.
Faire des chiers spars.
Le .h doit sufre lutilisa-
teur (qui ne doit pas regarder
le .cpp)
Ne pas abuser du rcursif.
Ne pas oublier delete.
Compiler rgulirement.
Debug/Release : nettoyer les
deux.
#include <cassert>
...
assert(x!=0);
y=1/x;
7.9 Examens sur machine
Nous vous conseillons aussi de vous confronter aux examens proposs en annexe.
Vous avez toutes les connaissances ncessaires.
101
8. Allocation dynamique
Chapitre 8
Allocation dynamique
Nous revenons une fois de plus sur lutilisation du tas pour grer des tableaux de taille
variable. Aprs avoir mentionn lexistence de tableaux bidimensionnels de taille xe, nous d-
taillons lallocation dynamique
1
dj vue en 7.4.2 et expliquons enn les pointeurs, du moins
partiellement. A travers lexemple des matrices (et des images en TP) nous mlangeons struc-
tures et allocation dynamique. Il sagira l de notre structure de donne la plus complexe avant
larrive tant attendue - et maintenant justie - des objets...

8.1 Tableaux bidimensionnels


8.1.1 Principe
Il existe en C++ des tableaux deux dimensions. Leur utilisation est similaire celle
des tableaux standards :
Il faut utiliser des crochets (lignes 1 et 4 du programme ci-dessous). Attention :
[ i ][ j ] et non [ i , j ].
Linitialisation est possible avec des accolades (ligne 5). Attention : accolades im-
briques.
Leurs dimensions doivent tre constantes (lignes 6 et 7).
1 i nt A[ 2 ] [ 3 ] ;
2 f or ( i nt i =0; i <2; i ++)
3 f or ( i nt j =0; j <3; j ++)
4 A[ i ] [ j ]= i +j ;
5 i nt B[ 2 ] [ 3 ] ={ { 1 , 2 , 3 } , { 4 , 5 , 6 } } ;
6 const i nt M=2 ,N=3;
7 i nt C[M] [N] ;
1 2 3
4 6 5
B[0]
B[1]
Tableau 2D B [2][3]={{1,2,3},{4,5,6}} .
Notez que B[0] est le tableau 1D {1,2,3}
et B[1] le tableau 1D {4,5,6} .
La gure ci-dessus montre le tableau B. A noter que B[0] et B[1] sont des tableaux
1D reprsentant les lignes de B.
1. cest--dire lallocation de mmoire dans le tas avec new et delete.
8.1. Tableaux bidimensionnels 8. Allocation dynamique
8.1.2 Limitations
Vis--vis des fonctions, les particularits sont les mmes quen 1D :
Impossible de retourner un tableau 2D.
Passage uniquement par variable.
mais avec une restriction supplmentaire :
On est oblig de prciser les dimensions dun tableau 2Dparamtre de fonc-
tion.
Impossible donc de programmer des fonctions qui peuvent travailler sur des tableaux
de diffrentes tailles comme dans le cas 1D (cf 4.3.1). Cest trs restrictif et explique
que les tableaux 2D ne sont pas toujours utiliss. On peut donc avoir le programme
suivant :
1 / / Pas s age de pa r a m t r e
2 double t r ac e ( double A[ 2 ] [ 2 ] ) {
3 double t =0;
4 f or ( i nt i =0; i <2; i ++)
5 t +=A[ i ] [ i ] ;
6 ret urn t ;
7 }
8
9 / / Le pa s s a ge e s t t o uj o ur s par r f r e n c e . . .
10 void s et ( double A[ 2 ] [ 3 ] ) {
11 f or ( i nt i =0; i <2; i ++)
12 f or ( i nt j =0; j <3; j ++)
13 A[ i ] [ j ]= i +j ;
14 }
15
16 . . .
17 double D[ 2 ] [ 2 ] = { { 1 , 2 } , { 3 , 4 } } ;
18 double t =t r ac e (D) ;
19 double E [ 2 ] [ 3 ] ;
20 s et ( E ) ;
21 . . .
mais il est impossible de programmer une fonction trace () ou set () qui marche pour
diffrentes tailles de tableaux 2D comme on laurait fait en 1D :
1 / / OK
2 void s et ( double A[ ] , i nt n , double x ) {
3 f or ( i nt i =0; i <n ; i ++)
4 A[ i ]=x ;
5 }
6 / / NON! ! ! ! ! ! ! ! ! ! ! ! ! ! !
7 / / do ubl e A[ ] [ ] e s t r e f u s
8 void s et ( double A[ ] [ ] , double m, double n , double x ) {
9 f or ( i nt i =0; i <m; i ++)
10 f or ( i nt j =0; j <n ; j ++)
11 A[ i ] [ j ]=x ;
12 }
104
8. Allocation dynamique 8.1. Tableaux bidimensionnels
B[0]=1
B[1]=4
B[2]=2
B[3]=5
B[4]=3
B[5]=6
FIGURE 8.1 La matrice B de lexemple prcdent stocke en 1D.
8.1.3 Solution
En pratique, ds que lon doit manipuler des tableaux de dimension 2 (ou plus !) de
diffrentes tailles, on les mmorise dans des tableaux 1D en stockant par exemple les
colonnes les unes aprs les autres pour proter des avantages des tableaux 1D. Ainsi,
on stockera une matrice A de m lignes de n colonnes dans un tableau T de taille mn
en plaant llment A(i, j) en T(i + mj). La Fig. 8.1 montre le tableau B de lexemple
prcdent stock comme tableau 1D. On peut alors crire :
1 void s et ( double A[ ] , i nt m, i nt n) {
2 f or ( i nt i =0; i <m; i ++)
3 f or ( i nt j =0; j <n ; j ++)
4 A[ i +m j ]= i +j ;
5 }
6 . . .
7 double F [ 2 3 ] ;
8 s et ( F , 2 , 3 ) ;
9 double G[ 3 5 ] ;
10 s et (G, 3 , 5 ) ;
ou par exemple, ce produit matrice vecteur dans lequel les vecteurs et les matrices sont
stocks dans des tableaux 1D :
1 / / y=Ax
2 void produi t ( double A[ ] , i nt m, i nt n , double x [ ] , double y [ ] )
3 {
4 f or ( i nt i =0; i <m; i ++) {
5 y[ i ] =0;
6 f or ( i nt j =0; j <n ; j ++)
7 y[ i ]+=A[ i +m j ] x [ j ] ;
8 }
9 }
10
11 . . .
12 double P[ 23] , x [ 3 ] , y [ 2 ] ;
13 . . .
14 / / P = . . . x = . . .
15 produi t ( P, 2 , 3 , x , y ) ; / / y=Px
105
8.2. Allocation dynamique 8. Allocation dynamique
8.2 Allocation dynamique
Il ny a pas dallocation dynamique possible pour les tableaux 2D. Il faut donc vrai-
ment les mmoriser dans des tableaux 1D comme expliqu ci-dessus pour pouvoir les
allouer dynamiquement dans le tas. Lexemple suivant montre comment faire. Il utilise
la fonction produit() donne ci-dessus sans quil soit besoin de la rednir :
1 i nt m, n ;
2 . . .
3 double A=new double [mn ] ;
4 double x=new double [ n ] ;
5 double y=new double [m] ;
6 . . .
7 / / A= . . . x = . . .
8 produi t (A, m, n , x , y ) ; / / y=Ax
9 . . .
10 del et e [ ] A;
11 del et e [ ] x ;
12 del et e [ ] y ;
8.2.1 Pourquoi a marche ?
Il est maintenant temps dexpliquer pourquoi, une fois allous, nous pouvons utili-
ser des tableaux dynamiques exactement comme des tableaux de taille xe. Il suft de
comprendre les tapes suivantes :
1. int t [n] dnit une variable locale, donc de la mmoire dans la pile, capable de
stocker n variables int.
2. int t dnit une variable de type "pointeur" dint, cest--dire que t peut m-
moriser ladresse dune zone mmoire contenant des int.
3. new int[n] alloue dans le tas une zone mmoire pouvant stocker n int et renvoie
ladresse de cette zone. Do le int t=new int[n]
4. delete[] t libre dans le tas ladresse mmorise dans t.
5. Lorsque t est un tableau de taille xe t [ i ] dsigne son i
me
lment. Lorsque t
est un pointeur dint, t [ i ] dsigne la variable int stocke i places
2
plus loin en
mmoire que celle situe ladresse t. Ainsi, aprs un int t [n] comme aprs un
int t=new int[n], la syntaxe t [ i ] dsigne bien ce quon veut.
6. Lorsque t est un tableau de taille xe, la syntaxe t tout court dsigne ladresse
(dans la pile) laquelle le tableau est mmoris. De plus, lorsquune fonction
prend un tableau comme paramtre, la syntaxe int s [] signie en ralit que s
est ladresse du tableau. Ce qui fait quen n de compte :
une fonction f ( int s []) est conue pour quon lui passe une adresse s
elle marche videmment avec les tableaux allous dynamiquement qui ne sont
nalement que des adresses
cest plutt lappel f ( t ), avec t tableau de taille xe, qui sadapte en passant
f ladresse o se trouve le tableau.
2. Ici, une place est videmment le nombre doctets ncessaires au stockage dun int.
106
8. Allocation dynamique 8.2. Allocation dynamique
logiquement, on devrait mme dclarer f par f ( int s) au lieu de f ( int s []) .
Les deux sont en fait possibles et synonymes.
Vous pouvez donc maintenant programmer, en comprenant, ce genre de choses :
1 double somme( double t , i nt n) { / / Synt axe " p o i nt e ur "
2 double s =0;
3 f or ( i nt i =0; i <n ; i ++)
4 s+=t [ i ] ;
5 ret urn s ;
6 }
7 . . .
8 i nt t 1 [ 4 ] ;
9 . . .
10 double s1=somme( t1 , 4 ) ;
11 . . .
12 i nt t 2=new i nt [ n ] ;
13 . . .
14 double s2=somme( t2 , n ) ;
15 . . .
16 del et e [ ] t 2 ;
8.2.2 Erreurs classiques
Vous comprenez maintenant aussi les erreurs classiques suivantes (que vous nvi-
terez pas pour autant !).
1. Oublier dallouer :
i nt t ;
f or ( i nt i =0; i <n ; i ++)
t [ i ] = . . . / / Horreur : t vaut n i mpo r t e
/ / quoi comme a d r e s s e
2. Oublier de dsallouer :
void f ( i nt n) {
i nt t =new i nt [ n ] ;
. . .
} / / On o u b l i e d e l e t e [ ] t ;
/ / Chaque a ppe l f ( ) va pe r dr e n i nt dans l e t a s !
3. Ne pas dsallouer ce quil faut :
i nt t =new i nt [ n ] ;
i nt s=new i nt [ n ] ;
. . .
s=t ; / / Ai e ! Du coup , s c o n t i e n t l a mme a d r e s s e que t
/ / (On n a pas r e c o p i l a zone p o i nt e par t dans c e l l e
/ / p o i nt e par s ! )
. . .
del et e [ ] t ; / / OK
del et e [ ] s ; / / Cat a : Non s e ul e me nt on ne l i b r e pas l a mmoi re
107
8.2. Allocation dynamique 8. Allocation dynamique
/ / i n i t i a l e me n t m mor i s e dans s , mai s en pl us on
/ / d s a l l o u e nouveau c e l l e qui v i e nt d t r e l i b r e !
8.2.3 Consquences
Quand librer ?
Maintenant que vous avez compris new et delete, vous imaginez bien quon nat-
tend pas toujours la n de lexistence du tableau pour librer la mmoire. Le plus tt
est le mieux et on libre la mmoire ds que le tableau nest plus utilis :
1 void f ( ) {
2 i nt t [ 1 0 ] ;
3 i nt s=new i nt [ n ] ;
4 . . .
5 del et e [ ] s ; / / s i s ne s e r t pl us dans l a s u i t e . . .
6 / / Autant l i b r e r mai nt e nant . . .
7 . . .
8 } / / Par c o nt r e , t a t t e nd c e t t e l i g n e pour mouri r .
En fait, le tableau dont ladresse est mmorise dans s est allou ligne 3 et libr ligne
5. La variable s qui mmorise son adresse, elle, est cre ligne 3 et meurt ligne 8 !
Pointeurs et fonctions
Il est frquent que le newet le delete ne se fassent pas dans la mme fonction (atten-
tion, du coup, aux oublis !). Ils sont souvent intgrs dans des fonctions. A ce propos,
lorsque des fonctions manipulent des variables de type pointeur, un certain nombre de
questions peuvent se poser. Il suft de respecter la logique :
Une fonction qui retourne un pointeur se dclare int f ();
1 i nt al l oue ( i nt n) {
2 ret urn new i nt [ n ] ;
3 }
4 . . . .
5 i nt t =al l oue ( 1 0 ) ;
6 . . .
Un pointeur pass en paramtre une fonction lest par valeur. Ne pas mlan-
ger avec le fait quun tableau est pass par rfrence ! Considrez le programme
suivant :
1 void f ( i nt t , i nt n) {
2 . . . .
3 t [ i ] = . . . ; / / On mo d i f i e t [ i ] mai s pas t !
4 t = . . . / / Une t e l l e l i g n e ne c h a ng e r a i t pas s
5 / / dans l a f o n c t i o n a p p e l a nt e
6 }
7 . . .
8 i nt s=new i nt [m] ;
9 f ( s ,m) ;
108
8. Allocation dynamique 8.3. Structures et allocation dynamique
En fait, cest parce quon passe ladresse dun tableau quon peut modier ses l-
ments. Par ignorance, nous disions que les tableaux taient passs par rfrence
en annonant cela comme une exception. Nous pouvons maintenant rectier :
Un tableau est en fait pass via son adresse. Cette adresse est passe par
valeur. Mais ce mcanisme permet la fonction appele de modier le
tableau. Dire quun tableau est pass par rfrence tait un abus de
langage simplicateur.
Si on veut vraiment passer le pointeur par rfrence, la syntaxe est logique :
int& t. Un cas typique de besoin est :
1 / / t e t n s e r o nt mo d i f i s ( e t pl us s e ul e me nt t [ i ] )
2 void al l oue ( i nt & t , i nt& n) {
3 ci n >> n ; / / n e s t c h o i s i au c l a v i e r
4 t =new i nt [ n ] ;
5 }
6 . . .
7 i nt t ;
8 i nt n ;
9 al l oue ( t , n ) ; / / t e t n s o nt a f f e c t s par a l l o u e ( )
10 . . .
11 del et e [ ] t ; / / Ne pas o u b l i e r pour aut a nt !
Bizzarerie ? Les lignes 7 et 8 ci-dessus auraient pu scrire int t , n;. En fait, il faut
remettre une toile devant chaque variable lorsquon dnit plusieurs pointeurs en
mme-temps. Ainsi, int t , s,u; dnit deux pointeurs dint (les variables t et u) et
un int (la variable s).
8.3 Structures et allocation dynamique
Passer systmatiquement un tableau et sa taille toutes les fonctions est videm-
ment pnible. Il faut les runir dans une structure. Je vous laisse mditer lexemple
suivant qui pourrait tre un passage dun programme implmentant des matrices
3
et
leur produit :
1 # i ncl ude <i ostream>
2 # i ncl ude <s t r i ng >
3 usi ng namespace st d ;
4
5 / / ==================================================
6 / / f o n c t i o n s sur l e s ma t r i c e s
7 / / p o ur r a i e nt e t r e dans un ma t r i c e . h e t un ma t r i c e . cpp
8
9 s t r uc t Mat ri ce {
10 i nt m, n ;
11 double t ;
12 } ;
3. Coin des enfants : les matrices et les vecteurs vous sont inconnus. Ca nest pas grave. Comprenez
le source quand mme et rattrapez vous avec le TP qui, lui, joue avec des images.
109
8.3. Structures et allocation dynamique 8. Allocation dynamique
13
14 Mat ri ce cr ee ( i nt m, i nt n) {
15 Mat ri ce M;
16 M.m=m;
17 M. n=n ;
18 M. t =new double [mn ] ;
19 ret urn M;
20 }
21
22 void de t r ui t ( Mat ri ce M) {
23 del et e [ ] M. t ;
24 }
25
26 Mat ri ce produi t ( Mat ri ce A, Mat ri ce B) {
27 i f (A. n! =B.m) {
28 cout << " Erreur ! " << endl ;
29 e x i t ( 1 ) ;
30 }
31 Mat ri ce C=cr ee (A. m, B. n ) ;
32 f or ( i nt i =0; i <A.m; i ++)
33 f or ( i nt j =0; j <B. n ; j ++) {
34 / / Ci j =Ai0 B0j +Ai1 B1j + . . .
35 C. t [ i +C.m j ] =0;
36 f or ( i nt k=0; k<A. n ; k++)
37 C. t [ i +C.m j ]+=A. t [ i +A.mk] B. t [ k+B.m j ] ;
38
39 }
40 ret urn C;
41 }
42
43 void a f f i c he ( s t r i ng s , Mat ri ce M) {
44 cout << s << " =" << endl ;
45 f or ( i nt i =0; i <M.m; i ++) {
46 f or ( i nt j =0; j <M. n ; j ++)
47 cout << M. t [ i +M.m j ] << " " ;
48 cout << endl ;
49 }
50 }
51
52 / / ==================================================
53 / / Ut i l i s a t e u r
54
55 i nt main ( )
56 {
57 Mat ri ce A=cr ee ( 2 , 3 ) ;
58 f or ( i nt i =0; i <2; i ++)
59 f or ( i nt j =0; j <3; j ++)
60 A. t [ i +2 j ]= i +j ;
61 a f f i c he ( "A" ,A) ;
110
8. Allocation dynamique 8.3. Structures et allocation dynamique
62 Mat ri ce B=cr ee ( 3 , 5 ) ;
63 f or ( i nt i =0; i <3; i ++)
64 f or ( i nt j =0; j <5; j ++)
65 B. t [ i +3 j ]= i +j ;
66 a f f i c he ( "B" , B ) ;
67 Mat ri ce C=produi t (A, B ) ;
68 a f f i c he ( "C" ,C) ;
69 de t r ui t (C) ;
70 de t r ui t ( B ) ;
71 de t r ui t (A) ;
72 ret urn 0;
73 }
Lutilisateur na maintenant plus qu savoir quil faut allouer et librer les matrices
en appelant des fonctions mais il na pas savoir ce que font ces fonctions. Dans cette
logique, on pourra rajouter des fonctions pour quil nait pas non plus besoin de savoir
comment les lments de la matrice sont mmoriss. Il na alors mme plus besoin de
savoir que les matrices sont des structures qui ont un champ t ! (Nous nous rappro-
chons vraiment de la programmation objet...) Bref, on rajoutera en gnral :
10 double get ( Mat ri ce M, i nt i , i nt j ) {
11 ret urn M. t [ i +M.m j ] ;
12 }
13
14 void s et ( Mat ri ce M, i nt i , i nt j , double x ) {
15 M. t [ i +M.m j ]=x ;
16 }
que lutilisateur pourra appeler ainsi :
51 f or ( i nt i =0; i <2; i ++)
52 f or ( i nt j =0; j <3; j ++)
53 s et (A, i , j , i +j ) ;
et que celui qui programme les matrices pourra aussi utiliser pour lui :
39 void a f f i c he ( s t r i ng s , Mat ri ce M) {
40 cout << s << " =" << endl ;
41 f or ( i nt i =0; i <M.m; i ++) {
42 f or ( i nt j =0; j <M. n ; j ++)
43 cout << get (M, i , j ) << " " ;
44 cout << endl ;
45 }
46 }
Attention, il reste facile dans ce contexte :
Doublier dallouer.
Doublier de dsallouer.
De ne pas dsallouer ce quil faut si on fait A=B entre deux matrices. (Cest alors
deux fois la zone alloue initialement pour B qui est dsalloue lorsquon libre
A et B tandis que la mmoire initiale de A ne le sera jamais, comme on peut le
voir sur la Fig. 8.2).
111
8.4. Boucles et continue 8. Allocation dynamique
A.t
B.t
A.t
B.t
A.t
B.t
detruit(A);
A.t
B.t
A=cree(2,3);
B=cree(2,3);
A=B; detruit(B);
...
...
...
...
...
...
...
...
FIGURE 8.2 Attention au double delete : le code A=B fait pointer deux fois sur la
mme zone mmoire alors quil ny a plus de pointeur sur le tableau du haut (donc
une fuite mmoire puisquil nest plus possible de la librer). Le detruit(B) libre
une zone mmoire qui lavait dj t, avec des consquences fcheuses...
La programmation objet essaiera de faire en sorte quon ne puisse plus faire ces erreurs.
Elle essaiera aussi de faire en sorte que lutilisateur ne puisse plus savoir ce quil na pas
besoin de savoir, de faon rendre vraiment indpendantes la conception des matrices
et leur utilisation.
8.4 Boucles et continue
Nous utiliserons dans le TP linstruction continue qui est bien pratique. Voici ce
quelle fait : lorsquon la rencontre dans une boucle, toute la n de la boucle est saute
et on passe au tour suivant. Ainsi :
f or ( . . . ) {
. . .
i f (A)
cont i nue ;
. . .
i f ( B)
cont i nue ;
. . .
}
est quivalent (et remplace avantageusement au niveau clart et mise en page) :
f or ( . . . ) {
. . .
i f ( ! A) {
. . .
i f ( ! B) {
. . .
}
}
}
Ceci est rapprocher de lutilisation du return en milieu de fonction pour vacuer les
cas particuliers (section 7.3).
8.5 TP
Le TP que nous proposons en A.7 est une illustration de cette faon de manipuler
des tableaux bidimensionnels dynamiques travers des structures de donnes. Pour
112
8. Allocation dynamique 8.6. Fiche de rfrence
FIGURE 8.3 Deux images et diffrents traitements de la deuxime (ngatif, ou, relief,
dformation, contraste et contours).
changer de nos passionnantes matrices, nous travaillerons avec des images (gure 8.3).
8.6 Fiche de rfrence
Fiche de rfrence (1/3)
Boucles
do {
...
} while (!ok);
int i=1;
while (i<=100) {
...
i=i+1;
}
for (int i=1;i<=10;i++)
...
for (int i=1,j=10;j>i;
i=i+2,j=j-3)
...
for (int i=...)
for (int j=...) {
//saute le cas i==j
if (i==j)
continue;
...
}
Variables
Dnition :
int i;
int k,l,m;
Affectation :
i=2;
j=i;
k=l=3;
Initialisation :
int n=5,o=n;
Constantes :
const int s=12;
Porte :
int i;
// i=j; interdit!
int j=2;
i=j; // OK!
if (j>1) {
int k=3;
j=k; // OK!
}
//i=k; interdit!
Types :
int i=3;
double x=12.3;
char c=A;
string s="hop";
bool t=true;
float y=1.2f;
unsigned int j=4;
signed char d=-128;
unsigned char d=254;
complex<double> z(2,3);
Variables globales :
int n;
const int m=12;
void f() {
n=10; // OK
int i=m; // OK
...
Conversion :
int i=int(x);
int i,j;
double x=double(i)/j;
Pile/Tas
Clavier
Build : F7
Debug : F5
Step over : F10
Step inside : F11
Indent : Ctrl+K,Ctrl+F
Add New It. : Ctrl+Maj+A
Add Exist. It. : Alt+Maj+A
Step out : Maj+F11
Run to curs. : Click droit
Compltion : Alt+
Gest. tches : Ctrl+Maj+Ech
113
8.6. Fiche de rfrence 8. Allocation dynamique
Fiche de rfrence (2/3)
Fonctions
Dnition :
int plus(int a,int b) {
int c=a+b;
return c;
}
void affiche(int a) {
cout << a << endl;
}
Dclaration :
int plus(int a,int b);
Retour :
int signe(double x) {
if (x<0)
return -1;
if (x>0)
return 1;
return 0;
}
void afficher(int x,
int y) {
if (x<0 || y<0)
return;
if (x>=w || y>=h)
return;
DrawPoint(x,y,RED);
}
Appel :
int f(int a) { ... }
int g() { ... }
...
int i=f(2),j=g();
Rfrences :
void swap(int& a,
int& b){
int tmp=a;
a=b;b=tmp;
}
...
int x=3,y=2;
swap(x,y);
Surcharge :
int hasard(int n);
int hasard(int a,
int b);
double hasard();
Oprateurs :
vect operator+(
vect A,vect B) {
...
}
...
vect C=A+B;
Pile des appels
Itratif/Rcursif
Tableaux
Dnition :
double x[10],y[10];
for(int i=0;i<10;i++)
y[i]=2
*
x[i];
const int n=5;
int i[n],j[2
*
n]; //OK
Initialisation :
int t[4]={1,2,3,4};
string s[2]={"ab","c"};
Affectation :
int s[3]={1,2,3},t[3];
for (int i=0;i<3;i++)
t[i]=s[i];
En paramtre :
void init(int t[4]) {
for(int i=0;i<4;i++)
t[i]=0;
}
void init(int t[],
int n) {
for(int i=0;i<n;i++)
t[i]=0;
}
Taille variable :
int
*
t=new int[n];
...
delete[] t;
En paramtre (suite) :
void f(int
*
t,int n){
t[i]=...
}
void alloue(int
*
& t){
t=new int[n];
}
2D :
int A[2][3];
A[i][j]=...;
int A[2][3]=
{{1,2,3},{4,5,6}};
void f(int A[2][2]);
2D dans 1D :
int A[2
*
3];
A[i+2
*
j]=...;
Taille variable (suite) :
int
*
t,
*
s,n;
Structures
struct Point {
double x,y;
Color c;
};
...
Point a;
a.x=2.3; a.y=3.4;
a.c=Red;
Point b={1,2.5,Blue};
Compilation spare
#include "vect.h", y
compris dans vect.cpp
Fonctions : dclarations dans
le .h, dnitions dans le .cpp
Types : dnitions dans le .h
Ne dclarer dans le .h que les
fonctions utiles.
#pragma once au dbut du
chier.
Ne pas trop dcouper...
Tests
Comparaison :
== != < > <= >=
Ngation : !
Combinaisons : && ||
if (i==0)
j=1;
if (i==0)
j=1;
else
j=2;
if (i==0) {
j=1;
k=2;
}
bool t=(i==0);
if (t)
j=1;
switch (i) {
case 1:
...;
...;
break;
case 2:
case 3:
...;
break;
default:
...;
}
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
114
8. Allocation dynamique 8.6. Fiche de rfrence
Fiche de rfrence (3/3)
Divers
i++;
i--;
i-=2;
j+=3;
j=i%n; // Modulo
#include <cstdlib>
...
i=rand()%n;
x=rand()/
double(RAND_MAX);
#include <ctime>
...
srand((unsigned int)
time(0));
#include <cmath>
double sqrt(double x);
double cos(double x);
double sin(double x);
double acos(double x);
#include <string>
using namespace std;
string s="hop";
char c=s[0];
int l=s.size();
#include <ctime>
s=double(clock())
/CLOCKS_PER_SEC;
#define _USE_MATH_DEFINES
#include <cmath>
double pi=M_PI;
Erreurs frquentes
Pas de dnition de fonction
dans une fonction!
int q=r=4; // NON!
if (i=2) // NON!
if i==2 // NON!
if (i==2) then // NON!
for (int i=0,i<100,i++)
// NON!
int f() {...}
...
int i=f; // NON!
double x=1/3; // NON!
int i,j;
double x;
x=i/j; // NON!
x=double(i/j); //NON!
double x[10],y[10];
for (int i=1;i<=10;i++)
y[i]=2
*
x[i]; //NON
int n=5;
int t[n]; // NON
int f()[4] { // NON!
int t[4];
...
return t; // NON!
}
int t[4]; t=f();
int s[3]={1,2,3},t[3];
t=s; // NON!
int t[2];
t={1,2}; // NON!
struct Point {
double x,y;
} // NON!
Point a;
a={1,2}; // NON!
#include "vec.cpp"//NON
void f(int t[][]);//NON
int t[2,3]; // NON!
t[i,j]=...; // NON!
int
*
t;
t[1]=...; // NON!
int
*
t=new int[2];
int
*
s=new int[2];
s=t; // On perd s!
delete[] t;
delete[] s; //Dja fait
int
*
t,s;// s est int
// et non int
*
t=new int[n];
s=new int[n];// NON!
Imagine++
Voir documentation...
Conseils
Travailler en local
Imagine++ Project
Nettoyer en quittant.
Erreurs et warnings : cliquer.
Indenter.
Ne pas laisser de warning.
Utiliser le debuggeur.
Faire des fonctions.
Tableaux : pas pour transcrire
une formule mathmatique !
Faire des structures.
Faire des chiers spars.
Le .h doit sufre lutilisa-
teur (qui ne doit pas regarder
le .cpp)
Ne pas abuser du rcursif.
Ne pas oublier delete.
Compiler rgulirement.
Debug/Release : nettoyer les
deux.
#include <cassert>
...
assert(x!=0);
y=1/x;
115
9. Premiers objets
Chapitre 9
Premiers objets
Nous abordons maintenant notre dernire tape dans la direction dune meilleure organisa-
tion des programmes. Tantt nous structurions davantage les instructions (fonctions, chiers),
tantt nous nous intressions aux donnes (structures, tableaux). Nous allons maintenant pen-
ser donnes et instructions simultanment : cest l lide premire des objets, mme sils pos-
sdent de nombreux autres aspects
1
. Enn, nous justierons lemploi des objets par la notion
d"interface"
2
.

9.1 Philosophie
Runir les instructions en fonctions ou chiers est une bonne chose. Runir les don-
nes en tableaux ou structures aussi. Il arrive que les deux soient lis. Cest dailleurs
ce que nous avons constat naturellement dans les exemples des chapitres prcdents,
dans lesquels un chier regroupait souvent une structure et un certain nombre de fonc-
tions sy rapportant. Cest dans ce cas quil faut faire des objets.
Lide est simple : un objet est un type de donne possdant un certain nombre de
fonctionnalits propres
3
. Ainsi :
Ce ne sont plus les fonctions qui travaillent sur des donnes. Ce sont les
donnes qui possdent des fonctionnalits.
Ces "fonctionnalits" sont souvent appeles les mthodes de lobjet. En pratique, luti-
lisation dun objet remplacera ce genre dinstructions :
obj a ;
i nt i =f ( a ) ; / / f o n c t i o n f ( ) a p p l i q u e a
par :
obj a ;
i nt i =a . f ( ) ; / / a ppe l l a mt hode f ( ) de a
1. Le plus important tant lhritage, que nous ne verrons pas dans ce cours, prfrant nous consacrer
dautres aspects du C++ plus indispensables et ngligs jusquici...
2. Nous exposerons une faon simple de crer des interfaces. Un programmeur C++ expriment
utilisera plutt de lhritage et des fonctions virtuelles pures, ce qui dpasse largement ce cours !
3. Il arrive mme parfois quun objet regroupe des fonctionnalits sans pour autant stocker la
moindre donne. Nous nutiliserons pas ici cette faon de prsenter les choses, dont le dbutant pourrait
rapidement abuser.
9.2. Exemple simple 9. Premiers objets
Vous lavez compris, il sagit ni plus ni moins de "ranger" les fonctions dans les
objets. Attention, crions tout de suite haut et fort qu
il ne faut pas abuser des objets, surtout lorsquon est dbutant. Les dangers
sont en effet :
de voir des objets l o il ny en na pas. Instructions et donnes ne sont
pas toujours lies.
de mal penser lorganisation des donnes ou des instructions en objets.
Un conseil donc : quand a devient trop compliqu pour vous, abandonnez
les objets.
Ce qui ne veut pas dire quun dbutant ne doit pas faire dobjets. Des petits objets
dans des cas simples sont toujours une bonne ide. Mais seule lexprience permet
de correctement organiser son programme, avec les bons objets, les bonnes fonctions,
etc. Un exemple simple : lorsquune fonction travaille sur deux types de donnes, le
dbutant voudra souvent sacharner en faire malgr tout une mthode de lun des
deux objets, et transformer :
obj 1 a ;
obj 2 b ;
i nt i =f ( a , b ) ; / / f ( ) a p p l i q u e a e t b
en :
obj 1 a ;
obj 2 b ;
i nt i =a . f ( b ) ; / / mt hode f ( ) de a a p p l i q u e b
/ / Estc e b i e n l a c ho s e f a i r e ????
Seuls un peu de recul et dexprience permettent de rester simple quand il le faut. Le
premier code tait le plus logique : la fonction f () na souvent rien faire chez a, ni
chez b.
9.2 Exemple simple
On laura compris dans les exemples prcdents, les mthodes des objets sont consi-
dres comme faisant partie du type de lobjet, au mme titre que ses champs. Dailleurs,
les champs dun objet sont parfois appels membres de lobjet, et ses mthodes des fonc-
tions membres. Voici ce que cela donne en C++ :
s t r uc t obj {
i nt x ; / / champ x
i nt f ( ) ; / / mt hode f ( )
i nt g( i nt y ) ; / / mt hode g ( )
} ;
. . .
i nt main ( ) {
obj a ;
a . x=3;
i nt i =a . f ( ) ;
i nt j =a . g ( 2 ) ;
. . .
118
9. Premiers objets 9.3. Visibilit
Il y a juste un dtail, mais dimportance : la dnition de la structure obj ci-dessus ne
fait que dclarer les mthodes. Elles ne sont dnies nulle part dans le code prcdent.
Pour les dnir, on fait comme pour les fonctions habituelles, sauf que
pour permettre plusieurs objets davoir les mmes noms de mthodes, on
prxe leur dnition par le nom de lobjet suivi de ::
a
.
a. Ce mcanisme existe aussi pour les fonctions usuelles. Ce sont les espaces de nom, que
nous avons rencontrs et contourns immdiatement avec using namespace std pour ne
pas avoir crire std::cout ...
Voici comment cela scrit :
s t r uc t obj 1 {
i nt x ; / / champ x
i nt f ( ) ; / / mt hode f ( ) ( d c l a r a t i o n )
i nt g( i nt y ) ; / / mt hode g ( ) ( d c l a r a t i o n )
} ;
s t r uc t obj 2 {
double x ; / / champ x
double f ( ) ; / / mt hode f ( ) ( d c l a r a t i o n )
} ;
. . .
i nt obj 1 : : f ( ) { / / mt hode f ( ) de o b j 1 ( d f i n i t i o n )
. . .
ret urn . . .
}
i nt obj 1 : : g( i nt y) { / / mt hode g ( ) de o