Professional Documents
Culture Documents
(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 !
...
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.)
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.
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 b j 1 ( d f i n i t i o n )
. . .
ret urn . . .
}
double obj 2 : : f ( ) { / / mt hode f ( ) de o b j 2 ( d f i n i t i o n )
. . .
ret urn . . .
}
. . .
i nt main ( ) {
obj 1 a ;
obj 2 b ;
a . x=3; / / l e champ x de a e s t i nt
b . x =3. 5; / / c e l u i de b e s t do ubl e
i nt i =a . f ( ) ; / / mt hode f ( ) de a ( donc o b j 1 : : f ( ) )
i nt j =a . g ( 2 ) ; / / mt hode g ( ) de a ( donc o b j 1 : : g ( ) )
double y=b . f ( ) ; / / mt hode f ( ) de b ( donc o b j 2 : : f ( ) )
. . .
9.3 Visibilit
Il y a une rgle que nous navons pas vue sur les espaces de nom mais que nous
pouvons facilement comprendre : quand on est "dans" un espace de nom, on peut
119
9.4. Exemple des matrices 9. Premiers objets
utiliser toutes les variables et fonctions de cet espace sans prciser lespace en question.
Ainsi, ceux qui ont programm cout et endl ont dni lespace std puis se sont "placs
lintrieur" de cet espace pour programmer sans avoir mettre std:: partout devant
cout, cin, endl et les autres... Cest suivant cette mme logique, que
dans ses mthodes, un objet accde directement ses champs et ses autres
mthodes, cest--dire sans rien mettre devant
a
!
a. Vous verrez peut-tre parfois traner le mot cl this qui est utile certains moment en
C++ et que les programmeurs venant de Java mettent partout en se trompant dailleurs sur
son type. Vous nen naurez en gnral pas besoin.
Par exemple, la fonction obj1::f() ci-dessus pourrait scrire :
1 i nt obj 1 : : f ( ) { / / mt hode f ( ) de o b j 1 ( d f i n i t i o n )
2 i nt i =g ( 3 ) ; / / mt hode g ( ) de l o b j e t dont l a mt hode f ( ) e s t
3 / / en t r a i n de s e x c ut e r
4 i nt j =x+i ; / / champ x de l o b j e t dont l a mt hode f ( ) e s t
5 / / en t r a i n de s e x c ut e r
6 ret urn j ;
7 }
8 . . .
9 i nt main ( ) {
10 obj 1 a1 , a2 ;
11 i nt i 1=a1 . f ( ) ; / / Cet a ppe l va u t i l i s e r a1 . g ( ) l i g ne 2
12 / / e t a1 . x l i g n e 4
13 i nt i 2=a2 . f ( ) ; / / Cet a ppe l va u t i l i s e r l i g ne 2 a2 . g ( )
14 / / e t a2 . x l i g n e 4
Il est dailleurs normal quun objet accde simplement ses champs depuis ses m-
thodes, car
si un objet nutilise pas ses champs dans une mthode, cest probablement
quon est en train de ranger dans cet objet une fonction qui na rien voir
avec lui (cf abus mentionn plus haut)
9.4 Exemple des matrices
En programmation, un exemple de source vaut mieux quun long discours. Si jus-
quici vous naviguiez dans le vague, les choses devraient maintenant sclaircir ! Voil
donc ce que devient notre exemple du chapitre 8 avec des objets :
# i ncl ude <i ostream>
# i ncl ude <s t r i ng >
usi ng namespace st d ;
/ / ==================================================
/ / f o n c t i o n s sur l e s ma t r i c e s
/ / p o ur r a i e nt e t r e dans un ma t r i c e . h e t ma t r i c e . cpp
/ / ========= d e c l a r a t i o n s ( dans l e . h )
s t r uc t Mat ri ce {
120
9. Premiers objets 9.4. Exemple des matrices
i nt m, n ;
double t ;
void cr ee ( i nt m1, i nt n1 ) ;
void de t r ui t ( ) ;
double get ( i nt i , i nt j ) ;
void s et ( i nt i , i nt j , double x ) ;
void a f f i c he ( s t r i ng s ) ;
} ;
Mat ri ce operat or ( Mat ri ce A, Mat ri ce B ) ;
/ / ========= d f i n i t i o n s ( dans l e . cpp )
void Mat ri ce : : cr ee ( i nt m1, i nt n1 ) {
/ / Not ez que l e s pa r a me t r e s ne s a p p e l l e n t pl us m e t n
/ / pour ne pas m l ange r ave c l e s champs !
m=m1;
n=n1 ;
t =new double [mn ] ;
}
void Mat ri ce : : de t r ui t ( ) {
del et e [ ] t ;
}
double Mat ri ce : : get ( i nt i , i nt j ) {
ret urn t [ i +m j ] ;
}
void Mat ri ce : : s et ( i nt i , i nt j , double x ) {
t [ i +m j ]=x ;
}
void Mat ri ce : : a f f i c he ( s t r i ng s ) {
cout << s << " =" << endl ;
f or ( i nt i =0; i <m; i ++) {
f or ( i nt j =0; j <n ; j ++)
cout << get ( i , j ) << " " ;
cout << endl ;
}
}
Mat ri ce operat or ( Mat ri ce A, Mat ri ce B) {
i f (A. n! =B.m) {
cout << " Erreur ! " << endl ;
e x i t ( 1 ) ;
}
Mat ri ce C;
C. cr ee (A. m, B. n ) ;
f or ( i nt i =0; i <A.m; i ++)
f or ( i nt j =0; j <B. n ; j ++) {
121
9.5. Cas des oprateurs 9. Premiers objets
/ / Ci j =Ai0 B0j +Ai1 B1j + . . .
C. s et ( i , j , 0 ) ;
f or ( i nt k=0; k<A. n ; k++)
C. s et ( i , j ,
C. get ( i , j )+A. get ( i , k) B. get ( k , j ) ) ;
}
ret urn C;
}
/ / ==================== main ===========
i nt main ( )
{
Mat ri ce A;
A. cr ee ( 2 , 3 ) ;
f or ( i nt i =0; i <2; i ++)
f or ( i nt j =0; j <3; j ++)
A. s et ( i , j , i +j ) ;
A. a f f i c he ( "A" ) ;
Mat ri ce B;
B. cr ee ( 3 , 5 ) ;
f or ( i nt i =0; i <3; i ++)
f or ( i nt j =0; j <5; j ++)
B. s et ( i , j , i +j ) ;
B. a f f i c he ( "B" ) ;
Mat ri ce C=AB;
C. a f f i c he ( "C" ) ;
C. de t r ui t ( ) ;
B. de t r ui t ( ) ;
A. de t r ui t ( ) ;
ret urn 0;
}
9.5 Cas des oprateurs
Il est un peu dommage que loprateur ne soit pas dans lobjet Matrice. Pour y
remdier, on adopte la convention suivante :
Soit A un objet. Sil possde une mthode operatorop(objB B), alors
AopB appellera cette mthode pour tout B de type objB.
En clair, le programme :
s t r uc t objA {
. . .
} ;
s t r uc t obj B {
. . .
} ;
122
9. Premiers objets 9.5. Cas des oprateurs
i nt operat or +( objA A, obj B B) {
. . .
}
. . .
i nt main ( ) {
objA A;
obj B B;
i nt i =A+B; / / a p p e l l e o p e r a t o r +(A, B)
. . .
peut aussi scrire :
s t r uc t objA {
. . .
i nt operat or +( obj B B ) ;
} ;
s t r uc t obj B {
. . .
} ;
i nt objA : : operat or +( obj B B) {
. . .
}
. . .
i nt main ( ) {
objA A;
obj B B;
i nt i =A+B; / / a p p e l l e mai nt e nant A. o p e r a t o r +(B)
. . .
ce qui pour nos matrices donne :
s t r uc t Mat ri ce {
. . .
Mat ri ce operat or ( Mat ri ce B ) ;
} ;
. . .
/ / AB a p p e l l e A. o p e r a t o r ( B) donc t o us
/ / l e s champs e t f o n c t i o n s u t i l i s s d i r e c t e me nt
/ / c o nc e r ne nt c e qui t a i t p r f i x prcdemment par A.
Mat ri ce Mat ri ce : : operat or ( Mat ri ce B) {
/ / On e s t dans l o b j e t A du AB a p p e l
i f ( n! =B.m) { / / Le n de A
cout << " Erreur ! " << endl ;
e x i t ( 1 ) ;
}
Mat ri ce C;
C. cr ee (m, B. n ) ;
f or ( i nt i =0; i <m; i ++)
f or ( i nt j =0; j <B. n ; j ++) {
/ / Ci j =Ai0 B0j +Ai1 B1j + . . .
C. s et ( i , j , 0 ) ;
123
9.6. Interface 9. Premiers objets
f or ( i nt k=0; k<n ; k++)
/ / ge t ( i , j ) s e r a c e l u i de A
C. s et ( i , j ,
C. get ( i , j )+ get ( i , k) B. get ( k , j ) ) ;
}
ret urn C;
}
Notez aussi que largument de loprateur na en fait pas besoin dtre un objet.
Ainsi pour crire le produit B=A2, il sufra de crer la mthode :
Mat ri ce Mat ri ce : : operat or ( double lambda ) {
. . .
}
. . .
B=A2; / / Appe l l e A. o p e r a t o r ( 2)
Par contre, pour crire B=2A, on ne pourra pas crer :
Mat ri ce double : : operat or ( Mat ri ce A) / / IMPOSSIBLE
/ / do ubl e n e s t pas un o b j e t !
car cela reviendrait dnir une mthode pour le type double, qui nest pas un ob-
jet
4
. Il faudra simplement se contenter dun oprateur standard, qui, dailleurs, sera
bien inspir dappeler la mthode Matrice:: operator(double lambda) si elle est dj
programme :
Mat ri ce operat or ( double lambda , Mat ri ce A) {
ret urn Alambda ; / / d f i n i prcdemment , donc r i e n reprogrammer !
}
. . .
B=2A; / / a p p e l l e o p e r a t o r ( 2 , A) qui a p p e l l e son t o ur
/ / A. o p e r a t o r ( 2)
Nous verrons au chapitre suivant dautres oprateurs utiles dans le cas des objets...
9.6 Interface
Si on regarde bien le main() de notre exemple de matrice, on saperoit quil nutilise
plus les champs des Matrice mais seulement leurs mthodes. En fait, seule la partie
s t r uc t Mat ri ce {
void cr ee ( i nt m1, i nt n1 ) ;
void de t r ui t ( ) ;
double get ( i nt i , i nt j ) ;
void s et ( i nt i , i nt j , double x ) ;
void a f f i c he ( s t r i ng s ) ;
Mat ri ce operat or ( Mat ri ce B ) ;
} ;
4. et de toute faon nappartient pas au programmeur !
124
9. Premiers objets 9.7. Protection
intresse lutilisateur. Que les dimensions soient dans des champs int met int n et que
les lments soient dans un champ double t ne le concerne plus : cest le problme de
celui qui programme les matrices. Si ce dernier trouve un autre moyen
5
de stocker un
tableau bidimensionnel de double, libre lui de le faire. En fait
Si lutilisateur des Matrice se conforme aux dclarations des mthodes
ci-dessus, leur concepteur peut les programmer comme il lentend. Il peut
mme les reprogrammer ensuite dune autre faon : les programmes de luti-
lisateur marcheront toujours ! Cest le concept mme dune interface :
Le concepteur et lutilisateur des objets se mettent daccord sur les m-
thodes qui doivent exister.
Le concepteur les programme : il implmente
a
linterface.
Lutilisateur les utilise de son ct.
Le concepteur peut y retoucher sans gner lutilisateur.
En particulier le chier den-tte de lobjet est le seul qui intresse lutilisa-
teur. Cest lui qui prcise linterface, sans rentrer dans les dtails dimpl-
mentation. Bref, relies uniquement par linterface, utilisation et implmen-
tation deviennent indpendantes
b
.
a. Il se trouve en gnral face au difcile problme du choix de limplmentation : certaines
faons de stocker les donnes peuvent rendre efcaces certaines mthodes au dtriment de
certaines autres, ou bien consommer plus ou moins de mmoire, etc. Bref, cest lui qui doit
grer les problmes dalgorithmique. Cest aussi en gnral ce qui fait que, pour une mme
interface, un utilisateur prfrera telle ou telle implmentation : le concepteur devra aussi
faire face la concurrence !
b. Ce qui est sr, cest que les deux y gagnent : le concepteur peut amliorer son implmen-
tation sans gner lutilisateur, lutilisateur peut changer pour une implmentation concurrente
sans avoir retoucher son programme.
9.7 Protection
9.7.1 Principe
Tout cela est bien beau, mais les dtails dimplmentation ne sont pas entirement
cachs : la dnition de la structure dans le chier den-tte fait apparatre les champs
utiliss pour limplmentation. Du coup, lutilisateur peut-tre tent des les utiliser !
Rien ne lempche en effet des faire des btises :
Mat ri ce A;
A. cr ee ( 3 , 2 ) ;
A.m=4; / / Ai e ! Le s a c c s vont t r e f aux !
ou tout simplement de prfrer ne pas sembter en remplaant
f or ( i nt i =0; i <3; i ++)
f or ( i nt j =0; j <2; j ++)
A. s et ( i , j , 0 ) ;
par
5. Et il en existe ! Par exemple pour stocker efcacement des matrices creuses, cest--dire celles dont
la plupart des lments sont nuls. Ou bien, en utilisant des objets implmentant dj des tableaux de fa-
on sre et efcace, comme il en existe dj en C++ standard ou dans des bibliothques complmentaires
disponibles sur le WEB. Etc, etc.
125
9.7. Protection 9. Premiers objets
f or ( i nt i =0; i <6; i ++)
A. t [ i ] =0; / / Horreur ! Et s i on i mpl me nt e aut r e me nt ?
Dans ce cas, lutilisation nest plus indpendante de limplmentation et on a perdu
une grande partie de lintrt de la programmation objet... Cest ici quintervient la
possibilit dempcher lutilisateur daccder certains champs ou mme certaines
mthodes. Pour cela :
1. Remplacer struct par class : tous les champs et les mthodes de-
viennent privs : seules les mthodes de lobjet lui-mme ou de tout
autre objet du mme type
a
peuvent les utiliser.
2. Placer la dclaration public: dans la dnition de lobjet pour dbu-
ter la zone
b
partir de laquelle seront dclars les champs et mthodes
publics, cest--dire accessibles tous.
a. Bref, les mthodes de la classe en question!
b. On pourrait nouveau dclarer des passages privs avec private:, puis publics, etc. Il
existe aussi des passages protgs, notion qui dpasse ce cours...
Voici un exemple :
c l a s s obj {
i nt x , y ;
void a_moi ( ) ;
publ i c :
i nt z ;
void pour_tous ( ) ;
void une_autre ( obj A) ;
} ;
void obj : : a_moi ( ) {
x = . . ; / / OK
. . = y ; / / OK
z = . . ; / / OK
}
void obj : : pour_tous ( ) {
x = . . ; / / OK
a_moi ( ) ; / / OK
}
void obj : : une_autre ( obj A) {
x=A. x ; / / OK
A. a_moi ( ) ; / / OK
}
. . .
i nt main ( ) {
obj A, B;
A. x = . . ; / / NON!
A. z = . . ; / / OK
A. a_moi ( ) ; / / NON!
A. pour_tous ( ) ; / / OK
A. une_autre ( B ) ; / / OK
126
9. Premiers objets 9.7. Protection
Dans le cas de nos matrices, que nous avions dj bien programmes, il suft de les
dnir comme suit :
c l a s s Mat ri ce {
i nt m, n ;
double t ;
publ i c :
void cr ee ( i nt m1, i nt n1 ) ;
void de t r ui t ( ) ;
double get ( i nt i , i nt j ) ;
void s et ( i nt i , i nt j , double x ) ;
void a f f i c he ( s t r i ng s ) ;
Mat ri ce operat or ( Mat ri ce B ) ;
} ;
pour empcher une utilisation dpendante de limplmentation.
9.7.2 Structures vs Classes
Notez que, nalement, une structure est une classe o tout est public... Les anciens
programmeurs C pensent souvent tort que les structures du C++ sont les mmes
quen C, cest--dire quelles ne sont pas des objets et quelles nont pas de mthode
6
.
9.7.3 Accesseurs
Les mthodes get () et set () qui permettent daccder en lecture (get) ou en criture
(set) notre classe, sont appeles accesseurs. Maintenant que nos champs sont tous pri-
vs, lutilisateur na plus la possibilit de retrouver les dimensions dune matrice. On
rajoutera donc deux accesseurs en lecture vers ces dimensions :
i nt Mat ri ce : : nbLin ( ) {
ret urn m;
}
i nt Mat ri ce : : nbCol ( ) {
ret urn n ;
}
. . .
i nt main ( ) {
. . .
f or ( i nt i =0; i <A. nbLin ( ) ; i ++)
f or ( i nt j =0; j <A. nbCol ( ) ; j ++)
A. s et ( i , j , 0 ) ;
. . .
mais pas en criture, ce qui est cohrent avec le fait que changer m en cours de route
rendrait fausses les fonctions utilisant t [ i+mj] !
6. sans compter quils les dclarent souvent comme en C avec dinutiles typedef. Mais bon, ceci ne
devrait pas vous concerner !
127
9.8. TP 9. Premiers objets
FIGURE 9.1 Fractales
9.8 TP
Vous devriez maintenant pouvoir faire le TP en A.8 qui dessine quelques courbes
fractales (gure 9.1) en illustrant le concept dobjet..
9.9 Fiche de rfrence
Fiche de rfrence (1/4)
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;
...
}
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
128
9. Premiers objets 9.9. Fiche de rfrence
Fiche de rfrence (2/4)
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
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};
Une structure est un objet en-
tirement public (cf objets !)
129
9.9. Fiche de rfrence 9. Premiers objets
Fiche de rfrence (3/4)
Objets
struct obj {
int x; // champ
int f(); // mthode
int g(int y);
};
int obj::f() {
int i=g(3); // mon g
int j=x+i; // mon x
return j;
}
...
int main() {
obj a;
a.x=3;
int i=a.f();
class obj {
int x,y;
void a_moi();
public:
int z;
void pour_tous();
void un_autre(obj A);
};
void obj::a_moi() {
x=..; // OK
..=y; // OK
z=..; // OK
}
void obj::pour_tous() {
x=..; // OK
a_moi(); // OK
}
void une_autre(obj A) {
x=A.x; // OK
A.a_moi(); // OK
}
...
int main() {
obj A,B;
A.x=..; //NON
A.z=..; //OK
A.a_moi(); //NON
A.pour_tous(); //OK
A.une_autre(B); //OK
class obj {
obj operator+(obj B);
};
...
int main() {
obj A,B,C;
C=A+B;
// C=A.operator+(B)
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;
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!
130
9. Premiers objets 9.9. Fiche de rfrence
Fiche de rfrence (4/4)
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;
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;
Faire des objets.
Ne pas toujours faire des ob-
jets !
Penser interface / implmen-
tation / utilisation.
131
10. Constructeurs et Destructeurs
Chapitre 10
Constructeurs et Destructeurs
Dans ce long chapitre, nous allons voir comment le C++ offre la possibilit dintervenir
sur ce qui se passe la naissance et la mort dun objet. Ce mcanisme essentiel repose sur la
notion de constructeur et de destructeur. Ces notions sont trs utiles, mme pour le dbutant
qui devra au moins connatre leur forme la plus simple. Nous poursuivrons par un aspect bien
pratique du C++, tant pour lefcacit des programmes que pour la dcouverte de bugs la
compilation : une autre utilisation du const. Enn, pour les plus avancs, nous expliquerons
aussi comment les problmes de gestion du tas peuvent tre ainsi automatiss.
10.1 Le problme
Avec lapparition des objets, nous avons transform :
s t r uc t poi nt {
i nt x , y ;
} ;
. . .
poi nt a ;
a . x=2; a . y=3;
i =a . x ; j =a . y ;
en :
c l a s s poi nt {
i nt x , y ;
publ i c :
void get ( i nt&X, i nt&Y) ;
void s et ( i nt X, i nt Y) ;
} ;
. . .
poi nt a ;
a . s et ( 2 , 3 ) ;
a . get ( i , j ) ;
Consquence :
poi nt a ={ 2 , 3 } ;
10.2. La solution 10. Constructeurs et Destructeurs
est maintenant impossible. On ne peut remplir les champs privs dun objet, mme
linitialisation, car cela permettrait daccder en criture une partie prive
1
!
10.2 La solution
La solution est la notion de constructeur :
c l a s s poi nt {
i nt x , y ;
publ i c :
poi nt ( i nt X, i nt Y) ;
} ;
poi nt : : poi nt ( i nt X, i nt Y) {
x=X;
y=Y;
}
. . .
poi nt a ( 2 , 3 ) ;
Un constructeur est une mthode dont le nom est le nom de la classe elle-
mme. Il ne retourne rien mais son type de retour nest pas void : il na pas
de type de retour. Le constructeur est appel la cration de lobjet et ses
paramtres sont passs avec la syntaxe ci-dessus. Il est impossible dappeler
un constructeur sur un objet dj cr
a
.
a. Ce qui explique quil nest pas besoin de lui prciser un type de retour.
Ici, cest le constructeur point :: point(int X,int Y) qui est dni. Notez bien quil
est impossible dappeler un constructeur sur un objet dj contruit :
poi nt a ( 1 , 2 ) ; / / OK! Val e ur s i n i t i a l e s
/ / On ne f a i t pas comme a pour c hange r l e s champs de a .
a . poi nt ( 3 , 4 ) ; / / ERREUR!
/ / Mais p l ut t comme a .
a . s et ( 3 , 4 ) ; / / OK!
10.3 Cas gnral
10.3.1 Constructeur vide
Lorsquun objet est cre sans rien prciser, cest le construteur vide qui est appel,
cest--dire celui sans paramtre. Ainsi, le programme :
c l a s s obj {
publ i c :
obj ( ) ;
1. En ralit, il y a une autre raison, plus profonde et trop difcile expliquer ici, qui fait quen
gnral, ds quon programme des objets, cette faon dinitialiser devient impossible.
134
10. Constructeurs et Destructeurs 10.3. Cas gnral
} ;
obj : : obj ( ) {
cout << " hel l o " << endl ;
}
. . .
obj a ; / / a p p e l l e l e c o ns t r uc t e ur par d f a ut
afche "hello".
Le constructeur vide obj::obj() est appel chaque fois quon construit
un objet sans prciser de paramtre. Font exception les paramtres des fonc-
tions et leur valeur de retour qui, eux, sont construits comme des recopies
des objets passs en paramtre ou retourns
a
.
a. Nous allons voir plus loin cette construction par copie.
Ainsi, le programme :
# i ncl ude <i ostream>
usi ng namespace st d ;
c l a s s obj {
publ i c :
obj ( ) ;
} ;
obj : : obj ( ) {
cout << " obj " ;
}
void f ( obj d) {
}
obj g ( ) {
obj e ;
cout << 6 << " " ;
ret urn e ;
}
i nt main ( )
{
cout << 0 << " " ;
obj a ;
cout << 1 << " " ;
f or ( i nt i =2; i <=4; i ++) {
obj b ;
cout << i << " " ;
}
f ( a ) ;
cout << 5 << " " ;
a=g ( ) ;
135
10.3. Cas gnral 10. Constructeurs et Destructeurs
ret urn 0;
}
afche :
0 obj 1 obj 2 obj 3 obj 4 5 obj 6
Bien reprer les deux objets non construits avec obj :: obj () : le paramtre d de f () , copie
de a, et la valeur de retour de g(), copie de e.
10.3.2 Plusieurs constructeurs
Un objet peut avoir plusieurs constructeurs.
c l a s s poi nt {
i nt x , y ;
publ i c :
poi nt ( i nt X, i nt Y) ;
poi nt ( i nt V) ;
} ;
poi nt : : poi nt ( i nt X, i nt Y) {
x=X;
y=Y;
}
poi nt : : poi nt ( i nt V) {
x=y=V;
}
. . .
poi nt a ( 2 , 3 ) ; / / c o n s t r u i t ave c po i nt (X, Y)
poi nt b ( 4 ) ; / / c o n s t r u i t ave c po i nt (V)
Il faut cependant retenir la chose suivante :
Si on ne dnit aucun constructeur, tout se passe comme sil ny avait quun
constructeur vide ne faisant rien. Mais attention : ds quon dnit soi-mme
un constructeur, le constructeur vide nexiste plus, sauf si on le rednit soi-
mme.
Par exemple, le programme :
c l a s s poi nt {
i nt x , y ;
} ;
. . .
poi nt a ;
a . s et ( 2 , 3 ) ;
poi nt b ; / / OK
devient, avec un constructeur, un programme qui ne se compile plus :
c l a s s poi nt {
i nt x , y ;
publ i c :
poi nt ( i nt X, i nt Y) ;
136
10. Constructeurs et Destructeurs 10.3. Cas gnral
} ;
poi nt : : poi nt ( i nt X, i nt Y) {
x=X;
y=Y;
}
. . .
poi nt a ( 2 , 3 ) ; / / c o n s t r u i t ave c po i nt (X, Y)
poi nt b ; / / ERREUR! po i nt ( ) n e x i s t e pl us
et il faut alors rajouter un constructeur vide, mme sil ne fait rien :
c l a s s poi nt {
i nt x , y ;
publ i c :
poi nt ( ) ;
poi nt ( i nt X, i nt Y) ;
} ;
poi nt : : poi nt ( ) {
}
poi nt : : poi nt ( i nt X, i nt Y) {
x=X;
y=Y;
}
. . .
poi nt a ( 2 , 3 ) ; / / c o n s t r u i t ave c po i nt (X, Y)
poi nt b ; / / OK! c o n s t r u i t ave c po i nt ( )
10.3.3 Tableaux dobjets
Il nest pas possible de spcier globalement quel constructeur est appel pour les
lments dun tableau. Cest toujours le constructeur vide qui est appel...
poi nt t [ 3 ] ; / / Co ns t r ui t 3 f o i s ave c l e c o ns t r uc t e ur vi de
/ / sur chacun de s l me nt s du t a b l e a u
poi nt s=new poi nt [ n ] ; / / Idem , n f o i s
poi nt u=new poi nt ( 1 , 2 ) [ n ] ; / / ERREUR e t HORREUR!
/ / Un e s s a i de c o n s t r u i r e l e s u[ i ]
/ / ave c po i nt ( 1 , 2 ) , qui n e x i s t e pas
Il faudra donc crire :
poi nt u=new poi nt [ n ] ;
f or ( i nt i =0; i <n ; i ++)
u[ i ] . s et ( 1 , 2 ) ;
ce qui nest pas vraiment identique car on construit alors les points vide puis on les
affecte.
Par contre, il est possible dcrire :
poi nt t [ 3] ={ poi nt ( 1 , 2 ) , poi nt ( 2 , 3 ) , poi nt ( 3 , 4 ) } ;
ce qui nest videmment pas faisable pour un tableau de taille variable.
137
10.4. Objets temporaires 10. Constructeurs et Destructeurs
10.4 Objets temporaires
On peut, en appelant soi-mme un constructeur
a
, construire un objet sans
quil soit rang dans une variable. En fait il sagit dun objet temporaire
sans nom de variable et qui meurt le plus tt possible.
a. Attention, nous avions dj dit quon ne pouvait pas appeler un constructeur dun objet
dj construit. Ici, cest autre chose : on appelle un constructeur sans prciser dobjet !
Ainsi, le programme :
void f ( poi nt p) {
. . .
}
poi nt g ( ) {
poi nt e ( 1 , 2 ) ; / / pour l e r e t o ur ne r
ret urn e ;
}
. . .
poi nt a ( 3 , 4 ) ; / / uni quement pour po uvo i r a p p e l e r f ( )
f ( a ) ;
poi nt b ;
b=g ( ) ;
poi nt c ( 5 , 6 ) ; / / on p o ur r a i t a v o i r e nvi e de f a i r e
b=c ; / / a pour me t t r e b ( 5 , 6 )
peut largement sallger, en ne stockant pas dans des variables les points pour lesquels
ce ntait pas utile :
1 void f ( poi nt p) {
2 . . .
3 }
4 poi nt g ( ) {
5 ret urn poi nt ( 1 , 2 ) ; / / r e t o ur ne d i r e c t e me nt
6 / / l o b j e t t e mp o r a i r e po i nt ( 1 , 2 )
7 }
8 . . .
9 f ( poi nt ( 3 , 4 ) ) ; / / Pas s e d i r e c t e me nt l o b j . temp . po i nt ( 3 , 4 )
10 poi nt b ;
11 b=g ( ) ;
12 b=poi nt ( 5 , 6 ) ; / / a f f e c t e d i r e c t e me nt b l o b j e t
13 / / t e mp o r a i r e po i nt ( 5 , 6 )
Attention la ligne 12 : elle est utile quand b existe dj mais bien comprendre quon
construit un point (5,6) temporaire qui est ensuite affect b. On ne remplit pas b
directement avec (5,6) comme on le ferait avec un b. set (5,6) .
Attention aussi lerreur suivante, trs frquente. Il ne faut pas crire
poi nt p=poi nt ( 1 , 2 ) ; / / NON! ! ! ! ! ! !
mais plutt
poi nt p( 1 , 2 ) ; / / OUI !
138
10. Constructeurs et Destructeurs 10.5. TP
Lutilit de ces objets temporaires est visible sur un exemple rel :
poi nt poi nt : : operat or +( poi nt b) {
poi nt c ( x+b . x , y+b . y ) ;
ret urn c ;
}
. . .
poi nt a ( 1 , 2 ) , b ( 2 , 3 ) ;
c=a+f ( b ) ;
scrira plutt :
poi nt poi nt : : operat or +( poi nt b) {
ret urn poi nt ( x+b . x , y+b . y ) ;
}
. . .
c=poi nt ( 1 , 2) + f ( poi nt ( 2 , 3 ) ) ;
FIGURE 10.1 Jeu de Tron.
10.5 TP
Nous pouvons faire une pause et aller faire le TP que nous proposons en A.9. Il
sagit de programmer le jeu de motos de Tron (gure 10.1).
10.6 Rfrences Constantes
10.6.1 Principe
Lorsquon passe un objet en paramtre une fonction, il est recopi. Cette recopie
est source dinefcacit. Ainsi, dans le programme suivant :
const i nt N=1000;
c l a s s vect eur {
double t [N] ;
. . .
} ;
c l a s s mat ri ce {
double t [N] [N] ;
. . .
139
10.6. Rfrences Constantes 10. Constructeurs et Destructeurs
} ;
/ / r s o ut AX=B
void sol ve ( mat ri ce A, vect eur B, vect eur& X) {
. . .
}
. . .
vect eur b , x ;
mat ri ce a ;
. . .
sol ve ( a , b , x ) ; / / r s o ut ax=b
les variables A et B de la fonction solve() sont des copies des objets a et b de la fonction
appelante. Notez bien que, pass par rfrence, le paramtre X nest pas une copie car
il sagit juste dun lien vers la variable x.
La recopie de a dans A nest pas une trs bonne chose. La variable a fait dans notre
cas pas moins de 8 millions doctets : les recopier dans A prend du temps ! Mme pour
des objets un peu moins volumineux, si une fonction est appele souvent, cette recopie
peut ralentir le programme. Lorsquune fonction est courte, il nest pas rare non plus
que ce temps de recopie soit suprieur celui pass dans la fonction!
Lide est alors, pour des objets volumineux, de les passer eux-aussi par rfrence,
mme si la fonction na pas les modier ! Il suft donc de dnir la fonction solve()
ainsi :
void sol ve ( mat ri ce& A, vect eur& B, vect eur& X) {
. . .
pour acclrer le programme.
Cependant, cette solution nest pas sans danger. Rien ne garantit en effet que solve
ne modie pas ses paramtres A et B. Il est donc possible, suivant la faon dont solve
est programme, quen sortie de solve(a, b,x), a et b eux-mmes aient t modis,
alors que prcdemment ctaient leurs copies A et B qui ltaient. Cest videmment
gnant ! Le C++ offre heureusement la possibilit de demander au compilateur de vrier
quune variable passe par rfrence nest pas modie par la fonction. Il suft de rajouter
const au bon endroit :
void sol ve ( const mat ri ce& A, const vect eur& B, vect eur& X) {
. . .
Si quelque part dans solve (ou dans les sous-fonctions appeles par solve !), la variable
A ou la variable B est modie, alors il y aura erreur de compilation. La rgle est donc :
Lorsquun paramtre obj o dune fonction est de taille importante
a
, cest
une bonne ide de le remplacer par const obj& o.
a. En ralit, le programme sen trouvera acclr pour la plupart des objets courants.
10.6.2 Mthodes constantes
Considrons le programme suivant :
void g( i nt& x ) {
cout << x << endl ;
}
140
10. Constructeurs et Destructeurs 10.6. Rfrences Constantes
void f ( const i nt& y) {
double z=y ; / / OK ne mo d i f i e pas y
g( y ) ; / / OK?
}
. . .
i nt a =1;
f ( a ) ;
La fonction f () ne modie pas son paramtre y et tout va bien. Imaginons une deuxime
version de g() :
void g( i nt& x ) {
x++;
}
Alors y serait modie dans f () cause de lappel g(). Le programme ne se compi-
lerait videmment pas... En ralit, la premire version de g() serait refuse elle aussi
car
pour savoir si une sous-fonction modie ou non un des paramtres dune
fonction, le compilateur ne se base que sur la dclaration de cette sous-
fonction et non sur sa dnition complte
a
.
a. Le C++ nessaie pas de deviner lui-mme si une fonction modie ses paramtres
puisque la logique est que le programmeur indique lui-mme avec const ce quil veut faire,
et que le compilateur vrie que le programme est bien cohrent.
Bref, notre premier programme ne se compilerait pas non plus car lappel g(y) avec
const int& y impose que g() soit dclare void g(const int& x). Le bon programme est
donc :
void g( const i nt& x ) {
cout << x << endl ;
}
void f ( const i nt& y) {
double z=y ; / / OK ne mo d i f i e pas y
g( y ) ; / / OK! Pas b e s o i n d a l l e r r e g a r d e r dans g ( )
}
. . .
i nt a =1;
f ( a ) ;
Avec les objets, nous avons besoin dune nouvelle notion. En effet, considrons
maintenant :
void f ( const obj& o) {
o . g ( ) ; / / OK?
}
Il faut indiquer au compilateur si la mthode g() modie ou non lobjet o. Cela se fait
avec la syntaxe suivante :
c l a s s obj {
. . .
void g ( ) const ;
141
10.7. Destructeur 10. Constructeurs et Destructeurs
. . .
} ;
void obj : : g ( ) const {
. . .
}
void f ( const obj& o) {
o . g ( ) ; / / OK! Mthode c o ns t a nt e
}
Cela nest nalement pas compliqu :
On prcise quune mthode est constante, cest--dire quelle ne modie pas
son objet, en plaant const derrire les parenthses de sa dclaration et de
sa dnition.
On pourrait se demander si toutes ces complications sont bien ncessaires, notre
point de dpart tant juste le passage rapide de paramtres en utilisant les rfrences.
En ralit, placer des const dans les mthodes est une trs bonne chose. Il ne faut pas
le vivre comme une corve de plus, mais comme une faon de prciser sa pense :
"suis-je ou non en train dajouter une mthode qui modie lobjets ?". Le compilateur
va ensuite vrier pour nous la cohrence de ce const avec tout le reste. Ceci a deux
effets importants :
Dcouverte de bugs la compilation. (On pensait quun objet ntait pas modi
et il lest.)
Optimisation du programme
2
.
La n du chapitre peut tre considre comme difcile. Il est toutefois recommand de la com-
prendre, mme si la matrise et la mise en application de ce qui sy trouve est laisse aux plus
avancs.
10.7 Destructeur
Lorsquun objet meurt, une autre de ses mthodes est appele : le destructeur.
Le destructeur :
est appel quand lobjet meurt.
porte le nom de la classe prcd de .
comme les constructeurs, na pas de type.
na pas de paramtres (Il ny a donc quun seul destructeur par classe.)
Un exemple sera plus parlant. Rajoutons un destructeur au programme de la section
10.3 :
2. Lorsque le compilateur sait quun objet reste constant pendant une partie du programme, il peut
viter daller le relire chaque fois. Le const est donc une information prcieuse pour la partie optimi-
sation du compilateur.
142
10. Constructeurs et Destructeurs 10.7. Destructeur
# i ncl ude <i ostream>
usi ng namespace st d ;
c l a s s obj {
publ i c :
obj ( ) ;
~obj ( ) ;
} ;
obj : : obj ( ) {
cout << " obj " ;
}
obj : : ~ obj ( ) {
cout << " dest " ;
}
void f ( obj d) {
}
obj g ( ) {
obj e ;
cout << 6 << " " ;
ret urn e ;
}
i nt main ( )
{
cout << 0 << " " ;
obj a ;
cout << 1 << " " ;
f or ( i nt i =2; i <=4; i ++) {
obj b ;
cout << i << " " ;
}
f ( a ) ;
cout << 5 << " " ;
a=g ( ) ;
ret urn 0;
}
Il afche maintenant :
0 obj 1 obj 2 dest obj 3 dest obj 4 dest dest 5 obj 6 dest dest dest
Reprez bien quel moment les objets sont dtruits. Constatez aussi quil y a des ap-
pels au destructeur pour les objets qui sont construits par copie et pour lesquels nous
navons pas encore parl du constructeur...
143
10.8. Destructeurs et tableaux 10. Constructeurs et Destructeurs
10.8 Destructeurs et tableaux
Le destructeur est appel pour tous les lments du tableau. Ainsi,
1 i f ( a==b) {
2 obj t [ 1 0 ] ;
3 . . .
4 }
appellera 10 fois le constructeur vide en ligne 2 et dix fois le destructeur en ligne 4.
Dans le cas dun tableau dynamique, cest au moment du delete[] que les destructeurs
sont appels (avant la dsallocation du tableau!).
i f ( a==b) {
obj t =new obj [ n ] ; / / n a p p e l s o b j ( )
. . .
del et e [ ] t ; / / n a p p e l s ~o b j ( ) ;
}
Attention : il est possible dcrire delete t sans les []. Cest une erreur !
Cette syntaxe est rserve une autre utilisation du new/delete. Lutiliser
ici a pour consquence de bien dsallouer le tas, mais doublier dappeler les
destructeurs sur les t[i]
.
10.9 Constructeur de copie
Voyons enn ce fameux constructeur. Il na rien de mystrieux. Il sagit dun construc-
teur prenant en paramtre un autre objet, en gnral en rfrence constante.
Le constructeur de copie :
Se dclare : obj::obj(const obj& o);
Est utilis videmment par :
obj a;
obj b(a); // b partir de a
Mais aussi par :
obj a;
obj b=a; // b partir de a, synonyme de b(a)
ne pas confondre avec :
obj a,b;
b=a; // ceci nest pas un constructeur!
Et aussi pour construire les paramtres des fonctions et leur valeur de
retour.
Notre programme exemple est enn complet. En rajoutant :
obj : : obj ( const obj& o) {
cout << " copy " ;
}
il afche :
144
10. Constructeurs et Destructeurs 10.10. Affectation
0 obj 1 obj 2 dest obj 3 dest obj 4 dest copy dest 5 obj 6 copy dest
dest dest
Nous avons enn autant dappels aux constructeurs quau destructeur !
Il reste malgr tout savoir une chose sur ce constructeur, dont nous comprendrons
limportance par la suite :
Lorsquil nest pas programm explicitement, le constructeur par copie re-
copie tous les champs de lobjet copier dans lobjet construit.
Remarquez aussi que lorsquon dnit soi-mme un constructeur, le constructeur vide
par dfaut nexiste plus mais le constructeur de copie par dfaut existe toujours !
10.10 Affectation
Il reste en fait une dernire chose quil est possible de reprogrammer pour un objet :
laffectation. Si laffectation nest pas reprogramme, alors elle se fait naturellement par
recopie des champs. Pour la reprogrammer, on a recours loprateur =. Ainsi a=b, se
lit a.operator=(b) si jamais celui-ci existe. Rajoutons donc :
void obj : : operat or =( const obj&o) {
cout << " = " ;
}
notre programme, et il afche :
0 obj 1 obj 2 dest obj 3 dest obj 4 dest copy dest 5 obj 6 copy dest
= dest dest
On rafne en gnral un peu. Linstruction a=b=c; entre trois entiers marche pour
deux raisons :
Elle se lit a=(b=c);
Linstruction b=c affecte c b et retourne la valeur de c
Pour pouvoir faire la mme chose entre trois objets, on reprogrammera plutt laffec-
tation ainsi :
obj obj : : operat or =( const obj&o) {
cout << " = " ;
ret urn o ;
}
. . .
obj a , b , c ;
a=b=c ; / / OK c a r a =( b=c )
ou mme ainsi, ce qui dpasse nos connaissances actuelles, mais que nous prconisons
car cela vite de recopier un objet au moment du return :
const obj& obj : : operat or =( const obj&o) {
cout << " = " ;
ret urn o ;
}
. . .
obj a , b , c ;
a=b=c ; / / OK c a r a =( b=c )
145
10.11. Objets avec allocation dynamique 10. Constructeurs et Destructeurs
Un dernier conseil :
Attention ne pas abuser ! Il nest utile de reprogrammer le constructeur
par copie et loprateur daffectation que lorsquon veut quils fassent autre
chose que leur comportement par dfaut
a
!
a. Contrairement au constructeur vide, qui, lui, nexiste plus ds quon dnit un autre
constructeur, et quil est donc en gnral indispensable de reprogrammer, mme pour repro-
duire son comportement par dfaut
10.11 Objets avec allocation dynamique
Tout ce que nous venons de voir est un peu abstrait. Nous allons enn dcouvrir
quoi a sert. Considrons le programme suivant :
# i ncl ude <i ostream>
usi ng namespace st d ;
c l a s s vect {
i nt n ;
double t ;
publ i c :
void al l oue ( i nt N) ;
void l i be r e ( ) ;
} ;
void vect : : al l oue ( i nt N) {
n=N;
t =new double [ n ] ;
}
void vect : : l i be r e ( ) {
del et e [ ] t ;
}
i nt main ( )
{
vect v ;
v . al l oue ( 1 0 ) ;
. . .
v . l i be r e ( ) ;
ret urn 0;
}
10.11.1 Construction et destruction
Il apparat videmment que les constructeurs et les destructeurs sont l pour nous
aider :
# i ncl ude <i ostream>
146
10. Constructeurs et Destructeurs 10.11. Objets avec allocation dynamique
usi ng namespace st d ;
c l a s s vect {
i nt n ;
double t ;
publ i c :
vect ( i nt N) ;
~vect ( ) ;
} ;
vect : : vect ( i nt N) {
n=N;
t =new double [ n ] ;
}
vect : : ~ vect ( ) {
del et e [ ] t ;
}
i nt main ( )
{
vect v ( 1 0 ) ;
. . .
ret urn 0;
}
Grce aux constructeurs et au destructeur, nous pouvons enn laisser les
allocations et les dsallocations se faire toutes seules !
10.11.2 Problmes !
Le malheur est que cette faon de faire va nous entraner assez loin pour des dbu-
tants. Nous allons devoir affronter deux types de problmes.
Un problme simple
Puisquil ny a quun seul destructeur pour plusieurs constructeurs, il va falloir faire
attention ce qui se passe dans le destructeur. Rajoutons par exemple un constructeur
vide :
vect : : vect ( ) {
}
alors la destruction dun objet cr vide va vouloir dsallouer un champ t absurde. Il
faudra donc faire, par exemple :
vect : : vect ( ) {
n=0;
}
vect : : ~ vect ( ) {
147
10.11. Objets avec allocation dynamique 10. Constructeurs et Destructeurs
i f ( n! =0)
del et e [ ] t ;
}
Des problmes compliqus
Le programme suivant ne marche pas :
i nt main ( )
{
vect v ( 1 0 ) ,w( 1 0 ) ;
w=v ;
ret urn 0;
}
Pourquoi ? Parce que laffectation par dfaut recopie les champs de v dans ceux de
w. Du coup, v et w se retrouvent avec les mmes champs t ! Non seulement ils iront
utiliser les mmes valeurs, do certainement des rsultats faux, mais en plus une mme
zone du tas va tre dsalloue deux fois, tandis quune autre ne le sera pas
3
!
Il faut alors reprogrammer laffectation, ce qui nest pas trivial. On dcide en gn-
ral de rallouer la mmoire et de recopier les lments du tableau :
const vect& vect : : operat or =( const vect& v) {
i f ( n! =0)
del et e [ ] t ; / / On s e d e s a l l o u e s i n e c e s s a i r e
n=v . n ;
i f ( n! =0) {
t =new double [ n ] ; / / Re a l l o c a t i o n e t r e c o p i e
f or ( i nt i =0; i <n ; i ++)
t [ i ]=v . t [ i ] ;
}
ret urn v ;
}
Cette version ne marche dailleurs pas si on fait v=v car alors v est dsallou avant
dtre recopi dans lui-mme, ce qui provoque une lecture dans une zone qui vient
dtre dsalloue
4
.
10.11.3 Solution!
Des problmes identiques se posent pour le constructeur de copie... Ceci dit, en
factorisant le travail faire dans quelques petites fonctions prives, la solution nest
pas si complique. Nous vous la soumettons en bloc. Elle peut mme servir de schma
pour la plupart des objets similaires
5
:
3. Ne pas dsallouer provoque videmment des fuites de mmoire. Dsallouer deux fois provoque
dans certains cas une erreur. Cest le cas en mode Debug sous Visual, ce qui aide reprer les bugs !
4. Il suft de rajouter un test (&v==this) pour reprer ce cas, ce qui nous dpasse un petit peu...
5. Ceci nest que le premier pas vers une srie de faon de grer les objets. Doit-on recopier les ta-
bleaux ? Les partager en faisant en sorte que le dernier utilisateur soit charg de dsallouer ? Etc, etc.
148
10. Constructeurs et Destructeurs 10.11. Objets avec allocation dynamique
1 # i ncl ude <i ostream>
2 usi ng namespace st d ;
3
4 c l a s s vect {
5 / / champs
6 i nt n ;
7 double t ;
8 / / f o n c t i o n s p r i v e s
9 void a l l oc ( i nt N) ;
10 void k i l l ( ) ;
11 void copy ( const vect& v ) ;
12 publ i c :
13 / / c o ns t r uc t e ur s " o b l i g a t o i r e s "
14 vect ( ) ;
15 vect ( const vect& v ) ;
16 / / d e s t r uc t e ur
17 ~vect ( ) ;
18 / / a f f e c t a t i o n
19 const vect& operat or =( const vect& v ) ;
20 / / c o ns t r uc t e ur s s up p l me nt a i r e s
21 vect ( i nt N) ;
22 } ;
23
24 void vect : : a l l oc ( i nt N) {
25 n=N;
26 i f ( n! =0)
27 t =new double [ n ] ;
28 }
29
30 void vect : : k i l l ( ) {
31 i f ( n! =0)
32 del et e [ ] t ;
33 }
34
35 void vect : : copy ( const vect& v) {
36 a l l oc ( v . n ) ;
37 f or ( i nt i =0; i <n ; i ++) / / OK mme s i n==0
38 t [ i ]=v . t [ i ] ;
39 }
40
41 vect : : vect ( ) {
42 a l l oc ( 0 ) ;
43 }
44
45 vect : : vect ( const vect& v) {
46 copy ( v ) ;
47 }
48
49 vect : : ~ vect ( ) {
149
10.11. Objets avec allocation dynamique 10. Constructeurs et Destructeurs
50 k i l l ( ) ;
51 }
52
53 const vect& vect : : operat or =( const vect& v) {
54 i f ( t hi s !=&v) {
55 k i l l ( ) ;
56 copy ( v ) ;
57 }
58 ret urn v ;
59 }
60
61 vect : : vect ( i nt N) {
62 a l l oc (N) ;
63 }
64
65 / / Pour t e s t e r c o ns t r uc t e ur de c o p i e
66 vect f ( vect a ) {
67 ret urn a ;
68 }
69 / / Pour t e s t e r l e r e s t e
70 i nt main ( )
71 {
72 vect a , b ( 1 0 ) , c ( 1 2 ) , d;
73 a=b ;
74 a=a ;
75 a=c ;
76 a=d;
77 a=f ( a ) ;
78 b=f ( b ) ;
79 ret urn 0;
80 }
150
10. Constructeurs et Destructeurs 10.12. Fiche de rfrence
10.12 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;
...
}
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
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};
Une structure est un objet en-
tirement public (cf objets !)
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
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
Rfrences constantes (pour
un passage rapide) :
void f(const obj& x){
...
}
void g(const obj& x){
f(x); // OK
}
151
10.12. Fiche de rfrence 10. Constructeurs et Destructeurs
Fiche de rfrence (2/3)
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;
Objets
struct obj {
int x; // champ
int f(); // mthode
int g(int y);
};
int obj::f() {
int i=g(3); // mon g
int j=x+i; // mon x
return j;
}
...
int main() {
obj a;
a.x=3;
int i=a.f();
class obj {
int x,y;
void a_moi();
public:
int z;
void pour_tous();
void un_autre(obj A);
};
void obj::a_moi() {
x=..; // OK
..=y; // OK
z=..; // OK
}
void obj::pour_tous() {
x=..; // OK
a_moi(); // OK
}
void une_autre(obj A) {
x=A.x; // OK
A.a_moi(); // OK
}
...
int main() {
obj A,B;
A.x=..; //NON
A.z=..; //OK
A.a_moi(); //NON
A.pour_tous(); //OK
A.une_autre(B); //OK
class obj {
obj operator+(obj B);
};
...
int main() {
obj A,B,C;
C=A+B;
// C=A.operator+(B)
Mthodes constantes :
void obj::f() const{
...
}
void g(const obj& x){
x.f(); // OK
}
Constructeur :
class point {
int x,y;
public:
point(int X,int Y);
};
point::point(int X,
int Y){
x=X;
y=Y;
}
...
point a(2,3);
Constructeur vide :
obj::obj() {
...
}
...
obj a;
Objets temporaires :
point point::operator+(
point b) {
return point(x+b.x,
y+b.y);
}
...
c=point(1,2)
+f(point(2,3));
Destructeur :
obj::~obj() {
...
}
Constructeur de copie :
obj::obj(const obj& o){
...
}
Utilis par :
- obj b(a);
- obj b=a;
// mieux que obj b;b=a;
- paramtres des fonctions
- valeur de retour
Affectation :
obj& obj::operator=(
const obj&o){
...
return
*
this;
}
Objets avec allocation dyna-
mique automatique : cf section
10.11
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...
152
10. Constructeurs et Destructeurs 10.12. Fiche de rfrence
Fiche de rfrence (3/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:
...;
}
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
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;
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;
Faire des objets.
Ne pas toujours faire des ob-
jets !
Penser interface / implmen-
tation / utilisation.
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!
class point {
int x,y;
public:
...
};
...
point a={2,3}; // NON
Oublier de rednir le
constructeur vide.
point p=point(1,2);//NON
point p(1,2); // OUI
obj
*
t=new obj[n];
...
delete t; // manque []
153
10.13. Devoir crit 10. Constructeurs et Destructeurs
10.13 Devoir crit
Vous pouvez maintenant vous confronter aux devoirs crits proposs en annexe,
par exemple B.13 et B.12. Vous avez toutes les connaissances ncessaires...
154
11. En vrac...
Chapitre 11
En vrac...
Nous commenons avec ce chapitre un tour de tout ce qui est utile et mme souvent in-
dispensable et que nous navons pas encore vu : chanes de caractres, chiers, etc. Encore une
fois, nous ne verrons pas tout de manire exhaustive, mais les fonctions les plus couramment
utilises.
Voil. Cest tout pour aujourdhui ! Nous continuerons au prochain chapitre. Il est donc
temps de retrouver notre clbre che de rfrence...
165
11.7. Fiche de rfrence 11. En vrac...
11.7 Fiche de rfrence
Fiche de rfrence (1/4)
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;
...
}
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
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};
Une structure est un objet en-
tirement public (cf objets !)
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
Type numr :
enum Dir{nord,est,
sud,ouest};
void avance(Dir d);
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:
...;
}
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;
Faire des objets.
Ne pas toujours faire des ob-
jets !
Penser interface / implmen-
tation / utilisation.
166
11. En vrac... 11.7. Fiche de rfrence
Fiche de rfrence (2/4)
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
Rfrences constantes (pour
un passage rapide) :
void f(const obj& x){
...
}
void g(const obj& x){
f(x); // OK
}
Valeurs par dfaut :
void f(int a,int b=0);
void g() {
f(12); // f(12,0);
f(10,2);// f(10,2);
}
void f(int a,int b) {
// ...
}
Inline (appel rapide) :
inline double sqr(
double x) {
return x
*
x;
}
...
double y=sqr(z-3);
Rfrence en retour :
int i; // Var. globale
int& f() {
return i;
}
...
f()=3; // i=3!
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;
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...
167
11.7. Fiche de rfrence 11. En vrac...
Fiche de rfrence (3/4)
Objets
struct obj {
int x; // champ
int f(); // mthode
int g(int y);
};
int obj::f() {
int i=g(3); // mon g
int j=x+i; // mon x
return j;
}
...
int main() {
obj a;
a.x=3;
int i=a.f();
class obj {
int x,y;
void a_moi();
public:
int z;
void pour_tous();
void un_autre(obj A);
};
void obj::a_moi() {
x=..; // OK
..=y; // OK
z=..; // OK
}
void obj::pour_tous() {
x=..; // OK
a_moi(); // OK
}
void une_autre(obj A) {
x=A.x; // OK
A.a_moi(); // OK
}
...
int main() {
obj A,B;
A.x=..; //NON
A.z=..; //OK
A.a_moi(); //NON
A.pour_tous(); //OK
A.une_autre(B); //OK
class obj {
obj operator+(obj B);
};
...
int main() {
obj A,B,C;
C=A+B;
// C=A.operator+(B)
Mthodes constantes :
void obj::f() const{
...
}
void g(const obj& x){
x.f(); // OK
}
Constructeur :
class point {
int x,y;
public:
point(int X,int Y);
};
point::point(int X,
int Y){
x=X;
y=Y;
}
...
point a(2,3);
Constructeur vide :
obj::obj() {
...
}
...
obj a;
Objets temporaires :
point point::operator+(
point b) {
return point(x+b.x,
y+b.y);
}
...
c=point(1,2)
+f(point(2,3));
Destructeur :
obj::~obj() {
...
}
Constructeur de copie :
obj::obj(const obj& o){
...
}
Utilis par :
- obj b(a);
- obj b=a;
// mieux que obj b;b=a;
- paramtres des fonctions
- valeur de retour
Affectation :
obj& obj::operator=(
const obj&o){
...
return
*
this;
}
Objets avec allocation dyna-
mique automatique : cf section
10.11
Accesseurs :
class mat {
double
*
x;
public:
double& operator()
(int i,int j){
assert(i>=0 ...);
return x[i+M
*
j];
}
double operator()
(int i,int j)const{
assert(i>=0 ...);
return x[i+M
*
j];
}
...
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();
if (s1==s1) ...
if (s1!=s2) ...
if (s1<s2) ...
size_t i=s.find(h),
j=s.find(h,3);
k=s.find("hop");
l=s.find("hop",3);
a="comment";
b="a va?";
txt=a+" "+b;
s1="un deux trois";
s2=string(s1,3,4);
getline(cin,s);
getline(cin,s,:);
const char
*
t=s.c_str();
#include <ctime>
s=double(clock())
/CLOCKS_PER_SEC;
#define _USE_MATH_DEFINES
#include <cmath>
double pi=M_PI;
168
11. En vrac... 11.7. Fiche de rfrence
Fiche de rfrence (4/4)
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
#include <fstream>
using namespace std;
ofstream f("hop.txt");
f << 1 << << 2.3;
f.close();
ifstream g("hop.txt");
if (!g.is_open()) {
return 1;
}
int i;
double x;
g >> i >> x;
g.close();
do {
...
} while (!(g.eof());
ofstream f;
f.open("hop.txt");
double x[10],y;
ofstream f("hop.bin",
ios::binary);
f.write((const char
*
)x,
10
*
sizeof(double));
f.write((const char
*
)&y,
sizeof(double));
f.close();
ifstream g("hop.bin",
ios::binary);
g.read((char
*
)x,
10
*
sizeof(double));
g.read((const char
*
)&y,
sizeof(double));
g.close();
string nom;
ifstream f(nom.c_str());
#include <sstream>
using namespace std;
stringstream f;
// Chane vers entier
f << s;
f >> i;
// Entier vers chane
f.clear();
f << i;
f >> s;
ostream& operator<<(
ostream& f,
const point&p) {
f<<p.x<< << p.y;
return f;
}
istream& operator>>(
istream& f,point& p){
f>>p.x>>p.y;
return f;
}
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!
class point {
int x,y;
public:
...
};
...
point a={2,3}; // NON
Oublier de rednir le
constructeur vide.
point p=point(1,2);//NON
point p(1,2); // OUI
obj
*
t=new obj[n];
...
delete t; // manque []
//NON!
void f(int a=2,int b);
void f(int a,int b=0);
void f(int a);// NON!
Ne pas tout mettre inline!
int f() {
...
}
...
f()=3; // HORREUR!
int& f() {
int i;
return i;
}
...
f()=3; // NON!
Imagine++
Voir documentation...
169
12. En vrac (suite) ...
Chapitre 12
En vrac (suite) ...
Nous continuons dans ce chapitre un inventaire de diverses choses utiles. Parmi elles, les
structures de donnes de la STL (Standard Template Library) ncessiteront la comprhension
des template. Nous aborderons donc cet aspect intressant du C++
Toujours sous forme dun inventaire, le dbut de ce chapitre sera un peu en vrac,
mais nous nous limiterons toujours quelques aspects pratiques du C++ souvent uti-
liss donc souvent rencontrs dans les programmes des autres ! La n du chapitre est
plus utile et plus fondamentale : nous y abordons les template, ou programmation
gnrique.
12.1 Oprateur binaires
Parmi les erreurs classiques, il y a videmment celle qui consiste remplacer
i f ( i ==0)
. . .
par
i f ( i =0) / / NON! ! !
. . .
qui range 0 dans i puis considre 0 comme un boolen, cest dire false. Une autre
erreur frquente consiste crire
i f ( i ==0 & j ==2) / / NON! ! !
. . .
au lieu de
i f ( i ==0 && j ==2)
. . .
Cette erreur nest possible que parce que & existe. Il sagit de oprateur binaire "ET"
sur des entiers. Il est dni ainsi : effectuer a&b revient considrer lcriture de a et
de b en binaire puis effectuer un "ET" bit par bit (avec la table 1&1 donne 1 ; 1&0, 0&1
et 0&0 donnent 0). Par exemple : 13&10 vaut 8 car en binaire 1101&1010 vaut 1000.
Il existe ainsi toute une panoplie doprateurs binaires :
12.2. Valeur conditionnelle 12. En vrac (suite) ...
symbole utilisation nom rsultat exemple
& a&b et 1&1=1, 0 sinon 13&10=8
| a|b ou 0|0=0, 1 sinon 13|10=15
^ a^b ou exclusif 1^0=0^1=1, 0 sinon 13^10=7
>> a>>n dcalage dcale les bits de a n fois vers la 13>>2=3
droite droite et comble gauche avec des 0
(les n premiers de droite sont perdus)
<< a<<n dcalage dcale les bits de a n fois vers la 5<<2=20
gauche gauche et comble droite avec des 0
~ ~a complment ~1=0, ~0=1 ~13=14
Remarques :
Ces instructions sont particulirement rapides car simples pour le processeur.
Le fait que a^b existe est aussi source de bugs (il ne sagit pas de la fonction
puissance !)
Le rsultat de ~ dpend en fait du type : si par exemple i est un entier non sign
sur 8 bits valant 13, alors ~i vaut 242, car ~00001101 vaut 11110010.
En pratique, tout cela ne sert pas faire joli ou savant, mais manipuler les nombres
bit par bit. Ainsi, il arrive souvent quon utilise un int pour mmoriser un certain
nombre de proprits en utilisant le moins possible de mmoire avec la convention
que la proprit n est vraie ssi le n
eme
bit de lentier est 1. Un seul entier de 32 bits
pourra par ainsi mmoriser 32 proprits l o il aurait fallu utiliser 32 variables de
type bool. Voici comment on utilise les oprateurs ci-dessus pour manipuler les bits en
question :
i|=(1<<n) passe 1 le bit n de i
i&=~(1<<n) passe 0 le bit n de i
i^=(1<<n) inverse le bit n de i
if ( i&(1<<n)) vrai ssi le bit n de i est 1
Il existe aussi dautres utilisations frquentes des oprateurs binaires, non pour des
raisons de gain de place, mais pour des raisons de rapidit :
(1<<n) vaut 2
n
(sinon il faudrait faire int (pow(2.,n)) !)
( i>>1) calcule i/2 rapidement
( i>>n) calcule i/2
n
rapidement
( i&255) calcule i%256 rapidement (idem pour toute puissance de 2)
12.2 Valeur conditionnelle
Il arrive quon ait choisir entre deux valeurs en fonction du rsultat dun test. Une
construction utile est alors :
( t e s t ) ? val 1 : val 2
qui vaut val1 si test est vrai et val2 sinon. Ainsi
i f ( x>y)
maxi=x ;
e l s e
maxi=y ;
172
12. En vrac (suite) ... 12.3. Boucles et break
pourra tre remplac par :
maxi =( x>y) ? x : y ;
Il ne faut pas abuser de cette construction sous peine de programme illisible !
12.3 Boucles et break
Nous avons dj rencontr la section 8.4 linstruction continue qui saute la n
dune boucle et passe au tour daprs. Trs utile aussi, la commande break sort de la boucle
en ignorant tout ce quil restait y faire. Ainsi le programme :
bool a r r e t e r =f a l s e ;
f or ( i nt i =0; i <N && ! a r r e t e r ; i ++) {
A;
i f ( B)
a r r e t e r =t r ue ;
e l s e {
C;
i f (D)
a r r e t e r =t r ue ;
e l s e {
E;
}
}
}
devient de faon plus lisible et plus naturelle :
f or ( i nt i =0; i <N; i ++) {
A;
i f ( B)
break ;
C;
i f (D)
break ;
E;
}
Questions rcurrentes des dbutants :
1. break ne sort pas dun if!
i f ( . . . ) {
. . . ;
i f ( . . . )
break ; / / NON! ! ! Ne s o r t pas du i f ! ( mai s v e nt ue l l e me nt
/ / d un f o r qui s e r a i t aut our . . . )
. . .
}
2. break ne sort que de la boucle courante, pas des boucles autour :
173
12.4. Variables statiques 12. En vrac (suite) ...
f or ( i nt i =0; i <N; i ++) {
. . .
f or ( i nt j =0; j <M; j ++) {
. . .
i f ( . . . )
break ; / / t e r mi ne l a b o uc l e en j e t pa s s e donc
/ / en l i g n e 10 ( pas en l i g n e 12)
. . .
}
. . .
}
. . .
3. break et continue marchent videmment avec while et do ... while de la
mme faon quavec for.
12.4 Variables statiques
Il arrive souvent quon utilise une variable globale pour mmoriser de faon per-
manente une valeur qui nintresse quune seule fonction :
/ / Fo nc t i o n random qui a p p e l l e s r and ( ) t o ut e s e u l e
/ / au pr e mi e r a ppe l . . .
bool f i r s t =t r ue ;
double random( ) {
i f ( f i r s t ) {
f i r s t =f a l s e ;
srand ( ( unsigned i nt ) time ( 0 ) ) ;
}
ret urn double ( rand ( ) ) /RAND_MAX;
}
Le danger est alors que tout le reste du programme voie cette variable globale et luti-
lise ou la confonde avec une autre variable globale. Il est possible de cacher cette variable
dans la fonction grce au mot cl static plac devant la variable :
/ / Fo nc t i o n random qui a p p e l l e s r and ( ) t o ut e s e u l e
/ / au pr e mi e r a ppe l . . . ave c s a v a r i a b l e g l o b a l e
/ / masque l i n t r i e u r
double random( ) {
s t a t i c bool f i r s t =t r ue ; / / Ne pas o u b l i e r s t a t i c !
i f ( f i r s t ) {
f i r s t =f a l s e ;
srand ( ( unsigned i nt ) time ( 0 ) ) ;
}
ret urn double ( rand ( ) ) /RAND_MAX;
}
Attention : il sagit bien dune variable globale et non dune variable locale. Une
variable locale mourrait la sortie de la fonction, ce qui dans lexemple prcdent
donnerait un comportement non dsir !
174
12. En vrac (suite) ... 12.5. const et tableaux
NB : Il est aussi possible de cacher une variable globale dans une classe, toujours
grce static . Nous ne verrons pas comment et renvoyons le lecteur la documenta-
tion du C++.
12.5 const et tableaux
Nous avons vu malgr nous const char comme paramtre de certaines fonctions
(ouverture de chier par exemple). Il nous faut donc lexpliquer : il ne sagit pas dun
pointeur de char qui serait constant mais dun pointeur vers des char qui sont constants ! Il
faut donc retenir que :
plac devant un tableau, const signie que ce sont les lments du tableau
qui ne peuvent tre modis.
Cette possibilit de prciser quun tableau ne peut tre modi est dautant plus im-
portante quun tableau est toujours pass en rfrence : sans le const, on ne pourrait
assurer cette prservation des valeurs :
void f ( i nt t [ 4 ] ) {
. . .
}
void g( const i nt t [ 4 ] ) {
. . .
}
void h( const i nt t , i nt n) {
. . .
}
. . .
i nt a [ 4 ] ;
f ( a ) ; / / mo d i f i e peut t r e a [ ]
g( a ) ; / / ne mo d i f i e pas a [ ]
h( a , 4 ) ; / / ne mo d i f i e pas a [ ]
. . .
12.6 template
12.6.1 Principe
Considrons la fonction classique pour changer deux variables :
void echange ( i nt& a , i nt& b) {
i nt tmp;
tmp=a ;
a=b ;
b=tmp;
}
175
12.6. template 12. En vrac (suite) ...
. . .
i nt i , j ;
. . .
echange ( i , j ) ;
Si nous devions maintenant changer deux variables de type double, il faudrait r-
crire une autre fonction echange(), identique aux dnitions de type prs. Heureuse-
ment, le C++ offre la possibilit de dnir une fonction avec un type gnrique, un peu
comme un type variable, que le compilateur devra "instancier" au moment de lappel
de la fonction en un type prcis. Cette "programmation gnrique" se fait en dnissant
un "template" :
/ / Echange deux v a r i a b l e s de n i mpo r t e q ue l t ype T
t empl at e <typename T>
void echange ( T& a , T& b) {
T tmp;
tmp=a ;
a=b ;
b=tmp;
}
. . .
i nt a=2 , b=3;
double x =2. 1 , y =2. 3;
echange ( a , b ) ; / / " i n s t a n c i e " T en i nt
echange ( x , y ) ; / / " i n s t a n c i e " T en do ubl e
. . .
Autre exemple :
/ / Maximum de deux v a r i a b l e s ( a c o nd i t i o n que o pe r a t o r >( ) e x i s t e
/ / pour l e t ype T)
t empl at e <typename T>
T maxi ( T a , T b) {
ret urn ( a>b) ? a : b ;
}
La dclaration typename T prcise le type gnrique. On peut en prciser plusieurs :
/ / Che r che e1 dans l e t a b l e a u t ab1 e t met
/ / dans e2 l e l e me nt de t ab2 de meme i n d i c e
/ / Re nvoi e f a l s e s i non t r o uv
t empl at e <typename T1 , typename T2>
bool cherche ( T1 e1 , T2& e2 , const T1 tab1 , const T2 tab2 , i nt n) {
f or ( i nt i =0; i <n ; i ++)
i f ( t ab1 [ i ]==e1 ) {
e2=t ab2 [ i ] ;
ret urn t r ue ;
}
ret urn f a l s e ;
}
. . .
s t r i ng noms [ 3] ={ " j ean " , " pi er r e " , " paul " } ;
i nt ages [ 3 ] ={ 2 1 , 2 5 , 1 5 } ;
176
12. En vrac (suite) ... 12.6. template
. . .
s t r i ng nm=" pi er r e " ;
i nt ag ;
i f ( cherche (nm, ag , noms , ages , 3 ) )
cout << nm << " a " << ag << " ans " << endl ;
. . .
12.6.2 template et chiers
Il faut bien comprendre que
Le compilateur ne fabrique pas une fonction "magique" qui arrive tra-
vailler sur plusieurs types ! Il cre en ralit autant de fonctions quil y a
dutilisations de la fonction gnrique avec des types diffrents (ie. dins-
tanciations)
Pour ces raisons :
1. Faire des fonctions template ralentit la compilation et augmente la taille des pro-
grammes.
2. On ne peut plus mettre la dclaration dans un chier den-tte et la dnition
dans un chier .cpp, car tous les chiers utilisateurs doivent connatre aussi la
dnition. Du coup, la rgle est de tout mettre dans le chier den-tte
1
.
12.6.3 Classes
Il est frquent quune dnition de classe soit encore plus utile si elle est gnrique.
Cest possible. Mais attention! Dans le cas des fonctions, cest le compilateur qui d-
termine tout seul quels types sont utiliss. Dans le cas des classes, cest lutilisateur qui
doit prciser en permanence avec la syntaxe obj<type> le type utilis :
/ / Pa i r e de deux v a r i a b l e s de t ype T
t empl at e <typename T>
c l a s s pai r e {
T x [ 2 ] ;
publ i c :
/ / c o ns t r uc t e ur s
pai r e ( ) ;
pai r e ( T A, T B ) ;
/ / a c c e s s e u r s
T operat or ( ) ( i nt i ) const ;
T& operat or ( ) ( i nt i ) ;
} ;
t empl at e <typename T>
pai re <T>: : pai r e ( ) {
1. Ceci est gnant et va lencontre du principe consistant mettre les dclarations dans le .h et
masquer les dnitions dans le .cpp. Cette remarque a dj t formule pour les fonctions inline. Le
langage prvoit une solution avec le mot cl export, mais les compilateurs actuels nimplmentent pas
encore cette fonctionnalit !
177
12.6. template 12. En vrac (suite) ...
}
t empl at e <typename T>
pai re <T>: : pai r e ( T A, T B) {
x [ 0] =A; x [ 1] =B;
}
t empl at e <typename T>
T pai re <T>: : operat or ( ) ( i nt i ) const {
as s e r t ( i ==0 || i ==1) ;
ret urn x [ i ] ;
}
t empl at e <typename T>
T& pai re <T>: : operat or ( ) ( i nt i ) {
as s e r t ( i ==0 || i ==1) ;
ret urn x [ i ] ;
}
. . .
pai re <i nt > p( 1 , 2 ) , r ;
i nt i =p ( 1 ) ;
pai re <double> q ;
q ( 1 ) =2 . 2 ;
. . .
Dans le cas de la classe trs simple ci-dessus, on aura recours aux fonctions inline vues
en 11.4.5 :
/ / Pa i r e de deux v a r i a b l e s de t ype T
/ / Fo nc t i o ns c o ur t e s e t r a p i d e s en i n l i n e
t empl at e <typename T>
c l a s s pai r e {
T x [ 2 ] ;
publ i c :
/ / c o ns t r uc t e ur s
i nl i ne pai r e ( ) { }
i nl i ne pai r e ( T A, T B) { x [ 0] =A; x [ 1] =B; }
/ / a c c e s s e u r s
i nl i ne T operat or ( ) ( i nt i ) const {
as s e r t ( i ==0 || i ==1) ;
ret urn x [ i ] ;
}
i nl i ne T& operat or ( ) ( i nt i ) {
as s e r t ( i ==0 || i ==1) ;
ret urn x [ i ] ;
}
} ;
Lorsque plusieurs types sont gnriques, on les spare par une virgule :
/ / Pa i r e de deux v a r i a b l e s de t ype s d i f f r e n t s
178
12. En vrac (suite) ... 12.6. template
t empl at e <typename S , typename T>
c l a s s pai r e {
publ i c :
/ / Tout en p ub l i c pour s i mp l i f i e r
S x ;
T y ;
/ / c o ns t r uc t e ur s
i nl i ne pai r e ( ) { }
i nl i ne pai r e ( S X, T Y) { x=X; y=Y; }
} ;
. . .
pai re <i nt , double> P ( 1 , 2 . 3 ) ;
pai re <s t r i ng , i nt > Q;
Q. x=" pi er r e " ;
Q. y=25;
. . .
Enn, on peut aussi rendre gnrique le choix dun entier :
/ / nup l e t de v a r i a b l e s de t ype T
/ / At t e nt i o n : chaque nupl e t <T, N> s e r a un t ype d i f f r e n t
t empl at e <typename T, i nt N>
c l a s s nupl et {
T x [N] ;
publ i c :
/ / a c c e s s e u r s
i nl i ne T operat or ( ) ( i nt i ) const {
as s e r t ( i >=0 && i <N) ;
ret urn x [ i ] ;
}
i nl i ne T& operat or ( ) ( i nt i ) {
as s e r t ( i >=0 && i <N) ;
ret urn x [ i ] ;
}
} ;
. . .
nupl et <i nt , 4 > A;
A( 1 ) =3 ;
nupl et <s t r i ng , 2 > B;
B( 1) = " pi er r e " ;
. . .
Les fonctions doivent videmment sadapter :
t empl at e <typename T, i nt N>
T somme( nupl et <T, N> u) {
T s=u ( 0 ) ;
f or ( i nt i =1; i <N; i ++)
s+=u( i ) ;
ret urn s ;
}
179
12.6. template 12. En vrac (suite) ...
. . .
nupl et <double , 3 > C;
. . .
cout << somme(C) << endl ;
. . .
Au regard de tout a, on pourrait tre tent de mettre des template partout. Et bien,
non!
Les templates sont dlicats programmer, longs compiler, etc. Il ne faut
pas en abuser ! Il vaut mieux plutt commencer des classes ou des fonctions
sans template. On ne les rajoute que lorsquapparat le besoin de rutiliser
lexistant avec des types diffrents. Et rptons-le encore une fois : le compi-
lateur cre une nouvelle classe ou une nouvelle fonction chaque nouvelle
valeur (instanciation) des types ou des entiers gnriques
a
.
a. Les nuplets ci-dessus, nont donc rien--voir avec des tableaux de taille variables. Tout
se passe comme si on avait programm des tableaux de taille constante pour plusieurs valeurs
de la taille.
12.6.4 STL
Les template sont dlicats programmer, mais pas utiliser. Le C++ offre un cer-
tain nombre de fonctions et de classes utilisant les template. Cet ensemble est commu-
nment dsign sous le nom de STL (Standard Template Library). Vous en trouverez
la documentation complte sous Visual ou dfaut sur Internet. Nous exposons ci-
dessous quelques exemples qui devraient pouvoir servir de point de dpart et faciliter
la comprhension de la documentation.
Des fonctions simples comme min et max sont dnies de faon gnrique :
i nt i =max ( 1 , 3 ) ;
double x=min ( 1 . 2 , 3 . 4 ) ;
Attention : une erreur classique consiste appeler max(1,2.3) : le compilateur linter-
prte comme le max dun int et dun double ce qui provoque une erreur ! Il faut taper
max(1.,2.3).
Les complexes sont eux-aussi gnriques, laissant variable le choix du type de leurs
parties relle et imaginaire :
# i ncl ude <complex>
usi ng namespace st d ;
. . .
complex<double> z1 ( 1 . 1 , 3 . 4 ) , z2 ( 1 , 0 ) , z3 ;
z3=z1+z2 ;
cout << z3 << endl ;
double a=z3 . r e al ( ) , b=z3 . imag ( ) ;
double m=abs ( z3 ) ; / / modul e
double th=arg ( z3 ) ; / / argument
Les couples sont aussi offerts par la STL :
pai r <i nt , s t r i ng > P( 2 , " hop" ) ;
P. f i r s t =3;
P. second=" hop" ;
180
12. En vrac (suite) ... 12.6. template
Enn, un certain nombre de structures de donnes sont fournies et sutilisent suivant
un mme schma. Voyons lexemple des listes :
# i ncl ude <l i s t >
usi ng namespace st d ;
. . .
l i s t <i nt > l ; / / l =[ ]
l . push_f ront ( 2 ) ; / / l =[ 2]
l . push_f ront ( 3 ) ; / / l =[ 3 , 2]
l . push_back ( 4 ) ; / / l =[ 3 , 2 , 4]
l . push_f ront ( 5 ) ; / / l =[ 5 , 3 , 2 , 4]
l . push_f ront ( 2 ) ; / / l =[ 2 , 5 , 3 , 2 , 4]
Pour dsigner un emplacement dans une liste, on utilise un itrateur. Pour dsigner un
emplacement en lecture seulement, on utilise un itrateur constant. Le sert ensuite
accder llment situ lemplacement dsign par litrateur. Seule difcult : le
type de ces itrateurs est un peu compliqu taper
2
:
l i s t <i nt >: : c ons t _ i t e r a t or i t ;
i t =l . begi n ( ) ; / / Po i nt e ve r s l e d but de l a l i s t e
cout << i t << endl ; / / a f f i c h e 2
i t =l . f i nd ( 3 ) ; / / Po i nt e ve r s l e nd r o i t ou s e t r o uve
/ / l e pr e mi e r 3
i f ( i t ! = l . end ( ) )
cout << " 3 es t dans l a l i s t e " << endl ;
l i s t <i nt >: : i t e r a t o r i t 2 ;
i t 2 =l . f i nd ( 3 ) ; / / Po i nt e ve r s l e nd r o i t ou s e t r o uve
/ / l e pr e mi e r 3
i t =6; / / mai nt e nant l =[ 2 , 5 , 6 , 2 , 4]
Les itrateurs servent galement parcourir les listes (do leur nom!) :
/ / Pa r c o ur t e t a f f i c h e une l i s t e
t empl at e <typename T>
void a f f i c he ( l i s t <T> l ) {
cout << " [ " ;
f or ( l i s t <T>: : c ons t _ i t e r a t or i t =l . begi n ( ) ; i t ! = l . end ( ) ; i t ++)
cout << i t << ;
cout << ] << endl ;
}
/ / Rempl ace a par b dans une l i s t e
t empl at e <typename T>
void remplace ( l i s t <T>& l , T a , T b) {
f or ( l i s t <T>: : i t e r a t o r i t =l . begi n ( ) ; i t ! = l . end ( ) ; i t ++)
i f ( i t ==a )
i t =b ;
}
. . .
a f f i c he ( l ) ;
2. Nous navons pas vu comment dnir de nouveaux types cachs dans des classes ! Cest ce qui est
fait ici...
181
12.7. Fiche de rfrence 12. En vrac (suite) ...
remplace ( l , 2 , 1 ) ; / / mai nt e nant l =[ 1 , 5 , 3 , 1 , 4]
. . .
Enn, on peut appeler des algorithmes comme le tri de la liste :
l . s or t ( ) ;
a f f i c he ( l ) ;
Sur le mme principe que les listes, vous trouverez dans la STL :
Les piles ou stack (Last In First Out).
Les les ou queue (First In First Out).
Les ensembles ou set (pas deux fois le mme lment).
Les vecteurs ou vector (tableaux de taille variable).
Les tas ou heap (arbres binaires de recherche).
Les tables ou map (table de correspondance cl/valeur).
Et quelques autres encore...
12.7 Fiche de rfrence
Fiche de rfrence (1/6)
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;
...
}
for (int i=...) {
...
if (t[i]==s){
...
// quitte la boucle
break;
}
...
}
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
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:
...;
}
mx=(x>y)?x:y;
182
12. En vrac (suite) ... 12.7. Fiche de rfrence
Fiche de rfrence (2/6)
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
Rfrences constantes (pour
un passage rapide) :
void f(const obj& x){
...
}
void g(const obj& x){
f(x); // OK
}
Valeurs par dfaut :
void f(int a,int b=0);
void g() {
f(12); // f(12,0);
f(10,2);// f(10,2);
}
void f(int a,int b) {
// ...
}
Inline (appel rapide) :
inline double sqr(
double x) {
return x
*
x;
}
...
double y=sqr(z-3);
Rfrence en retour :
int i; // Var. globale
int& f() {
return i;
}
...
f()=3; // i=3!
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};
Une structure est un objet en-
tirement public (cf objets !)
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
Type numr :
enum Dir{nord,est,
sud,ouest};
void avance(Dir d);
Variables statiques :
int f() {
static bool first=true;
if (first) {
first=false;
...
}
...
}
183
12.7. Fiche de rfrence 12. En vrac (suite) ...
Fiche de rfrence (3/6)
Objets
struct obj {
int x; // champ
int f(); // mthode
int g(int y);
};
int obj::f() {
int i=g(3); // mon g
int j=x+i; // mon x
return j;
}
...
int main() {
obj a;
a.x=3;
int i=a.f();
class obj {
int x,y;
void a_moi();
public:
int z;
void pour_tous();
void un_autre(obj A);
};
void obj::a_moi() {
x=..; // OK
..=y; // OK
z=..; // OK
}
void obj::pour_tous() {
x=..; // OK
a_moi(); // OK
}
void une_autre(obj A) {
x=A.x; // OK
A.a_moi(); // OK
}
...
int main() {
obj A,B;
A.x=..; //NON
A.z=..; //OK
A.a_moi(); //NON
A.pour_tous(); //OK
A.une_autre(B); //OK
class obj {
obj operator+(obj B);
};
...
int main() {
obj A,B,C;
C=A+B;
// C=A.operator+(B)
Mthodes constantes :
void obj::f() const{
...
}
void g(const obj& x){
x.f(); // OK
}
Constructeur :
class point {
int x,y;
public:
point(int X,int Y);
};
point::point(int X,
int Y){
x=X;
y=Y;
}
...
point a(2,3);
Constructeur vide :
obj::obj() {
...
}
...
obj a;
Objets temporaires :
point point::operator+(
point b) {
return point(x+b.x,
y+b.y);
}
...
c=point(1,2)
+f(point(2,3));
Destructeur :
obj::~obj() {
...
}
Constructeur de copie :
obj::obj(const obj& o){
...
}
Utilis par :
- obj b(a);
- obj b=a;
// mieux que obj b;b=a;
- paramtres des fonctions
- valeur de retour
Affectation :
obj& obj::operator=(
const obj&o){
...
return
*
this;
}
Objets avec allocation dyna-
mique automatique : cf section
10.11
Accesseurs :
class mat {
double
*
x;
public:
double& operator()
(int i,int j){
assert(i>=0 ...);
return x[i+M
*
j];
}
double operator()
(int i,int j)const{
assert(i>=0 ...);
return x[i+M
*
j];
}
...
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...
STL
min,max,...
complex<double> z;
pair<int,string> p;
p.first=2;
p.second="hop";
#include<list>
using namespace std;
...
list<int> l;
l.push_front(1);
...
if (l.find(3)!=l.end())
...
list<int>::const_iterator
it;
for (it=l.begin();
it!=l.end();it++)
s+=
*
it;
list<int>::iterator it
for (it=l.begin();
it!=l.end();it++)
if (
*
it==2)
*
it=4;
stack, queue, heap, map,
set, vector, ...
184
12. En vrac (suite) ... 12.7. Fiche de rfrence
Fiche de rfrence (4/6)
Template
Fonctions :
// A mettre dans LE
// fichier qui lutilise
// ou dans un .h
template <typename T>
T maxi(T a,T b) {
...
}
...
// Le type est trouv
// tout seul!
maxi(1,2); //int
maxi(.2,.3); //double
maxi("a","c");//string
Objets :
template <typename T>
class paire {
T x[2];
public:
paire() {}
paire(T a,T b) {
x[0]=a;x[1]=b;
}
T somme()const;
};
...
template <typename T>
T paire<T>::somme()const{
return x[0]+x[1];
}
...
// Le type doit tre
// prcis!
paire<int> a(1,2);
int s=a.somme();
paire<double> b;
...
Multiples :
template <typename T,
typename S>
class hop {
...
};
...
hop<int,string> A;
...
Entiers :
template <int N>
class hop {
..
};
...
hop<3> A;
hop<5> B;
...
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
#include <fstream>
using namespace std;
ofstream f("hop.txt");
f << 1 << << 2.3;
f.close();
ifstream g("hop.txt");
if (!g.is_open()) {
return 1;
}
int i;
double x;
g >> i >> x;
g.close();
do {
...
} while (!(g.eof());
ofstream f;
f.open("hop.txt");
double x[10],y;
ofstream f("hop.bin",
ios::binary);
f.write((const char
*
)x,
10
*
sizeof(double));
f.write((const char
*
)&y,
sizeof(double));
f.close();
ifstream g("hop.bin",
ios::binary);
g.read((char
*
)x,
10
*
sizeof(double));
g.read((const char
*
)&y,
sizeof(double));
g.close();
string nom;
ifstream f(nom.c_str());
#include <sstream>
using namespace std;
stringstream f;
// Chane vers entier
f << s;
f >> i;
// Entier vers chane
f.clear();
f << i;
f >> s;
ostream& operator<<(
ostream& f,
const point&p) {
f<<p.x<< << p.y;
return f;
}
istream& operator>>(
istream& f,point& p){
f>>p.x>>p.y;
return 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.
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;
Faire des objets.
Ne pas toujours faire des ob-
jets !
Penser interface / implmen-
tation / utilisation.
185
12.7. Fiche de rfrence 12. En vrac (suite) ...
Fiche de rfrence (5/6)
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();
if (s1==s1) ...
if (s1!=s2) ...
if (s1<s2) ...
size_t i=s.find(h),
j=s.find(h,3);
k=s.find("hop");
l=s.find("hop",3);
a="comment";
b="a va?";
txt=a+" "+b;
s1="un deux trois";
s2=string(s1,3,4);
getline(cin,s);
getline(cin,s,:);
const char
*
t=s.c_str();
#include <ctime>
s=double(clock())
/CLOCKS_PER_SEC;
#define _USE_MATH_DEFINES
#include <cmath>
double pi=M_PI;
Oprateurs binaires
and : a&b
or : a|b
xor : a^b
right shift : a>>n
left shift : a<<n
complement : ~a
exemples :
set(i,1) : i|=(1<<n)
reset(i,1) : i&=~(1<<n)
test(i,1) : if (i&(1<<n))
ip(i,1) : i^=(1<<n)
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!
class point {
int x,y;
public:
...
};
...
point a={2,3}; // NON
Oublier de rednir le
constructeur vide.
point p=point(1,2);//NON
point p(1,2); // OUI
obj
*
t=new obj[n];
...
delete t; // manque []
//NON!
void f(int a=2,int b);
void f(int a,int b=0);
void f(int a);// NON!
Ne pas tout mettre inline!
int f() {
...
}
...
f()=3; // HORREUR!
int& f() {
int i;
return i;
}
...
f()=3; // NON!
if (i>0 & i<n) // NON
if (i<0 | i>n) // NON
if (...) {
...
if (...)
break; // Non,
// boucles seulement
}
for (i ...)
for (j ...) {
...
if (...)
break;//NON, quitte
// juste la boucle j
int i;
double x;
...
j=max(i,0);//OK
y=max(x,0);//NON!
// 0.0 et non 0: max
// est un template STL
Imagine++
Voir documentation...
186
12. En vrac (suite) ... 12.8. Devoir nal
Fiche de rfrence (6/6)
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;
En paramtre (n) :
void f(const int
*
t,
int n) {
...
s+=t[i]; // OK
...
t[i]=...; // NON!
}
12.8 Devoir nal
Vous pouvez enn vous confronter aux devoirs complets proposs en annexe, par
exemple B.22 et B.21.
187
13. Structure de donnes
Chapitre 13
Structure de donnes
Les ordinateurs sont l pour nous affranchir des tches fastidieuses ou rptitives. Mais les
rptitions se retrouvent mme dans nos programmes. Ainsi, nous sommes souvent amens
rassembler une collection de donnes dans un tableau. Nous savons dj utiliser les tableaux
C++, mais notre usage en est primitif : ce ne sont pas des classes, donc nous devons tout faire
la main. En fait, il ny a pas une structure canonique satisfaisant tout le monde. Suivant
lusage quon en fait, une manire de grer la collection peut tre prfrable une autre. Ce
problme se rencontre si frquemment que le C++ propose par dfaut des classes. Pour la plus
grande gnricit possible, ces classes sont template et font partie de la STL, dont nous avons
dj rapidement parl. Ce chapitre na pas pour but de documenter les dtails de ces classes,
mais plutt dexpliquer les forces et faiblesses de chacune et la faon dont elles ont pu tre
implmentes.
i
F
i/A
= m
A
a
G(A)
Gravitation universelle
Soient deux corps A et B. Alors A subit une force dattraction
F
B/A
= Gm
A
m
B
1
d
2
A,B
u
BA
.
Chocs lastiques
Soient A et B deux particules rentrant en collision. Connaissant tous les paramtres
avant le choc, comment dterminer leur valeur aprs ? En fait, seule la vitesse des par-
ticules reste calculer, puisque dans linstant du choc, les positions ne changent pas.
Durant un choc dit lastique, trois quantits sont conserves :
1. la quantit de mouvement
P = m
A
v
A
+ m
B
v
B
2. le moment cintique M = m
A
r
A
v
A
+ m
B
r
B
v
B
(qui est un rel dans le
cas dun mouvement plan).
3. lnergie cintique E
c
=
1
2
m
A
v
2
A
+
1
2
m
B
v
2
B
.
Ce qui fait 4 quations pour 4 inconnues.
222
A. Travaux Pratiques A.4. Structures
Rsolution du choc
On se place dans le rfrentiel du centre de masse. On a alors, tout instant :
1.
P = 0 (par dnition de ce rfrentiel), do m
A
v
A
= m
B
v
B
.
2. M = (
r
A
r
B
) m
A
v
A
, do, en notant
r =
r
A
r
B
, M =
r m
A
v
A
.
3. 2E
c
= m
A
(1 +
m
A
m
B
)v
2
A
.
La constance de E
c
nous informe que dans ce repre, la norme des vitesses est
conserve, et la constance du moment cintique que les vitesses varient paralllement
r . Si lon veut que les vitesses varient effectivement, il ne nous reste plus quune
possibilit : mutliplier par 1 la composante des
v
i
selon
r . Ce qui fournit un algo-
rithme simple de rebond.
Dcider de limminence dun choc
On ne peut pas se contenter, lors de lvolution pas pas des coordonnes des
disques, de dcider quun choc aura lieu entre t et t +dt rien quen estimant la distance
entre les deux disques candidats la collision linstant t, ni mme en prenant en plus
en considration cette distance linstant t + dt, car, si la vitesse est trop leve, un
disque peut dj avoir travers lautre et en tre ressorti en t +dt... La solution consiste
expliciter le minimum de la distance entre les disques en fonction du temps, variant
entre t et t + dt.
Soit N(u) = (
r
A
(u)
r
B
(u))
2
le carr de la distance en question. On a :
N(u) = (
r
A
(t)
r
B
(t) + (u t)(
v
A
(t)
v
B
(t)))
2
Ce qui donne, avec des notations supplmentaires :
N(u) =
r (t)
2
+ 2(u t)
r (t)
v (t) + (u t)
2
v (t)
2
La norme, toujours positive, est minimale au point u tel que
u
N(u) = 0, soit :
(t
m
t) =
r (t)
v (t)
v (t)
2
Donc :
1. si t
m
< t, le minimum est atteint en t,
2. si t < t
m
< t + dt, le minimum est atteint en t
m
;
3. sinon, t + dt < t
m
, le minimum est atteint en t + dt.
Ce qui nous donne explicitement et simplement la plus petite distance atteinte entre
les deux corps entre t et t + dt.
223
A.5. Fichiers spars A. Travaux Pratiques
A.5 Fichiers spars
Nous allons poursuivre dans ce TP les simulations de gravitation et de chocs las-
tiques entames la semaine dernire, en sparant dans diffrents chiers les diffrentes
fonctions et structures utilises.
1. De bonnes bases :
Tlcharger le chier Tp5.zip sur la page habituelle, le dcompresser et lancer
Visual C++. Le projet Gravitation contient une solution partielle au TP4 (jusqu
la question 7, incluse). Si vous avez t plus loin et/ou si vous prfrez rutili-
ser votre propre solution, vous pouvez quitter Visual C++, remplacer le chier
Gravitation.cpp par celui que vous aurez rcupr dans votre TP4, et relan-
cer Visual C++.
A.5.1 Fonctions outils
2. Un chier de dnitions...
Ajouter un nouveau chier source nomm Tools.cpp au projet avec "Fichier
/ Ajouter un nouvel lment / Fichier C++". Y placer les fonctions
fournies lavance au dbut du TP4 (InitRandom, Random, Choc, ChocSimple
et Collision), en les retirant de Gravitation.cpp. Ne pas oublier les lignes sui-
vantes, que lon pourra retirer de Gravitation :
# i ncl ude <c s t dl i b >
# i ncl ude <ctime >
usi ng namespace st d ;
3. ... et un chier de dclarations
Ajouter un nouveau chier den-tte nomm Tools.h. Inclure la protection contre
la double inclusion vue en cours (#pragma once). Y placer les dclarations des
fonctions mises dans Tools.cpp, ainsi que la dnition de dt, en retirant celle-ci
de main. Rajouter au dbut de Tools.cpp et de Gravitation.cpp un #include "Tools.h".
A.5.2 Vecteurs
4. Structure Vector :
Crer dans un nouveau chier Vector.h une structure reprsentant un vecteur
du plan, avec deux membres de type double. Ne pas oublier le mcanisme de
protection contre la double inclusion. Dclarer (et non dnir) les oprateurs et
fonction suivants :
Vect or operat or +( Vect or a , Vect or b ) ; / / Somme de deux v e c t e ur s
Vect or operat or ( Vect or a , Vect or b ) ; / / Di f f r e n c e de deux v e c t e ur s
double norme2 ( Vect or a ) ; / / Norme e u c l i d i e n n e d un v e c t e ur
Vect or operat or ( Vect or a , double lambda ) ; / / Mul t i p l i c a t i o n par un s c a l a i r e
Vect or operat or ( double lambda , Vect or a ) ; / / Mul t i p l i c a t i o n par un s c a l a i r e
5. Fonctions et oprateurs sur les Vector :
Crer un nouveau chier Vector.cpp. Mettre un #include du chier den-tte
correspondant et dnir les oprateurs qui y sont dclars (Rappel : sqrt est
dni dans le chier den-tte systme <cmath>; ne pas oublier non plus le
224
A. Travaux Pratiques A.5. Fichiers spars
using namespace std; qui permet dutiliser cette fonction). Astuce : une fois quune
version de operator est dnie, la deuxime version peut utiliser la premire
dans sa dnition...
6. Vecteur vitesse et vecteur position :
Systmatiquement remplacer dans Gravitation.cpp les vitesses et positions
par des objets de type Vector (y compris dans la dnition de la structure Balle).
Utiliser autant que possible les oprateurs et fonction dnis dans Vector.cpp.
A.5.3 Balle part
7. Structure Balle :
Dplacer la structure Balle dans un nouveau chier den-tte Balle.h. Puisque
Balle utilise les types Vector et Color, il faut aussi ajouter ces lignes :
# i ncl ude <Imagine/Graphi cs . h>
usi ng namespace Imagine ;
# i ncl ude " Vect or . h"
8. Fonctions associes :
Dplacer toutes les fonctions annexes prenant des Balle en paramtres dans un
nouveau chier Balle.cpp. Il ne devrait plus rester dans Gravitation.cpp
dautre fonction que main. Dclarer dans Balle.h les fonctions dnies dans
Balle.cpp. Ajouter les #include ncessaires dans ce dernier chier et dans Gravitation.cpp
et faire les adaptations ncessaires (par exemple, si des fonctions utilisent largeur
ou hauteur, comme ces constantes ne sont dnies que dans Gravitation.cpp,
il faut les passer en argument...)
A.5.4 Retour la physique
9. Des soleils par milliers... :
Placer 10 soleils alatoirement (et en tenir compte lafchage, dans le calcul du
dplacement de lastrode...).
10. Diminuer le pas de temps de calcul :
An dviter les erreurs dues la discrtisation du temps, diminuer le pas de
temps dt, pour le xer 0.01 (voire 0.001 si la machine est assez puissante).
Rgler la frquence dafchage en consquence (inversement proportionnelle
dt). Lancer plusieurs fois le programme.
Chocs lastiques simples
11. Faire rebondir lastrode :
Faire subir des chocs lastiques lastrode chaque fois quil sapproche trop
dun soleil, de faon ce quil ne rentre plus dedans (fonction ChocSimple),
et rtablir dt une valeur plus leve, par exemple 0.1 (modier la frquence
dafchage en consquent). Pour savoir si deux corps sont sur le point dentrer
en collision, utiliser la fonction Collision.
225
A.5. Fichiers spars A. Travaux Pratiques
Jeu de tir
12. Ouvrir un nouveau projet :
An de partir dans deux voies diffrentes et travailler proprement, ajouter un
nouveau projet appel Duel, dans cette mme solution.
13. Ne pas refaire deux fois le travail : Comme nous aurons besoins des mmes fonctions
dans ce projet que dans le projet Gravitation, ajouter au projet (sans en crer de
nouveaux !) les chiers Vector.h, Vector.cpp, Balle.h, Balle.cpp, Tools.h,
Tools.cpp. Les chiers sont les mmes que dans le projet Gravitation, ils ne sont
pas recopis. Mettre au dbut du Duel.cpp les #include correspondants. Essayer
de compiler Duel.cpp. Comme le compilateur narrive pas trouver les chiers
inclus, qui ne sont pas dans le mme rpertoire, il faut lui indiquer o les trouver.
(#include " ../Gravitation/Tools.h" par exemple).
14. vous de jouer !
Transformer le projet Duel, laide des fonctions dnies auparavant, en un jeu
de tir, deux joueurs. Chacun des deux joueurs a une position xe, et divers
soleils sont placs alatoirement dans lcran. Chaque joueur, tour de rle, peut
lancer une Balle avec la vitesse initiale de son choix, la balle subissant les effets
de gravitation des divers soleils, et disparaissant au bout de 250 pas de temps
dafchage. Le gagnant est le premier qui russit atteindre lautre... Conseils
pratiques : positionner symtriquement les joueurs par rapport au centre, de pr-
frence mi-hauteur en laissant une marge dun huitime de la largeur sur le
ct ; utiliser la fonction GetMouse pour connatre la position de la souris ; en
dduire la vitesse dsire par le joueur en retranchant ces coordonnes celles
du centre de la boule lancer, et en multipliant par un facteur 0.00025.
15. Amliorations :
Faire en sorte quil y ait systmatiquement un gros soleil au centre de lcran (de
masse non ncessairement consquente) an dempcher les tirs directs.
16. Initialisation correcte :
Modier la fonction de placement des soleils de faon ce que les soleils ne sin-
tersectent pas initialement, et quils soient une distance minimale de 100 pixels
des emplacements des joueurs.
Chocs lastiques
17. Tout faire voluer, tout faire rebondir :
On retourne dans le projet Gravitation. Tout faire bouger, y compris les soleils.
Utiliser, pour les chocs lastiques, la fonction Chocs (qui fait rebondir les deux
corps). Faire en sorte que lors de linitialisation les soleils ne sintersectent pas.
226
A. Travaux Pratiques A.6. Les tris
FIGURE A.5 Corps clestes et jeu de tir...
FIGURE A.6 Deux tris en cours dexcution : tri bulle et Quicksort...
A.6 Les tris
Dans ce TP, nous allons programmer quelques algorithmes de tri dlments dans
un tableau. Pour que cela soit interactif, et que lon puisse voir comment se passent
chacun des tris, une interface graphique a t programme, qui afche le tableau et
permet de visualiser les oprations quon ralise dessus (gure A.6).
A.6.1 Mlanger un tableau
1. Pour commencer, tudier le projet :
Tlcharger le chier Tp6_Initial.zip sur la page habituelle, le dcompresser
et lancer Visual C++. Le projet est spar entre le chier main.cpp, dans lequel
on programmera les algorithmes de tri, et le couple (tools.cpp, tools.h), qui
gre linterface graphique et quelques fonctions utiles la comparaison des dif-
frents tris.
Ouvrir tools.h pour dcouvrir les fonctions de cette interface graphique, puis
main.cpp pour voir comment elles sont utilises (les lignes commentes sont
l pour montrer comment vous utiliserez les fonctions melange_tableau et
tri_selection que vous allez programmer).
227
A.6. Les tris A. Travaux Pratiques
Excuter le projet. Pour linstant, il ne fait quinitialiser un tableau et lafcher.
2. Accs un tableau, change de 2 valeurs
Pour que les oprations que vous effectuerez sur les tableaux soient afches
automatiquement, il faudra que vous utilisiez uniquement les fonctions valeur
et echange dclares dans tools.h (ne pas accder directement au tableau avec
T[i]).
Entranez-vous les utiliser dans la fonction main(), en accdant une valeur du
tableau T0, et en permutant 2 de ses lments.
3. Scuriser les accs tableau
Pour sassrer quon ne sort pas des bornes du tableaux, ajouter des appels
la fonction assert (vue en cours) dans valeur et echange. Constater ce qui se
passe lexcution lorsquon appelle par exemple
val eur ( T0 , t a i l l e , t a i l l e ) ;
4. Mlanger un tableau
Une fonction dclare dans tools.h nexiste pas encore dans tools.cpp : la
fonction
void mel ange_tabl eau ( double T[ ] , i nt t a i l l e )
qui, comme son nomlindique, mlange un tableau. Ajoutez-la (dans tools.cpp
bien sr)
Ide : le mlange le plus rapide (et le plus efcace) consiste parcourir le tableau
une fois, et permuter chacun des lments avec un autre choisi au hasard (uti-
liser la fonction int random(int a) dnie dans tools.cpp pour tirer un entier
entre 0 et a-1).
A.6.2 Tris quadratiques
Les 3 algorithmes de tri qui suivent trient un tableau en temps 0(n
2
), cest dire
que le temps pour trier un tableau est proportionnel au carr de la taille de ce
tableau.
Si vous avez peu de temps, vous pouvez ne faire quun ou deux des trois, pour
pouvoir toucher galement au tri Quicksort.
5. Tri slection
Cest le tri le plus naf. Il consiste parcourir le tableau une premire fois pour
trouver le plus petit lment, mettre cet lment au dbut (par une permutation),
parcourir une seconde fois le tableau (de la 2me la dernire case) pour trouver
le second plus petit lment, le placer en 2me position, et ainsi de suite...
Programmer la fonction void tri_selection (double T[], int taille ). Vous pou-
vez alors dcommenter les lignes commentes dans main() et excuter.
6. Tri insertion
En gnral, cest peu prs lalgorithme quutilise un tre humain pour trier un
paquet de cartes, des ches...
Il consiste ajouter un un les lments non tris au bon endroit parmi ceux qui
sont dj tris : si ncessaire on change les 2 premiers lments du tableau pour
les mettre dans lordre, puis (si ncessaire) on dplace le 3me lment vers la
228
A. Travaux Pratiques A.6. Les tris
gauche, par des changes de proche en proche, jusqu ce quil soit la bonne
position par rapport aux 2 premiers, puis le 4me, et ainsi de suite...
Programmer void tri_insertion (double T[], int taille ) et regarder comment a
se passe.
7. Tri bulle
Le tri bulle consiste parcourir n fois le tableau, et chaque fois quon est sur un
lment, on lchange avec son voisin de droite si ce dernier est plus petit que lui.
Programmer tri_bulle(double T[], int taille) et regarder comment
a se passe. Constater quon nest pas oblig de parcourir tout le tableau chaque
fois et amliorer la fonction.
A.6.3 Quicksort
Lalgorithme :
le tri Quicksort adopte la stratgie diviser pour rgner qui consiste rduire le
problme du tri dun tableau de taille n aux tris de 2 tableaux de taille
n
2
:
on choisit un lment dans le tableau (on le prend en gnral au hasard, mais
par commodit on prendra ici le premier lment du tableau) quon appelle pi-
vot. On spare ensuite les autres lments entre ceux infrieurs au pivot et ceux
suprieurs au pivot. Il ny a plus alors qu trier ces deux moitis.
8. Pivot
Crer une fonction int pivot(double T[], int taille ) qui prend comme pivot
le premier lment du tableau, change les lments du tableau de manire
ce quon aie dabord les lments infrieurs au pivot, puis le pivot, puis les
lments suprieurs au pivot, et qui renvoie la nouvelle position du pivot.
Ne pas oublier dexcuter la fonction pour vrier quelle marche bien!
Ide :
on utilise 2 index qui parcourent le tableau, le premier partir du 2me l-
ment (le 1er tant le pivot) et avanant vers la droite, le second partir du
dernier lment et avanant vers la gauche
le premier index sarrte sur le premier lment suprieur au pivot quil ren-
contre, et le second index, sur le premier lment infrieur au pivot quil
rencontre
on change alors les 2 lments, et les 2 index continuent davancer, et ainsi
de suite
quand les 2 index se rencontrent, gauche de lintersection tous les lments
sont infrieurs au pivot, et droite ils sont suprieurs
on change le pivot (en 1re position) avec le dernier des lments infrieurs
pour obtenir ce quon dsire
Attention, des diffrences apparemment anodines dans la faon de program-
mer cette fonction peuvent la faire chouer dans des cas particuliers : demandez-
vous ce qui se passe si le pivot est la valeur minimale ou la valeur maximale
du tableau.
9. Fonctions rcursives
Le principe mme de la statgie diviser pour rgner implique que la fonction qui
effectue le tri quicksort va sappeler elle-mme pour trier une sous-partie du ta-
bleau. En pratique, on va utiliser 2 arguments debut et fin qui indiquent quon
ne ralise le tri quentre les indices debut et fin.
229
A.6. Les tris A. Travaux Pratiques
Changer la fonction pivot en lui ajoutant ces 2 arguments, et en ne la faisant
effectivement travailler que entre ces 2 indices (par exemple, le pivot est initiale-
ment lindice debut)
10. Quicksort
On peut maintenant crire une fonction
void quicksort_recursif (double T[], int taille , int debut, int n),
qui contient lalgorithme, ainsi que la fonction
void quicksort(double T[], int taille ),
qui ne fait quappeler cette dernire, mais qui sera celle quon utilisera dans
main() (car plus simple).
A.6.4 Gros tableaux
Maintenant quon a vu graphiquement comment marchent ces algorithmes, il est
intressant de les faire fonctionner et de les comparer sur des tableaux de grande
taille.
11. Tableaux de taille variable
Si on veut tester nos algorithmes sur des tableaux de grande taille, il faut utiliser
des tableaux de taille variable. Remplacer toutes les lignes de type double t[ taille ];
par double t = new double[taille], et la n des fonctions o se trouvent ces d-
clarations, ajouter la ligne delete[] t ; .
Dautre part il faut dsactiver lafchage :
init_tools (512, false ).
12. Nombre de lectures et dcriture
Pour comparer plus rigoureusement 2 algorithmes, on peut comparer le nombre
de lectures du tableau et le nombre dcritures dans le tableau.
Crer 2 variables globales dans tools.cpp et modier les fonctions init_tri,
valeur, echange et fin_tri pour initialiser, compter et afcher le nombre de
lectures et dcritures. Au fait, en combien doprations seffectue en moyenne
Quicksort ?
13. Temps de calcul
Il est intressant galement davoir les temps de calcul exacts. Pour cela, on peut
enregistrer dans une nouvelle variable globale timer0 le temps quil est avant le
tri :
timer0 = double(clock())/CLOCKS_PER_SEC;
et la retrancher au temps quil est aprs le tri (modier les fonctions init_tri
et fin_tri pour faire ce calcul et lafcher).
14. Mode Release
On peut changer le mode de compilation en le passant de Debug Release. Vri-
er que lexcution des algorithmes est effectivement bien plus rapide en mode
Release !
230
A. Travaux Pratiques A.7. Images
A.7 Images
FIGURE A.7 Deux images et diffrents traitements de la deuxime (ngatif, ou, relief,
dformation, contraste et contours).
Dans ce TP, nous allons jouer avec les tableaux bidimensionnels statiques (mais
stocks dans des tableaux 1D) puis dynamiques. Pour changer de nos passionnantes
matrices, nous travaillerons avec des images (gure A.7).
A.7.1 Allocation
1. Rcuprer le projet :
Tlcharger le chier Tp7_Initial.zip sur la page habituelle, le dcompresser
et lancer Visual C++.
2. Saturer la mmoire :
Rien voir avec ce quon va faire aprs mais il faut lavoir fait une fois... Faire,
dans une boucle innie, des allocations de 1000000 entiers sans dsallouer et re-
garder la taille du process grandir. (Utiliser Ctrl+Shift+Echap pour accder
au gestionnaire de tches). Compiler en mode Release pour utiliser la "vraie" ges-
tion du tas (Le mode Debug utilise une gestion spcique qui aide trouver les
bugs et se comporte diffremment...)
A.7.2 Tableaux statiques
3. Niveaux de gris :
Une image noir et blanc est reprsente par un tableau de pixels de dimensions
constantes W=300 et H=200. Chaque pixel (i,j) est un byte (entier de 0 255)
allant de 0 pour le noir 255 pour le blanc. Lorigine est en haut gauche, i est
lhorizontale et j la verticale. Dans un tableau de byte mono-dimensionnel t de
taille W
*
H mmorisant le pixel (i,j) en t[i+W
*
j] :
231
A.7. Images A. Travaux Pratiques
Stocker une image noire et lafcher avec putGreyImage(0,0,t,W,H).
Idem avec une image blanche.
Idem avec un dgrad du noir au blanc (attention aux conversions entre byte
et double).
Idem avec t(i, j) = 128 + 128 sin(4i/W) sin(4j/H) (cf gure A.7). Utiliser
# def i ne _USE_MATH_DEFINES
# i ncl ude <cmath>
pour avoir les fonctions et les constantes mathmatiques : M_PI vaut .
4. Couleurs :
Afcher, avec putColorImage(0,0,r,g,b,W,H), une image en couleur sto-
cke dans trois tableaux r, g et b (rouge, vert, bleu). Utiliser la fonction click()
pour attendre que lutilisateur clique avec la souris entre lafchage prcdent et
ce nouvel afchage.
A.7.3 Tableaux dynamiques
5. Dimensions au clavier :
Modier le programme prcdent pour que W et H ne soient plus des constantes
mais des valeurs entres au clavier. Ne pas oublier de dsallouer.
A.7.4 Charger un chier
6. Image couleur :
La fonction loadColorImage("ppd.jpg",r,g,b,W,H); charge le chier "ppd.jpg"
qui est dans le rpertoire du projet, alloue elle-mme les tableaux r,g,b, les rem-
plit avec les pixels de limage, et affecte aussi W et H en consquence. Attention :
ne pas oublier de dsallouer les tableaux r,g,b avec delete[] aprs usage.
Charger cette image et lafcher. Ne pas oublier les dsallocations.
7. Image noir et blanc :
La fonction loadGreyImage("ppd.jpg",t,W,H) fait la mme chose mais conver-
tit limage en noir et blanc. Afcher limage en noir et blanc...
A.7.5 Fonctions
8. Dcouper le travail :
On ne garde plus que la partie noir et blanc du programme. Faire des fonctions
pour allouer, dtruire, afcher et charger les images :
byt e AlloueImage ( i nt W, i nt H) ;
void Detrui tImage ( byte I ) ;
void Affi cheImage ( byte I , i nt W, i nt H) ;
byt e ChargeImage ( char name , i nt &W, i nt &H) ;
9. Fichiers :
Crer un image.cpp et un image.h en consquence...
232
A. Travaux Pratiques A.7. Images
A.7.6 Structure
10. Principe :
Modier le programme prcdent pour utiliser une structure :
s t r uc t Image {
byt e t ;
i nt w, h ;
} ;
AlloueImage() et ChargeImage() pourront retourner des Image.
11. Indpendance :
Pour ne plus avoir savoir comment les pixels sont stocks, rajouter :
byt e Get ( Image I , i nt i , i nt j ) ;
void Set ( Image I , i nt i , i nt j , byt e g ) ;
12. Traitements :
Ajouter dans main.cpp diffrentes fonctions de modication des images
Image Negat i f ( Image I ) ;
Image Flou ( Image I ) ;
Image Re l i e f ( Image I ) ;
Image Contours ( Image I , double s e ui l ) ;
Image Deforme ( Image I ) ;
et les utiliser :
(a) Negatif : changer le noir en blanc et vise-versa par une transformation
afne.
(b) Flou : chaque pixel devient la moyenne de lui-mme et de ses 8 voisins.
Attention aux pixels du bords qui nont pas tous leurs voisins (on pourra ne
pas moyenner ceux-l et en proter pour utiliser linstruction continue!).
(c) Relief : la drive suivant une diagonale donne une impression dombres
projetes par une lumire rasante.
Approcher cette drive par diffrence nie : elle est proportionnelle
I(i + 1, j + 1) I(i 1, j 1).
Sarranger pour en faire une image allant de 0 255.
(d) Contours : calculer par diffrences nies la drive horizontale d
x
= (I(i +
1, j) I(i 1, j))/2 et la drive verticale d
y
, puis la norme du gradient
|I| =
_
d
2
x
+ d
2
y
et afcher en blanc les points o cette norme est suprieure
un seuil.
(e) Deforme : Construire une nouvelle image sur le principe J(i, j) = I(f(i, j))
avec f bien choisie. On pourra utiliser un sinus pour aller de 0 W-1 et de 0
H-1 de faon non linaire.
A.7.7 Suite et n
13. Sil reste du temps, samuser :
Rtrcir une image.
Au lieu du ngatif, on peut par exemple changer le contraste. Comment ?
233
A.8. Premiers objets et dessins de fractales A. Travaux Pratiques
A.8 Premiers objets et dessins de fractales
FIGURE A.8 Fractales...
Dans ce TP, nous allons nous essayer la programmation objet. Nous allons trans-
former une structure vecteur en une classe et lutiliser pour dessiner des courbes frac-
tales (gure A.8).
A.8.1 Le triangle de Sierpinski
1. Rcuprer le projet :
Tlcharger le chier Tp8_Initial.zip sur la page habituelle, le dcompres-
ser et lancer Visual C++. Etudier la structure Vector dnie dans les chiers
Vector.cpp et Vector.h.
2. Interfaage avec Imagine++ :
La structure Vector ne comporte pas de fonction dafchage graphique. Ajouter
dans main.cpp des fonctions drawLine et drawTriangle prenant des Vector
en paramtres. Il suft de rebondir sur la fonction
void drawLine ( i nt x1 , i nt y1 , i nt x2 , i nt y2 , const Color& c , i nt pen_w) }
dImagine++. Le dernier paramtre contrle lpaisseur du trait.
3. Triangle de Sierpinski :
Cest la gure fractale choisie par lENPC pour son logo. La gure ci-dessous
illustre sa construction.
Ecrire une fonction rcursive pour dessiner le triangle de Sierpinski. Cette fonc-
FIGURE A.9 Construction du triangle de Sierpinski.
tion prendra en paramtres les trois points du triangle en cours et lepaisseur du
234
A. Travaux Pratiques A.8. Premiers objets et dessins de fractales
trait. Les trois sous-triangles seront dessins avec un trait plus n. Ne pas oublier
la condition darrt de la rcursion!
Utiliser cette fonction dans le main en lui fournissant un triangle initial dpais-
seur 6.
A.8.2 Une classe plutt quune structure
4. Classe vecteur :
Transformer la structure Vector en une classe. Y incorporer toutes les fonctions
et les oprateurs. Passer en public le strict ncessaire. Faire les modications n-
cessaires dans main.cpp.
5. Accesseurs pour les membres :
Rajouter des accesseurs en lecture et en criture pour les membres, et les utiliser
systmatiquement dans le programme principal. Lide est de cacher aux utilisa-
teurs de la classe Vector les dtails de son implmentation.
6. Dessin rcursif dun arbre :
Nous allons maintenant dessiner un arbre. Pour cela il faut partir dun tronc et
remplacer la deuxime moiti de chaque branche par deux branches de mme
longueur formant un angle de 20 degrs avec la branche mre. La gure ci-
dessous illustre le rsultat obtenu pour diffrentes profondeurs de rcursion.
Ecrire une fonction rcursive pour dessiner une telle courbe. Vous aurez besoin
FIGURE A.10 Construction de larbre.
de la fonction Rotate de la classe Vector.
A.8.3 Changer dimplmentation
7. Deuxime implmentation :
Modier limplmentation de la classe Vector en remplaant les membres double x,y;
par un tableau double coord[2];. Quelles sont les modications apporter dans
main.cpp?
8. Vecteurs de dimension suprieure :
Lavantage de cette dernire implmentation est quelle se gnralise aisment
des vecteurs de dimension suprieure. Placer une constante globale DIM gale
2 au dbut de Vector.h et rendre la classe Vector indpendante de la dimen-
sion.
NB : la fonction Rotate et les accesseurs que nous avons crits ne se gnra-
lisent pas directement aux dimensions suprieures. Les laisser tels quels pour
linstant...
235
A.8. Premiers objets et dessins de fractales A. Travaux Pratiques
A.8.4 Le ocon de neige
9. Courbe de Koch :
Cette courbe fractale sobtient en partant dun segment et en remplaant le deuxime
tiers de chaque segment par deux segments formant la pointe dun triangle qui-
latral.
Ecrire une fonction rcursive pour dessiner une courbe de Koch.
FIGURE A.11 Construction de la courbe de Koch.
10. Flocon de neige :
Il sobtient en construisant une courbe de Koch partir de chacun des cts dun
triangle quilatral.
236
A. Travaux Pratiques A.9. Tron
FIGURE A.12 Jeu de Tron.
A.9 Tron
Dans ce TP, nous allons programmer le jeu TRON. Il sagit dun jeu 2 joueurs,
dans lequel chaque joueur pilote un mobile qui se dplace vitesse constante et laisse
derrire lui une trace infranchissable. Le premier joueur qui percute sa propre trace ou
celle de son adversaire a perdu.
A.9.1 Serpent
Nous allons procder en deux temps. Dabord programmer un jeu de Serpent
un joueur. Le programme serpent.exe vous donne une ide du rsultat recherch.
Dans ce jeu, le joueur pilote un Serpent qui sallonge petit petit (dun lment tous
les x tours, avec la convention que la longueur totale est borne nmax lments). Il
sagit de ne pas se rentrer dedans ni de percuter les murs.
La solution de dpart comporte deux chiers, utils.h et utils.cpp, qui contiennent
une structure point (quil faudra ventuellement toffer de mthodes utiles) et une
fonction destine rcuprer les touches clavier pour linteraction avec les joueurs.
Il sagit ici de concevoir un objet Serpent dot des mthodes adquates, plus une
fonction jeu_1p exploitant les capacits du Serpent pour reproduire le comportement
dsir. On pourra dans un premier temps ne pas grer les collisions (avec le bord et
avec lui-mme), et ne les rajouter que dans un second temps. Votre travail se dcom-
pose en 6 tapes :
1. (sur papier) Dnir linterface de la classe Serpent (cest--dire lister toutes les
fonctionnalits ncessaires).
2. (sur papier) Rchir limplmentation de la classe Serpent : comment stocker les
donnes ? comment programmer les diffrentes mthodes ? (lire en prliminaire
les remarques du paragraphe suivant).
3. Dans un chier serpent.h, crire la dclaration de votre classe Serpent : ses membres,
ses mthodes, ce qui est public, ce qui ne lest pas.
4. Soumettre le rsultat de vos rexions votre enseignant pour valider avec lui les choix
retenus.
5. Implmenter la classe Serpent (cest--dire programmer les mthodes que vous
avez dclares).
237
A.9. Tron A. Travaux Pratiques
6. Programmer la fonction jeu_1p utilisant un Serpent.
Remarque : Dans le chier utils.h sont dnis :
1. 4 entiers gauche, bas, haut, droite de telle manire que :
(a) la fonction x (x +1)%4 transforme gauche en bas, bas en droite, droite en
haut et haut en gauche ; cette fonction correspond donc un quart de tour
dans le sens trigonomtrique.
(b) la fonction x (x 1)%4 transforme gauche en haut, haut en droite, droite
en bas et bas en gauche ; cette fonction correspond donc un quart de tour
dans le sens des aiguilles dune montre.
2. un tableau de 4 points dir de telle manire que, moyennant la dnition dune
fonction permettant de faire la somme de deux points, la fonction p p + dir[d]
renvoie :
(a) pour d=gauche le point correspondant au dcalage de p de 1 vers la gauche.
(b) pour d=haut le point correspondant au dcalage de p de 1 vers la haut.
(c) pour d=droite le point correspondant au dcalage de p de 1 vers la droite.
(d) pour d=bas le point correspondant au dcalage de p de 1 vers la bas.
A.9.2 Tron
A partir du jeu de Serpent ralis prcdemment, nous allons facilement pouvoir
implmenter le jeu Tron. Le programme tron.exe vous donne une ide du rsultat
recherch. Le principe de ce jeu est que chaque joueur pilote une moto qui laisse der-
rire elle une trace infranchissable. Le but est de survivre plus longtemps que le joueur
adverse.
1. Passage deux joueurs.
A partir de la fonction jeu_1p, crer une fonction jeu_2p implmentant un
jeu de serpent 2 joueurs. On utilisera pour ce joueur les touches S, X, D et F.
La fonction Clavier() renverra donc les entiers int ( S ), int ( X), int ( D) et
int ( F ). Remarque : on ne grera quune touche par tour, soit un seul appel la
fonction Clavier() par tour.
2. Ultimes rglages
(a) Grer la collision entre les deux serpents.
(b) Le principe de Tron est que la trace des mobiles reste. Pour implmenter
cela, il suft dallonger nos serpents chaque tour.
A.9.3 Graphismes
Petit bonus pour les rapides : nous allons voir comment grer des graphismes un
peu plus sympas que les rectangles uniformes que nous avons utiliss jusquici. Lob-
jectif est de remplacer le carr de tte par une image que lon dplace chaque tour.
Nous allons utiliser pour cela les NativeBitmap dImagine++, qui sont des images
afchage rapide. Pour charger une image dans une NativeBitmap on procde ainsi :
238
A. Travaux Pratiques A.9. Tron
/ / Ent i e r s p a s s s par r f r e n c e l o r s du char ge me nt de l i mage pour
/ / qu y s o i e n t s t o c k e s l a l a r g e ur e t l a haut e ur de l i mage
i nt w, h ;
/ / Chargement de l i mage
byt e rgb ;
loadColorImage ( " nom_f i chi er . bmp" , rgb , w, h ) ;
/ / D c l a r a t i o n de l a Nat i ve Bi t map
NativeBitmap ma_native_bitmap (w, h ) ;
/ / On p l a c e l i mage dans l a Nat i ve Bi t map
ma_native_bitmap . setCol orImage ( 0 , 0 , rgb , w, h ) ;
Lafchage dune NativeBitmap lcran se fait alors avec la mthode :
void putNativeBitmap ( i nt x , i nt y , NativeBitmap nb)
1. Remplacer dans le serpent lafchage de la tte par lafchage dune image. On
pourra utiliser les images moto_blue.bmp et moto_red.bmp fournies.
2. Utiliser limage explosion.bmp lors de la mort dun des joueurs.
239
B. Examens
Annexe B
Examens
Note : les corrigs sont disponibles sur la page Web du cours.
B.1 Examen sur machine 2011 : nonc
B.1.1 Automate cellulaire
Un automate cellulaire est une rgle de transformation dune squence de bits (0 ou
1), appels cellules, en une autre squence par une rgle de transformation : chaque bit
est transform en fonction de sa valeur et de ses deux voisins immdiats. Par exemple,
voici une telle rgle :
voisinage 111 110 101 100 011 010 001 000
nouvelle valeur centrale 0 1 1 0 1 1 1 0
La squence de bits de la deuxime ligne se lit en binaire comme le nombre 2
1
+ 2
2
+
2
3
+ 2
5
+ 2
6
= 110 et est la rgle 110. Voici un exemple de transformation suivant cette
rgle :
automate initial 1 1 0 1
automate transform 0 1 1 1
en considrant la squence comme circulaire, cest--dire que le voisin de gauche de la
premire cellule est la dernire cellule et que le voisin de droite de la dernire cellule
est la premire.
Pour calculer la valeur centrale, il suft dinterprter le voisinage comme un bi-
naire, par exemple 101 = 2
2
+ 2
0
= 5 et de lire le bit numro 5 en partant de la droite
(et commenant compter par 0) de la dcomposition binaire de la rgle : 01101110.
Parmi les 256 rgles possibles, certaines sont plus intressantes que dautres : elles
exhibent une certaine rgularit sans tre rellement priodiques. On reprsente un
automate en laissant en blanc ou en noir un pixel dune ligne en fonction de la valeur
de la cellule. Dans le diagramme (voir gure), chaque ligne est lautomate transform
de la ligne prcdente.
Il existe en C++ des oprateurs agissant directement sur les bits. Comme nous ne
les avons pas encore vus en cours, nous nallons pas les utiliser mais reprsenter la
valeur dune cellule par un bool et grer nous-mmes les oprations.
B.1. Examen sur machine 2011 : nonc B. Examens
FIGURE B.1 Une ralisation de lautomate cellulaire
B.1.2 Travail demand
Il est plus important de livrer un code clair et qui compile sans warning,
mme sil ne rpond pas toutes les questions. Pour cela, vriez chaque
tape que votre programme compile et se lance correctement.
1. Crez un nouveau projet Imagine++ nomm Automate et crivez le main, qui
ouvre une fentre de taille xe.
2. Dans un chier automate.h, crivez une structure Automate, comprenant un
tableau de bool et sa taille, de type int.
Automate
3. Dans automate.cpp, implmentez des fonctions :
init prenant un automate et une taille et allouant le tableau;
detruis librant le tableau de lautomate pass en argument ;
random mettant les cellules de lautomate alatoirement true ou false.
Noubliez pas de dclarer ces fonctions dans automate.h.
4. Implmentez une fonction affiche prenant un automate et un numro de ligne
j et mettant noir ou blanc le pixel (i, j) suivant la valeur de la cellule numro i
de lautomate.
5. Dans le chier diagramme.h, crivez la structure Diagramme avec 3 champs : n
(le nombre dautomates, un entier), nmax (taille maximum du diagramme) et un
tableau dautomates.
6. Une fonction init cre un nombre nmax dautomates, le premier tant initialis
par random.
7. Ecrivez une fonction affiche dessinant les n cases dun diagramme.
Binaires
8. Dans un chier binaire.h, crivez une structure Binaire contenant un ta-
bleau de 8 boolens.
242
B. Examens B.1. Examen sur machine 2011 : nonc
9. Ecrivez dans binaire.cpp une fonction decompose dcomposant un entier
pass en paramtre (suppos entre 0 et 255) en sa dcomposition binaire, avec la
convention 1=true, 0=false. Procder ainsi :
Si le nombre est impair (utiliser lopration modulo % sur les entiers), mettre
la premire valeur du tableau true (sinon false).
Diviser le nombre par 2 (quotient de division euclidienne).
Tester la parit du nombre, et affecter la deuxime valeur du tableau.
Diviser nouveau par 2.
Ritrer pour remplir tout le tableau.
10. Ecrivez une fonction compose prenant un tableau de 3 boolens et retournant
le nombre binaire correpondant : le premier boolen vaut 1, le deuxime 2 et le
troisime 4. On obtient donc un entier entre 0 et 7.
Rgle de transformation
11. Ecrivez une fonction transforme prenant deux 2 automates en paramtre et
remplissant le deuxime par la rgle de transformation. Pour cela, on passe aussi
la dcomposition binaire de la rgle et il suft daller chercher le bon bit dans ce
tableau en fonction du voisinage.
12. Ecrivez une fonction evolue ajoutant une ligne au diagramme par transforma-
tion de la dernire.
13. Faites remplir progressivement toute la fentre avec le diagramme : la premire
ligne est un automate alatoire et les suivantes sont le rsultat de la transforma-
tion de lautomate de la ligne prcdente.
14. Quant on arrive au bout de la fentre, pour ajouter une ligne on remonte tout
le diagramme actuel dune ligne pour pouvoir insrer la nouvelle. Modiez la
fonction evolue pour mettre a jour le diagramme quand n atteint nmax.
15. Faire dler linni lautomate dans la fentre.
Important : Quand vous avez termin, nettoyez la solution et crez une archive du
projet votre nom. Ne vous dconnectez pas avant que le surveillant ne soit pass vous
voir pour copier cette archive sur cl USB.
243
B.2. Examen sur machine 2010 : nonc B. Examens
FIGURE B.2 Des ttradres et octadres en rotation dans lespace. Aucun traitement
particulier nest fait pour les solides qui sintersectent.
B.2 Examen sur machine 2010 : nonc
B.2.1 Visualisation 3D par z-buffer
Nous allons visualiser des volumes 3D agencs dans lespace sur lcran et allons
les animer. Nous nous restreignons des polydres rguliers, mais le principe serait
similaire pour dautres volumes.
La principale difcult rside dans la gestion des parties caches (nos volumes sont
opaques), ou occlusions. Nous utiliserons pour cela la mthode classique du z-buffer,
qui est galement utilise dans les interfaces graphiques 3D openGL et DirectX par
exemple, et donc dans la plupart des jeux vido.
Lide de base est simple : pour chaque pixel on enregistre la hauteur (coordonne z)
du point 3D projet le plus haut. Cela forme une carte des hauteurs appele le z-buffer.
On reprsente la surface par une srie de triangles ; chacun de ceux-ci est projet dans
un ordre quelconque en un ensemble de pixels. On ne met le pixel dans limage la
couleur du triangle que si la hauteur en ce point est suprieure celle enregistre dans
le z-buffer jusqu prsent. Si cest le cas, on enregistre en plus ce nouveau z dans le
z-buffer.
De cette faon, on peut projeter les triangles dans nimporte quel ordre et un pixel
est rcrit chaque fois quon trouve un nouveau point plus lev aux mmes coordon-
nes x et y.
Prcisons enn que nous utilisons le principe de projection linni, cest--dire
quun point
_
x y z
_
se projette en
_
x y
_
.
B.2.2 Travail demand
Il est plus important de livrer un code clair et qui compile sans warning,
mme sil ne rpond pas toutes les questions. Pour cela, vriez chaque
tape que votre programme compile et se lance correctement.
1. Crez un nouveau projet Imagine++ nomm Polyedres et crivez le main, qui
ouvre une fentre de taille xe.
2. Preparez des chiers poly.h, poly.cpp, buffer.h et buffer.cpp. Les deux
premiers serviront aux structures Point, TriangleFace et Polyedre ainsi
244
B. Examens B.2. Examen sur machine 2010: nonc
quaux fonctions sy rapportant, alors que les deux derniers seront spciques
la visualisation par z-buffer.
Polydres
3. Crez une structure Point correspondant un point ou un vecteur 3D de les-
pace (coordonnes relles, non entires).
4. Ecrivez les oprateurs daddition et de soustraction de deux Points et lopra-
teur de multiplication par une constante.
5. Ecrire une structure Polyedre qui contient :
(a) un tableau de Points (les sommets), quon appellera sommets, et son nombre
dlments. On fera attention au fait que le nombre de sommets nest pas une
constante.
(b) un tableau de TriangleFaces
1
et son nombre dlments.
(c) un point reprsentant le barycentre.
La structure TriangleFace (que lon crira) reprsente un triangle (face ou mor-
ceau de face du polydre). Il est constitu dun tableau de 3 index indiquant les in-
dices des sommets du triangle dans le tableau sommets, et dune couleur Color
(type dImagine++).
6. Ecrire une fonction set qui prend en argument un TriangleFace, 3 index (des
entiers) et une couleur pour les crire dans le TriangleFace.
7. Ecrire une fonction tetraedre(int w, int h, int rmax) qui renvoie un
Polyedre construit de la manire suivante :
4 sommets de coordonnes
_
0 0 1
_
,
_
1 0 0
_
et
_
1/2
3/2 0
_
.
4 triangles, joignant tout sous-groupe de 3 parmi ces 4 sommets.
Compltez cette fonction dans les trois items suivants :
8. Crez une fonction randCol qui renvoie une couleur tire au hasard et lutiliser
pour affecter une couleur chaque triangle. On rappelle que lon peut crer une
couleur avec la syntaxe suivante : Color col(r,v,b), o r, v et b prennent
des valeurs entre 0 et 255. Ne pas oublier dinitialiser le gnrateur alatoire dans
le main.
9. Multiplier les points par un facteur dchelle alatoire ne dpassant pas rmax.
10. Placez le centre (champ de Polyedre, cf 5c) en une position alatoire (abscisse
entre 0 et w, ordonne entre 0 et h, z = 0) et translater le polydre de ce vecteur
laide dune fonction translate que vous crivez.
11. Ecrivez une fonction detruit qui prend en paramtre un Polyedre et qui li-
bre la mmoire alloue.
Visualisation
12. Ecrivez une structure Buffer, qui a comme champs un tableau de hauteurs z et
une image couleur im de type Image<Color> (type Imagine++) qui reprsente
limage qui sera afche.
1. ne pas lappeler Triangle pour viter la confusion avec la structure du mme nom dans
Imagine++
245
B.2. Examen sur machine 2010 : nonc B. Examens
13. Ecrivez la fonction Buffer creeBuffer(int w,int h) : elle alloue le ta-
bleau des z et initialise les dimensions de limage :
buf.im = Image<Color>(w,h);
Par la suite, pour retrouver ces dimensions on pourra utiliser buf.im.width()
et buf.im.height().
14. Ecrivez la fonction reinit qui va mettre le z-buffer une grande valeur ngative
et limage tout en blanc. On rappelle que lon peut accder au pixel (i,j) dune
image im de la manire suivante : im(i,j).
15. Ecrivez une fonction affiche qui se contente de dessiner limage du buffer dans
la fentre dafchage. On pourra utiliser par exemple la fonction display(im)
qui afche limage im dans la fentre.
16. Ecrivez une fonction projette(Polyedre p, Buffer& buf) qui dessine la
projection de p dans buf. Celle-ci appelle simplement une fonction
projette(TriangleFace tr, Point
*
sommets, Buffer& buf)
sur chacun des triangles et que nous allons implmenter.
17. Cette mthode fonctionne en trois temps :
Elle cherche le rectangle (de coordonnes entires) englobant le triangle.
Pour chaque pixel de ce rectangle (attention sil dborde de limage !) il calcule
ses coordonnes barycentriques (voir quation B.1 en annexe) et vrie sil est
bien lintrieur du triangle (coordonnes toutes positives). Si cest le cas, son
z est la moyenne pondre par les coordonnes barycentriques des z des som-
mets du triangle.
Si le z est au-dessus de la valeur enregistre dans le z-buffer, on met jour le
Buffer comme indiqu dans lintroduction.
18. Ecrivez ces fonctions rectangle et barycentre et servez-vous en pour projette.
Animation
19. A ce stade, vous pouvez dj afcher un ttradre (dont on ne peut jamais voir
plus de 3 faces la fois).
20. Pour varier le point de vue, nous allons faire tourner le polydre autour dun axe
arbitraire :
(a) Ecrivez une fonction randomVect() renvoyant un vecteur 3D alatoire de
la sphre :
_
cos cos sin cos sin
_
,
avec [0, 2] et [0, ], reprsentant la direction dun axe de rotation.
(b) Pour effectuer la rotation du polydre, il suft de :
translater le polyhdre pour le centrer lorigine (fonction translate_inv
crire.
appliquer la rotation chacun des sommets (voir les quations B.2 et B.3
en annexe)
utiliser translate pour ramener le centre sa position initiale.
(c) Avant dafcher votre ttradre, faites-le tourner de faon arbitraire suivant
un vecteur donn par randomVect().
246
B. Examens B.2. Examen sur machine 2010 : nonc
21. Animer le ttradre en rotation, en le faisant tourner autour dun axe arbitraire
mais x une fois pour toutes. Multiplier le rsultat de randomVect par 0.1 pour
avoir un angle pas trop grand (environ 6
).
22. Faites tourner ainsi une bonne dizaine de ttradres, chacun ayant son propre
axe de rotation.
23. Question bonus : ajouter une fonction octaedre sur le modle de tetraedre
dont les 6 sommets sont les points
_
0 0 1
_
(points 0 et 5)
_
1 0 0
_
(points 1 et 3)
_
0 1 0
_
(points 2 et 4)
et les 8 faces donnes par les points dindices
_
0 1 2
_ _
0 2 3
_ _
0 3 4
_ _
0 4 1
_
_
5 1 2
_ _
5 2 3
_ _
5 3 4
_ _
5 4 1
_
Ajoutez dans votre scne des octadres en rotation.
Important : Quand vous avez termin, nettoyez la solution et crez une archive du
projet votre nom. Ne vous dconnectez pas avant que le surveillant ne soit pass vous
voir pour copier cette archive sur cl USB.
B.2.3 Annexe : les formules
Coordonnes barycentriques
Le point
_
x y
_
scrit A + B + C avec
d = (x
B
x
A
)(y
C
y
A
) (y
B
y
A
)(x
C
x
A
)
= ((x
B
x)(y
C
y) (y
B
y)(x
C
x))/d
= ((x
C
x)(y
A
y) (y
C
y)(x
A
x))/d
= ((x
A
x)(y
B
y) (y
A
y)(x
B
x))/d
(B.1)
d est laire (ventuellement ngative) du paralllogramme dont 3 sommets sont A, B et
C. Si cette aire est trop petite |d| < 1, renvoyer des coordonnes ngatives de manire
dire que le triangle est vide et donc que tout point est en-dehors.
Justication (pour les curieux) : on peut imposer + + = 1 et on se retrouve
alors avec le systme :
_
_
x
A
x
B
x
C
y
A
y
B
y
C
1 1 1
_
_
_
_
_
_
=
_
_
x
y
1
_
_
.
Par les formules de Cramer, on obtient
=
x x
B
x
C
y y
B
y
C
1 1 1
x
A
x
B
x
C
y
A
y
B
y
C
1 1 1
x
A
x x
C
y
A
y y
C
1 1 1
x
A
x
B
x
C
y
A
y
B
y
C
1 1 1
x
A
x
B
x
y
A
y
B
y
1 1 1
x
A
x
B
x
C
y
A
y
B
y
C
1 1 1
.
247
B.2. Examen sur machine 2010 : nonc B. Examens
Pour calculer de tels dterminants, on soustrait une colonne chacune des deux autres
et on dveloppe suivant la troisime ligne. Par exemple :
x x
B
x
C
y y
B
y
C
1 1 1
x x
B
x x
C
x
y y
B
y y
C
y
1 0 0
x
B
x x
C
x
y
B
y y
C
y
= (x
B
x)(y
C
y)(y
B
y)(x
C
x).
Rotation 3D autour dun axe
On code la rotation par un vecteur v dont la norme reprsente langle de rotation et la
direction laxe de rotation. On extrait dabord ceci de v :
=
_
x
2
v
+ y
2
v
+ z
2
v
v v/
c = cos
s = sin
(B.2)
(remarquez quon renormalise v pour quil soit de norme 1, si est trop petit, on se
contente de ne rien faire, car cest une rotation faible) puis
d = x
v
x + y
v
y + z
v
z
x
= d(1 c)x
v
+ cx sz
v
y + sy
v
z
y
= d(1 c)y
v
+ cy + sz
v
x sx
v
z
z
= d(1 c)z
v
+ cz sy
v
x + sx
v
y
(B.3)
248
B. Examens B.3. Examen sur machine 2009 : nonc
21 22 23
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13
FIGURE B.3 Ordre des cases parcourues par la spirale dUlam et rsultat sur une
fentre 512 512.
B.3 Examen sur machine 2009 : nonc
B.3.1 Spirale dUlam
Le mathmaticien Stanislav Ulam, dans une priode dennui lors dune confrence,
prit son stylo et machinalement crivit les nombres entiers en spirale sur une feuille de
papier, puis noircit les cases contenant un nombre premier. Des diagonales comportant
un nombre remarquable de cases noires apparurent, que jusqu prsent personne na
pu expliquer. Le but est de reproduire la dcouverte dUlam sur machine.
On rappelle quun nombre premier na par dnition que 1 et lui-mme comme
diviseurs, lexception tant le nombre 1 qui nest pas premier.
B.3.2 Travail demand
Le travail se compose de deux parties. Dans la premire, on va chercher les nombres
premiers par un crible dErastosthne. Dans la seconde, on va dessiner la spirale par
un robot qui se deplace et remplit sa case si celle-ci correspond un nombre premier.
Consignes importantes : Il est plus important de livrer un code propre mais qui com-
pile sans warning, mme sil ne rpond pas toutes les questions. Pour cela, vriez
chaque tape que votre programme compile et se lance correctement.
1. Crez un nouveau projet Imagine++ nomm Ulam et crivez le main, qui de-
mande lutilisateur une taille de fentre carre et cre un tableau de variables
249
B.3. Examen sur machine 2009 : nonc B. Examens
boolennes premier contenant autant dlments que le nombre de cases. Ll-
ment dindice i du tableau sera true si le nombre i est premier.
2. Dans des chiers spars, crez des fonctions crible et spirale, qui pour lins-
tant ne font rien (nous les remplirons plus tard). Appelez ces fonctions depuis le
main. A ce stade, veriez dj que votre programme compile et se lance correc-
tement, mme sil ne fait pas beaucoup...
Crible
3. Crez une fonction init qui initialise le tableau premier en mettant a priori
tous les indices true sauf 1.
4. Crez une fonction barre_multiples qui met false les multiples (autres
que lui-mme) dun nombre i dans premier.
5. Ecrivez la fonction crible, qui appelle barre_multiples pour tous les nombres
premiers.
Robot
6. Dans la fonction spirale, crez un tableau pour mmoriser le fait quune case
a t visite ou non. Linitialiser.
7. Pour dessiner la spirale, on va crire un robot qui part du centre de la fentre,
a une direction initiale, et cherche tourner droite ds que la case na pas t
visite. Crez une structure Robot qui a une position et une direction code sur
un entier, qui prendra une valeur entre 0 et 3.
8. Crez la fonction avance qui fait bouger le robot dune case dans sa direction.
9. Crez la fonction tourne qui fait tourner le robot sur sa droite si la case na pas
t visite. Cette fonction indique en retour si le dplacement a pu seffectuer.
10. Dans la fonction spirale, faire partir le robot du centre de la fentre et se dpla-
cer en appelant tourne, ou avance si le quart de tour sest sold par un chec.
Le robot noircit sa position si elle correspond un nombre premier.
Important : Quand vous avez termin, crez une archive du projet votre nom. Ne
vous dconnectez pas avant que le surveillant ne soit pass vous voir pour copier cette
archive sur cl USB.
250
B. Examens B.4. Examen sur machine 2008 : nonc
FIGURE B.4 Ensemble de Mandelbrot. A droite : dessin progressif
B.4 Examen sur machine 2008 : nonc
B.4.1 Ensemble de Mandelbrot
Le but de lexercice demand est de dessiner lensemble de Mandelbrot Mde deux
faons diffrentes.
Dnition. Soit c un nombre complexe. On considre la suite dnie par z
0
= 0 et
z
n+1
= z
2
n
+ c. Lensemble M est constitu des points c pour lesquels cette suite ne
diverge pas en module.
Proprit. On peut montrer que ds que |z
n
| > 2 pour un certain n alors la suite
diverge.
B.4.2 Travail demand
Notes importantes :
Crer sur le bureau un projet portant son nom.
Ne pas se dconnecter, an que lenseignant rcupre le travail la n de lexa-
men.
Etapes :
1. Dnir une structure reprsentant les complexes et les fonctions associes stric-
tement ncessaires au programme.
2. Programmer une fonction dcidant, de faon approche aprs un nombre maxi-
mum ditrations, si un complexe appartient M.
3. Dans une fentre de taille n n correspondant la rgion {z = a +ib | 2 a
1, 1.5 b +1.5}, dessiner M. On dessinera en blanc les points de M, en noir
les autres.
4. La dcision c / M est prise aprs un certain nombre ditrations. Dessiner ces
points dune couleur intermdiaire entre noir et blanc, fonction de ce nombre
ditrations (cf. gure)
5. Raliser maintenant dans une nouvelle fonction un dessin progressif de M. Il
sagit de voir safcher un carr occupant toute la fentre, puis quatre, puis seize,
etc. an dobserver M se prciser au fur et mesure (cf gure). La couleur de
chaque carr doit tre celle du complexe correspondant au coin en haut a gauche
251
B.4. Examen sur machine 2008 : nonc B. Examens
du carr. On sappliquera en outre ne pas recalculer ni afcher deux fois la
mme valeur.
252
FIGURE B.5 Chemin le plus court...
B.5 Examen sur machine 2007 : nonc
B.5.1 Chemins entre deux points
Le but de lexercice demand est de gnrer et de dessiner tous les chemins pos-
sibles entre deux points en utilisant une fonction rcursive.
B.5.2 Travail demand
Notes importantes :
travailler sur le bureau Windows et dans un projet portant son nom.
ne pas utiliser de variable globale non constante.
1. Modliser un terrain par un tableau de boolens de dimensions NxN, N tant un
entier constant (prendre une petite valeur, par exemple N=12). Chaque case est
soit vide, soit occupe par un mur.
2. Gnrer un terrain alatoirement. Les bords du terrain sont toujours occups par
un mur. Les autres cases seront occupes par un mur 3 fois sur 10 en moyenne.
3. Dessiner le terrain (en le grossissant).
4. Dsigner la souris un point de dpart et un point darrive (qui ne devront pas
tre occups par un mur)
5. Programmer une fonction rcursive explorant tous les chemins entre ces deux
points. Un chemin ne peut pas traverser un mur et ne repasse pas deux fois au
mme endroit. Les chemins seront dessins et effacs au fur et mesure.
6. Rajouter de quoi afcher la longueur du chemin chaque fois que larrive est
atteinte.
7. Rajouter de quoi mmoriser et afcher la longueur du chemin le plus court, sil
existe.
8. Rajouter de quoi mmoriser et afcher le plus court chemin une la recherche
termine.
9. (Rpondre cette question dans une remarque la n de votre source) La recherche est
trs lente puisquelle est exhaustive. Si le seul but est de trouver un des chemins
les plus courts, il existe des meilleures solutions. Proposer, sans le programmer,
un moyen de limiter (et donc dacclrer) la recherche.
B.6 Examen sur machine 2006 : nonc
B.6.1 Voyageur de commerce par recuit simul
Soient n villes situes aux points M
1
, ..., M
n
, le problme du voyageur de commerce
consiste trouver un circuit ferm de longueur minimale passant par toutes les villes.
Il sagit donc de permuter les villes entre elles pour minimiser
l(M
1
, ..., M
n
) =
n1
i=1
d(M
i
, M
i+1
) + d(M
n
, M
1
)
o d(A, B) est la distance entre A et B. Une mthode classique pour trouver une solu-
tion approche ce problme est de procder un "recuit simul" :
1. Partir dun circuit quelconque C
2. Pour un "grand" nombre de fois
(a) Modier alatoirement C en un circuit D
(b) Si l(D) < l(C) alors remplacer C par D
(c) Sinon, remplacer C par D avec une probabilit e
(l(D)l(C))/T
, o T est une
constante choisir.
B.6.2 Travail demand
1. Travailler en local dans D:\nom_prenom ;
2. Y crer une solution Examen et lui ajouter un projet "Winlib" de nomvoyageur;
3. Un circuit sera mmoris comme un tableau de Pixel
2
de taille constante n
(valeur raisonnable : n = 20) ;
4. Faire et utiliser une fonction qui gnre un circuit correspondant n villes situes
en des positions alatoires dans la fentre ;
5. Faire et utiliser une fonction qui afche ce circuit
3
;
6. Faire et utiliser une fonction qui calcule la longueur de ce circuit ;
7. Faire et utiliser une fonction qui transforme un circuit en un autre par change
de deux villes choisies au hasard;
8. Implmenter le recuit simul sans ltape (c). Afcher le circuit et sa longueur
chaque fois quil change. Lalgorithme devrait rester coinc dans un minimum
local ;
9. Rajouter ltape (c). On rappelle que double(rand())/RAND_MAX est un nombre
alatoire entre 0 et 1. Ajuster T pour ne pas toujours remplacer C par D!
10. Choisir maintenant une valeur de T qui dcrot en 1/
3
2
, 0}, {
1
2
,
3
2
, 0}, {0, 0,
2}.
On rappelle que la fonction sqrt est dnie dans #include <cmath>.
B.7.2 Projection : du 3D au 2D
Nous nous proccupons maintenant de la projection 2D de ces reprsentations 3D.
Ajouter au projet deux chiers camera.cpp et camera.h dans lesquels vous dclare-
rez et dnirez :
1. une structure camera contenant les variables suivantes : int u0,v0 (le centre
de limage), double x0 (lloignement), et double f (la focale). La gure ci-
aprs schmatise la reprsentation dune camra.
256
B. Examens B.7. Examen sur machine 2005 : nonc
2. une fonction projette qui projette un point 3D (vect M) par lintermdiaire
dune camra (camera c). La fonction projette retourne un point 2D de type
Pixel. Nous rappelons que le type Pixel est dni dans la WinLib :
struct Pixel{
int x,y;
};
Par consquent, ne pas oublier dajouter les lignes #include <win> et using namespace Win
dans le chier camera.h. Les coordonnes (u,v) du projet dun point 3D de
coordonnes (x,y,z) sont :
u = c.u0 +
c.f * y
c.x0-x
v = c.v0
c.f * z
c.x0-x
.
B.7.3 Afchage lcran
Nous sommes maintenant prts pour afcher notre objet ttradre lcran.
1. Dans les chiers tetra.cpp et tetra.h, dclarer et dnir une fonction affiche
prenant en argument un camera c, un tetra T. Cette fonction dessine un t-
tradre tetra T dans sa couleur, vu par la camera camera c. Pour cela, on uti-
lisera la fonction projette (dclare et dnie dans camera.h et camera.cpp),
ainsi que la fonction DrawLine (dnie dans la WinLib) pour tracer un segment
entre deux Pixel. La dnition de la fonction DrawLine est la suivante :
void DrawLine(const Pixel& p1,const Pixel& p2,const Color& col).
Le projet dun ttradre doit ressembler la gure ci-dessous (gure-a) :
2. Dans le chier main.cpp, crer un ttradre rgulier et lafcher lcran dans
une image de taille 512 512. Pour cela, crer une camra camera C de para-
mtres :
u0=256,v0=256, double x0=10, et double f=500.
B.7.4 Animation du ttradre
Nous cherchons maintenant animer notre modle 3D.
257
B.7. Examen sur machine 2005 : nonc B. Examens
1. Rotation dun vect : dans vect.h et vect.cpp, ajouter une fonction rotate
qui applique une rotation dangle double alpha autour de laxe Oz sur un vec-
teur vect a et qui renvoie un vect b. Les fonctions cos et sin sont dnies
dans #include <cmath>.
b.x = cos() a.x sin() a.y
b.y = sin() a.x + cos() a.y
b.z = a.z
2. Rotation dun tetra : dans tetra.h et tetra.cpp, dclarer et dnir une fonc-
tion rotate qui applique une rotation dangle double alpha autour de laxe
Oz sur un tetra et qui retourne un tetra.
3. Premire animation : dans main.cpp, animer le ttradre dun mouvement de
rotation sur place (pour linstant sans ce soucier de leffacer) : dans une boucle
for (int i=0;i<10000;i++), appliquer une rotation dangle
i
15
chaque
pas de temps. On pourra utiliser la fonction MilliSleep(10).
4. Deuxime animation : maintenant, nous souhaitons afcher et effacer notre ttra-
dre en mouvement :
(a) dans les chiers tetra.cpp et tetra.h, dclarer et dnir une fonction
changeColor prenant en argument un tetra T et un Color c et retour-
nant une structure tetra (de couleur Color c et dont les sommets pos-
sdent les mmes coordonnes que celles de tetra T),
(b) ajouter une fonction pour effacer un ttradre (utiliser les fonctions dnies
prcdemment !).
(c) dans main.cpp, animer le ttradre dun mouvement de rotation en effa-
ant proprement chaque pas de temps.
B.7.5 Un modle plus labor
1. Dans le chier main.cpp, crer un tableau tetra tetras[4] de 4 structures
tetra. Initialiser les 4 ttradres du tableau de manire produire la gure re-
presente ci-dessus (gure-b). Pour cela, gnrer 4 ttradres rguliers et ap-
pliquer lune des 4 translations suivantes sur chacun dentre eux :
{1, 0, 0}, {
1
2
,
3
2
, 0}, {
1
2
,
3
2
, 0}, {0, 0,
2}.
Dnir pour cela une fonction translate pour gnrer le translat dun ttra-
dre tetra T par un vecteur vect t (utiliser loprateur + de vect).
2. Finalement, nous allons animer notre objet tetra tetras[4] dun mouve-
ment complexe et afcher ce dernier dans la camra camera C. A chaque pas
de temps dans la boucle for (int i=0;i<10000;i++), appliquer une rota-
tion dangle
i
15
suivie par une translation de vecteur :
vect t={-12+8
*
cos(i/150.),8
*
sin(i/150.0),-3.0}.
258
B. Examens B.8. Examen sur machine 2004 : nonc
B.8 Examen sur machine 2004 : nonc
B.8.1 Calcul de lexponentielle dun nombre complexe
Le but de cet exercice est de calculer lexponentielle dun nombre complexe et de
sen servir pour calculer le sinus et le cosinus dun angle.
1. Partir dun projet "console" Win 32 Basic Console
2. Ajouter au projet deux chiers complexe.cpp et complexe.h dans lesquels
vous dclarerez et dnirez lendroit appropri :
(a) une structure complexe (et pas complex qui existe dj) reprsentant un
nombre complexe sous forme cartsienne (partie relle, partie imaginaire)
(b) les oprateurs +,
*
entre deux complexe
(c) loprateur / dnissant la division dun complexe par un double
3. On souhaite approximer la fonction exponentielle en utilisant son dveloppe-
ment en srie entire :
e
z
=
+
i=0
z
i
i!
crire une fonction exponentielle, prenant en argument un complexe z et
un int n, et qui retourne la somme :
n
i=0
z
i
i!
4. crire une fonction cos_sin qui renvoie le cosinus et le sinus dun angle en
utilisant le dveloppement limit de e
i
lordre n (on passera donc, en plus de
langle theta, lentier n en argument). On rappelle que :
e
i
= cos + i sin
5. Tester la fonction cos_sin pour diffrentes valeurs de theta et n. Vrier quavec
n = 15 et =
6
, on obtient une bonne approximation des valeurs du cosinus
(
3
2
0.866025404) et du sinus (
1
2
).
B.8.2 Compression RLE
Dans cet exercice nous allons implmenter lune des plus anciennes mthodes de
compression : le codage RLE (Run Length Encoding). Le principe consiste dtecter
une donne ayant un nombre dapparitions conscutives qui dpasse un seuil xe, puis
remplacer cette squence par deux informations : un chiffre indiquant le nombre de
rptitions et linformation rpter. Aussi, cette mthode remplace une squence par
une autre beaucoup plus courte moyennant le respect du seuil (que nous xerons, par
simplicit, 0). Elle ncessite la prsence de rptitions relativement frquentes dans
linformation source compresser.
Cette mthode prsente peu davantages pour la compression de chier texte. Par
contre, sur une image, on rencontre rgulirement une succession de donnes de mme
259
B.8. Examen sur machine 2004 : nonc B. Examens
valeur : des pixels de mme couleur.
Sur une image monochrome (un fax par exemple), lensemble compresser est une
succession de symboles dans un ensemble deux lments. Les lments peuvent tre
soit des 255 (pixel allum=blanc), soit des 0 (pixel teint=noir) ; il est relativement facile
de compter alternativement une succession de 0 et de 255, et de la sauvegarder telle
quelle.
source : 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 0 0 0 0 0 255 255 255 255
compression : 10 8 5 4
Cependant, une convention reste prendre : savoir par quel pixel commencera la suc-
cession de chiffres. Nous considrerons que le premier nombre reprsente une succes-
sion de 0. Si la source ne commence pas par des pixels noirs (un zro) il faut alors
commencer la chaine codante par un 0 pour indiquer labsence de pixel noir.
Dans ce qui suit nous allons encoder une image binaire (constitue de 0 et de 255
stocks dans un tableau de byte) dans un tableau de int.
1. Partir dun projet "Winlib" (Winlib5 Project).
2. Dans la fonction main,
(a) Dclarer les variables de type const int w et h representant la largeur et
la hauteur de limage encoder. Ces variables pourront tre initialises la
valeur 256.
(b) Dclarer le tableau de byte image_source de taille w h (rappel : le pixel
(i, j) est llment i + j w du tableau).
(c) Dclarer le tableau de byte image_decodee de taille w h (rappel : le pixel
(i, j) est llment i + j w du tableau).
(d) Dclarer le tableau de int image_encodee de taille w h + 1
3. Crer une fonction affiche_image de dclaration :
void affiche_image( byte image[], int w, int h );
Cette fonction afche limage stocke dans image de largeur w et de hauteur h
laide de la fonction PutGreyImage de la Winlib.
4. Dans la fonction main, tester la fonction affiche_image avec image_source, sans
lavoir initialise.
5. Crer une fonction remplir_rectangle de dclaration :
void remplir_rectangle(
byte image[], int w, int h,
int xul, int yul, int height, int width );
Cette fonction dessine un rectangle blanc dans une image en mettant 255 tous
les pixels de limage contenus dans le rectangle. Limage dans laquelle est dessin
le rectangle plein est donne par le tableau image et les dimensions w et h de
limage. Le rectangle remplir est donn par les coordonnes xul et yul de son
coin suprieur gauche ainsi que par ses dimensions height et width.
6. Nous allons maintenant tester la fonction remplir_rectangle. Pour ce faire :
(a) Remplir limage avec des 0.
260
B. Examens B.8. Examen sur machine 2004 : nonc
(b) Utiliser la fonction remplir_rectangle sur cette image pour y placer un rec-
tangle de votre choix.
(c) Afcher cette image laide de affiche_image
7. Crer une fonction RLE_encode de dclaration :
void RLE_encode(
byte source_image[], int w, int h,
int compression[], int &comp_size );
Limage compresser est donne par sa largeur w, sa hauteur h et par un ta-
bleau source_image. Le rsultat de la compression est stock dans le tableau
compression et le nombre dlments utiliss dans ce tableau comp_size. (pour
rappel, le tableau prvu pour recevoir limage comprime est dclare de ma-
nire statique dans main et w h + 1 nest quun majorant de la taille de limage
comprime.)
8. Crer une fonction RLE_decode de dclaration :
void RLE_decode( int compression[], int comp_size,
byte decomp_image[] );
Limage dcompresser est donne par un tableau compression et la taille des
donnes dans ce tableau comp_size. Le resultat de la dcompression est stock
dans le tableau decomp_image.
9. Dans la fonction main et laide des fonctions prcdemment dnies :
(a) Remplir dans le tableau image_source deux rectangles de votre choix.
(b) Afcher cette image
(c) Encoder image_source dans image_encodee
(d) Decoder image_encodee dans image_decodee
(e) Alaide dune boucle, vrier que les deux images image_source et image_decodee
sont identiques.
(f) Afcher limage dcode et valider la vrication prcdente de manire
visuelle.
10. Crer une fonction remplir_diagonale de dclaration :
void remplir_diagonale( byte image[], int w, int h );
Cette fonction met tous les pixels (i, j) tels que i == j de image 255.
11. Tester la fonction remplir_diagonale de la mme faon que la fonction remplir_rectangle
a t teste.
12. On xe w = 256 et h = 128
(a) Remplir limage source de zros.
(b) Remplir dans limage source un rectangle dont le coin suprieur gauche est
en (20, 20) de dimensions (80, 80)
(c) Remplir dans limage source un second rectangle dont le coin suprieur
gauche est en (120, 10) de dimensions (100, 100)
(d) Compresser limage source et afcher la taille de limage compresse comp_size
(e) Remplir nouveau limage source de zros.
261
B.8. Examen sur machine 2004 : nonc B. Examens
(f) Remplir dans limage source la diagonale.
(g) Compresser limage source et afcher la taille de limage compresse comp_size
13. On xe w = 1024 et h = 1024
(a) Un plantage se produit.
(b) Identier le problme et modier le programme pour quil fonctionne avec
les valeurs de w et h donnes.
262
B. Examens B.9. Examen sur machine 2003: nonc
B.9 Examen sur machine 2003 : nonc
B.9.1 Crible dratosthne
Rappel : un entier naturel est dit premier sil nest divisible que par 1 et lui-mme, et quil
est diffrent de 1.
Le but de cet exercice est de dresser par ordre croissant la liste des nombres pre-
miers. On utilisera pour cela le crible dratosthne, qui repose essentiellement sur le
fait que les diviseurs ventuels dun entier sont plus petits que lui. La mthode consiste
parcourir dans lordre croissant la liste des nombres entiers candidats (par exemple
initialement tous les nombres de 2 999, si lon se restreint aux entiers infrieurs
1000), et, chaque nombre rencontr, retirer de la liste des nombres candidats tous
les multiples de celui-ci. Une fois la liste parcourue, il ne restera que les nombres pre-
miers.
On recherche les nombres premiers infrieurs ou gaux n, n tant un nombre
entier suprieur 2, intialement x 100. Plutt que de grer une liste dentiers et den
enlever des nombres, on travaillera avec un tableau de n boolens avec la convention
que la i
e
case du tableau contiendra true si i est premier, et false sinon.
1. Partir dun projet "console" (Win 32 Basic Console).
2. Dans la fonction main, crer le tableau de boolens et le remplir avec des true.
3. Crer une fonction multiples qui prend en argument le tableau, sa taille et un
entier a, et qui tourne false les lments du tableau correspondants des
multiples de a (except a, bien sr).
4. Utiliser la fonction multiples de faon approprie dans la fonction main, dans
une boucle parcourant le tableau, an dexcuter le crible dratosthne. Il est
inutile de considrer les multiples des nombres qui ne sont pas premiers ( ce
propos ne pas oublier que 1 consitue un cas particulier).
5. Afcher le nombre de nombres premiers infrieurs ou gaux 211, ainsi que les
nombres premiers en question.
6. Vrier que lon peut sarrter
n.
B.9.2 Calcul de par la mthode de Monte Carlo
On dsigne par mthode de Monte Carlo une mthode de rsolution dun problme
mathmatique laide de suites de nombres alatoires convergeant vers le rsultat,
en rfrence aux nombreux casinos mongasques. Le mthode de Monte Carlo clas-
sique pour calculer une valeur approche de consiste tirer alatoirement un grand
nombre n de fois des points (x, y) du plan avec 1 x 1, 1 y 1 puis de d-
terminer quelle est la proportion p
n
de ces points qui sont situs dans le disque unit.
Comme la surface de ce dernier vaut , on peut montrer que lim
n+
p
n
=
4
. Le but
de cet exercice est de programmer ce calcul et une visualisation graphique de celui-ci.
Fonctions utiles
Nombres pseudo-alatoires
#include <cstdlib>
using namespace std;
void srand(unsigned int seed); // Initialise le gestionnaire de nombres
263
B.9. Examen sur machine 2003 : nonc B. Examens
// pseudo-alatoires
int rand(); // Retourne un nombre pseudo-alatoire entre 0 et RAND_MAX
// inclus
Temps
#include <ctime>
using namespace std;
long time(...); // time(0) renvoie le nombre de secondes coules
// depuis le 1er janvier 1970
WinLib
#include <win>
using namespace Win;
void DrawPoint(int x,int y,const Color& col); // Affiche un pixel
// lcran
void DrawCircle(int xc,int yc,int r,const Color& col); // Affiche un cercle
// centr en (xc,yc),
// de rayon r
// et de couleur col
1. Ajouter un nouveau projet WinLib nomm MonteCarlo la solution et le dnir
cmme projet de dmarrage.
2. Dnir dans main.cpp une constante globale taille_fenetre et lutiliser
dans lappel OpenWindow. Dans tout ce qui suit, la fentre sera carre, repr-
sentant lensemble des points dont les coordonnes sont entre -1 et 1.
3. Ajouter au projet deux chiers Point.h et Point.cpp dans lesquels vous d-
clarerez et dnirez lendroit appropri :
(a) une structure PointPlan reprsentant des points du plan (il faut en particu-
lier pouvoir avoir des coordonnes entre 1 et 1)
(b) une fonction GenerePoint retournant un PointPlan dont les coordonnes
sont tires alatoirement entre -1 et 1. Ne pas oublier quen C++, la division
de deux entiers est la division entire !
(c) une fonction AfchePoint, prenant en argument la taille de la fentre daf-
chage, une couleur et un PointPlan, et qui afche ce dernier lcran dans la
couleur prcise (penser renormaliser !).
4. Appeler la procdure dinitialisation du gestionnaire de nombre pseudo-alatoires
au dbut de main avec srand(unsigned int(time(0)));. Penser aux #include
et using namespace correspondants.
5. Dessiner lcran le cercle unitaire au dbut de main.cpp.
6. Dnir une constante globale nb_iterations dans main.cpp reprsentant le
nombre ditrations effectues. Construire une boucle effectuant nb_iterations
fois les oprations suivantes :
(a) Gnrer un point pseudo-alatoire
264
B. Examens B.9. Examen sur machine 2003 : nonc
(b) Incrmenter une variable compteur si ce point est dans le disque unitaire
(cest--dire si x
2
+y
2
1). On rajoutera une fonction retournant le carr de
la norme dun point.
(c) Afcher ce point lcran, en bleu sil est dans le disque, en rouge sinon.
7. Afcher la n du programme la valeur de dduite.
8. Varier nb_iterations an davoir un bon compromis temps dafchage / pr-
cision de la valeur calcule. Que constate-t-on? Pourquoi ? (Rpondre en com-
mentaire du programme)
B.9.3 Serpent
FIGURE B.6 A gauche : calcul de . A droite : un serpent.
Le but de cet exercice est de programmer un serpent qui se dplace sur un terrain
rectangulaire en vitant de se mordre lui-mme. Pour cela structures et tableaux seront
utiles. Ne pas oublier de compiler et tester chaque tape... NB : certaines questions
sont indpendantes.
1. Structure : Partir dun projet WinLib. Crer une structure point mmorisant
deux coordonnes entires x et y.
2. Dessin : On va dessiner un serpent de dplaant sur un terrain de dimensions
(w,h). Pour bien le visualiser, on lafchera dans un fentre de dimensions (w
*
z,h
*
z)
(Prendre par exemple (w,h,z)=(40,30,10)).
(a) Programmer une fonction void dessine(point p,int zoom,Color c)
utilisant la fonction
FillRect(x,y,w,h,c) pour dessiner un carr plein de coin suprieur
gauche (p.x
*
zoom,p.y
*
zoom), de ct zoom-1 et de couleur c.
(b) Ecrire une fonction void dessine(point s[],int n,int zoom) des-
sinant un serpent constitu des points s[0] s[n-1], s[0] tant la tte.
On pourra tracer le corps du serpent en rouge et sa tte en bleu (gure B.6).
(c) Initialiser un serpent dans un tableau de dimension constante n=10 et laf-
cher.
3. Divers : programmer quatre fonctions utiles pour la suite :
(a) Une fonction bool operator==(point a,point b) retournant vrai si
les points a et b sont gaux, ce qui permettra dcrire un test comme if (p1==p2).
265
B.9. Examen sur machine 2003 : nonc B. Examens
(b) Une fonction bool cherche(point s[],int n,point p) retournant
vrai si le point p se trouve dans le tableau s de taille n.
(c) Une fonction void decale(point s[],int n,point p) qui dcale le
tableau s vers le haut (i.e. s[i]=s[i-1]) et range p dans s[0]. Cette fonc-
tion sera utile pour la suite !
(d) Une fonction point operator+(point a,point b) calculant la somme
de deux points (considrs comme des vecteurs).
4. Avancer dune case : Le serpent peut avancer dans une des quatre directions. On
mmorise la direction de son dplacement par un entier de 0 3, avec la conven-
tion (0,1,2,3)=(est,sud,ouest,nord).
(a) Crer et initialiser une variable globale const point dir[4] telle que
dir[d] correspond un dplacement dans la direction d. Ainsi, d[0]={1,0},
d[1]={0,1}, etc.
(b) Ecrire et tester une fonction void avance(point s[],int n,int d,int zoom)
utilisant ce qui prcde pour :
Avancer le serpent s,n dans la direction d.
Afcher sa nouvelle position sans tout re-dessiner (effacer la queue et des-
siner la tte).
5. Avancer : Ecrire les quatre fonctions suivantes :
bool sort(point a,int w,int h) qui retourne vrai si le point a est en
dehors du terrain.
void init_rand() qui initialise le gnrateur alatoire.
void change_dir(int& d) qui change alatoirement d en d-1 une fois sur
20, en d+1 une fois sur 20 et ne modie pas d les 18 autres fois, ce qui, compte
tenu de la convention adopte pour les directions, revient tourner droite ou
gauche de temps en temps. Attention bien conserver d entre 0 et 3.
bool ok_dir(point s[],int n,int d,int w,int h) qui teste si le d-
placement du serpent dans la direction d ne va pas le faire sortir.
puis les utiliser pour faire avancer le serpent dans une boucle de 500 pas de
temps, en vriant quil ne sort pas du terrain. Penser rajouter un MilliSleep()
si le dplacement est trop rapide (sur certains PC de lENPC, la WinLib ne sera
pas jour et lafchage sera lent et saccad... Ignorer.)
6. Ne pas se manger : modier ok_dir() pour que le serpent ne se rentre pas dans
lui-mme.
7. Escargot : le serpent peut se retrouver coinc sil senroule sur lui-mme. Program-
mer une fonction bool coince(point s[],int n,int w,int h) qui teste
si aucune direction nest possible et modier la boucle principale pour terminer
le programme dans ce cas.
8. Grandir (question nale difcile) :
Changer le programme pour que le tableau s soit allou dans le tas (n pourra
alors tre variable).
Un pas de temps sur 20, appeler, la place de avance(), une fonction void allonge()
qui avance dans le direction d sans supprimer la queue. Du coup, s doit tre
rallou et n augmente de 1. Ne pas oublier de dsallouer lancienne valeur de
s. Bien grer lafchage, etc. Cette fonction sera dclare void allonge(point
*
& s,int& n,
int d,int zoom).
266
B. Examens B.10. Devoir maison 2007: nonc
B.10 Devoir maison 2007 : nonc
Enonc Erreurs et Quafche ce programme ?
Dans cet exercice, on vous demande deux choses :
1. Corriger les 10 erreurs contenues dans le code du programme suivant, directe-
ment sur la feuille dnonc ;
2. Donner, en le justiant, lafchage que produit ce programme sur la sortie stan-
dard (cest--dire lcran, via la commande cout << ... ;). Procdez avec
mthode en faisant attention aux retours de fonction, et lquilibre ncessaire
entre appels aux constructeurs/destructeurs.
1 include<iostream>
2 namespace std;
3
4 class A {
5 int a;
6 A();
7 A(int b);
8 A(const A& b);
9 void operator=(const A& b);
10 void add(int b);
11 ~A();
12 }
13
14 void A() {
15 cout << "C1" << endl;
16 a=0;
17 }
18
19 void A(int b) {
20 cout << "C2 " << b << endl;
21 a=b;
22 }
23
24 void A(const B& b){
25 cout << "C3 " << b.a << endl;
26 a=b.a;
27 }
28
29 void A::operator=(const A& b){
30 cout << "E " << a << " " << b.a << endl;
31 a.a=b.a;
32 }
33
34 void A::add(int b) {
35 cout << "A " << a << " " << b << endl;
36 a+=b;
37 }
267
B.10. Devoir maison 2007 : nonc B. Examens
38
39 void F(A d,A& e) {
40 d.add(3);
41 e.add(4);
42 f=d;
43 return f;
44 }
45
46 void ~A() {
47 cout << "D " << a << endl;
48 }
49
50 int main()
51 {
52 A a;
53 A b(1);
54 A c(b);
55 b.add(4);
56 c=F(b,a);
57 }
268
B. Examens B.11. Devoir maison 2006 : nonc
B.11 Devoir maison 2006 : nonc
B.11.1 Enonc Tours de Hanoi
Principe et rgles
Le jeu est constitu de 3 tiges, A, B et C, sur lesquelles sont empils des anneaux de
taille dcroissante, que lon numrotera de N 1.
FIGURE B.7 Conguration initiale
Au dbut du jeu, tous les anneaux sont empils sur la tige A (voir gure B.7). Lob-
jectif est de transfrer tous les anneaux sur la tige C. Il nest possible de dplacer les
anneaux que un par un, et il nest pas possible de poser un anneau sur un autre de
taille infrieure.
On dsignera par le terme configuration une disposition des anneaux sur les
tiges (voir gure B.8).
FIGURE B.8 Exemple de conguration
On dsignera par le terme dplacement de la tige X la tige Y le fait denlever
lanneau situ au sommet de la pile de la tige X pour le positionner au sommet de la
pile de la tige Y (voir gure B.9).
Objectif
Lobjectif ici est dcrire un programme qui afche la suite des dplacements ra-
liser pour rsoudre le problme avec n anneaux, sous la forme suivante :
numero_anneau : tige_origine > tige_destination
On souhaite de plus afcher ltat du jeu (les anneaux prsents sur chaque tige) aprs
chaque dplacement.
269
B.11. Devoir maison 2006 : nonc B. Examens
FIGURE B.9 Exemple de dplacement
Exemple pour 2 anneaux (la gure B.10 en donne une reprsentation graphique) :
A> 2 1
B> . .
C> . .
deplacement: 1 : A->B
A> 2 .
B> 1 .
C> . .
deplacement: 2 : A->C
A> . .
B> 1 .
C> 2 .
deplacement: 1 : B->C
A> . .
B> . .
C> 2 1
FIGURE B.10 Solution du problme pour N=2
270
B. Examens B.11. Devoir maison 2006 : nonc
Ce problme apparemment complexe se traite en fait simplement : pour transfrer
n anneaux dune tige X une tige Y, il "suft" deffectuer :
le transfert des n-1 anneaux suprieurs de la tige X sur la troisime tige Z
le dplacement de lanneau n de la tige X la tige destination Y
le transfert des n-1 anneaux de la tige Z la tige Y
Pour transfrer n-1 anneaux, on applique la mme mthode : transfert de n-2 anneaux
de la tige origine une tige temporaire, dplacement dun anneau de la tige origine
la tige destination, transfert des n-2 anneaux de la tige temporaire la tige destination
...
Questions
1. Dclarer une constante N, que lon xera 10, et qui reprsentera le nombre dan-
neaux du problme rsoudre.
2. Crer un objet capable de stocker une conguration. On pourra par exemple re-
prsenter chaque tige par un tableau de taille N, et chaque anneau par un entier
entre 1 et N. Vous utiliserez au choix une structure ou une classe, selon ce qui
vous semble le plus pertinent, ou dfaut ce avec quoi vous tes le plus laise.
3. Programmer de quoi initialiser une conguration, cest dire lui donner sa valeur
de dpart (tous les anneaux sur la premire tige).
4. Programmer une fonction permettant dafcher une conguration lcran, par
exemple sous la forme utilise ci-dessus pour lexemple pour N=2.
5. Programmer une fonction ralisant un dplacement : pour une tige origine et une
tige destination spcies, elle prlve le pion suprieur sur la tige origine et le
place sur la tige destination.
6. En vous basant sur la mthode propose, programmer une fonction ralisant un
transfert de k anneaux dune tige une autre, et afchant au fur et mesure les
dplacements effectus, et ltat du jeu aprs chaque dplacement.
7. En utilisant les lments prcdents, crire une fonction main() qui rsout le pro-
blme des tours de Hanoi de taille N et afche la solution complte.
Questions complmentaires
1. Si lon avait souhait nafcher que la liste des dplacements effectuer sans
afcher chaque fois les congurations intermdaires, le programme aurait t
beaucoup plus simple. Pourquoi ? Ecrire la fonction correspondante (5 lignes de
code environ).
2. Pour rsoudre le problme avec N anneaux, combien de dplacements sont n-
cessaires ?
271
B.12. Devoir maison 2004 : nonc B. Examens
B.12 Devoir maison 2004 : nonc
B.12.1 Tableau dexcution
Pour ce premier exercice, il sagit dexcuter pas pas le programme suivant :
1 #include <iostream>
2 using namespace std;
3
4 int hop(int x) {
5 x = x+2;
6 return x;
7 }
8
9 int hip(int& y) {
10 y = y
*
2;
11 return y+1;
12 }
13
14 int f(int& z) {
15 int t = z+3;
16 z=2
*
t;
17 if (z>20)
18 return z;
19 return f(t);
20 }
21
22 int main() {
23 int a;
24 a = hop(1);
25 int b;
26 b = hip(a);
27 a = f(a);
28 return 0;
29 }
Pour cela, remplissez le tableau ci-dessous, en crivant, si elles existent, les va-
leurs des variables du programme pour chaque excution de ligne (selon lexemple
du cours).
272
B. Examens B.12. Devoir maison 2004: nonc
Conventions :
mettre le numro de la ligne quon vient dexcuter (ventuellement, on peut
dcouper lexcution dune mme ligne en plusieurs tapes)
on peut utiliser le symbole pour rpter la valeur dune variable la ligne sui-
vante
une case vide signie que la variable nexiste plus ou pas encore
pour une variable qui nest autre quune rfrence sur une autre variable x, on
indiquera [x] ;
sil y a rcursivit, indicer par un entier plusieurs appels imbriqus une mme
fonction (f
1
, f
2
, ...)
Ligne a
m
b
m
x
hop
ret
hop
y
hip
ret
hip
z
f
1
t
f
1
ret
f
1
z
f
2
t
f
2
ret
f
2
B.12.2 Constructeurs
Dans ce deuxime exercice, on vous demande tout simplement de donner et jus-
tier lafchage que produit lexecution du programme suivant sur la sortie standard
(cest--dire lcran, via la commande cout<<...) :
1 #include<iostream>
2 using namespace std;
3
4 class Vecteur
5 {
6 int tab[2];
7 void affiche() const;
8 public:
9 Vecteur();
10 Vecteur(int n);
11 Vecteur(const Vecteur &right);
12 ~Vecteur();
13 void operator=(const Vecteur& right);
14 Vecteur operator+(const Vecteur& right) const;
15 int operator
*
(const Vecteur right) const;
16 int& getX(int i);
17 };
18
19 Vecteur::Vecteur()
20 {
21 for(int i=0;i<2;i++) tab[i]=0;
22 cout<<"Contructeur par defaut: ";
23 affiche();
273
B.12. Devoir maison 2004: nonc B. Examens
24 }
25 Vecteur::Vecteur(int x)
26 {
27 for(int i=0;i<2;i++) tab[i]=x;
28 cout<<"Constructeur de remplissage: ";
29 affiche();
30 }
31 Vecteur::Vecteur(const Vecteur &right)
32 {
33 for(int i=0;i<2;i++) tab[i]=right.tab[i];
34 cout<<"Constructeur par copie: ";
35 affiche();
36 }
37 Vecteur::~Vecteur()
38 {
39 cout<<"Destructeur: ";
40 affiche();
41 }
42 void Vecteur::operator=(const Vecteur& right) {
43 for(int i=0;i<2;i++) tab[i]=right.tab[i];
44 cout<<"Operateur de copie: ";
45 affiche();
46 }
47 Vecteur Vecteur::operator+(const Vecteur& right) const {
48 Vecteur Res;
49 for(int i=0;i<2;i++) Res.tab[i]=tab[i]+right.tab[i];
50 return Res;
51 }
52 int Vecteur::operator
*
(const Vecteur right) const {
53 int Res=0;
54 for(int i=0;i<2;i++) Res+=tab[i]
*
right.tab[i];
55 return Res;
56 }
57 int& Vecteur::getX(int i){
58 return tab[i];
59 }
60 void Vecteur::affiche() const{
61 for (int i=0;i<2;i++)
62 cout<<tab[i]<<" ";
63 cout<<endl;
64 }
65 void affiche(Vecteur vec){
66 cout<<"Affiche: ";
67 for (int i=0;i<2;i++)
68 cout<<vec.getX(i)<<" ";
69 cout<<endl;
70 }
71 int main()
72 {
274
B. Examens B.12. Devoir maison 2004 : nonc
73 Vecteur A;
74 cout<<endl;
75 Vecteur B(-2);
76 cout<<endl;
77 Vecteur C=B;
78 cout<<endl;
79 B.getX(1)=3;
80 affiche(C);
81 cout<<endl;
82 cout<<"Produit scalaire: "<<B
*
C<<endl;
83 cout<<endl;
84 A=B+C;
85 cout<<endl;
86 return 0;
87 }
B.12.3 Le compte est bon
Le but de cet exercice va tre dcrire un programme capable de rsoudre le pro-
blme du Compte est bon dont voici une description :
6 plaques sont tires au hasard parmi 14 plaques diffrentes dont chacune peut
tre choisi de 0 2 fois. Les 14 plaques comportent les nombres : 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 25, 50, 75, 100.
Un nombre entre 100 et 999 (inclus) est tir au hasard, on lappelera par la suite
le total.
Une des 4 oprations arithmtiques (addition, soustraction, division entire, mul-
tiplication) est utilise sur deux des 6 plaques pour obtenir un nouveau nombre
(attention : la division entire ne peut tre utilise que si le dividande est divi-
sible par le diviseur ; la soustraction ne peut tre utilise que si le premier terme
est plus grand que le second). Il nous reste alors 5 nombres (les 4 plaques non
choisies et le nouveau nombre) partir desquels recommencer.
Le but est dobtenir nalement le total, en utilisant tout ou partie des 6 plaques
ainsi que dcrit prcdemment.
Par exemple, on tire le total 987 et les plaques suivantes :
1 50 9 1 50 7
Une solution sera par exemple :
1 + 1 = 2
2 50 = 100
100 9 = 91
91 + 50 = 141
141 7 = 987
Il nexiste pas toujours de solution. Dans ce cas, le candidat doit trouver une solu-
tion approchant au plus prs le total. Pour simplier, le programme que vous crirez
cherchera uniquement des solutions exactes.
275
B.12. Devoir maison 2004 : nonc B. Examens
La manire dont trouver une solution est trs simple : le programme va simplement
munrer toutes les possibilits de combiner les nombres crits sur les plaques et les
oprateurs arithmtiques, jusqu tomber sur une bonne solution ou les avoir explores
toutes.
On utilisera dans le programme partout o cela est possible les constantes globales
suivantes :
const int total_min=100;
const int total_max=999;
const int nb_plaques=6;
const int nb_plaques_possibles=14;
const int plaques_possibles[nb_plaques_possibles]=
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 25, 50, 75, 100};
const int nb_operateurs=4;
const char operateurs[nb_operateurs]={+,-,/,
*
};
1. Dnir une fonction de prototype int random(int a,int b) renvoyant un
nombre alatoire entre a et b (inclus). Prciser les #include et using namespace
ncessaires.
2. Dnir une fonction int genere_total() renvoyant un nombre alatoire entre
total_min et total_max
3. Dnir une fonction void affiche_plaques(int tab[nb_plaques]) que
lon utilisera ultrieurement pour afcher lcran les plaques tires au hasard.
Que faut-il rajouter comme #include?
4. Dnir une fonction void genere_plaques(int tab[nb_plaques]) effec-
tuant le tirage au hasard des plaques. An de se souvenir du nombre de fois o
on a tir chaque plaque et dimposer den tirer au plus 2, on pourra utiliser une
variable int plaque_deja_tiree[nb_plaques_possibles].
5. Dnir la fonction main de votre programme qui initialisera le gestionnaire de
nombre alatoires, effectuera le tirage du total et des plaques, et afchera le tout
lcran. Que faut-il rajouter comme #include?
6. Nous allons maintenant nous attaquer au cur du problme, la fonction
bool trouve_combinaison (int plaques[], int n, int total) qui,
tant donne un tableau de plaques plaques de taille n et un total total :
Renvoie true et afche lcran une solution si elle existe.
Renvoie false sinon.
trouve_combinaison sera programme rcursivement suivant le nombre de
plaques n :
Si n==1, le problme est trivial
Sinon, on effectue lopration plaques[i] op plaques[j] pour tous les
i et j distincts entre 0 et n et tous les oprateurs arithmtiques op, si elle est
possible. Ensuite :
Si on tombe sur le nombre total, on afche lopration qui nous a permis
dy accder et on renvoie true.
Sinon, on appelle rcursivement la fonction bool trouve_combinaison
sur un nouveau tableau de plaques. Si cet appel rcursif renvoie true, cest
276
B. Examens B.12. Devoir maison 2004 : nonc
quil est possible dobtenir une solution partir de cette tape intermdiaire.
On renvoie alors galement true et on afche lopration qui nous a permir
daccder cette tape intermdiaire. Sinon, on continue itrer.
7. Ajouter votre fonction main lutilisation de la fonction trouve_combinaison.
Quand aucune combinaison nest trouve, le signaler en afchant un message
lcran.
8. Le programme que vous avez crit ne sait pas trouver de solution approche, ne
retient quune seule solution (pas forcment la plus courte) et lafche en ordre
inverse. Que faudrait-il faire (en franais, sans essayer de le programmer) pour
rsoudre ces limitations ?
277
B.13. Devoir maison 2003 : nonc B. Examens
B.13 Devoir maison 2003 : nonc
B.13.1 Tableau dexcution
Pour ce premier exercice, il sagit dexcuter pas pas le programme suivant :
1 int hop(int x) {
2 x = x/2;
3 return x;
4 }
5
6 int hip(double& y) {
7 y = y/2;
8 return (int(y));
9 }
10
11 int test(double z) {
12 z = 2
*
hip(z) - z;
13 if (z>4)
14 z = test(z);
15 return (int(z));
16 }
17
18 int main() {
19
20 double a = 3.14;
21
22 int b = hop(int(a));
23 b = hip(a);
24
25 a = 18;
26 do {
27 a = test(a);
28 } while (a != 0);
29
30 return 0;
31 }
Pour cela, remplissez le tableau ci-dessous, en crivant, si elles existent, les va-
leurs des variables du programme pour chaque excution de ligne (selon lexemple
du cours).
278
B. Examens B.13. Devoir maison 2003 : nonc
Conventions :
mettre le numro de la ligne quon vient dexcuter (ventuellement, on peut
dcouper lexcution dune mme ligne en plusieurs tapes)
on peut utiliser le symbole pour rpter la valeur dune variable la ligne sui-
vante
pour une variable qui nest autre quune rfrence sur une autre variable x, on
indiquera [x] ;
Ligne a
main
b
main
ret
main
x
hop
ret
hop
x
hip
ret
hop
x
test(1)
ret
test(1)
x
test(2)
ret
test(2)
B.13.2 Grands entiers
Le but de cet exercice est de manipuler des entiers arbitrairement grands. Un entier
long sera un entier compris entre 0 et 10
4n
1, o n est une constante xe une fois
pour toutes, par exemple n = 30. On dcoupera les grands entiers comme si on les
considrait crits en base 10
4
, cest--dire sous la forme dun tableau de n int.
1. Crer une classe entier comprenant un tableau dentiers de taille n.
2. Le tableau dun entier contient la reprsentation de celui-ci en base 10
4
, la pre-
mire case contenant llment de poids le plus faible. Par exemple 15 439 573 458
se codera sous la forme 3458 3957 154. En consquent, on a besoin de connatre
lindice de llment de poids le plus fort an de savoir o arrter la lecture du
tableau. Ajouter la classe un champ de type int servant stocker lindice en
question.
3. Ajouter cette classe un constructeur vide.
4. Dnir un constructeur prenant en argument un int positif crant un entier
de mme valeur.
5. Ajouter la classe une mthode afchant lcran un entier, dans lordre stan-
dard pour la lecture.
6. Ajouter loprateur daddition (attention aux retenues !).
7. Ajouter loprateur de multiplication. On pourra procder en 3 temps : crer
une fonction multipliant un entier par un int (< 10
4
), une autre multipliant un
entier par 10
4
, et utiliser de faon adquate ces deux fonctions ainsi que laddi-
tion prcdemment dnie. Ou alors on pourra faire mieux (ce qui nest pas bien
difcile, il suft deffectuer une multiplication la main pour entrevoir diffrents
algorithmes).
8. Calculer 50! et lafcher.
B.13.3 Constructeurs
Examinez bien le contenu du programme suivant. La question est simple : quelles
sont les diffrentes lignes afches sur la sortie standard (cest--dire en console, via les
279
B.13. Devoir maison 2003: nonc B. Examens
instructions cout << ... ;) au cours de son excution? Justier vos rponses.
1 #include <iostream>
2 using namespace std;
3
4 class foo {
5 int x;
6
7 public:
8 // Constructeurs
9 foo();
10 foo(const foo &f);
11 foo(int i);
12
13 // Destructeur
14 ~foo();
15
16 // Oprateurs
17 foo operator+(const foo &f) const;
18 void operator=(const foo &f);
19
20 // Accesseur
21 int getx() const;
22 };
23
24 foo::foo()
25 {
26 x=0;
27 cout << "constr vide " << endl;
28 }
29
30 foo::foo(int i)
31 {
32 x=i;
33 cout << "constr int " << x << endl;
34 }
35
36 foo::foo(const foo &f)
37 {
38 x=f.x;
39 cout << "constr copie " << x << endl;
40 }
41
42 foo::~foo()
43 {
44 cout << "dest " << x << endl;
45 }
46
47 foo foo::operator+(const foo &f) const
280
B. Examens B.13. Devoir maison 2003 : nonc
48 {
49 cout << "somme " << x << " " << f.x << endl;
50 foo somme(x+f.x);
51 return somme;
52 }
53
54 void foo::operator=(const foo &f)
55 {
56 x=f.x;
57 cout << "affecte " << x << endl;
58 }
59
60 int foo::getx() const
61 {
62 return x;
63 }
64
65 void affiche1(foo f)
66 {
67 cout << f.getx() << endl;
68 }
69
70 void affiche2(const foo &f)
71 {
72 cout << f.getx() << endl;
73 }
74
75 int main()
76 {
77 foo a;
78 foo b=1;
79 foo c(2);
80 affiche1(b);
81 affiche2(c);
82 a=b+c;
83 return 0;
84 }
281
B.14. Devoir surveill 2011 : nonc B. Examens
B.14 Devoir surveill 2011 : nonc
B.14.1 Liste avec sauts
Les listes sont des structures de donnes simples permettant lajout et le retrait
dun lment en temps constant. Chaque noeud contient, outre une valeur, un pointeur
sur le noeud suivant. Les listes avec saut (en anglais, skip lists, voir Fig. B.11) ont t
proposes en 1990 par William Pugh, professeur lUniversit du Maryland, College
Park. Elles compensent des inconvnients des listes en ce qui concerne la recherche
dun lment dans une liste trie. Lide est de maintenir des raccourcis dans la liste
qui permettent de se dplacer plus vite. Cela se fait au prix dune certaine utilisation
mmoire supplmentaire, mais qui peut rester modre et qui est modulable.
1
3
4
8
10
15
16
T
e
t
e
Q
u
e
u
e
niveau 0
niveau 1
niveau 2
FIGURE B.11 Une liste avec sauts. Les valeurs sont tries. Des raccourcis existent aux
niveaux 1 et 2 pour une recherche plus rapide.
Le plus logique est dutiliser des pointeurs pour coder le lien dun noeud au sui-
vant. Comme nous avons vit le plus possible de manipuler des pointeurs dans le
cours, nous nous en passerons et coderons simplement un index (sous forme dentier)
dans un tableau.
Nous utiliserons des tableaux de taille variable. La structure de choix est la classe
template std :: vector, accessible par #include <vector>. Rappelons la partie de linter-
face des vecteurs qui nous sera utile :
t empl at e <typename T>
c l a s s vect or {
publ i c :
vect or ( ) ;
void push_back ( T t ) ;
T& operat or [ ] ( i nt i ) ;
i nt s i ze ( ) ;
/ / . . .
} ;
Un lment sajoute avec push_back. Par exemple :
st d : : vect or <i nt > vec ;
vec . push_back ( 0 ) ;
vec . push_back ( 1 ) ;
st d : : cout << vec [ 0 ] << << vec [ 1 ] << st d : : endl ;
vec [ 0 ] =2 ;
st d : : cout << vec [ 0 ] << << vec [ 1 ] << st d : : endl ;
/ / Af f i c h a g e :
/ / 0 1
/ / 2 1
282
B. Examens B.14. Devoir surveill 2011 : nonc
B.14.2 Travail demand
Certaines questions concernent lanalyse de la complexit, dautres la pro-
grammation et lalgorithmique.
Prliminaires
1. Rappeler la complexit de la recherche dichotomique dans un tableau tri.
2. Rappeler la complexit de la recherche dun lment dans une liste en fonction
de son nombre n dlments. Cette complexit change-t-elle lorsquon suppose la
liste trie ?
3. On implmente maintenant une liste trie 2 niveaux, avec des raccourcis comme
ci-dessous. Dcrire un algorithme permettant de vrier la prsence dun lment
de valeur v dans cette liste, utilisant au maximum les raccourcis de niveau 1 (la
liste complte sans raccourcis tant au niveau 0). On ne demande pas un code en
C++ mais une description dtaille en franais de lalgorithme.
1
3
4
8
10
15
16
T
e
t
e
Q
u
e
u
e
niveau 0
niveau 1
FIGURE B.12 Liste rgulire 2 niveaux
4. Quelle est la complexit en nombre de comparaisons de cet algorithme de re-
cherche ?
5. Dessiner la mme liste avec des raccourcis au niveau 2, sautant de 4 en 4 noeuds.
Adapter lalgorithme prcdent cette conguration, quelle est la complexit de
la recherche ?
6. Gnraliser en supposant quil y a log
2
(n) niveaux. Montrer que la recherche peut
alors se faire en log
2
(n) comparaisons.
7. Quelle est le nombre de liens (pointeurs) ncessaire pour une telle liste log
2
(n)
niveaux ?
8. Expliquer pourquoi une telle structure nest pas pratique modier.
Pour pallier cet inconvnient, lide est de faire des noeuds avec un nombre ala-
toire de niveaux : un noeud aura une probabilit p (0 < p < 1) davoir un lien
au niveau 1, p
2
davoir en plus un lien au niveau 2, p
3
davoir en plus un lien au
niveau 3, etc.
Implmentation
9. On dnit un noeud de la faon suivante :
c l a s s Noeud {
publ i c :
i nt v ;
st d : : vect or <i nt > l i e ns ;
/ / . . .
} ;
283
B.14. Devoir surveill 2011 : nonc B. Examens
Dans liens [0] il y aura lindex du noeud suivant de niveau 0, lindex du noeud
suivant au niveau 1 dans liens [1] (si le noeud a le niveau au moins 1), etc. Ainsi
le noeud est prsent liens . size () niveaux.
Implmenter un constructeur pour cette classe, prenant la valeur v en paramtre
et ne crant aucun lien.
10. Voici la dclaration de la classe :
c l a s s Li st eAvecSaut s {
st d : : vect or <Noeud> noeuds ; / / Ensembl e de s noeuds
void precedent s ( i nt prec [ maxNiveau] , i nt v ) ;
publ i c :
Li st eAvecSaut s ( ) ;
void aj out e ( i nt v ) ;
bool r e t i r e ( i nt v ) ;
bool cherche ( i nt v ) ;
} ;
Les noeuds sont stocks dans un std :: vector. On mettra lindice 0 de ce vecteur
un noeud qui servira la fois de dbut et de n : il aura une valeur plus grande
que toutes les valeurs admissibles (mettons 10000) et il pointe initialement vers
lui-mme tous les niveaux, de 0 maxNiveau1, qui est une constante du pro-
gramme :
const i nt maxNiveau=5;
Ecrire le constructeur de la classe.
11. Ecrire la mthode ListeAvecSauts::cherche qui procde ainsi : elle part du niveau
le plus haut de noeuds[0].liens et avance tant que la valeur du noeud suivant est
strictement infrieure v. La recherche continue alors au niveau immdiatement
infrieur et ainsi de suite jusquau niveau 0. Il ne reste plus qu comparer la
valeur du noeud suivant celui o lon sest arrt.
Modication de la liste
12. Ecrire une fonction qui retourne un niveau alatoire entre 0 et maxNiveau1 : 1
ou plus avec probabilit p, 2 ou plus avec probabilit p
2
, etc.
13. Pour ajouter ou enlever un lment, il faut remplir la mthode ListeAvecSauts::precedents
qui retourne les indices de noeuds o la recherche sarrte chaque niveau. Ainsi
dans la Fig. B.11, precedents(12) retournerait les indices des noeuds de valeur
10 (niveau 0), 8 (niveau 1) et 3 (niveau 2). Il sagit donc juste dune variante de
cherche. Ecrire cette fonction.
14. Ecrire la fonction retire . On ne cherchera pas retirer llment de noeuds, car
cela modierait les indices. On accepte simplement de perdre cette case noeuds[i]
et de ne plus lutiliser par la suite.
NB : cette fonction renvoie false si la valeur nest pas prsente dans la liste.
15. Ecrire de mme la mthode ListeAvecSauts::ajoute qui cre un nouveau noeud
et cherche le placer dans la liste avec un nombre de niveaux tir alatoire-
ment (comme dcrit ci-dessus). Il sagit dappeler ListeAvecSauts::precedents et
de faire les connexions ncessaires.
284
B. Examens B.14. Devoir surveill 2011 : nonc
Complexit
16. Montrer que la profondeur moyenne (nombre de niveaux) dun noeud est 1/(1
p). Rappel (de probabilit) : cette esprance se calcule par la formule :
1Proba(profondeur = 1)+2Proba(profondeur = 2)+3Proba(profondeur = 3)+. . .
On supposera que la profondeur nest pas limite par maxNiveau et donc laisser
la somme aller linni pour simplier.
17. Discuter loccupation mmoire de la liste avec sauts compare une liste ordi-
naire pour p = 1/2 et p = 1/4.
18. Montrer que la complexit de recherche C(n) sur la liste est en moyenne O(log n).
On procdera de la faon suivante :
(a) Montrer quen moyenne les noeuds ayant un niveau suprieur 0 sont
distance 1/p.
(b) Montrer quau niveau 1, il y a environ np noeuds.
(c) Etablir la relation de rcurrence :
C(n) 1/p + C(np)
(d) Conclure que C(n) = O(log n), le facteur constant dpendant de la valeur de
p.
19. Montrer un exemple dutilisation de la structure pour un tri en O(nlog n).
20. Comparer une autre structure de donnes adapte au stockage dlments avec
recherche rapide.
21. Proposer, sans limplmenter, une petite modication la structure permettant
daccder en temps O(log n) au k-ime lment.
285
B.15. Devoir surveill 2010 : nonc B. Examens
B.15 Devoir surveill 2010 : nonc
B.15.1 Programmation : machine registres
Nous allons implmenter en C++ une machine dinformatique thorique, dite ma-
chine registres, les registres correspondant aux variables dont les valeurs possibles
sont les entiers naturels (on ne soccupera pas des problmes de borne), et possdant
un nombre trs restreint dinstructions. Un programme est une suite dinstructions nu-
mrotes partir de 0. Les registres sont galement numrots partir de 0, le registre
R
0
tant spcial car il indique si le programme doit continuer (valeur 1) ou sarrter
(valeur 0). Les instructions sont les suivantes :
1. incrmenter le registre i : R
i
R
i
+ 1.
2. dcrmenter le registre i : R
i
R
i
1.
3. goto conditionnel qui, si le registre R
i
est nul (valeur 0), fait passer linstruction
numro p et sinon continue linstruction suivante :
if R
i
= 0 goto p
4. instruction darrt halt qui en fait met le registre R
0
0.
Il est noter que cette machine est sufsante pour faire de nombreux calculs, pourvu
que le nombre de registres soit sufsant. Pour le voir, considrons que chaque registre
est un bit (valeur 0 ou 1) et regardons par exemple le programme faisant un ip de
R
1
:
0 if R[1]=0 goto 3
1 dec R[1]
2 if R[2]=0 goto 4
3 inc R[1]
4 halt
La ligne 2 effectue un goto inconditionnel en supposant que le test R
2
= 0 est
toujours vrai (mais on aurait pu aussi bien dans ce cas remplacer par un halt). La
programmation en C++ de cette machine registres est en annexe 12.
Questions
1. Ecrire un programme mettant dans R
1
le rsultat de laddition de R
1
et R
2
. Pour
cela, dcrmenter R
2
tout en incrmentant R
1
tant que cest possible. On pourra
utiliser le registre R
3
pour un goto inconditionnel si ncessaire. Attention : il sagit
dcrire ce programme dans le langage de la machine registres.
2. Ecrire en C++ une classe Etat qui contient le tableau des registres un instant
donn et le numro de la prochaine instruction excuter (nomm next et quon
pourra mettre dans la partie publique), ainsi que ses constructeur et destructeur.
Par dfaut, seul le registre R
0
est stock, mais dautres registres pourront tre
ajouts la demande.
3. Ajouter des mthodes get et set qui respectivement renvoie la valeur du re-
gistre numro i et laffecte une valeur v. La mthode get est paresseuse, dans
le sens o elle renvoie 0 pour les registres nayant jamais t initialiss, mais sans
ajouter un nouveau registre.
286
B. Examens B.15. Devoir surveill 2010 : nonc
4. Ajouter une mthode qui afche les registres (autres que R
0
).
5. Ecrire une classe Instruction avec un constructeur par dfaut (correspondant
au halt) et un constructeur prenant un identiant, un numero de registre (utilis
par inc et dec) et un numro dinstruction suivante p, utilis uniquement pour
le goto. Lidentiant prendra lune des valeurs suivantes :
const int ID_HALT=0, ID_INC=1, ID_DEC=2, ID_GOTO=3;
6. Ajouter une mthode execute Instruction qui prend une variable de type
Etat en entre et le modie en sortie.
7. Ajouter une mthode afchant linstruction.
8. Ecrire une classe Programme qui contient une suite dinstructions, vide par d-
faut, et un Etat.
9. Ecrire une mthode pour ajouter une instruction la n du programme.
10. Ajouter une mthode print qui afche le programme, avec la prochaine instruc-
tion excuter prcde dun >, et ltat des registres (voir annexe 12).
11. Ajouter une mthode init qui met le registre i une valeur v.
12. Ajouter une mthode run qui excute le programme avec un appel print
aprs chaque instruction excute et qui sarrte aprs avoir excut linstruction
halt.
Annexe : exemple de programme ip
int main() {
Programme flip;
flip.ajoute( Instruction(ID_GOTO,1,3) );
flip.ajoute( Instruction(ID_DEC,1) );
flip.ajoute( Instruction(ID_GOTO,2,4) );
flip.ajoute( Instruction(ID_INC,1) );
flip.ajoute( Instruction(ID_HALT) );
std::cout << "flip 0 --> 1" << std::endl;
flip.init(1,0);
flip.run();
std::cout << "flip 1 --> 0" << std::endl;
flip.init(1,1);
flip.run();
return 0;
}
La sortie de ce programme est la suivante :
287
B.15. Devoir surveill 2010 : nonc B. Examens
flip 0 --> 1
[ 0 ]
> 0 if R[1]=0 goto 3
1 dec R[1]
2 if R[2]=0 goto 4
3 inc R[1]
4 halt
[ 0 ]
0 if R[1]=0 goto 3
1 dec R[1]
2 if R[2]=0 goto 4
> 3 inc R[1]
4 halt
[ 1 ]
0 if R[1]=0 goto 3
1 dec R[1]
2 if R[2]=0 goto 4
3 inc R[1]
> 4 halt
flip 1 --> 0
[ 1 ]
> 0 if R[1]=0 goto 3
1 dec R[1]
2 if R[2]=0 goto 4
3 inc R[1]
4 halt
[ 1 ]
0 if R[1]=0 goto 3
> 1 dec R[1]
2 if R[2]=0 goto 4
3 inc R[1]
4 halt
[ 0 ]
0 if R[1]=0 goto 3
1 dec R[1]
> 2 if R[2]=0 goto 4
3 inc R[1]
4 halt
[ 0 ]
0 if R[1]=0 goto 3
1 dec R[1]
2 if R[2]=0 goto 4
3 inc R[1]
> 4 halt
B.15.2 Algorithmique : ensemble sans doublon
On se propose de programmer un ensemble dlments au sens mathmatique,
cest--dire que les doublons (valeurs rptes) sont interdits. Les lments seront
du type Element dont la dnition exacte importe peu (cela pourrait tre un
argument template). Les lments sont stocks dans une classe Ensemble dont
voici une partie de linterface :
class Ensemble {
public:
Ensemble();
Ensemble(const Ensemble& e); // Constructeur de copie
int taille() const; // Nombre delements
Element opertor[](int i) const; // Element numero i (0<=i<=taille()-1)
void insere(int i, const Element& e);
void ajoute(const Element& e); // Raccourci pour insere(taille(),e)
...
};
13. Ecrire une fonction retournant lensemble union de deux Ensemble passs en
arguments.
14. Quelle est sa complexit en fonction des tailles m et n des ensembles ?
On suppose dans la suite quil existe une relation dordre stricte entre lments :
bool operator<(const Element& e1, const Element& e2);
et que les lments sont tris par ordre croissant au sein de lEnsemble.
15. Ecrire une fonction retournant lensemble union u de deux Ensemble passs en
arguments, e1 et e2. Pour cela, on peut :
dabord copier e2 dans u;
puis chercher le premier lment de u non infrieur strictement e1[0], appelons-
le u[j];
288
B. Examens B.15. Devoir surveill 2010 : nonc
insrer e1[0] dans u lindice j sil ne fait pas doublon;
faire de mme pour e1[1], sachant quil suft de parcourir u seulement
partir de lindice j+1;
continuer ainsi jusqu arriver au bout de u ou e1;
si on sest arrt par puisement de u, ajouter les lments restants de e1.
16. Quelle est sa complexit si tous les lments de e2 sont infrieurs ceux de e1?
17. Quelle est sa complexit si tous les lments de e1 sont infrieurs ceux de e2?
18. Quelle est sa pire complexit en fonction des tailles m et n des ensembles ? Pour
le voir, on pourra noter n
0
le nombre dlments de e2 infrieurs e1[0], n
i
entre e1[i-1] et e1[i] (i {1 . . . m 1}), n
m
ceux suprieurs e1[m-1]. On
regardera ce qui se passe suivant que n
m
est nul ou non.
289
B.16. Devoir surveill 2009: nonc B. Examens
B.16 Devoir surveill 2009 : nonc
B.16.1 Quafche ce programme ?
1. Examinez bien le contenu du programme suivant. La question est simple : quelles
sont les diffrentes lignes afches sur la sortie standard (cest--dire en console,
via les instructions cout << ... ;) au cours de son excution? Procdez
avec mthode en faisant attention aux retours de fonction par valeurs, et lqui-
libre ncessaire entre appels aux constructeurs/destructeurs. Justiez vos r-
ponses.
1 #include <iostream>
2 #include <algorithm> // Pour la fonction max
3 using namespace std;
4
5 const int maxDegre = 10;
6
7 class Polynome {
8 int deg;
9 float t[maxDegre+1];
10 void recalc_deg();
11 public:
12 Polynome();
13 Polynome(float a);
14 Polynome(float a, float b);
15 Polynome(int d, float
*
tab);
16 ~Polynome();
17
18 bool est_nul() const;
19 void set_coeff(int i, float a);
20 float evalue(float x) const;
21 void affiche() const;
22 Polynome operator+(const Polynome& P) const;
23 Polynome operator-(const Polynome& P) const;
24 };
25
26 void Polynome::recalc_deg() {
27 while(deg>=1 && t[deg]==0.0f)
28 --deg;
29 }
30
31 void Polynome::set_coeff(int i, float a) {
32 t[i] = a;
33 if(i > deg)
34 deg = i;
35 recalc_deg();
36 }
37
38 bool Polynome::est_nul() const {
290
B. Examens B.16. Devoir surveill 2009: nonc
39 return (deg==0 && t[0]==0.0f);
40 }
41
42 Polynome::Polynome() {
43 deg = 0;
44 t[0] = 0.0f;
45 cout << "C0: ";
46 affiche();
47 }
48
49 Polynome::Polynome(float a) {
50 deg = 0;
51 t[0] = a;
52 cout << "C1: ";
53 affiche();
54 }
55
56 Polynome::Polynome(float a, float b) {
57 deg = 1;
58 t[0] = b;
59 t[1] = a;
60 cout << "C2: ";
61 affiche();
62 }
63
64 Polynome::Polynome(int d, float
*
tab) {
65 deg = d;
66 for(int i=0; i<=d; i++) {
67 t[i] = tab[d-i];
68 }
69 cout << "C3: ";
70 affiche();
71 }
72
73 Polynome::~Polynome() {
74 cout << "D: ";
75 affiche();
76 }
77
78 float Polynome::evalue(float x) const {
79 float xn=1.0f, v=0.0f;
80 for(int i=0; i<=deg; i++) {
81 v += t[i]
*
xn;
82 xn
*
= x;
83 }
84 return v;
85 }
86
87 void Polynome::affiche() const {
291
B.16. Devoir surveill 2009: nonc B. Examens
88 for(int i=deg; i>=0; i--) {
89 if(t[i] >= 0)
90 cout << "+";
91 cout << t[i] << "X" << i << " ";
92 }
93 cout << endl;
94 }
95
96 Polynome Polynome::operator+(const Polynome& P) const {
97 Polynome Q;
98 Q.deg = max(deg,P.deg);
99 for(int i=0; i <=Q.deg; i++) {
100 float a=0.0f, b=0.0f;
101 if(i <= deg) a = t[i];
102 if(i <= P.deg) b = P.t[i];
103 Q.t[i] = a+b;
104 }
105 Q.recalc_deg();
106 cout << "op+" << endl;
107 return Q;
108 }
109
110 Polynome Polynome::operator-(const Polynome& P) const {
111 Polynome Q;
112 Q.deg = max(deg,P.deg);
113 for(int i=0; i <=Q.deg; i++) {
114 float a=0.0f, b=0.0f;
115 if(i <= deg) a = t[i];
116 if(i <= P.deg) b = P.t[i];
117 Q.t[i] = a-b;
118 }
119 Q.recalc_deg();
120 cout << "op-" << endl;
121 return Q;
122 }
123
124 int main() {
125 float p1[] = {1.0f, 3.0f, 3.0f};
126 Polynome P(2,p1);
127 cout << "P= ";
128 P.affiche();
129 cout << "P(-2)=" << P.evalue(-2.0f) << endl;
130 Polynome Q(2.0f,-1.0f);
131 cout << "Q= ";
132 Q.affiche();
133 Polynome R = P+Q;
134 cout << "R= ";
135 R.affiche();
136 R = R-P;
292
B. Examens B.16. Devoir surveill 2009 : nonc
137 cout << "R= ";
138 R.affiche();
139 return 0;
140 }
B.16.2 Programmation : enrichir la classe polynme
2. Ecrire une classe monme (aX
k
) avec un constructeur prenant comme paramtres
a et k.
3. Ecrire loprateur de multiplication dun polynme et dun monme.
4. Ajouter loprateur % : P%Q est le reste de la division euclidenne de P par Q.
Cest un polynme dont le degr est strictement infrieur celui de Q. Pour cela,
retirer de P le produit de Q par un monme bien choisi de manire annuler son
coefcient de plus haut degr. Recommencer cette opration tant que le degr de
P est au moins aussi grand que celui de Q.
5. Programmer le PGCD de deux polynmes par lalgorithme dEuclide : partant de
lobservation que le PGCD de P et Q est aussi celui de Q et Q%P, on itre ces restes
de divisions euclidiennes jusqu obtenir un polynme R et le polynme 0. R est
alors le PGCD recherch.
B.16.3 Algorithmie : problme de slection
On sintresse au problme de la recherche du kime plus petit lment parmi
un ensemble de n lments, t[0] . . . t[n 1]. Par exemple, pour k = 0 il sagit du
minimum, pour k = n 1 du maximum et pour k = n/2 du mdian.
6. Ecrire une fonction qui nen appelle aucune autre et qui calcule cette valeur. Pour
cela, chercher le minimum, puis le deuxime minimum, etc. On prendra alors
garde au cas o plusieurs lments de t ont mme valeur.
7. Quelle est la complexit de lalgorithme ci-dessus ?
8. Proposer sans lcrire une mthode de complexit moyenne O(nlog n).
9. Supposant la fonction pivot de QuickSort disponible, adapter QuickSort de ma-
nire ne trier que le sous-tableau contenant le kime.
10. Ecrire une relation de rcurrence concernant la complexit moyenne de cet algo-
rithme.
11. Montrer que cet algorithme a une complexit moyenne en O(n).
12. Montrer quune telle complexit est optimale.
293
B.17. Devoir surveill 2008: nonc B. Examens
B.17 Devoir surveill 2008 : nonc
B.17.1 Erreurs
Dans chacun des programmes ou passages de programmes suivants, notre pro-
grammeur utilise (ou devrait utiliser) un concept particulier du C++. Malheureuse-
ment, il commet chaque fois une ou plusieurs erreurs. A vous de comprendre ce quil
a voulu faire et de proposer une version exacte de son programme. Les ... repr-
sentent des passages inutiles la comprhension quil ne vous est pas demand de
complter.
1. Variables
double a=...;
double b=...;
if (a<b) {
int min=a;
} else {
min=b;
}
double c=3
*
min+15;
2. Fonctions
void solve(double a,double b,double c) {
delta(double a,b,c) {
return b
*
b-4
*
a
*
c;
}
double d=delta(a,b,c);
if (d>0) {
...
} else if (d==0)
...
else
...
}
3. Tableaux
int f() {
int t[10];
for (int i=1;i<=10;i++)
t(i)=...;
return t;
}
4. Rfrences
solve(double a,double b,double c) {
double d=delta(a,b,c);
int n;
double x1,x2;
294
B. Examens B.17. Devoir surveill 2008: nonc
if (d>0) {
n=2;
x1=-b+sqrt(d)/(2
*
a);
x2=-b-sqrt(d)/(2
*
a);
} else if (d==0) {
n=1;
x1=-b/(2
*
a);
} else
n=0;
return (n,x1,x2);
}
5. Rcursivit
double dichotomie(double a,double b) {
double c=(a+b)/2;
if (f(a)
*
f(c)>0)
dichotomie(c,b);
else
dichotomie(a,c);
}
6. Boucles
double dichotomie(double a,double b) {
until (b-a<1e-5) {
double c=(a+b)/2;
if (f(a)
*
f(c)>0)
b=c;
else
a=c;
}
return c;
}
7. Tests
...
int t[10];
do {
change(t);
} while ( for (int i=0;i<10;i++) mauvais(t[i]); )
...
8. Allocation dynamique
void f(int n) {
int t[n];
remplit(t,n);
295
B.17. Devoir surveill 2008 : nonc B. Examens
affiche(t,n);
}
9. Objets
class A {
int f(int x);
}
int f(int x) {
return 2
*
x;
}
void g() {
A a;
int b=a.f(2);
}
10. Constructeurs
class equipe {
int n;
string
*
noms;
public:
equipe();
equipe(int nb);
~equipe();
void print();
};
equipe::equipe() {
}
equipe::equipe(int nb) {
noms=new string[n];
}
equipe::~equipe() {
delete[] noms;
}
void equipe::print() {
for (int i=1;i<=n;i++)
cout << noms[i] << endl;
}
B.17.2 Problme
1. Etant donns :
deux entiers constants N et M
un tableau bi-dimensionnel de lettres char grille[N][N] reprsentant une
grille de jeu
un tableau mono-dimensionnel de lettres char mot[M] reprsentant un mot
296
B. Examens B.17. Devoir surveill 2008 : nonc
crire une fonction qui cherche partout dans la grille si le mot est crit horizonta-
lement de gauche droite et qui afche les coordonnes correspondantes.
2. Amliorer la fonction pour quelle cherche le mot horizontalement, verticalement
et en diagonale dans tous les sens, soit huit directions au total. (NB : il ne sagit
pas de multiplier par 8 la longueur de la rponse la question prcdente ! A titre
indicatif, une solution simple prend une trentaine de lignes).
3. Amliorer la fonction pour quelle accepte un mot de taille variable.
297
B.18. Devoir surveill 2007: nonc B. Examens
B.18 Devoir surveill 2007 : nonc
B.18.1 Groupes
Le programme suivant afche
====
Tous
====
Aarabi Sarah : 21 ans
Adamjy Inssia : 20 ans
Arlaud Jules : 22 ans
Aroles Jeremy : 22 ans
Bairi Iken : 23 ans
Baumhauer Oriane : 23 ans
Begon-Lours Clotilde : 22 ans
Bellakrid Amine : 24 ans
Benchimol Mike : 20 ans
Kharoub Amine : 25 ans
==========
Ont 22 ans
==========
Arlaud Jules : 22 ans
Aroles Jeremy : 22 ans
Begon-Lours Clotilde : 22 ans
==========
Se prenomment Amine
==========
Bellakrid Amine : 24 ans
Kharoub Amine : 25 ans
(NB : les ges ne sont pas exacts !).
Il manque les mthodes des objets. Dnissez-les !
1 #include <string>
2 #include<iostream>
3 using namespace std;
4
5 //====================================
6 class personne {
7 string N,P;
8 int A;
9 public:
10 personne();
11 personne(string n,string P,int a);
12 string nom() const;
13 string prnom() const;
14 int age() const;
15 };
298
B. Examens B.18. Devoir surveill 2007 : nonc
16
17 //========================================
18 class groupe {
19 personne
*
t;
20 int n;
21 public:
22 groupe();
23 groupe(const groupe& g);
24 void operator=(const groupe& g);
25 ~groupe();
26 void ajouter(personne p);
27 void affiche() const;
28 groupe agsDe(int a) const;
29 groupe prnomms(string p) const;
30 };
31
32 //=============================================================
33
34 ............ ici, les mthodes de personne et de groupe!
35
36 //=============================================
37 int main()
38 {
39 groupe g;
40
41 g.ajouter(personne("Aarabi","Sarah",21));
42 g.ajouter(personne("Adamjy","Inssia",20));
43 g.ajouter(personne("Arlaud","Jules",22));
44 g.ajouter(personne("Aroles","Jeremy",22));
45 g.ajouter(personne("Bairi","Iken",23));
46 g.ajouter(personne("Baumhauer","Oriane",23));
47 g.ajouter(personne("Begon-Lours","Clotilde",22));
48 g.ajouter(personne("Bellakrid","Amine",24));
49 g.ajouter(personne("Benchimol","Mike",20));
50 g.ajouter(personne("Kharoub","Amine",25));
51 cout << "====" << endl << "Tous" << endl << "====" << endl;
52 g.affiche();
53
54 groupe g2;
55 g2=g.agsDe(22);
56 cout << "==========" << endl << "Ont 22 ans" << endl << "==========" << endl;
57 g2.affiche();
58
59 cout << "==========" << endl << "Se prenomment Amine" << endl << "==========" << endl;
60 g.prnomms("Amine").affiche();
61
62 return 0;
63 }
299
B.18. Devoir surveill 2007 : nonc B. Examens
B.18.2 Anniversaires
Il est connu que sur une classe de 23 lves, il y a une chance sur 2 pour que deux
lves au moins soient ns le mme jour. crire un programme
qui tire au hasard le jour de naissance de N personnes,
qui vrie sil en existe au moins deux nes le mme jour,
et qui recommence un grand nombre de fois pour estimer la probabilit que ce
phnomne se produise.
Modier le programme pour estimer cette probabilit pour N allant de 2 30.
Voici, pour information, ce quon trouve :
2 eleves. Frequence: 0.00272
3 eleves. Frequence: 0.008289
4 eleves. Frequence: 0.016509
5 eleves. Frequence: 0.026964
6 eleves. Frequence: 0.040578
7 eleves. Frequence: 0.0559
8 eleves. Frequence: 0.074285
9 eleves. Frequence: 0.094771
10 eleves. Frequence: 0.117261
11 eleves. Frequence: 0.141013
12 eleves. Frequence: 0.167189
13 eleves. Frequence: 0.195052
14 eleves. Frequence: 0.222897
15 eleves. Frequence: 0.253055
16 eleves. Frequence: 0.28374
17 eleves. Frequence: 0.314569
18 eleves. Frequence: 0.346247
19 eleves. Frequence: 0.379274
20 eleves. Frequence: 0.411193
21 eleves. Frequence: 0.443089
22 eleves. Frequence: 0.476296
23 eleves. Frequence: 0.508387
24 eleves. Frequence: 0.536925
25 eleves. Frequence: 0.568921
26 eleves. Frequence: 0.598471
27 eleves. Frequence: 0.626731
28 eleves. Frequence: 0.653526
29 eleves. Frequence: 0.68141
30 eleves. Frequence: 0.705967
300
B. Examens B.19. Devoir surveill 2006: nonc
B.19 Devoir surveill 2006 : nonc
B.19.1 Erreurs corriger
Corrigez les erreurs dans le programme suivant. Cherchez bien : il y en a 23
1 int dmax=10;
2 class polynom {
3 double coef[dmax];
4 int deg;
5 void updateDegree() const;
6 public:
7 polynom() {
8 deg=0;
9 coef[0]=0;
10 }
11 void set(int d,double
*
c);
12 void print() const;
13 polynom derivate() const;
14 polynom integrate() const;
15 void op-(const polynom& Q) const;
16 }
17
18 void polynom::set(int d,double
*
c) {
19 deg=d;
20 for (int i=1;i<=d+1;i++)
21 coef[i]=c[i];
22 }
23
24 void polynom::print() const {
25 for (int i=deg;i>=0;i++) {
26 if (i<deg & coef[i]>=0)
27 cout<<+;
28 cout << coef[i] << "
*
x^"<<i;
29 }
30 }
31
32 polynom derivate(){
33 polynom D;
34 if (deg>0) {
35 D.deg=deg-1;
36 for (int i=0,i<deg,i++)
37 D.coef[i]=(i+1)
*
coef[i+1];
38 }
39 }
40
41 polynom polynom::integrate(){
42 polynom I;
43 I.deg=deg+1;
44 for (int i=1;i<=deg+1;i++)
301
B.19. Devoir surveill 2006: nonc B. Examens
45 I.coef[i]=coef[i-1]/i;
46 return I;
47 }
48
49 int polynom::updateDegree() {
50 for (int i=deg;i>=1;i--)
51 if (coef[i]==0)
52 deg=i-1;
53 }
54
55 polynom polynom::op-(const polynom& Q) const {
56 polynom P;
57 P.deg=max(deg,Q.deg);
58 for (int i=0;i<=P.deg;i++) {
59 double c1,c2;
60 if (i>deg) c1=0 else c1=coef[i];
61 if (i>Q.deg) c2=0 else c2=Q.coef[i];
62 P.coef[i]=c1-c2;
63 }
64 P.updateDegree;
65 return P;
66 }
67
68 int main() {
69 polynom P;
70 int t[4]={5,2,3,4};
71 P.set(3,t);
72 polynom Q;
73 Q=P.derivate();
74 polynom R;
75 R=Q.integrate();
76 S=P-R;
77 cout << "P=" ; P.print; cout << endl;
78 cout << "Q=" ; Q.print; cout << endl;
79 cout << "R=" ; R.print; cout << endl;
80 cout << "S=" ; S.print; cout << endl;
81 }
B.19.2 Quafche ce programme ?
Examinez bien le contenu du programme suivant. La question est simple : quelles
sont les diffrentes lignes afches sur la sortie standard (cest--dire en console, via les
instructions cout << ... ;) au cours de son excution? Procdez avec mthode
en faisant attention aux retours de fonction par valeurs, et lquilibre ncessaire entre
appels aux constructeurs/destructeurs. Justiez vos rponses.
1 #include <iostream>
2 #include <cmath>
3 using namespace std;
302
B. Examens B.19. Devoir surveill 2006: nonc
4
5 int number_of_points;
6
7 class Point3{
8 int which_point;
9 int X,Y,Z;
10
11 void init(int _x=0, int _y=0, int _z=0){
12 which_point = number_of_points++;
13 X=_x; Y=_y; Z=_z;
14 }
15 void print(){
16 cout << " Point #" << which_point ;
17 cout << " [ " << X << ", " << Y << ", " << Z << "]" << endl;
18 }
19
20 public:
21
22 Point3(){
23 cout << "Constructor #0: " ;
24 init();
25 print();
26 }
27 Point3(int _x, int _y, int _z){
28 cout << "Constructor #1: ";
29 init(_x,_y,_z);
30 print();
31 }
32 Point3(const Point3 &pt){
33 cout << "Constructor #2: ";
34 init(pt.X,pt.Y,pt.Z);
35 print();
36 }
37 ~Point3(){
38 cout << "Destructor: " ;
39 print();
40 number_of_points--;
41 }
42
43 Point3 operator+(Point3 pt){
44 cout << "Dans operator+ :" ; print();
45 Point3 tmp(X + pt.X , Y + pt.Y , Z + pt.Z);
46 cout << "Fin operator+ " <<endl;
47 return tmp;
48 }
49 const Point3& operator=(const Point3 &pt){
50 cout << "Dans operator= :" ; print();
51 X=pt.X; Y=pt.Y; Z=pt.Z;
52 cout << "Fin operator= :" ; print();
303
B.19. Devoir surveill 2006: nonc B. Examens
53 return pt;
54 }
55 };
56
57 int main()
58 {
59 number_of_points = 0 ;
60 cout << number_of_points << endl;
61 Point3 PTS[2];
62 cout << number_of_points << endl;
63 PTS[0] = Point3(1,2,3);
64 cout << number_of_points << endl;
65 Point3 PT(3,2,1);
66 PTS[1] = PTS[0] + PT;
67 cout << number_of_points << endl;
68 return 0;
69 }
B.19.3 Tableau dexcution
Remplir le tableau dexcution du programme suivant : le tableau dexcution est
fourni en annexe.
1 #include <iostream>
2 using namespace std;
3
4 void initClasse(int
*
classe , bool
*
bienHabilles, int nbEleves)
5 {
6 int identifiant_eleve;
7
8 for ( int i = 0 ; i < nbEleves ; i++ )
9 {
10 identifiant_eleve = i
*
2;
11 classe[i] = identifiant_eleve;
12 if( i%2 == 0 )
13 bienHabilles[i] = false;
14 else
15 bienHabilles[i] = true;
16 }
17 }
18
19 bool tousBienHabilles(bool
*
bienHabilles, int nbEleves)
20 {
21 bool ok = true;
22 for ( int i = 0 ; i < nbEleves ; i++ )
23 {
24 if( !bienHabilles[i] )
25 return false;
26 }
304
B. Examens B.19. Devoir surveill 2006 : nonc
27
28 nbEleves = 2;
29 return ok;
30 nbEleves = 1;
31 }
32
33 void PrendreLaPhoto(int & nbEleves)
34 {
35 nbEleves--;
36
37 int &n = nbEleves;
38 for (int i = 0 ; i < nbEleves ; i++ )
39 cout << "Eleve " << i << " dit : cheese" << endl;
40 cout << "Photographe dit : souriez ... Click Clack, merci ... " << endl;
41
42 n++ ;
43 }
44
45
46 int main()
47 {
48
49 int nbEleves = 2;
50 int
*
classe = new int[nbEleves];
51 int
*
copieDeClasse = classe;
52 bool
*
bienHabilles = new bool [nbEleves];
53
54 initClasse(classe,bienHabilles,nbEleves);
55
56 for (int i = 0 ; i < nbEleves ; i++ )
57 copieDeClasse[i] =classe[i] ;
58
59 bienHabilles[0] = true;
60
61 if( tousBienHabilles(bienHabilles,nbEleves ) )
62 PrendreLaPhoto(nbEleves);
63
64 delete[] bienHabilles;
65 delete[] classe;
66
67 return 0;
68 }
Il sagit dcrire, si elles existent, les valeurs des variables du programme pour
chaque excution de ligne.
Conventions :
mettre le numro de la ligne quon vient dexcuter (ventuellement, on peut
dcouper lexcution dune mme ligne en plusieurs tapes) ;
305
B.19. Devoir surveill 2006 : nonc B. Examens
laisser en blanc les variables non existantes ;
mettre un point dinterrogation pour les variables dclares non initialises ;
pour une variable qui nest autre quune rfrence sur une autre variable x, on
indiquera [x] ; mme chose si deux pointeurs adressent le mme espace m
moire
on peut utiliser le symbole pour rpter la valeur dune variable la ligne sui-
vante ;
pour gagner de la place dans le tableau, les noms des variables nont t indexs
que par la premire lettre du nom de la fonction laquelle elles sont rattaches,
suivie le cas chant du numro dappel la fonction. De mme, le retour dune
fonction f a pour nom ret
f
.
dans le cas dun tableau, on indiquera les valeurs prises dans tout le tableau dans
une seule cellule du tableau dexcution. Par exemple, si on a int tab[2] = {4,6} ;,
on indiquera le contenu de tab par : 4,6 dans la cellule correspondante du tableau
dexcution.
dans le cas des boucles for, il faudra mettre en vidence chaque passage. Ne pas
oublier les variables compteurs
B.19.4 Huit dames
FIGURE B.13 Une solution du problme des huit dames
Le but de cet exercice est dcrire un programme capable de gnrer toutes les so-
lutions du problme des 8 dames. Il sagit de poser huit dames dun jeu dchecs sur
un chiquier de 88 cases sans que les dames ne puissent se menacer mutuellement,
conformment aux rgles du jeu dchecs. Par consquent, deux dames ne doivent
jamais partager la mme range, colonne, ou diagonale. Une solution possible est re-
prsente gure B.13. On demande de fournir les programmes correspondant trois
solutions successives. Programmez bien de faon progressive, en dcoupant en fonc-
tions, etc. Mme sil vaut habituellement 8, mettez le nombre N de dames (et donc la
taille de lchiquier en paramtre constant au dbut du programme).
1. Solution 1 :
Une conguration, cest--dire les positions des huit dames, est mmorise
sous forme dun tableau de coordonnes.
crire une fonction qui afche une conguration.
crire une fonction rcursive qui gnre toutes les congurations possibles
(sans tenir compte des menaces !)
306
B. Examens B.19. Devoir surveill 2006 : nonc
crire une fonction qui vrie pour une conguration donne quil sagit dune
solution, cest--dire que les dames ne se menacent pas.
Complter la fonction de gnration pour afcher les solutions.
Combien explore ton de congurations ? Est-ce beaucoup pour un ordinateur
quand N = 8 ?
2. Solution 2 :
An de limiter le nombre de congurations explores, modier la solution pr-
cdente pour vrier, au moment de placer un dame, quelle nest pas en prise
avec celles qui sont dj poses.
3. Solution 3 :
Protant du fait quil y a exactement une dame par colonne, changer la faon
de reprsenter une solution.
Changer en consquence la faon de gnrer les congurations. Combien y-a-
til maintenant de congurations possibles ?
Pour acclrer les tests, il est astucieux de mmoriser pour chaque ligne et
chaque diagonale si celle-ci est dj "occupe" par une dame prcdemment
pose. Mettre en oeuvre cette solution.
4. NB : les meilleures solutions algorithmiques actuelles arrivent rsoudre le pro-
blme avec N = 1000000 en trs peu dtapes !
307
B.20. Devoir surveill 2005: nonc B. Examens
B.20 Devoir surveill 2005 : nonc
B.20.1 Erreurs corriger
Corriger le code fourni en annexe : effectuer les corrections directement sur le
script. Conseil : il y a une vingtaine derreurs.
B.20.2 Quafche ce programme ?
Examinez bien le contenu du programme suivant. La question est simple : quelles
sont les diffrentes lignes afches sur la sortie standard (cest--dire en console, via les
instructions cout << ... ;) au cours de son excution? Procdez avec mthode
en faisant attention aux retours de fonction par valeurs, et lquilibre ncessaire entre
appels aux constructeurs/destructeurs. Justiez vos rponses.
1 #include <iostream>
2 #include <cmath>
3 using namespace std;
4
5 class Complexe{
6 double m_Re, m_Im;
7 public:
8 Complexe();
9 Complexe(double re, double im);
10 Complexe(const Complexe & c);
11 ~Complexe();
12 void operator= (const Complexe & c);
13 const Complexe operator
*
(const Complexe & c) const;
14 void conjugue();
15 double norme() const;
16 void print() const;
17 };
18
19 Complexe::Complexe(){
20 cout << "Constructeur : vide" << endl;
21 }
22
23 Complexe::Complexe(double re, double im){
24 m_Re = re; m_Im = im;
25 cout << "Constructeur : ";
26 print();
27 }
28
29 Complexe::Complexe(const Complexe & c){
30 m_Re = c.m_Re; m_Im = c.m_Im;
31 cout << "Constructeur Copie : ";
32 print();
33 }
34
308
B. Examens B.20. Devoir surveill 2005: nonc
35 Complexe::~Complexe(){
36 cout << "Destructeur : ";
37 print();
38 }
39
40 void Complexe::operator= (const Complexe & c){
41 cout << "dans op= : " ;
42 m_Re = c.m_Re; m_Im = c.m_Im;
43 print();
44 }
45
46 const Complexe Complexe::operator
*
(const Complexe & c) const{
47 cout << "dans op
*
: " << endl;
48 Complexe result(c.m_Re
*
m_Re-c.m_Im
*
m_Im,c.m_Re
*
m_Im+c.m_Im
*
m_Re);
49 cout << "fin op
*
." << endl;
50 return( result );
51 }
52
53 void Complexe::conjugue (){
54 cout << "dans conjugue : ";
55 m_Im = -m_Im;
56 print();
57 }
58
59 double Complexe::norme() const{
60 cout << "dans norme : " << endl;
61 Complexe c(m_Re,m_Im);
62 c.conjugue();
63 c = operator
*
(c);
64 cout << "fin norme. " << endl;
65 return( sqrt(c.m_Re) );
66 }
67
68 void Complexe::print() const{
69 cout << m_Re << " + I
*
" << m_Im << endl;
70 }
71
72 int main(){
73 cout << "1" << endl;
74 Complexe c1(3,4);
75 Complexe c2(0,1);
76 cout << "2" << endl;
77 Complexe c3 = c1;
78 cout << "3" << endl;
79 c2 = (c1
*
c2);
80 cout << "4" << endl;
81 double d = c1.norme();
82 cout << "norme de c1 : " << d << endl;
83 cout << "5" << endl;
309
B.20. Devoir surveill 2005 : nonc B. Examens
84 return 0;
85 }
B.20.3 Tableau dexcution
Remplir le tableau dexcution du programme suivant : le tableau dexcution est
fourni en annexe.
1 int U(int &n)
2 {
3 n += 1;
4 return V(n)-5;
5 }
6
7 int V(int n)
8 {
9 if (n == 4 || n == 16)
10 return -1;
11
12 int tmp;
13 n = n+2;
14 tmp = U(n);
15 return tmp + n;
16 }
17
18 int setValueToTwelve(int a)
19 {
20 a = 12;
21 return a;
22 }
23
24 int main()
25 {
26 int a = 0 ;
27 int fin;
28
29 fin = setValueToTwelve(a);
30 fin = U(a);
31
32 if(fin-7)
33 a = 12;
34 else if(fin+7)
35 a = 0;
36 else
37 a = 4;
38
39 return 0;
40 }
310
B. Examens B.20. Devoir surveill 2005 : nonc
Il sagit dcrire, si elles existent, les valeurs des variables du programme pour
chaque excution de ligne.
Conventions :
mettre le numro de la ligne quon vient dexcuter (ventuellement, on peut
dcouper lexcution dune mme ligne en plusieurs tapes) ;
laisser en blanc les variables non existantes ;
mettre un point dinterrogation pour les variables dclares non initialises ;
pour une variable qui nest autre quune rfrence sur une autre variable x, on
indiquera [x] ;
on peut utiliser le symbole pour rpter la valeur dune variable la ligne sui-
vante ;
pour gagner de la place dans le tableau, les noms des variables nont t indexs
que par la premire lettre du nom de la fonction laquelle elles sont rattaches,
suivie le cas chant du numro dappel la fonction. De mme, le retour de la
fonction f a pour nom ret
f
.
B.20.4 Rsolveur de Sudoku
Le but de cet exercice est dcrire un programme capable de rsoudre le problme
du Sudoku dont on rappelle les rgles :
une grille 9 9 partiellement remplie est donne, chaque case de cette grille doit
contenir un entier de 1 9
il faut complter la grille en respectant les trois rgles suivantes :
dans une mme ligne, ne peuvent apparatre quune seule fois les entiers de 1
9,
dans une mme colonne, ne peuvent apparatre quune seule fois les entiers de
1 9,
dans une mme rgion, ne peuvent apparatre quune seule fois les entiers de
1 9 : une rgion est lun des neuf blocs 3 3 qui constituent la grille.
Dans la suite du problme, on considre la structure suivante :
1 struct Grille {
2 int valeur[9][9];
3 bool indice[9][9];
4 };
qui indique, pour chacune des 81 cases de la grille, sa valeur (un entier entre 1 et 9 ou
bien 0 si la case na pas de valeur) et si la case en question fait partie des indices (sa
valeur est xe).
1. Dnir une fonction de prototype void affiche_grille(const Grille& g)
qui afche une grille (avec cout comme droite de FIG. B.14 ) : si, en une case
de la grille, il ny a pas encore de valeur affecte, un caractre X est afch la
place.
2. crire une fonction Grille lit_grille(string l[9]) qui lit une grille en
entre (un caractre aprs lautre, ligne par ligne). Chaque string du tableau
pass en paramtre reprsente une ligne de la grille. Si s est lune de ces lignes,
alors :
311
B.20. Devoir surveill 2005 : nonc B. Examens
4 3
6 8
1
5 9
8 6
7 2
1 2 7
5 3 4
9
4 X X X 3 X X X X
X X X 6 X X 8 X X
X X X X X X X X 1
X X X 6 X X X 9 X
X 8 X X X X 6 X X
X 7 X 2 X X X X X
X X X 1 X 2 7 X X
5 X 3 X X X X 4 X
9 X X X X X X X X
FIGURE B.14 Exemple de grille
4 6 8 9 3 1 5 2 7
7 5 1 6 2 4 8 3 9
3 9 2 5 7 8 4 6 1
1 3 4 7 5 6 2 9 8
2 8 9 4 1 3 6 7 5
6 7 5 2 8 9 3 1 4
8 4 6 1 9 2 7 5 3
5 1 3 8 6 7 9 4 2
9 2 7 3 4 5 1 8 6
FIGURE B.15 Solution correspondante
312
B. Examens B.20. Devoir surveill 2005 : nonc
s[i] est le i-me caractre de la ligne,
si s[i] est gal X alors la case est complter,
sinon, il sagit dun indice de valeur s[i] - 0.
3. Programmer une fonction bool verifie_case(const Grille& g, int i, int j)
qui indique si la valeur actuellement attribue la case (i, j) entre en conit avec
les autres cases valides de la ligne i, de la colonne j et de la rgion dans laquelle
se trouve la case.
4. Dnir une fonction de prototype bool case_suivante(const Grille& g, int& i, int& j)
qui passe dune case (i, j) dans la grille la suivante dans lordre lexigraphique
(la nouvelle case sera renvoye par rfrence) : les cases dindice sont sautes, et,
si il ny a pas de case suivante ((i, j) est la dernire case de la grille), alors false
est renvoy.
5. Programmer une fonction rcursive bool resout_grille(Grille& g, int i, int j),
qui va :
donner successivement la case (i, j) toutes les valeurs possibles,
tester chaque fois si la valeur entre en conit ou non avec le reste de la grille
dj remplie,
sil ny a pas de conit, sappeler rcursivement sur la case suivante (unique-
ment si la n de la grille na pas dj t atteinte).
Cette fonction renvoie true si la grille est soluble partir de la conguration
donne, et false sinon. Quel est lintrt de passer la structure Grille par rf-
rence ?
6. Dnir une fonction de prototype bool resout_grille(Grille& g) qui ap-
pelle la fonction prcdente avec la bonne position de dpart pour la rsolution.
7. Programmer la fonction int main() qui lit une grille ( dnir dans le code),
lafche, puis essaie de la rsoudre en afchant la solution sil y en a une ou bien
un message.
8. Lalgorithme propos ralise beaucoup de calculs inutiles et nexploite pas suf-
samment les indices. Suggrer des amliorations (ne pas les programmer !).
313
B.21. Devoir surveill 2004: nonc B. Examens
B.21 Devoir surveill 2004 : nonc
B.21.1 Erreurs
Corriger le code suivant : (effectuer les corrections directement sur le script en
annexe )
1 // fichier main.cpp
2 #include <win>
3
4 const int w;
5 const int h;
6
7 struct point
8 {
9 int x,y;
10 }
11
12 point operator+(point p1, point p2)
13 {
14 point p
15 p.x = p1.x+p2.x
16 p.y = p1.y+p2.y
17 }
18
19 class quadrilatere
20 {
21 point t[4];
22 quadrilatere(point pts[4]);
23 affiche(Color col=Black) const;
24 void translate(point v) const;
25 bool dans_la_fenetre();
26 }
27
28 quadrilatere::quadrilatere(point pts[4])
29 {
30 t=pts;
31 }
32
33 quadrilatere::affiche(Color col) const
34 {
35 for(int i=0;i<=4;i++)
36 {
37 DrawLine(t[i].x,t[i].y,t[(i+1)%4].x,t[(i+1)%4].y,col);
38 }
39 }
40
41 void quadrilatere::translate(point v) const
42 {
314
B. Examens B.21. Devoir surveill 2004: nonc
43 for(int i=0;i<4;i=i+1)
44 t[i]=t[i]+v;
45 }
46
47 bool quadrilatere::dans_la_fenetre()
48 {
49 bool in=false;
50 for(int i=0;(i<4) && in;i++)
51 {
52 if ((t[i].x<0) or (t[i].x>=w) or (t[i].y<0) or (t[i].y>=h))
53 then in=true;
54 }
55 return in;
56 }
57
58 int main()
59 {
60 OpenWindow(w,h);
61
62 quadrilatere Q;
63 Q(pts);
64
65 point pts[4];
66 pts={{10,10},{10,100},{100,100},{100,10}};
67
68 point v={1,2};
69
70 while(Q.dans_la_fenetre())
71 {
72 Q.affiche();
73 MilliSleep(10);
74 Q.affiche(White);
75 Q.translate(v);
76 }
77
78 delete [] Q.t;
79 Terminate();
80 return 0;
81 }
B.21.2 Quafche ce programme ?
Examinez bien le contenu du programme suivant. La question est simple : quelles
sont les diffrentes lignes afches sur la sortie standard (cest--dire en console, via les
instructions cout << ... ;) au cours de son excution? Justiez vos rponses.
1 #include <iostream>
2 using namespace std;
3
315
B.21. Devoir surveill 2004: nonc B. Examens
4 int NbPt;
5
6 void check() {
7 cout<<endl;
8 cout<<"n_points= "<<NbPt<<endl;
9 cout<<endl;
10 }
11
12
13 struct Point {
14 double x,y;
15
16 Point()
17 {
18 NbPt++;
19 x=y=0;
20 cout<<"Point: Void Cons"<<endl;
21 };
22
23 Point( const Point &model)
24 {
25 NbPt++;
26 x=model.x;
27 y=model.y;
28 cout<<"Point: Copy Cons"<<endl;
29 }
30
31 Point( const double &_x, const double &_y)
32 {
33 NbPt++;
34 x=_x; y=_y;
35 cout<<"Point: (x,y) Cons"<<endl;
36 }
37
38 ~Point()
39 {
40 NbPt--;
41 cout<<"Point: Dest"<<endl;
42 }
43
44 void display() const
45 {
46 cout<<"x= "<<x<<" y= "<<y<<endl;
47 }
48 };
49
50 void displayPoint ( Point T)
51 {
52 T.display();
316
B. Examens B.21. Devoir surveill 2004: nonc
53 }
54
55 void displayTriangle2 ( Point
*
T) {
56 cout<<"A"<<endl; T[0].display();
57 cout<<"B"<<endl; T[1].display();
58 cout<<"C"<<endl; T[2].display();
59 }
60
61 void displayTriangle1 ( Point
*
&T) {
62 cout<<"A"<<endl; displayPoint(T[0]);
63 cout<<"B"<<endl; displayPoint(T[1]);
64 cout<<"C"<<endl; displayPoint(T[2]);
65 }
66
67 void buildTriangleStatic ( Point
*
T, const double
*
array) {
68 for(int i=0;i<3;i++) {
69 T[i]=Point(array[2
*
i],array[2
*
i+1]);
70 }
71 }
72
73 Point
*
buildTriangleDynamic( const double
*
array) {
74 Point
*
T=new Point[3];
75 for(int i=0;i<3;i++) {
76 T[i]=Point(array[2
*
i],array[2
*
i+1]);
77 }
78 return T;
79 }
80
81 void destroyTriangleDynamic (Point
*
T) {
82 delete[] T;
83 }
84
85 int main()
86 {
87 NbPt=0;
88 const double d6_1[6]={1.1,2.2,3.3,-0.1,-0.2,-0.3};
89 const double d6_2[6]={1,1,2,2,3,3};
90
91 check();
92 Point
*
t1=buildTriangleDynamic(d6_1);
93 check();
94 Point t2[3];
95 check();
96 buildTriangleStatic(t2,d6_2);
97 check();
98
99 displayTriangle1(t1);
100 check();
101 displayTriangle2(t2);
317
B.21. Devoir surveill 2004 : nonc B. Examens
102 check();
103
104 destroyTriangleDynamic(t1);
105 check();
106 t1=t2;
107 check();
108 displayTriangle1(t1);
109 check();
110
111 return 0;
112 }
B.21.3 Chemins dans un graphe
FIGURE B.16 Chemins minimaux
On se propose de calculer les plus courts chemins dans un graphe par lalgorithme
de Floyd. Soient n villes et, pour 0 i < n et 0 j < n, C
ij
le cot du trajet de la ville i
vers la ville j (avec C
ii
= 0, C
ij
non ncessairement gal C
ji
, et ventuellement C
ij
=
si ce trajet nexiste pas). Le cot dun chemin i
1
, i
2
, ..., i
p
est la somme
p1
k=1
C
i
k
i
k+1
.
Pour trouver les cots de tous les chemins minimaux entre toutes les villes, il suft de
construire, pour 0 k < n, les matrices D
(k)
dnies par :
_
D
(0)
= C
D
(k)
ij
= min(D
(k1)
ij
, D
(k1)
ik
+ D
(k1)
kj
)
Le cot du chemin minimum entre i et j est alors D
(n1)
ij
(ventuellement si on ne
peut relier i j).
Questions
1. Dnir une matrice int C[n][n] reprsentant le graphe gure B.16 dans la-
quelle chaque che de i vers j reprsente un C
ij
2. Ecrire une fonction void floyd(const int C[n][n],int D[n][n]) cal-
culant D
(n1)
partir de C
3. Appeler cette fonction et afcher les cots des chemins minimaux pour tous les
(i, j).
318
B. Examens B.21. Devoir surveill 2004 : nonc
Chemins
Pour mmoriser les chemins et non plus seulement leur cot, il suft de rajouter
une matrice P correspondant aux prdcesseurs dans les chemins minimaux. Cette
matrice est dnie comme suit :
Initialement, P
ij
= i si i = j et C
ij
< , P
ij
= sinon.
Lorsque D
(k1)
ik
+ D
(k1)
kj
est retenu comme valeur de D
(k)
ij
, alors faire P
ij
= P
kj
Aprs quoi, le chemin minimal de i vers j est celui de i vers P
ij
, suivi du trajet P
ij
j.
1. Modier la fonction floyd pour quelle remplisse cette matrice P.
2. Ecrire une fonction rcursive void chemin(const int P[n][n],int i, int j)
afchant le chemin minimal de i vers j pour P donne.
3. Utiliser les deux fonctions prcdentes pour calculer et afcher tous les chemins
minimaux dans le graphe prcdent.
B.21.4 Tours de Hano
Principe et rgles
Le jeu est constitu de 3 tiges, A, B et C, sur lesquelles sont empils des anneaux de
taille dcroissante, que lon numrotera de N 1.
FIGURE B.17 Conguration initiale
Au dbut du jeu, tous les anneaux sont empils sur la tige A (voir gure B.17). Lob-
jectif est de transfrer tous les anneaux sur la tige C. Il nest possible de dplacer les
anneaux que un par un, et il nest pas possible de poser un anneau sur un autre de
taille infrieure.
On dsignera par le terme configuration une disposition des anneaux sur les
tiges (voir gure B.18).
FIGURE B.18 Exemple de conguration
319
B.21. Devoir surveill 2004 : nonc B. Examens
On dsignera par le terme dplacement de la tige X la tige Y le fait denlever
lanneau situ au sommet de la pile de la tige X pour le positionner au sommet de la
pile de la tige Y (voir gure B.19).
FIGURE B.19 Exemple de dplacement
Objectif
Lobjectif ici est dcrire un programme qui afche la suite des dplacements ra-
liser pour rsoudre le problme avec n anneaux, sous la forme suivante :
numero_anneau : tige_origine > tige_destination
On souhaite de plus afcher ltat du jeu (les anneaux prsents sur chaque tige) aprs
chaque dplacement.
Exemple pour 2 anneaux (la gure B.20 en donne une reprsentation graphique) :
A> 2 1
B> . .
C> . .
deplacement: 1 : A->B
A> 2 .
B> 1 .
C> . .
deplacement: 2 : A->C
A> . .
B> 1 .
C> 2 .
deplacement: 1 : B->C
A> . .
B> . .
C> 2 1
Ce problme apparemment complexe se traite en fait simplement : pour transfrer
n anneaux dune tige X une tige Y, il "suft" deffectuer :
le transfert des n-1 anneaux suprieurs de la tige X sur la troisime tige Z
le dplacement de lanneau n de la tige X la tige destination Y
le transfert des n-1 anneaux de la tige Z la tige Y
320
B. Examens B.21. Devoir surveill 2004 : nonc
FIGURE B.20 Solution du problme pour N=2
Pour transfrer n-1 anneaux, on applique la mme mthode : transfert de n-2 anneaux
de la tige origine une tige temporaire, dplacement dun anneau de la tige origine
la tige destination, transfert des n-2 anneaux de la tige temporaire la tige destination
...
Questions
1. Dclarer une constante N, que lon xera 10, et qui reprsentera le nombre dan-
neaux du problme rsoudre.
2. Crer un objet capable de stocker une conguration. On pourra par exemple re-
prsenter chaque tige par un tableau de taille N, et chaque anneau par un entier
entre 1 et N. Vous utiliserez au choix une structure ou une classe, selon ce qui
vous semble le plus pertinent, ou dfaut ce avec quoi vous tes le plus laise.
3. Programmer de quoi initialiser une conguration, cest dire lui donner sa valeur
de dpart (tous les anneaux sur la premire tige).
4. Programmer une fonction permettant dafcher une conguration lcran, par
exemple sous la forme utilise ci-dessus pour lexemple pour N=2.
5. Programmer une fonction ralisant un dplacement : pour une tige origine et une
tige destination spcies, elle prlve le pion suprieur sur la tige origine et le
place sur la tige destination.
6. En vous basant sur la mthode propose, programmer une fonction ralisant un
transfert de k anneaux dune tige une autre, et afchant au fur et mesure les
dplacements effectus, et ltat du jeu aprs chaque dplacement.
7. En utilisant les lments prcdents, crire une fonction main() qui rsoud le pro-
blme des tours de Hanoi de taille N et afche la solution complte.
321
B.21. Devoir surveill 2004 : nonc B. Examens
Questions complmentaires
1. Si lon avait souhait nafcher que la liste des dplacements effectuer sans
afcher chaque fois les congurations intermdaires, le programme aurait t
beaucoup plus simple. Pourquoi ? Ecrire la fonction correspondante (5 lignes de
code environ).
2. Pour rsoudre le problme avec N anneaux, combien de dplacements sont n-
cessaires ?
B.21.5 Table de hachage
On a souvent besoin, en informatique, de manipuler des donnes sous forme de
tableaux associatifs, dans lesquels on associe une valeur chaque clef dun ensemble.
Cest le cas quand on veut reprsenter un annuaire ( un nom, on associe un numro
de tlphone) ou un dictionnaire monolingue ( un mot, on associe une dnition). On
se place dans le cas o clefs et valeurs sont reprsentes par des chanes de caractres
et o une unique valeur est associe chaque clef.
Une manire efcace de reprsenter cette notion abstraite de tableau associatif est
dutiliser une table de hachage. On se xe un entier naturel N et on alloue en mmoire
un tableau de N cases. On suppose que lon dispose dune fonction de hachage h qui
une clef (une chane de caractres, donc), associe un entier entre 0 et N1. On stockera
le couple clef/valeur (c, v) dans la case h(c) du tableau. Ainsi, pour rechercher par la
suite quelle valeur est associe une clef c, il sufra de regarder dans la case h(c), sans
avoir besoin de parcourir lintgralit du tableau.
Un problme qui se pose est que h nest pas une fonction injective. Non seulement
il y a potentiellement un nombre inni de clefs, mais on souhaite galement garder N
relativement petit pour ne pas avoir de trop gros besoins en mmoire. Il faut donc pr-
voir les collisions, cest--dire les cas de deux clefs distinctes c et c
).
Plusieurs stratgies de gestion des collisions existent, on en choisira une trs simple : si,
au moment dinsrer le couple (c
, v
), la case h(c
i=0
B
l1i
x
i
_
mod N
o B est une constante, que lon xera 256 et x mod y dsigne le reste de la
division euclidienne de x par y
la manire de grer les collisions, dcrite plus haut
1. Dnir les constantes globales N et B.
2. Dnir la fonction de hachage int hachage(const string &clef).
322
B. Examens B.21. Devoir surveill 2004 : nonc
3. Dnir une structure Entree, qui correspondra une case de la table de hachage.
Cette structure contient trois champs : la clef, la valeur et un boolen indiquant si
la case est occupe.
4. Dnir une classe TableHachage comprenant :
un tableau de N Entree
une fonction membre void inserer(const string &clef, const string &valeur);
une fonction membre string rechercher(const string &clef) const;
Un constructeur est-il ncessaire ? Pourquoi ? Le dnir le cas chant.
5. Dnir la fonction TableHachage::inserer. Dans le cas o la table est pleine,
on pourra simplement afcher un message lcran et ne rien faire dautre.
6. Dnir la fonction TableHachage::rechercher. Dans le cas o la clef nest
pas prsente dans la table, on pourra renvoyer la chane vide.
7. Dnir une fonction main utilisant un objet de type TableHachage. On pourra
stocker le mini-annuaire suivant, puis rechercher et afcher le numro de tl-
phone du SAMU.
SAMU 15
Police Secours 17
Pompiers 18
8. Sans rien programmer, expliquer ce quil faudrait faire pour rajouter la possibilit
denlever un lment la table de hachage.
323
B.22. Devoir surveill 2003 : nonc B. Examens
B.22 Devoir surveill 2003 : nonc
B.22.1 Tableau dexcution
Remplir le tableau dexcution du programme suivant :
1 int suite(int x){
2 if (x%2 == 0)
3 return x/2;
4 else
5 return 3
*
x + 1;
6 }
7
8 bool test(int y){
9 bool h;
10
11 if (y == 1)
12 h = true;
13 else
14 h = test(suite(y));
15
16 return h;
17 }
18
19 void initialise(int& z){
20 z = 4;
21 }
22
23 int fin(int& w){
24 w += 36;
25 return w+2;
26 w += 1;
27 }
28
29 int main(){
30 int a;
31 initialise(a);
32
33 if (test(a))
34 a = fin(a);
35
36 return 0;
37 }
Il sagit dcrire, si elles existent, les valeurs des variables du programme pour
chaque excution de ligne. Question bonus : ce code gnre un warning la compi-
lation; lequel, quelle ligne ?
Conventions :
324
B. Examens B.22. Devoir surveill 2003: nonc
mettre le numro de la ligne quon vient dexcuter (ventuellement, on peut
dcouper lexcution dune mme ligne en plusieurs tapes) ;
laisser en blanc les variables non existantes ;
mettre un point dinterrogation pour les variables dclares non initialises ;
pour une variable qui nest autre quune rfrence sur une autre variable x, on
indiquera [x] ;
on peut utiliser le symbole pour rpter la valeur dune variable la ligne sui-
vante ;
pour gagner de la place dans le tableau, les noms des variables nont t indexs
que par la premire lettre du nom de la fonction laquelle elles sont rattaches,
suivie le cas chant du numro dappel la fonction. De mme, le retour de la
fonction f a pour nom ret
f
.
B.22.2 Erreurs
Corriger le code suivant :
1 // fichier main.cpp
2
3 class paire {
4 string clef;
5 int valeur;
6 public:
7 paire(string key, int value);
8 void affecte_clef(string key) const;
9 void affecte_valeur(int value) const;
10 string donne_clef() const;
11 int donne_valeur() const;
12 }
13
14 paire::paire(string key, int value) {
15 clef=key;
16 valeur=value;
17 }
18
19 void paire::affecte_clef(string key) {
20 clef=key;
21 }
22
23 void paire::affecte_valeur(int value) {
24 valeur=value;
25 }
26
27 string paire::donne_clef() {
28 return clef;
29 }
30
31 int paire::donne_valeur() {
32 return valeur;
325
B.22. Devoir surveill 2003: nonc B. Examens
33 }
34
35 int cherche_valeur(paire repertoire[], int n, string key) {
36 for (i=1, i<=n, i++) {
37 if repertoire[i].donne_clef = key
38 return (repertoire[i].donne_valeur);
39 cout << "clef non trouvee" << endl;
40 }
41
42 int main()
43 {
44 paire a={"cheval",4};
45
46 paire b;
47 b.clef="poule";
48 b.valeur=2;
49
50 paire
*
pattes = new paire[5];
51 pattes = {a, b, paire("araignee",8), paire("baleine",0),
52 paire("martien",3)};
53
54 cout << "Un martien a "
55 << cherche_valeur(pattes[5],5,"martien")
56 << " pattes." << endl;
57
58 return 0;
59 }
B.22.3 Quafche ce programme ?
Examinez bien le contenu du programme suivant. La question est simple : quelles
sont les diffrentes lignes afches sur la sortie standard (cest--dire en console, via les
instructions cout << ... ;) au cours de son excution? Justiez vos rponses.
1 #include <iostream>
2 using namespace std;
3
4 class Paire {
5 double x,y;
6 public:
7 Paire();
8 Paire(double a,double b);
9 Paire operator+(const Paire &v) const;
10 Paire operator-(const Paire &v) const;
11 double getx() const;
12 double gety() const;
13 void setxy(double xx,double yy);
14 };
15
326
B. Examens B.22. Devoir surveill 2003 : nonc
16 Paire::Paire() {
17 cout << "Constructeur sans argument." << endl;
18 }
19
20 Paire::Paire(double a,double b) {
21 x=a;
22 y=b;
23 cout << "Constructeur avec arguments [" << x << "," << y << "]" << endl;
24 }
25
26 Paire Paire::operator+(const Paire& v) const {
27 cout << "Addition [" << x << "," << y << "] [" << v.x << ","
28 << v.y << "]" << endl;
29 Paire w;
30 w.x=x+v.x;
31 w.y=y+v.y;
32 return w;
33 }
34
35 Paire Paire::operator-(const Paire &v) const {
36 cout << "Soustraction [" << x << "," << y << "] [" << v.x << ","
37 << v.y << "]" << endl;
38 return Paire(x-v.x,y-v.y);
39 }
40
41 double Paire::getx() const {
42 return x;
43 }
44
45 double Paire::gety() const {
46 return y;
47 }
48
49 void Paire::setxy(double xx,double yy) {
50 x=xx;
51 y=yy;
52 }
53
54 int main(void) {
55 Paire tab[2];
56 tab[0].setxy(3,4);
57 tab[1]=Paire(4,6);
58
59 Paire a(1,1);
60 Paire b= ( ( a+Paire(1,2) ) + tab[0] ) - tab[1];
61 cout << "Resultat [" << b.getx() << "," << b.gety() << "]" << endl;
62 }
327
B.22. Devoir surveill 2003 : nonc B. Examens
B.22.4 Le jeu du Pendu
Tout le monde connat le jeu de pendu. Rappelons tout de mme les rgles pour
plus de sret ... Il sagit de trouver un mot cach en proposant des lettres une par
une. Si la lettre propose nest pas prsente dans le mot, une erreur est comptabilise.
Si le joueur dpasse 11 erreurs avant davoir trouv le mot, il a perdu. Inversement,
si le joueur parvient dcouvrir lintgralit du mot avant de totaliser 11 erreurs, il a
gagn.
Commencez par programmer au brouillon! ! !
On dispose dune fonction string dictionnaire(int n) qui renvoie un mot de
10 lettres diffrent pour chaque entier compris entre 0 et 999 pass en argument.
1. Utiliser cette fonction pour programmer une fonction mot_mystere qui renvoie
un mot mystre faire dcouvrir, en faisant en sorte que ce mot change alatoi-
rement chaque excution.
On utilise un tableau de boolens pour stocker le fait que le i
eme
caractre du mot
mystre ait t dcouvert ou non.
Exemple : pour "maquillage", si le joueur a dj entr i, a et s, le tableau de boolens est
{false, true, false, false, true, false, false, true, false, false}.
2. Programmer une fonction affiche qui partir du mot mystre et du tableau de
boolens associ afche lcran le rsultat courant (mot mystre dans lequel les
caractres non dcouverts sont remplacs par une toile *).
Exemple : pour "maquillage", si le joueur a dj entr i, a et s, le rsultat courant est
"*a**i**a**". La fonction afche donc "*a**i**a**".
3. Programmer une fonction essai qui demande lutilisateur de rentrer un carac-
tre au clavier et qui met jour le tableau de boolens en consquence.
4. Programmer une fonction reste qui renvoie le nombre de caractres restant
trouver dans le mot mystre (pour 2 caractres identiques, on comptera 2 pour
simplier).
Exemple : pour "maquillage", si le joueur a dj entr i, a et s, le rsultat courant est
"*a**i**a**". Il reste 7 caractres trouver (m,q,u,l,l,g,e).
On dispose maintenant de sufsants dlments pour construire une version simple
du jeu, sans notion de nombre limit dessais.
5. A partir des fonctions prcdentes, programmer une fonction jeu_mystere qui
demande lutilisateur dentrer un caractre puis afche le rsultat courant jus-
qu ce que le mot mystre soit entirement dcouvert, et signale ensuite luti-
lisateur quil a gagn.
Il sagit maintenant de rajouter cette premire version du jeu la notion de nombre
limit dessais.
6. Programmer une nouvelle version de la fonction essai pour quelle renvoie en
plus une variable signalant si le caractre entr par lutilisateur restait dcouvrir
(succs) ou non (chec) dans le mot mystre.
Exemple : pour "maquillage", si le joueur a dj entr i, a et s, le rsultat courant est
"*a**i**a**". Si lutilisateur rentre m, la fonction renvoie succs ; si lutilisateur rentre
z, la fonction renvoie chec ; si lutilisateur rentre a (dj rentr), la fonction renvoie
chec.
328
B. Examens B.22. Devoir surveill 2003: nonc
7. Assembler les fonction prcdentes lintrieur dune fonction jeu_pendu pour
crer un jeu de pendu. Grer la dfaite du joueur si il arrive 11 checs. Grer la
victoire du joueur si il dcouvre lintgralit du mot mystre avant de totaliser 11
checs.
B.22.5 Programme mystre
Le programme suivant est inspir dun clbre puzzle. Il sagit de deviner la logique
dune suite de chanes de caractres. On donne les quatre premiers lments de la suite
et on demande de trouver les deux suivants. Il y a un pige et certaines personnes
mettent plusieurs jours trouver...
Ici, nous ne vous donnons pas les premiers lments, mais un programme qui g-
nre la suite complte. Pour quelquun qui parle C++, ce programme est donc directe-
ment la solution du puzzle. A vous de jouer :
Que fait exactement ce programme ? Donnez le principe de la suite et dtaillez
un peu le fonctionnement de la fonction next().
Quafche t-il ?
Le programmeur a construit ligne 15 le caractre reprsentant le chiffre count
en utilisant char(0+count). Il a donc suppos que count restait plus petit
que 10. Pour se rassurer, il a ajout un assert() ligne 14. Etait-ce la peine ? Le
assert() reste-t-il vrai si on afche le reste de la suite ? La condition aurait-elle
pu tre encore plus restrictive ?
Question subsidiaire (hors examen!) : faites le test autour de vous et voyez com-
bien de personnes trouvent le 5
eme
lment partir des 4 premiers...
1 // Programme mystre...
2
3 #include <iostream>
4 #include <string>
5 #include <cassert>
6 using namespace std;
7
8 string next(string s) {
9 string t;
10 int count=1;
11 for (unsigned int i=0;i<s.size();i++) {
12 if (i==s.size()-1 || s[i]!=s[i+1]) {
13 string u="xx";
14 assert(count<10);
15 u[0]=char(0+count); // caractre reprsentant le chiffre count
16 u[1]=s[i];
17 t+=u;
18 count=1;
19 } else
20 count++;
21 }
22 return t;
23 }
24
329
B.22. Devoir surveill 2003 : nonc B. Examens
25 int main()
26 {
27 string s="1";
28 cout << s << endl;
29 for (int i=0;i<8;i++) {
30 s=next(s);
31 cout << s << endl;
32 }
33 return 0;
34 }
...
330
C. Imagine++
Annexe C
Imagine++
Imagine++ est un ensemble de bibliothques permettant de faire simplement du
graphisme et de lalgbre linaire. Elles sappuient pour cela sur les projets Qt (gra-
phisme 2D et 3D) et Eigen (algbre linaire). Ceux-ci proposent une richesse de pos-
sibilits bien plus importantes que Imagine++ mais en contrepartie Imagine++ est
plus simple utiliser.
Imagine++ est un logiciel libre, vous pouvez donc lutiliser et le distribuer votre
guise (et gratuitement !), mais si vous le distribuez sous une forme modie vous de-
vez offrir selon les mmes termes les sources de vos modications. Une documentation
complte est disponible sur la page Web dImagine++, dtaillant linsallation et luti-
lisation.
Tout est englob dans un namespace Imagine, donc si vous voulez viter de pr-
xer les noms par Imagine:: vous devez utiliser dans votre code
usi ng namespace Imagine ;
C.1 Common
Imagine/Common.h dnit entre autres la classe Color code par un mlange de
rouge, vert et bleu, la quantit de chacun code par un entier entre 0 et 255 :
Color noi r = Color ( 0 , 0 , 0 ) ;
Color bl anc = Color ( 255 , 255 , 255) ;
Color rouge = Color ( 2 5 5 , 0 , 0 ) ;
Un certain nombre de constantes de ce type sont dj dnies : BLACK, WHITE, RED,
GREEN, BLUE, CYAN, MAGENTA, YELLOW.
Un type byte (synonyme de unsigned char) est dni pour coder une valeur
entire entre 0 et 255.
C.2 Graphics
Imagine/Graphics.h propose du dessin en 2D et 3D. Les coordonnes 2D sont
en pixel, laxe des x est vers la droite et laxe des y vers le bas (attention, ce nest pas
le sens mathmatique usuel !). Le point (0,0) est donc le coin haut-gauche de la fentre
(pour les fonctions de trac) ou de lcran (pour openWindow).
C.3. Image C. Imagine++
openWindow( 5 0 0 , 5 0 0 ) ; / / T a i l l e de f e n t r e
drawRect ( 10 , 10 , 480 , 480 ,RED) ; / / Coi n haut gauche ( 10 , 10) ,
/ / l a r g e ur 480 , haut e ur 480
drawLine ( 10 , 10 , 490 , 490 , BLUE) ; / / Di agonal e
Window w = openWindow( 1 0 0 , 1 0 0 ) ; / / Aut re f e n t r e
setActiveWindow(w) ; / / S l e c t i o n pour l e s pr o c ha i ns t r a c s
drawStri ng ( 10 , 10 , "Du t e xt e " , MAGENTA) ; / / Me t t r e du t e x t e
endGraphics ( ) ; / / At t end un c l i c s o ur i s avant de f e r me r l e s f e n t r e s
Si on a beaucoup de dessins faire la suite et quon veut nafcher que le rsultat
nal (cest plus esthtique), on encadre le code de trac par :
noRefreshBegi n ( ) ;
. . .
noRefreshEnd ( ) ;
Pour faire une animation, il est utile de faire une petite pause entre les images pour
rguler la cadence :
mi l l i Sl e ep ( 5 0 ) ; / / Temps en mi l l i s e c o n d e s
On peut charger une image (loadGreyImage, loadColorImage) ou sauvegar-
der (saveGreyImage, saveColorImage) dans un chier. Attention, ces fonctions
allouent de la mmoire quil ne faut pas oublier de librer aprs usage.
byt e g ;
i nt l argeur , hauteur ;
loadGreyImage ( srcPat h ( " image . j pg " ) , g , l argeur , hauteur ) ;
/ / On a ur a i t d v r i f i e r l e r e t o ur de l oadGr e yI mage pour s a v o i r
/ / s i l e char ge me nt s e s t b i e n pa s s . . .
/ / De s s i ne ave c c o i n haut gauche en ( 0 , 0 ) :
putGreyImage ( 0 , 0 , g , l argeur , hauteur ) ;
del et e [ ] g ; / / Ne pas o u b l i e r !
A noter srcPath, dni dans Common, qui indique de chercher dans le dossier conte-
nant les chiers source.
En fait, pour viter de grer soi-mme la mmoire des images, il existe une classe
ddie cela :
C.3 Image
Imagine/Images.h gre le chargement, la manipulation et la sauvegarde des
images.
Image<byte > im; / / Image en ni ve aux de g r i s
l oad ( im, " f i chi er _i mage . j pg " ) ; / / I l f a u d r a i t v r i f i e r l e r e t o ur
di spl ay ( im ) ; / / De s s i ne dans l a f e n t r e a c t i v e
im( 0 , 0) =128; / / Met l e p i x e l en g r i s
save ( im, " f i chi er _i mage2 . png" ) ; / / Sauve gar de l i mage dans un f i c h i e r
Attention : la recopie et laffectation (oprateur =) sont des oprations peu co-
teuses qui en fait ne font quun lien entre les images, sans relle copie. Ce qui fait que
la modication de lune affecte lautre :
332
C. Imagine++ C.4. LinAlg
Image<Color > im1 ( 1 0 0 , 1 0 0 ) ;
Image<Color > im2 = im1 ; / / Co ns t r uc t e ur par r e c o p i e
im1 ( 10 , 10) = CYAN;
as s e r t ( im2 ( 10 , 10) == CYAN) ; / / im2 a t a f f e c t e
Pour faire une vraie copie plutt quun lien, on utilise :
im2 = im1 . cl one ( ) ;
im1 ( 10 , 10) = CYAN; / / N a f f e c t e pas im2
Ainsi, si on passe une image comme paramtre dune fonction, puisque cest le
constructeur par copie qui est appel, tout se passe comme si on avait pass par rf-
rence :
void f ( Image<Color > im) { / / Pas s age par va l e ur
im( 10 , 10) = CYAN;
}
f ( im1 ) ; / / Mo di f i e quand mme l e p i x e l ( 10 , 10)
Une erreur courante est de chercher lire ou crire des coordonnes au-del des
bornes du tableau, typiquement une erreur dans un indice de boucle.
C.4 LinAlg
Imagine/LinAlg propose lalgbre linaire avec des classes matrice et vecteur.
Matrix<f l oat > I ( 2 , 2 ) ; / / T a i l l e 2x2
I . f i l l ( 0 . 0 f ) ; / / Mat r i c e nul l e
I ( 0 , 0) = I ( 1 , 1) =1. 0 f ; / / Mat r i c e i d e n t i t
cout << " det ( I )= " << det ( I ) << endl ; / / Dt ermi nant
Les oprateurs daddition (matrice+matrice, vecteur+vecteur), soustraction (matrice-
matrice, vecteur-vecteur) et multiplication (matrice*matrice, matrice*vecteur) sont bien
sr dnis.
Comme pour les images, attention de ne pas sortir des bornes en accdant aux
lments des matrices et vecteurs !
Une fonction trs utile est linSolve pour rsoudre un systme linaire.
333
D. Fiche de rfrence nale
Annexe D
Fiche de rfrence nale
Fiche de rfrence (1/5)
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
Type numr :
enum Dir{nord,est,
sud,ouest};
void avance(Dir d);
Variables statiques :
int f() {
static bool first=true;
if (first) {
first=false;
...
}
...
}
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:
...;
}
mx=(x>y)?x:y;
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;
...
}
for (int i=...) {
...
if (t[i]==s){
...
// quitte la boucle
break;
}
...
}
D. Fiche de rfrence nale
Fiche de rfrence (2/5)
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
Rfrences constantes (pour
un passage rapide) :
void f(const obj& x){
...
}
void g(const obj& x){
f(x); // OK
}
Valeurs par dfaut :
void f(int a,int b=0);
void g() {
f(12); // f(12,0);
f(10,2);// f(10,2);
}
void f(int a,int b) {
// ...
}
Inline (appel rapide) :
inline double sqr(
double x) {
return x
*
x;
}
...
double y=sqr(z-3);
Rfrence en retour :
int i; // Var. globale
int& f() {
return i;
}
...
f()=3; // i=3!
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;
En paramtre (n) :
void f(const int
*
t,
int n) {
...
s+=t[i]; // OK
...
t[i]=...; // NON!
}
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};
Une structure est un objet en-
tirement public (cf objets !)
336
D. Fiche de rfrence nale
Fiche de rfrence (3/5)
Objets
struct obj {
int x; // champ
int f(); // mthode
int g(int y);
};
int obj::f() {
int i=g(3); // mon g
int j=x+i; // mon x
return j;
}
...
int main() {
obj a;
a.x=3;
int i=a.f();
class obj {
int x,y;
void a_moi();
public:
int z;
void pour_tous();
void un_autre(obj A);
};
void obj::a_moi() {
x=..; // OK
..=y; // OK
z=..; // OK
}
void obj::pour_tous() {
x=..; // OK
a_moi(); // OK
}
void une_autre(obj A) {
x=A.x; // OK
A.a_moi(); // OK
}
...
int main() {
obj A,B;
A.x=..; //NON
A.z=..; //OK
A.a_moi(); //NON
A.pour_tous(); //OK
A.une_autre(B); //OK
class obj {
obj operator+(obj B);
};
...
int main() {
obj A,B,C;
C=A+B;
// C=A.operator+(B)
Mthodes constantes :
void obj::f() const{
...
}
void g(const obj& x){
x.f(); // OK
}
Constructeur :
class point {
int x,y;
public:
point(int X,int Y);
};
point::point(int X,
int Y){
x=X;
y=Y;
}
...
point a(2,3);
Constructeur vide :
obj::obj() {
...
}
...
obj a;
Objets temporaires :
point point::operator+(
point b) {
return point(x+b.x,
y+b.y);
}
...
c=point(1,2)
+f(point(2,3));
Destructeur :
obj::~obj() {
...
}
Constructeur de copie :
obj::obj(const obj& o){
...
}
Utilis par :
- obj b(a);
- obj b=a;
// mieux que obj b;b=a;
- paramtres des fonctions
- valeur de retour
Affectation :
obj& obj::operator=(
const obj&o){
...
return
*
this;
}
Objets avec allocation dyna-
mique automatique : cf section
10.11
Accesseurs :
class mat {
double
*
x;
public:
double& operator()
(int i,int j){
assert(i>=0 ...);
return x[i+M
*
j];
}
double operator()
(int i,int j)const{
assert(i>=0 ...);
return x[i+M
*
j];
}
...
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...
STL
min,max,...
complex<double> z;
pair<int,string> p;
p.first=2;
p.second="hop";
#include<list>
using namespace std;
...
list<int> l;
l.push_front(1);
...
if (l.find(3)!=l.end())
...
list<int>::const_iterator
it;
for (it=l.begin();
it!=l.end();it++)
s+=
*
it;
list<int>::iterator it
for (it=l.begin();
it!=l.end();it++)
if (
*
it==2)
*
it=4;
stack, queue, heap, map,
set, vector, ...
337
D. Fiche de rfrence nale
Fiche de rfrence (4/5)
Entres/Sorties
#include <iostream>
using namespace std;
...
cout <<"I=" <<i <<endl;
cin >> i >> j;
#include <fstream>
using namespace std;
ofstream f("hop.txt");
f << 1 << << 2.3;
f.close();
ifstream g("hop.txt");
if (!g.is_open()) {
return 1;
}
int i;
double x;
g >> i >> x;
g.close();
do {
...
} while (!(g.eof());
ofstream f;
f.open("hop.txt");
double x[10],y;
ofstream f("hop.bin",
ios::binary);
f.write((const char
*
)x,
10
*
sizeof(double));
f.write((const char
*
)&y,
sizeof(double));
f.close();
ifstream g("hop.bin",
ios::binary);
g.read((char
*
)x,
10
*
sizeof(double));
g.read((const char
*
)&y,
sizeof(double));
g.close();
string nom;
ifstream f(nom.c_str());
#include <sstream>
using namespace std;
stringstream f;
// Chane vers entier
f << s;
f >> i;
// Entier vers chane
f.clear();
f << i;
f >> s;
ostream& operator<<(
ostream& f,
const point&p) {
f<<p.x<< << p.y;
return f;
}
istream& operator>>(
istream& f,point& p){
f>>p.x>>p.y;
return f;
}
Template
Fonctions :
// A mettre dans LE
// fichier qui lutilise
// ou dans un .h
template <typename T>
T maxi(T a,T b) {
...
}
...
// Le type est trouv
// tout seul!
maxi(1,2); //int
maxi(.2,.3); //double
maxi("a","c");//string
Objets :
template <typename T>
class paire {
T x[2];
public:
paire() {}
paire(T a,T b) {
x[0]=a;x[1]=b;
}
T somme()const;
};
...
template <typename T>
T paire<T>::somme()const{
return x[0]+x[1];
}
...
// Le type doit tre
// prcis!
paire<int> a(1,2);
int s=a.somme();
paire<double> b;
...
Multiples :
template <typename T,
typename S>
class hop {
...
};
...
hop<int,string> A;
...
Entiers :
template <int N>
class hop {
..
};
...
hop<3> A;
hop<5> B;
...
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;
Faire des objets.
Ne pas toujours faire des ob-
jets !
Penser interface / implmen-
tation / utilisation.
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
338
D. Fiche de rfrence nale
Fiche de rfrence (5/5)
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();
if (s1==s1) ...
if (s1!=s2) ...
if (s1<s2) ...
size_t i=s.find(h),
j=s.find(h,3);
k=s.find("hop");
l=s.find("hop",3);
a="comment";
b="a va?";
txt=a+" "+b;
s1="un deux trois";
s2=string(s1,3,4);
getline(cin,s);
getline(cin,s,:);
const char
*
t=s.c_str();
#include <ctime>
s=double(clock())
/CLOCKS_PER_SEC;
#define _USE_MATH_DEFINES
#include <cmath>
double pi=M_PI;
Oprateurs binaires
and : a&b
or : a|b
xor : a^b
right shift : a>>n
left shift : a<<n
complement : ~a
exemples :
set(i,1) : i|=(1<<n)
reset(i,1) : i&=~(1<<n)
test(i,1) : if (i&(1<<n))
ip(i,1) : i^=(1<<n)
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!
class point {
int x,y;
public:
...
};
...
point a={2,3}; // NON
Oublier de rednir le
constructeur vide.
point p=point(1,2);//NON
point p(1,2); // OUI
obj
*
t=new obj[n];
...
delete t; // manque []
//NON!
void f(int a=2,int b);
void f(int a,int b=0);
void f(int a);// NON!
Ne pas tout mettre inline!
int f() {
...
}
...
f()=3; // HORREUR!
int& f() {
int i;
return i;
}
...
f()=3; // NON!
if (i>0 & i<n) // NON
if (i<0 | i>n) // NON
if (...) {
...
if (...)
break; // Non,
// boucles seulement
}
for (i ...)
for (j ...) {
...
if (...)
break;//NON, quitte
// juste la boucle j
int i;
double x;
...
j=max(i,0);//OK
y=max(x,0);//NON!
// 0.0 et non 0: max
// est un template STL
Imagine++
Voir documentation...
339