Vous êtes sur la page 1sur 245

Exercices en langage C

C. Delannoy

Exe rcice s e n langage C

PREM IERE PARTIE :


EXERCICES D 'APPLICATIO N

Ce tte pre m i re partie vous propose des exercices, r s oudre , de prf re nce , pe ndant la ph ase d'tude du langage C luim m e . Elle pous e la structure d'un cours "classique"1, sous la form e de 7 ch apitre s : types de bas e , op rate urs e t
e xpre s s ions ;e ntr e s -sortie s conve rsationne lles ;instructions de contrle ;les fonctions ;les tableaux e t les pointe urs ;
les ch a
nes de caract re s ;les s tructure s .
Ch aq ue ch apitre com porte :
- des exe rcices d'application im m diate destin s facilite r l'assim ilation du cours corre s pondant,
- des exe rcice s , sans grande difficult algorith m iq ue m e ttant e n oe uvre les diff re nte s notions acq uis e s au cours des
pr cdents ch apitre s .
Note z q ue l'utilisation de s fich ie rs, ainsi que la ge s tion dynam iq ue ne s ont pas abords dans ce tte pre m i re partie ;ce s
deux points fe ront ch acun l'obje t d'un ch apitre appropri dans la s e conde partie de l'ouvrage .

1 Un telcours vous e s t propos, par exem pl


e, dans "Apprendre program m er en Turbo C" ou dans "C norm e ANSI - Guide com plet de

program m ation" du m m e auteur, galem ent aux ditions Eyrolles.

I : TYPES D E BASE,
O PERA TEURS
ET EXPRESSIO NS

Exe rcice I.1


___________________________________________________________________________

Enonc
Elim ine r les pare nth s e s s upe rflues dans les e xpre s s ions suivante s :
a = (x+5)
a = (x=y) + 2
a = (x==y)
(a<b) && (c<d)
(i++) * (n+p)

/*
/*
/*
/*
/*

expression
expression
expression
expression
expression

1
2
3
4
5

*/
*/
*/
*/
*/

___________________________________________________________________________

Sol
ution

a = x+5

/* expression 1 */

L'op rate ur + e s t prioritaire s ur l'op rate ur d'affe ctation =.


a = (x=y) + 2

/* expression 2 */

Ici, l'op rate ur + tant prioritaire s ur =, les pare nth s e s s ont indispensables .
a = x==y

/* expression 3 */

Exe rcice s e n langage C

L'op rate ur == e s t prioritaire s ur =.


a<b && c<d

/* expression 4 */

L'op rate ur & & e s t prioritaire s ur l'op rate ur < .


i++ * (n+p)

/* expression 5 */

L'op rate ur + + e s t prioritaire s ur *;e n re vanch e , *e s t prioritaire s ur + ;de sorte q u'on ne pe ut lim ine r les derni re s
pare nth s e s .

Exe rcice I.2


___________________________________________________________________________

Enonc
Soie nt les dclarations :
char c = '\x01' ;
short int p = 10 ;

Quels sont le type e t la valeur de ch acune d e s e xpre s s ions suivante s :


p
c
p
3

+
+
+
*

3
1
c
p + 5 * c

/* 1 */
/* 2 */
/* 3 */
/* 4 */

___________________________________________________________________________

Sol
ution
1) p e s t d'abord soum is la conve rsion "syst m atiq ue " sh ort -> int, avant d' tre ajout la valeur 3 (int). Le r s ultat 13
e s t de type int.
2) c e s t d'abord soum is la conve rsion "syst m atiq ue " ch ar -> int (ce q ui aboutit la valeur 1), avant d' tre ajout la
valeur 1 (int). Le r s ultat 2 e s t de type int.

I. Types de base, oprate urs e t e xpre s s ions


5
3) p e s t d'abord soum is la conve rsion syst m atiq ue sh ort -> int, tandis q ue c e s t soum is la conve rsion syst m atiq ue
ch ar -> int ;les r s ultats sont alors additionn s pour aboutir la valeur 11 de type int.
4) p e t c sont d'abord aux m m e s conve rsions syst m atiq ue s q ue ci-de s s us ;le r s ultat 35 e s t de type int.

Exe rcice I.3


___________________________________________________________________________

Enonc
Soie nt les dclarations :
char c = '\x05' ;
int n = 5 ;
long p = 1000 ;
float x = 1.25 ;
double z = 5.5 ;

Quels sont le type e t la valeur de ch acune d e s e xpre s s ions suivante s :


n + c + p
2 * x + c
(char) n + c
(float) z + n / 2

/*
/*
/*
/*

1
2
3
4

*/
*/
*/
*/

___________________________________________________________________________

Sol
ution
1) c e s t tout d'abord conve rti e n int, avant d' tre ajout n. Le r s ultat (10), de type int, e s t alors conve rti e n long, avant
d' tre ajout p. O n obtie nt finalem e nt la valeur 1010, de type long.
2) O n value d'abord la valeur de 2*x, e n conve rtissant 2 (int) e n float, ce q ui fournit la valeur 2.5 (de type float). Par
ailleurs, c e s t conve rti e n int (conve rsion syst m atiq ue ). O n value e nsuite la valeur de 2*x, e n conve rtissant 2 (int) e n
float, ce q ui fournit la valeur 2.5 (de type float). Pour e ffe ctue r l'addition, on conve rtit alors la valeur e nti re 5 (c) e n
float, avant de l'ajoute r au r s ultat pr cdent. O n obtie nt finalem e nt la valeur 7.75, de type float.

6
Exe rcice s e n langage C
3) n e s t tout d'abord conve rti e n ch ar ( cause de l'op rate ur de "cast"), tandis q ue c e s t conve rti (conve rsion
syst m atiq ue ) e n int. Puis, pour procder l'addition, ile s t n ce s s aire de re conve rtir la valeur de (ch ar) n e n int.
Finalem e nt, on obtie nt la valeur 10, de type int.
4) z e s t d'abord conve rti e n float, ce q ui fournit la valeur 5.5 (approxim ative , car, e n fait, on obtie nt une valeur un pe u
m oins prcise que ne le s e rait 5.5 e xprim e n double). Par ailleurs, on proc de la division e nti re de n par 2, ce q ui
fournit la valeur e nti re 2. Ce tte derni re e s t e nsuite conve rtie e n float, avant d' tre ajout e 5.5, ce q ui fournit le
r s ultat 7.5, de type float.
R e m arque :
D ans la pre m i re dfinition de K e rnigh an e t R itch ie , les valeurs de type float taie nt, e lles aussi, soum ises une
conve rsion syst m atiq ue e n double. Dans ce cas, les e xpre s s ions 3 et 4 taie nt alors de type double.

Exe rcice I.4


___________________________________________________________________________

Enonc
Soie nt les dclarations suivante s :
int n = 5, p = 9 ;
int q ;
float x ;

Quelle e s t la valeur affe ct e aux diff re nte s variables conce rn e s par ch acune des instructions suivante s :
q
q
q
x
x
x
x
q
q

=
=
=
=
=
=
=
=
=

n < p ;
n == p ;
p % n + p > n ;
p / n ;
(float) p / n ;
(p + 0.5) / n ;
(int) (p + 0.5) / n ;
n * (p > n ? n : p) ;
n * (p < n ? n : p) ;

/*
/*
/*
/*
/*
/*
/*
/*
/*

1
2
3
4
5
6
7
8
9

*/
*/
*/
*/
*/
*/
*/
*/
*:

___________________________________________________________________________

I. Types de base, oprate urs e t e xpre s s ions

Sol
ution
1) 1
2) 0
3) 5 (p%n vaut 4, tandis q ue p> n vaut 1)
4) 1 (p/n e s t d'abord valu e n int, ce q ui fournit 1 ;puis le r s ultat e s t conve rti e n float, avant d' tre affe ct x).
5) 1.8 (p e s t conve rti e n float, avant d' tre divis par le r s ultat de la conve rsion de n en float).
6) 1.9 (p e s t conve rti e n float, avant d' tre ajout 0.5 ;le r s ultat e s t divis par le r s ultat de la conve rsion de n en
float).
7) 1 (p e s t conve rti e n float, avant d' tre ajout 0.5 ;le r s ultat (5.5) e s t alors conve rti e n int avant d' tre divis par n).
8) 25
9 ) 45

Exe rcice I.5


___________________________________________________________________________

Enonc
Quels r s ultats fournit le program m e s uivant :
#include <stdio.h>
main ()
{
int i, j, n ;
i = 0 ; n = i++ ;
printf ("A : i = %d

n = %d \n", i, n ) ;

i = 10 ; n = ++ i ;
printf ("B : i = %d

n = %d \n", i, n ) ;

Exe rcice s e n langage C


i = 20 ; j = 5 ; n = i++ * ++ j ;
printf ("C : i = %d j = %d n = %d \n", i, j, n ) ;
i = 15 ; n = i += 3 ;
printf ("D : i = %d n = %d \n", i, n) ;
i = 3 ; j = 5 ; n = i *= --j ;
printf ("E : i = %d j = %d n = %d \n", i, n) ;
}

___________________________________________________________________________

Sol
ution

A
B
C
D
E

:
:
:
:
:

i
i
i
i
i

=
=
=
=
=

1 n = 0
11 n = 11
21 j = 6 n = 120
18 n = 18
12 j = 12 n = 6

Exe rcice I.6


___________________________________________________________________________

Enonc
Quels r s ultats fournira ce program m e :
#include <stdio.h>
main()
{
int n=10, p=5, q=10, r ;
r = n == (p = q) ;
printf ("A : n = %d

p = %d

q = %d

n = p = q = 5 ;
n += p += q ;
printf ("B : n = %d

p = %d

q = %d\n", n, p, q) ;

r = %d\n", n, p, q, r) ;

I. Types de base, oprate urs e t e xpre s s ions


q = n < p ? n++ : p++ ;
printf ("C : n = %d p = %d

q = %d\n", n, p, q) ;

q = n > p ? n++ : p++ ;


printf ("D : n = %d p = %d

q = %d\n", n, p, q) ;

___________________________________________________________________________

Sol
ution

A
B
C
D

:
:
:
:

n
n
n
n

=
=
=
=

10
15
15
16

p
p
p
p

=
=
=
=

10
10
11
11

q
q
q
q

=
=
=
=

10
5
10
15

r = 1

Exe rcice I.7


___________________________________________________________________________

Enonc
Quels r s ultats fournira ce program m e :
#include <stdio.h>
main()
{
int n, p, q ;
n = 5 ; p = 2 ;
q = n++ >p || p++ != 3 ;
printf ("A : n = %d p = %d
n = 5 ; p = 2 ;
q = n++<p || p++ != 3 ;
printf ("B : n = %d p = %d
n = 5 ; p = 2 ;

/* cas 1 */
q = %d\n", n, p, q) ;
/* cas 2 */
q = %d\n", n, p, q) ;
/* cas 3 */

10

Exe rcice s e n langage C


q = ++n == 3 && ++p == 3 ;
printf ("C : n = %d p = %d
n = 5 ; p = 2 ;
q = ++n == 6 && ++p == 3 ;
printf ("D : n = %d p = %d

q = %d\n", n, p, q) ;
/* cas 4 */
q = %d\n", n, p, q) ;

___________________________________________________________________________

Sol
ution
Ilne faut pas oublie r q ue les op rate urs & & e t || n' value nt leur de uxi m e op rande q ue lors q ue ce la e s t n ce s s aire .
Ainsi, ici, iln'e s t pas valu dans les cas 1 et 3. Voici les r s ultats fournis par le program m e :
A
B
C
D

:
:
:
:

n
n
n
n

=
=
=
=

6
6
6
6

p
p
p
p

=
=
=
=

2
3
2
3

q
q
q
q

=
=
=
=

1
1
0
1

II : LES ENTREES-SO RTIES


CO NVERSA TIO NNELLES

Exe rcice II.1


___________________________________________________________________________

Enonc
Quels s e ront les r s ultats fournis par ce program m e :
#include <stdio.h>
main ()
{
int n = 543 ;
int p = 5 ;
float x = 34.5678;
printf ("A : %d %f\n", n, x) ;
printf ("B : %4d %10f\n", n, x) ;
printf ("C : %2d %3f\n", n, x) ;
printf ("D : %10.3f %10.3e\n", x, x) ;
printf ("E : %-5d %f\n", n, x) ;
printf ("F : %*d\n", p, n) ;
printf ("G : %*.*f\n", 12, 5, x) ;
printf ("H : %x : %8x :\n", n, n) ;
printf ("I : %o : %8o :\n", n, n) ;
}

_______________________________________________________________

Sol
ution
A : 543 34.567799
B : 543 34.567799

12

Exe rcice s e n langage C


C
D
E
F
G
H
I

:
:
:
:
:
:
:

543 34.567799
34.568 3.457e+01
543
34.567799
543
34.56780
21f :
21f :
1037 :
1037 :

Exe rcice II.2


___________________________________________________________________________

Enonc
Quels s e ront les r s ultats fournis par ce program m e :
#include <stdio.h>
main()
{
char c ;
int n ;
c = 'S' ;
printf ("A : %c\n", c)
n = c ;
printf ("B : %c\n", n)
printf ("C : %d %d\n",
printf ("D : %x %x\n",
}

;
;
c, n) ;
c, n) ;

_______________________________________________________________

Sol
ution
A
B
C
D

:
:
:
:

S
S
83 83
53 53

II. Le s e ntr e s -sortie s conve rsationne lles

13

Exe rcice II.3


___________________________________________________________________________

Enonc
Quelles s e ront les valeurs lues dans les variables n e t p (de type int), par l'instruction suivante :
scanf ("%d %d", &n, &p) ;

lors q u'on lui fournit les donnes suivante s (le sym bole ^ re pr s e nte un e s pace e t le sym bole @ re pr s e nte une fin de
ligne , c'e s t- -dire une "validation") :
a)
253^45@

b)
^253^@
^^ 4 ^ 5 @

_______________________________________________________________

Sol
ution
a) n = 243, p = 45
b) n = 253, p = 4 (les dernie rs caract res de la deuxi m e ligne pourront ve ntue llem e nt tre utiliss par une instruction
de lecture ult rie ure ).

Exe rcice II.4


___________________________________________________________________________

Enonc
Quelles s e ront les valeurs lues dans les variables n e t p (de type int), par l'instruction suivante :
scanf ("%4d %2d", &n, &p) ;

lors q u'on lui fournit les donnes suivante s (le sym bole ^ re pr s e nte un e s pace e t le sym bole @ re pr s e nte une fin de
ligne , c'e s t- -dire une "validation") :

14
a)

Exe rcice s e n langage C


12^45@

b)
123456@

c)
123456^7@

d)
1^458@

e)
^^^4567^^8912@

_______________________________________________________________

Sol
ution
R appe lons q ue lors q u'une indication de longue ur e s t pr s e nte dans le code form at fourni scanf (com m e , par e xe m ple, le
4 de %4d), scanf inte rrom pt son exploration si le nom bre corre s pondant de caract re s a t e xplor , sans q u'un
s parate ur (ou "e s pace blanc") n'ait t trouv . Note z bie n, ce pe ndant, q ue les ve ntue ls caract re s s parate urs "saut s "
auparavant ne s ont pas considrs dans ce com pte . Voici les r s ultats obte nus :
a) n=12, p=45
b) n=1234, p=56
c) n=1234, p=56
d) n=1, p=45
e) n=4567, p=89
En a, on obtie ndrait e xacte m e nt les m m e s r s ultats sans indication de longue ur (c'e s t- -dire ave c %d %d). En b, e n
re vanch e , sans l'indication de longue ur 4, les r s ultats s e raie nt diff re nts (n vaudrait 123456, tandis q u'ilm anq ue rait des
inform ations pour p). En c, les inform ations ^ et 7 ne s ont pas prises en com pte par scanf (e lles le s e ront ve ntue llem e nt
par une proch aine lecture !) ;sans la pre m i re indication de longue ur, les r s ultats s e raie nt diff re nts : 123456 pour n (e n
supposant q ue ce la ne conduis e pas une valeur non re pr s e ntable dans le type int) e t 7 pour p. En d, ce tte fois, c'e s t
l'indication de longue ur 2 q ui a de l'im portance ;e n son abscence, n vaudrait e ffe ctive m e nt 1, m ais p vaudrait 458.
Enfin, e n e , les deux indications de longue ur sont im portante s ;note z bie n q ue les trois e s pace s plac s avant les
caract re s pris e n com pte pour n, ainsi que les 2 e s pace s plac s avant les caract re s pris e n com pte pour p ne s ont pas
com ptabiliss dans la longue ur im pos e .

Exe rcice II.5


___________________________________________________________________________

II. Le s e ntr e s -sortie s conve rsationne lles

15

Enonc
Soit le program m e s uivant :
#include <stdio.h>
main()
{
int n, p ;
do
{ printf ("donnez 2 entiers (0 pour finir) : ") ;
scanf("%4d%2d", &n, &p) ;
printf ("merci pour : %d %d\n", n, p) ;
}
while (n) ;
}

Quels r s ultats fournira-t-il, e n supposant q u'on lui e ntre les donnes suivante s (atte ntion, on supposera q ue les donnes
sont frapp e s au clavie r e t les r s ultats affich s l' cran, ce q ui signifie q u'ily aura "m ixage " e ntre ces deux sorte s
d'inform ations) :
1 2
3
4
123456
78901234 5
6 7 8 9 10
0
0
12

_______________________________________________________________

Sol
ution
Ici, on re trouve le m canism e li l'indication d'une longue ur m axim ale dans le code form at, com m e dans l'e xe rcice
pr cdent. De plus, on e xploite le fait q ue les inform ations d'une ligne q ui n'ont pas t pris e s e n com pte lors d'une
lecture re s te nt disponibles pour la lecture s uivante . Enfin, rappe lons q ue , tant q ue scanf n'a pas re u suffisam m e nt
d'inform ation, com pte te nu des diff re nts code s form at spcifi s (e t non pas des variables indiq u e s ), e lle e n atte nd de
nouve lles . Voici finalem e nt les r s ultats obte nus :
donnez 2 entiers (0 pour finir)
1 2
merci pour : 1 2

16

Exe rcice s e n langage C


donnez 2 entiers (0 pour
3
4
merci pour : 3 4
donnez 2 entiers (0 pour
123456
merci pour : 1234 56
donnez 2 entiers (0 pour
78901234 5
merci pour : 7890 12
donnez 2 entiers (0 pour
merci pour : 34 5
donnez 2 entiers (0 pour
6 7 8 9 10
merci pour : 6 7
donnez 2 entiers (0 pour
merci pour : 8 9
donnez 2 entiers (0 pour
0
merci pour : 10 0
donnez 2 entiers (0 pour
0
12
merci pour : 0 12

finir)

finir)

finir)

finir)
finir)

finir)
finir)

finir)

III : LES INSTRUCTIO NS


D E CO NTRO LE

Exe rcice III.1


___________________________________________________________________________

Enonc
Quelles e rre urs ont t com m ises dans ch acun de s groupes d'instructions suivants :
1)
if (a<b) printf ("ascendant")
else printf ("non ascendant") ;

2)
int n ;
...
switch (2*n+1)
{ case 1 : printf ("petit") ;
case n : printf ("moyen") ;
}

3)
#define LIMITE 100
int n ;
...
switch (n)
{ case LIMITE-1 : printf ("un peu moins") ;
case LIMITE
: printf ("juste") ;
case LIMITE+1 : printf ("un peu plus") ;
}

4)
const int LIMITE=100
int n ;

18

Exe rcice s e n langage C


...
switch
{ case
case
case
}

(n)
LIMITE-1 : printf ("un peu moins") ;
LIMITE
: printf ("juste") ;
LIMITE+1 : printf ("un peu plus") ;

_______________________________________________________________

Sol
ution
1) Ilm anq ue un point-virgule la fin du pre m ie r printf :
if (a<b) printf ("ascendant") ;
else printf ("non ascendant") ;

2) Le s valeurs suivant le m ot cas e doive nt obligatoire m e nt tre des "e xpre s s ions constante s ", c'e s t- -dire d e s e xpre s s ions
calculables par le com pilate ur lui-m m e . Ce n'e s t pas le cas de n.
3) Aucune e rre ur, les e xpre s s ions te lles q ue LIM ITE-1 tant bien des expressions constante s .
4) Ici, les e xpre s s ions suivant le m ot cas e ne s ont plus des expre s s ions constante s , car le sym bole LIM ITE a t dfini
sous form e d'une "constante sym boliq ue " (e n C+ + , ce pe ndant, ce s instructions s e ront corre cte s ).

Exe rcice III.2


___________________________________________________________________________

Enonc
Soit le program m e s uivant :
#include <stdio.h>
main()
{
int n ;
scanf ("%d", &n) ;
switch (n)
{ case 0 : printf ("Nul\n") ;
case 1 :

III. Le s instructions de contrle


case 2 : printf ("Petit\n") ;
break ;
case 3 :
case 4 :
case 5 : printf ("Moyen\n") ;
default : printf ("Grand\n") ;
}
}

Quels r s ultats affich e -t-illors q u'on lui fournit e n donn e :


a) 0
b) 1
c) 4
d) 10
e) -5
___________________________________________________________________________

Sol
ution
a)
Nul
Petit

b)
Petit

c)
Moyen
Grand

d)
Grand

e)
Grand

Exe rcice III.3


___________________________________________________________________________

19

20

Exe rcice s e n langage C

Enonc
Quelles e rre urs ont t com m ises dans ch acune des instructions suivante s :
a)
do c = getchar() while (c != '\n') ;

b)
do while ( (c = getchar()) != '\n') ;

c)
do {} while (1) ;

___________________________________________________________________________

Sol
ution
a) Ilm anq ue un point-virgule :
do c = getchar() ; while (c != '\n') ;

b) Ilm anq ue une instruction ( ve ntue llem e nt "vide") apr s le m ot do. O n pourrait crire , par e xe m ple :
do {} while ( (c = getchar()) != '\n') ;

ou :
do ; while ( (c = getchar()) != '\n') ;

c) Iln'y aura pas d'erreur de com pilation ;toute fois, ils'agit d'une "boucle infinie ".

Exe rcice III.4


___________________________________________________________________________

Enonc
Ecrire plus lisiblem e nt :
do {} while (printf("donnez un nombre >0 "), scanf ("%d", &n), n<=0) ;

___________________________________________________________________________

III. Le s instructions de contrle

21

Sol
ution
Plusieurs possibilit s e xiste nt, puis q u'il "suffit" de re porte r, dans le corps de la boucle, des instructions figurant
"artificie llem e nt" sous form e d'expressions dans la condition de poursuite :
do
printf("donnez un nombre >0 ") ;
while (scanf ("%d", &n), n<=0) ;

ou, m ie ux :
do
{ printf("donnez un nombre >0 ") ;
scanf ("%d", &n) ;
}
while (n<=0) ;

Exe rcice III.5


___________________________________________________________________________

Enonc
Soit le pe tit program m e s uivant :
#include <stdio.h>
main()
{ int i, n, som ;
som = 0 ;
for (i=0 ; i<4 ; i++)
{ printf ("donnez un entier ") ;
scanf ("%d", &n) ;
som += n ;
}
printf ("Somme : %d\n", som) ;
}

Ecrire un program m e r alisant e xacte m e nt la m m e ch os e , e n e m ployant, la place de l'instruction for :

22
Exe rcice s e n langage C
a) une instruction w h ile,
b) une instruction do ... w h ile.
___________________________________________________________________________

Sol
ution
a)
#include <stdio.h>
main()
{ int i, n, som ;
som = 0 ;
i = 0 ;
/* ne pas oublier cette "initialisation" */
while (i<4)
{ printf ("donnez un entier ") ;
scanf ("%d", &n) ;
som += n ;
i++ ;
/* ni cette "incrmentation" */
}
printf ("Somme : %d\n", som) ;
}

b)
#include <stdio.h>
main()
{ int i, n, som ;
som = 0 ;
i = 0 ;
/* ne pas oublier cette "initialisation" */
do
{ printf ("donnez un entier ") ;
scanf ("%d", &n) ;
som += n ;
i++ ;
/* ni cette "incrmentation" */
}
while (i<4) ;
/* attention, ici, toujours <4 */
printf ("Somme : %d\n", som) ;
}

III. Le s instructions de contrle

Exe rcice III.6


___________________________________________________________________________

Enonc
Quels r s ultats fournit le program m e s uivant :
#include <stdio.h>
main()
{ int n=0 ;
do
{ if (n%2==0) { printf ("%d est pair\n", n) ;
n += 3 ;
continue ;
}
if (n%3==0) { printf ("%d est multiple de 3\n", n) ;
n += 5 ;
}
if (n%5==0) { printf ("%d est multiple de 5\n", n) ;
break ;
}
n += 1 ;
}
while (1) ;
}

___________________________________________________________________________

Sol
ution

0 est pair
3 est multiple de 3
9 est multiple de 3
15 est multiple de 3
20 est multiple de 5

23

24

Exe rcice s e n langage C

Exe rcice III.7


___________________________________________________________________________

Enonc
Quels r s ultats fournit le program m e s uivant :
#include <stdio.h>
main()
{
int n, p ;
n=0 ;
while (n<=5) n++ ;
printf ("A : n = %d\n", n) ;
n=p=0 ;
while (n<=8) n += p++ ;
printf ("B : n = %d\n", n) ;
n=p=0 ;
while (n<=8) n += ++p ;
printf ("C : n = %d\n", n) ;
n=p=0 ;
while (p<=5) n+= p++ ;
printf ("D : n = %d\n", n) ;
n=p=0 ;
while (p<=5) n+= ++p ;
printf ("D : n = %d\n", n) ;
}

___________________________________________________________________________

Sol
ution
A
B
C
D

:
:
:
:

n
n
n
n

=
=
=
=

6
10
10
15

III. Le s instructions de contrle


D : n = 21

Exe rcice III.8


___________________________________________________________________________

Enonc
Quels r s ultats fournit le program m e s uivant :
#include <stdio.h>
main()
{
int n, p ;
n=p=0 ;
while (n<5) n+=2 ; p++ ;
printf ("A : n = %d, p = %d \n", n, p) ;
n=p=0 ;
while (n<5) { n+=2 ; p++ ; }
printf ("B : n = %d, p = %d \n", n, p) ;
}

___________________________________________________________________________

Sol
ution
A : n = 6, p = 1
B : n = 6, p = 3

Exe rcice III.9


___________________________________________________________________________

25

26

Exe rcice s e n langage C

Enonc
Quels r s ultats fournit le program m e s uivant :
#include <stdio.h>
main()
{
int i, n ;
for (i=0, n=0 ; i<5 ; i++) n++ ;
printf ("A : i = %d, n = %d\n", i, n) ;
for (i=0, n=0 ; i<5 ; i++, n++) {}
printf ("B : i = %d, n = %d\n", i, n) ;
for (i=0, n=50 ; n>10 ; i++, n-= i ) {}
printf ("C : i = %d, n = %d\n", i, n) ;
for (i=0, n=0 ; i<3 ; i++, n+=i, printf ("D : i = %d, n = %d\n", i, n) ) ;
printf ("E : i = %d, n = %d\n", i, n) ;
}

___________________________________________________________________________

Sol
ution
A
B
C
D
D
D
E

:
:
:
:
:
:
:

i
i
i
i
i
i
i

=
=
=
=
=
=
=

5,
5,
9,
1,
2,
3,
3,

n
n
n
n
n
n
n

=
=
=
=
=
=
=

5
5
5
1
3
6
6

III. Le s instructions de contrle

27

Exe rcice III.10


___________________________________________________________________________

Enonc
Ecrire un program m e q ui calcule les racine s carr e s d e nom bre s fournis e n donn e . Ils'arr te ra lorq u'on lui fournira la
valeur 0. Ilre fus e ra les valeurs ngative s . Son e x cution s e pr s e nte ra ainsi :
donnez un nombre
sa racine carre
donnez un nombre
svp positif
donnez un nombre
sa racine carre
donnez un nombre

positif : 2
est : 1.414214e+00
positif : -1
positif : 5
est : 2.236068e+00
positif : 0

R appe lons q ue la fonction s q rt fournit la racine carr e (double) de la valeur (double) q u'on lui fournit e n argum e nt.
___________________________________________________________________________

Sol
ution
Ile xiste beaucoup de "rdactions possibles " ;e n voici 3 :
#include <stdio.h>
#include <math.h>

/* indispensable pour sqrt (qui fourni un rsultat */


/*
de type double
*/

main()
{ double x ;
do
{ printf ("donnez un nombre positif : ") ;
scanf ("%le", &x) ;
if (x < 0) printf ("svp positif \n") ;
if (x <=0) continue ;
printf ("sa racine carre est : %le\n", sqrt (x) ) ;
}
while (x) ;
}

28

Exe rcice s e n langage C


#include <stdio.h>
#include <math.h>
main()
{ double x ;
do
{ printf ("donnez un nombre positif : ") ;
scanf ("%le", &x) ;
if (x < 0) { printf ("svp positif \n") ;
continue ;
}
if (x>0) printf ("sa racine carre est : %le\n", sqrt (x) ) ;
}
while (x) ;
}

#include <stdio.h>
#include <math.h>
main()
{ double x ;
do
{ printf ("donnez un nombre positif : ") ;
scanf ("%le", &x) ;
if (x < 0) { printf ("svp positif \n") ;
continue ;
}
if (x>0) printf ("sa racine carre est : %le\n", sqrt (x) ) ;
if (x==0) break ;
}
while (1) ;
}

R e m arque :
Ilne faut surtout pas oublie r #include < m ath .h > car, sinon, le com pilate ur consid re (e n l'absce nce du prototype )
q ue s q rt fournit un r s ultat de type int.

III. Le s instructions de contrle

Exe rcice III.11


___________________________________________________________________________

Enonc
Calculer la som m e des n pre m ie rs te rm es de la "s rie h arm oniq ue ", c'e s t- -dire la som m e :
1 + 1/2 + 1/3 + 1/4 + ..... + 1/n
La valeur de n s e ra lue e n donn e .
___________________________________________________________________________

Sol
ution

#include <stdio.h>
main()
{
int nt ;
float som ;
int i ;

/* nombre de termes de la srie harmonique */


/* pour la somme de la srie */

do
{ printf ("combien de termes : ") ;
scanf ("%d", &nt) ;
}
while (nt<1) ;
for (i=1, som=0 ; i<=nt ; i++) som += (float)1/i ;
printf ("Somme des %d premiers termes = %f", nt, som) ;
}

R e m arques :
1) R appe lons q ue dans :
som += (float)1/i

l'e xpre s s ion de droite e s t valu e e n conve rtissant d'abord 1 e t i e n float.

29

30

Exe rcice s e n langage C


Ilfaut vite r d' crire :
som += 1/i

auq ue lcas, les valeurs de 1/i seraient toujours nulles (sauf pour i=1) puiq ue l'op rate ur /, lors q u'ilporte s ur de s
e ntie rs, corre s pond la division e nti re .
D e m m e , e n crivant :
som += (float) (1/i)

le r s ultat ne s e rait pas plus satisfaisant puis q ue la conve rsion en flottant n'aurait lie u q u'apr s la division (e n e ntie r).
En re vanch e , on pourrait crire :
som += 1.0/i ;

2) Si l'on ch e rch ait e x cute r ce program m e pour de s valeurs lev e s d e n (e n pr voyant alors une variable de type
float ou double), on constate rait q ue la valeur de la som m e s e m ble "conve rge r" ve rs une lim ite (bie n q u'e n th orie la
s rie h arm oniq ue "dive rge "). Ce la provie nt tout sim plem e nt de ce q ue , d s q ue la valeur de 1/i e s t "pe tite " devant
som , le r s ultat de l'addition de 1/i e t de som e s t exactem ent som . O n pourrait toute fois am liore r le r s ultat e n
e ffe ctuant la som m e " l'e nve rs" (e n e ffe t, dans ce cas, le rapport e ntre la valeur ajoute r e t la som m e courante s e rait
plus faible q ue pr cdem m e nt)..

Exe rcice III.12


___________________________________________________________________________

Enonc
Affich e r un triangle isoc le form d'toiles . La h aute ur du triangle (c'e s t- -dire le nom bre de ligne s ) s e ra fourni e n
donn e , com m e dans l'e xe m ple ci-de s s ous. O n s'arrange ra pour q ue la derni re ligne du triangle s 'affich e s ur le bord
gauch e de l' cran.
combien de lignes ? 10
*
***
*****
*******
*********
***********
*************
***************

III. Le s instructions de contrle

31

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

___________________________________________________________________________

Sol
ution
#include <stdio.h>
#define car '*'

/* caractre de remplissage */

main()
{
int
int
int
int

/* nombre total de lignes */


/* compteur de ligne */
/* nombre d'espaces prcdent une toile */

nlignes ;
nl ;
nesp ;
j ;

printf ("combien de lignes ? ") ;


scanf ("%d", &nlignes) ;
for (nl=0 ; nl<nlignes ; nl++)
{ nesp = nlignes - nl - 1 ;
for (j=0 ; j<nesp ; j++)
putchar (' ') ;
for (j=0 ; j<2*nl+1 ; j++) putchar (car) ;
putchar ('\n') ;
}
}

Exe rcice III.13


___________________________________________________________________________

Enonc
Affich e r toute s les m ani re s possibles d'obte nir un franc ave c des pi ces de 2 ce ntim e s , 5 ce ntim e s e t 10 ce ntim e s . Dire
com bien de possibilit s ont t ainsi trouv e s . Le s r s ultats s e ront affich s com m e s uit :
1 F = 50 X 2c

32

Exe rcice s e n langage C


1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1

F
F
F
F
F
F
F
F
F
F
F
F
F
F
F
F
F
F
F
F
F
F

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

45
40
35
30
25
20
15
10
5
20
45
40
35
10
5
6
10
5
4
5
2
10

X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X

2c 2
2c 4
2c 6
2c 8
2c 10
2c 12
2c 14
2c 16
2c 18
5c
2c 1
2c 2
2c 4
2c 2
2c 4
5c 7
2c 8
2c 2
5c 8
2c 9
5c 9
10c

X
X
X
X
X
X
X
X
X

5c
5c
5c
5c
5c
5c
5c
5c
5c

X
X
X
X
X
X
X
X
X
X
X

10c
5c
5c
5c
5c
10c
10c
5c
10c
10c
10c

1
1
7
7

X
X
X
X

10c
10c
10c
10c

8 X 10c

En tout, il y a 66 faons de faire 1 F

___________________________________________________________________________

Sol
ution

#include <stdio.h>
main()
{
int nbf ;
int n10 ;
int n5 ;
int n2 ;

/*
/*
/*
/*

compteur du nombre de faons de faire 1 F */


nombre de pices de 10 centimes */
nombre de pices de 5 centimes */
nombre de pices de 2 centimes */

nbf = 0 ;
for (n10=0 ; n10<=10 ; n10++)
for (n5=0 ; n5<=20 ; n5++)
for (n2=0 ; n2<=50 ; n2++)

III. Le s instructions de contrle


if ( 2*n2 + 5*n5 + 10*n10 ==
{ nbf ++ ;
printf ("1 F = ") ;
if (n2) printf ("%2d X
if (n5) printf ("%2d X
if (n10) printf ("%2d X
printf ("\n") ;
}

33

100)

2c ", n2 ) ;
5c ", n5 ) ;
10c", n10) ;

printf ("\nEn tout, il y a %d faons de faire 1 F\n", nbf) ;


}

Exe rcice III.14


___________________________________________________________________________

Enonc
Ecrire un program m e q ui d te rm ine la nie m e valeur un (n tant fourni e n donn e ) de la "suite de Fibonacci" d finie
com m e s uit :
u1 = 1
u2 = 1
un = un-1 + un-2

pour n> 2

_______________________________________________________________

Sol
ution
#include <stdio.h>
main()
{
int u1, u2, u3 ;
int n ;
int i ;

/* pour "parcourir" la suite */


/* rang du terme demand */
/* compteur */

34

Exe rcice s e n langage C


do
{ printf ("rang du terme demand (au moins 3) ? ") ;
scanf ("%d", &n) ;
}
while (n<3) ;
u2 = u1 = 1 ;
i = 2 ;
while (i++ < n)
{ u3 = u1 + u2 ;
u1 = u2 ;
u2 = u3 ;
}

/* les deux premiers termes */


/* attention, l'algorithme ne fonctionne */
/*
que pour n > 2
*/

/*
autre formulation possible :
/* for (i=3 ; i<=n ; i++, u1=u2, u2=u3) u3 = u1 + u2 ;

*/
*/

printf ("Valeur du terme de rang %d : %d", n, u3) ;


}

Note z q ue , com m e l'accoutum e e n C, be aucoup de form ulations sont possibles . Nous e n avons d'ailleurs plac une
s e conde e n com m e ntaire de notre program m e .

Exe rcice III.15


___________________________________________________________________________

Enonc
Ecrire un program m e q ui trouve la plus grande e t la plus petite valeur d'une s ucce s s ion de note s (nom bre s e ntie rs e ntre 0
e t 20) fournie s e n donn e s , ainsi que le nom bre de fois o ce m axim um e t ce m inim um ont t attribu s . O n supposera
q ue les note s , e n nom bre non connu l'avance , s e ront te rm in e s par une valeur n gative . O n s'astre indra ne pas utiliser
de "tableau". L'e x cution du program m e pourra s e pr s e nte r ainsi :
donnez
donnez
donnez
donnez

une
une
une
une

note
note
note
note

(-1
(-1
(-1
(-1

pour
pour
pour
pour

finir)
finir)
finir)
finir)

:
:
:
:

12
8
13
7

III. Le s instructions de contrle


donnez
donnez
donnez
donnez
donnez

une
une
une
une
une

note
note
note
note
note

(-1
(-1
(-1
(-1
(-1

pour
pour
pour
pour
pour

finir)
finir)
finir)
finir)
finir)

:
:
:
:
:

11
12
7
9
-1

note maximale : 13 attribue 1 fois


note minimale : 7 attribue 2 fois

_______________________________________________________________

Sol
ution
#include <stdio.h>
main()
{
int
int
int
int
int

note ;
max ;
min ;
nmax ;
nmin ;

/*
/*
/*
/*
/*

note "courante" */
note maxi */
note mini */
nombre de fois o la note maxi a t trouve */
nombre de fois o la note mini a t trouve */

max = -1 ;
/* initialisation max (possible car toutes notes >=0 */
min = 21 ;
/* initialisation min (possible car toutes notes < 21) */
while (printf ("donnez une note (-1 pour finir) : "),
scanf ("%d", &note),
note >=0)
{ if (note == max) nmax++ ;
if (note > max) { max = note ;
nmax = 1 ;
}
if (note == min) nmin++ ;
if (note < min) { min = note ;
nmin = 1 ;
}
}
/* attention, si aucune note (cad si max<0) */
/* les rsultats sont sans signification
*/
if (max >= 0)
{ printf ("\nnote maximale : %d attribue %d fois\n", max, nmax) ;

35

36

Exe rcice s e n langage C


printf

("note minimale : %d attribue %d fois\n", min, nmin) ;

}
}

Exe rcice III.16


___________________________________________________________________________

Enonc
Ecrire un program m e q ui affich e la "table de m ultiplication" de s nom bres de 1 10, sous la form e s uivante :
I
1
2
3
4
5
6
7
8
9 10
----------------------------------------------1 I
1
2
3
4
5
6
7
8
9 10
2 I
2
4
6
8 10 12 14 16 18 20
3 I
3
6
9 12 15 18 21 24 27 30
4 I
4
8 12 16 20 24 28 32 36 40
5 I
5 10 15 20 25 30 35 40 45 50
6 I
6 12 18 24 30 36 42 48 54 60
7 I
7 14 21 28 35 42 49 56 63 70
8 I
8 16 24 32 40 48 56 64 72 80
9 I
9 18 27 36 45 54 63 72 81 90
10 I 10 20 30 40 50 60 70 80 90 100

_______________________________________________________________

Sol
ution
#include <stdio.h>
#define NMAX 10

/* nombre de valeurs */

main()
{
int i, j ;
/* affichage ligne en-tte */
printf ("
I") ;
for (j=1 ; j<=NMAX ; j++) printf ("%4d", j) ;

III. Le s instructions de contrle


printf ("\n") ;
printf ("-------") ;
for (j=1 ; j<=NMAX ; j++) printf ("----") ;
printf ("\n") ;
/* affichage des diffrentes lignes */
for (i=1 ; i<=NMAX ; i++)
{ printf ("%4d I", i) ;
for (j=1 ; j<=NMAX ; j++)
printf ("%4d", i*j) ;
printf ("\n") ;
}

37

IV : LES FO NCTIO NS

N.B. Ici, on ne trouve ra aucun e xe rcice faisant inte rve nir de s pointe urs, e t par cons q ue nt aucun e xe rcice m e ttant e n
oe uvre une transm ission d'argum e nts par adre s s e . De te ls e xe rcice s appara
tront dans le ch apitre s uivant.

Exe rcice IV.1


___________________________________________________________________________

Enonc
a) Que fournit le program m e s uivant :
#include <stdio.h>
main()
{
int n, p=5 ;
n = fct (p) ;
printf ("p = %d, n = %d\n", p, n) ;
}
int fct (int r)
{ return 2*r ;
}

b) Ajoute r une dclaration conve nable de la fonction fct :


- sous la form e la plus br ve possible (suivant la norm e ANSI),

40

Exe rcice s e n langage C


- sous form e d'un "prototype ".

_______________________________________________________________

Sol
ution
a) Bie n q u'ilne poss de pas de dclaration de la fonction fct, le program m e m ain e s t corre ct. En e ffe t, la norm e ANSI
autoris e q u'une fonction ne s oit pas dclar e , auq ue lcas e lle e s t considre com m e fournissant un r s ultat de type int.
Ce tte facilit e s t toute fois forte m e nt dcons e ille (e t e lle ne s e ra plus acce pt e d e C+ + ). Voici les r s ultats fournis par
le program m e :
p = 5, n = 10

b) La dclaration la plus br ve s e ra :
int fct () ;

La dclaration (vive m e nt cons e ille ), sous form e de prototype s e ra :


int fct (int) ;

ou, ve ntue llem e nt, sous form e d'un prototype "com plet" :
int fct (int r) ;

D ans ce dernie r cas, le nom r n'a aucune s ignification : on utilise souve nt le m m e nom (lors q u'on le conna
t!) q ue dans
l'e n-t te de la fonction, m ais ilpourrait s'agir de n'im porte q ue lautre nom de variable).

Exe rcice IV.2


___________________________________________________________________________

Enonc
Ecrire :

IV. Le s fonctions
41
- une fonction, nom m e f1, s e conte ntant d'affich e r "bonjour" (e lle ne possdera aucun argum e nt, ni valeur de
re tour),
- une fonction, nom m e f2, q ui affich e "bonjour" un nom bre de fois gal la valeur re ue e n argum e nt (int) e t q ui ne
re nvoie aucune valeur,
- une fonction, nom m e f3, q ui fait la m m e ch os e q ue f2, m ais q ui, de plus, re nvoie la valeur (int) 0.
Ecrire un pe tit program m e appe lant succe s s ive m e nt ch acune de ce s 3 fonctions, apr s les avoir conve nablem e nt dclar e s
sous form e d'un prototype .
_______________________________________________________________

Sol
ution
#include <stdio.h>
void f1 (void)
{
printf ("bonjour\n") ;
}
void f2 (int n)
{
int i ;
for (i=0 ; i<n ; i++)
printf ("bonjour\n") ;
}
int f3 (int n)
{
int i ;
for (i=0 ; i<n ; i++)
printf ("bonjour\n") ;
return 0 ;
}
main()
{
void f1 (void) ;
void f2 (int) ;
int f3 (int) ;
f1 () ;
f2 (3) ;
f3 (3) ;

42

Exe rcice s e n langage C


}

Exe rcice IV.3


___________________________________________________________________________

Enonc
Quels r s ultats fournira ce program m e :
#include <stdio.h>
int n=10, q=2 ;
main()
{
int fct (int) ;
void f (void) ;
int n=0, p=5 ;
n = fct(p) ;
printf ("A : dans main, n = %d, p = %d, q = %d\n", n, p, q) ;
f() ;
}
int fct (int p)
{
int q ;
q = 2 * p + n ;
printf ("B : dans fct,
return q ;
}
void f (void)
{
int p = q * n ;
printf ("C : dans f,
}

n = %d, p = %d, q = %d\n", n, p, q) ;

n = %d, p = %d, q = %d\n", n, p, q) ;

_______________________________________________________________

IV. Le s fonctions

43

Sol
ution
B : dans fct, n = 10, p = 5, q = 20
A : dans main, n = 20, p = 5, q = 2
C : dans f,
n = 10, p = 20, q = 2

Exe rcice IV.4


___________________________________________________________________________

Enonc
Ecrire une fonction q ui re oit e n argum e nts 2 nom bre s flottants e t un caract re e t q ui fournit un r s ultat corre s pondant
l'une des 4 op rations appliq u e s ses deux pre m ie rs argum e nts, e n fonction de la valeur du de rnie r, savoir : addition
pour le caract re + , soustraction pour -, m ultiplication pour *e t division pour / (tout autre caract re q ue l'un de s 4 cit s
s e ra inte rpr t com m e une addition). O n ne tie ndra pas com pte des ris q ues de division par z ro.
Ecrire un pe tit program m e (m ain) utilisant ce tte fonction pour e ffe ctue r les 4 op rations sur de ux nom bre s fournis e n
donn e .
_______________________________________________________________

Sol
ution
#include <stdio.h>
float oper (float v1, float
{
float res ;
switch (op)
{ case '+' : res = v1 +
break ;
case '-' : res = v1 break ;
case '*' : res = v1 *
break ;
case '/' : res = v1 /

v2, char op)

v2 ;
v2 ;
v2 ;
v2 ;

44

Exe rcice s e n langage C


default

break ;
: res = v1 + v2 ;

}
return res ;
}

main()
{
float oper (float, float, char) ;
float x, y ;

/* prototype de oper */

printf ("donnez deux nombres rels : ") ;


scanf ("%e %e", &x, &y) ;
printf
printf
printf
printf

("leur
("leur
("leur
("leur

somme est :
%e\n", oper
diffrence est : %e\n", oper
produit est :
%e\n", oper
quotient est :
%e\n", oper

(x,
(x,
(x,
(x,

y,
y,
y,
y,

'+')
'-')
'*')
'/')

)
)
)
)

;
;
;
;

Exe rcice IV.5


___________________________________________________________________________

Enonc
Transform e r le program m e (fonction + m ain) crit dans l'e xe rcice pr cdent de m ani re ce q ue la fonction ne dispose
plus q ue de 2 argum e nts, le caract re indiq uant la nature de l'op ration e ffe ctue r tant pr cis , ce tte fois, l'aide d'une
variable globale.
_______________________________________________________________

Sol
ution
#include <stdio.h>

IV. Le s fonctions
char op ;

45

/* variable globale pour la nature de l'opration */


/* attention : doit tre dclare avant d'tre utilise */

float oper (float v1, float


{
float res ;
switch (op)
{ case '+' : res = v1 +
break ;
case '-' : res = v1 break ;
case '*' : res = v1 *
break ;
case '/' : res = v1 /
break ;
default : res = v1 +
}
return res ;
}

v2)

v2 ;
v2 ;
v2 ;
v2 ;
v2 ;

main()
{
float oper (float, float) ;
/* prototype de oper */
float x, y ;
printf ("donnez deux nombres rels : ") ;
scanf ("%e %e", &x, &y) ;
op = '+' ;
printf ("leur somme est :
%e\n", oper (x, y) ) ;
op = '-' ;
printf ("leur diffrence est : %e\n", oper (x, y) ) ;
op = '*' ;
printf ("leur produit est :
%e\n", oper (x, y) ) ;
op = '/' ;
printf ("leur quotient est :
%e\n", oper (x, y) ) ;
}

R e m arque :
Ils'agissait ici d'un e xe rcice d'" cole" destin force r l'utilisation d'une variable globale. Dans la pratiq ue , on
vite ra le plus possible ce ge nre de program m ation q ui favoris e trop large m e nt les ris q ues d'"e ffe ts de bord".

46

Exe rcice s e n langage C

Exe rcice IV.6


___________________________________________________________________________

Enonc
Ecrire une fonction, sans argum e nt ni valeur de re tour, q ui s e conte nte d'affich e r, ch aq ue appe l, le nom bre totalde fois
o e lle a t appe le s ous la form e :
appel numro 3

_______________________________________________________________

Sol
ution
La m e illeure s olution consiste pr voir, au s e in de la fonction e n q ue s tion, une variable de clas s e s tatiq ue . Elle s e ra
initialise une seule fois z ro (ou toute autre valeur ve ntue llem e nt e xplicit e ) au dbut de l'e x cution du program m e .
Ici, nous avons, de plus, pr vu un pe tit program m e d'essai.
#include <stdio.h>
void fcompte (void)
{
static int i ;
/* il est inutile, mais pas dfendu, d'crire i=0 */
i++ ;
printf ("appel numro %d\n", i) ;
}
/* petit programme d'essai de fcompte */
main()
{ void fcompte (void) ;
int i ;
for (i=0 ; i<3 ; i++) fcompte () ;
}

L e ncore , la dm arch e consistant utiliser com m e com pte ur d'appe ls une variable globale (q ui de vrait alors tre connue
du program m e utilisate ur) e s t proscrire .

IV. Le s fonctions

47

Exe rcice IV.7


___________________________________________________________________________

Enonc
Ecrire 2 fonctions un argum e nt e ntie r e t une valeur de re tour e nti re pe rm e ttant de prciser si l'argum e nt re u e s t
m ultiple de 2 (pour la pre m i re fonction) ou m ultiple de 3 (pour la s e conde fonction).
Utiliser ces deux fonctions dans un pe tit program m e q ui lit un nom bre e ntie r e t q ui pr cis e s 'ile s t pair, m ultiple de 3
e t/ou m ultiple de 6, com m e dans ce t e xe m ple (ily a de ux e x cutions) :
donnez un entier : 9
il est multiple de 3
_______________
donnez
il est
il est
il est

un entier : 12
pair
multiple de 3
divisible par 6

_______________________________________________________________

Sol
ution
#include <stdio.h>
int mul2 (int n)
{
if (n%2) return 0 ;
else return 1 ;
}
int mul3 (int n)
{
if (n%3) return 0 ;
else return 1 ;
}
main()
{
int mul2 (int) ;

48

Exe rcice s e n langage C


int mul3 (int) ;
int n ;
printf ("donnez un entier : ")
scanf ("%d", &n) ;
if (mul2(n))
printf
if (mul3(n))
printf
if (mul2(n) && mul3(n)) printf
}

;
("il est pair\n") ;
("il est multiple de 3\n") ;
("il est divisible par 6\n") ;

V : TA BLEAUX ET
PO INTEURS

Exe rcice V.1


___________________________________________________________________________

Enonc
Quels r s ultats fournira ce program m e :
#include <stdio.h>
main()
{
int t [3] ;
int i, j ;
int * adt ;
for (i=0, j=0 ; i<3 ; i++) t[i] = j++ + i ;

/* 1 */

for (i=0 ; i<3 ; i++) printf ("%d ", t[i]) ;


printf ("\n") ;

/* 2 */

for (i=0 ; i<3 ; i++) printf ("%d ", *(t+i)) ;


printf ("\n") ;

/* 3 */

for (adt = t ; adt < t+3 ; adt++) printf ("%d ", *adt) ;
printf ("\n") ;

/* 4 */

for (adt = t+2 ; adt>=t ; adt--) printf ("%d ", *adt) ;

/* 5 */

50

Exe rcice s e n langage C


printf ("\n") ;
}

_______________________________________________________________

Sol
ution
/*1*/ re m plit le tableau ave c les valeurs 0 (0+ 0), 2 (1+ 1) e t 4 (2+ 2) ;on obtie ndrait plus sim plem e nt le m m e r s ultat
ave c l'e xpre s s ion 2*i.
/*2 */ affich e "classiquem e nt" les valeurs du tableau t, dans l'ordre "nature l".
/* 3 */ fait la m m e ch os e , e n utilisant le form alism e pointe ur au lie u du form alism e tableau. Ainsi, *(t+ i) e s t
parfaite m e nt q uivalent t[i].
/*4 */ fait la m m e ch os e , e n utilisant la "lvalue " adt ( laq ue lle on a affe ct initialem e nt l'adre s s e t du tableau) e t e n
"l'incr m e ntant" pour parcourir les diff re nte s adresses des 4 lm e nts du tableau.
/*5 */ affich e les valeurs de t, l'e nve rs, e n utilisant le m m e form alism e pointe ur q ue dans 4. O n aurait pu crire , de
faon q uivalente :
for (i=2 ; i>=0 ; i--) printf ("%d ", t[i]) ;

Voici les r s ultats fournis par ce program m e :


0
0
0
4

2
2
2
2

4
4
4
0

Exe rcice V.2


___________________________________________________________________________

V. Tableaux e t pointe urs

51

Enonc
Ecrire , de deux faons diff re nte s , un program m e q ui lit 10 nom bre s e ntie rs dans un tableau avant d'en rech e rch e r le plus
grand e t le plus petit :
a) e n utilisant uniq ue m e nt le "form alism e tableau",
b) e n utilisant le "form alism e pointe ur", ch aq ue fois q ue ce la e s t possible
_______________________________________________________________

Sol
ution
a) La program m ation e s t, ici, "classique". Nous avons sim plem e nt dfini un sym bole NVALdestin conte nir le nom bre
de valeurs du tableau. Note z bie n q ue la dclaration int t[NVAL] e s t acce pt e puis q ue NVAL e s t une "e xpre s s ion
constante ". En re vanch e , e lle ne l'aurait pas t s i nous avions dfini ce sym bole NVAL par une "constante sym boliq ue "
(const int NVAL = 10).
#include <stdio.h>
#define NVAL 10
main()
{
int i, min, max ;
int t[NVAL] ;

/* nombre de valeurs du tableau */

printf ("donnez %d valeurs\n", NVAL) ;


for (i=0 ; i<NVAL ; i++) scanf ("%d", &t[i]) ;
max = min = t[0] ;
for (i=1 ; i<NVAL ; i++)
{ if (t[i] > max) max = t[i] ;
if (t[i] < min) min = t[i] ;
}

/* ou max = t[i]>max ? t[i] : max */


/* ou min = t[i]<min ? t[i] : min */

printf ("valeur max : %d\n", max) ;


printf ("valeur min : %d\n", min) ;
}

b) O n pe ut re m place r syst m atiq ue m e nt, t[i] par *(t+ i)./ D e plus, dans scanf, on pe ut re m place r & t[i] par t+ i. Voici
finalem e nt le program m e obte nu :
#include <stdio.h>
#define NVAL 10
main()
{
int i, min, max ;

/* nombre de valeurs du tableau */

52

Exe rcice s e n langage C


int t[NVAL] ;
printf ("donnez %d valeurs\n", NVAL) ;
for (i=0 ; i<NVAL ; i++) scanf ("%d", t+i) ;

/* attention t+i et non *(t+i) */

max = min = *t ;
for (i=1 ; i<NVAL ; i++)
{ if (*(t+i) > max) max = *(t+i) ;
if (*(t+i) < min) min = *(t+i) ;
}
printf ("valeur max : %d\n", max) ;
printf ("valeur min : %d\n", min) ;
}

Exe rcice V.3


___________________________________________________________________________

Enonc
Soie nt deux tableaux t1 e t t2 d clar s ainsi :
float t1[10], t2[10] ;

Ecrire les instructions perm e ttant de re copie r, dans t1, tous les lm e nts positifs de t2, e n com pltant ve ntue llem e nt t1
par de s z ros. Ici, on ne ch e rch e ra pas fournir un program m e com plet e t on utilisera syst m atiq ue m e nt le form alism e
tableau.
_______________________________________________________________

Sol
ution
O n pe ut com m e nce r par re m plir t1 de z ros, avant d'y re copie r les lm e nts positifs de t2 :
int i, j ;
for (i=0 ; i<10 ; i++) t1[i] = 0 ;
/* i sert pointer dans t1 et j dans t2 */
for (i=0, j=0 ; j<10 ; j++)

V. Tableaux e t pointe urs

53

if (t2[j] > 0) t1[i++] = t2[j] ;

M ais, on pe ut re copie r d'abord dans t1 les lm e nts positifs de t2, avant de com plte r ve ntue llem e nt par de s z ros.
Ce tte deuxi m e form ulation, m oins sim ple q ue la pr cdente , s e r v lerait toute fois plus e fficace s ur de grands tableaux :
int i, j ;
for (i=0, j=0 ; j<10 ; j++)
if (t2[j] > 0) t1[i++] = t2[j] ;
for (j=i ; j<10 ; j++) t1[j] = 0 ;

Exe rcice V.4


___________________________________________________________________________

Enonc
Quels r s ultats fournira ce program m e :
#include <stdio.h>
main()
{ int t[4] = {10, 20, 30, 40} ;
int * ad [4] ;
int i ;
for (i=0 ; i<4 ; i++) ad[i] = t+i ;
for (i=0 ; i<4 ; i++) printf ("%d ", * ad[i]) ;
printf ("\n") ;
printf ("%d %d \n", * (ad[1] + 1), * ad[1] + 1) ;
}

/* 1 */
/* 2 */
/* 3 */

_______________________________________________________________

Sol
ution
Le tableau ad e s t un tableau de 4 lm e nts ;ch acun de ce s lm e nts e s t un pointe ur sur un int. L'instruction /* 1 */
re m plit le tableau ad ave c les adresses des 4 lm e nts du tableau t. L'instruction /*2 */ affich e finalem e nt les 4 lm e nts
du tableau t ;e n e ffe t, *ad[i] re pr s e nte la valeur situ e l'adre s s e ad[i]. /*2 */ e s t q uivalente ici :
for (i=0 ; i<4 ; i++) printf ("%d", t[i]) ;

54
Exe rcice s e n langage C
Enfin, dans l'instruction /*3 */, *(ad[1] + 1) re pr s e nte la valeur situ e l'e ntie r suivant ce lui d'adre s s e ad[1] ;ils'agit
donc de t[2]. En re vanch e , *ad[1] + 1 re pr s e nte la valeur situ e l'adre s s e ad[1] augm e nt e d e 1, autre m e nt dit t[1] +
1.
Voici, e n d finitive , les r s ultats fournis par ce program m e :
10 20 30 40
30 21

Exe rcice V.5


___________________________________________________________________________

Enonc
Soit le tableau t dclar ainsi :
float t[3] [4] ;

Ecrire les (s e ules ) instructions perm e ttant de calculer, dans une variable nom m e som , la som m e d e s lm e nts de t :
a) e n utilisant le "form alism e usueldes tableaux deux indice s ",
b) e n utilisant le "form alism e pointe ur".
_______________________________________________________________

Sol
ution
a) La pre m i re s olution ne pos e aucun problm e particulie r :
int i, j ;
som = 0 ;
for (i=0 ; i<3 ; i++)
for (j=0 ; j<4 ; j++)
som += t[i] [j] ;

b) Le form alism e pointe ur e s t ici m oins facile appliq ue r q ue dans le cas des tableaux un indice . En e ffe t, ave c, par
e xe m ple, float t[4], t e s t de type int * e t ilcorre s pond un pointe ur sur le pre m ie r lm e nt du tableau. Ilsuffit donc
d'incr m e nte r conve nablem e nt t pour parcourir tous les lm e nts du tableau.

V. Tableaux e t pointe urs


55
En re vanch e , ave c notre tableau float t [3] [4], t e s t du type pointe ur sur des tabl
eaux de 4 fl
ottants(type : float[4] *). La
notation *(t+ i) e s t g n ralem e nt inutilisable s ous ce tte form e puis q ue , d'une part, e lle corre s pond des valeurs de
tableaux de 4 flottants e t q ue , d'autre part, l'incr m e nt i porte , non plus sur de s flottants, m ais sur des blocs de 4
flottants ;par e xe m ple, t+ 2 re pr s e nte l'adresse du h uiti m e flottant, com pt partir de ce lui d'adre s s e t.
Une s olution consiste "conve rtir" la valeur de t e n un pointe ur de type float *. O n pourrait s e conte nte r de procder
ainsi :
float * adt ;
.....
adt = t ;

En e ffe t, dans ce cas, l'affe ctation e ntra


ne une conve rsion forc e d e t e n float *, ce q ui ne ch ange pas l'adre s s e
corre s pondante 1 (s e ule la nature du pointe ur a ch ang ).
G n ralem e nt, on y gagne ra e n lisibilit e n e xplicitant la conve rsion m ise en oeuvre l'aide de l'op rate ur de "cast".
Note z q ue , d'une part, ce la pe ut vite r ce rtains m e s s ages d'ave rtissem e nt ("w arnings") de la part du com pilate ur.
Voici finalem e nt ce q ue pourraie nt tre les instructions dem and e s :
int
int
som
adt
for

i ;
* adt ;
= 0 ;
= (float *) t ;
(i=0 ; i<12 ; i++)
som += * (adt+i);

Exe rcice V.6


___________________________________________________________________________

Enonc
Ecrire une fonction q ui fournit e n valeur de re tour la som m e d e s lm e nts d'un tableau de flottants transm is, ainsi q ue s a
dim e nsion, e n argum e nt.
Ecrire un pe tit program m e d'essai.

1 Attention, cel
a n'e s t vrai q ue parce que l'on passe de pointeurs sur des groupes d'lm ents un pointeur sur ces lm ents. Autrem ent dit, aucune

"contrainte d'alignem ent" ne risque de nuire ici. Iln'en irait pas de m m e, par exem ple, pour des conversions de ch ar *e n int *.

56
Exe rcice s e n langage C
_______________________________________________________________

Sol
ution
En ce q ui conce rne le tableau de flottants re u e n argum e nt, ilne pe ut tre transm is que par adresse. Quant au nom bre
d'lm e nt (de type int), nous le transm e ttrons classiquem e nt par valeur. L'e n-t te de notre fonction pourra s e pr s e nte r
sous l'une des form e s s uivante s :
float somme (float t[], int n)
float somme (float * t, int n)
float somme (float t[5], int n)

/* dconseill car laisse croire que t */


/*
est de dimension fixe 5
*/

En e ffe t, la dim e nsion r e lle de t n'a aucune incide nce s ur les instructions de la fonction e lle-m m e (e lle n'inte rvie nt pas
dans le calculde l'adresse d'un lm e nt du tableau2 e t e lle ne s e rt pas "alloue r" un e m place m e nt puis q ue le tableau e n
q ue s tion aura t allou dans la fonction appe lant som m e ).
Voici ce q ue pourrait tre la fonction de m and e :
float somme (float t[], int n)

int i ;
float s = 0 ;
for (i=0 ; i<n ; i++)
s += t[i] ;
return s ;

/* on pourrait crire somme (float * t, ... */


/*
ou encore somme (float t[4], ... */
/*
mais pas somme (float t[n], ... */

/* on pourrait crire s += * (t+i) ; */

Pour ce q ui e s t du program m e d'utilisation de la fonction som m e , on pe ut, l e ncore , crire le "prototype " sous
diff re nte s form e s :
float somme (float [], int ) ;
float somme (float * , int ) ;
float somme (float [5], int ) ;

/* dconseill car laisse croire que t */


/*
est de dimension fixe 5
*/

Voici un e xe m ple d'un te lprogram m e :


#include <stdio.h>
main()
2Iln'en irait pas de m m e pour des tabl
eaux plusieurs indices.

V. Tableaux e t pointe urs

57

{
float somme (float *, int) ;
float t[4] = {3, 2.5, 5.1, 3.5} ;
printf ("somme de t : %f\n", somme (t, 4) ) ;
}

Exe rcice V.7


___________________________________________________________________________

Enonc
Ecrire une fonction q ui ne re nvoie aucune valeur e t q ui d te rm ine la valeur m axim ale e t la valeur m inim ale d'un tableau
d'entie rs ( un indice ) de taille q ue lconq ue . Ilfaudra donc pr voir 4 argum e nts : le tableau, sa dim e nsion, le m axim um e t
le m inim um .
Ecrire un pe tit program m e d'essai.
_______________________________________________________________

Sol
ution
En langage C, un tableau ne pe ut tre transm is que par adresse (en toute rigue ur, C n'autoris e q ue la transm ission par
valeur m ais, dans le cas d'un tableau, on transm e t une valeur de type pointe ur q ui n'e s t rie n d'autre q ue l'adresse du
tableau!). En ce q ui conce rne s on nom bre d'lm e nts, on pe ut indiff re m m e nt e n transm e ttre l'adre s s e (sous form e d'un
pointe ur de type int*), ou la valeur ;ici, la s e conde s olution e s t la plus norm ale.
En re vanch e , e n ce q ui conce rne le m axim um e t le m inim um , ils ne peuve nt pas tre transm is par valeur, puis q u'ils
doive nt pr cis m e nt tre dte rm in s par la fonction. Ilfaut donc obligatoire m e nt pr voir de pas s e r de s pointe urs sur de s
float. L'e n-t te de notre fonction pourra donc s e pr s e nte r ainsi (nous ne donnons plus toute s les criture s possibles ) :
void maxmin (int t[], int n, int * admax, int * admin)

L'algorith m e de re ch e rch e de m axim um e t de m inim um pe ut tre calqu s ur ce lui de l'e xe rcice V.2, e n re m plaant m ax
par *adm ax e t m in par *adm in. Ce la nous conduit la fonction suivante :
void maxmin (int t[], int n, int * admax, int * admin)

58

Exe rcice s e n langage C


{
int i ;
*admax = t[1] ;
*admin = t[1] ;
for (i=1 ; i<n ; i++)
{ if (t[i] > *admax) *admax = t[i] ;
if (t[i] < *admin) *admin = t[i] ;
}
}

Si l'on souh aite vite r les "indire ctions" q ui apparais s e nt syst m atiq ue m e nt dans les instructions de com paraison, on pe ut
"travailler" te m poraire m e nt sur des variables locales la fonction (nom m e s ici m ax e t m in). Ce la nous conduit une
fonction de la form e s uivante :
void maxmin (int t[], int n, int * admax, int * admin)
{
int i, max, min ;
max = t[1] ;
min = t[1] ;
for (i=1 ; i<n ; i++)
{ if (t[i] > max) max = t[i] ;
if (t[i] < min) min = t[i] ;
}
*admax = max ;
*admin = min ;
}

Voici un pe tit e xe m ple de program m e d'utilisation de notre fonction :


#include <stdio.h>
main()
{
void maxmin (int [], int, int *, int *) ;
int t[8] = { 2, 5, 7, 2, 9, 3, 9, 4} ;
int max, min ;
maxmin (t, 8, &max, &min) ;
printf ("valeur maxi : %d\n", max) ;
printf ("valeur mini : %d\n", min) ;
}

V. Tableaux e t pointe urs

59

Exe rcice V.8


___________________________________________________________________________

Enonc
Ecrire une fonction q ui fournit e n re tour la som m e des valeurs d'un tableau de flottants
dim e nsions sont fournie s e n argum e nt.

deux indices dont les

_______________________________________________________________

Sol
ution
Par analogie ave c ce q ue nous avions fait dans l'e xe rcice V.6, nous pourrions songe r dclare r le tableau conce rn dans
l'e n-t te de la fonction sous la form e t[][]. M ais, ce la n'e s t plus possible car, ce tte fois, pour d te rm ine r l'adresse d'un
lm e nt t[i][j] d'un te ltableau, le com pilate ur doit e n conna
tre la deuxi m e dim e nsion.
Une s olution consiste considrer qu'on reoit un pointe ur (de type float*) sur le dbut du tableau e t d'en parcourir tous
les lm e nts (au nom bre de n*p si n et p d s igne nt les dim e nsions du tableau) com m e s i l'on avait affaire un tableau
une dim e nsion.
Ce la nous conduit ce tte fonction :
float somme (float * adt, int n, int p)
{
int i ;
float s ;
for (i=0 ; i<n*p ; i++) s += adt[i] ;
return s ;
}

/* ou s += *(adt+i) */

Pour utiliser une te lle fonction, la s e ule difficult consiste lui transm e ttre e ffe ctive m e nt l'adresse de dbut du tableau,
sous la form e d'un pointe ur de type int *. O r, ave c, par e xe m ple t[3][4], t, s'ilcorrre s pond bie n la bonne adre s s e , e s t
du type "pointe ur sur des tableaux de 4 flottants". A priori, toute fois, com pte te nu de la pr s e nce du prototype , la
conve rsion voulue s e ra m ise en oeuvre autom atiq ue m e nt par le com pilate ur. Toute fois, com m e nous l'avons dj dit dans
l'e xe rcice V.5, on y gagne ra e n lisibilit (e t e n ve ntue ls m e s s ages d'ave rtissem e nt!) e n faisant appe l l'op rate ur de
"cast".
Voici finalem e nt un e xe m ple d'un te lprogram m e d'utilisation de notre fonction :
#include <stdio.h>
main()
{

60

Exe rcice s e n langage C


float somme (float *, int, int) ;
float t[3] [4] = { {1,2,3,4}, {5,6,7,8}, {9,10,11,12} } ;
printf ("somme : %f\n", somme ((float *)t, 3, 4) ) ;
}

VI: LES CH A INES D E


CARACTERES

Exe rcice VI.1


___________________________________________________________________________

Enonc
Quels r s ultats fournira ce program m e :
#include <stdio.h>
main()
{
char * ad1 ;
ad1 = "bonjour" ;
printf ("%s\n", ad1) ;
ad1 = "monsieur" ;
printf ("%s\n", ad1) ;
}

_______________________________________________________________

Sol
ution
L'instruction ad1 = "bonjour" place dans la variable ad1 l'adresse de la ch a
ne constante "bonjour". L'instruction printf
("%s\n", ad1) s e conte nte d'affich e r la valeur de la ch a
ne dont l'adre s s e figure dans ad1, c'e s t- -dire , e n l'occurre nce
"bonjour". D e m ani re com parable, l'instruction ad1 = "m onsie ur" place l'adresse de la ch a
ne constante "m onsieur"

62
Exe rcice s e n langage C
dans ad1 ;l'instruction printf ("%s\n", ad1) affich e la valeur de la ch a
ne ayant m ainte nant l'adre s s e conte nue dans ad1,
c'e s t- -dire m ainte nant "m onsieur".
Finalem e nt, ce program m e affich e tout sim plem e nt :
bonjour
monsieur

O n aurait obte nu plus sim plem e nt le m m e r s ultat e n crivant :


printf ("bonjour\nmonsieur\n") ;

Exe rcice VI.2


___________________________________________________________________________

Enonc
Quels r s ultats fournira ce program m e :
#include <stdio.h>
main()
{
char * adr = "bonjour" ;
int i ;
for (i=0 ; i<3 ; i++) putchar (adr[i]) ;
printf ("\n") ;
i = 0 ;
while (adr[i]) putchar (adr[i++]) ;
}

/* 1 */
/* 2 */

/* 3 */

_______________________________________________________________

Sol
ution
La dclaration /*1 */ place dans la variable adr, l'adresse de la ch a
ne constante bonjour. L'instruction /*2 */ affich e
les caract re s adr[0], adr[1] e t adr[2], c'e s t- -dire les 3 pre m ie rs caract res de ce tte ch a
ne . L'instruction /*3 */ affich e
tous les caract re s partir de ce lui d'adre s s e adr, tant q ue l'on a pas affaire un caract re nul;com m e notre ch a
ne

VI. Le s ch a
ne s d e caract re s
63
"bonjour" e s t pr cis m e nt te rm in e par un te lcaract re nul, ce tte instruction affich e finalem e nt, un par un, tous les
caract res de "bonjour".
En d finitive , le program m e fournit sim plem e nt les r s ultats suivants :
bon
bonjour

Exe rcice VI.3


___________________________________________________________________________

Enonc
Ecrire le program m e pr cdent (Exe rcice VI.2), sans util
iser l
e "form al
ism e tabl
eau" (ile xiste plusieurs solutions).
_______________________________________________________________

Sol
ution
Voici de ux solutions possibles :
a) O n pe ut re m place r syst m atiq ue m e nt la notation adr[i] par *(adr+ i), ce q ui conduit ce program m e :
#include <stdio.h>
main()
{
char * adr = "bonjour" ;
int i ;
for (i=0 ; i<3 ; i++) putchar (*(adr+i)) ;
printf ("\n") ;
i = 0 ;
while (adr[i]) putchar (*(adr+i++)) ;
}

b) O n pe ut galem e nt parcourir notre ch a


ne , non plus l'aide d'un "indice " i, m ais e n incr m e ntant un pointe ur de type
ch ar *: ilpourrait s'agir tout sim plem e nt de adr, m ais gnralem e nt, on pr f re ra ne pas dtruire ce tte inform ation e t e n
e m ploye r une copie :

64

Exe rcice s e n langage C


#include <stdio.h>
main()
{
char * adr = "bonjour" ;
char * adb ;
for (adb=adr ; adb<adr+3 ; adb++) putchar (*adb) ;
printf ("\n") ;
adb = adr ;
while (*adb) putchar (*(adb++)) ;
}

Note z bie n q ue s i nous incr m e ntions directe m e nt adr dans la pre m i re instruction d'affich age , nous ne disposerions plus
de la "bonne adre s s e " pour la deuxi m e instruction d'affich age .

Exe rcice VI.4


___________________________________________________________________________

Enonc
Ecrire un program m e q ui de m ande l'utilisate ur de lui fournir un nom bre e ntie r e ntre 1 e t 7 e t q ui affich e le nom du jour
de la s e m aine ayant le num ro indiq u (lundi pour 1, m ardi pour 2, ... dim anch e pour 7).
_______________________________________________________________

Sol
ution
Une dm arch e consiste cr e r un "tableau de 7 pointe urs sur de s ch a
ne s ", corre s pondant ch acune au nom d'un jour de
la s e m aine . Com m e ce s ch a
ne s s ont ici constante s , ile s t possible de cr e r un te ltableau par une dclaration com portant
une intialisation de la form e :
char * jour [7] = { "lundi", "mardi", ...

N'oublie z pas alors q ue jour[0] contie ndra l'adresse de la pre m i re ch a


ne , c'e s t- -dire l'adresse de la ch a
ne constante
"lundi" ;jour[1] contie ndra l'adresse de "m ardi", ...
Pour affich e r la valeur de la ch a
ne de rang i, ilsuffit de re m arq ue r q ue s on adre s s e e s t sim plem e nt jour[i-1].
D 'o le program m e dem and :

VI. Le s ch a
ne s d e caract re s

65

#include <stdio.h>
main()
{
char * jour [7] = { "lundi",
"mardi", "mercredi", "jeudi",
"vendredi", "samedi", "dimanche"
} ;
int i ;
do
{ printf ("donnez un nombre entier entre 1 et 7 : ") ;
scanf ("%d", &i) ;
}
while ( i<=0 || i>7) ;
printf ("le jour numro %d de la semaine est %s", i, jour[i-1]) ;
}

Exe rcice VI.5


___________________________________________________________________________

Enonc
Ecrire un program m e q ui lit deux nom bre s e ntie rs fournis obligatoire m e nt sur une m m e ligne . Le program m e ne devra
pas "s e plante r" e n cas de r pons e incorre cte (caract re s invalides) com m e le fe rait scanf ("%d %d", ...) m ais
sim plem e nt affich e r un m e s s age e t redem ande r une autre r pons e . Ildevra e n aller de m m e lors q ue la r pons e fournie
ne com porte pas as s e z d'inform ations. En re vanch e , lors q ue la r pons e com porte ra trop d'inform ations, les derni re s
devront tre ignor e s .
Le traite m e nt (dem ande de 2 nom bre s e t affich age ) devra s e poursuivre jus q u' ce q ue le pre m ie r nom bre fourni soit 0.
Voici un e xe m ple d'excution d'un te lprogram m e :
--- donnez deux
rponse errone
merci pour 2 15
--- donnez deux
rponse errone
merci pour 4 12
--- donnez deux
merci pour 4 8
--- donnez deux

entiers :
- redonnez-la : 2 15
entiers : 5
- redonnez-la : 4 12
entiers : 4 8 6 9
entiers : 5 3

66

Exe rcice s e n langage C


rponse errone - redonnez-la : 5 23
merci pour 5 23
--- donnez deux entiers : 0 0
merci pour 0 0

R e m arque : on pe ut utiliser les fonctions ge ts e t sscanf.


_______________________________________________________________

Sol
ution
Com m e le s ugg re la re m arq ue de l' nonc , on pe ut r s oudre les problm e s pos s e n e ffe ctuant e n de ux te m ps la lecture
d'un couple d'entie rs :
- lecture d'une ch a
ne de caract re s (c'e s t- -dire une s uite de caract re s absol
um ent quel
conques, valide par
"re turn") ave c la fonction ge ts,
- "dcodage " de ce tte ch a
ne ave c sscanf, suivant un "form at", d'une m ani re com parable ce q ue fe rait scanf,
partir de s on "tam pon d'e ntr e ".
R appe lons q ue sscanf, tout com m e scanf, fournit e n re tour le nom bre d'inform ations corre cte m e nt lue s , de sorte q u'il
suffit de r p te r les deux op rations prcdente s jus q u' ce q ue la valeur fournie par sscanf soit gale 2.
L' nonc ne fait aucune h ypoth s e s ur le nom bre m axim alde caract re s q ue l'utilisate ur pourra tre am e n fournir. Ici,
nous avons suppos q u'au plus 128 caract re s s e raie nt fournis ;ils'agit l d'une h ypoth s e q ui, dans la pratiq ue , s'av re
r aliste , dans la m e s ure o on ris q ue rare m e nt de frappe r de s ligne s plus longue s ;de surcro
t, ils'agit m m e d'une
lim itation "nature lle" de ce rtains e nvironne m e nts (DOS, e n particulie r).
Voici le program m e dem and :
#include <stdio.h>
#define LG 128
main()
{
int n1, n2 ;
int compte ;
char ligne [LG+1] ;

/* longueur maximale d'une ligne */

/* entiers lire en donne */


/* pour la valeur de retour de sscanf */
/* pour lire une ligne (+1 pour \0) */

/* boucle de lecture des diffrents couples de valeurs */


do
{

/* boucle de lecture d'un couple de valeur jusqu' OK */


printf ("--- donnez deux entiers : ") ;
do
{ gets (ligne) ;
compte = sscanf (ligne, "%d %d", &n1, &n2) ;

VI. Le s ch a
ne s d e caract re s

67

if (compte<2) printf ("rponse errone - redonnez-la : ") ;


}
while (compte < 2) ;
printf ("merci pour %d %d\n", n1, n2) ;
}
while (n1) ;
}

R e m arques
1) Si l'utilisate ur fournit plus de caract re s q u'iln'e n faut pour form e r 2 nom bre s e ntie rs, ce s caract re s (lus dans
ligne ) ne s e ront pas utiliss par sscanf ;m algr tout, ils ne seront pas e xploit s ult rie ure m e nt puis q ue , lors q ue l'on
redem ande ra 2 nouve aux e ntie rs, on re lira une nouve lle ch a
ne par ge ts.
2) Si l'on souh aite absolum e nt pouvoir lim ite r la longue ur de la ch a
ne lue au clavie r, e n utilisant des instructions
1
"portables ", ilfaut s e tourne r ve rs la fonction fge ts destin e lire une ch a
ne dans un fich ie r, e t l'appliq ue r stdin.
O n re m place ra l'instruction ge ts (ligne ) par fge ts (ligne , LG, stdin) q ui lim ite ra LG le nom bre de caract re s pris e n
com pte . Note z toute fois q ue , dans ce cas, les caract re s e xcdentaire s (e t donc non "vus" par fge ts) re s te ront
disponibles pour une proch aine lecture (ce q ui n'e s t pas pire q ue dans la situation actue lle o ce s caract re s
vie ndraie nt cras e r de s e m place m e nts m m oire s itu s au-de l du tableau ligne !).
D ans ce rtaine s im plm e ntations (Turbo/Borland C/C+ + e t Quick C/C M icrosoft), il e xiste une fonction (non
portable, puis q ue non pr vue par la norm e ANSI) nom m e cge ts q ui, utilise la place de ge ts (ou fge ts) pe rm e t de
r gler le problm e voq u . En e ffe t, cge ts pe rm e t de lire une ch a
ne , e n lim itant le nom bre de caract re s
e ffe ctive m e nt fournis au clavie r : iln'e s t pas possible l'utilisate ur d'e n frappe r plus q ue pr vu, de s orte q ue le ris q ue
de caract re s e xcdentaire s n'e xiste plus!

Exe rcice VI.6


___________________________________________________________________________

1 M ais, si vous ral


isez ces exercices en accom pagnem ent d'un cours de langage C, ile s t probable q ue vous n'aurez pas e ncore tudi la fonction

fge ts (en gnral, elle e s t introduite dans le ch apitre relatif au traitem ent des fich iers). Certains e xercices de la s e conde partie de cet ouvrage feront
appel fgets, et/ou s s canf.

68

Exe rcice s e n langage C

Enonc
Ecrire un program m e dte rm inant le nom bre de lettre s e (m inuscule) conte nues dans un te xte fourni e n donn e s ous
form e d'une seule ligne ne dpassant pas 128 caract re s . O n ch e rch e ra, ici, n'utiliser aucune des fonctions de
traite m e nt de ch a
ne .
_______________________________________________________________

Sol
ution
Com pte te nu de s contrainte s im pos e s par l' nonc , nous ne pouvons pas faire appe l la fonction strlen. Pour "e xplore r"
notre ch a
ne , nous utiliserons le fait q u'e lle e s t te rm in e par un caract re nul(\0]. D'o le program m e propos :
#define LG_LIG 128
#include <stdio.h>
main()
{
char ligne [LG_LIG+1] ;
int i ;
int ne ;

/* pour lire une ligne au clavier


+1 pour \0 */
/* pour explorer les diffrents caractres de ligne */
/* pour compter le nombre de 'e' */

printf ("donnez un texte de moins d'une ligne : \n") ;


gets (ligne) ;
ne = 0 ;
i = 0 ;
while (ligne[i])

if (ligne[i++] == 'e') ne++ ;

printf ("votre texte comporte %d lettres e", ne) ;


}

Exe rcice VI.7


___________________________________________________________________________

Enonc
Ecrire un program m e q ui lit, e n donn e , un ve rbe du prem ie r groupe e t q ui e n affich e la conjugaison au pr s e nt de
l'indicatif, sous la form e :

VI. Le s ch a
ne s d e caract re s

69

je chante
tu chantes
il chante
nous chantons
vous chantez
ils chantent

O n s'assure ra q ue le m ot fourni s e te rm ine bien par "er". O n supposera q u'ils'agit d'un ve rbe r gulie r ;autre m e nt dit,
on adm e ttra q ue l'utilisate ur ne fournira pas un ve rbe te lq ue m ange r (le program m e affich e rait alors : nous m angons!).
_______________________________________________________________

Sol
ution
O n lira "classiquem e nt" un m ot, sous form e d'une ch a
ne l'aide de la fonction ge ts. Pour v rifie r sa te rm inaison par
"e r", on com pare ra ave c la ch a
ne constante "e r", la ch a
ne ayant com m e adre s s e l'adresse de fin du m ot, dim inu e d e 2.
L'adresse de fin se dduira de l'adresse de dbut e t de la longue ur de la ch a
ne (obte nue par la fonction strlen).
Quant la com paraison voulue , e lle s e fe ra l'aide de la fonction strcm p ;rappe lons q ue ce tte derni re re oit e n
argum e nt 2 pointe urs sur de s ch a
ne s e t q u'e lle fournit e n re tour une valeur nulle lors q ue les deux ch a
ne s
corre s pondante s s ont gales e t une valeur non nulle dans tous les autre s cas.
Les diff re nte s pe rsonnes du ve rbe s 'obtie nne nt e n re m plaant, dans la ch a
ne e n q ue s tion, la te rm inaison "e r" par une
te rm inaison appropri e . O n pe ut, pour ce la, utiliser la fonction strcpy q ui re copie une ch a
ne donne (ici la te rm inaison)
une adresse donn e (ici, ce lle dj utilise dans strcm p pour v rifie r q ue le ve rbe s e te rm ine bien par "er").
Les diff re nte s te rm inaisons possibles s e ront ranges dans un tableau de ch a
ne s constante s (plus prcism e nt, dans un
tableau de pointe urs sur de s ch a
ne s constante s ). Nous fe rons de m m e pour les diff re nts suje ts (je , tu...) ;e n re vanch e ,
ici, nous ne ch e rch e rons pas les "concat ne r" au ve rbe conjugu ;nous nous conte ntons de les crire , au m om e nt
opportun.
Voici finalem e nt le program m e dem and :
#include <stdio.h>
#include <string.h>
#define LG_VERBE 30
/* longueur maximale du verbe fourni en donne */
main()
{ char verbe [LG_VERBE+1] ;
/* verbe conjuguer +1 pour \0 */
char * sujet [6] = { "je", "tu", "il", "nous", "vous", "ils"} ; /* sujets */
char * term [6] = { "e", "es", "e", "ons", "ez",
"ent" } ;/* terminaisons */
int i ;
char * adterm ;
/* pointeur sur la terminaison du verbe */

70

Exe rcice s e n langage C


do
{ printf ("donnez un verbe rgulier du premier groupe : ") ;
gets (verbe) ;
adterm = verbe + strlen(verbe) - 2 ;
}
while (strcmp (adterm, "er") ) ;
printf ("conjugaison l\'indicatif prsent :\n") ;
for (i=0 ; i<6 ; i++)
{ strcpy (adterm, term[i]) ;
printf ("%s %s\n", sujet[i], verbe) ;
}
}

R e m arque : rappe lons q ue strcpy re copie (sans aucun contrle) la ch a


ne dont l'adre s s e e s t fournie e n pre m ie r argum e nt
(c'e s t- -dire , e n fait, tous les caract re s partir de ce tte adre s s e , jus q u' ce q ue l'on re ncontre un \0) l'adre s s e fournie
e n s e cond argum e nt ;de plus, e lle com plte bien le tout ave c un caract re nulde fin de ch a
ne .

Exe rcice VI.8


___________________________________________________________________________

Enonc
Ecrire un program m e q ui supprim e toute s les lettre s e (m inuscule) d'un te xte de m oins d'une ligne (ne dpassant pas 128
caract re s ) fourni e n donn e . O n s'arrange ra pour q ue le te xte ainsi m odifi s oit cr e n m m oire , l
a pl
ace de
l
'ancien.
N.B. on pourra utiliser la fonction strch r.
_______________________________________________________________

Sol
ution
La fonction strch r pe rm e t de trouve r un caract re donn dans une ch a
ne . Elle e s t donc tout fait appropri e pour
localiser les 'e ' ;ilfaut toute fois note r q ue , pour localiser tous les 'e ', ile s t n ce s s aire de r p te r l'appe lde ce tte

VI. Le s ch a
ne s d e caract re s
71
fonction, e n m odifiant ch aq ue fois l'adresse de dbut de la ch a
ne conce rn e (ilfaut vite r de boucler sur la re ch e rch e
du m m e caract re 'e ').
La fonction strch r fournit l'adre s s e laq ue lle on a trouv le pre m ie r caract re indiq u (ou la valeur 0 si ce caract re
n'e xiste pas). La suppre s s ion du 'e ' trouv pe ut s e faire e n re copiant le "re s te " de la ch a
ne l'adre s s e o l'on a
trouv le 'e '.
Voici une s olution possible :

#include <stdio.h>
#include <string.h>
#define LG_LIG 128
#define CAR 'e'

/* longueur maximum d'une ligne de donnes */


/* caractre supprimer */

main()
{
char ligne [LG_LIG+1] ;
char * adr ;

/* pour lire une ligne


+1 pour \0 */
/* pointeur l'intrieur de la ligne */

printf ("donnez un texte de moins d'une ligne : \n") ;


gets (ligne) ;
adr = ligne ;
while (adr = strchr (adr,'e') ) strcpy (adr, adr+1) ;
printf ("voici votre texte, priv des caractres %c :\n") ;
puts (ligne) ;
}

VII : LES STRUCTURES

Exe rcice VII.1


___________________________________________________________________________

Enonc
Soit le m od le (type ) de structure s uivant :
struct s_point
{ char c ;
int x, y ;
} ;

Ecrire une fonction q ui re oit e n argum e nt une s tructure de type s_point e t q ui e n affich e le conte nu sous la form e :
point B de coordonnes 10 12

a) En transm e ttant e n argum e nt la val


eur de la structure conce rn e ,
b) En transm e ttant e n argum e nt l'adresse de la structure conce rn e .
D ans les deux cas, on crira un pe tit program m e d'essai de la fonction ainsi ralise.
_______________________________________________________________

Sol
ution
a) Voici la fonction de m and e :
#include <stdio.h>

74

Exe rcice s e n langage C


void affiche (struct s_point p)
{
printf ("point %c de coordonnes %d %d\n", p.c, p.x, p.y) ;
}

Note z q ue s a com pilation n ce s s ite obligatoire m e nt la dclaration du type s_point, c'e s t- -dire les instructions :
struct s_point
{ char c ;
int x, y ;
} ;

Voici un pe tit program m e q ui affe cte les valeurs 'A', 10 e t 12 aux diff re nts ch am ps d'une structure nom m e s , avant
d'en affich e r les valeurs l'aide de la fonction pr cdente :
main()
{
void affiche (struct s_point) ;
struct s_point s ;
s.c = 'A' ;
s.x = 10 ;
s.y = 12 ;
affiche (s) ;
}

// dclaration (prototype) de affiche

Nature llem e nt, la re m arq ue pr cdente s 'appliq ue galem e nt ici. En pratiq ue , la dclaration de la structure s_point
figure ra dans un fich ie r d'e xte nsion h q ue l'on s e conte nte ra d'incorpore r par #include au m om e nt de la com pilation. D e
m m e , ile s t n ce s s aire d'inclure stdio.h .
b) Voici la nouve lle fonction de m and e :
#include <stdio.h>
void affiche (struct s_point * adp)
{
printf ("point %c de coordonnes %d %d\n", adp->c, adp->x, adp->y) ;
}

Note z q ue l'on doit, ce tte fois, faire appe l l'op rate ur -> , la place de l'op rate ur point (.), puis q ue l'on "travaille"
sur un pointe ur sur une s tructure , e t non plus sur la valeur de la structure e lle-m m e . Toute fois l'usage de -> n'e s t pas
totalem e nt indispensable, dans la m e s ure o, par e xe m ple, adp-> x e s t q uivalent (*adp).x.
Voici l'adaptation du program m e d'essai pr cdent :
main()
{

VII. Le s s tructure s

75

void affiche (struct s_point *) ;


struct s_point s ;
s.c = 'A' ;
s.x = 10 ;
s.y = 12 ;
affiche (&s) ;
}

R e m arque :
Au lie u d'affe cte r de s valeurs aux ch am ps c, x e t y de notre s tructure s (dans les deux program m es d'essai), nous
pourrions (ici) utiliser les possibilit s d'initial
isation offe rte s par le langage C, e n crivant :
struct s_point s = {'A', 10, 12} ;

Exe rcice VII.2


___________________________________________________________________________

Enonc
Ecrire une fonction q ui "m e t z ro" les diff re nts ch am ps d'une structure du type s_point (dfini dans l'e xe rcice
pr cdent) q ui lui e s t transm ise en argum e nt. La fonction ne com porte ra pas de valeur de re tour.
_______________________________________________________________

Sol
ution
Ici, bie n q ue l' nonc ne le pr cis e pas, ile s t n ce s s aire de transm e ttre la fonction conce rn e , non pas la valeur, m ais
l'adresse de la structure "re m e ttre z ro". Voici la fonction de m and e (ici, nous avons re produit la dclaration de
s_point) :
#include <stdio.h>
struct s_point
{ char c ;
int x, y ;
} ;
void raz (struct s_point * adr)

76

Exe rcice s e n langage C


{

adr->c = 0 ;
adr->x = 0 ;
adr->y = 0 ;

Voici, titre indicatif, un pe tit program m e d'essai (sa com pilation n ce s s ite la dclaration de s_point, ainsi que le fich ie r
stdio.h ) :
main()
{
struct s_point p ;
void raz (struct s_point *) ;
// dclaration de raz
raz (&p) ;
/* on crit c en %d pour voir son code */
printf ("aprs : %d %d %d", p.c, p.x, p.y) ;
}

Exe rcice VII.3


___________________________________________________________________________

Enonc
Ecrire une fonction q ui re oit e n argum e nt l'adresse d'une s tructure du type s_point (dfini dans l'e xe rcice VII.1) e t q ui
re nvoie e n r s ultat une s tructure de m m e type corre s pondant un point de m m e nom (c) e t de coordonn e s oppos e s .
Ecrire un pe tit program m e d'essai.
_______________________________________________________________

Sol
ution
Bie n q ue l' nonc ne pr cis e rie n, le r s ultat de notre fonction ne pe ut tre transm is que par valeur. En e ffe t, ce r s ultat
doit tre cr au s e in de la fonction e lle-m m e ;ce la signifie q u'ils e ra d truit d s la sortie de la fonction ;e n transm e ttre
l'adre s s e re vie ndrait re nvoye r l'adre s s e d e q ue lque ch ose destin dispara
tre ...
Voici ce q ue pourrait tre notre fonction (ici, e ncore , nous avons re produit la dclaration de s_point) :
#include <stdio.h>
struct s_point
{ char c ;

VII. Le s s tructure s

77

int x, y ;
} ;
struct s_point sym (struct s_point * adr)
{ struct s_point res ;
res.c = adr->c ;
res.x = - adr->x ;
res.y = - adr->y ;
return res ;
}

Note z la "dissym trie " d'instructions te lles q ue re s .c = adr-> c ;on y fait appe l l'op rate ur . gauch e e t l'op rate ur
-> droite (on pourrait ce pe ndant crire re s .c = (*adr).c.
Voici un e xe m ple d'essai de notre fonction (ici, nous avons utilis les possibilits d'initialisation d'une s tructure pour
donne r de s valeurs p1) :
main()
{
struct s_point sym (struct s_point *) ;
struct s_point p1 = {'P', 5, 8} ;
struct s_point p2 ;
p2 = sym (&p1) ;
printf ("p1 = %c %d %d\n", p1.c, p1.x, p1.y) ;
printf ("p2 = %c %d %d\n", p2.c, p2.x, p2.y) ;
}

Exe rcice VII.4


___________________________________________________________________________

Enonc
Soit la structure s uivante , re pr s e ntant un point d'un plan :
struct s_point
{ char c ;
int x, y ;
} ;

1) Ecrire la dclaration d'un tableau (nom m courbe ) de NP points (NP suppos dfini par une instruction #de fine )
2) Ecrire une fonction (nom m e affich e ) q ui affich e les valeurs des diff re nts "points" du tableau courbe , transm is en
argum e nt, sous la form e :

78

Exe rcice s e n langage C


point D de coordonnes 10 2

3) Ecrire un program m e q ui :
- lit e n donnes des valeurs pour le tableau courbe ;on utilisera de prf re nce les fonctions ge ts e t sscanf, de
pr f re nce scanf (voir ve ntue llem e nt l'e xe rcice VI.5) ;on supposera q u'une ligne de donne ne peut pas dpas s e r
128 caract re s ,
- fait appe l la fonction pr cdente pour les affich e r.
_______________________________________________________________

Sol
ution
1) Ilsuffit de dclare r un tableau de s tructure s :
struct s_point courbe [NP] ;

2) Com m e courbe e s t un tableau, on ne pe ut q u'e n transm e ttre l'adre s s e e n argum e nt de affich e . Ile s t pr f rable de
pr voir galem e nt e n argum e nt le nom bre de points. Voici ce q ue pourrait tre notre fonction :
void affiche (struct s_point courbe [], int np)
/* courbe : adresse de la premire structure du tableau */
/*
(on pourrait crire struct s_point * courbe)
*/
/* np : nombre de points de la courbe */
{
int i ;
for (i=0 ; i<np ; i++)
printf ("point %c de coordonnes %d %d\n", courbe[i].c,
courbe[i].x, courbe[i].x) ;
}

Com m e pour n'im porte q ue ltableau une dim e nsion transm is en argum e nt, ile s t possible de ne pas e n m e ntionne r la
dim e nsion dans l'e n-t te de la fonction. Bie n e nte ndu, com m e , e n fait, l'ide ntificate ur courbe n'e s t q u'un pointe ur de
type s_point*(pointe ur sur la pre m i re s tructure du tableau), nous aurions pu galem e nt crire s_point*courbe .
Note z q ue , com m e l'accoutum e , le "form alism e tableau" e t le "form alism e pointe ur" pe uve nt tre indiff re m m e nt
utiliss (voire com bin s ). Par e xe m ple, notre fonction aurait pu galem e nt s' crire :
void affiche (struct s_point * courbe, int np)
{
struct s_point * adp ;
int i ;

VII. Le s s tructure s

79

for (i=0, adp=courbe ; i<np ; i++, adp++)


printf ("point %c de coordonnes %d %d", courbe->c, courbe->x, courbe->y) ;
}

3) Com m e nous avons appris le faire dans l'e xe rcice VI.5, nous lirons les inform ations re lative s aux diff re nts points
l'aide des deux fonctions :
- ge ts, pour lire , sous form e d'une ch a
ne , une ligne d'inform ation,
- sscanf, pour d code r suivant un form at le conte nu de la ch a
ne ainsi lue .
Voici ce q ue pourrait le program m e dem and (ici, nous avons re produit, la fois la dclaration de s_point e t la fonction
affich e pr cdente ) :
#include <stdio.h>
struct s_point
{ char c ;
int x, y ;
} ;
#define NP 10
/* nombre de points d'une courbe */
#define LG_LIG 128
/* longueur maximale d'une ligne de donne */
main()
{ struct s_point courbe [NP] ;
int i ;
char ligne [LG_LIG+1] ;
void affiche (struct s_point [], int) ;
/* lecture des diffrents points de la courbe */
for (i=0 ; i<NP ; i++)
{ printf ("nom (1 caractre) et coordonnes point %d : ", i+1) ;
gets (ligne) ;
sscanf (ligne, "%c %d %d", &courbe[i].c, &courbe[i].x, &courbe[i].y) ;
}
affiche (courbe, NP) ;
}
void affiche (struct s_point courbe [], int np)
{
int i ;
for (i=0 ; i<np ; i++)
printf ("point %c de coordonnes %d %d\n", courbe[i].c,
courbe[i].x, courbe[i].x) ;
}

80

Exe rcice s e n langage C

Exe rcice VII.5


___________________________________________________________________________

Enonc
Ecrire le program m e de la q ue s tion 3 de l'e xe rcice pr cdent, sans util
iser de structures. O n pr voira toujours une
fonction pour lire les inform ations re lative s un point.
_______________________________________________________________

Sol
ution
Ici, ilnous faut obligatoire m e nt pr voir 3 tableaux diff re nts de m m e taille : un pour les nom s de points, un pour leurs
abscis s e s e t un pour leurs ordonn e s . Le program m e ne pr s e nte pas de difficult s particuli re s (son principalint r t e s t
d' tre com par au pr cdent!).
#include <stdio.h>
#define NP 10
/* nombre de points d'une courbe */
#define LG_LIG 128
/* longueur maximale d'une ligne de donne */
main()
{
char c [NP] ;
/* noms des diffrents points */
int x [NP] ;
/* abscisses des diffrents points */
int y [NP] ;
/* ordonnes des diffrents points */
int i ;
char ligne [LG_LIG+1] ;
void affiche (char [], int[], int[], int) ;
/* lecture des diffrents points de la courbe */
for (i=0 ; i<NP ; i++)
{ printf ("nom (1 caractre) et coordonnes point %d : ", i+1) ;
gets (ligne) ;
sscanf (ligne, "%c %d %d", &c[i], &x[i], &y[i]) ;
}
affiche (c, x, y, NP) ;
}

VII. Le s s tructure s

81

void affiche (char c[], int x[], int y[], int np)
{
int i ;
for (i=0 ; i<np ; i++)
printf ("point %c de coordonnes %d %d\n", c[i], x[i], x[i]) ;
}

Exe rcice VII.6


___________________________________________________________________________

Enonc
Soie nt les deux m od les de structure date e t pe rsonne dclar s ainsi :
#define LG_NOM 30
struct date
{ int jour ;
int mois ;
int annee ;
} ;
struct personne
{ char nom [LG_NOM+1] ;
/* chane de caractres reprsentant le nom */
struct date date_embauche ;
struct date date_poste ;
} ;

Ecrire une fonction q ui re oit e n argum e nt une s tructure de type pe rsonne e t q ui e n re m plit les diff re nts ch am ps ave c un
dialogue s e pr s e ntant sous l'une des 2 form e s s uivante s :
nom : DUPONT
date embauche (jj mm aa) : 16 1 75
date poste = date embauche ? (O/N) : O

nom : DUPONT
date embauche (jj mm aa) : 10 3 81
date poste = date embauche ? (O/N) : N
date poste (jj mm aa) : 23 8 91

82
Exe rcice s e n langage C
_______________________________________________________________

Sol
ution
Notre fonction doit m odifie r le conte nu d'une s tructure de type pe rsonne ;ile s t donc n ce s s aire q u'e lle e n re oive
l'adre s s e e n argum e nt. Ici, l' nonc n'im posant aucune prote ction particuli re conce rnant les lecture s au clavie r, nous
lirons "classiquem e nt" le nom par ge ts e t les trois autre s inform ations num riq ue s par scanf. Voici ce q ue pourrait tre la
fonction de m and e :
void remplit (struct personne * adp)
{
char rep ;
/* pour lire une rponse de type O/N */
printf ("nom : ") ;
gets (adp->nom) ;

/* attention, pas de contrle de longueur */

printf ("date embauche (jj mm aa) : ") ;


scanf ("%d %d %d", &adp->date_embauche.jour,
&adp->date_embauche.mois,
&adp->date_embauche.annee) ;
printf ("date poste = date embauche ? (O/N) : ") ;
getchar () ; rep = getchar () ;
/* premier getchar pour sauter \n */
if (rep == 'O') adp->date_poste = adp->date_embauche ;
else { printf ("date poste (jj mm aa) : ") ;
scanf ("%d %d %d", &adp->date_poste.jour,
&adp->date_poste.mois,
&adp->date_poste.annee) ;
}
}

Note z q ue , com m e l'accoutum e , d s lors q u'une lecture de valeurs num riq ue s (ici par scanf) e s t suivie d'une lecture
d'un caract re (ici par ge tch ar, m ais le m m e problm e s e pos e rait ave c scanf e t le code %c), ile s t n ce s s aire de
"saute r" artificie llem e nt le caract re ayant s e rvi la validation de la derni re inform ation num riq ue ;e n e ffe t, dans le
cas contraire , c'e s t pr cis m e nt ce caract re (\n) q ui e s t pris e n com pte .
En toute rigue ur, la dm arch e ainsi utilise n'est pas infaillible : si l'utilisate ur fournit des inform ations supplm e ntaire s
apr s la derni re valeur num riq ue (ne s e rait-ce q u'un sim ple e s pace ), le caract re lu ult rie ure m e nt ne s e ra pas ce lui
atte ndu. Toute fois, ils'agit alors des "problm e s h abitue ls" li s la fourniture d'inform ations e xcdentaire s . Ils peuve nt
tre r s olus par diff re nte s te ch niq ues dont nous avons parl, notam m e nt, dans l'e xe rcice VI.5.

VII. Le s s tructure s
83
Voici, titre indicatif, un pe tit program m e d'essai de notre fonction (sa com pilation n ce s s ite les dclarations des
structure s date e t pe rsonne ) :
main()
{
struct personne bloc ;
remplit (&bloc) ;
printf ("nom : %s \n date embauche : %d %d %d \n date poste
: %d %d %d",
bloc.nom,
bloc.date_embauche.jour, bloc.date_embauche.mois, bloc.date_embauche.annee,
bloc.date_poste.jour,
bloc.date_poste.mois,
bloc.date_poste.annee ) ;
}

D EUXIEM E PARTIE :
EXERCICES TH EM A TIQUES

INTRO D UCTIO N
A LA D EUXIEM E PARTIE

Ce ch apitre vous fournit q ue lque s e xplications conce rnant la m ani re dont sont conus les problm e s proposs dans ce tte
deuxi m e partie de l'ouvrage e t les q ue lque s r gles q ue nous nous som m e s fix e s pour la rdaction de s program m e s
corre s pondants.

1 - Cane vas com m un ch aq ue e xe rcice


Pour ch aq ue e xe rcice , nous avons adopt le m m e cane vas.

a)L'e xpos du probl


me
Ile s t constitu d'un nonc accom pagn d'un exem ple. Ce t e ns e m ble constitue ce q u'ile s t indispensable de lire avant de
te nte r de r s oudre le problm e . Ce rte s , l'e xe m ple pe rm e t d'illustre r e t de concr tiser l' nonc m ais, de plus, ille
pr cis e , e n particulie r e n e xplicitant la m ani re dont le program m e dialogue ave c l'utilisate ur. O n note ra q ue ce t e xe m ple
corre s pond e xacte m e nt une im age d'cran obte nue ave c le program m e propos e n solution.

b)L'anal
yse
Elle s p cifie (ou pr cis e ) les algorith m e s m e ttre e n oe uvre pour aboutir une solution. Elle garde un caract re g n ral;
notam m e nt, e lle vite de s'int re s s e r ce rtains dtails de program m ation dont le ch oix e s t re je t au m om e nt de l' criture
du program m e . A priori, e lle fait dj partie de la solution ;toute fois, si vous s ch e z sur l' nonc lui-m m e , rie n ne vous
e m p ch e , apr s la lecture de ce tte analyse, de te nte r d' crire le program m e corre s pondant. En e ffe t, un te le xe rcice , bie n

86
Exe rcice s e n langage C
q ue lim it la sim ple traduction d'un algorith m e dans un langage , n'e n poss de pas m oins un int r t propre e n ce q ui
conce rne l'appre ntissage du langage lui-m m e .

c)Le program m e
Bie n q u'ilsuive e xacte m e nt l'analyse propose, iln'e n re s te pas m oins q u'ilfaille le considrer com m e une rdaction
possible parm i beaucoup d'autre s . N'oublie z pas q u' ce nive au ile s t bien difficile de porte r un juge m e nt de valeur sur
les q ualit s ou les dfauts de te lle ou te lle rdaction, tant q ue l'on n'a pas prcis les crit re s re te nus (vitesse d'e x cution,
taille m m oire , clart de la rdaction, re s pe ct de ce rtaine s r gles de style, ...) ;ce la e s t d'autant plus vrai q ue ce rtains de
ce s crit re s pe uve nt s'av re r incom patibles e ntre e ux. Ce s re m arq ue s s 'appliq ue nt d'ailleurs dj aux e xe rcice s propos s
pr cdem m e nt dans la pre m i re partie de ce t ouvrage m ais ave c m oins d'accuit .

d)Le s com m e ntaire s


Ils fournis s e nt ce rtaine s e xplications q ue nous avons jug e s utiles la com pr h e nsion du program m e lui-m m e . Ilpe ut,
par e xe m ple, s'agir :
- de rappe ls conce rnant une instruction ou une fonction pe u usuelle,
- de justifications de ce rtains ch oix r aliss uniquem e nt au m om e nt de la rdaction du program m e ,
- de m ise en vidence de certaine s particularit s ou originalits du langage ,
- e tc.

e )La dis cus s ion


Elle constitue une s orte d'ouve rture fond e s ur une r flexion de caract re g n ralq ui pe ut porte r sur :
- les insuffisance s ve ntue lles du program m e propos , notam m e nt e n ce q ui conce rne s on com porte m e nt face des
e rre urs de la part de l'utilisate ur,
- les am liorations q u'ile s t possible de lui apporte r,
- une g n ralisation du problm e pos ,
- e tc.

Introduction la de uxi m e partie

2 - Prote ction de s program m e s par rapport aux donn e s

87

Com m e beaucoup d'autre s langage s , les instructions usuelles de lecture au clavie r du langage C ne s ont pas totalem e nt
prot ges d' ve ntue lles r pons e s incorre ctes de la part de l'utilisate ur. Ce lles -ci pe uve nt e ntra
ne r un com porte m e nt
anorm aldu program m e .
D 'une m ani re g n rale, ce problm e de contrle des donnes peut tre r s olu par l'e m ploi de te ch niq ue s appropri e s
te lles q ue ce lles q ue nous avons re ncontres dans l'e xe rcice VI.5 de la pre m i re partie . Toute fois, ce lles -ci pr s e nte nt
l'inconv nie nt d'alourdir le te xte du program m e . C'e s t pourq uoi nous avons vit d'introduire syst m atiq ue m e nt de te lles
prote ctions dans tous nos exem ples , ce q ui aurait m anife s te m e nt m as q u l'obje ctif e s s e ntie lde l'e xe rcice (bie n e nte ndu,
ce s prote ctions pourraie nt deve nir indispe nsables dans un program m e r e l). Note z toute fois q ue ce rtains e xe rcice s , de par
leur nature m m e , re q ui re nt une te lle prote ction ;ce lle-ci s e ra alors claire m e nt dem ande dans l' nonc lui-m m e .

3 - A propos d e s s tructure s de boucl


e
En principe , lors q ue l'analyse d'un problm e fait inte rve nir une r p tition, ilfaudrait, pour tre com plet, e n pr cis e r le
type :
- r p tition dfinie (ou ave c com pte ur) : e lle e s t r alise en C ave c l'instruction for,
- r p tition tant q u e , dans laq ue lle le te s t de poursuite a lie u e n dbut de boucle : e lle e s t r alise en C ave c
l'instruction w h ile,
- r p tition jusqu' dans laq ue lle le te s t d'arr t a lie u e n fin de boucle : e lle e s t r alise en C ave c l'instruction do ...
w h ile.
En fait, ile xiste plusieurs raisons de ne pas toujours sp cifie r le ch oix du type d'une rptition au nive au de l'analyse et
de le re porte r au nive au de l' criture du program m e :
- d'une part, le ch oix d'un type de boucle n'e s t pas toujours dict im p rative m e nt par le problm e : par e xe m ple, un
algorith m e utilisant une r p tition de type jusqu' pe ut toujours tre transform e n un algorith m e utilisant une
r p tition de type tant q u e ,
- d'autre part, com m e nous l'avons dj e ntre vu dans le ch apitre III de la pre m i re partie , le langage C autorise des
form es de r p tition plus vari e s q ue les trois q ue nous ve nons d'voq ue r (e t q ui sont ce lles propos e s classiquem e nt
par la "program m ation structur e ") : ainsi, par e xe m ple :
*gr ce la notion d'op rate ur s q ue ntie l, on pe ut r aliser, l'aide de l'instruction w h ile, des boucles dans
les q ue lles le te s t de poursuite a lie u, non plus e n dbut, m ais e n cours de boucle,
*l'instruction bre ak autorise des boucles sortie s m ultiples .

88
Exe rcice s e n langage C
Ce rte s , on pe ut obje cte r q ue ce s ont l des possibilit s q ui sont contraire s l'e s prit de la program m ation structur e .
Ce pe ndant, utilises bon e s cie nt, e lles pe uve nt am liore r la concision et le te m ps d'excution de s program m e s . Com pte
te nu de l'orie ntation du langage C, ilne nous a pas paru opportun de nous prive r totalem e nt de ce s facilit s .
En d finitive , ilnous arrive ra souve nt, au cours de l'analyse, de nous conte nte r de pr cis e r la (ou les ) condition(s) d'arr t
d'une it ration e t de re porte r au nive au de la program m ation m m e le ch oix de s instructions utiliser. On note ra q u'e n
procdant ainsi un effort de r flexion logiq ue pe ut re s te r n ce s s aire au m om e nt de la rdaction du program m e , laq ue lle,
dans ce cas, s e trouve tre plus q u'une s im ple traduction litt rale!

4 - A propos d e s fonctions
a) Com m e nous l'avons dj re m arq u dans l'avant-propos, la norm e ANSI acce pte deux form es de dfinition de
fonctions. Voici, par e xe m ple, deux faons d'crire l'e n-t te d'une fonction fct re ce vant deux argum e nts de type int e t
ch are t re nvoyant une valeur de type double :
double fct (int x, char * p)

double fct (x, p)


int x ;
char * p ;

Ilne s 'agit l q ue de sim ples diff re nces de rdaction, sans aucune incide nce s ur le plan fonctionne l. Ici, nous avons
syst m atiq ue m e nt e m ploy la pre m i re form e (on la nom m e parfois form e "m ode rne "), dans la m e s ure o e lle a te ndance
s e g n raliser et o, de plus, ils'agit de la s e ule form e acce pt e par le C+ + .

b) Le s fonctions ont toujours t dclares dans les fonctions les utilisant bien q u'a priori :
- ce la ne s oit pas obligatoire pour les fonctions fournissant un r s ultat de type int,
- ce la ne s oit pas obligatoire lors q u'une fonction a t dfinie , dans le m m e s ource , avant d' tre utilise.

c) D ans les dclarations des fonctions, nous avons utilis la form e prototype autoris e par le s tandard ANSI. Ce lle-ci s e
r v le s urtout fort pr cie us e lors q ue l'on e xploite les possibilits de com pilation s par e e t q ue l'on a donc affaire
plusieurs fich ie rs source diff re nts. Ce rte s , ce n'e s t pas le cas ici, m ais, com pte te nu de ce q u'e lle e s t pratiq ue m e nt
acce pt e d e tous les com pilate urs actue ls e t q ue , de plus, e lle e s t e s t obligatoire e n C+ + , ilnous a paru judicie ux d'e n
faire une h abitude .

I : VARIA TIO NS A LGO RITH M IQUES


SUR LES INSTRUCTIO NS
D E BASE

Ce ch apitre vous propose des problm e s ne faisant appe lq u'aux notions de base du langage C, savoir :
- e ntr e s -sortie s conve rsationne lles (ge tch ar, scanf, ge ts, putch ar, printf),
- instructions de contrle,
- tableaux,
- ch a
ne s ,
- fonctions.

I-1 Triangl
e de Pas cal
______________________________________________________________________________

Enonc
Affich e r un "triangle de Pascal" dont le nom bre de ligne s e s t fourni e n donn e . Nous vous rappe lons q ue les "cas e s " d'un
te ltriangle contie nne nt les valeurs des coe fficie nts du binom e C (ou nom bre de com binaisons de n lm e nts pris p p).
n,p

Ce tte valeur e s t place dans la cas e corre s pondant l'inte rs e ction de la ligne de rang n e t la colonne de rang p (la
num rotation com m e nant 0).
O n vite ra de calculer ch aq ue te rm e s par m e nt ;au contraire , on ch e rch e ra e xploite r la re lation de r curre nce :

90
C

Exe rcice s e n langage C


= C
+ C

i,j

i-1, j

i-1,j-1

O n lim ite ra 15 le nom bre de lignes dem and e s par l'utilisate ur e t on re s pe cte ra la pr s e ntation propose dans l'e xe m ple
ci-de s s ous.

Exe m pl
e
combien de lignes voulez vous ? 12
p
0
1
2
3
4
5
6
7
8
9
10
11
n
----------------------------------------------------------------0 -1
1 -1
1
2 -1
2
1
3 -1
3
3
1
4 -1
4
6
4
1
5 -1
5
10
10
5
1
6 -1
6
15
20
15
6
1
7 -1
7
21
35
35
21
7
1
8 -1
8
28
56
70
56
28
8
1
9 -1
9
36
84 126 126
84
36
9
1
10 -1
10
45 120 210 252 210 120
45
10
1
11 -1
11
55 165 330 462 462 330 165
55
11
1
______________________________________________________________________________

ANALYSE
A priori, nous pourrions utiliser un tableau t deux dim e nsions com portant 15x15 lm e nts e t dcide r (arbitraire m e nt)
q ue le pre m ie r indice corre s pond au rang d'une ligne du triangle, le s e cond ce lui d'une colonne . Nous re m plirions
alors partie llem e nt ce tableau ave c les valeurs C voulue s (i varie rait de 0 n-1 si n re pr s e nte le nom bre de ligne s
i,j

dem and e s e t, pour ch aq ue valeur de i, j varie rait de 0 i).


Pour e xploite r la r curre nce propos e , ilnous suffirait alors de procder com m e s uit :
- place r la valeur 1 e n t(0,0) (ce q ui constitue la pre m i re ligne ),
- pour ch aq ue ligne de rang i, partir de i=1, procder ainsi :
*place r la valeur 1 e n t(i,0) e t t(i,i) (e xtr m its de la ligne de rang i),
*pour j variant de 1 i-1, faire :
t(i,j) = t(i-1,j) + t(i-1,j-1)

I. Variations algorith m iques sur les instructions de base


91
En fait, ile s t possible de n'utiliser qu'un tableau une s e ule dim e nsion, dans leq ue lon vie nt calculer succe s s ive m e nt
ch acune des lignes du triangle (ilfaut alors, bie n sr, affich e r ch aq ue ligne d s q u'e lle a t dte rm in e ).
Supposons, en effe t, q u' un instant donn , nous disposions dans ce tableau t des i+1 valeurs de la ligne de rang i e t
voyons com m e nt dte rm ine r ce lles de la ligne de rang i+1. Nous constatons q ue la r curre nce propos e pe rm e t de dfinir
la nouve lle valeur d'un lm e nt de t e n fonction de s on ancie nne valeur e t de l'ancie nne valeur de l' lm e nt pr cdent.
Ce rte s , si nous rptions une affe ctation de la form e :
t(j) = t(j) + t(j-1)
e n faisant varie r j de 1 i-1, nous n'aboutirions pas au rsultat e s com pt puis q u'alors la valeur de t(j) dpendrait de la
nouve lle valeur pr alablem e nt attribu e t(j-1).
M ais, ile s t facile de m ontre r q u'e n e xplorant la ligne de droite gauch e , c'e s t- -dire e n r p tant l'affe ctation ci-de s s us
e n faisant dcro
tre j de i-1 0, le problm e ne s e pos e plus.
Voici finalem e nt l'algorith m e q ue nous utiliserons :
Faire varie r i de 0 n-1. Pour ch aq ue valeur de i :
- r p te r, e n faisant dcro
tre j de i-1 1 :
t(j) = t(j) + t(j-1)
- place r la valeur 1 dans t(i).
R e m arques :
1) Te lq ue l'algorith m e vie nt d' tre nonc , nous constatons q ue pour i=0, j doit dcro
tre de -1 1! Nous adm e ttrons
q ue ce la signifie e n fait q u'aucun traite m e nt n'e s t r aliser dans ce cas (ce qui est norm alpuis q ue alors notre ligne
e s t rduite la s e ule valeur 1, laq ue lle s e ra plac e par l'affe ctation t(i)=1). Ile n va de m m e pour i=1, j devant alors
dcro
tre de 0 1. O n note ra q u'e n langage C la boucle for pe rm e t de te nir com pte de ce s cas particulie rs (le te s t de
poursuite de boucle tant r alis en dbut). Ce n'e s t toute fois pas l une r gle g n ralisable tous les langage s .
2) Ave c les pr cautions q ue nous ve nons d'voq ue r, l'algorith m e "s'initialise" de lui-m m e .

Program m e
#include <stdio.h>
#define NMAX 15

/* nombre maximal de lignes */

main()
{ int t [NMAX],

/* tableau reprsentant une ligne du triangle */

92

Exe rcice s e n langage C


nl,
i,
j ;

/* nombre de lignes souhaites */


/* indice de la ligne courante */
/* indice courant de colonne */

/* lecture nombre de lignes souhaites et affichage titres */


printf ("combien de lignes voulez vous ? ") ;
scanf ("%d", &nl) ;
if (nl > NMAX) nl = NMAX ;
printf ("\n\n p
") ;
for (i=0 ; i<nl ;i++)
printf ("%5d", i) ;
printf ("\n n\n") ;
for (i=0 ; i<=nl ; i++)
printf ("-----") ;
printf ("\n") ;
/* cration et affichage de chaque ligne */
for (i=0 ; i<nl ;i++)
{ t[i] = 1 ;
for (j=i-1 ; j>0 ; j--)
t[j] = t[j-1] + t[j] ;
printf ("%2d --", i) ;
for (j=0 ; j<=i ; j++)
printf ("%5d", t[j]) ;
printf ("\n") ;
}
}

Com m e ntaire s
*En langage C, les indices d'un tableau com m e nce nt 0. Ici, ce tte particularit s 'av re int re s s ante puis q ue nos
num ros de ligne s ou de colonnes doive nt aussi com m e nce r 0.
*Plutt q ue d'utiliser directe m e nt la constante 15 dans notre program m e , nous avons prf r faire appe l l'instruction
#de fine du pr proce s s e ur pour d finir un sym bole NMAX possdant ce tte valeur. Ile s t ainsi beaucoup plus facile, le cas
ch ant, de m odifie r ce tte valeur (puis q u'ilsuffit alors d'inte rve nir e n un s e ule ndroit du program m e ). Note z q ue nous
n'aurions pas pu utiliser la dclaration de constante sym boliq ue (const int NM AX = 15), car, dans ce cas, NM AX n'aurait
pas t une "e xpre s s ion constante ", e t nous n'aurions pas pu l'utiliser com m e dim e nsion d'un tableau.
*Ne pas oublie r q ue t[NM A X] r s e rve NMAX lm e nts (c'e s t- -dire 15), dont les indice s varie nt de 0 14.

I. Variations algorith m iques sur les instructions de base

93

*Si l'utilisate ur de m ande un nom bre de ligne s s up rie ur NMAX, le program m e s e conte nte de lim ite r ce tte dem ande
la valeur NM A X.

D ISCUSSIO N
*Nous aurions pu te nir com pte de la sym trie de ch aq ue ligne par rapport son ce ntre ;q ue lque s instructions
supplm e ntaire s nous auraie nt alors perm is une lg re rduction du te m ps de calcul.
*L' nonc lim itait 15 le nom bre de lignes de notre triangle. En e ffe t, au-de l, iln'e s t g n ralem e nt plus possible
d'affich e r toute s les valeurs sur une s e ule ligne d'cran.
*Notre program m e n'e s t pas prot g dans le cas o l'utilisate ur fournit une r pons e non num riq ue la q ue s tion pos e .
D ans ce cas, toute fois, la situation n'e s t pas tr s grave ;e n e ffe t, la valeur de nle s t, ce rte s , alatoire m ais, de toute
faon, e lle s e ra lim it e 15 par le program m e .
Si vous souh aitie z q uand m m e traite r ce type d'anom alie , ilvous suffirait d'exam ine r le code de re tour de la fonction
scanf (ilfournit le nom bre de valeurs conve nablem e nt lue s ) e t de v rifie r q u'ile s t bien gal 1.

I-2 Cribl
e d'Eratos th ne
________________________________________________________________________________________

Ile xiste une m th ode de dte rm ination de nom bre s pre m ie rs connue s ous le nom de "crible d'Erastoth ne ". Elle pe rm e t
d'obte nir tous les nom bre s pre m ie rs inf rie urs une valeur donn e n.
La m th ode (m anue lle) consiste dre s s e r une liste des nom bre s considrs (de 1 n) e t y raye r tous les nom bre s
m ultiples d'autre s e ntie rs (de te ls nom bre s s ont n ce s s aire m e nt non pre m ie rs). Plus prcism e nt, on proc de ainsi :
1 - on raye le 1 (q ui, par d finition, n'e s t pas un nom bre pre m ie r).
2 - on re ch e rch e , partir du de rnie r nom bre pre m ie r considr (la pre m i re fois, on convie nt q u'ils'agit du 1), le
pre m ie r nom bre non ray (on pe ut m ontre r q u'ile s t pre m ie r). Ildevie nt, son tour, le dernie r nom bre pre m ie r considr
e t on raye tous s e s m ultiples .
3 - on r p te le point 2 jus q u' ce q ue le nom bre pre m ie r considr soit suprieur la racine carr e d e n. O n pe ut alors
m ontre r q ue tous les nom bre s non pre m ie rs ont t rays de la liste .

94

Exe rcice s e n langage C

Enonc
Ecrire un program m e bas s ur ce tte m th ode re ch e rch ant tous les nom bre s pre m ie rs com pris e ntre 1 e t n (la valeur de n
tant fixe dans le program m e )

Exe m pl
e
entre 1 et 1000, les nombres premiers sont :
2
3
5
7
11
13
31
37
41
43
47
53
73
79
83
89
97
101
127
131
137
139
149
151
179
181
191
193
197
199
233
239
241
251
257
263
283
293
307
311
313
317
353
359
367
373
379
383
419
421
431
433
439
443
467
479
487
491
499
503
547
557
563
569
571
577
607
613
617
619
631
641
661
673
677
683
691
701
739
743
751
757
761
769
811
821
823
827
829
839
877
881
883
887
907
911
947
953
967
971
977
983

17
59
103
157
211
269
331
389
449
509
587
643
709
773
853
919
991

19
61
107
163
223
271
337
397
457
521
593
647
719
787
857
929
997

23
67
109
167
227
277
347
401
461
523
599
653
727
797
859
937

29
71
113
173
229
281
349
409
463
541
601
659
733
809
863
941

________________________________________________________________________________________

ANALYSE
La m th ode m anue lle s ugg re d'utiliser un tableau. Toute fois, devons-nous, par analogie , y range r les nom bre s e ntie rs de
1 n?En fait, ce la ne s e rait gu re utile puis q ue alors ch aq ue nom bre s e rait gal son rang dans le tableau (du m oins,
une unit pr s, suivant les conve ntions q ue l'on adopte rait pour l'indice du prem ie r lm e nt).
En r alit , le bon droulem e nt de l'algorith m e nous im pos e s e ulem e nt d' tre e n m e s ure de faire corre s pondre ch aq ue
e ntie r e ntre 1 e t n, une inform ation pr cisant, ch aq ue instant, s'ile s t ray ou non (ce tte inform ation pouvant volue r au
fildu droulem e nt du program m e ). Ils'agit l tout nature llem e nt d'une inform ation de type "logiq ue " (vrai ou faux).
Com m e ce type n'e xiste pas e n tant q ue te le n langage C, nous le s im ulerons l'aide de deux constante s e nti re s : VR A I
de valeur 1, FAUX de valeur 0. Note z q ue le ch oix de la valeur 0 pour FAUX est im pos par la m ani re dont le langage

I. Variations algorith m iques sur les instructions de base


95
C consid re une e xpre s s ion num riq ue apparaissant dans une condition ;la valeur 1, par contre , pourrait tre , sans
inconv nie nt, re m plac e par n'im porte q ue lle valeur non nulle.
Notons raye un te ltableau e t supposons q ue raye [i] corre s pond l'e ntie r i (ce q ui, com pte te nu de s conve ntions du
langage C, signifie q ue raye [0] e s t inutilis). Notre algorith m e nous im pose de garde r la trace du dernier nom bre pre m ie r
considr. Nous le nom m e rons pre m . La dm arch e m anue lle s e transpose alors com m e s uit :
*Initialisation :
- m e ttre FAUX tous les lm e nts du tableau raye ,
- m e ttre FAUX le pre m ie r lm e nt de raye , e t faire :
pre m = 1
*It ration :
- re ch e rch e r, partir de pre m , le pre m ie r nom bre non e ncore ray , c'e s t- -dire incr m e nte r la valeur de pre m
jus q u' ce q ue t[pre m ] soit FAUX (en toute rigue ur, ilfaut se dem ande r s'ile xiste e ncore un te lnom bre dans
notre tableau, e t donc lim ite r l'incr m e ntation de pre m N).
- raye r tous les m ultiples de pre m , dans le cas o un te lnom bre a t trouv .
*L'it ration propos e pe ut tre r p t e , indiff re m m e nt (les deux form ulations tant q uivalentes d s q ue N est
suprieur ou gal 1) :
- jusqu' ce q ue la valeur de pre m soit suprieure la racine carre de N,
- ou tant q u e la valeur de pre m e s t inf rie ure ou gale la racine carre de N.

Program m e

#include <stdio.h>
#define N 1000
#define VRAI 1
#define FAUX 0
main()
{
int raye [N+1],
prem,
na,
i ;

/* plus grand entier examiner */


/* pour "simuler" des ..... */
/* ..... valeurs logiques */

/* tableau servant de crible */


/* dernier nombre premier considr */
/* compteur de nombres affichs */

/* initialisations */
for (i=1 ; i<=N ; i++)

/* mise zro du crible */

96

Exe rcice s e n langage C


raye[i] = FAUX ;
raye[1] = VRAI ;

/* on raye le nombre 1 */

/* passage au crible */
prem = 1 ;
while (prem*prem <= N)
{ while (raye[++prem] && prem<N ) {}
/* recherche premier nombre non ray */
for (i=2*prem ; i<=N ; i+=prem) /* on raye tous ses multiples */
raye[i] = VRAI ;
}
/* affichage rsultats */
printf ("entre 1 et %d, les nombres premiers sont :\n", N) ;
na = 0 ;
for (i=1 ; i<=N ; i++)
if ( !raye[i] )
{ printf ("%7d",i) ;
na++ ;
if ( na%10 == 0) printf ("\n") ;
/* 10 nombres par ligne */
}
}

Com m e ntaire s
*La re ch e rch e du prem ie r nom bre non e ncore ray est r alise par la s e ule instruction :
while (raye[++prem] && prem<N) {}

Note z bie n la pr -incr m e ntation de pre m ;une post-incr m e ntation :


while (t[prem++] && prem<N) {}

aurait conduit une boucle infinie s ur le pre m ie r nom bre pre m ie r trouv , c'e s t- -dire 2 (du m oins si N est suprieur ou
gal 2). Ilsuffirait toute fois d'incr m e nte r pre m une fois avant d'entre r dans la boucle pour q ue ce la fonctionne .
*Nous avons cons e rv le garde -fou :
prem < N

I. Variations algorith m iques sur les instructions de base


97
O n pourrait toute fois dm ontre r q ue , d s q ue N est suprieur ou gal 2, on e s t toujours assur de trouve r au m oins un
nom bre non ray avant la fin du tableau (com pte te nu de ce q ue l'on com m e nce l'e xploration ave c un nom bre inf rie ur
ou gal la racine carre de N).
*Nous avons prvu d'affich e r nos nom bre s pre m ie rs, raison de 10 par ligne , ch aq ue nom bre occupant 7 caract re s .
Pour ce faire , nous utilisons une variable nom m e na nous perm e ttant de com ptabiliser le nom bre de nom bre s affich s . A
ch aq ue fois q ue na e s t m ultiple de 10, nous provoq uons un saut de ligne .

D ISCUSSIO N
*Te lq u'ile s t propos ici, le program m e traite le cas n=1000. Pour le faire fonctionne r ave c d'autre s valeurs, ile s t
n ce s s aire d'inte rve nir au nive au du program m e lui-m m e e t de le re com piler. Si vous souh aite z q ue la valeur de n puis s e
tre fournie e n donn e , ilfaut lui fixe r une valeur m axim ale, afin de pr voir la r s e rvation du tableau corre s pondant.
Note z toute fois q ue les possibilits de ge s tion dynam iq ue du langage C offre nt une s olution plus agr able ce problm e
de dim e nsions variables . Vous e n trouve re z ce rtains e xe m ples dans le ch apitre consacr la ge s tion dynam iq ue .
*Le tableau raye , ainsi que les variables pre m e t i, ont t dclars de type int, ce q ui, dans ce rtaine s im plm e ntations,
pe ut lim ite r 32767 les valeurs q u'ile s t ainsi possible d'exam ine r. O n pe ut toujours faire m ie ux, e n utilisant le type
unsigne d int, ou m ie ux le type long ou unsigne d long. Toute fois, dans ce cas, on s'assure ra q ue l'on n'e s t pas soum is
des contrainte s s ur la taille des diff re nts m odules obje ts, sur la taille de la pile ou, e ncore , tout sim plem e nt, sur la taille
des diff re nts obje ts q u'ile s t possible de m anipuler. Iln'e s t pas rare , e n e ffe t, q ue l'on re ncontre des lim itations 64 KO
(c'e s t le cas, actue llem e nt, des com pilate urs Borland/Turbo C/C+ + utiliss dans l'e nvironne m e nt D O S).

I-3 Le ttre s com m une s de ux m ots (1)


________________________________________________________________________________________

Enonc
R aliser un program m e q ui affich e les lettre s com m une s deux m ots fournis au clavie r. O n pr voira d'affich e r plusieurs
fois une lettre q ui appara
t plusieurs reprises dans ch acun des deux m ots.

98
Exe rcice s e n langage C
O n supposera q ue ce s m ots ne peuve nt pas com porte r plus de 26 caract re s e t on les lira l'aide de la fonctions ge ts.

Exe m pl
es
donnez un
donnez un
la lettre
la lettre
la lettre
la lettre

premier mot : monsieur


deuxime mot : bonjour
o est commune aux deux mots
n est commune aux deux mots
u est commune aux deux mots
r est commune aux deux mots
_________________

donnez un
donnez un
la lettre
la lettre
la lettre

premier mot : barbara


deuxime mot : ravage
a est commune aux deux mots
r est commune aux deux mots
a est commune aux deux mots

________________________________________________________________________________________

ANALYSE
L' nonc nous im pose d'utiliser ge ts, donc de re pr s e nte r nos m ots sous form e de ch a
nes de caract re s (suites de
caract re s te rm in e s par le caract re nul, not e n C : \0). Nous utiliserons ce t e ffe t des tableaux de caract res de
dim e nsion 27 (pour 26 lettre s m axim um e t un caract re de fin).
La re ch e rch e des lettre s com m une s aux de ux m ots peut s e faire e n com parant ch acun de s caract res de la pre m i re ch a
ne
ch acun de s caract res de la s e conde . Ce la nous conduit nature llem e nt l'utilisation de deux boucles ave c com pte ur
(instructions for) im briq u e s .
Toute fois, nous devons te nir com pte de ce q u'une m m e lettre pe ut figure r plusieurs fois dans un m m e m ot. Dans ces
conditions, ilfaut vite r :
*q u'une m m e lettre du prem ie r m ot ne puis s e tre trouv e e n de ux e ndroits diff re nts du second. Par e xe m ple,
ave c :
m onsieur
et
bonjour

I. Variations algorith m iques sur les instructions de base


99
apr s avoir trouv q ue le o de m onsie ur figurait e n position 2 de bonjour, ilfaut vite r de s ignaler une nouve lle
concide nce e ntre ce m m e o de m onsie ur e t le s e cond o de bonjour.
Ile s t donc n ce s s aire d'inte rrom pre la com paraison entre une lettre du prem ie r m ot ave c toute s ce lles du second m ot,
d s q u'une concide nce a t dte ct e .
*q u'une m m e lettre du second m ot ne puis s e concide r ave c deux lettres diff re ntes du second. Par e xe m ple, ave c
(atte ntion l'ordre des m ots) :
bonjour
et
m onsieur
ilfaut vite r de trouve r une concide nce e ntre le pre m ie r o de bonjour e t l'uniq ue o de m onsie ur e t une autre
concide nce e ntre le s e cond o de bonjour e t le m m e o de m onsie ur.
Pour ce faire , une dm arch e (parm i d'autre s ) consiste lim ine r dans le s e cond m ot la lettre ayant fait l'obje t d'une
concide nce . Plus prcism e nt, ilsuffit de re m place r une te lle lettre par un caract re dont on e s t sr q u'iln'appara
tra
pas dans un m ot. Ici, nous avons ch oisi l'e s pace puis q ue nous som m e s ce ns s travailler ave c des m ots.

Program m e

#include <stdio.h>
#include <string.h>
#define LMAX 26
main()
{
char mot1 [LMAX+1],
mot2 [LMAX+1] ;
int i, j ;

/* premier mot */
/* deuxime mot */

/* lecture des deux mots */


printf ("donnez un premier mot : ") ;
gets (mot1) ;
printf ("donnez un deuxime mot : ") ;
gets (mot2) ;
/* comparaison */
for (i=0 ; i<strlen(mot1) ; i++)
for (j=0 ; j<strlen(mot2) ; j++)
if (mot1[i] == mot2[j])

100

Exe rcice s e n langage C


{ printf ("la lettre %c est commune aux deux mots\n", mot1[i]) ;
mot2[j] = ' ' ;
break ;
}

Com m e ntaire s
*Nous avons utilis le sym bole LM A X pour re pr s e nte r la longue ur m axim ale d'un m ot. Note z bie n q ue les tableaux
m ot1 e t m ot2 ont d tre pr vus de dim e nsion LM A X+1, afin de te nir com pte de la pr s e nce du caract re de fin de
ch a
ne .
*Nous aurions pu utiliser, la place de la s e conde boucle ave c com pte ur (e n j), une boucle tant q u e (w h ile). Ce rte s , la
program m ation e t t plus structur e m ais, n anm oins, m oins concis e .

D ISCUSSIO N
Ce program m e n'e s t pas prot g contre des r ponses de plus de 26 caract re s . Dans ce cas, en effe t, les caract re s
superflus iront cras e r les donnes se trouvant au-de l de l'un de s tableaux m ot1 ou m ot2. Le s cons q ue nce s pe uve nt tre
as s e z vari e s (vous pouve z e xp rim e nte r le pr s e nt program m e dans dive rs e s s ituations e t te nte r d'e xpliq ue r les
com porte m e nts observ s ).
Ile xiste diff re nte s faons d'vite r ce ris q ue . Citons, par e xe m ple :
- lire (toujours par ge ts), une ch a
ne com portant un nom bre de caract re s s uffisam m e nt lev pour q ue l'utilisate ur ne
ris q ue pas (trop!) d'en fournir plus. O n pourrait ch oisir, par e xe m ple 80 ou 128 caract re s (dans ce rtaine s
im plm e ntations, iln'e s t jam ais possible de tape r de s lignes de plus de 128 caract re s ).
- lim ite r autom atiq ue m e nt la longue ur de la ch a
ne lue , e n utilisant la fonction fge ts ;par e xe m ple, ave c fge ts (m ot1,
LM AX, stdin), on lim ite LM AX le nom bre de caract re s lus sur stdin.
- utiliser, dans certaine s im plm e ntations (Turbo/Borland C/C+ + , C/Quick C M icrosoft), une fonction (non
portable!) nom m e cge ts.

I. Variations algorith m iques sur les instructions de base

101

I-4 Le ttre s com m une s de ux m ots (2)


________________________________________________________________________________________

Enonc
R aliser un program m e q ui affich e les lettre s com m une s deux m ots fournis e n donn e . Ce tte fois, on n'im pos e ra pas de
lim ite la taille des m ots fournis par l'utilisate ur, m ais on ne pre ndra e n com pte q ue les 26 pre m ie rs caract re s . Que lq ue
soit le nom bre de caract re s e ffe ctive m e nt frapp s , l'utilisate ur de vra toujours valider sa rponse par la frappe de la
touch e re turn.
L e ncore , on pr voira d'affich e r plusieurs fois une lettre q ui appara
t plusieurs reprises dans ch acun de s m ots.
O n s'astre indra n'utiliser pour la lecture au clavie r q ue l
a seul
e fonction getch ar. De plus, on r alisera une fonction
destin e lire un m ot dans un tableau q u'on lui transm e ttra e n argum e nt ;e lle fournira, e n re tour, la longue ur e ffe ctive
du m ot ainsi lu.

Exe m pl
es
Voir ce ux de l'e xe rcice pr cdent
________________________________________________________________________________________

ANALYSE
L' nonc nous im pos e l'e m ploi de ge tch ar, ce q ui signifie q ue ch acun des deux m ots devra tre lu caract re par
caract re . Dans ces conditions, nous pouvons ch oisir de reprsente r nos m ots :
- soit sous form e d'une ch a
ne de caract re s . Ilnous faudra alors introduire nous-m m e s le caract re de fin de ch a
ne
(\0), ce q ue faisait autom atiq ue m e nt ge ts.
- soit sous form e d'une sim ple s uite de caract re s (c'e s t- -dire s ans ce caract re de fin). Dans ce cas, ilnous faudra
alors prvoir d'e n d te rm ine r la "longue ur".
Com m e l' nonc nous im pos e q ue la fonction de lecture d'un m ot e n re s titue la longue ur, nous ch oisirons la s e conde
solution.
La lecture d'un m ot consiste donc lire des caract re s au clavie r jus q u' ce q ue l'on re ncontre une validation (\n) ou q ue
l'on ait obte nu 26 caract re s ;de plus, dans le cas o l'on a obte nu 26 caract re s , ilfaut poursuivre la lecture de
caract re s au clavie r, sans les pre ndre e n com pte , jus q u' ce q ue l'on re ncontre une validation.

102

Exe rcice s e n langage C

Program m e
#include <stdio.h>
#define LMAX 26
main()
{
int lire(char []) ;
char mot1 [LMAX],
mot2 [LMAX] ;
int l1,
l2,
i, j ;

/* longueur maximale d'un mot */

/*
/*
/*
/*
/*

dclaration (prototype) fonction lecture d'un mot */


premier mot (sans '\0') */
deuxime mot (sans '\0') */
longueur premier mot */
longueur deuxime mot */

/* lecture des deux mots */


printf ("donnez un premier mot : ") ;
l1 = lire (mot1) ;
printf ("donnez un deuxime mot : ") ;
l2 = lire (mot2) ;
/* comparaison */
for (i=0 ; i<l1 ; i++)
for (j=0 ; j<l2 ; j++)
if (mot1[i] == mot2[j])
{ printf ("la lettre %c est commune aux deux mots\n", mot1[i]) ;
mot2[j] = ' ' ;
break ;
}
}
/* Fonction de lecture d'un mot */
int lire (char mot [LMAX])
{
int i ;
/* rang du prochain caractre lire */
char c ;
i = 0 ;
while ( (c=getchar()) != '\n' && i<=LMAX )
mot[i++] = c ;
/* ici, soit on a lu \n, soit on a lu LMAX caractres */
/* dans tous les cas, c contient le premier caractre */
/*
non pris en compte */
if (c != '\n')

I. Variations algorith m iques sur les instructions de base


while (getchar() != '\n') {}
return(i) ;

103

/* recherche '\n' */

Com m e ntaire s
*L e ncore , nous avons utilis le sym bole LM A X pour re pr s e nte r la taille m axim ale d'un m ot. Par contre , ce tte fois, la
dim e nsion des tableaux m ot1 e t m ot2 e s t gale LM A X (e t non plus LM A X+ 1), puis q ue nous n'avons pas y introduire
le caract re s upplm e ntaire de fin de ch a
ne .
*En ce q ui conce rne la fonction (nom m e lire ) de lecture d'un m ot au clavie r, vous constate z q ue nous l'avons dclar e
dans le program m e principal(m ain), bie n q ue ce la soit facultatif, dans la m e s ure o e lle fournit un r s ultat de type int (e n
e ffe t, toute fonction q ui n'e s t pas e xplicite m e nt dclar e e s t suppose produire un rsultat de type int).
D 'autre part, com m e nous l'avons e xpliq u dans l'introduction de ce tte s e conde partie , nous avons utilis, dans ce tte
dclaration, la form e "prototype " autoris e par la norm e ANSI (ce prototype assure les contrles de types d'argum e nts e t
m e t e n place d've ntue lles conve rsions).
Par ailleurs, l'e n-t te de notre fonction lire a t crit suivant la form e "m ode rne ". La norm e ANSI aurait autoris le
re m place m e nt de note e n-t te par :
int lire (mot)
char mot [LMAX] ;

*Le tableau de caract re s re pr s e ntant l'uniq ue argum e nt de lire doit obligatoire m e nt tre transm is par adre s s e puis q ue
ce tte fonction doit tre e n m e s ure d'en m odifie r le conte nu. N'oublie z pas ce pe ndant q u'e n langage C un nom de tableau
e s t inte rpr t (par le com pilate ur) com m e un pointe ur (constant) sur son pre m ie r lm e nt. C'e s t ce q ui justifie la
pr s e nce , dans les appe ls la fonction lire , de m ot1 ou m ot2, e t non de & m ot1 ou & m ot2.
*La dclaration de l'argum e nt de lire , dans son e n-t te :
char mot [LMAX]

aurait pu galem e nt s' crire :


char mot []

ou m m e :
char * mot

104
Exe rcice s e n langage C
D ans le pre m ie r cas, on continue de sp cifie r (au lecte ur du program m e plus q u'au com pilate ur) q ue m ot e s t un tableau
de caract re s m ais q ue s a dim e nsion n'a pas besoin d' tre connue au s e in de lire . Dans le s e cond cas, on e xprim e plus
claire m e nt q ue , finalem e nt, l'argum e nt re u par lire n'e s t rie n d'autre q u'un pointe ur sur des caract re s . Ce s
form ulations sont totalem e nt q uivalente s pour le com pilate ur e t, dans tous les cas (m m e le dernie r), ilre s te possible de
faire appe lau "form alism e " tableau au s e in de lire , e n utilisant une notation te lle q ue :
mot [i++]

D 'ailleurs, pour le com pilate ur, ce tte derni re e s t q uivalente :


* (mot + i++)

Le s m m e re flexions s'appliq ue nt l' criture du prototype de lire .

D ISCUSSIO N
*Le sym bole
M ais, si ce tte
(#de fine ) dans
faire appe l

LM A X e s t dfini pour l'e ns e m ble du source conte nant, ici, le program m e principale t la fonction lire .
fonction de vait tre com pile s par m e nt du re s te , ils e rait alors nce s s aire de faire figure r la dfinition
les deux source s , ce q ui com porte un ris q ue d'erreur. Dans une situation "r e lle", on pourrait avoir int r t
l'une des dm arch e s s uivante s :

- transm e ttre la valeur de LM A X e n argum e nt de la fonction lire .


- re groupe r les dfinitions de sym boles com m uns plusieurs sources dans un fich ie r s par q ue l'on appe lle par
#include dans ch acun de s s ource s conce rn s .
*Contraire m e nt au program m e de l'e xe rcice pr cdent, ce lui-ci s e trouve prot g de r pons e s trop longues de la part de
l'utilisate ur.

I-5 Com ptage de l


e ttre s
________________________________________________________________________________________

I. Variations algorith m iques sur les instructions de base

105

Enonc
R aliser un program m e q ui com pte le nom bre de ch acune des lettres de l'alph abet d'un te xte e ntr au clavie r. Pour
sim plifie r, on ne tie ndra com pte q ue des m inuscules , m ais on com pte ra le nom bre des caract re s non re connus com m e
te ls (q ue ls q u'ils soie nt : m ajuscules , ponctuation, ch iffre s ,...).
Le program m e devra acce pte r un nom bre q ue lconq ue de ligne s . L'utilisate ur tape ra une "ligne vide" pour signaler q u'ila
te rm in la frappe de son te xte (ce q ui re vie nt dire q u'ilfrappe ra donc de ux fois de suite la touch e re turn, apr s la
frappe de sa derni re ligne ).
O n supposera q ue les ligne s frapp e s au clavie r ne pe uve nt jam ais dpas s e r 127 caract re s . Par ailleurs, on fe ra
l'h ypoth s e (pe u re s trictive e n pratiq ue ) q ue les "code s " des lettre s m inuscules a z sont cons cutifs (ce q ui e s t le cas,
notam m e nt, ave c le code A SCII).

Exe m pl
e
donnez votre texte, en le terminant par une ligne vide
je me figure ce zouave qui joue
du xylophone en buvant du whisky

votre texte comporte 63 caractres dont :


2 fois la lettre a
1 fois la lettre b
1 fois la lettre c
2 fois la lettre d
8 fois la lettre e
1 fois la lettre f
......
......
7 fois la lettre u
2 fois la lettre v
1 fois la lettre w
1 fois la lettre x
2 fois la lettre y
1 fois la lettre z
et 11 autres caractres
________________________________________________________________________________________

106

Exe rcice s e n langage C

ANALYSE
Ilnous faut donc utiliser un tableau de 26 e ntie rs perm e ttant de com ptabiliser le nom bre de fois o l'on a re ncontr
ch acune des 26 lettre s (m inuscules ) de l'alph abet. Nous le nom m e rons com pte . Nous utiliserons galem e nt un com pte ur
nom m ntot pour le nom bre totalde caract re s e t un autre nom m nautre s pour les caract res diff re nts d'une lettre
m inuscule.
En ce q ui conce rne le com ptage propre m e nt dit, ilnous faut e xam ine r ch acune des lettres du te xte . Pour ce faire , ile xiste
(au m oins) deux dm arch e s possibles :
- e ffe ctue r une r p tition du traite m e nt d'un caract re ,
- e ffe ctue r une r p tition du traite m e nt d'une ligne , lui-m m e constitu de la r p tition du traite m e nt de ch acun de s
caract re s q u'e lle contie nt.
a) La pre m i re dm arch e aboutit une s im ple boucle ave c com pte ur. Elle ne dem ande d'accder q u' un s e ulcaract re
la fois (par e xe m ple, par ge tch ar). Elle n ce s s ite , par contre , l' lim ination de s caract res de fin de ligne \n (q ui sont
transm is com m e les autre s par ge tch ar), puis q u'ils ne font pas vraim e nt partie du te xte .
D e s urcro
t, la dte ction de la fin du te xte oblige cons e rve r e n pe rm ane nce le "caract re pr cdent". Lors q ue ce
caract re , ainsi que le caract re courant, sont gaux \n, c'e s t q ue l'on a atte int la fin du te xte . Ilsuffit d'initialiser
artificie llem e nt ce caract re pr cdent une valeur q ue lconq ue (autre q ue \n) pour vite r de devoir e ffe ctue r un
traite m e nt particulie r pour le pre m ie r caract re .
b) La s e conde dm arch e aboutit deux boucles im briq u e s . Elle pe rm e t de lire directe m e nt ch aq ue ligne par ge ts. Elle
r gle de m ani re nature lle les problm es de fin de ligne e t de fin de te xte .
Nous vous proposons ici de ux program m e s , corre s pondant ch acune de ces deux d m arch e s .

Program m e bas s ur l
a r p tition du traite m e nt d'un caract re
#include <stdio.h>
main()
{
char c,
cprec ;
int compte[26] ;
int numl,
ntot,
nautres,
i ;

/*
/*
/*
/*
/*
/*

pour lire un caractre frapp au clavier */


caractre prcdent */
pour compter les diffrentes lettres */
rang lettre courante dans l'alphabet */
nombre de caractres du texte */
nb caractres autres qu'une lettre minuscule */

/* initialisations */

I. Variations algorith m iques sur les instructions de base

107

cprec = ' ' ;


ntot = 0 ; nautres = 0 ;
for (i=0 ; i<26 ; i++) compte[i]=0 ;
/* lecture texte et comptages */
printf ("donnez votre texte, en le terminant par une ligne vide\n") ;
while ( (c=getchar()) != '\n' || cprec != '\n' )
{ if (c != '\n')
{ numl = c - 'a' ;
/* on donne le rang 0 la lettre 'a' */
if (numl >=0 && numl < 26) compte[numl]++ ;
else nautres++ ;
ntot++ ;
}
cprec = c ;
}
/* affichage rsultats */
printf ("\n\nvotre texte comporte %d caractres dont :\n", ntot) ;
for (i=0; i<26 ; i++)
printf ("%d fois la lettre %c\n", compte[i], 'a'+i) ;
printf ("\net %d autres caractres\n", nautres) ;
}

Com m e ntaire s
*L'e xpre s s ion :
c - 'a'
pe rm e t d'obte nir le "rang" dans l'alph abet du caract re conte nu dans c. N'oublie z pas q ue le langage C consid re le type
ch ar com m e num riq ue . Plus prcism e nt, dans le cas prsent, les valeurs de c e t de 'a' sont conve rtie s e n int (ce q ui
fournit la valeur num riq ue de leur code ) avant q ue ne s oit valu e l'e xpre s s ion c-'a'. Com m e nous avons suppos q ue
les codes des m inuscules s ont cons cutifs, nous obte nons bien le r s ultat e s com pt .
*Le s instructions :
if (c != '\n')
{ numl = c - 'a' ;
if (numl >=0 && numl < 26) compte[numl]++ ;
else nautres++ ;
ntot++ ;

108

Exe rcice s e n langage C


}
cprec = c;

pourraie nt s e conde ns e r e n :
if ( (cprec=c) != '\n')
{ numl = c - 'a' ;
if (numl >=0 && numl < 26) compte[numl]++ ;
else nautres++ ;
ntot++ ;
}

Program m e bas s ur l
a r p tition du traite m e nt d'une l
igne
#include <stdio.h>
#include <string.h>
main()
{ char ligne[128] ;
int compte[26] ;
int numl,
ntot,
nautres,
i ;

/*
/*
/*
/*
/*

pour lire une ligne frappe au clavier */


pour compter les diffrentes lettres */
rang lettre courante dans l'alphabet */
nombre de caractres du texte */
nombre de caractres autres qu'une lettre minuscule */

/* initialisations */
ntot = 0 ; nautres = 0 ;
for (i=0 ; i<26 ; i++) compte[i]=0 ;
/* lecture texte et comptages */
printf ("donnez votre texte, en le terminant par une ligne vide\n") ;
do
{ gets(ligne) ;
for (i=0 ; i<strlen(ligne) ; i++, ntot++)
{ numl = ligne[i] - 'a' ;/* on donne le rang 0 la lettre 'a' */
if (numl >=0 && numl < 26) compte[numl]++ ;
else nautres++ ;
}
}
while (strlen(ligne)) ;
/* affichage rsultats */

I. Variations algorith m iques sur les instructions de base

109

printf ("\n\nvotre texte comporte %d caractres dont :\n", ntot) ;


for (i=0; i<26 ; i++)
printf ("%d fois la lettre %c\n", compte[i], 'a'+i) ;
printf ("\net %d autres caractres\n", nautres) ;
}

D ISCUSSIO N
*Aucun des deux program m e s propos s ne pose de problm e de prote ction vis- -vis des rponses fournie s par
l'utilisate ur.

I-6 Com ptage de m ots


________________________________________________________________________________________

Enonc
Ecrire un program m e pe rm e ttant de com pte r le nom bre de m ots conte nus dans un te xte fourni au clavie r. Le te xte pourra
com porte r plusieurs ligne s e t l'utilisate ur tape ra une ligne "vide" pour signaler q u'ile n a te rm in la frappe (ce q ui re vie nt
dire q u'ilfrappe ra de ux fois de suite la touch e re turn apr s avoir fourni la derni re ligne ).
O n adm e ttra q ue deux m ots sont toujours s par s par un ou plusieurs des caract re s s uivants :
- fin de ligne
- e s pace
- ponctuation :

: . , ;?!

- pare nth s e s :

( )

- guillem e ts :

"

- apostroph e :

'

O n adm e ttra galem e nt, pour sim plifie r, q u'aucun m ot ne pe ut tre com m e nc s ur une ligne e t s e poursuivre s ur la
suivante .
O n pr voira une fonction pe rm e ttant de dcide r si un caract re donn transm is en argum e nt e s t un de s s parate urs
m e ntionn s ci-de s s us. Elle fournira la valeur 1 lors q ue le caract re e s t un s parate ur e t la valeur 0 dans le cas contraire .

110

Exe rcice s e n langage C

Exe m pl
e
donnez votre texte, en le terminant par une ligne vide
Le langage C a t conu en 1972 par Denis Ritchie avec un objectif
trs prcis : crire un "systme d'exploitation" (UNIX). A cet effet,
il s'est inspir du langage B (cr par K. Thompson) qu'il a hauss
au niveau de langage volu, notamment en l'enrichissant de structures
et de types, et ceci tout en lui conservant ses aptitudes de
programmation proche de la machine.

votre texte comporte 68 mots


_______________________________________________________________________________________

ANALYSE
Com m e dans l'e xe rcice pr cdent, ile xiste (au m oins) deux dm arch e s possibles :
- e ffe ctue r une r p tition du traite m e nt d'un caract re ,
- e ffe ctue r une r p tition du traite m e nt d'une ligne , lui-m m e constitu de la r p tition du traite m e nt de ch acun de s
caract re s q u'e lle contie nt.
La pre m i re dm arch e aboutit une s im ple boucle ave c com pte ur. Elle dem ande s im plem e nt d'accder un s e ul
caract re (par e xe m ple par ge tch ar).
La s e conde dm arch e aboutit deux boucles im briq u e s . Elle dem ande d'effe ctue r une lecture ligne par ligne (par
e xe m ple par ge ts).
L e ncore , nous e xam ine rons les deux d m arch e s e t nous proposerons un program m e corre s pondant ch acune d'entre
e lles .
D ans les deux d m arch e s , tous les caract re s s parate urs joue nt le m m e rle, condition d'y inclure \n (si l'on travaille
ave c ge tch ar) ou \0 (si l'on travaille ave c ge ts). O n pe ut alors dire que l'on a progress d'un m ot dans le te xte , ch aq ue
fois q ue l'on a r alis la s q ue nce s uivante :
- re ch e rch e du prem ie r caract re diff re nt d'un sparate ur,
- re ch e rch e du prem ie r caract re gal un s parate ur.

I. Variations algorith m iques sur les instructions de base


111
O n pourrait r p te r succe s s ive m e nt ces deux op rations, tant q u e q ue l'on n'e s t pas arriv la fin du te xte . En fait, ile s t
plus sim ple d'utiliser un "indicate ur logiq ue " (nous l'appe llerons m ot_e n_cours) e t d'effe ctue r pour ch aque caract re le
traite m e nt suivant :
- si le caract re e s t un s parate ur e t si m ot_e n_cours e s t vrai, augm e nte r de un le com pte ur de m ots e t re m e ttre
m ot_e n_cours faux.
- si le caract re n'e s t pas un sparate ur e t si m ot_e n_cours e s t faux, m e ttre m ot_e n_cours vrai.
Quant la condition d'arr t, e lle s 'e xprim e diff re m m e nt suivant la dm arch e adopt e :
- deux caract re s cons cutifs gaux \n pour la pre m i re , ce q ui im pose de cons e rve r e n pe rm ane nce la valeur du
"caract re pr cdent" ;ce dernie r s e ra initialis une valeur q ue lconq ue diff re nte de \n pour vite r un traite m e nt
particulie r du pre m ie r caract re du te xte .
- ligne vide pour la s e conde .

Program m e bas s ur l
a r p tition du traite m e nt d'un caract re

#include <stdio.h>
#define VRAI 1
#define FAUX 0

/* pour "simuler" des ..... */


/* ..... valeurs logiques */

main()
{ int sep(char) ;
char c,
cprec ;
int nmots,
fin_texte,
mot_en_cours ;

/*
/*
/*
/*
/*
/*

prototype fonction test "caractre sparateur?" */


pour lire un caractre frapp au clavier */
caractre prcdent */
compteur du nombre de mots */
indicateurs logiques : - fin texte atteinte */
- mot trouv */

cprec = ' ' ;


fin_texte = FAUX ;
mot_en_cours = FAUX ;
nmots = 0 ;
printf ("donnez votre texte, en le terminant par une ligne vide\n") ;
while (!fin_texte)
{ if ( sep(c=getchar()) )
{ if (mot_en_cours)
{ nmots++ ;
mot_en_cours = FAUX ;
}

112

Exe rcice s e n langage C


}
else mot_en_cours = VRAI ;
if ( c=='\n' && cprec=='\n') fin_texte = VRAI ;
cprec = c ;
}
printf ("\n\nvotre texte comporte %d mots :\n", nmots) ;

}
/*******************************************/
/*
fonction d'examen d'un caractre
*/
/*******************************************/
int sep (char c)
{
char sep[12] = {'\n',
/* fin de ligne */
' ',
/* espace */
',', ';', ':', '.', '?', '!',
/* ponctuation */
'(', ')',
/* parenthses */
'"', '\'' } ;
/* guillemets, apostrophe*/
int nsep=12,
/* nombre de sparateurs */
i ;
i = 0 ;
while ( c!=sep[i] && i++<nsep-1 ) ;
if (i == nsep) return (0) ;
else return (1) ;
}

Com m e ntaire s
*Nous avons introduit une variable "logiq ue " nom m e fin_te xte q ui nous facilite la dte ction de la fin du te xte . Nous
aurions pu nous en passer en introduisant une instruction bre ak au s e in d'une boucle do ... w h ile {1}(boucle infinie ).
*D ans le traite m e nt de ch aq ue caract re , nous n'avons pas respect " la lettre " l'algorith m e propos lors de l'analyse.
En e ffe t, nous e x cutons l'instruction :
mot_en_cours = VRAI

m m e s i l'indicate ur m ot_e n_cours a dj la valeur VR A I ;ce la nous vite un te s t supplm e ntaire , sans m odifie r le
com porte m e nt du program m e (puis q ue la m odification ainsi apport e consiste m e ttre VR A I l'indicate ur alors q u'ily
e s t dj ).

I. Variations algorith m iques sur les instructions de base

113

*D ans la fonction s e p, la s e ule instruction :


while ( c!=sep[i] && i++<nsep-1 ) ;

pe rm e t de savoir si le caract re c e s t un s parate ur. En e ffe t, ilne faut pas oublie r q ue l'op rate ur & & n' value s on
s e cond op rande q ue lors q ue ce la e s t n ce s s aire . Autre m e nt dit, si la pre m i re condition e s t faus s e (c e s t donc gal un
s parate ur), l'e xpre s s ion i++<nsep-1 n'e s t pas valu e e t i n'e s t donc pas incr m e nt e . Si, par contre , ce tte pre m i re
condition e s t v rifi e alors q u'on a e xplor la totalit des sparate urs (i=11), la s e conde condition e s t valu e e t e lle e s t
trouv e faus s e , m ais e n m m e te m ps, i s e trouve incr m e nt e ( 12).
En d finitive , on voit q u' la fin de ce tte instruction, lors q ue i vaut 12, ce la signifie q ue c ne figure pas dans la liste des
s parate urs.

Program m e bas s ur l
a r p tition du traite m e nt d'une l
igne
#include <stdio.h>
#include <string.h>
#define VRAI 1
#define FAUX 0
main()
{
int sep(char) ;
char ligne[128] ;
int nmots,
mot_en_cours,
i ;

/* pour "simuler" des ..... */


/* ..... valeurs logiques */

/*
/*
/*
/*

prototype fonction test "caractre sparateur?" */


pour lire une ligne frappe au clavier */
compteur du nombre de mots */
indicateur logique : mot trouv */

nmots = 0 ;
mot_en_cours = FAUX ;
printf ("donnez votre texte, en le terminant par une ligne vide\n") ;
do
{ gets(ligne) ;
for (i=0 ; i<=strlen(ligne) ; i++)
/* on traite aussi le '\0' */
if ( sep(ligne[i]) )
{ if (mot_en_cours)
{ nmots++ ;
mot_en_cours = FAUX ;
}
}
else mot_en_cours = VRAI ;
}
while (strlen(ligne)) ;

114

Exe rcice s e n langage C


printf ("\n\nvotre texte comporte %d mots :\n", nmots) ;

}
/********************************************/
/*
fonction d'examen d'un caractre
*/
/********************************************/
int sep (char c)
{
char sep[12] = {'\0',
/* fin de ligne (chane) */
' ',
/* espace */
',', ';', ':', '.', '?', '!',
/* ponctuation */
'(', ')',
/* parenthses */
'"', '\'' } ;
/* guillemets, apostrophe*/
int nsep=12,
/* nombre de sparateurs */
i ;
i = 0 ;
while ( c!=sep[i] && i++<nsep-1 ) ;
if (i == nsep) return (0) ;
else return (1) ;
}

Com m e ntaire s
Nous avons d :
- d'une part, au s e in de la fonction s e p, re m place r le s parate ur \n par \0,
- d'autre part, dans la boucle de traite m e nt des caract res d'une ligne , traite r com m e les autre s ce caract re de fin de
ligne (c'e s t- -dire faire varie r i de 0 strlen(ligne ) e t non strlen(ligne )-1), afin d' vite r de com pte r pour un s e ulm ot
le dernie r m ot d'une ligne (non suivi d'un sparate ur) e t le pre m ie r de la suivante .

D is cus s ion
*En ce q ui conce rne la fonction d'e xam e n d'un caract re (nom m e s e p), vous constate z (dans les deux ve rsions
propos e s ) q ue nous l'avons dclare dans le program m e principal(m ain), bie n q ue ce la soit facultatif, dans la m e s ure o
e lle fournit un r s ultat de type int.
*Aucun des deux program m e s propos s ne pose de problm e de prote ction vis- -vis des rponses fournie s par
l'utilisate ur.

II : UTILISATIO N
D E STRUCTURES

Le ch apitre I vous a propos des exe rcice s faisant appe laux instructions de base du langage C. Le s e xe rcices de ce
ch apitre font inte rve nir, e n plus, la notion de structure sous des form es dive rs e s (e n particulie r les tableaux de s tructure s
e t leur initialisation).

II-1 Signe du zodiaq ue


________________________________________________________________________________________

Enonc
Affich e r le s igne du zodiaq ue corre s pondant une date de naissance fournie e n donn e , sous la form e :
jour m ois
Les deux inform ations s e ront s par e s par au m oins un espace. La pre m i re s e ra fournie s ous form e num riq ue , tandis
q ue la s e conde le s e ra sous form e d'une ch a
ne de caract re s .
Nous vous rappe lons q ue les p riode s corre s pondant ch aq ue s igne s ont les s uivante s :
Capricorne
Verseau
Poisson

23 dcembre - 19 janvier
20 janvier - 19 fvrier
20 fvrier - 20 mars

116

Exe rcice s e n langage C


Blier
Taureau
Gmeau
Cancer
Lion
Vierge
Balance
Scorpion
Sagittaire

21
20
21
21
22
23
23
23
22

mars - 19 avril
avril - 20 mai
mai - 20 juin
juin - 21 juillet
juillet - 22 aot
aot - 22 septembre
septembre - 22 octobre
octobre - 21 novembre
novembre - 22 dcembre

Exe m pl
es
donnez votre jour et votre mois (sans accent) de naissance ?
11 july
*** erreur de nom de mois ***
_______________________
donnez votre jour et votre mois de naissance ?
16 janvier
vous tes n sous le signe suivant : Capricorne
________________________________________________________________________________________

ANALYSE
Le program m e doit tre e n m e s ure d'tablir une corre s pondance e ntre le nom d'un signe e t les deux date s lim ite s
corre s pondante s . O n pe ut dj note r q ue la date de fin d'un signe e s t la ve ille de ce lle de dbut du suivant. Nous nous
conte nte rons donc de ne cons e rve r q u'une s e ule de ces deux inform ations, par e xe m ple la date de fin.
La corre s pondance s ouh ait e pe ut tre r alise :
- par plusieurs tableaux (jour, m ois, signe) re li s par une valeur com m une d'indice .
- par un s e ultableau dans leq ue lch aq ue lm e nt e s t une structure com portant un num ro de jour, un nom de m ois e t
un nom de signe.
Nous ch oisirons la s e conde s olution car e lle pe rm e t de m ie ux m e ttre e n vidence la corre s pondance e ntre les
inform ations, au m om e nt de l'initialisation au s e in du program m e .
La re ch e rch e du signe correspondant une date donne se fait alors de la m ani re s uivante :
- O n ch e rch e tout d'abord l' lm e nt (nous le nom m e rons x) apparte nant notre tableau de s tructure s , dont le nom de
m ois corre s pond ce lui propos e n donn e . S'iln'e xiste pas, on le s ignale par un m e s s age appropri .

II. Utilisation de s tructure s


- O n re garde e nsuite s i le num ro du jour propos e s t inf rie ur ou gal ce lui de l' lm e nt x.

117

D ans l'affirm ative , on pe ut e n conclure q ue la date propos e e s t ant rie ure la date de fin du signe figurant dans
l' lm e nt x, ce q ui fournit la r pons e voulue .
D ans le cas contraire , on e n conclut q ue la date propos e e s t post rie ure la date de dbut du signe figurant dans
l' lm e nt x ;ilsuffit donc d'e xam ine r l' lm e nt suivant pour obte nir la r pons e voulue . Toute fois, si x est le
dernie r lm e nt de notre tableau, ilfaudra considrer que son suivant e s t e n fait le pre m ie r lm e nt du tableau.
O n re m arq ue ra q ue l'algorith m e propos fonctionne e ffe ctive m e nt parce q ue ch acun de s 12 m ois de l'ann e ne com porte
q u'un s e ulch ange m e nt de signe. Si ce la n'avait pas t le cas, ilaurait fallu "e ncadre r" la date propos e par de ux date s
d'lm e nts cons cutifs de notre tableau.

Program m e

#include <stdio.h>
#include <conio.h>
#include <string.h>
main()
{
struct s_date { int jour ;
char mois [10] ;
char signe [11] ;
} ;
struct s_date date [12] = { 23, "decembre", "Sagittaire",
20, "janvier",
"Capricorne",
20, "fevrier",
"Verseau",
21, "mars",
"Poisson",
20, "avril",
"Blier",
21, "mai",
"Taureau",
21, "juin",
"Gmeau",
22, "juillet",
"Cancer",
23, "aout",
"Lion",
23, "septembre", "Vierge",
23, "octobre",
"Balance",
22, "novembre", "Scorpion"
} ;
int jour_n ;
/* jour de naissance */
char mois_n [10] ;
/* mois de naissance */
int nbv, i ;

118

Exe rcice s e n langage C


/* lecture date de naissance */
printf ("donnez votre jour et votre mois de naissance ?\n") ;
scanf ("%d %s", &jour_n, mois_n) ;
/* recherche et affichage du signe correspondant */
i = 0 ;
while ( stricmp(date[i].mois, mois_n) && i++<11 ) { }
if (i<12)
{ printf ("vous tes n sous le signe suivant : ") ;
if (jour_n >= date[i].jour) i = (i+1)%12 ;
printf ("%s", date[i].signe) ;
}
else printf ("*** erreur de nom de mois ***") ;

Com m e ntaire s
*Nous avons dfini ici un m od le de structure nom m s_date , dans leq ue lnous trouvons un num ro de jour, un nom de
m ois e t le s igne corre s pondant. Nous avons prvu 10 caract re s pour le nom de m ois, ce q ui autorise des ch a
nes de
longue ur inf rie ure ou gale 9 (com pte te nu du \0 de fin) ;de m m e , nous avons prvu 11 caract re s pour le s igne .
Le tableau nom m date e s t un tableau de 12 lm e nts ayant ch acun le type s_date . Nous l'avons initialis dans sa
dclaration, ce q ui pe rm e t de m e ttre facilem e nt e n parallle ch aq ue s igne e t sa date de fin.
*En ce q ui conce rne la lecture de la date au clavie r, nous n'avons pas prvu, ici, de prote ction vis- -vis d've ntue lles
e rre urs de frappe de l'utilisate ur (ce la n' tait pas dem and par l' nonc ).
*R appe lons q ue la fonction stricm p com pare , sans te nir com pte de la distinction m ajuscules /m inuscules , les deux ch a
ne s
dont on lui fournit l'adre s s e e n argum e nt. Elle re s titue une valeur non nulle (q u'on pe ut inte rpr te r com m e vrai) lors q ue
les deux ch a
ne s s ont diff re nte s e t une valeur nulle (faux) lors q u'e lles s ont gales .
*La re ch e rch e du nom de m ois e s t r alise par la s e ule instruction :
while ( stricmp(date[i].mois, mois_n) && i++<11 ) {}

Ce lle-ci poss de un double avantage ;tout d'abord, ce lui de la concision ;e nsuite , ce lui de nous perm e ttre de savoir
dire cte m e nt si la re ch e rch e a t fructue us e ou non.

II. Utilisation de s tructure s


119
En e ffe t, ilne faut pas oublie r q ue l'op rate ur & & n' value s on s e cond op rande q ue lors q ue ce la e s t n ce s s aire .
Autre m e nt dit, si la pre m i re condition e s t faus s e (ily a donc galit des deux ch a
ne s ), l'e xpre s s ion i++<11 n'e s t pas
valu e e t i n'e s t donc pas incr m e nt e . La valeur de i dsigne alors l' lm e nt voulu.
Si, par contre , ce tte pre m i re condition e s t v rifi e (iln'y a donc pas galit des deux ch a
ne s ) alors q u'on e s t arriv e n
fin de table (i=11), la s e conde condition e s t valu e e t e lle e s t trouv e faus s e , m ais e n m m e te m ps i se trouve
incr m e nt e ( 12).
En d finitive , on voit q ue , la fin de ce tte instruction, lors q ue i vaut 12, ce la signifie q ue l' lm e nt ch e rch ne figure pas
dans la table. Dans le cas contraire (i< 12), i d s igne l' lm e nt ch e rch .
Bie n e nte ndu, ce tte "re ch e rch e e n table" pouvait s e program m e r de beaucoup d'autre s m ani re s . Par e xe m ple, nous
aurions pu crire :
while ( stricmp(date[i].mois, mois_n) && i<11 ) i++ ;

Toute fois, ce tte instruction n'e s t pas q uivalente la pr cdente . En e ffe t, lors q ue i vaut 11, ce la pe ut signifie r :
- soit q ue l' lm e nt ch e rch e s t e n position 11 (pre m ie r te s t satisfait),
- soit q ue l' lm e nt ch e rch ne figure pas dans la table (s e cond te s t satisfait).
Pour tranch e r, ile s t donc n ce s s aire , dans ce cas, d'e ffe ctue r une com paraison supplm e ntaire .
Note z q ue , par contre , une instruction te lle q ue :
while ( stricmp(date[i].mois, mois_n) && i++ <= 11) {}

s e rait q ue lque pe u e rron e . En e ffe t, dans le cas o l' lm e nt ch e rch ne figure rait pas dans le tableau, on s e rait am e n
value r l'e xpre s s ion :
date[i].mois

ave c une valeur i gale 12, c'e s t- -dire dsignant un lm e nt situ e n de h ors du tableau. Ce rte s , e n g n ral, ce la ne
s e rait gu re visible dans le com porte m e nt du program m e , dans la m e s ure o ile s t bien peu probable q ue ce tte valeur soit
gale au nom de m ois voulu...
*Note z l'e m ploi de l'op rate ur arith m tiq ue % q ui pe rm e t de r gler le problm e du signe suivant le dernie r signe du
tableau.

D ISCUSSIO N
*Te lq u'ila t pr vu, notre program m e acce pte des nom s de m ois crits e n m inuscules ou e n m ajuscules m ais sans
acce nt. Dans un program m e r e l, ils e rait souh aitable de faire pre uve de plus de tolrance .

120

Exe rcice s e n langage C

*Notre re ch e rch e du nom de m ois a t r alise ici par un algorith m e dit de rech erch e squentiel
l
e en tabl
e (algorith m e
q ui, com m e nous l'avons vu, pe ut s e program m e r e n C l'aide d'une seule instruction). D'autre s algorith m e s plus
rapide s e xiste nt, e n particulie r ce lui dit de rech erch e dich otom ique. L'e xe rcice IV-5 vous en proposera un exem ple.

II-2 Codage m ors e


________________________________________________________________________________________

Enonc
Ecrire un program m e affich ant le codage e n m orse d'un te xte fourni au clavie r e t ne dpassant pas une "ligne " de 127
caract re s . Le s caract re s s usce ptibles d' tre cod s e n m ors e s ont :
- les 26 lettres de l'alph abet (supposes tap e s e n m ajuscul
es),
- les 10 ch iffres de 0 9 ,
- le point,
Si le te xte contie nt d'autre s caract re s q ue ce ux-ci, le program m e affich e ra sim plem e nt des points d'inte rrogation la
place du code m ors e .

Tabl
e au de s code s m ors e s
A
F
K
P
U
Z
0
5

...-.
-..--.
..--..
----.....

B
G
L
Q
V
.
1
6

-...
--.
.-..
--.....-.-..----....

C
H
M
R
W

-.-.
....
-.-.
.--

D
I
N
S
X

-..
..
-.
...
-..-

E
J
O
T
Y

.
.-----.--

2
7

..----...

3
8

...----..

4
9

....----.

Exe m pl
e
donnez votre message (1 ligne maxi) :
LE LANGAGE C, CONCU EN 1972, EST L'OEUVRE DE DENIS RITCHIE.
voici la traduction de votre message

II. Utilisation de s tructure s

121

.-..
. ??????
.-..
.-.
--.
.--.
.
??????
-.-. ?????? ??????
-.-.
---.
-.-.
..- ??????
.
-. ?????? .---- ----. --... ..--- ?????? ??????
.
...
- ??????
.-.. ??????
--.
......-.
. ??????
-..
. ??????
-..
.
-.
..
...
??????
.-.
..
-.-.
....
..
. .-.-.________________________________________________________________________________________

ANALYSE
Le program m e doit donc tre e n m e s ure d'tablir une corre s pondance e ntre un caract re e t son code m ors e . L e ncore ,
nous pourrions utiliser deux tableaux re li s par une valeur com m une d'un indice . M ais l'e m ploi d'un tableau de
structure s pe rm e t de m ie ux m e ttre e n vidence la corre s pondance e ntre les inform ations, lors de l'initialisation. Ch aq ue
lm e nt (structure ) du tableau contie ndra :
- un caract re ,
- le code m ors e corre s pondant, e xprim s ous form e d'une ch a
ne .
Le codage d'un caract re s e fe ra alors sim plem e nt par sa localisation dans le tableau.

Program m e
#include <stdio.h>
#include <string.h>
#define NL 37
main()
{
struct code { char lettre ;
char * morse ;
} ;
struct code table[NL] =
{ 'A', ".-",
'D', "-..",
'G', "--.",
'J', ".---",
'M', "--",
'P', ".--.",
'S', "...",
'V', "...-",

/* nombre de caractres cods */

'B',
'E',
'H',
'K',
'N',
'Q',
'T',
'W',

"-...",
".",
"....",
"-.-",
"-.",
"--.-",
"-",
".--",

/* code morse */
'C', "-.-.",
'F', "..-.",
'I', "..",
'L', ".-..",
'O', "---",
'R',".-.",
'U', "..-",
'X', "-..-",

122

Exe rcice s e n langage C


'Y',
'.',
'0',
'3',
'6',
'9',
} ;
char ligne[128] ;
int i, j ;

"-.--",
".-.-.-",
"-----",
"...--",
"-....",
"----."

'Z', "--..",
'1', ".----",
'4', "....-",
'7', "--...",

'2', "..---",
'5', ".....",
'8', "---..",

/* pour lire une ligne au clavier */

/* lecture message traduire */


printf ("donnez votre message (1 ligne maxi) : \n") ;
gets (ligne) ;
printf ("\n\n voici la traduction de votre message\n") ;
/* traduction lettre par lettre */
for (i=0 ; i<strlen(ligne) ; i++)
{ j=0 ;
while (ligne[i] != table[j].lettre && j++<NL-1) ;
if (j<NL) printf ("%7s", table[j].morse) ;
else printf (" ??????") ;
if ( ! ((i+1)%10) ) printf ("\n") ; /* 10 codes morse par ligne */
}
}

Com m e ntaire s
*Nous avons dfini un m od le de structure , nom m code , dans leq ue lnous trouvons :
- un caract re ,
- un pointeur sur une ch a
ne de caract res destin e conte nir le code m ors e corre s pondant.
Note z q ue , contraire m e nt ce q ue nous avions fait dans le program m e de l'e xe rcice pr cdent, nous avons prvu ici un
pointe ur sur une ch a
ne e t non un tableau de caract re s .
D ans ce s conditions, le tableau table occupe ra s e ulem e nt 37 (valeur de NL) e m place m e nts dont la taille s e ra
g n ralem e nt de 3 ou 5 octe ts (1 pour le caract re e t 2 ou 4 pour le pointe ur). L'e m place m e nt m m e des ch a
ne s
corre s pondante s s e trouve ce pe ndant r s e rv la com pilation, de par le fait q ue nous avons initialis ce tableau lors de sa
dclaration. Ilne faut pas oublie r, e n e ffe t, q u'une notation te lle q ue :
".-.-."

II. Utilisation de s tructure s


123
e s t inte rpr t e par le com pilate ur com m e re pr s e ntant l'adresse de la ch a
ne fournie , m ais q u'e n m m e te m ps illui
r s e rve un e m place m e nt.
Ce tte faon de procder pe ut s e r v ler plus conom iq ue e n place m m oire q ue la pr cdente , dans la m e s ure o ch aq ue
ch a
ne n'occupe q ue l'e s pace q ui lui e s t n ce s s aire (ilfaut toute fois ajoute r, pour ch aq ue ch a
ne , l'e s pace n ce s s aire un
pointe ur).

R e m arque :
En toute rigue ur, le tableau table e s t de clas s e autom atiq u e (puis q u'ilappara
t au s e in d'une fonction - ici le
program m e principal). Son e m place m e nt e s t donc allou au m om e nt de l'e x cution du program m e (c'e s t- -dire , ici,
d s le dbut). Le s constante s ch a
ne s , par contre , voie nt leurs e m place m e nts dfinis d s la com pilation.
Si notre tableau table avait t dclar de m ani re globale, ilaurait t de clas s e statiq u e . Son e m place m e nt aurait
alors t r s e rv d s la com pilation.
Une te lle distinction e s t toute fois re lative m e nt form e lle e t e lle n'a gu re d'incide nce e n pratiq ue . Ile s t, e n e ffe t,
g n ralem e nt, as s e z te ntant de considrer les variables dclares dans le program m e principal com m e "q uasi
statiq ue s ", dans la m e s ure o, bie n q ue non r s e rv e s la com pilation, e lles n'e n n'occupe nt pas m oins de l'e s pace
pe ndant toute la dur e d e l'e x cution du program m e .
*La re ch e rch e du caract re dans notre tableau table e s t r alise par la s e ule instruction :
while (ligne[i] != table[j].lettre && j++<NL-1) ;

D ISCUSSIO N
D ans un program m e "r e l", ilfaudrait pr voir d'acce pte r un m e s s age de plus d'une ligne , ce q ui pos e rait le problm e de
sa m m orisation. O n pourrait tre am e n , soit lui im pos e r une taille m axim ale, soit s e tourne r ve rs des m th odes de
"ge s tion dynam iq ue ".

II-3 D codage m ors e


________________________________________________________________________________________

124

Exe rcice s e n langage C

Enonc
Ecrire un program m e pe rm e ttant de dcode r un m e s s age e n m ors e fourni au clavie r sous form e d'une suite de caract re s .
Ce lle-ci pourra com porte r :
- des points e t des tire ts re pr s e ntant les code s propre m e nt dits,
- un ou plusieurs espaces pour sparer les diff re nts code s (on n'im pos e ra donc pas l'utilisate ur d'e m ploye r un
"gabarit" fixe pour ch aq ue code ).
O n supposera q ue le m e s s age fourni ne dpas s e pas une ligne de 127 caract re s . Le s code s ine xistants s e ront traduits par
le caract re "?".
O n utilisera le tableau de s code s m ors e s fourni dans l'e xe rcice pr cdent (II-2).

Exe m pl
e
donnez votre message (1 ligne maxi) :
-...
--- -.
.----..-

.-.

.-.-.-

.-.-.

voici la traduction de votre message


B O N J O U R . ?
________________________________________________________________________________________

ANALYSE
Ce program m e doit donc tablir une corre s pondance e ntre un code m ors e e t un caract re . Nous pouvons, pour ce faire ,
utiliser la m m e s tructure q ue dans l'e xe rcice pr cdent. Le dcodage d'un caract re s e fe ra alors e n e xplorant, non plus
la partie caract re , m ais la partie ch a
ne du tableau de s tructure . L'algorith m e de re ch e rch e s e ra donc sim ilaire , la
com paraison de caract re s tant re m plac e par une com paraison de ch a
ne s .
En ce q ui conce rne le m e s s age e n m ors e , nous pouvons le lire par ge ts dans un tableau de 128 caract re s , nom m ligne .
Le principalproblm e q ui s e pos e alors nous e s t ce lui de l'acc s ch acun de s code s m ors e s conte nus dans ligne ;e n
e ffe t, ce ux-ci sont crits ave c un gabarit variable e t s par s par un nom bre variable d'espace s .
Nous proposons de r p te r le traite m e nt suivant, fond s ur l'e m ploi d'un pointe ur de caract re s (indice ) dans le tableau
ligne :
- Avance r le pointe ur, tant q u'ildsigne un espace.

II. Utilisation de s tructure s


125
- Extraire , partir de la position indiq u e par le pointe ur, l'aide de sscanf, une ch a
ne de longue ur m axim ale 7
(puis q ue aucun code m ors e ne dpas s e ce tte longue ur). Pour ce la, nous fe rons appe lau code form at %7s, leq ue l
inte rrom pt l'e xploration, soit q uand un s parate ur e s t re ncontr , soit lors q ue la longue ur indiq u e (7) e s t atte inte .
- Incr m e nte r le pointe ur de la longue ur de la ch a
ne ainsi lue (car, bie n sr, iln'aura pas t m odifi par sscanf).

Program m e
#include <stdio.h>
#include <string.h>
#define NL 37
#define LG 127
main()
{
struct code { char lettre ;
char * morse ;
} ;
struct code table[NL] =
{ 'A', ".-",
'D', "-..",
'G', "--.",
'J', ".---",
'M', "--",
'P', ".--.",
'S', "...",
'V', "...-",
'Y', "-.--",
'.', ".-.-.-",
'0', "-----",
'3', "...--",
'6', "-....",
'9', "----."
} ;
char ligne[LG+1] ;
char code[7] ;
int i, j ;

/* nombre de caractres cods */


/* longueur ligne clavier */

'B',
'E',
'H',
'K',
'N',
'Q',
'T',
'W',
'Z',

"-...",
".",
"....",
"-.-",
"-.",
"--.-",
"-",
".--",
"--..",

'1', ".----",
'4', "....-",
'7', "--...",

/* code morse */
'C', "-.-.",
'F', "..-.",
'I', "..",
'L', ".-..",
'O', "---",
'R',".-.",
'U', "..-",
'X', "-..-",

'2', "..---",
'5', ".....",
'8', "---..",

/* pour lire une ligne au clavier */


/* code courant traduire */

/* lecture message traduire */


printf ("donnez votre message (1 ligne maxi) : \n") ;
gets (ligne) ;
printf ("\n\n voici la traduction de votre message\n") ;

126

Exe rcice s e n langage C


/* traduction code par code */
i=0 ;
while (i<strlen(ligne))
{
while (ligne[i] == ' ') i++ ;
/* saut des espaces ventuels
if ( i<strlen(ligne) )
/* si pas en fin de ligne
{ sscanf (&ligne[i], "%6s", code); /* lecture code (6 car max)
i += strlen(code) ;
/* incrment pointeur dans ligne
j=0 ;
/* recherche code dans table
while ( stricmp (code, table[j].morse) && j++<NL-1) ;
if (j<NL) printf ("%2c", table[j].lettre) ;
/* code trouv
else printf (" ?") ;
/* code non trouv
}
}

*/
*/
*/
*/
*/
*/
*/

Com m e ntaire s
*D ans la boucle de saut des espace s ve ntue ls, on ne ris q ue pas d'aller au-de l de la fin de la ch a
ne conte nue dans
ligne , car le caract re de fin (\0), diff re nt d'un e s pace , s e rvira de "s e ntine lle".
*Par contre , avant d'extraire un nouve au code par sscanf, ile s t n ce s s aire de s'assure r q ue l'on n'e s t pas parve nu e n fin
de ligne . En e ffe t, dans ce cas, sscanf fournirait une s uite de caract re s constitue du caract re \0 (q ui n'e s t pas considr
par ce tte fonction com m e un s parate ur) e t des caract re s s uivants (pr lev s e n de h ors du tableau ligne ). Note z q ue , e n
l'abs e nce d'un te lte s t, le m alne s e rait pas tr s grave puis q u'ilre vie ndrait sim plem e nt place r au plus 7 caract res dans
code , com m e nant par \0.
*La re ch e rch e du code m orse dans le tableau table e s t r alise par la s e ule instruction :
while ( stricmp (code, table[j].morse) && j++<NL-1) ;

Le s re m arq ue s faites dans le q uatri m e com m e ntaire de l'e xe rcice II-1, propos de la re ch e rch e s q ue ntie lle e n table,
s'appliq ue nt galem e nt ici.

D ISCUSSIO N

II. Utilisation de s tructure s


127
Notre program m e ne dte cte pas le cas o l'utilisate ur fournit un code m orse de plus de 6 caract re s . Dans ce cas, en
e ffe t, ils e conte nte de le "dcoupe r" e n tranch es de 6 caract re s (la derni re tranch e pouvant avoir une longue ur
inf rie ure ).
Si l'on souh aitait dte cte r ce ge nre d'anom alie , il faudrait, apr s ch aq ue e xam e n d'un code , s'assure r q u'il e s t
e ffe ctive m e nt suivi d'un e s pace ou d'une fin de ch a
ne .

II-4 Facturation par code


________________________________________________________________________________________

Enonc
R aliser un program m e tablissant une facture pouvant porte r sur plusieurs articles . Pour ch aq ue article facture r,
l'utilisate ur ne fournira q ue la quantit e t un num ro de code partir duq ue lle program m e devra re trouve r la fois le
libell e t le prix unitaire .
Le program m e devra re fus e r les code s ine xistants. A la fin, ilaffich e ra un r capitulatif te nant lie u de facture .
Le s inform ations re lative s aux diff re nts articles s e ront dfinies dans le s ource m m e du program m e (e t non dans un
fich ie r de donnes). Elle s e ront toute fois plac e s un nive au gl
obal
, de m ani re pouvoir, le cas ch ant, faire l'obje t
d'un source s par , appe lable par #include .
O n pr voira de ux fonctions :
- une pour re ch e rch e r les inform ations re lative s un article, partir de s on num ro de code ,
- une pour affich e r la facture r capitulative .

Exe m pl
e
combien d'articles facturer ? 3
code article ? 25
quantit de Centrifugeuse au prix unitaire de
code article ? 7
** article inexistant - redonnez le code : 16

370.00 ? 33

128

Exe rcice s e n langage C

quantit de Grille-pain au prix unitaire de


199.50 ? 12
code article ? 26
quantit de Four raclette 6P au prix unitaire de
295.25 ? 6
FACTURE
ARTICLE
Centrifugeuse
Grille-pain
Four raclette 6P

TOTAL

NBRE

P-UNIT

MONTANT

33
12
6

370.00
199.50
295.25

12210.00
2394.00
1771.50

16375.50

________________________________________________________________________________________

ANALYSE
L' nonc nous prcise que les codes d'articles s ont num riq ue s , m ais ilne dit pas q u'ils sont cons cutifs. Dans ces
conditions, ile s t n ce s s aire de m m oris e r les diff re nte s valeurs possibles de ce s code s . Com m e nous devons pouvoir
associe r ch aq ue code un libell (ch a
ne ) e t un prix (r e l), nous pouvons songe r utiliser un tableau de s tructure s , dans
leq ue lch aq ue lm e nt contie nt les inform ations re lative s un article (code , libell, prix unitaire ). Ce tableau s e ra,
com m e dem and par l' nonc , dclar un nive au globale t initialis dans sa dclaration.
Le travailde la fonction de re ch e rch e (nous la nom m e rons re ch e rch e ) consiste ra v rifie r la pr s e nce du code d'article
dans le tableau de s tructure ainsi dfini. En cas de succ s, e lle e n re s titue ra le rang (ce q ui s e ra suffisant au program m e
principalpour affich e r les inform ations corre s pondante s ). Dans le cas contraire , e lle re s titue ra la valeur -1. Note z q ue le
code d'article s e ra le s e ulargum e nt de ce tte fonction.
Nous voyons donc d j com m e nt, pour ch aq ue code (corre ct) fourni par l'utilisate ur, affich e r les inform ations
corre s pondante s avant d'en dem ande r la q uantit . M ais, com pte te nu de ce q ue l'dition de la facture doit tre faite apr s
les s aisies re lative s tous les articles , nous devons obligatoire m e nt, pour ch aq ue article facture r, cons e rve r :
- la q uantit ,
- une inform ation pe rm e ttant d'en retrouve r le libell e t le prix unitaire . Nous pourrions, ce rte s , arch ive r ce s
inform ations dans un tableau. M ais, e n fait, ce la n'e s t pas nce s s aire puis q u'ile s t possible de les re trouve r partir du
rang de l'article dans la structure (le code article convie ndrait galem e nt, m ais ilnous faudrait alors e xplore r
nouve au notre tableau de s tructure s lors de l'dition de la facture ).
Ces deux inform ations s e ront cons e rves dans deux tableaux (nom m s q te e t rangart) com portant autant d'lm e nts q ue
d'articles facture r (on e n pr voira un nom bre m axim al).

II. Utilisation de s tructure s


129
La fonction d'dition de la facture (nom m e facture ) s e conte nte ra alors d'explore r s q ue ntie llem e nt ces deux tableaux
pour re trouve r toute s les inform ations nce s s aire s . Elle re ce vra, e n argum e nt, les adresses des deux tableaux (q te e t
rangart), ainsi que le nom bre d'articles facture r.

Program m e
#include <stdio.h>
/* ------ structure contenant les informations relatives aux
*/
/*
diffrents articles
-------------- */
#define NBART 6
/* nombre total d'articles */
typedef struct { int code ;
/* code article */
char * lib ;
/* libell */
float pu ;
/* prix unitaire */
} t_article ;
t_article article [NBART] =
{ 11, "Gaufrier",
268.0,
14, "Cafetire 12 T",
235.0,
16, "Grille-pain",
199.50,
19, "Balance de mnage", 278.0,
25, "Centrifugeuse",
370.0,
26, "Four raclette 6P", 295.25
} ;
/* ----------------------------------------------------------------------*/
#define NAFMAX 10

/* nombre maxi d'articles facturer */

main()
{
int recherche(int) ;
void facture(int[], int[], int) ;
int naf,
rang,
codart,
i ;
int rangart [NAFMAX],
qte [NAFMAX] ;

/*
/*
/*
/*
/*

proto fonction de recherche d'un article */


proto fonction d'affichage de la facture */
nombre d'articles facturer */
rang courant d'un article */
code courant d'un article */

/* rang des articles facturer */


/* quantit de chaque article facturer */

/* entre du nombre d'articles facturer */


printf ("combien d'articles facturer ? ") ;
scanf ("%d", &naf) ;

130

Exe rcice s e n langage C


/* boucle de traitement de chaque article facturer */
for (i=0 ; i<naf ; i++)
{
printf ("code article ? ") ;
do
{ scanf ("%d", &codart) ;
rang = recherche (codart) ;
if (rang == -1)
printf (" ** article inexistant - redonnez le code : ") ;
}
while (rang == -1) ;
rangart[i] = rang ;
printf ("quantit de %s au prix unitaire de %8.2f ?
",
article[rang].lib, article[rang].pu) ;
scanf ("%d", &qte[i]) ;
}
/* affichage facture */
facture (rangart, qte, naf) ;

}
/***********************************************************/
/*
fonction de recherche d'un code article
*/
/***********************************************************/
int recherche (int codart)
{
int rang ;
/* rang courant d'un article */
rang = 0 ;
while (article[rang].code != codart && rang++ < NBART-1) {} ;
if (rang <NBART) return (rang) ;
else return (-1) ;
}
/***********************************************************/
/*
fonction d'affichage de la facture
*/
/***********************************************************/
void facture(int rangart[], int qte[], int naf)
/* rangart : tableau des rangs des codes articles */
/* qte :tableau des prix unitaires */
/* naf :nombre d'articles facturer */
{
float somme,
/* total facture */
montant ;
/* montant relatif un article */
int i ;

II. Utilisation de s tructure s

131

printf ("\n\n %32s\n\n", "FACTURE") ;


printf ("%-20s%5s%10s%12s\n\n",
"ARTICLE", "NBRE", "P-UNIT", "MONTANT") ;
somme = 0 ;
for (i=0 ; i<naf ; i++)
{ montant = article[rangart[i]].pu * qte[i] ;
printf ("%-20s%5d%10.2f%12.2f\n",
article[rangart[i]].lib, qte[i],
article[rangart[i]].pu, montant) ;
somme += montant ;
}
printf ("\n\n%-35s%12.2f", "
TOTAL", somme) ;
}

Com m e ntaire s
*Nous avons ch oisi ici d'utilise r type de f pour d finir sous le nom t_article la structure corre s pondant un article. Vous
constate z q ue le libell y appara
t sous la form e d'un pointe ur sur une ch a
ne e t non d'une ch a
ne ou d'un tableau de
caract re s . Dans ces conditions, le tableau article, dclar de ce type , n'occupe ra q ue 6 e m place m e nts de petite taille
(g n ralem e nt 6 ou 8 octe ts)
*L e ncore , une s e ule instruction pe rm e t d'effe ctue r la re ch e rch e d'un code article dans le tableau article. Voye z, ce
propos, les re m arq ue s faites dans le q uatri m e com m e ntaire de l'e xe rcice II-1.
*Le code form at %-20s, utilis deux reprises dans la fonction facture , pe rm e t de "cadre r" une ch a
ne gauch e .

D ISCUSSIO N
*Notre program m e n'e s t pas prot g contre des r pons e s incorre ctes de la part de l'utilisate ur. En particulie r, une
r pons e non num riq ue pe ut e ntra
ne r un com porte m e nt as s e z dsagr able. Dans un program m e r e l, ils e rait n ce s s aire
de r gler conve nablem e nt ce type de problm e , par e xe m ple e n utilisant fge ts (..., stdin) e t sscanf.
*D e m m e , dans un program m e r e l, ilpourrait tre judicie ux de dem ande r l'utilisate ur de confirm e r q ue le produit
ch e rch e s t bien celui dont on vie nt de lui affich e r les inform ations.

132

Exe rcice s e n langage C

*La pr cision offe rte par le type float (6 ch iffre s s ignificatifs) pe ut s e r v ler insuffisante .

III : H ASARD ET
RECREA TIO NS

Ce ch apitre vous propose un certain nom bre d'exercices correspondant la r alisation de program m e s r cr atifs, bas s
sur l'utilisation du h asard.
Les deux pre m ie rs e xe rcice s s ont e s s e ntie llem e nt destin s vous m ontre r com m e nt g n re r de s nom bre s alatoire s e n
langage C.

III-1 Tirage al
atoire
________________________________________________________________________________________

Enonc
Ecrire une fonction fournissant un nom bre e ntie r tir au h asard e ntre 0 (inclus) e t une valeur n (inclus e ) fournie e n
argum e nt.
R aliser un program m e principalutilisant ce tte fonction pour e xam ine r la "distribution" de s valeurs ainsi obte nues dans
l'inte rvalle [0, 10]. Le nom bre de tirage s r aliser sera lu e n donn e e t le program m e affich e ra le nom bre de fois o
ch acune de ce s valeurs aura t obte nue .

Exe m pl
e
combien de tirages : 1100
nombre de tirages obtenus
0 :
106
1 :
95

134

Exe rcice s e n langage C


2
3
4
5
6
7
8
9
10

:
:
:
:
:
:
:
:
:

115
95
91
103
103
101
92
94
105

Indication : ile s t n ce s s aire de faire appe l la fonction rand de la "biblioth q ue s tandard".


________________________________________________________________________________________

ANALYSE
Ilfaut faire appe l la fonction rand. Ce lle-ci fournit un nom bre e ntie r, tir de faon "ps e udo-alatoire " dans l'inte rvalle
[0, R A ND_M A X] , ch aq ue nom bre de ce t inte rvalle ayant q uasim e nt la m m e probabilit d' tre tir . Note z q ue la valeur
de RAND_M AX e s t dfinie dans stdlib.h ;d'apr s la norm e , e lle n'e s t jam ais inf rie ure la capacit m inim ale d'un int,
c'e s t- -dire 32767.
Pour aboutir au r s ultat voulu, une dm arch e consiste transform e r un te lnom bre e n un nom bre r e lapparte nant
l'inte rvalle [0,1[. Ilsuffit e nsuite de m ultiplie r ce r e lpar n+1 e t d'en prendre la partie e nti re pour obte nir le r s ultat
e s com pt . O n pe ut alors m ontre r q ue les valeurs 0, 1, ... n-1, n sont q uasi quiprobables .
Pour obte nir un te lnom bre alatoire , nous pouvons diviser le nom bre fourni par rand par la valeur RAND_M AX+ 1 (il
faut vite r de diviser par RAND_M AX, car la valeur 1 ris q ue rait alors d' tre obte nue - e n m oye nne une fois sur
RAND_M AX!). L e ncore , on pe ut, de m ani re form e lle, m ontre r q ue s i la loi de probabilit e s t uniform e s ur [0,1[, ile n
va de m m e de ce lle du nom bre ainsi fabriq u dans l'inte rvalle d'entie rs [0,n].

Program m e

#include <stdio.h>
#include <stdlib.h>

/* pour la fonction rand */

#define N 10

/* les tirages se feront entre 0 et N */

main()
{

III. H asard e t r cr ations


int aleat (int) ;
int ntir,
t[N+1],
i ;

135

/* prototype fonction de tirage alatoire */


/* nombre de tirages requis */
/* tableau comptage tirages de chaque valeur */

printf ("combien de tirages : ") ;


scanf ("%d", &ntir) ;
for (i=0 ; i<=N ; i++)
t[i] = 0 ;
for (i=1 ; i<=ntir ; i++)
t[aleat(N)]++ ;
printf ("nombre de tirages obtenus\n") ;
for (i=0 ; i<=N ; i++)
{ printf ("%4d : ", i) ;
printf ("%6d\n", t[i]) ;
}
}
/********************************************************/
/* fonction de tirage alatoire d'un nombre dans [0, n] */
/********************************************************/
int aleat (int n)
{
int i ;
i = rand() / (RAND_MAX + 1.) * (n+1) ;
return (i) ;
}

Com m e ntaire s
*D ans la fonction aleat, la division par RAND_M AX+ 1 doit bien sr s'effe ctue r sur des valeurs r e lles . M ais, de plus, il
faut pre ndre garde ne pas crire le diviseur sous la form e RAND_M AX + 1. En e ffe t, ce lui-ci s e rait valu dans le type
int e t, dans le cas (fr q ue nt) o la valeur de RAND_M AX e s t e xacte m e nt la valeur m axim ale du type int, l'addition de 1
RAND_M AX conduirait la valeur ... -1 (le dpas s e m e nt de capacit n' tant jam ais dte ct e n cas d'oprations sur de s
e ntie rs).

D ISCUSSIO N

136
Exe rcice s e n langage C
En g n ral, la fonction rand fournit toujours la m m e s uite de valeurs, d'une e x cution une autre . L'e xe rcice s uivant
vous m ontre com m e nt vite r ce ph nom ne .

III-2 Tirage al
atoire variabl
e
________________________________________________________________________________________

Enonce
Ecrire une fonction fournissant un nom bre e ntie r tir au h asard e ntre 0 e t une valeur n fournie e n argum e nt. La suite des
valeurs re s titu e s par ce tte fonction (lors q u'on l'appe lle dive rs e s re pris e s ) devra tre diff re nte d'une excution une
autre e t ne pas dpendre d'une quelconq ue inform ation fournie par l'utilisate ur.
Com m e dans l'e xe rcice pr cdent, on r alisera un program m e principal utilisant ce tte fonction pour e xam ine r la
"distribution" de s valeurs ainsi obte nues dans l'inte rvalle [0,10]. Pour ce faire , on lira e n donn e s le nom bre de tirage s
r aliser et le program m e affich e ra le nom bre de fois o ch acune des valeurs aura t obte nue .
Suggestion : ilfaut "initialiser" conve nablem e nt le "g n rate ur de nom bre s alatoire ", e n utilisant la fonction srand. La
"gra
ne " n ce s s aire pe ut tre fabriq u e l'aide de la fonction tim e , de faon avoir un caract re s uffisam m e nt
im pr visible.

Exe m pl
es
(ils'agit l des r s ultats corre s pondant deux excutions diff re ntes du m m e program m e )
combien de tirages : 1100
nombre de tirages obtenus
0 :
124
1 :
104
2 :
97
3 :
97
4 :
89
5 :
93
6 :
105

III. H asard e t r cr ations


7
8
9
10

:
:
:
:

137

109
110
89
83
___________________

combien de tirages : 1100


nombre de tirages obtenus
0 :
104
1 :
98
2 :
98
3 :
106
4 :
98
5 :
97
6 :
99
7 :
109
8 :
99
9 :
96
10 :
96
________________________________________________________________________________________

ANALYSE
En langage C, la fonction srand pe rm e t d'initialiser le g n rate ur de nom bre s alatoire s . Ilfaut ce pe ndant lui fournir une
"gra
ne ", c'e s t- -dire un nom bre e ntie r (de type unsigne d int) q ui d te rm ine ra le pre m ie r nom bre tir par rand. Ce tte
m th ode pe rm e t ainsi, si on le s ouh aite , d'obte nir volont une m m e s uite de nom bre s alatoire s ;ilfaut d'ailleurs
note r q ue , par d faut, tout s e pas s e com m e s i srand tait appe l, e n dbut de l'e x cution d'un program m e , ave c
l'argum e nt 1.
Ici, par contre , nous souh aitons obte nir une s uite diff re nte d'une excution une autre . Une s olution ce problm e
consiste ch oisir une "gra
ne " alatoire . Bie n sr, iln'e s t pas q ue s tion de faire appe l rand dans ce cas. Par contre , la
fonction tim e fournit une date , e xprim e e n s e conde s . Ce lle-ci poss de un caract re s uffisam m e nt im pr visible pour tre
utilise com m e gra
ne .
Ce tte initialisation du g n rate ur de nom bre s alatoires doit toute fois n' tre r alise qu'une seule fois pour une e x cution
donn e . Dans le cas contraire , on ris q ue rait, e n e ffe t, d'obte nir plusieurs fois de suite les m m e s nom bre s . Si l'on
souh aite q ue ce problm e s oit pris e n ch arge par la fonction de tirage d'un nom bre e lle-m m e , ile s t n ce s s aire q ue ce tte
derni re s oit capable de le faire lors de son prem ie r appe l(e t uniq ue m e nt ce m om e nt-l). Ce m canism e pas s e par
l'e m ploi d'une variable de clas s e statiq u e .

138

Exe rcice s e n langage C

Program m e
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* pour la fonction rand */


/* pour la fonction time */

#define N 10

/* les tirages se feront entre 0 et N */

main()
{
int aleat (int) ;
int ntir,
t[N+1],
i ;

/* prototype fonction de tirage alatoire */


/* nombre de tirages requis */
/* tableau comptage tirages de chaque valeur */

printf ("combien de tirages : ") ;


scanf ("%d", &ntir) ;
for (i=0 ; i<=N ; i++)
t[i] = 0 ;
for (i=1 ; i<=ntir ; i++)
t[aleat(N)]++ ;
printf ("nombre de tirages obtenus\n") ;
for (i=0 ; i<=N ; i++)
{ printf ("%4d : ", i) ;
printf ("%6d\n", t[i]) ;
}
}
/********************************************************/
/* fonction de tirage alatoire d'un nombre dans [0, n] */
/********************************************************/
int aleat (int n)
{
int i ;
static int prem = 1 ; /* drapeau premier appel */
time_t date ;
/* pour l'argument de time */
/* time_t est un type entier dfini dans time.h */
/* initialisation gnrateur au premier appel */
if (prem)
{ srand (time(&date)) ;
prem = 0 ;
}

III. H asard e t r cr ations

139

/* gnration nombre */
i = rand() / (RAND_MAX + 1.) * (n+1) ;
return (i) ;
}

Com m e ntaire s
*Le m canism e du traite m e nt particulie r e ffe ctue r au pre m ie r appe le s t r alis gr ce la variable pre m , dclar e d e
clas s e s tatiq ue . Ce tte variable e s t initialise un, lors de la com pilation. D s le pre m ie r appe l, e lle e s t m ise z ro e t e lle
garde ra e nsuite ce tte valeur jus q u' la fin de l'e x cution du program m e . Ainsi, la fonction srand n'e s t e ffe ctive m e nt
appe le q u'une s e ule fois, lors du prem ie r appe lde notre fonction aleat.
*La fonction tim e fournit e n re tour le te m ps (e xprim e n s e conde s ) coul depuis une certaine "origine " dpendant de
l'im plm e ntation. Le type de ce tte valeur d pe nd, lui aussi, de l'im plm e ntation ;toute fois, la norm e pr voit q u'ile xiste ,
dans tim e .h , un sym bole tim e _t (dfini par type de f) pr cisant le type e ffe ctive m e nt e m ploy . Ici, lors q ue nous
transm e ttons ce tte valeur srand, ile s t possible q u'apparais s e une conve rsion du type tim e _t dans le type unsigne d int ;
ici, ce la n'a gu re d'im portance , dans la m e s ure o, m m e s i ce tte conve rsion est "dgradante ", la valeur obte nue re s te ra
im pr visible pour l'utilisate ur.
D 'autre part, la fonction tim e ne s e conte nte pas de fournir une "h e ure " e n re tour ;e lle range galem e nt ce tte m m e
inform ation l'adre s s e q u'on lui fournit (obligatoire m e nt) e n argum e nt ;c'e s t ce q ui justifie l'e xiste nce de la variable
date (q ui n'e s t pas utilise par ailleurs) e t q ui doit, ici, absolum e nt tre dclare dans le "bon type ", sous peine de risquer
d'aboutir un cras e m e nt inte m pe s tif de donnes (dans le cas o on aurait dclar date d'un type "plus petit" q ue le type
e ffe ctif).

III-3 A l
a d' toil
es
________________________________________________________________________________________

140

Exe rcice s e n langage C

Enonc
Affich e r au h asard un ce rtain nom bre d'toiles (caract re "*") l'int rie ur d'un re ctangle. Le nom bre d'toiles
souh ait e s , ainsi que le nom bre de ligne s e t de colonnes du rectangle s e ront fournis e n donn e s .
Le program m e v rifie ra q ue la zone e s t as s e z grande pour re ce voir le nom bre d'toiles re q uis. O n vite ra q ue plusieurs
toiles ne s oie nt superposes.

Exe m pl
e
combien de lignes : 10
combien de colonnes : 45
combien de points : 200
** *
****
** *** * ** *** *
*** **
*
* * ** * ** * * ****** * **
**
* *
** * * * *****
*** **
* *** * *
* *** * *
* * *
**
* *
**
* * ** ** ** **** ** ** ** ** * *
* *
* * **
*** *
* * ** * * * * **
*** ** **
* **
* *
* * **
*
* * *
* ***** **
** * *
* * *****
**
*** * ** * *****
****
* *
***
*
** ****
* *****
________________________________________________________________________________________

ANALYSE
Nous utiliserons un tableau de caract re s deux dim e nsions, dans leq ue lch aq ue lm e nt re pr s e nte ra une case de notre
re ctangle. Nous convie ndrons q ue le pre m ie r indice re pr s e nte le rang de la ligne e t q ue le s e cond indice re pr s e nte le
rang de la colonne . Com m e l'utilisate ur doit pouvoir ch oisir les dim e nsions du rectangle conce rn , nous prvoirons de
donne r notre tableau une taille s uffisante pour couvrir tous les cas possibles (nous avons ch oisi, ici, 25 lignes de 80
caract re s ) ;ce la signifie q ue , la plupart du te m ps, le program m e n'utilisera qu'une partie de ce tableau.
Au dpart, nous initialiserons tous les lm e nts de la "partie utile" de ce tableau ave c le caract re e s pace . Nous
ch oisirons ensuite au h asard les lm e nts dans les q ue ls nous devrons place r un caract re "*". Pour ce faire , ilnous suffira
de tire r au h asard un num ro de ligne e t un num ro de colonne jusqu' ce q ue l'e m place m e nt corre s pondant soit
disponible (caract re e s pace ). L'algorith m e de tirage au h asard d'un nom bre e ntie r apparte nant un inte rvalle donn a
t e xpos dans l'analyse de l'e xe rcice III-1.

III. H asard e t r cr ations


141
Ilne nous re s te ra plus q u' affich e r, par e xe m ple ave c la fonction putch ar, les diff re nts lm e nts de notre tableau, e n
pr voyant un "ch ange m e nt de ligne " aux m om e nts opportuns.

Program m e
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define NY 25
#define NX 80
main()
{
int aleat (int) ;
int ny,
nx,
ix,
iy,
nb_points,
i, j ;
char ecran [NX] [NY] ;
const char blanc = ' ',
point = '*' ;

/* pour memset */
/* nombre total de lignes de l'cran */
/* nombre total de colonnes de l'cran */

/*
/*
/*
/*
/*
/*

prototype fonction tirage alatoire */


nombre de lignes du rect. considr */
nombre de col. du rect. considr */
colonne courante */
ligne courante */
nombre de points tirer */

/* image de l'cran */
/* caractre de remplissage */
/* reprsentation d'un point */

/* entre des dimensions du rectangle considr ...


... et du nombre de points souhaits */
do
{ printf ("combien de lignes : ") ;
scanf ("%d", &ny) ;
}
while (ny<=0 || ny>=NY) ;
do
{ printf ("combien de colonnes : ") ;
scanf ("%d", &nx) ;
}
while (nx<=0 || nx>=NX) ;
do
{ printf ("combien de points : ") ;
scanf ("%d", &nb_points) ;
}
while (nb_points > nx*ny || nb_points < 1 ) ;

142

Exe rcice s e n langage C


/* remplissage alatoire du tableau image d'cran */
memset (ecran, blanc, NX*NY) ;
for (i=1 ; i<=nb_points ; i++)
{ do
{ ix = aleat (nx-1) ;
iy = aleat (ny-1) ;
}
while ( ecran [ix] [iy] != blanc) ;
ecran [ix] [iy] = point ;
}
/* affichage du tableau image d'cran */
for (j=0 ; j<ny ; j++)
{ for (i=0 ; i<nx ; i++)
putchar ( ecran [i] [j] ) ;
printf ("\n") ;
}

}
/*******************************************************/
/* fonction de tirage alatoire d'un nombre dans [0,n] */
/*******************************************************/
int aleat (int n)
{
int i ;
static int prem = 1 ;
/* drapeau premier appel */
time_t date ;
/* pour l'argument de time */
/* initialisation gnrateur au premier appel */
if (prem)
{ srand (time(&date) ) ;
prem = 0 ;
}
/* gnration nombre alatoire */
i = rand() / (RAND_MAX + 1.) * (n+1) ;
return (i) ;
}

Com m e ntaire s

III. H asard e t r cr ations


*L'initialisation de la partie utile du tableau ave c le caract re e s pace aurait pu s e program m e r ainsi :

143

for (i=0 ; i<nx ; i++)


for (j=0 ; j<ny ; j++)
ecran [i][j] = ' ' ;

Ici, nous avons prf r faire appe l la fonction m e m s e t, d'e x cution plus rapide . Toute fois, ce lle-ci re m plit d'un
caract re donn une suite d'octe ts cons cutifs ;ce ci e xclut donc de lim ite r l'initialisation la partie utile du tableau. Ilne
faut pas oublie r, e n e ffe t, q ue ce lle-ci n'e s t pas form e d e nx*ny octe ts cons cutifs (q uoiq ue , e n toute rigue ur, e n te nant
com pte de la m ani re dont sont rang s e n m m oire les diff re nts lm e nts d'un tableau, ilsoit possible de lim ite r
l'initialisation nx*NY lm e nts cons cutifs).
*Nous avons re pris la fonction aleat de l'e xe rcice pr cdent. Ce lle-ci tire une valeur e nti re au h asard e ntre 0 e t une
lim ite q u'on lui fournit e n argum e nt ;de plus, lors de son prem ie r appe l, e lle e ffe ctue une initialisation du g n rate ur de
nom bre s alatoire s .

III-4 Es tim ation de pi


________________________________________________________________________________________

Enonc
Calculer une valeur approch e d e pi, par la m th ode s uivante :
- on tire un ce rtain nom bre de points au h asard dans un carr donn.
- on d te rm ine le rapport e ntre le nom bre de ce s points apparte nant au ce rcle inscrit dans le carr e t le nom bre total
de points tir s . Ce rapport fournit une e s tim ation de la valeur de pi/4.
Le nom bre totalde points tire r s e ra fourni e n donn e .

Exe m pl
e
combien de points ? 10000
estimation de pi avec 10000 points : 3.164800e+000

144

Exe rcice s e n langage C

________________________________________________________________________________________

ANALYSE
Nous ch oisirons un carr de ct unit . Nous convie ndrons de prendre son coin bas gauch e com m e origine d'un rep re
cart s ie n.
Nous tire rons alors au h asard le nom bre de points voulus, l'int rie ur de ce carr . Plus prcism e nt, pour ch aq ue point,
nous dte rm ine rons au h asard ses deux coordonn e s , e n tirant deux nom bre s r e ls apparte nant l'inte rvalle [0,1]. A ce t
e ffe t, nous fe rons appe l la m th ode e xpose dans l'analyse de l'e xe rcice III-1.
Pour ch aq ue point, nous calculerons sa distance au ce ntre du carr (de coordonn e s : 0.5, 0.5) e t nous considrerons qu'il
appartie nt au ce rcle inscrit si ce tte distance e s t inf rie ure 0.5 (note z q ue , par souci de s im plicit , nous travaillerons e n
fait ave c le carr de ce tte distance ).

Program m e
#include <stdio.h>
#include <stdlib.h>
main()
{
float caleat(void) ;
float x, y,
d2,
pi ;
int np,
nc,
i ;

/*
/*
/*
/*
/*
/*

prototype fonction de tirage valeur alatoire */


coordonnes d'un point courant */
distance (au carr) d'un point courant au centre */
valeur approche de pi */
nombre de points tirer */
nombre de points l'intrieur du cercle */

printf ("combien de points ? ") ;


scanf ("%d", &np) ;
for (nc=0, i=1 ; i<=np ; i++)
{ x = caleat() ;
y = caleat() ;
d2 = (x-0.5) * (x-0.5) + (y-0.5) * (y-0.5) ;
if (d2 <= 0.25) nc++ ;
}
pi = (4.0 * nc) / np ;

III. H asard e t r cr ations

145

printf ("estimation de pi avec %d points : %e", np, pi) ;


}
float caleat (void)
/* fonction fournissant une valeur alatoire */
/* appartenant l'intervalle [0-1] */
{
return ( (float) rand() / (RAND_MAX + 1.0) ) ;
}

D ISCUSSIO N
Notre fonction de tirage alatoire d'un entie r fournit toujours la m m e s uite de valeurs. Ce q ui signifie q ue , pour un
nom bre donn de points, nous obtie ndrons toujours la m m e e s tim ation de pi. Vous pouve z vite r ce ph nom ne e n
utilisant la fonction r alise dans l'e xe rcice III-2.

III-5 Je u du de vin
________________________________________________________________________________________

Enonc
Ecrire un program m e q ui ch oisit un nom bre e ntie r au h asard e ntre 0 e t 1000 e t q ui de m ande l'utilisate ur de le
"devine r". A ch aq ue proposition faite par le joue ur, le program m e r pondra e n situant le nom bre propos par rapport
ce lui devine r (plus grand, plus petit ou gagn ).
Lors q ue le joue ur aura de vin le nom bre ch oisi, ou lors q u'un nom bre m axim alde coups (10) aura t dpas s , le
program m e affich e ra la r capitulation des diff re nte s propositions.

Exe m pl
e
Devinez le nombre que j'ai choisi (entre 1 et 1000)
votre proposition : 500
----------- trop grand

146

Exe rcice s e n langage C

votre proposition : 250


----------- trop grand
votre proposition : 125
----------- trop grand
votre proposition : 64
----------- trop grand
votre proposition : 32
----------- trop grand
votre proposition : 16
----------- trop grand
votre proposition : 8
----------- trop petit
votre proposition : 12
----------- trop grand
votre proposition : 10
++++ vous avez gagn en 9 coups
---- Rcapitulation des coups jous ---500
250
125
64
32
16
8
12
10

trop grand
trop grand
trop grand
trop grand
trop grand
trop grand
trop petit
trop grand
exact

________________________________________________________________________________________

ANALYSE
Le program m e com m e nce ra par tire r un nom bre e ntie r au h asard, suivant la dm arch e e xpose dans l'analyse de
l'e xe rcice III-1.
Ildevra e nsuite r p te r l'action :
faire joue r le joue ur
jusqu' ce q ue le joue ur ait gagn ou q u'ilait dpas s le nom bre m axim alde coups perm is.
L'action e n q ue s tion consiste s im plem e nt :

III. H asard e t r cr ations

147

- D e m ande r au joue ur de propos e r un nom bre .


- Cons e rve r ce nom bre dans un tableau (pour pouvoir tablir la r capitulation finale). Note z q ue , com pte te nu de ce
q u'un nom bre de coups m axim ale s t im pos , ce dernie r fournira le nom bre m axim ald'lm e nts de notre tableau.
- Com pare r le nom bre fourni ave c la valeur ch oisie par le program m e e t affich e r le m e s s age corre s pondant.

Program m e

#include <stdio.h>
#include <stdlib.h>
#define NCOUPS 15
#define NMAX 1000
main()
{
int aleat(int) ;
int nc,
ndevin,
n,
prop[NMAX],
i ;

/* nombre maximal de coups autoriss */


/* valeur maximale du nombre deviner */

/*
/*
/*
/*
/*

prototype fonction de tirage d'un nombre au hasard */


compteur du nombre de coups jous */
nombre deviner */
nombre courant propos par le joueur */
tableau rcapitulatif des nombres proposs */

/* initialisations et tirage du nombre secret */


nc = 0 ;
printf ("Devinez le nombre que j'ai choisi (entre 1 et %d)\n", NMAX) ;
ndevin = aleat(NMAX) ;

/* droulement du jeu */
do
{ printf ("votre proposition : ") ;
scanf ("%d",&n) ;
prop [nc++] = n ;
if (n < ndevin)
printf ("----------- trop petit\n") ;
else if (n > ndevin) printf ("----------- trop grand\n") ;
}
while (n != ndevin && nc < NCOUPS) ;
/* affichage rsultats */

148

Exe rcice s e n langage C


if (n == ndevin) printf ("\n\n++++ vous avez gagn en %d coups\n", nc) ;
else { printf ("\n\n---- vous n'avez pas trouv\n") ;
printf ("le nombre choisi tait %d\n", ndevin) ;
}
/* affichage rcapitulation */
printf ("\n ---- Rcapitulation des coups jous ----\n\n") ;
for (i=0 ; i<nc ; i++)
{ printf ("%4d ", prop[i]) ;
if (prop[i] > ndevin)
printf ("trop grand \n") ;
else if (prop[i] < ndevin)
printf ("trop petit\n") ;
else
printf ("exact\n") ;
}

}
/*******************************************************/
/* fonction de tirage alatoire d'un nombre dans [0,n] */
/*******************************************************/
int aleat(int n)
{
int i = rand() / (RAND_MAX + 1.) * (n+1) ;
return i ;
}

D ISCUSSIO N
Notre fonction de tirage alatoire d'un nom bre e ntie r fournit toujours la m m e valeur, ce q ui g ch e q ue lque pe u l'int r t
du je u. D ans la pratiq ue , ils e rait n ce s s aire de re m place r la fonction aleat de ce program m e par ce lle propose dans
l'e xe rcice III-2, laq ue lle pe rm e t d'obte nir un nom bre diff re nt d'une e x cution une autre .

III-6 M as te rm ind
________________________________________________________________________________________

III. H asard e t r cr ations

149

Enonc
R aliser un program m e q ui ch oisit au h asard une com binaison de 5 ch iffre s (com pris e ntre 1 e t 8) e t q ui de m ande
l'utilisate ur de la devine r. A ch aq ue proposition, le program m e pr cis e ra :
- le nom bre de ch iffre s exacts propos s la bonne pl
ace,
- le nom bre de ch iffre s exacts m ais proposs la m auvaise pl
ace.
Les diff re nte s propositions du joue ur s e ront fournie s s ous la form e de 5 ch iffre s cons cutifs (sans aucun s parate ur),
valids par re turn.
Le program m e devra traite r conve nablem e nt le cas des r pons e s incorre cte s : lettre la place d'un ch iffre , r pons e trop
courte ou trop longue , ch iffre incorre ct (nulou suprieur 8).
O n pr voira un nom bre lim ite d'essais, au-de l duq ue l le program m e s 'inte rrom pra e n indiq uant q ue lle tait la
com binaison devine r.

Exe m pl
e
proposition ? : 12345
2 P 0 C
proposition ? : 23456
0 P 1 C
proposition ? :

34567

proposition ? :

45678

proposition ? :
** incorrect **
proposition ? :
** incorrect **
proposition ? :

56789

proposition ? :

11333

proposition ? :

11313

0 P 1 C
0 P 0 C

1133
11332
3 P 1 C
4 P 0 C

5 P 0 C
vous avez trouv en 7 coups
________________________________________________________________________________________

150

Exe rcice s e n langage C

ANALYSE
Ilpara
t as s e z nature ld'utiliser un tableau 5 lm e nts pour y range r la com binaison tir e au h asard. Note z q ue nous
pourrions galem e nt tire r au h asard un nom bre de 5 ch iffre s , m ais ilfaudrait, de toute faon, e n e xtraire ch acun de s
ch iffre s ;de plus, la m th ode s e rait difficilem e nt g n ralisable un nom bre q ue lconq ue de positions.
La principale difficult r s ide dans l'analyse de la proposition du joue ur. D ans la com paraison des deux tableaux
(com binaison tir e par le program m e e t com binaison propos e par le joue ur), ilfaudra te nir com pte des re m arq ue s
suivante s :
- Un ch iffre com pt " sa place " ne doit pas pouvoir tre galem e nt com pt com m e "e xact, m ais m alplac ".
- Lors q u'un tirage com porte plusieurs ch iffre s identiq ue s , ilne faut pas q u'un m m e ch iffre de la proposition du
joue ur puis s e tre com pt plusieurs fois com m e e xact.
- Lors q u'une proposition com porte plusieurs ch iffre s identiq ue s , il ne faut pas les considrer tous com m e
corre s pondant un m m e ch iffre du tirage .
Nous vous proposons la m th ode s uivante :
1 - Nous re ch e rch ons tout d'abord les ch iffre s e xacts plac s e n bonne position. A ch aq ue fois q u'une concide nce e s t
re lev e , nous supprim ons le ch iffre , la fois dans la proposition du joue ur e t dans le tirage (e n le re m plaant, par
e xe m ple, par la valeur 0).
2 - Nous re pre nons e nsuite , un un, ch acun de s ch iffres du tirage q ui n'ont pas t s upprim s (c'e s t- -dire q ui sont
diff re nts de 0). Nous les com parons ch acun de s ch iffres de la proposition. L e ncore , si une concide nce e s t
re lev e , nous supprim ons les ch iffre s corre s pondants, la fois dans la proposition e t dans le tirage . Note z bie n q u'il
faut absolum e nt vite r de considrer les ch iffres dj supprim s du tirage : ils ris q ue raie nt d' tre trouv s gaux
d'autre s ch iffre s s upprim s de la proposition.
Ce tte m th ode q ui d truit le tirage nous oblige n ce s s aire m e nt e n faire une copie avant d'entam e r l'analyse de la
proposition.
Nous avons ch oisi de raliser trois fonctions :
- tirage : tirage au h asard de la com binaison (tableau de 5 e ntie rs) devine r.
- e ntre e : e ntr e d e la proposition du joue ur. Ilpara
t logiq ue q ue ce tte fonction fournis s e ce tte proposition dans un
tableau d'e ntie rs. Toute fois, afin de traite r conve nablem e nt les cas de r pons e s incorre cte s , la proposition du joue ur
s e ra tout d'abord lue dans une ch a
ne l'aide de la fonction cge ts (son m canism e e s t dcrit dans l'e xe rcice II-4).
- analy s e : analyse de la proposition du joue ur, suivant l'algorith m e dcrit pr cdem m e nt.

Program m e

III. H asard e t r cr ations


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NPOS 5
#define NCHIF 8
#define NCMAX 12

/* nombre de positions */
/* nombre de chiffres (ici, de 1 a 8) */
/* nombre maximal de coups */

main()
{
void tirage (int []) ;
int entree (int []) ;
void analyse(int [], int[], int[], int []) ;
int tir[NPOS],
prop[NPOS],
ncoup,
bpos,
bchif ;

/*
/*
/*
/*
/*

/*****************************/
/*
prototypes fonctions */
/*****************************/

combinaison tire par le programme */


proposition du joueur */
compteur de coups jous */
nombre de chiffres bien placs */
nombre de chiffres exacts mais mal placs */

/* initialisations */
tirage (tir) ;
ncoup = 0 ;
/* droulement du jeu */
do
{ while (printf ("proposition ? : "), entree(&prop) )
printf ("\n** incorrect **\n") ;
analyse (prop, tir, &bpos, &bchif) ;
printf ("\n %22d P %d C\n", bpos, bchif) ;
ncoup++ ;
}
while (bpos < NPOS && ncoup < NCMAX) ;
/* affichage rsultats */
if (bpos == NPOS) printf ("vous avez trouv en %d coups", ncoup) ;
else { int i ;
printf ("vous n'avez pas trouv en %d coups\n", NCMAX) ;
printf ("la bonne combinaison tait : ") ;
for (i=0 ; i<NPOS ; i++) printf ("%d",tir[i]) ;
printf ("\n") ;
}
}

151

152

Exe rcice s e n langage C

/*************************************************/
/* fonction de tirage de la combinaison secrte */
/*************************************************/
void tirage (int tir [])
{
int i ;
for (i=0 ; i<NPOS ; i++)
tir[i] = rand() / (RAND_MAX + 1.) * NCHIF + 1 ;
}

/*************************************************/
/* fonction de lecture de la proposition du joueur */
/*****************************************************/
int entree (int prop [])
{
char ch[NPOS+3] ;
/* chane o sera lue la proposition du joueur */
int i ;
/* lecture proposition joueur dans chane ch */
ch[0] = NPOS+1 ;
/* prparation longueur maxi chane lue */
cgets (ch) ;
/* contrles */
if (strlen (&ch[2]) != NPOS) return(-1) ;
for (i=2 ; i<NPOS+2 ; i++)
if (ch[i] < '1' || ch[i] > '1'+NCHIF-1) return(-1) ;
/* extraction des chiffres choisis */
for (i=0 ; i<NPOS ; i++)
prop[i] = ch[2+i] -'0' ;
return (0) ;
}
/**************************************************/
/* fonction d'analyse de la proposition du joueur */
/**************************************************/
void analyse (int prop [], int tir [], int bpos [] , int bchif [])
{
int tirbis[NPOS],
/* double de la combinaison secrte */
i, j ;
/* recopie de la combinaison secrte */
for (i=0 ; i<NPOS ; i++) tirbis[i] = tir[i] ;

III. H asard e t r cr ations

153

/* comptage bonnes positions */


*bpos = 0 ;
for (i=0 ; i<NPOS ; i++)
if (prop[i] == tirbis[i])
{ (*bpos)++ ;
tirbis[i] = prop[i] = 0 ;
}
/* comptage bons chiffres mal placs */
*bchif = 0 ;
for (i=0 ; i<NPOS ; i++)
for (j=0 ; j<NPOS ; j++)
if (prop[i] !=0 && prop[i] == tirbis[j])
{ (*bchif)++ ;
prop[i] = tirbis[j] = 0 ;
}
}

Com m e ntaire s
*Le nom bre de positions (NPO S) e t le nom bre de ch iffre s (NCH IF) ont t dfinis par #de fine , ce q ui e n facilite
l' ve ntue lle m odification.
*La fonction tirage fait appe l l'algorith m e de tirage au h asard d'un e ntie r, te lq ue nous l'avons e xpos dans l'e xe rcice
III-1. Toute fois, ici, le nom bre tir doit apparte nir l'inte rvalle [1,NCH IF] e t non l'inte rvalle [0,NCH IF]. C'e s t ce q ui
e xpliq ue q ue le nom bre r e ltir dans l'inte rvalle [0,1[ soit m ultipli par NCH IF e t q ue l'on ajoute 1 au r s ultat.
*La fonction e ntre e lit, com m e pr vu, la proposition du joue ur sous form e d'une ch a
ne . Elle e n e ffe ctue les contrles
re q uis e n re s tituant la valeur 0 lors q ue la r pons e e s t valide et la r pons e -1 dans le cas contraire . Note z q ue la dcision
de dem ande r, e n cas d'erreur, une nouve lle proposition au joue ur e s t prise dans le program m e principale t non dans la
fonction e lle-m m e .
*Le s argum e nts de la fonction analy s e sont transm is par leur adre s s e , afin q ue leur valeur puis s e tre m odifi e . C'e s t ce
q ui justifie leur d claration sous form e de pointe urs sur de s e ntie rs. N'oublie z pas q ue les nom s de tableaux
corre s ponde nt leur adre s s e ;c'e s t ce q ui justifie q ue dans l'appe lde analy s e , on trouve e ffe ctive m e nt les sym boles prop
e t tir, alors q ue , par ailleurs, on y trouve & bpos e t & bch if.
*D ans la boucle s uivante (du program m e principal) :

154

Exe rcice s e n langage C


while (printf ("proposition ? : "), entree(&prop) )
printf ("\n** incorrect **\n") ;

l'e xpre s s ion figurant dans w h ile utilise un "oprate ur s q ue ntie l", ce q ui pe rm e t ainsi de sim plifie r q ue lque pe u l' criture .
A titre indicatif, voici de ux constructions q uivalente s , l'une parfaite m e nt structur e , l'autre bas e s ur l'utilisation de
bre ak (les valeurs des sym boles VR A I e t FAUX tant re s pe ctive m e nt 1 e t 0) :
ok = FAUX ;
while (!ok)
{ printf ("proposition ? : ") ;
if (entree(&prop)) ok = VRAI ;
else printf ("\n** incorrect **\n") ;
}

do
{ printf ("proposition ? : ") ;
if (entree(&prop)) break ;
else printf ("\n** incorrect **\n) ;
while(1) ;

D ISCUSSIO N
*Ici, la saisie de la proposition du joue ur e s t parfaite m e nt satisfaisante , m m e pour un program m e "r e l". En particulie r,
e lle autoris e les corre ctions, m m e apr s q ue l'utilisate ur a frapp le dernie r ch iffre .
*Par contre , te lq u'ile s t propos ici, ce program m e ch oisit toujours la m m e com binaison, ce q ui e nlve q ue lque int r t
la pratiq ue r guli re du je u (m ais q ui pe ut facilite r la m ise au point du program m e ). Pour r m dier ce tte lacune , il
suffit d'introduire , dans la fonction tirage , une initialisation du g n rate ur de nom bre s alatoire s , lors de son prem ie r
appe l, com m e nous l'avons fait dans l'e xe rcice III-2.
*Le program m e s upporte , sans aucune m odification, de s valeurs q ue lconq ues de NPO S e t des valeurs de NCH IF
inf rie ure s 10. Ile s t facile d'aller au-de l, e n m odifiant sim plem e nt la fonction e ntre e .

IV : TRIS, FUSIO NS
ET RECH ERCH E EN TA BLE

Nous vous proposons ici de s e xe rcices de program m ation d'algorith m e s classiques ayant trait aux tris e t fusions de
tableaux, ainsi qu' la re ch e rch e e n table.

IV-1 Tri par e xtraction s im pl


e
________________________________________________________________________________________

Enonc
R aliser un program m e de tri par valeurs dcroissantes d'un tableau d'e ntie rs, e n utilisant l'algorith m e dit "par e xtraction
sim ple" q ui se dfinit de la m ani re s uivante :
- O n re ch e rch e le plus grand de s n lm e nts du tableau.
- O n ch ange ce t lm e nt ave c le pre m ie r lm e nt du tableau.
- Le plus petit lm e nt s e trouve alors e n pre m i re position. O n pe ut alors appliq ue r les deux op rations prcdente s
aux n-1 lm e nts re s tants, puis aux n-2, ... e t ce la jus q u' ce q u'ilne re s te plus q u'un s e ul lm e nt (le dernie r - q ui
e s t alors le plus petit).
Le program m e affich e ra tous les "r s ultats inte rm diaire s ", c'e s t- -dire les valeurs du tableau, apr s ch aq ue ch ange de
deux lm e nts.

Exe m pl
e
combien de valeurs trier : 8
donnez vos valeurs trier

156

Exe rcice s e n langage C

3 9 2 7 11 6 2 8
---- valeurs trier ---3
9
2
7
11
6

11
11
11
11
11
11
11

6
6
6
6
3
3
3

2
2
2
2
2
2
2

8
8
2
2
2
2
2

9
9
9
9
9
9
9

2
2
8
8
8
8
8

7
7
7
7
7
7
7

3
3
3
3
6
6
6

---- valeurs tries ---11


9
8
7
6

________________________________________________________________________________________

ANALYSE
L'algorith m e propos par l' nonc pe ut s e form aliser com m e s uit, e n te nant com pte des conve ntions d'indice s propre s au
langage C :
R p te r, pour i variant de 0 n-2 :
- re ch e rch e r k

te lq ue t(k ) soit le plus grand de s t(k ), pour k allant de i n-1,


m

- ch ange r les valeurs de t(k ) e t de t(i).


m

Program m e
#include <stdio.h>
#define NMAX 100

/* nombre maximal de valeurs trier */

main()
{
int t [NMAX],
nval,
kmax,
tempo,

/*
/*
/*
/*

tableau contenant les valeurs trier */


nombre de valeurs trier */
position du maximum temporaire */
valeur temporaire pour change valeurs */

IV. Tris, fusions e t re ch e rch e e n table


i, j, k ;
/* lecture des valeurs trier */
printf ("combien de valeurs trier : ") ;
scanf ("%d", &nval) ;
if (nval > NMAX) nval = NMAX ;
printf ("donnez vos valeurs trier\n") ;
for (k=0 ; k<nval ; k++)
scanf ("%d", &t[k]) ;
printf ("\n
---- valeurs trier ----\n") ;
for (k=0 ; k<nval ; k++)
printf ("%5d", t[k]) ;
printf ("\n\n") ;
/* tri des valeurs */
for (i=0 ; i<nval-1 ; i++)
/* recherche maxi partiel pour chaque i
{ kmax = i ;
/* init recherche maxi partiel
for (j=i+1 ; j<nval ; j++)
/* recherche maxi partiel
if (t[j] > t[kmax]) kmax = j ;
tempo = t[kmax] ;
/* mise en place maxi partiel
t[kmax] = t[i] ;
t[i] = tempo ;
for (k=0 ; k<nval ; k++)
/* affichage intermdiaire
printf ("%5d", t[k]) ;
printf ("\n") ;
}
/* affichage valeurs tries */
printf ("\n
---- valeurs tries ----\n") ;
for (k=0 ; k<nval ; k++)
printf ("%5d", t[k]) ;
printf ("\n") ;
}

Com m e ntaire s
Ce program m e fonctionne pour toute s les valeurs de NMAX, en particulie r :
- pour NM A X inf rie ur ou gal 0, ilne fait rie n,
- pour NM A X = 1, illit une valeur q u'ilaffich e te lle q ue lle.

*/
*/
*/
*/

*/

157

158

Exe rcice s e n langage C

IV-2 Tri par pe rm utation s im pl


e
________________________________________________________________________________________

Enonc
Ecrire une fonction r alisant le tri par valeurs croissantes d'un tableau d'e ntie rs, e n utilisant l'algorith m e de tri par
pe rm utation sim ple (dit de "la bulle"), q ui se dfinit ainsi (n re pr s e ntant le nom bre d'lm e nts du tableau) :
O n parcourt l'e ns e m ble du tableau, de puis sa fin jus q u' son dbut, e n com parant deux lm e nts cons cutifs, e n les
inve rsant s'ils sont m alclas s s . O n s e re trouve ainsi ave c le plus petit lm e nt plac e n t te du tableau.
O n re nouve lle une te lle op ration (dite "pas s e ") ave c les n-1 lm e nts re s tants, puis ave c les n-2 lm e nts re s tants, e t
ainsi de suite ... jus q u' ce q ue :
- soit l'avant-dernier lm e nt ait t clas s (le dernie r tant alors obligatoire m e nt sa place ),
- soit q u'aucune pe rm utation n'ait e u lie u pe ndant la derni re pas s e (ce q ui prouve alors q ue l'e ns e m ble du tableau
e s t conve nablem e nt ordonn ).
O n pr voira e n argum e nts :
- l'adresse du tableau trie r,
- son nom bre d'lm e nts,
- un indicate ur pr cisant si l'on souh aite q ue la fonction affich e les valeurs du tableau apr s ch aq ue pe rm utation (0
pour non, 1 pour oui).

Exe m pl
e
combien de valeurs trier : 6
donnez vos valeurs trier
2 8 4 7 0 8
---- valeurs trier ---2
8
4
7
0
8
2
2

8
8

4
0

0
4

7
7

8
8

IV. Tris, fusions e t re ch e rch e e n table


2
0
0
0

0
2
2
2

8
8
4
4

4
4
8
7

7
7
7
8

---- valeurs tries ---0


2
4
7
8

159

8
8
8
8

________________________________________________________________________________________

ANALYSE
L'algorith m e nous e s t indiq u par l' nonc . Nous utiliserons cependant une r p tition de type tant q u e (instruction w h ile)
q ui pe rm e t de prendre conve nablem e nt e n com pte le cas o l'on appe lle la fonction de tri e n lui fournissant e n argum e nt
un nom bre de valeurs inf rie ur ou gal 1.
D ans la m ise en oeuvre de ce t algorith m e , nous fe rons appe l un e ntie r i spcifiant le rang partir duq ue lle tableau
n'e s t pas e ncore tri . Initialem e nt, ilfaudra pr voir q u'aucun lm e nt n'e s t e ncore sa place , ce q ui conduira
l'initialisation artificie lle de i -1 (puis q ue e n C, le pre m ie r lm e nt d'un tableau porte le num ro 0). D'autre part, un
indicate ur logiq ue nom m pe rm ut nous s e rvira pr cis e r si au m oins une perm utation a e u lie u au cours de la derni re
pas s e .
Si nous notons nvalle nom bre de valeurs de notre tableau, l'algorith m e de tri pe ut alors s' nonce r com m e s uit :
Tant q ue i ne dsigne pas le dernie r lm e nt du tableau (c'e s t- -dire i < nval-1) e t q ue pe rm ut e s t VR A I, nous
e ffe ctuons une passe. Cette derni re consiste e n une s ucce s s ion de com paraisons des lm e nts de rang j e t j+1, j
dcrivant tous les lm e nts depuis l'avant-dernier jus q u' ce lui de rang i+1 (autre m e nt dit, j dcroissant de nval-2
i+1). A ch aq ue pe rm utation, nous donnons pe rm ut la valeur VR A I ;nous aurons, bie n sr, pris soin d'initialiser
pe rm ut FAUX au dbut de ch aq ue pas s e .
Note z q ue l'utilisation d'une r p tition de type tant q u e (dans laq ue lle la condition de poursuite fait inte rve nir l'indicate ur
pe rm ut) nous oblige initialiser artificie llem e nt pe rm ut VR A I, e n tout dbut de travail.

Program m e
#include <stdio.h>
#define VRAI 1
#define FAUX 0
#define NMAX 100
main()
{

/* pour "simuler" des ... */


/* ... valeurs logiques */
/* nombre maximal de valeurs trier */

160

Exe rcice s e n langage C


void bulle(int [], int, int ) ;
int t [NMAX],
nval,
k ;

/* prototype fonction de tri */


/* tableau contenant les valeurs trier */
/* nombre de valeurs trier */

/* lecture des valeurs trier */


printf ("combien de valeurs trier : ") ;
scanf ("%d", &nval) ;
if (nval > NMAX) nval = NMAX ;
printf ("donnez vos valeurs trier\n") ;
for (k=0 ; k<nval ; k++)
scanf ("%d", &t[k]) ;
printf ("\n
---- valeurs trier ----\n") ;
for (k=0 ; k<nval ; k++)
printf ("%5d", t[k]) ;
printf ("\n\n") ;
/* tri des valeurs */
bulle (t, nval, 1) ;
/* affichage valeurs tries */
printf ("\n
---- valeurs tries ----\n") ;
for (k=0 ; k<nval ; k++)
printf ("%5d", t[k]) ;
printf ("\n") ;
}
/**************************************************/
/*
fonction de tri par la mthode de la bulle
*/
/**************************************************/
void bulle (int t[], int nval, int affich)
/* t : tableau trier
*/
/* nval : nombre de valeurs trier
*/
/* affich : indicateur affichages intermdiaires */
{
int i,
/* rang partir duquel le tableau n'est pas tri */
j,
/* indice courant */
tempo,
/* pour l'change de 2 valeurs */
k ;
int permut ;
/* indicateur logique prcisant si au moins une */
/* permutation a eu lieu lors de la prcdente passe */
i = -1 ;
permut = VRAI ;
while (i < nval-1 && permut)

IV. Tris, fusions e t re ch e rch e e n table

161

{ permut = FAUX ;
for (j=nval-2 ; j>i ; j--)
{ if ( t[j] > t[j+1] )
{ permut = VRAI ;
tempo = t[j] ;
t[j] = t[j+1] ;
t[j+1] = tempo ;
if (affich)
{ for (k=0 ; k<nval ; k++)
printf ("%5d", t[k]) ;
printf ("\n") ;
}
}
}
i++ ;
}
}

Com m e ntaire s
D ans la fonction bullle, la dclaration :
int * t ;

e s t q uivalente :
int t[] ;

D ISCUSSIO N
Les deux algorith m e s proposs dans l'e xe rcice pr cdent e t dans ce lui-ci corre s ponde nt ce q ue l'on appe lle des
"m th odes directe s ". D 'une m ani re g n rale, ce s ont des algorith m e s s im ples program m e r, m ais q ui n ce s s ite nt un
2

nom bre de com paraisons de l'ordre de n (note z q u'ile xiste une troisi m e m th ode directe dite "tri par ins e rtion").
En fait, ile xiste des m th odes dite s " volu e s " q ui conduis e nt un nom bre de com paraisons de l'ordre de n *log n.
Ce lles -ci dbouch e nt sur des program m e s plus com plexe s e t les op rations q u'e lles font inte rve nir sont e lles -m m e s plus
gourm ande s e n te m ps q ue ce lles des m th odes directe s . Aussi, les m th ode s volu e s ne pre nne nt v ritablem e nt d'int r t
q ue pour de s valeurs lev e s d e n.

162
Exe rcice s e n langage C
A titre indicatif, nous vous fournissons ici l'algorith m e re latif la m th ode volu e la plus perform ante , nom m e "Tri
rapide " (Quick sort), inve nt e par C. A. R . H oare . Ce t algorith m e , dlicat program m e r, e s t bas s ur l'op ration de
"s e gm e ntation" d'un tableau ;ce lle-ci consiste partage r un tableau e n de ux partie s , nom m e s s e gm e nts, te lles q ue tout
lm e nt de l'une s oit inf rie ur ou gal tout lm e nt de l'autre . Une te lle s e gm e ntation pe ut tre r alise par
l'algorith m e s uivant :
- Pre ndre un lm e nt au h asard (on pe ut pre ndre l' lm e nt du m ilie u). Soit m sa valeur.
- R e ch e rch e r, de puis le dbut du tableau, le pre m ie r lm e nt t(i) te lq ue t(i)> m .
- R e ch e rch e r, de puis la fin du tableau, le pre m ie r lm e nt t(j) te lq ue t(j)< m .
- Pe rm ute r t(i) e t t(j).
- Poursuivre ce "parcours" du tableau jus q u' ce q ue i e t j s e re ncontre nt.
Le tri propre m e nt dit s'e ffe ctue e n appliq uant nouve au l'op ration de s e gm e ntation ch aq ue s e gm e nt obte nu, puis aux
s e gm e nts obte nus par segm e ntation de ce s s e gm e nts,... e t ainsi de suite jus q u' ce q ue ch aq ue s e gm e nt ne contie nne plus
q u'un s e ul lm e nt.
Note z q u'une te lle m th ode s e pr te particuli re m e nt bien une program m ation r cursive .

IV-3 Tri d'un tabl


e au de ch a
ne s
________________________________________________________________________________________

Enonc
Ecrire une fonction utilisant la m th ode de tri par e xtraction sim ple (dcrite dans l'e xe rcice IV-1) pour trie r un tableau de
ch a
ne s , par ordre alph abtiq ue (sans distinction e ntre m ajuscules e t m inuscules ).
Ce tte fonction re ce vra, e n argum e nt :
- l'adresse d'un tableau de pointe urs sur les ch a
ne s conce rn e s ,
- le nom bre de ch a
ne s trie r.
Le tri propre m e nt dit porte ra, non sur les valeurs des ch a
ne s e lles -m m e s , m ais uniq ue m e nt sur le tableau de pointe urs.
O n te s te ra ce tte fonction l'aide d'un program m e principalcr ant un sim ple tableau de ch a
ne s (ayant donc ch acune une
longue ur m axim ale donne).

IV. Tris, fusions e t re ch e rch e e n table

163

Exe m pl
e
combien de chanes trier ? 7
donnez vos 7 chanes (validez chacune par 'return')
C
Turbo C
Basic
Pascal
Turbo Pascal
Fortran
ADA

voici vos chanes tries


ADA
Basic
C
Fortran
Pascal
Turbo C
Turbo Pascal
________________________________________________________________________________________

ANALYSE
La m th ode de tri a t dcrite dans l'e xe rcice IV-1. Il e s t ce pe ndant n ce s s aire de procder
d'adaptations :

plusieurs sorte s

- ilfaut e n faire une fonction,


- la re lation d'ordre q ui s e rt au tri ne porte plus sur de s e ntie rs, m ais sur de s ch a
nes de caract re s ;ce la im pliq ue de
re courir la fonction stricm p (e t non strcm p, puis q ue l'on souh aite ne pas distingue r les m ajuscules des m inuscules ),
- les lm e nts pe rm ute r s e ront des pointe urs e t non plus des entie rs.

164

Exe rcice s e n langage C

Program m e
#include <stdio.h>
#include <string.h>
#define NCHMAX 100
/* nombre maximal de chanes traiter */
#define LGMAX 25
/* longueur maximale d'une chane (sans \0) */
main()
{
void trichaines (char * *, int ) ; /* prototype fonction de tri */
char chaines [NCHMAX] [LGMAX+1] ;
/* tableau des chanes */
char * adr [NCHMAX] ;
/* tableau pointeurs sur les chanes */
int nch,
/* nombre de chane trier */
i ;
/* lecture des chanes et prparation du tableau de pointeurs */
printf ("combien de chanes trier ? ") ;
scanf ("%d", &nch) ;
if (nch > NCHMAX) nch = NCHMAX ;
getchar() ;
/* pour forcer la lecture de fin de ligne */
printf ("donnez vos %d chanes (validez chacune par 'return')\n", nch) ;
for (i=0 ; i<nch ; i++)
{ fgets (chaines[i], LGMAX+1, stdin) ; /* lit au maximum LGMAX caractres */
adr[i] = chaines[i] ;
}
/* tri des pointeurs sur les chanes */
trichaines (adr, nch) ;
/* affichage des chanes aprs tri */
/* attention aux chanes de longueur maximum !! */
printf ("\n\nvoici vos chanes tries\n") ;
for (i=0 ; i<nch ; i++)
printf ("%s", adr[i]) ;
}
void trichaines (char * * adr, int nch)
/* adr : adresse tableau de pointeurs sur chanes trier */
/* nch : nombre de chanes
*/
{
char * tempo ;
/* pointeur temporaire pour l'change de 2 pointeurs */
int kmax,

IV. Tris, fusions e t re ch e rch e e n table

165

i, j ;
for (i=0 ; i<nch-1 ; i++)
{ kmax = i ;
for (j=i+1 ; j<nch ; j++)
if ( stricmp (adr[kmax], adr[j]) > 0 ) kmax = j ;
tempo = adr[kmax] ;
adr[kmax] = adr[i] ;
adr[i] = tempo ;
}
}

Com m e ntaire s
*Ici, les ch a
ne s trie r ont t plac e s (par le program m e principal) dans un tableau de caract re s (nom m ch aine s )
deux dim e nsions. Note z bie n q u'ilne s e rait pas possible d'en inve rs e r l'ordre des dim e nsions ;ile s t e n e ffe t n ce s s aire
q ue tous les caract res d'une m m e ch a
ne s oie nt cons cutifs.
*Bie n q ue ce la n'ait pas t e xplicite m e nt dem and par l' nonc , nous avons prvu un contrle s ur la longue ur de s
ch a
ne s fournie s au clavie r ;pour ce faire , nous avons fait appe l la fonction fge ts, e n l'appliq uant au fich ie r stdin.
L'instruction :
fgets (chaines[i], LGMAX+1, stdin) ;

lit au m axim um LGM AX caract re s s ur stdin e t les range l'adre s s e ch aine [i], e n com pltant le tout par un z ro de fin de
ch a
ne . Ainsi, on vite les ris q ues de dborde m e nt m m oire q ue pr s e nte ge ts.
Toute fois un lge r inonv nie nt appara
t. En e ffe t, tant q ue le nom bre de caract re s m axim al(LGM AX) n'e s t pas atte int,
le caract re \n q ui a s e rvi dlim ite r la ch a
ne lue e s t rang e n m m oire , au m m e titre q ue les autre s . En re vanch e ,
lors q ue le nom bre m axim alde caract re s a t atte int, alors prcism e nt q ue ce caract re \n n'a pas t re ncontr , on ne
trouve plus ce caract re e n m m oire (le caract re nulde fin de ch a
ne , q uant lui, e s t bien toujours prsent).
Ce t inconv nie nt e s t surtout s e nsible lors q ue l'on affich e nouve au les ch a
ne s par printf apr s leur tri : les ch a
nes de
longue ur m axim ale ne s e ront pas suivies d'un ch ange m e nt de ligne . Note z bie n q u'e n e m ployant puts on obtie ndrait, e n
re vanch e , 1 caract re de ch ange m e nt de ligne pour les ch a
nes de longue ur m axim ale (transm is par la fonction puts
m m e ) e t 2 caract res de ch ange m e nt de ligne pour les autre s ch a
ne s (ce lui figurant dans la ch a
ne e t ce lui transm is par
puts).
D ans un "program m e op rationne l", ilfaudrait g re r conve nablem e nt ce tte s ituation, ce q ue nous n'avons pas fait ici.

166
Exe rcice s e n langage C
*R appe lons q ue , apr s la lecture par scanf du nom bre de ch a
ne s traite r, le pointe ur re s te (com m e l'accoutum e )
positionn s ur le dernie r caract re non e ncore utilis ;dans le m e illeur de s cas, ils'agit de \n (m ais ilpe ut y avoir
d'autre s caract re s avant si l'utilisate ur a t distrait). Dans ces conditions, la lecture ult rie ure d'une ch a
ne par ge ts
conduira lire ... une ch a
ne vide.
Pour vite r ce problm e , nous avons plac une instruction ge tch ar q ui absorbe ce caract re \n. En toute rigue ur, si l'on
souh aitait traite r corre cte m e nt le cas o l'utilisate ur a fourni trop d'inform ation pour le scanf pr cdent, il s e rait
n ce s s aire d'oprer une lecture d'une ch a
ne par ge ts (ilfaudrait pr voir un e m place m e nt ce t e ffe t!).
*D ans la fonction trich aine s , le pre m ie r argum e nt adr a t dclar par :
char * * adr

Ils'agit d'un pointe ur sur le tableau de pointe urs sur les diff re nte s ch a
ne s . Nous aurions pu galem e nt le dclare r par :
char * adr[]

Note z d'ailleurs q ue nous avons utilis le "form alism e " tableau au s e in de la fonction e lle-m m e . Ainsi :
adr[i] = adr[j]

aurait pu s e form uler :


* (adr+i) = * (adr+j)

*Nous vous rappe lons q ue la fonction stricm p com pare les deux ch a
nes dont on lui fournit les adre s s e s e t e lle fournit
une valeur e nti re dfinie com m e tant :
- positive s i la pre m i re ch a
ne arrive apr s la s e conde , au s e ns de l'ordre dfini par le code des caract re s (sans te nir
com pte de la diff re nce e ntre m ajuscules e t m inuscules pour les 26 lettres de l'alph abet),
- nulle s i les deux ch a
ne s s ont gales ,
- n gative s i la pre m i re ch a
ne arrive avant la s e conde .

D ISCUSSIO N
D 'une m ani re g n rale, iln'e s t pas nce s s aire q ue les ch a
ne s trie r soient, com m e ici, im plant e s e n m m oire de
m ani re cons cutive .
D e m m e , la fonction trich aine s propos e pourrait tout aussi bien oprer sur des ch a
nes dont les e m place m e nts auraie nt
t allou s "dynam iq ue m e nt" (le ch apitre V vous propose d'ailleurs un exercice dans ce sens).

IV. Tris, fusions e t re ch e rch e e n table

167

IV-4 Fus ion de de ux tabl


e aux ordonn s
La fusion consiste ras s e m bler e n un s e ultableau ordonn les lm e nts de deux tableaux, e ux-m m e s ordonn s .
________________________________________________________________________________________

Enonc
R aliser une fonction q ui fusionne deux tableaux d'e ntie rs ordonn s par valeurs croissante s .
O n pr voira e n argum e nts :
- les adresses des trois tableaux conce rn s ,
- le nom bre de valeurs de ch acun des deux tableaux fusionne r.
Pour te s te r ce tte fonction, on crira un program m e principalq ui lit au clavie r de ux e ns e m bles de valeurs q ue l'on trie ra
au pr alable l'aide de la fonction bulle r alise dans l'e xe rcice IV-2.

Exe m pl
e
combien de
donnez vos
3 9 2 8 11
combien de
donnez vos
12 4 6 3 1

valeurs pour le premier tableau ? 5


valeurs
valeurs pour le second tableau ?
valeurs
9 6

premier tableau fusionner


2
3
8
9
11
second tableau fusionner
1
3
4
6
6

12

rsultat de la fusion des deux tableaux


1
2
3
3
4
6
6
8
9
9
11
12
________________________________________________________________________________________

168

Exe rcice s e n langage C

ANALYSE
La dm arch e , as s e z sim ple, s'inspire de ce lle q ue l'on adopte rait pour r s oudre " la m ain" un te lproblm e . Ilsuffit, e n
e ffe t, d'avance r e n parallle dans ch acun des deux tableaux fusionne r (t1 e t t2), e n pr levant, ch aq ue fois, le plus
pe tit des deux lm e nts e t e n l'introduisant dans le tableau r s ultant t. Plus prcism e nt, nous som m e s am e n s utiliser
trois indice s :
- i1 : pre m ie r lm e nt de t1 non e ncore pris e n com pte ,
- i2 : pre m ie r lm e nt de t2, non e ncore pris e n com pte ,
- i : e m place m e nt du proch ain lm e nt introduire dans t.
Nous initialisons ces trois indice s z ro (com pte te nu de s conve ntions du C). Nous r p tons alors le traite m e nt suivant :
Ch oisir le plus petit des lm e nts t1(i1) e t t2(i2) e t le place r e n t(i). Incr m e nte r de 1 la valeur de l'indice
corre s pondant l' lm e nt e xtrait (i1 ou i2), ainsi que celle de i.
Nous poursuivons ainsi jus q u' ce q ue l'un des deux tableaux soit puis . Ilne re s te plus alors q u' re copie r la fin de
l'autre tableau.

Program m e
#include <stdio.h>
#define NMAX1 100
#define NMAX2 100

/* nombre maximal de valeurs du premier tableau */


/* nombre maximal de valeurs du second tableau */

main()
{
void fusion(int [], int [], int [], int, int ) ;
/* proto fonction de fusion */
void bulle(int [], int) ;
/* proto fonction servant assurer l'ordre des tableaux
*/
int t1 [NMAX1],
t2 [NMAX2],
t [NMAX1+NMAX2] ;
int nval1,
nval2,
k ;

/*
/*
/*
/*
/*

premier tableau
second tablleau
tableau rsultant
nombre de valeurs
nombre de valeurs

fusionner */
fusionner */
de la fusion */
prlever dans t1 */
prlever dans t2 */

/* lecture des valeurs des deux ensembles fusionner */


printf ("combien de valeurs pour le premier tableau ? ") ;
scanf ("%d", &nval1) ;

IV. Tris, fusions e t re ch e rch e e n table


if (nval1 > NMAX1) nval1 = NMAX1 ;
printf ("donnez vos valeurs\n") ;
for (k=0 ; k<nval1 ; k++)
scanf ("%d", &t1[k]) ;
printf ("combien de valeurs pour le second tableau ?
scanf ("%d", &nval2) ;
if (nval2 > NMAX2) nval2 = NMAX2 ;
printf ("donnez vos valeurs\n") ;
for (k=0 ; k<nval2 ; k++)
scanf ("%d", &t2[k]) ;

") ;

/* tri pralable et affichage des valeurs fusionner */


bulle (t1, nval1) ;
bulle (t2, nval2) ;
printf ("\npremier tableau fusionner\n") ;
for (k=0 ; k<nval1 ; k++)
printf ("%5d", t1[k]) ;
printf ("\nsecond tableau fusionner\n") ;
for (k=0 ; k<nval2 ; k++)
printf ("%5d", t2[k]) ;
/* fusion et affichage rsultats */
fusion (t, t1, t2, nval1, nval2) ;
printf ("\n\n rsultat de la fusion des deux tableaux\n") ;
for (k=0 ; k<nval1+nval2 ; k++)
printf ("%5d", t[k]) ;
}

/********************************************************/
/*
fonction de fusion de deux tableaux
*/
/********************************************************/
void fusion (int t[], int t1[], int t2[], int nval1, int nval2)
/* t1 et t2 : tableaux fusionner
*/
/* t :tableau rsultant
*/
/* nval1 : nombre de valeurs du premier tableau t1 */
/* nval2 : nombre de valeurs du second tableau t2 */
{
int i1, i2,
/* indices courants dans les tableaux fusionner */
i,
/* indice courant dans le tableau rsultant */
k ;

169

170

Exe rcice s e n langage C


i = 0 ; i1 = 0 ; i2 = 0 ;
while (i1 < nval1 && i2 < nval2)
{ if ( t1[i1] < t2[i2] ) t[i++] = t1[i1++] ;
else t[i++] = t2[i2++] ;
}
if (i1 == nval1)
for (k=i2 ; k<nval2 ; k++) t[i++] = t2[k] ;
else for (k=i1 ; k<nval1 ; k++) t[i++] = t1[k] ;

/*******************************************************/
/* fonction de tri d'un tableau (mthode de la bulle) */
/*******************************************************/
void bulle (int t[], int nval)
{
int i, j, tempo, k, permut ;
i = -1 ; permut = 1 ;
while (i < nval-1 && permut)
{ permut = 0 ;
for (j=nval-2 ; j>i ; j--)
if ( t[j] > t[j+1])
{ permut = 1 ;
tempo = t[j] ; t[j] = t[j+1] ; t[j+1] = tempo ;
}
i++ ;
}
}

Com m e ntaire s
*Pour e ffe ctue r le tri pr alable des deux tableaux fournis e n donn e , nous avons re pris la fonction bulle r alise dans
l'e xe rcice IV-2. Nous en avons toute fois supprim les instructions perm e ttant d'affich e r, sur dem ande , les im pre s s ions
inte rm diaire s .

IV. Tris, fusions e t re ch e rch e e n table

171

IV-5 Re ch e rch e dich otom iq ue


L'e xe rcice II-4 de facturation par code faisait inte rve nir un algorith m e s q ue ntie lde re ch e rch e e n table. Nous vous
proposons ici de raliser un algorith m e plus perform ant de re ch e rch e par "dich otom ie ".
________________________________________________________________________________________

Enonc
Ecrire un program m e q ui re ch e rch e , partir d'un code d'article (num riq ue ), l'inform ation q ui lui e s t associ e , savoir
un libell (ch a
ne ) e t un prix unitaire (r e l).
Com m e dans l'e xe rcice II-4, le program m e utilisera un tableau de s tructure s , dclar un nive au global, pour cons e rve r
les inform ations re q uis e s . Ce tte fois, par contre , ces derni re s s e ront rang e s par ordre croissant du num ro de code .
La localisation d'un num ro de code donn se fe ra par une re ch e rch e dich otom iq ue . Ce lle-ci consiste profite r de l'ordre
du tableau pour acc lre r la re ch e rch e e n procdant com m e s uit :
- O n consid re l' lm e nt figurant au "m ilie u" du tableau. Si le code ch e rch lui e s t gal, la re ch e rch e e s t te rm in e .
S'illui e s t inf rie ur, on e n conclut q ue le code re ch e rch ne pe ut s e trouve r q ue dans la pre m i re m oiti du tableau ;
dans le cas contraire , on e n conclut q u'ils e trouve dans la s e conde m oiti .
- O n re com m e nce alors l'op ration sur la "m oiti " conce rn e , puis sur la m oiti de ce tte m oiti , e t ainsi de suite ...
jus q u' ce q ue l'une des conditions suivante s s oit satisfaite :
*on a trouv l' lm e nt ch e rch ,
*on e s t sr q u'ilne figure pas dans le tableau.

Exe m pl
es
code article recherch : 24
le code 24 n'existe pas
________________
code article recherch : 19
article de code 19
libell : Balance de mnage
prix :
278.00
________________________________________________________________________________________

172

Exe rcice s e n langage C

ANALYSE
L'algorith m e propos par l' nonc s ugg re d'utiliser trois variables pe rm e ttant de spcifie r, un instant donn , la partie
du tableau dans laq ue lle s 'e ffe ctue la re ch e rch e :
gauch e : dbut de la partie re s tant e xplore r,
droite : fin de la partie re s tant e xplore r,
m ilie u : position ch oisie pour le "m ilie u" de ce tte partie re s tant e xplore r.
Note z dj q ue ce tte notion de m ilie u e s t q ue lque pe u am bigu. Nous convie ndrons q u'e lle corre s pond la partie e nti re
de la m oye nne des indice s gauch e e t droite .
L'algorith m e de re ch e rch e par dich otom ie pe ut alors s' nonce r ainsi (t dsignant le tableau, n le nom bre de code s e t x
l' lm e nt ch e rch ) :
- Initialiser gauch e e t droite de faon q u'ils dsignent l'e ns e m ble du tableau.
- R p te r le traite m e nt suivant :
*D te rm ine r le m ilie u de la partie e xplore r :
m ilie u = (gauch e + droite ) / 2
*Com pare r l' lm e nt ch e rch x ave c t(m ilie u) :
+ S'ils sont gaux, l' lm e nt ch e rch e s t localis en position m ilie u,
+ Si x e s t suprieur t(m ilie u), l' lm e nt ch e rch ne pe ut s e s itue r q ue dans la partie droite ;on r alise
l'affe ctation :
debut = m ilie u + 1
+ dans le cas contraire , l' lm e nt ch e rch ne pe ut s e s itue r q ue dans la partie gauch e ;on r alise l'affe ctation :
fin = m ilie u - 1
Ilnous re s te spcifie r la condition d'arr t (ou de poursuite ) de ce tte r p tition. O n pe ut dj note r q ue , ch aq ue
parcours de la boucle, soit la valeur de gauch e augm e nte , soit ce lle de droite dim inue . Ainsi, on e s t sr q u'au bout d'un
nom bre fini de tours on aboutira l'une des situations suivante s :
- l' lm e nt a t localis.
- la valeur de gauch e e s t suprieure ce lle de droite .
Elles nous fournis s e nt donc tout nature llem e nt la condition de fin de notre boucle.

IV. Tris, fusions e t re ch e rch e e n table

173

Note z q ue , dans un pre m ie r te m ps, la valeur de gauch e devie nt gale ce lle de droite ;m ais, dans ce cas, nous ne
savons pas encore si le s e ul lm e nt re s tant e xam ine r e s t ou non gal x ;aussi est-iln ce s s aire de faire un tour
supplm e ntaire pour s'e n assure r.

Program m e
#include <stdio.h>
/* ------ structure contenant les informations relatives aux
/*
diffrents articles
-------------#define NBART 6
/* nombre total d'articles */
typedef struct { int code ;
/* code article */
char * lib ;
/* libell */
float pu ;
/* prix unitaire */
} t_article ;

*/
*/

t_article article [NBART] =


{ 11, "Gaufrier",
268.0,
14, "Cafetire 12 T",
235.0,
16, "Grille-pain",
199.50,
19, "Balance de mnage", 278.0,
25, "Centrifugeuse",
370.0,
26, "Four raclette 6P", 295.25
} ;
/* ----------------------------------------------------------------------*/
#define VRAI 1
#define FAUX 0
main()
{ int coderec,
codecour,
gauche,
droite,
milieu,
trouve ;

/* pour "simuler" des ..... */


/* ..... valeurs logiques
*/

/*
/*
/*
/*
/*
/*

code article recherch */


code courant */
limite gauche de la recherche */
limite droite de la recherche */
nouvelle limite (droite ou gauche */
indicateur code trouv/non trouv */

printf ("code article recherch : ") ;


scanf ("%d", &coderec) ;
gauche = 0 ;
droite = NBART-1 ;
trouve = FAUX ;

174

Exe rcice s e n langage C


while (gauche <= droite && !trouve)
{ milieu = (gauche+droite) / 2 ;
codecour = article[milieu].code ;
if ( codecour == coderec ) trouve = VRAI ;
else if ( codecour < coderec)
gauche = milieu + 1 ;
else droite = milieu - 1 ;
}

if (trouve) printf ("article de code %d\nlibell : %s\nprix : %10.2f",


coderec, article[milieu].lib, article[milieu].pu) ;
else printf ("le code %d n'existe pas", coderec) ;
}

Com m e ntaire s
*Note z bie n la condition r gissant la boucle while :
gauche <= droite && !trouve

- D 'une part, com m e nous l'avons dit dans notre analyse, nous poursuivons notre e xploration, m m e q uand les
valeurs de gauch e e t droite sont gales , de m ani re savoir si le s e ul lm e nt re s tant e xam ine r convie nt ou non.
- D 'autre part, nous y faisons inte rve nir un indicate ur logiq ue (trouve ). Nous aurions pu nous e n pas s e r, condition
de place r un bre ak dans la boucle. Toute fois, dans ce cas, il aurait fallu pr voir, e n fin de boucle, un te s t
supplm e ntaire pe rm e ttant de savoir si la re ch e rch e avait t fructue us e ou non.

D ISCUSSIO N
Ilfaut pre ndre garde , dans le droulem e nt de l'algorith m e , ne pas s e conte nte r de pre ndre com m e nouve lle borne de la
partie de tableau e xplore r la valeur de m ilie u, e n crivant :
debut = m ilie u
ou :
fin = m ilie u
En e ffe t, dans ce cas, on ne pe ut plus prouve r q ue la boucle s 'ach ve e n un nom bre fini de tours. Ce rtaine s s ituations
conduis e nt d'ailleurs une boucle infinie .

V : GESTIO N D Y NA M IQUE

Les donnes d'un program m e s e r partissent e n trois cat gorie s : statiq ue s , autom atiq ue s e t dynam iq ue s . Les donnes
statiq ue s s ont dfinies d s la com pilation ;la ge s tion des donnes autom atiq ue s re s te transpare nte au program m e ur e t
s e ules les donnes dynam iq ue s s ont v ritablem e nt cr e s (dans le tas) sur son initiative .
D 'une m ani re g n rale, l'utilisation de donnes dynam iq ue s fournit des solutions des problm e s te ls q ue :
- ge s tion de donnes dont l'am pleur n'e s t pas connue lors de la r alisation du program m e ,
- m ise en oeuvre de structures dites dynam iq ue s , te lles q ue les liste s ch a
n e s ou les arbres binaire s .
Ce ch apitre vous e n propos e q ue lque s e xe m ples .

V-1 Cribl
e dynam iq ue
________________________________________________________________________________________

Enonc
R aliser un program m e q ui d te rm ine les pre m ie rs nom bre s pre m ie rs par la m th ode du crible d'Eratosth ne , e xpos e
dans l'e xe rcice I-2.
Ce tte fois, par contre , le nom bre d'entie rs considrer ne sera pas fix par le program m e , m ais fourni e n donn e . Le
program m e alloue ra dynam iq ue m e nt l'e m place m e nt m m oire n ce s s aire au d roulem e nt de l'algorith m e . En cas de
m m oire insuffisante , ildem ande ra l'utilisate ur de form uler une dem ande m oins im portante .
O n s'astre indra ici utiliser la fonction m al
l
oc.

Exe m pl
e
combien d'entiers voulez-vous examiner : 200

176

Exe rcice s e n langage C

entre 1 et 200 les nombres premiers sont :


2
3
5
7
11
13
31
37
41
43
47
53
73
79
83
89
97
101
127
131
137
139
149
151
179
181
191
193
197
199

17
59
103
157

19
61
107
163

23
67
109
167

29
71
113
173

________________________________________________________________________________________

ANALYSE
L'algorith m e lui-m m e a dj t e xpos dans l'e xe rcice I-2. La nouve aut r s ide ici dans l'allocation dynam iq ue de
l'e s pace im parti au tableau d'e ntie rs. Pour ce faire , la dm arch e la plus classique consiste faire appe l la fonction
m alloc, com m e nous le pr conis e l' nonc .

Program m e
#include <stdio.h>
#include <stdlib.h>
#define VRAI 1
#define FAUX 0
main()
{
unsigned n,
* raye,
prem,
i ;
int na ;

/* pour simuler des ...*/


/* ... valeurs "logiques" */

/* nombre d'entiers considrer */


/* pointeur sur tableau servant de crible */
/* dernier nombre premier considr */
/* compteur de nombres premiers affichs */

/* lecture du nombre d'entiers considrer et


allocation dynamique du tableau correspondant */
do
{ printf ("combien d'entiers voulez-vous examiner : ") ;
scanf ("%u", &n) ;
raye = (unsigned *) malloc ( (n+1)*sizeof(unsigned) ) ;
if (raye == NULL)
printf ("** mmoire insuffisante ") ;
}
while (raye == NULL) ;

V.Ge s tion dynam iq u e


/* initialisations du crible */
for (i=1 ; i<=n ; i++)
raye[i] = FAUX ;
raye[1] = VRAI ;

177

/* mise "zro" du crible */


/* on raye le nombre 1 */

/* passage au crible */
prem = 1 ;
while (prem*prem <= n)
{ while (raye[++prem] && prem<n ) {}
/* recherche premier nb prem non ray */
for (i=2*prem ; i<=n ; i+=prem)
/* on raye tous ses multiples */
raye[i] = VRAI ;
}
/* affichage rsultats */
printf ("entre 1 et %u les nombres premiers sont :\n", n) ;
na = 0 ;
for (i=1 ; i<=n ; i++)
if ( !raye[i] )
{ printf ("%7u", i) ;
if (++na%10 == 0) printf ("\n") ; /* 10 nombres par ligne */
}
}

Com m e ntaire s
*L'allocation de l'e s pace m m oire n ce s s aire au tableau d'e ntie rs e s t r alise par l'instruction :
raye = (unsigned *) malloc ( (n+1)*sizeof(unsigned) ) ;

dans laq ue lle raye e s t un pointe ur sur des entie rs non sign s .
O r, le prototype de m alloc e s t pr cis m e nt :
void * malloc (size_t) ;

Le r s ultat fourni par m alloc e s t un "pointe ur g n riq ue " q ui pe ut tre conve rti im plicite m e nt e n un pointe ur de n'im porte
q ue ltype . Aussi, l'op rate ur de "cast" (unsigne d *) n'e s t pas indispensable ici. Notre instruction d'allocation m m oire
aurait pu s' crire :
raye = malloc ( (n+1) * sizeof(unsigned) ) ;

178

Exe rcice s e n langage C

En ce q ui conce rne l'argum e nt de m alloc, ce lui-ci e s t a priori d'un type size _t dfini (par type de f) dans stdlib.h . Le type
e xact corre s pondant dpend de l'im plm e ntation (m ais ile s t toujours non sign - e n g n ral, ils'agit de unsigne d int).
Note z q ue le r s ultat fourni par size of e s t du m m e type size _t.
R appe lons q ue m alloc fournit e n r s ultat un pointe ur sur le dbut de la zone conce rn e lors q ue l'allocation a r ussi et un
pointe ur nuldans le cas contraire (note z q ue le sym bole NULLe s t dfini dans stdlib.h ).
*En ce q ui conce rne l'algorith m e de passage au crible, vous re m arq ue z q ue nous avons e m ploy e xacte m e nt les m m e s
instructions q ue dans le program m e de l'e xe rcice I-2. Pourtant, dans ce dernie r, le sym bole raye dsignait un tableau
d'entie rs, tandis q u'ici ildsigne un pointe ur sur des entie rs. Ce la e s t possible parce q u'e n langage C, un nom de tableau
e s t un pointe ur (constant).

D ISCUSSIO N
*Le ch oix du type unsigne d pour n e s t q ue lque pe u arbitraire ;ile s t guid par le fait q ue m alloc adm e t g n ralem e nt un
argum e nt de ce type . En supposant q ue te le s t le cas, on constate q u'alors l'e xpre s s ion :
(n+1) * sizeof (unsigned)

conduit des valeurs e rrones d s q ue la valeur de n*size of(int) dpas s e la capacit du type int (n'oublie z pas q u'iln'y a
pas de dte ction de dpas s e m e nt de capacit pour les op rations portant sur des entie rs). Le r s ultat pe ut alors tre
catastroph iq ue car le nom bre d'octe ts dem and s m alloc s e trouve tre inf rie ur ce lui r e llem e nt utilis.
Le problm e s e com pliq ue e ncore un pe u si l'on tie nt com pte de ce q ue , dans ce rtaine s im plm e ntations, le type size _t
pe u corre s pondre autre ch os e q ue unsigne d int.
En toute rigue ur, ilfaudrait donc s'assure r q ue le nom bre de valeurs dem and e s par l'utilisate ur e s t e ffe ctive m e nt
inf rie ur une ce rtaine lim ite fixe r e n fonction de l'im plm e ntation conce rn e .

V-2 Cr ation dynam iq ue de ch a


ne s
Lors q u'un program m e doit traite r un grand nom bre de ch a
nes de longue ur variable e t q ue ce nom bre n'e s t pas connu a
priori, ilpe ut s'av re r int re s s ant de faire alloue r dynam iq ue m e nt (par le program m e ) l'e s pace m m oire n ce s s aire au
stock age des ch a
ne s . C'e s t ce q ue vous propose cet e xe rcice q ui pe ut tre considr com m e pr alable un traite m e nt
ult rie ur de ce s ch a
ne s (par e xe m ple un tri com m e vous le propos e ra l'e xe rcice V-3).

V.Ge s tion dynam iq u e

179

________________________________________________________________________________________

Enonc
Ecrire un program m e q ui lit un nom bre q ue lconq ue de ch a
ne s au clavie r e t q ui les range e n m m oire dans des
e m place m e nts allous dynam iq ue m e nt au fur e t m e s ure des besoins. Le s adresses de ch acune des ch a
ne s s e ront
cons e rves dans un tableau de pointe urs. Ce dernie r s e ra r s e rv dans le program m e (e n clas s e autom atiq ue ) e t sa taille
(fixe ) im pos e ra donc une valeur m axim ale au nom bre de ch a
ne s q u'ils e ra ainsi possible de traite r.
L'utilisate ur signalera q u'ila fourni sa derni re ch a
ne e n la faisant suivre d'une ch a
ne "vide".
Le program m e affich e ra e nsuite les ch a
ne s lue s , titre de sim ple contrle.
R e m arque : on utilisera la fonction m alloc e t on supposera q ue les ligne s lue s au clavie r ne pe uve nt jam ais dpas s e r 127
caract re s .

Exe m pl
e
----- chane
C
----- chane
Turbo C
----- chane
Basic
----- chane
Pascal
----- chane
Turbo Pascal
----- chane

numro 1 (return pour finir)


numro 2 (return pour finir)
numro 3 (return pour finir)
numro 4 (return pour finir)
numro 5 (return pour finir)
numro 6 (return pour finir)

fin cration

liste des chanes cres


------- chane numro 1
C
------- chane numro 2
Turbo C
------- chane numro 3

180

Exe rcice s e n langage C

Basic
------- chane numro 4
Pascal
------- chane numro 5
Turbo Pascal
________________________________________________________________________________________

ANALYSE
L' nonc nous im pose donc de dfinir, au s e in du program m e , un tableau de pointe urs destin conte nir les adresses des
ch a
ne s cr e r.
Ch aq ue ch a
ne s e ra d'abord lue dans une zone inte rm diaire (non dynam iq ue ). O n lui alloue ra e nsuite , dynam iq ue m e nt,
l'aide de la fonction m alloc, un e m place m e nt dont la taille corre s pond e xacte m e nt sa longue ur ;l'adre s s e ainsi obte nue
s e ra m m orise dans le tableau de pointe urs.
Le traite m e nt s e ra inte rrom pu :
- soit q uand le tableau de pointe urs e s t plein,
- soit q uand l'utilisate ur fournit une ch a
ne vide.
D e plus, ch aq ue allocation r alise par m alloc, on s'assure ra q ue l'e s pace m m oire n ce s s aire a pu tre obte nu. D ans le
cas contraire , on pr voira d'inte rrom pre le program m e .

Program m e
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NCHMAX 1000
#define LGLIGNE 127
main()
{
char ligne [LGLIGNE+1],
* adr [NCHMAX],
* ptr ;
int nch,
i ;

/* pour la fonction exit */


/* nombre maximal de chanes */
/* longueur maximale d'une ligne d'cran */

/*
/*
/*
/*

chane servant lire une ligne cran */


tableau de pointeurs sur les chanes */
pointeur courant sur une chane */
compteur du nombre de chanes */

/* mise zro du tableau de pointeurs */

V.Ge s tion dynam iq u e

181

for (i=0 ; i<NCHMAX ; i++)


adr[i] = NULL ;
/* boucle de cration dynamique des chanes */
nch=0 ;
while (nch < NCHMAX)
/* tant que nb max chanes non atteint */
{ printf ("----- chane numro %d (return pour finir)\n", nch+1) ;
gets (ligne) ;
if ( strlen(ligne) )
{ if ( (ptr = malloc (strlen(ligne)+1)) != NULL)
strcpy (adr[nch++]=ptr, ligne) ;
else
{ printf ("\n\n*** erreur allocation dynamique") ;
exit(-1) ;
/* arrt si erreur alloc dynam */
}
}
else break ;
/* sortie boucle si rponse vide */
}
printf ("\nfin cration\n") ;
/* liste des chanes ainsi cres */
printf ("\n\nliste des chanes cres\n\n") ;
i = 0 ;
for (i=0 ; i<nch ; i++)
printf ("------- chane numro %d\n%s\n", i+1, adr[i]) ;
}

Com m e ntaire s
*Ici, com pte te nu de ce q ue nous prcisait l' nonc , nous avons ch oisi de lire nos ch a
nes dans un tableau de 128
caract re s , l'aide de la fonction ge ts.
*Nous avons re m is "z ro" le tableau de pointe urs sur nos ch a
ne s . Ils'agit l d'une op ration superflue m ais q ui pe ut
s'av re r utile pe ndant la ph ase de m ise au point du program m e . Note z l'usage du sym bole NULL;prdfini dans le
fich ie r stdlib.h , ilcorre s pond la constante pointe ur nulle.
*La cr ation de s ch a
ne s e s t r alise par une boucle tant q u e (instruction w h ile), dans laq ue lle nous avons prvu de ux
autre s s ortie s :

182
Exe rcice s e n langage C
- une s ortie par bre ak , dans le cas o l'utilisate ur a fourni une ch a
ne vide,
- un arr t e xce ptionne ldu program m e par e xit, dans le cas o l'allocation dynam iq ue a ch ou . Ce tte fonction (dont
le prototype figure dans stdlib.h ) re q uie rt un argum e nt ;sa valeur e s t transm ise au syst m e e t e lle pourrait
ve ntue llem e nt tre r cup r e par d'autre s program m e s . Note z q ue , e n l'abs e nce de l'instruction #include re lative
stdlib.h , le com pilate ur acce pte un appe lde e xit sans argum e nt (ile s t incapable de dte cte r l'e rre ur - laq ue lle n'a
d'ailleurs aucune incide nce s ur l'e x cution du program m e lui-m m e ).
Nature llem e nt, beaucoup d'autre s form ulations s e raie nt possibles .

D ISCUSSIO N
*Le fait de r s e rve r le tableau dans le program m e (e n clas s e autom atiq ue ) im pos e une lim ite au nom bre de ch a
ne s q u'il
e s t ainsi possible de traite r ;ce tte lim ite e s t ind pe ndante de la m m oire r e llem e nt disponible. O n pe ut am liore r
q ue lque pe u la situation e n faisant galem e nt al
l
ouer dynam iquem ent l
'espace ncessaire ce tabl
eau de pointeurs. Il
faut toute fois e n conna
tre la taille (ou du m oins une valeur m axim ale) lors de l'e x cution du program m e . Ce la pe ut faire
l'obje t d'une donne fournie par l'utilisate ur com m e dans l'e xe rcice s uivant.

V-3 Tri dynam iq ue de ch a


ne s
________________________________________________________________________________________

Enonc
Ecrire un program m e pe rm e ttant de trie r par ordre alph abtiq ue des
pr cdent, on alloue ra dynam iq ue m e nt des em place m e nts m m oire
leurs adre s s e s s e ront cons e rves dans un tableau de pointe urs.
e m place m e nt allou dynam iq ue m e nt e n dbut de program m e ;pour
valeur m axim ale du nom bre de ch a
ne s q u'ils e ra am e n fournir.

ch a
ne s fournie s e n donn e . Com m e dans l'e xe rcice
aux ch a
ne s , au fur e t m e s ure de leur lecture , e t
Par contre , ici, ce dernie r ve rra, lui aussi, son
ce faire , on de m ande ra l'utilisate ur de fournir une

O n utilisera l'algorith m e de "tri par e xtraction sim ple" e xpos dans l'e xe rcice V-1 e t on fe ra appe l la fonction m alloc.

Exe m pl
e

V.Ge s tion dynam iq u e


nombre maximal
------- chane
C
------- chane
Turbo C
------- chane
Basic
------- chane
Pascal
------- chane
Turbo Pascal
------- chane
Fortran
------- chane
ADA
------- chane

183

de chanes ? 100
numro 1 (return pour finir)
numro 2 (return pour finir)
numro 3 (return pour finir)
numro 4 (return pour finir)
numro 5 (return pour finir)
numro 6 (return pour finir)
numro 7 (return pour finir)
numro 8 (return pour finir)

fin cration

liste trie des chanes cres


ADA
Basic
C
Fortran
Pascal
Turbo C
Turbo Pascal
________________________________________________________________________________________

ANALYSE
Ilnous suffit e n fait d'adapte r le program m e de l'e xe rcice pr cdent, e n lui adjoignant :
- la r s e rvation dynam iq ue du tableau de pointe urs,
- le tri du tableau de ch a
ne s ainsi cr , par r organisation de s pointe urs. Nous utiliserons pour cela l'algorith m e de tri
par e xtraction sim ple Ce lui-ci a t e xpos dans l' nonc de l'e xe rcice V-1 e t son adaptation au tri de ch a
ne s a t
e xpliq ue dans l'analyse de l'e xe rcice V-2.

184

Exe rcice s e n langage C

Program m e
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LGLIGNE 127
main()
{
char ligne [LGLIGNE+1],
* * adr,
* ptr,
* tempo ;
unsigned nchmax,
nch,
i, j, kmax ;

/* longueur maximale d'une ligne d'cran */

/*
/*
/*
/*
/*
/*

chane servant lire une ligne cran */


adresse tableau pointeurs sur les chanes */
pointeur courant sur une chane */
pointeur temporaire pour ch. 2 pointeurs */
nombre maximal de chanes */
compteur du nombre de chanes */

/* cration et mise zro du tableau de pointeurs */


printf ("nombre maximum de chanes ? ") ;
scanf ("%d", &nchmax) ;
getchar() ;
/* pour sauter la validation */
if ( (adr = malloc (nchmax*sizeof(char*)) ) == NULL)
{ printf ("\n\n*** erreur allocation dynamique") ;
exit(-1) ;
/* arrt si erreur alloc dynam */
}
for (i=0 ; i<nchmax ; i++)
adr[i] = NULL ;
/* boucle de cration dynamique des chanes */
nch = 0 ;
while (nch < nchmax)
/* tant que nb max de chanes non atteint
{ printf ("------- chane numro %d (return pour finir)\n", nch+1)
gets (ligne) ;
if ( strlen(ligne) )
{ if ( ( ptr = malloc (strlen(ligne)+1)) != NULL)
strcpy (adr[nch++]=ptr, ligne) ;
else
{ printf ("\n\n*** erreur allocation dynamique") ;
exit(-1) ;
/* arrt si erreur alloc dynam
}
}
else break ;
/* sortie boucle si rponse vide
}

*/
;

*/

*/

V.Ge s tion dynam iq u e

185

printf ("\nfin cration\n") ;


/* tri des chanes par rarrangement des pointeurs */
for (i=0 ; i<nch-1 ; i++)
{ kmax = i ;
for (j=i+1 ; j<nch ; j++)
if ( stricmp (adr[kmax], adr[j]) > 0 ) kmax = j ;
tempo = adr[kmax] ;
adr[kmax] = adr[i] ;
adr[i] = tempo ;
}
/* liste tries des chanes ainsi cres */
printf ("\n\nliste trie des chanes cres\n\n") ;
for (i=0 ; i<nch ; i++)
puts ( adr[i] ) ;
}

Com m e ntaire s
*D ans le program m e de l'e xe rcice V-2, le sym bole adr dsignait un tableau de pointe urs. Ici, ce m m e sym bole dsigne
un pointe ur sur un tableau de pointe urs. O r, m algr ce tte diff re nce appare nte , vous constate z q ue nous e m ployons
toujours la notation :
adr[i]
ave c la m m e signification dans les deux cas.
En fait, dans le pr cdent program m e , adr tait une constante pointeur dont la valeur tait ce lle de l'adresse de dbut du
tableau de pointe urs. Dans le pr s e nt program m e , adr e s t une variabl
e pointeur dont la valeur e s t galem e nt ce lle de
dbut du tableau de pointe urs. Ainsi, dans les deux cas :
adr[i]
e s t q uivalent :
*(adr + i)
Note z ce pe ndant q ue l' q uivalence e ntre les deux program m e s n'e s t pas totale. En e ffe t, dans le pre m ie r cas, adr n'e s t
pas une lvalue (m ot anglais dont une traduction approch e pourrait tre : valeur gauch e ) ;par e xe m ple, l'e xpre s s ion
adr++ s e rait incorre cte . Dans le s e cond cas, par contre , adr e s t bien une lvalue .

186
Exe rcice s e n langage C
*Nous n'avons pris aucune pr caution particuli re e n ce q ui conce rne les lecture s au clavie r q ui sont r alises ici par
ge ts e t scanf. Ind pe ndam m e nt des anom alie s h abitue lles e ncourue s e n cas de donnes incorrecte s (ch a
ne trop longue
pour ge ts, donn e non num riq ue pour scanf), un problm e s upplm e ntaire appara
t, li au fait q u'apr s une lecture par
scanf, le pointe ur re s te positionn s ur le dernie r caract re non e ncore utilis, savoir ici le \n (du m oins si l'utilisate ur a
valid norm alem e nt, sans fournir d'inform ations supplm e ntaire s ). Si la lecture s uivante e s t, son tour, e ffe ctu e par
scanf, aucun problm e particulie r ne s e pos e , le caract re \n tant sim plem e nt ignor . Iln'e n va plus de m m e lors q ue la
lecture s uivante e s t e ffe ctu e par ge ts ;dans ce cas, e n e ffe t, ce caract re e s t inte rpr t com m e un caract re de "fin" e t
ge ts fournit... une ch a
ne vide. C'est pour vite r ce ph nom ne q ue nous avons d introduire une instruction ge tch ar pour
absorber le \n.

D ISCUSSIO N
Pour pouvoir alloue r conve nablem e nt l'e m place m e nt du tableau de pointe urs, notre program m e a besoin q ue l'utilisate ur
lui fournis s e une valeur m axim ale du nom bre de ch a
ne s . Si nous souh aitions q u'ile n soit autre m e nt, ils e rait n ce s s aire
de pouvoir alloue r provisoire m e nt un e m place m e nt ce tableau, q uitte l' te ndre e nsuite au fur e t m e s ure des besoins
l'aide de la fonction re alloc. Une te lle e xte nsion pourrait tre r alise, soit ch aq ue nouve lle ch a
ne e ntr e , soit par
blocs de taille fixe (par e xe m ple toute s les 100 ch a
ne s ).

V-4 Cr ation d'une l


is te ch a
n e
O n appe lle liste ch a
n e ou liste li e une s uite ordonne d' lm e nts dans laq ue lle ch aq ue lm e nt, sauf le dernie r,
com porte un pointe ur sur l' lm e nt suivant.

________________________________________________________________________________________

Enonc
Ecrire un program m e q ui cr e une liste ch a
ne d' lm e nts com portant ch acun :
- un nom (ch a
ne ) d'au m axim um 10 caract re s ,
- un ge .
Le s inform ations corre s pondante s s e ront lue s au clavie r e t l'utilisate ur frappe ra un nom "vide" apr s les donnes relative s
au de rnie r lm e nt.

V.Ge s tion dynam iq u e

187

Le program m e affich e ra e nsuite les inform ations conte nues dans la liste ainsi cr e , dans l'ordre inve rse de ce lui dans
leq ue le lles auront t fournie s .
O n pr voira de ux fonctions : l'une pour la cr ation, l'autre pour la liste . Elles possderont com m e uniq ue argum e nt
l'adresse de dbut de la liste (pointe ur sur le pre m ie r lm e nt).

Exe m pl
e
om : Laurence
age : 19
nom : Yvette
age : 35
nom : Catherine
age : 20
nom : Sebastien
age : 21
nom :

NOM
Sebastien
Catherine
Yvette
Laurence

AGE
21
20
35
19

________________________________________________________________________________________

ANALYSE
Ch aq ue lm e nt de notre liste s e ra re pr s e nt par une s tructure . Nous voyons q ue ce lle-ci doit conte nir un pointe ur sur un
lm e nt de m m e type . Ce la fait inte rve nir une ce rtaine "r cursivit " dans la dclaration corre s pondante , ce q ui e s t
acce pt e n C.
En ce q ui conce rne l'algorith m e de cr ation de la liste , deux possibilit s s 'offre nt nous :
- Ajoute r ch aq ue nouve l lm e nt la fin de la liste . Le parcours ult rie ur de la liste s e fe ra alors dans le m m e ordre
q ue ce lui dans leq ue lles donnes corre s pondante s ont t introduite s .
- Ajoute r ch aq ue nouve l lm e nt e n dbut de liste . Le parcours ult rie ur de la liste s e fe ra alors dans l'ordre inve rs e
de ce lui dans leq ue lles donnes corre s pondante s ont t introduite s .

188
Exe rcice s e n langage C
Com pte te nu de ce q ue l' nonc nous dem ande d'affich e r la liste l'e nve rs, apr s sa cr ation, ilpara
t plus apportun de
ch oisir la s e conde m th ode .
Com m e dem and , la cr ation de la liste s e ra r alise par une fonction. Le program m e principals e conte nte ra de r s e rve r
un pointe ur (nom m de but) destin dsigner le pre m ie r lm e nt de la liste . Sa valeur e ffe ctive s e ra fournie par la
fonction de cr ation.
L'algorith m e de cr ation, q uant lui, consiste ra r p te r le traite m e nt d'insertion d'un nouve l lm e nt e n dbut de liste ,
savoir :
- cr e r dynam iq ue m e nt un e m place m e nt pour un nouve l lm e nt e t y range r les inform ations fournie s au clavie r,
- affe cte r au pointe ur conte nu dans ce nouve l lm e nt l'ancie nne valeur de de but,
- affe cte r de but l'adresse de ce nouve l lm e nt.
Nous convie ndrons, de plus, q ue le dernie r lm e nt de la liste poss de un pointe ur nul, ce q ui nous facilite ra
l'initialisation de l'algorith m e ;e n e ffe t, ce lle-ci s e ram ne alors l'affe ctation de but d'une valeur nulle.

Program m e
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LGNOM 20

/* longueur maximale d'un nom */

typedef struct element


/* dfinition du type lment */
{ char nom [LGNOM+1] ;
/* nom */
int age ;
/* age */
struct element * suivant ;
/* pointeur element suivant */
} t_element ;

main()
{
void creation (t_element * *) ;
void liste (t_element *) ;
t_element * debut ;
creation (&debut) ;
liste (debut) ;
}

/* fonction de cration de la liste */


/* fonction de liste de la liste */
/* pointeur sur le dbut de la liste */

V.Ge s tion dynam iq u e

/****************************************************/
/*
fonction de cration d'une liste chane
*/
/****************************************************/
void creation (t_element * * adeb)
{
char nomlu [LGNOM+1] ;
/* pour lire un nom au clavier */
t_element * courant ;
/* pour l'change de valeurs de pointeurs */
* adeb = NULL ;

/* liste vide au dpart */

while (1)
/* boucle de cration apparemment infinie ... */
{
/* ... mais, en fait, interrompue sur "nom vide" */
printf ("nom : ") ;
gets (nomlu) ;
if (strlen(nomlu))
{ courant = (t_element *) malloc (sizeof(t_element)) ;
strcpy (courant->nom, nomlu) ;
printf ("age : ") ;
scanf ("%d", &courant->age) ;
getchar() ;
/* pour sauter le \n */
courant->suivant = * adeb ;
* adeb = courant ;
}
else break ;
/* sortie boucle si nom vide */
}
}

/******************************************************/
/*
fonction de liste d'une liste chane
*/
/******************************************************/
void liste (t_element * debut)
{
printf ("\n\n
NOM
AGE\n\n") ;
while (debut)
{ printf ("%15s %3d\n", debut->nom, debut->age) ;
debut = debut->suivant ;
}
}

189

19 0

Exe rcice s e n langage C

Com m e ntaire s
*Nous avons ici ch oisi de dclare r notre s tructure un nive au globale t de faire appe l type de f. Ce tte dclaration un
nive au global vite de devoir d crire la m m e s tructure e n diff re nts e ndroits, ce q ui s e rait, non s e ulem e nt laborie ux
m ais, de surcro
t, source d'erreurs. Par contre , le re cours type de f n'apporte q u'une s im plification des dclarations des
lm e nts de ce type (dans le cas contraire , ilsuffirait de re m place r t_e le m e nt par struct e le m e nt).
Note z bie n, par contre , q u'iln'e s t pas possible de re m place r, au s e in de la dfinition de notre s tructure , l' criture :
struct element * suivant

par :
t_element * suivant

*La fonction de cr ation re oit e n argum e nt l


'adresse du pointe ur de but, car e lle doit pouvoir lui attribue r une valeur.
La fonction de liste , q uant e lle, s e conte nte de la val
eur de ce m m e pointe ur. Ce tte diff re nce s e r pe rcute
nature llem e nt sur la m ani re d'utiliser cet argum e nt dans ch acune des deux fonctions.
Note z d'ailleurs q ue nous avons pu nous pe rm e ttre , dans la fonction de liste , de m odifie r la valeur ainsi reue (le pointe ur
de but y dcrit succe s s ive m e nt les diff re nts lm e nts de la liste ).
*L e ncore , les lecture s au clavie r ont t r alises par scanf e t ge ts, donc sans prote ctions particuli re s . Com m e nous
l'avons dj signal dans le pr cdent e xe rcice , l'utilisation conjointe de ces deux fonctions pose un problm e li au fait
q ue , apr s une lecture par scanf, le pointe ur re s te positionn s ur le dernie r caract re non e ncore utilis, savoir
(g n ralem e nt) \n. C'e s t ce q ui justifie l'introduction d'une instruction ge tch ar pour absorber ce caract re inte m pe s tif.

VI : RECURSIVITE

La r cursivit e s t une notion d licate m ais q ui a l'avantage de conduire s ouve nt des program m e s s im ples .
Le s trois prem ie rs e xe rcices de ce ch apitre s ont plutt des "e xe rcices d'cole" destin s vous faire e xplore r diff re nte s
situations e n vous forant crire une fonction r cursive , l o, e n pratiq ue , on ne s e rait pas am e n le faire .

VI-1 l
e cture r curs ive (1)
________________________________________________________________________________________

Enonc
Ecrire une fonction r cursive de lecture d'une valeur e nti re au clavie r. La fonction de vra s'appe ler e lle-m m e dans le
cas o l'inform ation fournie e s t incorre cte (non num riq ue ).
O n pr voira une fonction un argum ent (l'adresse de la variable pour laq ue lle on ve ut lire une valeur) e t sans val
eur de
retour.
O n pourra faire appe l fge ts e t sscanf pour d te cte r conve nablem e nt les r pons e s incorre cte s .

Re m arq ue
Nous vous cons e illons de com pare r ce t e xe rcice au suivant dans leq ue lle m m e problm e e s t r s olu par l'e m ploi d'une
fonction r cursive s ans argum e nt e t ave c valeur de re tour.

Exe m pl
e

19 2

Exe rcice s e n langage C

donnez un nombre entier : un


** rponse incorrecte - redonnez-la : '
** rponse incorrecte - redonnez-la : 40
-- merci pour 40
________________________________________________________________________________________

ANALYSE
Au sein de la fonction (q ue nous nom m e rons lecture ), nous lirons la valeur atte ndue l'aide de fge ts (..., stdin), associ
sscanf, com m e nous l'avons dj fait dans ce rtains des exe rcice s pr cdents.
Nous consid re rons la r ponse de l'utilisate ur com m e corre cte lors q ue le code de re tour de sscanf s e ra gal 1. Si te l
n'e s t pas le cas, nous fe rons nouve au appe l la m m e fonction lecture .

Program m e
#include <stdio.h>
#define LG_LIG 20
main()
{
void lecture (int *) ;
int n ;

/* longueur maxi information lue au clavier */

/* prototype fonction (rcursive) de lecture */


/* entier lire */

printf ("donnez un nombre entier : ") ;


lecture (&n) ;
printf ("-- merci pour %d", n) ;
}
void lecture (int *p)
{
int compte ;
char ligne[LG_LIG+1] ;

/* compteur du nb de valeurs OK */
/* pour lire une ligne au clavier par fgets */
/*
+1 pour tenir compte du \0 de fin
*/

fgets (ligne, LG_LIG, stdin) ;


compte = sscanf (ligne, "%d", p) ;
if (!compte)
{ printf ("** rponse incorrecte - redonnez la : ") ;
lecture (p) ;

VI. R cursivit

19 3

}
}

Com m e ntaire s
*Note z bie n q u'au s e in de la fonction lecture , au nive au de l'appe lde sscanf, nous voyons appara
tre p e t non & p,
puis q ue ici p e s t dj un pointe ur sur la variable dont on ve ut lire la valeur.
*Si nous avions utilis sim plem e nt ge ts (com m e dans l'e xe rcice VI.5 de la pre m i re partie ) au lie u de fge ts (..., stdin),
nous aurions pu galem e nt nous prot ge r de m auvais e s r ponses de l'utilisate ur, m ais nous aurions d dfinir une taille
m axim ale pour la ch a
ne lue au clavie r ;nous aurions couru le ris q ue de "dbordem e nt m m oire ", dans le cas o
l'utilisate ur aurait fourni une r pons e trop longue .

D ISCUSSIO N
Ch aq ue nouve lappe lde lecture e ntra
ne l'allocation autom atiq ue , sur la pile, d'e m place m e nts pour :
- l'argum e nt p,
- les obje ts locaux : com pte e t ligne .
O r, e n fait, ne s ont n ce s s aire s q ue les valeurs corre s pondant au de rnie r appe lde lecture (ce lui o la lecture s 'e s t
conve nablem e nt droule ) ;dans ce s conditions, l'e m pilem e nt des diff re nts e m place m e nts allou s au tableau ligne e s t
superflu. Si l'on souh aite faire q ue lque s conom ies d'espace m m oire ce nive au, on pe ut s'arrange r pour q ue ce t
e m place m e nt ne s oit r s e rv q u'une s e ule fois :
- soit dans le program m e appe lant (ici le program m e principal) ;dans ce cas, ilfaudra e n transm e ttre l'adre s s e e n
argum e nt, ce q ui e ntra
ne l'e m pilem e nt d'une variable s upplm e ntaire .
- soit e n clas s e globale ;dans ce cas, on pe ut galem e nt traite r de la sorte com pte e t p (c'e s t- -dire , e n fait, n), ce q ui
supprim e du m m e coup tous les argum e nts e t les obje ts locaux de lecture . Note z q u'ilre s te ra q uand m m e , ch aq ue
appe l, une allocation autom atiq ue d'espace pour l'adre s s e d e re tour.
- soit e n clas s e s tatiq ue (static) au s e in de la fonction. L e ncore , nous pouvons traite r de la m m e m ani re la variable
com pte , la variable p, q uant e lle, re s tant soum ise aux e m pilem e nts.

19 4

Exe rcice s e n langage C

VI-2 Le cture r curs ive (2)


________________________________________________________________________________________

Enonc
Ecrire une fonction r cursive de lecture d'une valeur e nti re au clavie r. La fonction de vra s'appe ler e lle-m m e dans le
cas o l'inform ation fournie e s t incorre cte (non num riq ue ).
O n pr voira ce tte fois une fonction dans laq ue lle la valeur de re tour e s t la valeur lue (iln'y aura donc pas d'argum e nts).
L e ncore , on pourra faire appe l fge ts (..., stdin) e t sscanf pour d te cte r conve nablem e nt les r pons e s incorre cte s .

Re m arq ue
Ce t e xe rcice e s t surtout destin tre com par au pr cdent dans leq ue lle m m e problm e e s t r s olu par l'e m ploi d'une
fonction ave c argum e nt e t sans valeur de re tour.

Exe m pl
e
donnez un nombre entier : un
** rponse incorrecte - redonnez la : '
** rponse incorrecte - redonnez la : 40
-- merci pour 40
________________________________________________________________________________________

ANALYSE
Com m e pr cdem m e nt, au s e in de notre fonction (nom m e lecture ), nous lirons la valeur atte ndue l'aide de fge ts
associ sscanf. Nous consid re rons la r ponse de l'utilisate ur com m e corre cte lors q ue le code de re tour de sscanf s e ra
gal 1. Si ce la n'e s t pas le cas, nous fe rons de nouve au appe l la m m e fonction lecture .

VI. R cursivit

19 5

Program m e

#include <stdio.h>
#define LG_LIG 20
main()
{
int lecture (void) ;
int n ;

/* longueur maxi information lue au clavier */

/* fonction (rcursive) de lecture */


/* entier lire */

printf ("donnez un nombre entier : ") ;


n = lecture() ;
printf ("-- merci pour %d", n) ;
}
int lecture (void)
{
int compte,
p ;
char ligne[LG_LIG+1] ;

/* compteur du nb de valeurs OK */
/* entier lire */
/* pour lire une ligne au clavier par fgets */

fgets (ligne, LG_LIG, stdin) ;


compte = sscanf (ligne, "%d", &p) ;
if (!compte)
{ printf ("** rponse incorrecte - redonnez-la : ") ;
p = lecture() ;
}
return(p) ;
}

Com m e ntaire s
*Ce tte fois, on note ra q ue p d s igne une variable locale de type int, dont l'e m place m e nt e s t allou autom atiq ue m e nt
ch aq ue appe lde la fonction lecture , de la m m e m ani re q ue pour les autre s obje ts locaux com pte e t ligne . Par ailleurs,
si aucun e m place m e nt n'e s t allou ici pour un q ue lconq ue argum e nt, ilfaut e n pr voir un pour la valeur de re tour. O n
re m arq ue d'ailleurs q u'ici ce tte valeur s e trouve "propag e " de proch e e n proch e , lors du "dpilem e nt" des appe ls.
*Pre ne z garde ne pas crire :

19 6

Exe rcice s e n langage C


if (!compte)
{ printf ("** rponse incorrecte - redonnez-la : ") ;
p = lecture() ;
}
else return (p) ;

car la fonction ne re nve rrait une valeur q ue lors q ue la lecture s e s e rait droule conve nablem e nt. Note z d'ailleurs q ue
dans ce cas, bon nom bre de com pilate urs vous prvie ndrait par un m e s s age d'ave rtissem e nt ("w arning").
Par contre , ils e rait tout fait corre ct (e t q uivalent) d'crire :
if (!compte)
{ printf ("** rponse incorrecte - redonnez la : ") ;
return (lecture()) ;
}
else return (p) ;

D ISCUSSIO N
Le s re m arq ue s faites dans le pr cdent e xe rcice
s'appliq ue nt e ncore ici.

propos des em pilem e nts de ligne (e t ve ntue llem e nt com pte )

VI-3 Le cture r curs ive (3)


________________________________________________________________________________________

Enonc
Ecrire une fonction r cursive de lecture d'un entie r au clavie r. La fonction de vra s'appe ler e lle-m m e dans le cas o
l'inform ation fournie e s t incorre cte .
Ce tte fois, la fonction possdera 3 argum e nts :
- le m e s s age q u'e lle doit im prim e r avant de lire une valeur (le m e s s age "donne z un nom bre e ntie r :" ne s e ra donc
plus affich par le program m e principal),
- l'adresse de la variable dans laq ue lle on doit lire une valeur,
- le nom bre m axim ald'essais autoris s .

VI. R cursivit

19 7

Elle fournira un code de re tour gal 0 si la lecture a fini par aboutir e t -1 lors q ue la lecture n'a pas pu aboutir dans le
nom bre d'essais im partis.
Com m e dans les deux pr cdents e xe rcice s , on fe ra appe l fge ts associ e sscanf.

Exe m pl
es
donnez un nombre entier : huit
** rponse incorrecte - redonnez-la : 8
-- merci pour 8
____________________
donnez un nombre entier : un
** rponse incorrecte - redonnez-la
** rponse incorrecte - redonnez-la
** rponse incorrecte - redonnez-la
** rponse incorrecte - redonnez-la
-- nombre d'essais dpass

:
:
:
:

deux
trois
quatre
cinq

________________________________________________________________________________________

ANALYSE
Le m e s s age im prim e r s e ra transm is sous form e de l'adresse d'une ch a
ne . La fonction affich e ra ce m e s s age d s son
appe l. Son conte nu de vra donc tre :
donne z un nom bre e ntie r :
dans l'appe linitialde la fonction (r alis dans le program m e principal), e t :
**r pons e incorre cte - re donne z -a :
dans l'appe lde la fonction par e lle-m m e e n cas de r pons e incorre cte .
En ce q ui conce rne le nom bre m axim ald'appe ls, on le transm e ttra par valeur e t on s'arrange ra pour faire dcro
tre s a
valeur de 1 ch aq ue appe l.
La r cursivit des appe ls ce s s e ra lors q ue l'une des deux conditions suivante s s e ra satisfaite :
- valeur lue corre cte - on fournira alors 0 com m e valeur de re tour,

19 8
Exe rcice s e n langage C
- nom bre m axim ald'appe ls dpas s - on fournira alors -1 com m e valeur de re tour.

Program m e
#include <stdio.h>
#define LG_LIG 20
/* longueur maxi information lue au clavier */
main()
{
int lecture (char *, int *, int) ; /* proto fonction (rcursive) de lecture */
int n ;
/* entier lire */
const nessais = 5 ;
/* nombre d'essais autoriss */
if ( lecture ("donnez un nombre entier : ", &n, nessais) != -1)
printf ("-- merci pour %d", n) ;
else printf ("-- nombre d'essais dpasss") ;
}
int lecture (char * mes, int * p, int nmax)
/* mes : adresse message afficher avant lecture */
/* p : adresse de la valeur lire
*/
/* nmax : nombre d'essais autoriss
*/
{
int compte ;
/* compteur du nb de valeurs OK */
char ligne [LG_LIG] ;
/* pour lire une ligne au clavier par fgets */
printf ("%s", mes) ;
fgets (ligne, LG_LIG, stdin) ;
compte = sscanf (ligne, "%d", p) ;
if (!compte)
if (--nmax)
return (lecture ("** rponse incorrecte - redonnez la : ",
p, nmax) ) ;
else return (-1) ;
else return (0) ;
}

Com m e ntaire s
*Nous avons ch oisi ici de faire affich e r le m e s s age :
nom bre d'e s s ais dpass

VI. R cursivit

19 9

dans le program m e principal. Ils'agit l d'un ch oix arbitraire puis q ue nous aurions tout aussi bien pu le faire affich e r par
la fonction e lle-m m e .

VI-4 Puis s ance e nti re


________________________________________________________________________________________

Enonc
k

Ecrire une fonction r cursive pe rm e ttant de calculer la valeur de x pour x r e lq ue lconq ue e t k e ntie r re latif q ue lconq ue .
O n e xploite ra les propri t s s uivante s :
0

x = 1,
k

x =x

pour k = 1,

-k

x = 1 /x
k

k -1

k /2

x = (x
x = (x

pour k positif,

)x
)x

pour k positif im pair,


pour k positif pair.

O n te s te ra ce tte fonction l'aide d'un program m e principalpe rm e ttant l'utilisate ur de fournir e n donn e s les valeurs de
x e t de k .

Exe m pl
es
donnez une valeur relle : 4
donnez une puissance entire : -2
4.000000e+000 la puissance -2 = 6.250000e-002
_______________________

donnez une valeur relle : 5.2

200

Exe rcice s e n langage C

donnez une puissance entire : 3


5.200000e+000 la puissance 3 = 1.406080e+002
________________________________________________________________________________________

ANALYSE
L' nonc fournit les "dfinitions r cursive s " e m ploye r.

Program m e

#include <stdio.h>
main()
{
double puissance(double, int) ;
double x ;
int n ;

/* proto fonction d'lvation la puissance */


/* valeur dont on cherche la puissance neme */
/* puissance laquelle on veut lever x */

printf ("donnez une valeur relle : ") ;


scanf ("%le", &x) ;
printf ("donnez une puissance entire : ") ;
scanf ("%d", &n) ;
printf ("%le la puissance %d = %le", x, n, puissance (x, n) ) ;
}
double puissance (double x, int n)
{
double z ;
if (n < 0) return (puissance (1.0/x, -n) ) ;
else if (n == 0) return (1) ;
else if (n == 1) return (x) ;
else if (n%2 == 0)
{ z = puissance (x, n/2) ;
return (z*z) ;
}
else return (x * puissance (x, n-1) ) ;

/* puissance ngative */
/* x puissance 0 gale 1 */
/* x puissance 1 gale x */
/* puissance paire */

/* puissance impaire */

VI. R cursivit

201

Com m e ntaire s
Ile s t pr f rable d'crire :
z = puissance (x, n/2) ;
return (z*z) ;

plutt q ue :
return (puissance (x,n/2) * puissance (x,n/2) ) ;

q ui produirait deux fois plus d'appe ls de la fonction puissance .

VI-5 Fonction d'A ck e rm ann


________________________________________________________________________________________

Enonc
Ecrire une fonction r cursive calculant la valeur de la fonction d'Ack e rm ann, d finie pour m e t n, e ntie rs positifs ou
nuls, par :
A(m ,n) = A(m -1, A(m ,n-1) ) pour m > 0 e t n> 0,
A(0,n) = n+ 1 pour n> 0,
A(m ,0) = A(m -1,1) pour m > 0.
Ce tte fonction possdera e n argum e nt les valeurs de m e t de n et fournira e n r s ultat la valeur de A corre s pondante .
O n visualisera l'e m pilem e nt des appe ls e t leur d pilem e nt e n affich ant un m e s s age accom pagn de la valeur des deux
argum e nts lors de ch aq ue e ntre dans la fonction ainsi que juste avant sa sortie (dans ce dernie r cas, on affich e ra
galem e nt la valeur q ue la fonction s'appr te re tourne r).
O n te s te ra ce tte fonction l'aide d'un program m e principalauq ue lon fournira e n donn e s les valeurs de m e t de n.

202

Exe rcice s e n langage C

Exe m pl
e
valeurs de m et
** entre Acker
** entre Acker
** entre Acker
-- sortie Acker
-- sortie Acker
** entre Acker
-- sortie Acker
-- sortie Acker

n ?
(1,
(1,
(0,
(0,
(1,
(0,
(0,
(1,

: 1 1
1)
0)
1)
1) = 2
0) = 2
2)
2) = 3
1) = 3

Acker (1, 1) = 3
________________________________________________________________________________________

Program m e
#include <stdio.h>
main()
{
int m, n, a ;
int acker (int, int) ;

/* prototype fonction de calcul fonction d'Ackermann */

printf ("valeurs de m et n ? : ") ;


scanf ("%d %d", &m, &n) ;
a = acker (m, n) ;
printf ("\n\nAcker (%d, %d) = %d", m, n, a) ;
}
/***********************************************************/
/* fonction rcursive de calcul de la fonction d'Ackermann */
/***********************************************************/
int acker (int m, int n)
{
int a ;
/* valeur de la fonction */
printf ("** entre Acker (%d, %d)\n", m, n) ;

VI. R cursivit

203

if (m<0 || n<0)
a = -1
;
/* cas arguments incorrects */
else if (m == 0)
a = n+1 ;
else if (n == 0)
a = acker (m-1, 1) ;
else
a = acker (m-1, acker(m, n-1) ) ;
printf ("-- sortie Acker (%d, %d) = %d\n", m, n, a) ;
return (a) ;
}

VI-6 Tours d e H anoi


________________________________________________________________________________________

Enonc
R aliser une fonction r cursive proposant une s olution au problm e dit des tours de H anoi, leq ue ls' nonce ainsi :
O n dispose de trois piq ue ts, num rot s 1, 2 e t 3 e t de n disques de tailles diff re nte s . Au dpart, ces disques sont
e m pils par taille dcroissante s ur le piq ue t num ro 1. Le but du je u e s t de dplace r ce s n disq ues du piq ue t num ro 1
sur le piq ue t num ro 3, e n re s pe ctant les contrainte s s uivante s :
- on ne dplace q u'un s e uldisque la fois (d'un piq ue t un autre ),
- un disq ue ne doit jam ais tre plac au-de s s us d'un disq ue plus petit q ue lui.
O n te s te ra ce tte fonction ave c un program m e principalpe rm e ttant de ch oisir, e n donn e , le nom bre totalde disques
dplace r (n).
Si vous n' te s pas fam iliaris ave c ce type de problm e , nous vous cons e illons de te nte r tout d'abord de le r s oudre
m anue llem e nt avant de ch e rch e r program m e r la fonction de m and e .

Exe m pl
e
combien de disques ? 4
dplacer un disque de 1 en 2

204

Exe rcice s e n langage C

dplacer
dplacer
dplacer
dplacer
dplacer
dplacer
dplacer
dplacer
dplacer
dplacer
dplacer
dplacer
dplacer
dplacer

un
un
un
un
un
un
un
un
un
un
un
un
un
un

disque
disque
disque
disque
disque
disque
disque
disque
disque
disque
disque
disque
disque
disque

de
de
de
de
de
de
de
de
de
de
de
de
de
de

1
2
1
3
3
1
1
2
2
3
2
1
1
2

en
en
en
en
en
en
en
en
en
en
en
en
en
en

3
3
2
1
2
2
3
3
1
1
3
2
3
3

________________________________________________________________________________________

ANALYSE
Pour n=1, la solution e s t vidente ;ilsuffit de dplace r l'uniq ue disque du piquet num ro 1 au piq ue t num ro 3.
D s q ue n e s t suprieur 1, on re m arq ue q u'il e s t n ce s s aire d'utiliser le piq ue t num ro 2 pour de s s tock age s
inte rm diaire s . O n pe ut considrer que le problm e consiste dplace r n disques du piquet num ro 1 ve rs le piq u e t
num ro 3, e n utilisant le piq u e t num ro 2 com m e piq u e t inte rm diaire . O n pe ut m ontre r q ue ce tte op ration s e
dcom pos e e n trois oprations plus sim ples :
- dplace r les n-1 disq ue s s up rie urs du piq ue t num ro 1 ve rs le piq ue t num ro 2 ;pe ndant ce tte ph as e , on pe ut
utiliser le piq ue t num ro 3 com m e piq ue t inte rm diaire ,
- dplace r les n-1 disq ues du piq ue t num ro 2 ve rs le piq ue t num ro 3 ;l e ncore , on pe ut utiliser le piq ue t num ro 1
com m e piq ue t inte rm diaire (le disque initialem e nt pr s e nt sur ce piq ue t tant plus grand q ue tous les disques
dplace r).
Ce la nous conduit la r alisation d'une fonction r cursive possdant com m e argum e nts :
- le nom bre de disques dplace r,
- le num ro du piq ue t "de dpart",
- le num ro du piq ue t "d'arriv e ",
- le num ro du piq ue t "inte rm diaire ".

VI. R cursivit

Program m e
#include <stdio.h>
main()
{
void hanoi (int, int, int, int) ;
int nd
;
/* nombre total de disques */
printf ("combien de disques ? ") ;
scanf ("%d", &nd) ;
hanoi (nd, 1, 3, 2) ;
}
/***********************************************/
/* fonction rsolvant le pb des tours de hanoi */
/***********************************************/
void hanoi (int n, int depart, int but, int inter)
/* n
: nombre de disques dplacer */
/* depart : tour d'o l'on part */
/* but
: tour o l'on arrive */
/* inter : tour intermdiaire */
{
if (n>0)
{ hanoi (n-1, depart, inter, but) ;
printf ("dplacer un disque de %d en %d\n", depart, but) ;
hanoi (n-1, inter, but, depart) ;
}
}

205

VII : TRA ITEM ENT D E


FICH IERS

Le s e xe rcices de ce ch apitre vous fournis s e nt des exe m ples classiques de traite m e nt de fich ie rs corre s pondant diff re nts
aspects :
- traite m e nt s q ue ntie l,
- acc s direct,
- fich ie rs de type te xte .

VII-1 Cr ation s q ue ntie l


l
e de fich ie r
________________________________________________________________________________________

Enonc
Ecrire un program m e de cration squentiel
l
e d'un fich ie r com portant, pour un ce rtain nom bre de pe rsonne s , les
inform ations suivante s , fournie s au clavie r :
- nom (au m axim um 20 caract re s ),
- ge ,
- nom bre d'enfants,
- ge de ch acun des diff re nts e nfants ;on ne dem ande ra (e t donc on n'e nre gistre ra) q ue l' ge des 15 pre m ie rs e nfants
(m ais le nom bre figurant dans le ch am p pr cdent pourra tre s up rie ur 15).
L'utilisate ur fournira un nom "vide" pour signaler q u'iln'a plus de personne s e nre gistre r.

208
Exe rcice s e n langage C
O n ne pr voira aucun contrle particulie r au nive au de la saisie des donnes

Exe m pl
e
donnez le nom du fichier crer : person
----- pour terminer la saisie, donnez un nom 'vide' --nom
: dubois
age
: 32
nombre enfants : 1
age enfant no 1 : 7
nom
age
nombre enfants

: dunoyer
: 29
: 0

nom
age
nombre enfants
age enfant no 1
age enfant no 2
age enfant no 3

:
:
:
:
:
:

nom

dutronc
45
3
21
18
17

-------- FIN CREATION FICHIER ---------________________________________________________________________________________________

ANALYSE
La structure de ch aq ue e nre gistre m e nt du fich ie r d coule de l' nonc . Ce pe ndant, e n ce q ui conce rne la m ani re de
re pr s e nte r le nom des personne s , nous devons dcide r de la pr s e nce ou de l'abs e nce du caract re de fin de ch a
ne (\0).
Ici, nous avons ch oisi, par facilit , d'introduire ce caract re , ce q ui im pliq ue q ue la zone corre s pondante s oit de longue ur
21.
Pour cr e r notre fich ie r, nous utiliserons les fonctions de nive au 2, c'e s t- -dire ici fope n e t fw rite . R appe lons q ue ce lles ci travaillent ave c un pointe ur sur une s tructure de type FILE (prdfini dans stdio.h ). La valeur de ce pointe ur nous e s t
fournie par fope n ;ce tte fonction re s titue un pointe ur nule n cas d'erreur d'ouve rture .
La cr ation du fich ie r consiste s im plem e nt r p te r les actions :

VII. Traite m e nt de fich ie rs


- lecture d'inform ations au clavie r,
- criture de ce s inform ations dans le fich ie r.
Ce tte r p tition doit tre inte rrom pue la re ncontre d'un nom vide.

Program m e
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LGNOM 20
#define NBENFMAX 15
#define LNOMFICH 20
main()
{ char nomfich [LNOMFICH+1] ;
FILE * sortie ;
struct { char nom [LGNOM+1] ;
int age ;
int nbenf ;
int agenf [NBENFMAX] ;
} bloc ;
int i ;

/* longueur maxi d'un nom */


/* nombre maxi d'enfants */
/* longueur maxi nom de fichier */

/* nom du fichier crer */


/* descripteur fichier (niveau 2) */
/* description d'un enregistrement */
/* du fichier */

/* ouverture fichier crer */


/* attention : mode d'ouverture w au lieu de wb dans certains cas */
printf ("donnez le nom du fichier crer : ") ;
gets (nomfich) ;
if ( (sortie = fopen (nomfich, "w")) == NULL )
{ printf ("***** erreur ouverture - abandon programme") ;
exit(-1) ;
}
/* cration du fichier partir d'informations */
/* fournies au clavier */
printf ("----- pour terminer la saisie, donnez un nom 'vide' ---\n") ;
do
{ printf ("nom
: ") ;
/* saisie nom */
gets (bloc.nom) ;
if ( strlen(bloc.nom) == 0) break ; /* sortie boucle si nom vide */
printf ("age
: ") ;
scanf ("%d", &bloc.age) ;
/* saisie age */

209

210

Exe rcice s e n langage C


printf ("nombre enfants : ") ;
scanf ("%d", &bloc.nbenf) ;
/* saisie nb enfants
for (i=0 ; i < bloc.nbenf && i < NBENFMAX ; i++)
{ printf ("age enfant no %d : ", i+1) ;
/* saisie age des
scanf ("%d", &bloc.agenf[i]) ;
/* diffrents enfants
}
getchar() ;
/* pour liminer \n
printf ("\n") ;
fwrite (&bloc, sizeof(bloc), 1, sortie) ;
/* criture fichier

*/
*/
*/
*/
*/

}
while (1) ;
/* fin cration */
fclose(sortie) ;
printf ("\n -------- FIN CREATION FICHIER ----------") ;
}

Com m e ntaire s
*Note z le "m ode d'ouve rture " w b :
w : ouve rture e n criture ;si le fich ie r n'e xiste pas, ile s t cr . S'ile xiste , son ancie n conte nu e s t pe rdu.
b : m ode dit "binaire " ou "non translat ".
En fait, l'indication b ne s e justifie q ue dans les im plm e ntations q ui distingue nt les fich ie rs de te xte des autre s . Une te lle
distinction e s t m otiv e par le fait q ue le caract re de fin de ligne (\n) poss de, sur certains syst m e s , une re pr s e ntation
particuli re obte nue par la succe s s ion de deux caract re s . La pr s e nce de b vite le ris q ue q ue le fich ie r conce rn s oit
considr com m e un fich ie r de type te xte , ce q ui am ne rait une inte rpr tation non souh ait e d e s couples de caract re s
re pr s e ntant une fin de ligne .
*Ici, nous avons fait appe l la fonction e xit (son prototype figure dans stdlib.h ) pour inte rrom pre le program m e e n cas
d'erreur d'ouve rture du fich ie r. Ils'agit l d'un ch oix arbitraire . Nous aurions pu de m ande r l'utilisate ur de propos e r un
autre nom de fich ie r.
*En ce q ui conce rne la boucle de cr ation du fich ie r, nous avons ch oisi de la program m e r sous form e d'une boucle
infinie :
do
.......
.......

VII. Traite m e nt de fich ie rs

211

while (1) ;

q ue nous inte rrom pons au m om e nt opportun par bre ak . Nous aurions pu galem e nt ch oisir d'introduire les pre m i re s
instructions de la boucle dans l'e xpre s s ion conditionnant une instruction w h ile, de ce tte m ani re :
while (printf("nom

: "), gets(bloc.nom), strlen(bloc.mot) )

*Com m e pr vu par l' nonc , aucun contrle particulie r n'e s t e ffe ctu s ur les donnes qui sont donc lue s par scanf e t
ge ts. L e ncore s e pos e le problm e d'ignore r le \n q ui subsiste apr s une lecture par scanf, ce q ui im pose d'introduire
artificie llem e nt une instruction ge tch ar (pour plus de dtails sur ce problm e , voye z les com m e ntaires de l'e xe rcice V-3).
*R appe lons q ue la fonction d' criture dans le fich ie r (fw rite ) poss de 4 argum e nts :
- L'adresse de dbut d'un e ns e m ble de blocs crire (note z bie n la notation & bloc e t non sim plem e nt bloc, dans la
m e s ure o le nom d'une s tructure dsigne sa valeur e t non son adre s s e , com m e ce la e s t le cas pour un tableau).
- La taille d'un bloc. Note z q u'ici nous avons utilis la fonction size of, ce q ui assure la portabilit du program m e .
- Le nom bre de blocs de ce tte taille crire (ici, 1).
- L'adresse de la structure dcrivant le fich ie r (e lle a t fournie par fope n).

D ISCUSSIO N
*Ce program m e n'e xam ine pas le code de re tour de fw rite , leq ue lpr cis e le nom bre de blocs r e llem e nt crits dans le
fich ie r (ce nom bre tant inf rie ur au nom bre s ouh ait e n cas d'erreur d'criture ). Ilfaut toute fois note r, ce propos, q ue ,
g n ralem e nt, un ce rtain nom bre d'erreurs sont "r cup r e s " par le syst m e q ui affich e alors lui-m m e s on propre
m e s s age .
*Com m e le pr voyait l' nonc , ce program m e n'e s t pas prot g d've ntue lles e rre urs dans les r pons e s fournie s par
l'utilisate ur. A titre indicatif, voici q ue lque s s ituations q ue l'on pe ut re ncontre r :
- Si l'utilisate ur fournit un nom de fich ie r de plus de 20 caract re s , ily aura cras e m e nt d'inform ations e n m m oire .
Ici, ils e rait toute fois as s e z facile de re m dier ce problm e e n attribuant au sym bole LNO M FICH une valeur
suprieure au nom bre de caract re s q ue l'on pe ut frappe r au clavie r dans l'im plm e ntation conce rn e . O n pourrait
galem e nt lire un nom bre de caract re s lim it s e n utilisant, au lie u de ge ts (nom fich ), l'instruction :
fgets (nomfich, LNOMFICH, stdin) ;

Note z toute fois q ue , dans ce cas, les caract re s s upplm e ntaire s frapp s ve ntue llem e nt par l'utilisate ur sur la m m e
"ligne " s e raie nt pris e n com pte par une proch aine instruction de lecture s ur l'e ntr e s tandard.

212
Exe rcice s e n langage C
D ans ce rtaine s im plm e ntations (notam m e nt Turbo/Borland C e t C/Quick C M icrosoft), ile s t possible de r gler
com plte m e nt le problm e e n utilisant l'instruction cge ts q ui a le m rite de lim ite r, non s e ulem e nt le nom bre de
caract re s pris e n com pte , m ais galem e nt ce ux e ffe ctive m e nt frapp s au clavie r.
- Si l'utilisate ur fournit plus de caract re s q ue n'e n atte nd scanf, ce ux-ci s e ront utiliss (ave c plus ou m oins de
bonh e ur) par une lecture s uivante . L e ncore , le problm e ne pe ut tre conve nablem e nt r gl q ue d'une faon
dpendant de l'im plm e ntation, par e xe m ple ave c la fonction cge ts (associ e , ce tte fois, sscanf) cit e
pr cdem m e nt.
- Si l'utilisate ur fournit des caract re s non num riq ue s l o scanf atte nd des ch iffre s , le r s ultat de la lecture s e ra
arbitraire ;le program m e ne s 'e n ape rce vra pas puisq u'ilne te s te pas le code de re tour de scanf (q ui fournit le nom bre
de valeurs e ffe ctive m e nt lue s ). De plus, l e ncore , les caract re s non trait s s e ront re pris par une lecture ult rie ure .
Le pre m ie r point pe ut, l e ncore , tre r s olu par l'e m ploi de sscanf, associ fge ts (..., stdin). L e ncore , dans
ce rtaine s im plm e ntations, cge ts (associ e sscanf) pe rm e t de r gler totalem e nt le problm e .

VII-2 Lis te s q ue ntie l


l
e d'un fich ie r
________________________________________________________________________________________

Enonc
R aliser un program m e pe rm e ttant d'affich e r succe s s ive m e nt ch acun de s e nre gistre m e nts d'un fich ie r analogue ce ux
cr s par le program m e pr cdent. Le program m e pr s e nte ra un s e ule nre gistre m e nt la fois, accom pagn d'un num ro
pr cisant son rang dans le fich ie r (on attribue ra le num ro 1 au pre m ie r e nre gistre m e nt) ;ilatte ndra q ue l'utilisate ur
frappe la touch e re turn avant de pas s e r l'e nre gistre m e nt suivant.
L'affich age des inform ations s e ra r alis par une fonction laq ue lle on transm e ttra e n argum e nt l'e nre gistre m e nt
affich e r e t son num ro. Le m od le m m e de la structure corre s pondante s e ra, q uant lui, d fini un nive au global.
Le program m e devra s'assure r de l'e xiste nce du fich ie r liste r.

Exe m pl
e
donnez le nom du fichier lister : person
enregistrement numro : 1
NOM
AGE
NOMBRE D'ENFANTS

: dubois
: 32
: 1

VII. Traite m e nt de fich ie rs


AGE ENFANT

213

enregistrement numro : 2
NOM
AGE
NOMBRE D'ENFANTS

: dunoyer
: 29
: 0

enregistrement numro : 3
NOM
AGE
NOMBRE D'ENFANTS
AGE ENFANT 1
AGE ENFANT 2
AGE ENFANT 3

:
:
:
:
:
:

dutronc
45
3
21
18
17

-------- FIN LISTE FICHIER ---------________________________________________________________________________________________

Program m e

#include <stdio.h>
#include <string.h>
#define LGNOM 20
#define NBENFMAX 15
#define LNOMFICH 20

/* longueur maxi d'un nom */


/* nombre maxi d'enfants */
/* longueur maxi nom de fichier */

struct enreg { char nom [LGNOM+1] ;


int age ;
int nbenf ;
int agenf [NBENFMAX] ;
} ;

214

Exe rcice s e n langage C

main()
{
void affiche (struct enreg *, int) ;
char nomfich [LNOMFICH+1] ;
FILE * entree ;
struct enreg bloc ;
int num ;

/*
/*
/*
/*
/*

fonction d'affichage */
nom du fichier lister */
descripteur fichier (niveau 2) */
enregistrement fichier */
numro d'enregistrement */

/* ouverture fichier lister */


/* attention : mode d'ouverture : r au lieu de rb dans certains cas */
do
{ printf ("donnez le nom du fichier lister : ") ;
gets (nomfich) ;
if ( (entree = fopen (nomfich, "rb")) == 0 )
printf ("fichier non trouv\n") ;
}
while (!entree) ;
/* liste du fichier */
num = 1 ;
while (fread(&bloc, sizeof(bloc), 1, entree), ! feof(entree) )
{ affiche (&bloc, num++) ;
getchar() ;
/* attente frappe "return" */
}
/* fin liste */
fclose(entree) ;
printf ("\n\n -------- FIN LISTE FICHIER ----------") ;
}
/*************************************************/
/*
fonction d'affichage d'un enregistrement
*/
/*************************************************/
void affiche (struct enreg * bloc, int num)
{
int i ;
printf ("\n\nenregistrement numro : %d\n\n", num) ;
printf ("NOM
: %s\n", bloc->nom) ;
printf ("AGE
: %d\n", bloc->age) ;
printf ("NOMBRE D'ENFANTS
: %d\n", bloc->nbenf) ;
for (i=0 ; i < bloc->nbenf && i < NBENFMAX ; i++)

VII. Traite m e nt de fich ie rs


printf ("AGE ENFANT %2d

215

: %2d\n", i+1, bloc->agenf[i]) ;

Com m e ntaire s
*Note z le m ode d'ouve rture rb :
r : ouve rture e n lecture . Si le fich ie r n'e xiste pas, fope n fournit un pointe ur nul.
b : ouve rture e n m ode "binaire " ou "non translat " (pour plus d'inform ations sur la diff re nce e ntre les m ode s
translat e t non translat , voye z les com m e ntaires de l'e xe rcice VII-1).
*R appe lons q ue la fonction de lecture fre ad poss de 4 argum e nts, com parables ce ux de fw rite :
- l'adresse de dbut d'un e ns e m ble de blocs lire ,
- la taille d'un bloc (e n octe ts),
- le nom bre de blocs de ce tte taille lire ,
- l'adresse de la structure dcrivant le fich ie r (e lle a t fournie par fope n).
*La fonction fe of pre nd la valeur vrai (1) lors q ue la fin de fich ie r a t e ffe ctive m e nt re ncontr e . Autre m e nt dit, ilne
suffit pas, pour d te cte r la fin d'un fich ie r, d'avoir sim plem e nt lu son dernier octe t ;ile s t, de plus, n ce s s aire d'avoir
te nt de lire au-de l. C'e s t ce q ui justifie q ue ce tte condition soit e xam in e apr s fre ad e t non avant.
*Voye z la faon dont nous avons program m la boucle de lecture des diff re nts e nre gistre m e nts du fich ie r. Ce la nous
vite une s ortie e n cours de boucle par bre ak , com m e dans :
do
{ fread (&bloc, sizeof(bloc), 1, entree) ;
if (feof(entree)) break ;
affiche (&bloc, num++) ;
getchar() ;
}
while (1) ;

ou un te s t supplm e ntaire dans la boucle com m e dans :

216

Exe rcice s e n langage C


do
{ fread (&bloc, sizeof(bloc), 1, entree) ;
if (!feof(entree))
{ affiche (&bloc, num++) ;
getchar ;
}
}
while (!feof(entree)) ;

D ISCUSSIO N
*Ce program m e n'e xam ine pas le code de re tour de fre ad (ce lui-ci pr cis e le nom bre de blocs r e llem e nt lus).
*Notre program m e n'e s t pas prot g contre la fourniture par l'utilisate ur d'un nom de fich ie r de plus de 20 caract re s .
Voye z la discussion de l'e xe rcice pr cdent.
*Le passage l'e nre gistre m e nt suivant e s t dclench par la frappe de re turn. M ais si l'utilisate ur frappe un ou plusieurs
caract re s (valids par re turn), ilve rra d filer plusieurs enregistre m e nts de suite . La solution ce problm e dpe nd, ici
e ncore , de l'im plm e ntation. Par e xe m ple, dans un environne m e nt D O S, ave c Turbo/Borland C/C+ + ou Quick C/C
M icrosoft, ilsuffira de "vider le tam pon du syst m e " par :
while (kbhit()) getch ;

avant ch aq ue atte nte .

VII-3 Corre ction de fich ie r


________________________________________________________________________________________

Enonc
R aliser un program m e pe rm e ttant d'effe ctue r de s corre ctions sur un fich ie r analogue ce ux cr s par le program m e de
l'e xe rcice VII-1.

VII. Traite m e nt de fich ie rs

217

L'utilisate ur d s igne ra un e nre gistre m e nt par son num ro d'ordre dans le fich ie r. Le program m e s 'assure ra de s on
e xiste nce e t l'affich e ra d'abord te lq ue lavant de dem ande r les m odifications lui apporte r. Ces derni re s s e ront
e ffe ctu e s ch am p par ch am p. Pour ch aq ue ch am p, le program m e e n affich e ra nouve au la valeur, puis ildem ande ra
l'utilisate ur d'e ntre r une ve ntue lle valeur de re m place m e nt. Si aucune m odification n'e s t souh ait e , ilsuffira ce
dernie r de r pondre directe m e nt par la frappe de re turn.
O n pr voira de ux fonctions :
- une pour l'affich age d'un enregistre m e nt (on pourra re pre ndre la fonction affich e de l'e xe rcice pr cdent),
- une pour la m odification d'un e nre gistre m e nt.

Exe m pl
e
donnez le nom du fichier modifier : person
numro enregistrement modifier (0 pour fin) : 14
numro enregistrement modifier (0 pour fin) : 2

enregistrement numro : 2
NOM
AGE
NOMBRE D'ENFANTS

: dunoyer
: 29
: 0

entrez vos nouvelles infos (return si pas de modifs)


NOM
: Dunoyer
AGE
:
NOMBRE D'ENFANTS : 1
AGE ENFANT 1
: 15
numro enregistrement modifier (0 pour fin) : 0

-------- FIN MODIFICATIONS FICHIER ---------________________________________________________________________________________________

218

Exe rcice s e n langage C

ANALYSE
A partir du m om e nt o l'on souh aite re trouve r un e nre gistre m e nt par son rang dans le fich ie r, ilpara
t logiq ue de r aliser
un "acc s direct". R appe lons q u'e n langage C ce lui-ci s'obtie nt e n agissant sur la valeur d'un pointe ur dans le fich ie r
l'aide de la fonction fs e e k . La lecture e t l' criture , q uant e lles , re s te nt toujours r alises par les fonctions fre ad e t
fw rite .
L' nonc ne nous im pos e pas de contrle s ur l'inform ation lue au clavie r. N anm oins, nous devons tre e n m e s ure
d'acce pte r e t de re conna
tre com m e te lle une "r pons e vide". D ans ce s conditions, nous ne pouvons pas em ploye r scanf
q ui ris q ue rait de conduire un bouclage s ur le caract re \n.
Une s olution un te lproblm e consiste lire tout d'abord la r ponse de l'utilisate ur sous form e d'une ch a
ne , ce q ui
pe rm e t de dce ler conve nablem e nt les r pons e s vides. Si l'on souh aite une s olution d pe ndante de l'im plm e ntation, ce la
pe ut s e faire s oit ave c ge ts, soit (si l'on souh aite lim ite r le nom bre de caract re s pris e n com pte ) ave c fge ts (..., stdin).Ici,
nous utiliserons la pre m i re possibilit , e n faisant appe l une zone de 128 caract re s (dans bon nom bre
d'im plm e ntations, on ne pe ut pas frappe r au clavie r de "ligne s " plus longue s !).
Lors q u'une inform ation num riq ue e s t atte ndue , ilnous suffit alors de "dcode r" le conte nu de ce tte ch a
ne . Ce la pe ut s e
faire , soit ave c la fonction sscanf assortie (ici) d'un form at %d, soit ave c la fonction standard atoi. Par souci de dive rsit ,
nous avons ch oisi ici la s e conde .

Program m e

#include <stdio.h>
#include <string.h>
#define
#define
#define
#define
#define

VRAI 1
FAUX 0
LGNOM 20
NBENFMAX 15
LNOMFICH 20

/*
/*
/*
/*
/*

pour simuler .....


*/
..... des boolens */
longueur maxi d'un nom */
nombre maxi d'enfants */
longueur maxi nom de fichier */

struct enreg { char nom [LGNOM+1] ;


int age ;
int nbenf ;
int agenf [NBENFMAX] ;
} ;
main()
{

VII. Traite m e nt de fich ie rs


void affiche (struct enreg *, int) ;
void modifie (struct enreg *) ;
char nomfich [LNOMFICH+1] ;
FILE * fichier ;
struct enreg bloc ;
int num,
horsfich ;
long nb_enreg,
pos ;

/*
/*
/*
/*
/*
/*
/*
/*
/*

fonction d'affichage */
fonction de modif d'un enreg */
nom du fichier lister */
descripteur fichier (niveau 2) */
enregistrement fichier */
numro d'enregistrement */
indicateur "logique" */
nbre d'enregistrements du fichier */
position courante (octets) dans fich */

/* ouverture (en mise jour) fichier modifier et calcul de sa taille */


/* attention, mode d'ouverture r+ au lieu de r+b dans certains cas */
do
{ printf ("donnez le nom du fichier modifier : ") ;
gets (nomfich) ;
if ( (fichier = fopen (nomfich, "r+b")) == 0 )
printf ("fichier non trouv\n") ;
}
while (! fichier) ;
fseek (fichier, 0, 2) ;
nb_enreg = ftell (fichier) / sizeof(bloc) ;
/* boucle de corrections d'enregistrements */
/* jusqu' demande d'arrt */
do
{ do
{ printf ("\nnumro enregistrement modifier (0 pour fin) : ");
scanf ("%d", &num) ;
getchar() ;
/* pour sauter le dernier \n" */
horsfich = num < 0 || num > nb_enreg ;
}
while (horsfich) ;
if (num == 0 ) break ;
/* sortie boucle si demande arrt
pos = (num-1) * sizeof(bloc) ;
/* calcul position courante
fseek (fichier, pos, 0) ;
/* positionnement fichier
fread (&bloc, sizeof(bloc), 1, fichier) ;
/* lecture enreg
affiche (&bloc, num) ;
/* affichage enreg
modifie (&bloc) ;
/* modif enreg
fseek (fichier, pos, 0) ;
/* repositionnement fichier
fwrite (&bloc, sizeof(bloc), 1, fichier) ;
/* rcriture enreg

*/
*/
*/
*/
*/
*/
*/
*/

219

220

Exe rcice s e n langage C


}
while (1) ;

/* fin modifications */
fclose(fichier) ;
printf ("\n\n -------- FIN MODIFICATIONS FICHIER ----------\n") ;
}
/*************************************************/
/*
fonction d'affichage d'un enregistrement
*/
/*************************************************/
void affiche (struct enreg * bloc, int num)
{
int i ;
printf ("\n\nenregistrement numro : %d\n\n", num) ;
printf ("NOM
: %s\n", bloc->nom) ;
printf ("AGE
: %d\n", bloc->age) ;
printf ("NOMBRE D'ENFANTS
: %d\n", bloc->nbenf) ;
for (i=0 ; i < bloc->nbenf && i < NBENFMAX ; i++)
printf ("AGE ENFANT %2d
: %2d\n", i+1, bloc->agenf[i]) ;
}
/***************************************************/
/*
fonction de modification d'un enregistrement */
/***************************************************/
void modifie (struct enreg * bloc)
{
char ligne[127] ;
/* chane de lecture d'une ligne d'cran */
int i ;
printf ("\n\n\entrez vos nouvelles infos (return si pas de modifs)\n") ;
printf ("NOM
: ") ;
gets (ligne) ;
if (strlen(ligne)) strcpy (bloc->nom, ligne) ;
printf ("AGE
: ") ;
gets (ligne) ;
if (strlen(ligne)) bloc->age = atoi(ligne) ;
printf ("NOMBRE D'ENFANTS

: ") ;

VII. Traite m e nt de fich ie rs

221

gets (ligne) ;
if (strlen(ligne)) bloc->nbenf = atoi(ligne) ;
for (i=0 ; i < bloc->nbenf && i < NBENFMAX ; i++)
{ printf ("AGE ENFANT %2d
: ", i+1) ;
gets (ligne) ;
if (strlen(ligne)) bloc->agenf[i] = atoi(ligne) ;
}
}

Com m e ntaire s
*Nous avons ouve rt le fich ie r dans le m ode r+ b, leq ue lautoris e la m ise jour (lecture e t criture e n un e m place m e nt
q ue lconq ue du fich ie r). Note z q u'ilfaut vite r d' crire ici rb+ , ce q ui ne provoq ue rait g n ralem e nt pas d'erreur
d'ouve rture , m ais q ui e m p ch e rait toute criture dans le fich ie r (ici, notre program m e ne s 'ape rce vrait pas de ce tte
anom alie puis q u'ilne te s te pas le code de re tour de fw rite ). En ce q ui conce rne l'indication b, rappe lons q ue ce lle-ci
n'e s t indispensable q ue dans les im plm e ntations q ui distingue nt les fich ie rs de type te xte des autre s . R e voye z
ve ntue llem e nt les com m e ntaires de l'e xe rcice VII.1.
*Apr s l'ouve rture du fich ie r, nous e n d te rm inons la taille (dans la variable nb_e nre g) l'aide des fonctions fs e e k e t
fte ll. Plus prcism e nt :
fseek (fichier, 0, 2)

nous place 0 octe t de la fin (code 2) du fich ie r e t :


ftell (fichier)

nous donne la position courante du pointe ur associ au fich ie r (q ui pointe ici sur la fin). Ilnous e s t alors facile de la
transform e r e n un nom bre d'enregistre m e nts, e n la divisant par la taille d'un enregistre m e nt.
*N'oublie z pas q u'apr s avoir lu un e nre gistre m e nt, ile s t n ce s s aire , avant de le r crire , de positionne r nouve au le
pointe ur dans le fich ie r.

D ISCUSSIO N

222
Exe rcice s e n langage C
*Com m e dans les pr cdents program m e s , nous n'avons pas introduit de prote ctions particuli re s vis- -vis des rponses
fournie s par l'utilisate ur (voye z les discussions des prcdents program m e s ). Toute fois, ici, la m ani re m m e dont nous
avons program m la saisie des corre ctions, iln'e xiste pas, ce nive au, de ris q ue de "plangage " cons cutif une
m auvais e r pons e puis q ue nous n'avons pas fait appe l scanf.

VII-4 Com ptage de l


e ttre s e t m ots d'un fich ie r te xte
________________________________________________________________________________________

Enonc
Ecrire un program m e q ui, partir d'un fich ie r te xte , dte rm ine :
- le nom bre de caract re s q u'ilcontie nt,
- le nom bre de ch acune des lettres de l'alph abet (on ne considrera que les m inuscules ),
- le nom bre de m ots,
- le nom bre de ligne s.
Le s fins de ligne s ne devront pas tre com ptabilises dans les caract re s . O n adm e ttra q ue deux m ots sont toujours
s par s par un ou plusieurs des caract re s s uivants :
- fin de ligne
- e s pace
- ponctuation : : . , ;?!
- pare nth s e s : ( )
- guillem e ts : "
- apostroph e : '
O n adm e ttra galem e nt, pour sim plifie r, q u'aucun m ot ne pe ut tre com m e nc s ur une ligne e t s e poursuivre s ur la
suivante .
Ile s t cons e ill de r aliser une fonction pe rm e ttant de dcide r si un caract re donn, transm is en argum e nt, e s t un de s
s parate urs m e ntionn s ci-de s s us. Elle re s titue ra la valeur 1 lors q ue le caract re e s t un s parate ur e t la valeur 0 dans le
cas contraire .

VII. Traite m e nt de fich ie rs

223

Exe m pl
e
donnez le nom du fichier examiner : b:letfic.c
votre fichier contient 87 lignes, 371 mots
et 3186 caractres dont :
69 fois la lettre a
6 fois la lettre b
74 fois la lettre c
36 fois la lettre d
163 fois la lettre e
........
110 fois la lettre t
63 fois la lettre u
7 fois la lettre v
3 fois la lettre w
6 fois la lettre x
0 fois la lettre y
1 fois la lettre z
et 1979 autres caractres
________________________________________________________________________________________

ANALYSE
Com m e nous avons dj e u l'occasion de le voir dans les e xe rcice s I-5 e t I-6, ce type de problm e pe ut tre r s olu d'au
m oins deux m ani re s :
- e n e ffe ctuant une r p tition du traite m e nt d'un caract re ,
- e n e ffe ctuant une r p tition du traite m e nt d'une ligne , lui-m m e constitu de la r p tition du traite m e nt de ch acun
des caract re s q u'e lle contie nt.
Toute fois, ici, nous avons faire un fich ie r dans leq ue lla longue ur m axim ale d'une ligne n'e s t pas connue a priori, ce
q ui re nd la s e conde m th ode difficile m e ttre e n oe uvre . Nous ch oisirons donc la pre m i re ;ch aq ue caract re du fich ie r
s e ra donc lu par fge tc.
R appe lons q ue ce rtaine s im plm e ntations distingue nt les fich ie rs de type te xte des autre s . Dans ce cas, une te lle
distinction n'e s t pas li e au conte nu m m e du fich ie r (e n fait, on pe ut toujours considrer qu'un fich ie r, q ue lq ue s oit son
conte nu, e s t form d'une suite d'octe ts, donc, finalem e nt, d'une s uite de caract re s ). Elle a sim plem e nt pour obje ctif de

224
Exe rcice s e n langage C
faire e n sorte q ue , pour le program m e , les "fins de ligne " apparais s e nt toujours m at rialises par un caract re uniq ue ,
savoir \n (alors q ue , pr cis m e nt, ce rtaine s im plm e ntations, DOS notam m e nt, re pr s e nte nt une fin de ligne par un
"coupe " de caract re s ). Lors q u'une te lle distinction e s t n ce s s aire , ile s t pr vu d'introduire l'indication t, au nive au du
m ode d'ouve rture du fich ie r (de m m e q u'on y introduisait l'indication b pour signaler q u'ilne s 'agissait pas d'un fich ie r
de type te xte ).
Bie n e nte ndu, ici, nous avons tout int r t profite r de ce tte possibilit , de m ani re nous facilite r la dte ction de s fins
de ligne e t, surtout, obte nir un program m e portable ( l'e xce ption, ve ntue llem e nt, de l'indication t).
Le s com ptage s e ffe ctue r au nive au de s caract re s (nom bre de caract re s , nom bre de ch acune des m inuscules ) pe uve nt
tre r aliss de faon nature lle, condition toute fois de ne pas com ptabiliser \n com m e un caract re (au contraire , sa
re ncontre , ilfaudra incr m e nte r le com pte ur de ligne s ).
En ce q ui conce rne les com ptages de m ots, nous procderons com m e dans le pre m ie r program m e de l'e xe rcice I-6 e n
e m ployant :
- une fonction pe rm e ttant de te s te r si un caract re e s t un s parate ur,
- un indicate ur logiq ue : m ot_e n_cours.

Program m e
#include <stdio.h>
#define LNOMFICH 20
#define VRAI 1
#define FAUX 0

/* longueur maximale d'un nom de fichier */


/* pour "simuler" des ..... */
/* ..... valeurs logiques */

main()
{
int sep (char) ;
/* fonction test "caractre sparateur?" */
char nomfich [LNOMFICH+1] ; /* nom du fichier examiner */
FILE * entree ;
char c ;
int compte [26],
numl,
ntot,
nautres,
nmots,
nlignes,
mot_en_cours,
i ;

/*
/*
/*
/*
/*
/*
/*
/*
/*

descripteur du fichier examiner */


caractre courant */
pour compter les diffrentes lettres */
rang lettre courante dans l'alphabet */
compteur nombre total de caractres */
compteur carac autres que minuscules */
compteur du nombre de mots */
compteur du nombre de lignes */
indicateur logique : mot trouv */

VII. Traite m e nt de fich ie rs


/* entre du nom de fichier examiner et ouverture */
/* attention, mode r au lieu de rt, dans certains cas */
do
{ printf ("donnez le nom du fichier examiner : ") ;
gets (nomfich) ;
if ( (entree = fopen (nomfich, "rt")) == NULL)
printf ("***** fichier non trouv\n") ;
}
while (entree == NULL) ;

/* initialisations */
for (i=0 ; i<26 ; i++)
compte[i] = 0 ;
ntot = 0 ; nautres = 0 ;
nmots = 0 ;
nlignes = 0 ;
mot_en_cours = FAUX ;
/* boucle d'examen de chacun des caractres du fichier */
while ( c = fgetc (entree), ! feof (entree) )
{
if (c == '\n') nlignes++ ;
/* comptages au niveau caractres */
else
{ ntot++ ;
numl = c -'a' ;
if (numl >= 0 && numl < 26) compte[numl]++ ;
else nautres++ ;
}
if (sep(c))
{ if (mot_en_cours)
{ nmots++ ;
mot_en_cours = FAUX ;
}
}
else mot_en_cours = VRAI ;

/* comptages au niveau mots */

}
/* affichage rsultats */
printf ("\nvotre fichier contient %d lignes, %d mots\n",
nlignes, nmots) ;

225

226

Exe rcice s e n langage C


printf ("et %d caractres dont :\n", ntot) ;
for (i=0 ; i<26 ; i++)
printf ("%d fois la lettre %c\n", compte[i], 'a'+i) ;
printf ("\net %d autres caractres\n", nautres) ;

}
/*********************************************************/
/*
fonction de test "caractre sparateur"
*/
/*********************************************************/
int sep (char c)
{
char sep[12] = {'\n',
' ',
',', ';', ':', '.', '?', '!',
'(', ')',
'"', '\'' } ;
int nsep=12,
i ;

/*
/*
/*
/*
/*
/*

fin de ligne */
espace */
ponctuation */
parenthses */
guillemets, apostr*/
nbre sparateurs */

i = 0 ;
while ( c!=sep[i] && i<nsep ) i++ ;
if (i == nsep) return (0) ;
else return (1) ;
}

Com m e ntaire s
Le fich ie r a t ouve rt e n m ode rt :
r : ouve rture e n lecture . Si le fich ie r n'e xiste pas, fope n fournit un pointe ur nul.
t : ouve rture e n m ode translat (voye z ce propos, le pre m ie r com m e ntaire de l'e xe rcice VII-1).
Note z q ue le ch oix du m ode translat n'e s t jam ais absolum e nt indispensable. Toute fois, com m e nous l'avons dit dans
l'analyse, ilnous facilite la dte ction de fin de ligne e t, de plus, ilre nd le program m e transportable (par e xe m ple s ous
UNIX, o une fin de ligne e s t re pr s e nt e par \n).

VII. Traite m e nt de fich ie rs

227

D ISCUSSIO N
Nous avons suppos (im plicite m e nt) q ue notre program m e traitait un v ritable fich ie r te xte , autre m e nt dit q ue ce dernie r
s e te rm inait par une fin de ligne . Si ce la n' tait pas le cas :
- la derni re ligne ne s e rait pas com ptabilise,
- le dernie r m ot ne s e rait pas com ptabilis, m oins d' tre s uivi d'au m oins un sparate ur.

VIII : ANALYSE
NUM ERIQUE

Ce ch apitre vous propose q ue lque s applications du langage C l'analyse num riq ue . Nous avons ch e rch y introduire
les te ch niq ues de program m ation q ui inte rvie nne nt fr q ue m m e nt dans ce dom aine . Citons, par e xe m ple :
- la re pr s e ntation e t les m anipulations de m atrice s ,
- la re pr s e ntation de nom bre s com plexe s ,
- la r alisation de m odules s usce ptibles de travailler ave c une fonction q ue lconq ue ou ave c des tableaux de dim e nsions
q ue lconq ue s .

VIII-1 Produit de m atrice s r e l


l
es
________________________________________________________________________________________

Enonc
Ecrire une fonction calculant le produit de deux m atrice s r e lles . O n supposera q ue le pre m ie r indice de ch aq ue tableau
re pr s e ntant une m atrice corre s pond une ligne .
O n pr voira e n argum e nts :
- les adresses des deux m atrice s m ultiplie r e t ce lle de la m atrice produit,
- le nom bre de ligne s e t le nom bre de colonnes de la pre m i re m atrice ,
- le nom bre de colonnes de la s e conde m atrice (son nom bre de ligne s tant obligatoire m e nt galau nom bre de
colonnes de la pre m i re ).
Un program m e principalpe rm e ttra de te s te r ce tte fonction.

230

Exe rcice s e n langage C

Exe m pl
e
MATRICE A
0
1
2
1
2
3
2
3
4
3
4
5
4
5
6

3
4
5
6
7

MATRICE B
0
1
2
1
2
3
2
3
4
3
4
5
PRODUIT A x B
14 20 26
20 30 40
26 40 54
32 50 68
38 60 82

ANALYSE
R appe lons q ue s i A est une m atrice n, p (n ligne s e t p colonne s ) e t si B e s t une m atrice p, q , la m atrice produit :
C=A x B
e s t une m atrice n, q d finie par :
c =
ij

Program m e
#define N 5
#define P 4
#define Q 3

a b
ik

kj

VIII. Analy s e num riq u e


main()
{
void prod_mat(double *, double *, double *, int, int, int) ;
double a[N][P], b[P][Q], c[N][Q] ;
int i, j ;
/* initialisation matrice a */
for (i=0 ; i<N ; i++)
for (j=0 ; j<P ; j++)
a[i][j] = i+j ;
/* initialisation matrice b */
for (i=0 ; i<P ; i++)
for (j=0 ; j<Q ; j++)
b[i][j] = i+ j ;
/* calcul produit a x b */
/* les "cast" (int *) sont facultatifs */
prod_mat ( (double *) a, (double *) b, (double *) c, N, P, Q) ;
/* affichage matrice a */
printf (" MATRICE A\n") ;
for (i=0 ; i<N ; i++)
{ for (j=0 ; j<P ; j++)
printf ("%4.0f", a[i][j]) ;
printf ("\n") ;
}
printf ("\n") ;
/* affichage matrice b */
printf (" MATRICE B\n") ;
for (i=0 ; i<P ; i++)
{ for (j=0 ; j<Q ; j++)
printf ("%4.0f", b[i][j]) ;
printf ("\n") ;
}
printf ("\n") ;
/* affichage produit */
printf (" PRODUIT A x B\n") ;
for (i=0 ; i<N ; i++)
{ for (j=0 ; j<Q ; j++)
printf ("%4.0f", c[i][j]) ;
printf ("\n") ;
}

231

232

Exe rcice s e n langage C

void prod_mat ( double * a, double * b, double * c,


int n, int p, int q)
{
int i, j, k ;
double s ;
double *aik, *bkj, *cij ;
cij = c ;
for (i=0 ; i<n ; i++)
for (j=0 ; j<q ; j++)
{ aik = a + i*p ;
bkj = b + j ;
s = 0 ;
for (k=0 ; k<p ; k++)
{ s += *aik * *bkj ;
aik++ ;
bkj += q ;
}
* (cij++) = s ;
}
}

Com m e ntaire s
*D ans la fonction prod_m at, nous n'avons pas pu utiliser le "form alism e " des tableaux pour les m atrice s a, b e t c car
ce lles -ci poss dent deux dim e nsions non connue s lors de la com pilation du program m e . R appe lons q u'un te lproblm e ne
s e pos e pas lors q u'ils'agit de tableaux une s e ule dim e nsion (car une notation te lle q ue t[i] a toujours un sens, quelle
q ue s oit la taille de t) ou lors q u'ils'agit d'un tableau plusieurs dim e nsions dont s e ule la pre m i re e s t inconnue (com pte
te nu de la m ani re dont les lm e nts d'un tableau sont rang s e n m m oire ).
D ans ce s conditions, nous som m e s oblig de faire appe lau form alism e des pointe urs pour re p re r un lm e nt q ue lconq ue
de nos m atrice s . Pour ce faire , nous transm e ttons la fonction prodm at l'adresse de dbut des trois m atrice s conce rn e s .
Note z q u'e n toute rigue ur (du m oins d'apr s la norm e ANSI), dans le program m e m ain, un sym bole te lq ue a e s t du type
(double [P]) * (c'e s t- -dire q u'ilre pr s e nte un pointe ur sur des blocs de P lm e nts de type double), e t non pas
sim plem e nt du type double*. Ildoit donc tre conve rti dans le type double *, ce tte conve rsion ne m odifiant pas, e n fait,
l'adre s s e corre s pondante (re voye z ve ntue llem e nt les com m e ntaires de l'e xe rcice V.5 de la pre m i re partie de ce t
ouvrage ). Ce tte conve rsion q ue lque pe u fictive pe ut soit tre m ise en place autom atiq ue m e nt par le com pilate ur, au vu du

VIII. Analy s e num riq u e

233

prototype , soit tre e xplicit e l'aide d'un op rate ur de "cast" ;ce tte derni re faon de faire a souve nt le m rite d'vite r
des m e s s ages d'ave rtissem e nt inte m pe s tifs ("w arnings").
*Note z q ue , dans la dfinition de la fonction prodm at, nous avons d te nir com pte de la m ani re dont le langage C range
e n m m oire les lm e nts d'un tableau deux dim e nsions (suivant ce q u'on nom m e abusive m e nt les "ligne s " du tableau,
c'e s t- -dire s uivant l'ordre obte nu e n faisant varie r e n pre m ie r le dernie r indice ). Plus prcism e nt :
- Le sym bole aik re pr s e nte un pointe ur courant sur les lm e nts a . Pour ch aq ue valeur de i, aik e s t initialis
ik

l'adresse du pre m ie r lm e nt de la ligne i de la m atrice a (a+i*p) e t ile s t incr m e nt d'une colonne , e n m m e te m ps


q ue l'indice k (d'o la pr s e nce de aik ++ dans la boucle e n k ).
- D e m m e , bk j re pr s e nte un pointe ur courant sur les lm e nts b . Pour ch aq ue valeur de j, bk j e s t initialis
kj

l'adresse du pre m ie r lm e nt de la colonne j de la m atrice b (b+j) e t ile s t incr m e nt d'une ligne e n m m e te m ps


q ue l'indice k (d'o la pr s e nce de bkj=bkj+q dans la boucle e n k ).
- Enfin, cij re pr s e nte un pointe ur courant sur les lm e nts c . Ile s t initialis l'adresse du pre m ie r lm e nt de la
ij

m atrice c. Ilprogresse de 1 ch aq ue tour de la boucle la plus inte rne e n j (note z q u'iln'e n aurait pas t ainsi si nous
avions inve rs les deux boucles e n i e t j).

D ISCUSSIO N
*O n a souve nt te ndance dire q u'une fonction com m e prod_m at travaille s ur de s m atrices de dim e nsions variables . En
fait, le te rm e e s t q ue lque pe u am bigu. Ainsi, dans notre e xe m ple, les m atrices dont on transm e t l'adre s s e e n argum e nt
prod_m at ont une taille bien dte rm ine dans le program m e principal. Iln'e n re s te pas m oins q ue :
- d'une part, la m m e fonction pe ut travailler sur des m atrices de tailles diff re nte s ,
- d'autre part, rie n n'e m p ch e rait q u'au s e in du program m e principal, les m atrice s a, b e t c voie nt leur taille dfinie
uniq ue m e nt lors de l'e x cution e t leurs e m place m e nts allous dynam iq ue m e nt.
*Au sein d'une fonction com m e prod_m at, ile s t possible d'em ploye r le form alism e des tableaux la place de ce lui de s
pointe urs e n faisant appe l un artifice . Ce lui-ci consiste cr e r, pour ch aq ue m atrice , un tableau de pointe urs conte nant
l'adresse de dbut de ch aq ue ligne . Ainsi, par e xe m ple, pour la m atrice a, on pourrait r s e rve r un tableau nom m ada
par :
double * * ada ;

Ils e rait re m pli de la m ani re s uivante :


for (i=1 ; i<n ; i++)
ada[i] = a + i*p ;

234

Exe rcice s e n langage C

D ans ce s conditions, e n e ffe t, la notation ada [i] [j] corre s pondrait (com pte te nu de l'associativit de gauch e droite de
l'op rate ur []) :
(ada [i]) [j]

c'e s t- -dire :
* (ada [i] + j)

Autre m e nt dit, ce tte notation ada [i] [j] dsignerait sim plem e nt la val
eur de l' lm e nt situ l'inte rs e ction de la ligne i e t
de la colonne j de la m atrice a.
O n note ra q ue pour q ue ce t artifice s oit utilisable au s e in d'une fonction com m e prod_m at, ce ns e travailler sur des
m atrices de taille q ue lconq ue , ile s t n ce s s aire q ue les e m place m e nts des tableaux de pointe urs te ls q ue ada soient allou s
dynam iq ue m e nt.

VIII-2 A rith m tiq ue com pl


e xe
________________________________________________________________________________________

Enonc
Ecrire deux fonctions calculant la som m e e t le produit de deux nom bre s com plexe s . Ces dernie rs s e ront re pr s e nt s par
une s tructure com portant deux lm e nts de type double, corre s pondant la partie r e lle e t la partie im aginaire .
Ch acune de ce s fonctions com porte ra trois argum e nts :
- l'adresse des deux nom bre s com plexe s (structure s ) conce rn s ,
- l'adresse du r s ultat (structure ).
Un program m e principalpe rm e ttra de te s te r ces deux fonctions ave c les valeurs com plexe s :
0,5 + i
1+ i

VIII. Analy s e num riq u e

235

Exe m pl
e
0.500000 + 1.000000 i
et
1.000000 + 1.000000 i
ont pour somme
1.500000 + 2.000000 i
et pour produit -0.500000 + 1.500000 i
________________________________________________________________________________________

ANALYSE
Soit deux nom bre s com plexe s :
x = a + ib
y = c + id
O n sait q ue :
x + y = (a+ c) + i (b+ d)
e t q ue :
x y = (ac - bd) + i (ad + bc)

Program m e
typedef struct
{ double reel ;
double imag ;
} complexe ;
main()
{
void somme (complexe *, complexe *, complexe *) ;
void produit (complexe *, complexe *, complexe *) ;
complexe z1, z2, s, p ;
z1.reel = 0.5 ; z1.imag = 1.0 ;
z2.reel = 1.0 ; z2.imag = 1.0 ;
somme
(&z1, &z2, &s) ;
produit (&z1 ,&z2, &p) ;
printf ("%lf + %lf i
et
%lf + %lf i \n",

236

Exe rcice s e n langage C


z1.reel, z1.imag, z2.reel, z2.imag) ;
printf ("ont pour somme
%lf + %lf i \n", s.reel, s.imag) ;
printf ("et pour produit %lf + %lf i \n", p.reel, p.imag) ;

}
void somme (complexe * x, complexe * y, complexe * som)
{
som->reel = x->reel + y->reel ;
som->imag = x->imag + y->imag ;
}
void produit (complexe * x, complexe * y, complexe * prod)
{
prod->reel = x->reel * y->reel - x->imag * y->imag ;
prod->imag = x->reel * y->imag + x->imag * y->reel ;
}

Com m e ntaire s
*Nous avons dfini, un nive au global, un m od le de structure nom m com plexe .
*Note z bie n q ue , dans le program m e principal, l'acc s une s tructure s e fait par l'op rate ur "." (com m e dans z1.re e l)
car z1 dsigne ici la val
eur d'une s tructure ;par contre , dans les fonctions, ils e fait par l'op rate ur -> (com m e dans x>re e l) car x d s igne alors l
'adresse d'une s tructure . O n pe ut toute fois vite r l'e m ploi de ce t op rate ur, e n re m arq uant
q ue x-> re e le s t q uivalent (*x).re e l.
*En toute rigue ur, d'apr s la norm e ANSI, ile s t possible de transm e ttre , e n argum e nt d'une fonction, la valeur d'une
structure . Aussi, aurions-nous pu pr voir q ue som m e e t produit re oive nt les valeurs des com plexe s s ur les q ue ls porte
l'op ration. En re vanch e , le r s ultat devrait toujours tre transm is par valeur puis q ue dte rm in par la fonction e llem m e . Par e xe m ple, la dfinition de som m e aurait pu tre :
void somme (complexe x, complexe y, complexe * som)
{
prod->reel = x.reel + y.reel ;
prod->imag = x.imag + y.imag ;
}

VIII. Analy s e num riq u e

237

D ISCUSSIO N
D ans la pratiq ue , les fonctions som m e e t produit s e raie nt com pile s s par m e nt des fonctions les utilisant. Pour ce faire ,
ile s t n ce s s aire q u'e lles disposent de la description de la structure com plexe . O n voit q u'on ris q ue alors d' tre am e n
dcrire une m m e s tructure diff re nte s re pris e s . Ce rte s , ici la ch os e n'e s t pas bien grave , dans la m e s ure o ce tte
dfinition e s t sim ple. D'une m ani re g n rale, toute fois, on a tout int r t r gler ce type de problm e e n plaant une fois
pour toute s une te lle dfinition dans un fich ie r (d'e xte nsion h , par e xe m ple) q u'on incorpore par #include dans tous les
program m e s e n ayant besoin.

VIII-3 Produit de m atrice s com pl


e xe s
________________________________________________________________________________________

Enonc
Ecrire une fonction calculant le produit de deux m atrice s com plexe s . Ch aq ue m atrice s e ra d finie com m e un tableau
deux dim e nsions dans leq ue lch aq ue lm e nt s e ra une s tructure re pr s e ntant un nom bre com plexe ;ce tte s tructure s e ra
constitue de deux lm e nts de type double corre s pondant la partie r e lle e t la partie im aginaire du nom bre . O n
supposera q ue le pre m ie r indice du tableau re pr s e ntant une m atrice corre s pond une ligne .
O n pr voira e n argum e nts :
- les adresses des deux m atrice s m ultiplie r,
- l'adresse de la m atrice produit,
- le nom bre de ligne s e t de colonnes de la pre m i re m atrice ,
- le nom bre de colonnes de la deuxi m e m atrice (son nom bre de ligne s tant obligatoire m e nt galau nom bre de
colonnes de la pre m i re ).
O n r alisera un program m e principalpe rm e ttant de te s te r ce tte fonction.
O n pourra ve ntue llem e nt faire appe laux fonctions som m e e t produit r alises dans l'e xe rcice VIII-2 pour calculer la
som m e e t le produit de deux nom bre s com plexe s .

Exe m pl
e
MATRICE A
0+
0i

1+

2i

2+

4i

3+

6i

238

Exe rcice s e n langage C


1+
2+
3+
4+

1i
2i
3i
4i

2+
3+
4+
5+

3i
4i
5i
6i

3+
4+
5+
6+

5i
6i
7i
8i

MATRICE B
0+
0i
1+
1i
2+
2i
3+
3i

1+
2+
3+
4+

2i
3i
4i
5i

2+
3+
4+
5+

4i
5i
6i
7i

PRODUIT A x B
-14+ 42i
-32+ 66i
-14+ 54i
-36+ 90i
-14+ 66i
-40+ 114i
-14+ 78i
-44+ 138i
-14+ 90i
-48+ 162i

-50+
-58+
-66+
-74+
-82+

90i
126i
162i
198i
234i

4+
5+
6+
7+

7i
8i
9i
10i

________________________________________________________________________________________

ANALYSE
Le s form ules de dfinition du produit de m atrice s com plexe s re s te nt ce lles proposes dans l'analyse de l'e xe rcice VIII-1
pour les m atrice s r e lles ;ilsuffit d'y re m place r les op rations + e t x portant sur des rels par les op rations som m e e t
produit de deux com plexe s (les r gles de ces deux op rations ont t e xposes dans l'analyse de l'e xe rcice VIII-2).

Program m e

#define N 5
#define P 4
#define Q 3
typedef struct
{ double reel ;
double imag ;
} complexe ;

VIII. Analy s e num riq u e


main()
{
void prod_mat (complexe *, complexe *, complexe *, int, int, int) ;
complexe a[N][P], b[P][Q], c[N][Q] ;
int i, j ;

/* initialisation matrice a */
for (i=0 ; i<N ; i++)
for (j=0 ; j<P ; j++)
{ a[i][j].reel = i+j ;
a[i][j].imag = i+2*j ;
}
/* initialisation matrice b */
for (i=0 ; i<P ; i++)
for (j=0 ; j<Q ; j++)
{ b[i][j].reel = i+j ;
b[i][j].imag = i+2*j ;
}
/* calcul produit a x b */
/* les "cast" (complexe *) sont facultatifs */
prod_mat ((complexe *) &a, (complexe *) &b, (complexe *) &c, N, P, Q) ;
/* affichage matrice a */
printf (" MATRICE A\n") ;
for (i=0 ; i<N ; i++)
{ for (j=0 ; j<P ; j++)
printf ("%4.0lf+%4.0lfi
", a[i][j].reel, a[i][j].imag) ;
printf ("\n") ;
}
printf ("\n") ;
/* affichage matrice b */
printf (" MATRICE B\n") ;
for (i=0 ; i<P ; i++)
{ for (j=0 ; j<Q ; j++)
printf ("%4.0lf+%4.0lfi
", b[i][j].reel, b[i][j].imag) ;
printf ("\n") ;
}
printf ("\n") ;

239

240

Exe rcice s e n langage C


/* affichage produit */
printf (" PRODUIT A x B\n") ;
for (i=0 ; i<N ; i++)
{ for (j=0 ; j<Q ; j++)
printf ("%4.0lf+%4.0lfi
", c[i][j].reel, c[i][j].imag) ;
printf ("\n") ;
}

}
/*********************************************************/
/* fonction de calcul de produit de 2 matrices complexes */
/*********************************************************/
void prod_mat ( complexe * a, complexe * b, complexe * c,
int n, int p, int q)
{
void produit() ;
int i, j, k ;
complexe s, pr ;
complexe *aik, *bkj, *cij ;
cij = c ;
for (i=0 ; i<n ; i++)
for (j=0 ; j<q ; j++)
{ aik = a + i*p ;
bkj = b + j ;
s.reel = 0 ; s.imag = 0 ;
for (k=0 ; k<p ; k++)
{ produit (aik, bkj, &pr) ;
s.reel += pr.reel ; s.imag += pr.imag ;
aik++ ;
bkj += q ;
}
* (cij++) = s ;
}
}
void produit (x, y, prod)
complexe *x, *y, *prod ;
{
prod->reel = x->reel * y->reel - x->imag * y->imag ;
prod->imag = x->reel * y->imag + x->imag * y->reel ;
}

VIII. Analy s e num riq u e

241

Com m e ntaire s
La fonction prod_m at pe ut tre considre com m e une adaptation de la fonction prod_m at de l'e xe rcice VIII-1. Ce tte
fois, les sym boles aik , bk j e t cij dsignent, non plus des pointe urs sur de s r e ls, m ais des pointe urs sur une s tructure
re pr s e ntant un nom bre com plexe . La souplesse du langage C e n m ati re d'oprations arith m tiq ue s s ur les pointe urs fait
q ue les instructions d'incr m e ntation de ce s q uantit s re s te nt les m m e s (l'unit tant ici la structure com plexe - soit 2
lm e nts de type double, au lie u d'une valeur de type double).

D ISCUSSIO N
Le s re m arq ue s faites dans l'e xe rcice VIII-2, propos de la description de la structure com plexe re s te nt nature llem e nt
valables ici.

VIII-4 Re ch e rch e de z ro d'une fonction par dich otom ie


________________________________________________________________________________________

Enonc
Ecrire une fonction d te rm inant, par dich otom ie , le z ro d'une fonction q ue lconq ue (r e lle d'une variable r e lle e t
continue ). O n supposera connu un inte rvalle [a,b] sur leq ue lla fonction ch ange de signe, c'est- -dire te lq ue f(a).f(b) soit
n gatif.
O n pr voira e n argum e nts :
- les valeurs des bornes a e t b (de type double) de l'inte rvalle de dpart,
- l'adresse d'une fonction pe rm e ttant de calculer la valeur de f pour une valeur q ue lconq ue de la variable. O n
supposera q ue l'e n-t te de ce tte fonction e s t de la form e :
double fct (x)
double x ;

242

Exe rcice s e n langage C

- l'adresse d'une variable de type double destin e re cue illir la valeur approch e du z ro de f,
- la valeur de la pr cision (absolue ) souh ait e (de type double).
Le code de re tour de la fonction s e ra de -1 lors q ue l'inte rvalle fourni e n argum e nt ne convie nt pas, c'e s t- -dire :
- soit lors q ue la condition a<b n'est pas satisfaite ,
- soit lors q ue la condition f(a).f(b)< 0 n'e s t pas satisfaite .
D ans le cas contraire , le code de re tour s e ra gal 0.
Un program m e principalpe rm e ttra de te s te r ce tte fonction.

Exe m pl
e
zro de la fonction sin entre -1 et 1 1e-2 prs = 0.000000e+000
zro de la fonction sin entre -1 et 2 1e-2 prs = 1.953125e-003
zro de la fonction sin entre -1 et 2 1e-12 prs = -2.273737e-013
________________________________________________________________________________________

ANALYSE
La dm arch e consiste donc, apr s avoir v rifi q ue l'inte rvalle re u e n argum e nt tait conve nable, r p te r le traite m e nt
suivant :
- pre ndre le m ilie u m de [a,b] : m = (a+ b)/2
- calculer f(m ),
- si f(m ) = 0, le z ro e s t e n m ,
- si f(a).f(m )< 0, ile xiste un z ro sur [a,m ] ;on re m place donc l'inte rvalle [a,b] par [a,m ] e n faisant :
b=m
- si f(a).f(m )> 0, ile xiste un z ro sur [b,m ] ;on re m place donc l'inte rvalle [a,b] par [b,m ], e n faisant :
a=m
Le traite m e nt e s t inte rrom pu soit lors q ue l'inte rvalle [a,b] aura t s uffisam m e nt rduit, c'e s t- -dire lors q ue |b-a| est
inf rie ur la pr cision souh ait e , soit lors q ue le z ro a t localis exacte m e nt (f(m )=0).

VIII. Analy s e num riq u e

Program m e
#include <stdio.h>
#include <math.h>
/* pour la fonction sin */
main()
{
/* fonction de recherche d'un zro par dichotomie */
int dichoto ( double (*(double)(), double, double, double *, double) ;
double z,
/* zro recherch */
a, b,
/* bornes de l'intervalle de recherche */
eps ;
/* prcision souhaite */
dichoto (sin, -1.0, 1.0, &z, 1.0e-2) ;
printf ("zro de la fonction sin entre -1 et 1 1e-2 prs = %le\n",z);
dichoto (sin, -1.0, 2.0, &z, 1.0e-2) ;
printf ("zro de la fonction sin entre -1 et 2 1e-2 prs = %le\n",z);
dichoto (sin, -1.0, 2.0, &z, 1.0e-12) ;
printf ("zro de la fonction sin entre -1 et 2 1e-12 prs = %le\n",z);
}
/*************************************************************/
/* fonction de recherhce dichotomique du zro d'une fonction */
/*************************************************************/
int dichoto ( double (* f)(double), double a, double b, double * zero, double eps)
/*
/*
/*
/*

f : fonction dont on cherche le zro */


a, b : bornes de l'intervalle de recherche */
zero : zro estim */
eps : prcision souhaite) */

{
double m,
fm,
fa, fb ;

/* milieu de l'intervalle courant */


/* valeur de f(m) */
/* valeurs de f(a) et de f(b) */

fa = (*f)(a) ;
fb = (*f)(b) ;
if (fa*fb >= 0 || a >= b) return (-1) ;

while (b-a > eps)


{ m = (b+a) / 2.0 ;

/* intervalle incorrect */

243

244

Exe rcice s e n langage C


fm = (*f)(m) ;
if (fm == 0) break ;
if (fa*fm < 0) { b
fb
}
else
{ a
fa
}

/* zro atteint */
= m ;
= fm ;
= m ;
= fm ;

}
* zero = m ;
return (0) ;
}

Com m e ntaire s
*Note z, dans la fonction dich oto :
- la dclaration de l'argum e nt corre s pondant l'adresse de la fonction dont on ch e rch e le z ro :
double (*f)(double)
Ce lle-ci s'inte rpr te com m e s uit :
(*f) e s t une fonction re ce vant un argum e nt de type double e t fournissant un r s ultat de type double,
*f e s t donc une fonction re ce vant un argum e nt de type double e t fournissant un r s ultat de type double,
f e s t donc un pointe ur sur une fonction re ce vant un argum e nt de type double e t fournissant un r s ultat de type
double.
- l'utilisation du sym bole f ;ainsi (*f)(a) re pr s e nte la valeur de la fonction (*f) (fonction d'adre s s e f), laq ue lle on
fournit l'argum e nt a.
Le s m m e s r flexions s'appliq ue nt au prototype s e rvant dclare r dich oto.
*La fonction dich oto re ce vant e n argum e nt les val
eurs des argum e nts a e t b (et non de s adresses), nous pouvons nous
pe rm e ttre de les m odifie r au s e in de la fonction, sans q ue ce la ait d'incide nce s ur les valeurs e ffe ctives des borne s
dfinies dans le program m e principal.
*Voye z com m e nt, dans le program m e principal, un sym bole com m e sin e s t inte rpr t par le com pilate ur com m e
l'adresse d'une fonction prdfinie ;ile s t toute fois nce s s aire d'avoir incorpor s on prototype (situ dans m ath .h ) ;e n

VIII. Analy s e num riq u e

245

l'abs e nce de l'instruction #include corre s pondante , le com pilate ur d te cte rait un e rre ur puis q ue alors le sym bole sin ne
s e rait pas dfini.

D ISCUSSIO N
En th orie , la m th ode de dich otom ie conduit toujours une s olution, ave c une pr cision aussi grande q u'on le dsire ,
partir du m om e nt o la fonction ch ange e ffe ctive m e nt de signe sur l'inte rvalle de dpart. En pratiq ue , toute fois, les
ch os e s ne s ont pas toujours aussi idylliq ue s , com pte te nu de la lim itation de la pr cision des calculs.
Tout d'abord, si on im pos e une pr cision trop faible par rapport la pr cision de l'ordinate ur, on pe ut aboutir ce q ue :
m = (a+b)/2

soit gal l'une des deux bornes a ou b. Ile s t alors facile de m ontre r q ue l'algorith m e pe ut boucler ind finim e nt.
D 'autre part, les valeurs de f(a) e t de f(b) sont n ce s s aire m e nt valu e s d e m ani re approch e . Dans le cas de form ules
q ue lque pe u com plexe s , on pe ut tr s bien aboutir une s ituation dans laq ue lle f(a).f(b) e s t positif.
La pre m i re s ituation e s t as s e z facile vite r : ilsuffit de ch oisir une pr cision re lative (atte ntion, ici, notre fonction
travaille ave c une pr cision absolue ) inf rie ure ce lle de l'ordinate ur. Iln'e n va pas de m m e pour la s e conde dans la
m e s ure o iln'e s t pas toujours possible de m a
tris e r la pr cision des calculs des valeurs de f.

Vous aimerez peut-être aussi