Anda di halaman 1dari 25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

Tableaux (corrig)
Table des matires
1 Utilitaires
1.1 Affichage dun tableau (*) . . . . . . .
1.2 Mise zro dun tableau (*) . . . . . .
1.3 Remplissage dun tableau alatoire (*)
1.4 Remplissage dun tableau alatoire tri

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

2
2
2
3
3

2 Calcul sur les lments dun tableau


2.1 Somme des lments dun tableau (*) . . . . . . .
2.2 Moyenne des lments dun tableau (*) . . . . . . .
2.3 Rsistance quivalente (**) . . . . . . . . . . . . .
2.4 Recherche dlments sur critre (*) . . . . . . . .
2.5 Maximum dun tableau (*) . . . . . . . . . . . . .
2.6 Indice du maximum dun tableau (*) . . . . . . . .
2.7 Un tableau est-il tri ? (*) . . . . . . . . . . . . . .
2.8 Recherche squentielle dans un tableau tri (*) . .
2.9 Recherche dichotomique dans un tableau tri (**) .
2.10 Tests (*) . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.

3
3
4
4
5
6
6
7
7
8
8

3 Copie et dcalage de tableaux (**)


3.1 Copie simple de tableaux (*) . . . . . . .
3.2 Copie scurise de tableaux (**) . . . . .
3.3 Dcalage droite dun tableau de rels (*) .
3.4 Dcalage gauche dun tableau de rels (*)
4 Les
4.1
4.2
4.3
4.4
4.5
4.6
4.7
4.8

chanes de caractres
Rptition (*) . . . . . . . . . .
Retournement dune chane(*) .
Recherche de motif (1) (**) . .
Recherche de motif (2) (**) . .
Chercher/remplacer (*) . . . .
Frquence (1) (**) . . . . . . .
Frquence (2) (**) . . . . . . .
Conversion chane de caractres

5 Pour aller plus loin


5.1 Mise en majuscules (**) . . . .
5.2 Classement alphabtique (***)
5.3 Des chiffres en lettres (**) . . .
5.4 Des nombres en lettres (****) .
5.5 Compteur de mots (***) . . .
5.6 Les huit reines (***) . . . . . .

. .
. .
. .
(*)

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

9
9
9
11
11

. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
en entier (**)

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

12
12
12
12
13
13
14
14
15

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

15
15
17
17
18
23
24

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

Tous les exercices sont faire.


Sont rendre (par binme) :
le programme de lexercice 1.3
les programme des exercices 2.7, 2.8 et 2.9
les programme des exercices 3.3 et 3.4
les programmes des exercices 4.2 et 4.8
Les exercices sont envoyer ladresse jean-claude.georges@esiee.fr
- objet obligatoire : IGI-3005 CR TP3 nom1 nom2
- fonctions C commentes en pices jointes (pas de zip)

1/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

Note : sauf spcification contraire, dans tous les exercices, on considrera que les tableaux contiennent
au moins un lment.

Utilitaires

1.1

Affichage dun tableau (*)

Exercice 1. crivez la fonction qui affiche les n premiers lments dun tableau de rels.
Prototype : void affiche_tab(double t[], int n);
Corrig

***************************************************************************
void affiche(double t[], int n) {
int i;
for (i=0;i<n;++i) {
printf("%10.5lf ",t[i]);
}
printf("\n");
}

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

1.2

Mise zro dun tableau (*)

Exercice 2. crivez la fonction qui remplit un tableau de n rels par des zros ( 0.0 ).
Prototype : double * raz(double t[], int n);
Note : on retourne souvent pour une fonction oprant sur un tableau ladresse de ce tableau, ce qui
permet denchaner les appels dans une seule ligne. Par exemple :
affiche(raz(t, n), n);
Corrig

***************************************************************************
double * raz(double t[], int n) {
int i;
for (i=0;i<n;++i) {
t[i]=0.0;
}
return t;
}

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

2/25

ESIEE IGI-3005

1.3

TP no 3 (deux sances) (corrig)

2014-2015

Remplissage dun tableau alatoire (*)

Exercice 3. crivez la fonction qui remplit un tableau de n rels par des nombres pseudo-alatoires
compris entre 0 et 1
Prototype : double * remplit_alea (double t[], int n);
Note : on se documentera sur la fonction C rand() dclare dans stdlib.h .
Corrig

***************************************************************************
double * remplit_alea(double t[], int n) {
int i;
for (i=0;i<n;++i) {
t[i]=rand()/(double)RAND_MAX;
}
return t;
}

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

1.4

Remplissage dun tableau alatoire tri (*)

Exercice 4. crivez la fonction qui remplit un tableau de n rels par des nombres pseudo-alatoires
en ordre croissant.
Prototype : double * remplit_trie (double t[], int n);
Corrig

***************************************************************************
double * remplit_trie(double t[], int n) {
int i;
t[0]=rand()/(double)RAND_MAX;
for (i=1;i<n;++i) {
t[i]=t[i-1]+rand()/(double)RAND_MAX;
}
return t;
}

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

2
2.1

Calcul sur les lments dun tableau


Somme des lments dun tableau (*)

Exercice 5. crivez une la fonction qui calcule la somme des n premiers lments dun tableau
de rels
Prototype : double somme (double t[], int n);
Corrig

***************************************************************************
Le principe est de parcourir le tableau pour en calculer la somme : dans une boucle, on accumulera dans
une variable les valeurs des lments du tableau. Ce genre de boucle est appel schma daccumulation.
Lcriture mathmatique bi=a expr(i) scrira en C :
3/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

var=0.0;
for (i=a;i<=b;++i)
var += expr(i);

Le parcours squentiel dun tableau de n lments en langage C se fait par une boucle allant de lindice
0 lindice n-1 (inclus). Il vaut mieux crire la condition de rptition sous la forme i < n que sous la
forme i <= n-1 , ce qui permet dune part de gagner une soustraction par tour de boucle, et dautre part de
garder sous forme explicite le nombre dlments traiter dans lcriture du programme.
Ce qui donne la solution possible suivante :
double somme(double t[], int n) {
int i;
double total=0.0;
for (i = 0 ; i < n ; ++i) {
total += t[i];
}
return total;
}

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

