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
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
4
4
5
6
6
7
7
8
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
. .
. .
. .
(*)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9
9
9
11
11
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
en entier (**)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
12
12
12
12
13
13
14
14
15
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
15
15
17
17
18
23
24
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1/25
ESIEE IGI-3005
2014-2015
Note : sauf spcification contraire, dans tous les exercices, on considrera que les tableaux contiennent
au moins un lment.
Utilitaires
1.1
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
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
2014-2015
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
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
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
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
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
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
2014-2015
***************************************************************************
2.4
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;
5/25
ESIEE IGI-3005
2014-2015
***************************************************************************
2.5
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
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
2014-2015
***************************************************************************
2.7
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
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
2014-2015
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
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);
}
}
***************************************************************************
3.1
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
9/25
ESIEE IGI-3005
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
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
2014-2015
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
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
2014-2015
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
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 */
}
***************************************************************************
4.3
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
2014-2015
***************************************************************************
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
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
2014-2015
***************************************************************************
4.6
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);
}
***************************************************************************
4.7
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
2014-2015
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
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
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;
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
2014-2015
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
***************************************************************************
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
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
2014-2015
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
}
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");
19/25
2014-2015
ESIEE IGI-3005
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
21/25
2014-2015
ESIEE IGI-3005
*/
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
2014-2015
***************************************************************************
5.5
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
2014-2015
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
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;
}
/*
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