2.2

Moyenne des lments dun tableau (*)

Exercice 6. crivez une la fonction qui calcule la moyenne des n premiers lments dun tableau
de rels
Prototype : double moyenne (double t[], int n);
Corrig

***************************************************************************
Il faut videmment utiliser la fonction de lexercice prcdent (rutilisation) :
double moyenne(double t[], int n) {
return somme(t,n)/n;
}

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

2.3

Rsistance quivalente (**)

Exercice 7. crivez une fonction qui calcule la rsistance quivalente dun nombre quelconque de
rsistances en parallle
n
X
1
1
Rappel :
=
Rq
Ri
i=1
Prototype : double resistance (double r[], int n);
Corrig

***************************************************************************
Cest un schma classique daccumulation (somme des inverses des lments du tableau), puis retour de
linverse de laccumulateur.
Un cueil viter est loubli du cas o un des lments est nul, ce qui conduirait une division par 0. La
solution consiste retourner directement 0 si lun des lments est nul.

4/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

double resistance (double r[], int n) {


double req=0.0;
int i;
for (i=0;i<n;++i) {
if (r[i]==0.0)
return 0.0;
req += 1/r[i];
}
return 1/req;
}

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

2.4

Recherche dlments sur critre (*)

Exercice 8. crivez la fonction qui retourne lindice du premier lment strictement ngatif parmi
les n premiers lments dun tableau de rels (-1 si aucun lment nest ngatif).
Prototype : int indice_premier_negatif (double t[], int n);
Corrig

***************************************************************************
Ici, lanalyse du problme nous conduit la solution suivante :
on parcourt le tableau
si lon rencontre un lment ngatif, on termine la fonction en retournant lindice courant
si lon a parcouru lintgralit du tableau sans avoir rencontr dlment ngatif, on retourne -1 comme
indiqu dans la spcification.
Attention : cest aprs la boucle que lon peut constater labsence dlment ngatif. Une erreur courante de
programmation consiste retourner -1 trop tt, avec un test du style
if (t[i]<0) return i; else return -1;

ce qui conduit retourner -1 si le premier un lment nest pas ngatif.


Cest toute la diffrence entre une recherche existentielle (i t[i] < 0) et une recherche universelle (i t[i]
0).

5/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

int indice_premier_negatif (double t[], int n) {


int i;
for (i=0; i<n ; ++i) {
if (t[i]<0)
return i;
}
return -1;
}

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

2.5

Maximum dun tableau (*)

Exercice 9. crivez la fonction qui retourne la valeur du plus grand des n premiers lments dun
tableau de rels
Prototype : double valeur_plus_grand (double t[], int n);
Corrig

***************************************************************************
Un parcours du tableau simpose, avec une mmorisation du plus grand lment rencontr. En effet, le
plus grand lment du tableau peut se situer nimporte o (en dbut, en cours ou en fin de tableau) et donc
on ne peut le connatre quaprs avoir examin tous les lments du tableau, et le mmoriser permettra de le
retourner en fin de parcours.
Linitialisation de ce maximum pourra se faire par le premier lment du tableau ( t[0] ), et la boucle peut
commencer par lindice 1.
Le corps de la boucle consistera comparer llment courant au maximum, et, sil lui est suprieur, le
mmoriser dans le maximum.
Ce qui conduit la solution suivante :
double valeur_plus_grand (double t[], int n) {
int i;
double maxi=t[0];
for (i=1;i<n;++i) {
if (t[i]>maxi)
maxi=t[i];
}
return maxi;
}

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

2.6

Indice du maximum dun tableau (*)

Exercice 10. crivez la fonction qui retourne lindice du plus grand des n premiers lments dun
tableau de rels (en cas dex-quo, lindice du premier dentre eux)
Prototype : int indice_plus_grand (double t[], int n);
Corrig

***************************************************************************
Le programme est semblable au prcdent. Un parcours du tableau simpose, avec une mmorisation de
lindice du plus grand lment rencontr. En effet, le plus grand lment du tableau peut se situer nimporte
o (en dbut, en cours ou en fin de tableau) et donc on ne peut le connatre quaprs avoir examin tous les
lments du tableau ; mmoriser sa position permettra de la retourner en fin de parcours.
Linitialisation de cet indice maximum pourra se faire par lindice du premier lment du tableau (0), et la
boucle peut commencer par lindice 1.
Ce qui conduit la solution suivante :
6/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

int indice_plus_grand (double t[], int n) {


int i;
int imax=0;
for (i=1;i<n;++i) {
if (t[i]>t[imax])
imax=i;
}
return imax;
}

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

2.7

Un tableau est-il tri ? (*)

Exercice 11. crivez la fonction qui retourne 1 si les n premiers lments du tableau sont en
ordre croissant (au sens large) et 0 sinon
Prototype : int est_trie(double t[], int n);
Corrig

***************************************************************************
Un parcours de tableau partir de lindice 1 pour vrifier la proprit i [1; n[t[i] t[i 1] Ce qui
conduit la solution suivante :
int est_trie(double t[], int n) {
int i;
for (i=1;i<n;++i) {
if (t[i]<t[i-1])
return 0;
}
return 1;
}

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

2.8

Recherche squentielle dans un tableau tri (*)

Exercice 12. crivez la fonction qui retourne la position dinsertion ventuelle dune valeur dans
un tableau suppos tri (recherche squentielle).
Note : La fonction doit retourner la place du premier x dans le tableau sil est prsent, ou la place
o devrait se trouver x dans le tableau sil est absent.
Prototype : int rech_seq_tab_trie(double x, double t[], int n);
Corrig

***************************************************************************
Comme le tableau est tri, le programme revient un parcours de tableau sur n lments, mix une
recherche de sentinelle gnralise : le premier lment du tableau x. Ce qui conduit la solution suivante :
int rech_seq_tab_trie(double x, double t[], int n) {
int i;
for (i=0 ; i<n; ++i) {
if (t[i] >= x)
return i;
}
return n;
}

***************************************************************************
7/25

ESIEE IGI-3005

2.9

TP no 3 (deux sances) (corrig)

2014-2015

Recherche dichotomique dans un tableau tri (**)

Exercice 13. crivez la fonction qui retourne la position dinsertion ventuelle dune valeur dans
un tableau suppos tri (recherche dichotomique).
Note : La fonction doit retourner la place du premier x dans le tableau sil est prsent, ou la place
o devrait se trouver x dans le tableau sil est absent.
Prototype : int rech_dicho_tab_trie(double x, double t[], int n);
Corrig

***************************************************************************
Comme vu en cours, linvariant du programme peut tre debut < pos f in. Lalgorithme du cours se
traduit immdiatement en C :
int rech_dicho_tab_trie(double x, double t[], int n) {
int d, f, m;
/* pos doit tre comprise entre 0 (x<=t[0]) et n (x>t[n-1]) */
/* Invariant logique : d < pos <=f */
d = -1; /* d < pos */
f = n; /* pos<= f */
while (d+1 < f) {
m = (d+f)/2;
if (t[m] < x) { /* x est forcment aprs m */
d = m; /* d<pos */
}
else { /* x est avant ou en m */
f = m; /* pos <= f */
}
}
/* d < pos <=f et d+1==f
==> pos = f */
return f;
}

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

2.10

Tests (*)

Exercice 14. crivez la fonction qui teste les deux fonctions prcdentes.
Note : La fonction doit crer des donnes de tests (tableau tri, taille, valeur cherche), des rsultats attendus, puis pour chaque donne de test, appeler rech_seq_tab_trie et rech_dicho_tab_trie et
signaler (messages) la non galit du rsultat obtenu avec le rsultat attendu.
Prototype : void test_seq_et_dicho_tab_trie(void);
Corrig

***************************************************************************
Par exemple :
void test_seq_et_dicho_tab_trie() {
double tab[] =
{1.0, 1.0,
2.0, 2.0, 3.0,
4.0, 5.0, 5.0};
double test_x[] = {0.0, 1.0,
1.1, 2.0,
3.0, 3.5,
5.0,
6.0};
int res[]
= { 0 , 0,
2,
2,
4,
5,
6,
8 };
int i, poss, posd;
int pbs=0, pbd = 0;
for (i=0; i<sizeof(test_x)/sizeof(test_x[0]);++i) {
poss = rech_seq_tab_trie(test_x[i], tab, sizeof(tab)/sizeof(tab[0]));
posd = rech_dicho_tab_trie(test_x[i], tab, sizeof(tab)/sizeof(tab[0]));
if (poss != res[i]) {
printf("Probleme seq test no %d. Res attendu :%d, res obtenu : %d\n",
i, res[i], poss);
8/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

pbs+=1;
}
if (poss != res[i]) {
printf("Probleme dicho test no %d. Res attendu :%d, res obtenu : %d\n",
i, res[i], posd);
pbd+=1;
}

}
if (pbs+pbd==0) {
printf("\n\nTest passe avec succes\n");
}
else {
printf("\n\nTest echoue : %d erreur(s)\n",pbs+pbd);
}
}

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

Copie et dcalage de tableaux (**)

3.1

Copie simple de tableaux (*)

Exercice 15. crivez la fonction qui copie les n premiers lments dun tableau source de rels
dans le tableau destination et retourne ladresse du tableau destination
Prototype : double * copie (double destination[], double source[], int n);
Corrig

***************************************************************************
La solution naturelle est base sur le principe : on parcourt paralllement les deux tableaux et on copie
lment par lment le contenu du tableau source dans le tableau destination, ce qui donne :
double *copie(double destination[], double source[], int n) {
/* Attention : ne fonctionne que si
* les tableaux ne se recouvrent pas
*/
int i;
for (i=0 ; i<n ; ++i) {
destination[i] = source[i];
}
return destination;
}

ou en plus concis :
double *copie(double destination[], double source[], int n) {
/* Attention : ne fonctionne que si
* les tableaux ne se recouvrent pas
*/
double *ret = destintation;
while (n--) {
*destination++ = *source++;
}
return ret;
}

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

3.2

Copie scurise de tableaux (**)

9/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

Exercice 16. crivez la fonction qui copie de manire scurise les n premiers lments dun
tableau source de rels dans le tableau destination et retourne ladresse du tableau destination
Attention : On devra prendre en compte le fait que les deux tableaux peuvent se recouvrir partiellement.
Prototype : double * copie_sec (double destination[], double source[], int n);
Corrig

***************************************************************************
Dans la solution prcdente, une erreur peut survenir lorsque lon appelle cette fonction avec deux tableaux
se recouvrant. Par exemple, avec le morceau de programme suivant :
double tab[]={8,2,103,-4,5,8};
copie(&tab[1],tab,5);/* tentative de decalage droite */

On voudrait dcaler dune position vers la fin de tableau les cinq premiers lments. Or la fonction va craser
succesivement les lments du tableau quelle na pas encore copis, ce qui conduira au rsultat suivant :
8 8 8 8 8 8

alors que lon aurait voulu obtenir :


8 8 2 103 -4 5

Faire la boucle dans lautre sens (de la fin vers le dbut) poserait le mme problme pour un dcalage vers
la gauche.
Une solution consiste tester la position en mmoire de la source par rapport la destination :
si source est avant destination, on copie de la fin vers le dbut
si source est aprs destination, on copie du dbut vers la fin
Pour tester le positionnement des deux tableaux, il suffit de les soustraire. La diffrence de deux pointeurs
de mme type donne le nombre dlments de ce type situs entre ces deux pointeurs. Ainsi, quel que soit le
type de t :
&t[5] - &t[3] vaut 2
&t[3] - &t[5] vaut -2
Ce qui conduit :
double *copie_sec(double destination[], double source[], int n) {
/* fonctionne meme si les tableaux se recouvrent */
int i;
if (destination - source < 0 ) {
for (i=0 ; i<n ; ++i) {
destination[i] = source[i];
}
}
else {
for (i=n-1 ; i>=0 ; --i) {
destination[i] = source[i];
}
}
return destination;
}

Attention : les fontions memcpy (copie de zones mmoires) et strcpy (copie de chanes de caractres) de
la librairie libc ne grent pas les recouvrements. Ci-dessous, un extrait de la documentation de memcpy :
If the regions overlap, the behavior is undefined.
***************************************************************************

10/25

ESIEE IGI-3005

3.3

TP no 3 (deux sances) (corrig)

2014-2015

Dcalage droite dun tableau de rels (*)

Exercice 17. crivez la fonction qui dcale de k lments vers la droite les lments dun tableau
de rels compris entre lindice d (inclus) et lindice f (inclus) et retourne ladresse du tableau.
Prototype : double *decale_droite (double t[], int k, int d, int f);
Corrig

***************************************************************************
Attention lordre de copie.
double *decale_droite(double t[], int k, int d, int f) {
int i;
for (i=f ; i>=d ; --i) {
t[i+k] = t[i];
}
return t;
}

ou laide de copie_sec :
double *decale_droite(double t[], int k, int d, int f) {
copie_sec(t+d+k, t+d, f-d+1);
return t;
}

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

3.4

Dcalage gauche dun tableau de rels (*)

Exercice 18. crivez la fonction qui dcale de k lments vers la gauche les lments dun tableau
de rels compris entre lindice d (inclus) et lindice f (inclus) et retourne ladresse du tableau.
Prototype : double *decale_gauche (double t[], int k, int d, int f);
Corrig

***************************************************************************
Attention lordre de copie.
double *decale_gauche (double t[], int k, int d, int f) {
for (i=d ; i<=f ; ++i) {
t[i-k] = t[i];
}
return t;
}

int i;

ou laide de copie_sec :
double *decale_gauche(double t[], int k, int d, int f) {
copie_sec(t+d-k, t+d, f-d+1);
return t;
}

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

11/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

Les chanes de caractres

4.1

Rptition (*)

Exercice 19. crivez une fonction qui prend en argument une chane de caractres et laffiche en
rptant chaque caractre n fois
Prototype : void * repete (char * s, int n);
Lappel repete("toto", 3) affichera tttoootttooo .
Corrig

***************************************************************************
void repete (char * s, int n) {
int i,j;
for (i=0;s[i]!=0;++i)
for (j=0;j<n;++j)
printf("%c",s[i]);
}

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

4.2

Retournement dune chane(*)

Exercice 20. crivez une fonction qui prend en argument une chane de caractres, la renverse
sur elle-mme ("toto"otot") et retourne ladresse de cette chane
Prototype : char * miroir (char * s);
Corrig

***************************************************************************
Il faut dj parcourir la chane pour accder son dernier caractre. Puis permuter les couples de caractres
symtriques en vitant de le faire deux fois, ce qui laisserait la chane inchange.
char * miroir (char * s) {
int g,d; /* indice gauche et droit de parcours */
char c;
for (d=0;s[d]!=0;++d){
/* on ne fait rien : on se contente de parcourir la chane */
}

for (g=0,--d ; g<d ; ++g,--d) {


c=s[g];
s[g]=s[d];
s[d]=c;
}
return s;

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

4.3

Recherche de motif (1) (**)

Exercice 21. crivez une fonction qui prend en argument deux chanes de caractres et retourne
1 si la premire chane de caractres commence par la seconde et 0 sinon. crivez un programme
pour tester cette fonction.
12/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

Prototype : int debute_par (char * chaine1, char * chaine2);


Par exemple, debute_par ("ESIEE","ES") 1
Corrig

***************************************************************************
Il suffit de regarder pour chaque caractre de chaine2 sil est gal au caractre correspondant de chaine1 .
Ds quil y a ingalit, on retourne 0 (faux). Si on arrive en bout de chaine2 sans avoir dtect dingalit,
on retourne 1 (vrai).
Note : ce programme renvoie toujours 1 si la chaine2 est vide.
int debute_par (char * chaine1, char * chaine2) {
int i;
for (i=0;chaine2[i]!='\0';++i)
if (chaine1[i]!=chaine2[i])
return 0;
return 1;
}

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

4.4

Recherche de motif (2) (**)

Exercice 22. crivez une fonction qui prend en argument deux chanes de caractres et retourne
la position de la premire occurrence de la chane2 dans la chane1 si elle y est prsente et 1 sinon.
Prototype : int presence (char * chaine1, char * chaine2);
Corrig

***************************************************************************
Une boucle contenant un appel debute_par permettra de dtecter la prsence de la sous-chane.
Note : ce programme considre que la chane vide dbute toute chane (retour 0).
int presence (char * chaine1, char * chaine2) {
int i;
for (i=0;chaine1[i]!='\0';++i) {
if (debute_par(&chaine1[i],chaine2)) {
return i;
}
}
return -1;
}

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

4.5

Chercher/remplacer (*)

Exercice 23. crivez une fonction qui recherche dans une chane chaque caractre c pour le
remplacer par un caractre r et retourne ladresse de la chane.
Prototype : char * cherche_remplace (char c, char r, char * s);
Corrig

***************************************************************************
Cest un parcours simple avec remplacement lorsque lon tombe sur le caractre remplacer :
13/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

char * cherche_remplace (char c, char r, char * s) {


int i;
for (i=0;s[i]!='\0';++i)
if (s[i]==c)
s[i]=r;
return(s);
}

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

4.6

Frquence (1) (**)

Exercice 24. crivez une fonction qui compte le nombre doccurrences dun caractre c dans une
chane s. La fonction pourra tre rcursive. crivez un programme pour tester cette fonction.
Prototype : int compte(char c, char * s);
Corrig

***************************************************************************
Cest encore un accumulateur :
int compte (char c, char * s) {
int i,acc=0;
for (i=0;s[i]!='\0';++i)
if (s[i]==c)
++acc;
return(acc);
}

Une fonction rcursive peut tre crite selon le principe suivant :


int compte2 (char c, char * s) {
if (*s=='\0') /* s[0] == '\0' */
return 0;
return ((*s==c)?1:0)+compte2(c,s+1);
}

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

4.7

Frquence (2) (**)

Exercice 25. crivez une fonction qui prend en argument un tableau de n char , remplit un
tableau dentiers avec les frquences des 256 caractres ASCII et retourne ladresse de ce tableau.
Prototype : int * frequence (char t[], int n ,int freq[]);
Attention : on parle ici de tableau de n caractres, qui peut contenir le clbre '0' .
Corrig

***************************************************************************
Cest un parcours simple avec incrmentation dans le tableau du compteur indic par le caractre courant.
int *frequence (char t[], int n ,int f[]) {
int i;
for (i=0;i<256;++i)
f[i]=0;
for (i=0;i<n;++i)
++f[(unsigned char)t[i]];
return f;
}

***************************************************************************
14/25

ESIEE IGI-3005

4.8

TP no 3 (deux sances) (corrig)

2014-2015

Conversion chane de caractres en entier (**)

Exercice 26. crivez une fonction qui prend en argument une chane de caractres reprsentant
un entier en dcimal et retourne lentier quivalent ("123" 123)
Note : on supposera que la chane est correcte et reprsente bien un entier.
Prototype : int chaine_vers_entier (char * s);
Corrig

***************************************************************************
Une chane reprsentant un entier est compose dune suite de caractres chiffres (compris entre '0' et
'9' ), ventuellement prcde dune caractre '-' ou '+' .
La valeur entire correspondant un caractre chiffre est gal ce caractre moins le caractre '0' .
( '2'-'0' vaut 2).
Sil y a un signe, on le mmorise sous le forme dune variable valant -1 ou +1. Puis, on accumule dans
un rsultat le nombre reprsent selon le principe suivant : pour chaque chiffre, on multiplie par 10 la valeur
accumule et on ajoute la valeur du chiffre.
En fin de calcul, on retourne le rsultat multipl par le signe.
int chaine_vers_entier (char * s) {
int i=0, signe=1, res=0;
if (s[i]=='+')
++i;
else if (s[i]=='-') {
signe=-1;
++i;
}
for(;s[i]!='\0';++i) {
res=res*10+s[i]-'0';
}
return signe*res;
}

Note : cest ainsi que les fontions du genre atoi (conversion dune chane en int ) de la librairie libc
oprent. Elles permettent galement la conversion dune chane exprimant un nombre en base 8 (commenant
par un 0 ) ou en base 16 (commenant par 0x ou 0X ). De plus, elles interrompent le calcul lorsquelles
parviennent un caractre non autoris et retournent le rsultat courant.
***************************************************************************

5
5.1

Pour aller plus loin


Mise en majuscules (**)

Exercice 27. crivez une fonction qui prend en argument une chane de caractres, la transforme
en majuscules ("toto" "TOTO") et retourne son adresse
On laissera inchangs les caractres non lettre. On prendra en compte les caractres accentus ou
cdills en les transformant en leurs majuscules sans accent ou sans cdille. Rflchissez au problme que
posent les ligatures (, ) et proposez une solution.
Prototype : char * majuscule (char * s);
Corrig

***************************************************************************
Cet exercice (et les suivants qui sen servent) avait pour but de vous sensibiliser aux problmes de lencodage das caractres selon les plate-formes et les langues. Il y a trop bien russi. lESIEE, sur une mme
machine, lencodage de lditeur de texte et de la console peuvent diffrer. Pour ceux que cela intresse,
15/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

la page http://pagesperso-systeme.lip6.fr/Jean-Francois.Perrot/inalco/cours11/index.html
donne une prsentation trs complte du sujet.
Concernant le programme proprement dit (mise en majuscule dune chane de caractres), il faut dj crire
une fonction utilitaire de majuscule dun caractre.
Prototype : int maj(int c);
La fonction est dclare avec le type int pour son retour et son paramtre, pour permettre le passage ou
le retour des caractres classiques, plus EOF (end of file), en gnral dfini par 1.
Les caractres lettres non accentues ont les majuscules prcdant de 32 (20 hexa) leurs minuscules
correspondantes, ce qui peut donner comme code pour traiter les minuscules :
if ('a'<=c && c<='z') return c-32;

Il vaut toutefois mieux crire :


if ('a'<=c && c<='z') return c-'a'+'A';

ce qui vite le magic number 32.


Concernant les lettres accentuess, une solution consiste les lister toutes, avec leurs majuscules asscocies,
et les programmer laide dun switch , ce qui est pnible et peu efficace.
Une meilleure solution, tout aussi pnible, mais plus efficace, consiste crer un tableau indic par les
caractres, initialise une fois pour toutes, comme par exemple :
static int TABMAJ[256];
void inittabmaj() {
int i;
for (i=0;i<256;++i) {
TABMAJ[i]=i;
}
for (i='a';i<='z';++i) {
TABMAJ[i]=i+'A'-'a';
}
TABMAJ[(unsigned char)'']='A';
TABMAJ[(unsigned char)'']='E';
/* etc ... */
}

De plus, cette solution peut tre adapte plusieurs types de majuscules ( E pour un classement
alphabtique, pour un traitement de texte)
int maj(int c) {
if (0<=c && c<=255)
return TABMAJ[c];
return c;
}

Note : Il existe des fonctions int tolower(int) , int isdigit(int) , etc. dclares dans ctype.h qui
permettent de grer tout ce qui concerne les lettres non accentues. Ces fonctions faisant rfrence une
table indice par les caractres, il faut transtyper un argument char en unsigned char pour viter les indices
ngatifs gnrant une sortie du tableau.
La fonction majuscule demande scrit alors simplement :
char * majuscule (char * s) {
int i;
for (i=0;s[i]!='\0';++i) {
s[i]=maj((unsigned char)s[i]);
}
return s;
}

Le cas des ligatures (, ) est plus dlicat. La normalisation "" "AE" change le nombre de caractre
et ncessite alors un buffer de rception de la chane normalise (qui ne sera pas de mme taille que la chane
initiale).
***************************************************************************
16/25

ESIEE IGI-3005

5.2

TP no 3 (deux sances) (corrig)

2014-2015

Classement alphabtique (***)

Exercice 28. crivez une fonction qui prend en argument deux chanes de caractres et retourne -1
si la premire (mise en majuscule) est avant la seconde (mise en majuscule) par ordre alphabtique,
0 si elles sont identiques (mises en majuscules) et 1 si la premire est aprs la seconde. Prenez en
compte les lettres accentues et les ligatures (buf)
On pourra utiliser strcmp (dclar dans string.h ). Par exemple,
compare("chat", "chien") 1
compare("zbre","lphant") 1
compare("corne","COR") 1
compare("relev","relve") 0

Prototype : int compare (char * s1, char * s2);


Corrig

***************************************************************************
Attention : on suppose ici que lon dispose dune fonction majuscule permettant de normaliser une chane
de caractres.
int compare (char * s1, char * s2) {
int i;
majuscule(s1);
majuscule(s2);
for(i=0;s1[i]==s2[i];++i) /* ou utiliser strcmp */
if (s1[i]==0)
return 0;
return (s1[i]<s2[i])?-1:1;
}

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

5.3

Des chiffres en lettres (**)

Exercice 29. crivez une fonction qui prend en argument un nombre de un chiffre et remplit
une chane avec lcriture en lettres de ce chiffre(par exemple, 8 "huit"). On supposera que la
mmoire alloue pour la chane est suffisante.
Prototype : char * chiffre_vers_chaine (int n, char * s);
Corrig

***************************************************************************
Une table static suffira pour cette fonction.
#include <string.h>
char * chiffre_vers_chaine (int n, char * s) {
static char *chiffres[10]={
"zro", "un", "deux", "trois", "quatre",
"cinq", "six", "sept", "huit", "neuf"};
}

return strcpy(s,chiffres[n]);

***************************************************************************
17/25

ESIEE IGI-3005

5.4

TP no 3 (deux sances) (corrig)

2014-2015

Des nombres en lettres (****)

Exercice 30. Gnralisez le programme prcdent pour faire afficher les nombres entiers en toutes
lettres (par exemple, 895 "huit cent quatre-vingt-quinze").
Renseignez-vous sur les rgles dcriture des nombres en franais.
Prototype : void affiche_en_lettres (int n);
Corrig

***************************************************************************
Ci-dessous un programme crit il y a plusieurs annes qui semble encore fonctionner.
#include <stdio.h>
#include <string.h>
/********************************************************
* Calcul et retour de : l'criture en toutes lettres
*
* d'un petit nombre entier
*
* fonctionne pour 0-999
*
* les rgles d'criture d'un nombre en lettres sont
*
* tires de "Grvisse Le bon usage" (p.572 & suivantes)*
*
*
********************************************************/
char* nb_en_lettres(char *buffer, int nombre) {
static char *nom_simple[]={"zro", "un","deux",
"trois","quatre",
"cinq","six","sept","huit",
"neuf","dix","onze","douze","treize","quatorze",
"quinze","seize"};
char txt[128]; /* pour les critures intermdiaires
(le 17 de 77 p.ex.) */
if (nombre<=16) { /* 0 - 16 */
strcpy(buffer,nom_simple[nombre]);
/* en dessous de 17, trivial */
return(buffer);
}
if (nombre<=59) { /* 17-59 */
switch(nombre/10) {
case 1 : strcpy(buffer,"dix");
break; /* 17 - 19 */
case 2 : strcpy(buffer,"vingt");
break; /* 20 - 29 */
case 3 : strcpy(buffer,"trente");
break; /* 30 - 39 */
case 4 : strcpy(buffer,"quarante");
break; /* 40 - 49 */
case 5 : strcpy(buffer,"cinquante");
break; /* 50 - 59 */
}
if (nombre%10==0)
/* 20, 30, 40, 50 */
return(buffer);
if (nombre%10==1)
/* 21,31,41,51 */
strcat(buffer," et ");
else
/* 17-19,22-29,32-39,42-49,52-59 */
strcat(buffer,"-");
return(strcat(buffer,nom_simple[nombre%10])) ;
}
if (nombre<=79) { /* 60-79 */
strcpy(buffer,"soixante");
if (nombre==60)
/* 60 */
return (buffer);
if (nombre%10==1)
strcat(buffer," et "); /*61, 71*/
else
strcat(buffer,"-");
/* 62-69 72-79 */
return (strcat(buffer,nb_en_lettres(txt,nombre-60)));
18/25

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

}
if (nombre<=99) { /* 80-99 */
strcpy(buffer,nb_en_lettres(txt,4));
strcat(buffer,"-");
strcat(buffer,nb_en_lettres(txt,20));
if (nombre==80)
/* 80 */
return (strcat(buffer,"s"));
strcat(buffer,"-");
/* 81-99 */
return (strcat(buffer,nb_en_lettres(txt,nombre-80)));
}
if (nombre<1000) { /*100-999 */
if (nombre>=200) { /*200-999 */
strcpy(buffer,nb_en_lettres(buffer,nombre/100));
strcat(buffer," ");
}
else {
strcpy(buffer,"");
}
strcat(buffer,"cent");
if (nombre%100==0) {
/* 100,200,300,400,500,600,700,800,900 */
if (nombre>=200)
/* 200,300,400,500,600,700,800,900 */
strcat(buffer,"s");
return(buffer);
}
strcat(buffer," ");
/*101-199 201-299 etc */
return(strcat(buffer,nb_en_lettres(txt,nombre%100)));
}
return("Erreur");

/* nombre = md (milliard(s)) mn (million(s)) m (mille) n


1234567890= 1
234
567
890
*/
/* Rgle :
md, mn, m, n sont des nombres infrieurs 1000
md, mn, n s'crivent de la mme facon (voir la rgle
des nombres <1000)
m suit la meme rgle sauf :
si m=1, il ne s'crit pas (mille deux, pas un mille deux)
si m=c80(avec c un chiffre quelconque) ou c00 (avec c>=2),
le s final de l'criture de m disparait
(deux cents, mais deux cent mille)
*/
char *nombre_en_lettres(char *buffer, unsigned long nombre) {
int md,mn,m,n;
char txt[80];
md=(int)(nombre/1000000000L); /* milliards */
mn=(int)((nombre%1000000000L)/1000000L); /* millions */
m = (int)((nombre%1000000L)/1000);
/* mille */
n=(int)(nombre%1000);
/* units (<1000) */
strcpy(buffer,"");
if (md!=0) {
nb_en_lettres(txt,md);
strcat(buffer,txt);
strcat(buffer, " milliard");
if (md>1)
strcat(buffer,"s");
}
if (mn!=0) {
if (md!=0)

19/25

2014-2015

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

strcat(buffer," ");
nb_en_lettres(txt,mn);
strcat(buffer,txt);
strcat(buffer, " million");
if (mn>1)
strcat(buffer,"s");

if (m!=0) {
if (md!=0 || mn!=0)
strcat(buffer," ");
if (m>1) {
nb_en_lettres(txt,m);
if (m%100==80 || m%100==0 && m>100)
/* suppression du 's' pour 200000 ou 80000*/
txt[strlen(txt)-1]='\0';
strcat(buffer,txt);
strcat(buffer," ");
}
strcat(buffer, "mille"); /* toujours invariable */
}
if (n!=0) {
if (md!=0 || mn!=0 || m!=0)
strcat(buffer," ");
nb_en_lettres(txt,n);
strcat(buffer,txt);
}
if (nombre==0) {
/* cas particulier de 0 tout seul */
nb_en_lettres(txt,0);
strcat(buffer,txt);
}
return buffer;

int test(void) {
/* vrifier :
1) les orthographes des noms simples 0 16 et des noms
servant composer des noms complexes
Rgle 01000
0 zro
01001
1 un
01002
2 deux
01003
3 trois
01004
4 quatre
01005
5 cinq
01006
6 six
01007
7 sept
01008
8 huit
01009
9 neuf
01010
10 dix
01011
11 onze
01012
12 douze
01013
13 treize
01014
14 quatorze
01015
15 quinze
01016
16 seize
01017
20 vingt
01018
30 trente
01019
40 quarante
01020
50 cinquante
01021
60 soixante
01022
100 cent
01023
1000 mille
01024
1 000 000 million
01025
1 000 000 milliard
2) les rles pour les nombres entre 17 et 59
02000
Les multiples de 10 s'crivent seuls
(sans - ou 'et' ou zro)
02001
Les nombres se terminant par 1 s'crivent
<dizaine>" et un"

20/25

2014-2015

ESIEE IGI-3005

02002
3) les rgles
03000
03001
03002
03003

TP no 3 (deux sances) (corrig)

Les autes nombres s'crivent


<dizaine>"-"<unit>
pour les nombres de 60 79
60 s'crit "soixante"
61 s'crit "soixante et un"
71 s'crit "soixante et onze"
Les autres nombres s'crivent
"soixante-"<nom de (nombre-60)>

4) les rgles pour les nombres de 80 99


04000
80 s'crit "quatre-vingts" s'il termine
le nombre
04001
80 s'crit "quatre-vingt" s'il ne termine
pas le nombre
04002
81 s'crit "quatre-vingt-un"
04003
91 s'crit "quatre-vingt-onze"
04004
Les autres nombres s'crivent
"quatre-vingt-"<nom de (nombre-80)>
5) les rgles pour les nombres de 100 199
05000
100 s'crit "cent"
05001
Les autres nombres s'crivent
"cent "<nom du mombre-100>
6) les rgles pour les nombres de 200 999
06000
Les multiples de 100 s'crivent
<nom du chiffre des centaines>" cents"
s'ils terminent le nombre
06001
Les multiples de 100 s'crivent
<nom du chiffre des centaines>" cent"
s'ils ne terminent le nombre
06002
Les autres nombres s'crivent
<nom du chiffre des centaines>
" cent "<nom du nombre modulo 100>
7) les rgles pour les nombres de 1000 1999
07000
1000 s'crit "mille"
07001
Les autres nombres s'crivent
"mille "<nom du nombre modulo 1000>
8) les rgles pour les nombres de 2000 999 999
08000
Les multiples de 1000 s'crivent
<nom du nombres de milliers>" mille"
08001
Les autres nombres s'crivent
<nom du nombre de milliers>
" mille "<nom du nombre modulo 1000>
9) les rgles pour les nombres de 1 000 000 1 999 999
09000
1 000 000 s'crit "un million"
09001
Les autres nombres s'crivent
"un million "<nom du nombre modulo 1 000 000>
10) les rgles pour les nombres de 2 000 000 999 999 999
10000
Les multiple de 1 000 000 s'crivent
<nom du nombre de millions>" millions"
10001
Les autres nombres s'crivent
<nom du nombre de millions>
" millions "<nom du nombre modulo 1 000 000>
11) les rgles pour les nombres de 1 000 000 000
1 999 999 999
11000
1 000 000 000 s'crit "un millard"
11001
Les autres nombres s'crivent
"un millard "
<nom du nombre modulo 1 000 000 000>
12) les rgles pour les nombres de 2 000 000 000
999 999 999 999
12000
Les multiple de 1 000 000 000 s'crivent
<nom du nombre de milliards>" milliards"
12001
Les autres nombres s'crivent
<nom du nombre de milliards>
" milliards "

21/25

2014-2015

TP no 3 (deux sances) (corrig)

ESIEE IGI-3005

*/

<nom du nombre modulo 1 000 000 000>

struct test {
unsigned long n;
char *l;
} t[]={
{0,"zro"},
/*01000 */
{2345678900, "deux milliards trois cent quarante-cinq \
millions six cent soixante-dix-huit mille neuf cents"},
{4000000000, "quatre milliards"},
/* 12000, 01002 */
{1600000000,
"un milliard six cents millions"},
/* 12001, 10000, 01003 01004 01024*/
{1000000000, "un milliard"},
/* 11001, 09000 */
{1110000,"un million cent dix mille"},
/*10001,08001,06001,06002,04004,0123,01022 */
{1000000,"un million"},
{1192,"mille cent quatre-vingt-douze"},
{1000,"mille"},
{100,"cent"},
{91081080,"quatre-vingt-onze millions \
quatre-vingt-un mille quatre-vingts"},
{80071061,"quatre-vingts millions soixante \
et onze mille soixante et un"},
{60059031,"soixante millions cinquante-neuf \
mille trente et un"},
{20016015,"vingt millions seize mille quinze"},
{14013012,"quatorze millions treize mille douze"},
{84,"quatre-vingt-quatre"},
{180,"cent quatre-vingts"},
{2123,"deux mille cent vingt-trois"},
{1001001100L,"un milliard un million mille cent"},
{80,"quatre-vingts"},
{2,"deux"},
{21,"vingt et un"}
};
char buffer[1024];
int i,c=0;
for (i=0;i<sizeof(t)/sizeof(t[0]);++i)
if (strcmp(t[i].l,nombre_en_lettres(buffer,t[i].n))!=0) {
printf("Problme pour : %lu\nAttendu : <%s>\n\
Obtenu : <%s>\n",t[i].n,t[i].l,buffer);
++c;
}
printf("%d problme(s) dans les tests inclus\n",c);
return c;
}

int main() {
unsigned int n; char b[1024];
test();
do {

22/25

2014-2015

ESIEE IGI-3005

TP no 3 (deux sances) (corrig)

2014-2015

printf("Entrez un entier positif (0 pour finir) : ");


scanf("%d",&n);
printf("%s\n",nombre_en_lettres(b,n));
} while (n!=0);
getchar();
return 0;

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

5.5

Compteur de mots (***)

Exercice 31. crivez une fonction qui compte le nombre de mots dans une chane de caractres
(la documentation devra dfinir exactement ce que lon entend par mot). crivez un programme
pour tester cette fonction.
Prototype : int compte_mots (char * s);
Corrig

***************************************************************************
Pour ce programme, on considrera comme mot toute suite continue de une ou plusieurs lettres. Un
parcours de la chane, avec mmorisation dtat, permet dcrire la fonction. Lors du parcours de la chane,
deux tats sont possibles :
on est dans un mot (tat MOT)
on nest pas dans un mot (tat NONMOT)
Les transitions dtat sont les suivantes :
si on est dans ltat MOT :
si on rencontre une lettre : on reste dans ltat MOT
si on rencontre un caractre non-lettre : on entre dans ltat NONMOT
si on est dans ltat NONMOT
si on rencontre une lettre : on rentre dans ltat MOT
si on rencontre un caractre non-lettre : on reste dans ltat NONMOT
On comptera le nombre de mots en incrmentant une variable chaque fois que lon entrera dans ltat MOT.
#include <ctype.h>
#define MOT 1
#define NONMOT 0
int compte_mots (char * s) {
int etat=NONMOT;
int cpt=0;
for(;*s!='\0';++s) {
switch(etat) {
case MOT :
if (! isalpha(*s))
etat=NONMOT;
break;
case NONMOT :
if (isalpha(*s)) {
etat=MOT;
++cpt;
}
break;

}
}
return cpt;

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

23/25

ESIEE IGI-3005

5.6

TP no 3 (deux sances) (corrig)

2014-2015

Les huit reines (***)

Exercice 32. crivez une fonction calculant et affichant toutes les solutions au problme des huit
reines.
Huit reines doivent tre places sur un chiquier 8 8 sans que deux dentre elles soient en prise, cest
dire sur une mme ligne, mme colonne ou mme diagonale.
Prototype : int huit_reines (void);
Corrig

***************************************************************************
Une solution qui utilise un tableau des hauteurs des reines sur lchiquier.
/* les huit reines */
#include <stdio.h>
#define abs(a) (a>=0?a:-(a))
void affiche(int e[],int n) {
int i;
printf("\n[%d",e[0]);
for (i=1;i<n;++i) {
printf(",%d",e[i]);
}
printf("]\n");
}
void affiche_complet(int e[],int n) {
int l,c;
printf("\n\n");
for (l=0;l<n;++l) {
for (c=0;c<n;++c) {
if (e[c]==l)
printf("X ");
else
printf(". ");
}
printf("\n");
}
}
int compatible(int l[], int n) {
int i;
for (i=n-1;i>=0;--i) {
if ((l[i]==l[n]) || abs(l[i]-l[n])==n-i) {
return 0;
}
}
return 1;
}
int reines(int n) {
int ech[n];
int col,s;
ech[0]=-1;
col=0;
s=0;
while (col>=0) {
++ech[col];
if (ech[col]>=n) {
--col;
}
else {
if (compatible(ech,col)) {
24/25

TP no 3 (deux sances) (corrig)

ESIEE IGI-3005

if (col==n-1) {
++s;
affiche_complet(ech,n);
}
else {
++col;
ech[col]=-1;
}

}
else {
}

}
}
return s;

int main() {
int i;
for (i=1;i<=8;++i) {
printf("echiquier %2dx%2d :
i,i, reines(i));
}
getchar();
return 0;
}

%10d solution(s) \n",

/*
dbut de l'affichage
X
echiquier
echiquier
echiquier
.
X
.
.

.
.
.
X

X
.
.
.

1x 1 :
2x 2 :
3x 3 :

1 solutions
0 solutions
0 solutions

4x 4 :

2 solutions

.
.
X
.

. X . .
. . . X
X . . .
. . X .
echiquier

................................
fin de l'affichage
. . X . . . . .
. . . . . X . .
. . . X . . . .
. X . . . . . .
. . . . . . . X
. . . . X . . .
. . . . . . X .
X . . . . . . .
echiquier 8x 8 :

92 solutions

*/

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

25/25

2014-2015

Anda mungkin juga menyukai