Vous êtes sur la page 1sur 8

Anne 2014-2015

Examen de Langage C
Vendredi 5 Dcembre 2014

Promotion Le Meur
1i`ere anne
. Salvat

Modalits :
 Dure : 2 heures
 Seul document autoris : carte de rfrence du C, pas de machine calculer, ni de tlphone.
 Toute sortie est dnitive !
 Le barme est donn titre indicatif.

(Les notes - 2 points).


Un enseignant a saisi les notes des n examens de ses m lves dans un tableau deux dimensions notes :
la ii`eme ligne reprsente les n notes obtenues par l'lve numro i chacun des examens, et la j i`eme
colonne la note de chaque lve l'examen numro j . Chaque note est un entier. On supposera que le
nombre de notes N et le nombre d'lves M ont t dnis par des directives de prcompilation de la
forme : #define N xx et #define M yy o, bien sr, xx et yy sont remplacs par des valeurs entires.

Cor
rig

Exercice 1

Par exemple si l'on considre le tableau de notes ci-dessous, le 2i`eme lve a obtenu un 15 au 3i`eme
examen.
12
16

14
11

13
12

10
16

9
15
...
13
17

...
...

16
14

...
...

12
8

1. Dnir la fonction Moyenne_Eleve qui prend en paramtre un tableau d'entiers (les notes) et un
entier x reprsentant le numro de l'lve qui renvoie la moyenne de l'lve (en nombre dcimal).
2. Dnir la fonction Moyennes qui prend en paramtre un tableau d'entiers (les notes) et qui renvoie
un tableau des moyennes (une moyenne par lve) en nombre dcimaux.
Corrig de l'exercice 1.

1. fonction Moyenne_Eleve :

float Moyenne_Eleve(int notes[M][N], int x)


{
float moy=0;
int i;

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


moy += notes[x][i];
return (moy / N);

2. fonction Moyennes
float* Moyennes(int notes[M][N])
{
float* moy;
int i;
moy = malloc(M * sizeof(float));
for(i=0 ; i<M ; i++)
{

moy[i]= Moyenne_Eleve(notes, i);


}
return moy;

(Pointeur, adresse et tableau - 4 points).


Dans un programme, on dclare et initialise un tableau d'entier, et un pointeur sur entier avec les instruction ci dessous.

Exercice 2

int tab[]={1,2,3,4,5,6,7,8,9};
int *p;
p=tab;

Cor
rig

Quelle est la nature (entier ou pointeur ) et la valeur ou l'adresse de chacune des expressions suivantes ?
1. p
2. *(p+5)
3. tab+5
4. &tab[5]-p
Corrig de l'exercice 2.

1.
2.
3.
4.

p=&tab[0] : i.e. l'adresse du premier lment du tableau.


*(p+5) = 6 : i.e. l'entier tab[5], la valeur du 6i`eme lment du tableau.
tab+5 =&tab[5] : i.e. l'adresse du 6e`me lment du tableau ;
&tab[5]-p=5 : i.e. dirence entre les adresses du 6e`me lment et celle du 1er lment.

(Le code de jules Csar - 4 points).


Lorsqu'il souhaitait envoyer un message secret, Jules Csar crivait le message en remplaant chaque
lettre par la troisime lettre la suivant dans l'alphabet. Ainsi la lettre 'a' devient 'd', la lettre 'b' devient
'e' ainsi de suite, en reprenant au dbut de l'alphabet pour les dernires lettres. Le 'v' devient 'z', le x
devient 'a',... Il s'agit d'une permutation circulaire. On peut bien entendu modier le code en changeant
simplement le dcalage.
1. crire un programme en C qui prend en paramtre une lettre et un nom de chier. La lettre sera
le codage de la lettre 'a', le nom du chier, celui du chier coder. Votre programme eectuera
le codage du contenu du chier pass en paramtre et enregistrera le rsultat dans un chier
"message_secret.txt". Seules les lettres seront codes, aussi bien les majuscules que les minuscules,
tous les autres caractres seront inchangs.
2. Modier le programme prcdent pour que l'on puisse l'appeler avec un nombre quelconque de
chiers sur la ligne de commande. Vous crerez autant de chiers de sortie que de chiers en entre.
Ils seront nomms "message_secret_i.txt", o i est le numro du chier dans l'ordre d'apparition
sur la ligne de commande.

Exercice 3

Remarque.

 Pour mmoire : le code ASCII de 'A' est 65 (et en suivant pour les autres lettres jusqu' 90 pour
'Z'), de mme le code ASCII de 'a' est 97 (et en suivant pour les autres lettres jusqu' 122 pour
'z').
 L'oprateur % (modulo) renvoie le reste de la division entire de deux entiers.
Corrig de l'exercice 3.

1. Programme appliquant le code de Jules Csar sur un chier


2

#include <stdio.h>
char code_lettre(char a_coder, char codage)
{
char base;
int decalage = codage -'a';
result = a_coder + decalage;

/* lettre minuscule */

return (base + (a_coder + decalage - base)%26);

Cor
rig

/* lettre majuscule */

if ( a_coder < 'Z' )


base = 'A';
else
base = 'a';

void codage(char l_code, char* nom_fic, char* fic_sauv)


{
FILE* fic=NULL;
FILE* sauv=NULL;
char l_lu;

if ( (fic=fopen(nom_fic,"r")) == NULL)
{
printf("Erreur ouverture du fichier : %s \n",nom_fic);
return(-1);
}
if ( (fic=fopen(fic_sauv,"w+")) == NULL)
{
printf("Erreur ouverture du fichier de sauvegarde \n");
return(-1);
}

while ( !feof(fic))
{
l_lu = fgetc(fic);
if (((l_lu >=65) && (l_lu<=90)) || ( (l_lu>=97) && (l_lu<=122) ) )
l_lu = code_lettre(l_lu, l_code);
fputc(l_lu, sauv);
}

int main(int argc, char** argv)


{
if (argc !=3 )
{
printf("Erreur !\nDonner 2 arguments : lettre et nom_fichier.\n");
return(-1);
}

codage(argv[1],argv[2],"message_secret.txt" );
}

return 0;

2. Pour appliquer la mme opration un nombre quelconque de chiers, il sut de modier la


fonction main comme indiqu ci-dessous. Les fonctions codage et code_lettre sont inchanges.
#include <stdio.h>

int code_lettre(char a_coder, char codage)


{
// Mme code que dans la question prcdente
}

Co
rrig

void codage(char l_code, char* nom_fic, char* fic_sauv)


{
// Mme code que dans la question prcdente
}
int main(int argc, char** argv)
{
int numfic=0;
char nom_fic[25];

if (argc < 3 )
{
printf("Erreur !\nDonner au moins 2 arguments : lettre et nom_fichier.\n");
return(-1);
}
for (numfic=2; numfic < argc; numfic++)
{
sprintf(nom_fic,"message_secret_%d.txt", numfic-1);
codage(argv[1],argv[2],nom_fic );
}

return 0;

(Les horaires de bus - 10 points).


Une socit de transport urbain souhaite reprsenter ses lignes de bus et leurs horaires en machine an
de pouvoir faire divers traitements informatique. Il a ainsi t dcid de reprsenter un horaire par deux
entiers (un pour les heures et un pour les minutes). Un arrt sera reprsent par un nom (une chane de
caractres) et un tableau de 15 horaires (les horaires de passage des bus cet arrt) et un pointeur vers
l'arrt suivant dans le parcours (structure de liste chane). Enn une ligne sera reprsente un numro
de ligne et deux listes chanes : une pour les arrts dans le sens "aller" de la ligne, et une autre pour les
arrts dans le sens "retour" de la ligne.
1. Donner la dnition de la structure d'un arrt, lment de la liste chane (aller ou retour) reprsentant la ligne de bus. Les horaires sont mis dans un tableau deux dimensions : une colonne
pour les heures, et une pour les minutes.
2. Donner la dnition de la structure d'une ligne.

Exercice 4

Cor
rig

3. crire la fonction Horaires qui prend en paramtre un nom d'arrt, une ligne de bus et un sens
(aller ou retour) et qui renvoie les horaires de passage des bus cet arrt.
4. crire la fonction Ajoute qui prend en paramtres un nom d'un nouvel arrt, un tableau d'horaires
(du nouvel arrt), un nom d'arrt, une ligne et un sens (aller ou retour), et qui ajoute un nouvel
arrt dans la ligne aprs l'arrt pass en paramtre. On supposera que l'on dispose de la fonction
void Copie_horaires(int origine[15][2], int copie[15][2]) qui recopie le tableau d'horaires origine dans le tableau copie.
5. On souhaite connatre les correspondances entre deux lignes. crire la fonction Correspondances
qui prend en paramtres deux lignes de bus et qui renvoie une liste chane des arrts communs
(mme nom) aux deux lignes.
Si cela est ncessaire on pourra utiliser les fonctions de la bibliothque string, notamment la fonction
strcmp : strcmp(chane1,chane2) renvoie un entier plus petit, gal ou plus grand que 0 si chane1
est respectivement plus petite, gale ou plus grande que chane2 dans l'ordre alphabtique.
Corrig de l'exercice 4.

1. Structure arrt :

typedef struct arret{


char nom[30];
int horaires[15][2];
struct arret* suiv;
} s_arret;

2. Structure ligne :

typedef struct ligne{


int num;
s_arret* Aller;
s_arret* Retour;
} s_ligne;

3. Recherche des horaires de passage un arrt donn. On avait le choix de reprsenter le sens comme
on le souhaite : un entier, une seule lettre, ou encore, comme dans ce corrig, avec les mots "aller"
et "retour".
int** Horaires(char* nom_a, s_ligne* lig, char* sens)
{
s_arret cour = NULL;

/* Initialisation du pointeur du parcours */


if (strcmp(sens, "aller") == 0)
cour = lig->Aller;
else if (strcmp(sens, "retour") == 0)
cour = lig->Retour;
else {
printf("Sens de parcours inconnu!\n");
return NULL;
}
/* Recherche de l'arrt de nom "nom_a" */
while ((cour!=NULL) && (strcmp(cour->nom, nom_a)!=0))
cour = coour->suiv;
if (cour != NULL) /* on a trouv l'arrt */

else {

return(cour->horaires);

printf("Arrt %s introuvable.\n",nom_a);
retrun NULL;

4. Ajouter un arrt dans une ligne existante :

void Ajoute(char* nom_nouv, int horaires_nouv[15][2], char* nom_pred, s_ligne* lig, char* sens)
{
s_arret* nouv=NULL;
s_arret* cour=NULL;

Cor
rig

/* Initialisation du pointeur du parcours */


if (strcmp(sens, "aller") == 0)
cour = lig->Aller;
else if (strcmp(sens, "retour") == 0)
cour = lig->Retour;
else {
printf("Sens de parcours inconnu!\n");
return NULL;
}

/* cration de la structure du nouvel arrt */


nouv = (s_arret*) malloc(sizeof(s_arret));
if (nouv == NULL) {
printf("Problme d'allocation mmoire.\n");
exit (-1);
}
strcpy(nouv->nom, nom_nouv);
Copie_horaires(horaires_nouv, nouv->horaires);
/* Recherche de l'arrt de nom "nom_pred" */
while ((cour!=NULL) && (strcmp(cour->nom, nom_pred)!=0))
cour = coour->suiv;

if (cour==NULL) {
printf("Arret %s introuvable.\n",nom_pred);
(exit(-1);
}
/* insertion de nouv dans la liste chane */
nouv->suiv = cour->suiv;
cour->suiv = nouv;

5. Recherche des noms des arrts permettant une correspondance entre deux lignes. Pour construire
la liste chane des arrts, on peut utiliser la structure dclare la question 1. A noter que les
horaires ne sont pas demands (il faudrait les horaires des 2 lignes...). On pourrait aussi construire
une strucure qui ne contient que les noms des arrts. Enn, pour tre variment prcis, il serait
souhaitable de ne pas mettre des doublons dans cette liste (ce qui n'est pas prcis dans le sujet).
s_arret* Correspondance(s_ligne* L1, sligne* L2)
{
s_arret* retour = NULL; /* la liste chane rsultat */

s_arret* nouv = NULL;


s-arret* cour1 = NULL;
s_arret* cour2 = NULL;
int A1=1,A2=1;

/* pour crer les correspondances trouves */


/* parcours des arrts de L1 */
/* parcours des arrts de L2 */
/* entier pour dclencher le changement de sens (aller o

while (cour1 != NULL)


{
cour2 = L2->Aller;
A2 = 1;

/* Initialisation du pointeurs de parcours de L1*/


cour1 = L1->Aller;

Cor
rig

while (cour2 != NULL)


{
if (strcmp(cour1->nom,cour2->nom) == 0)
{
/* mmorisation de l'arrt "correspondance" */
nouv = (s_arret*) malloc(sizeof(s_arret));
if (nouv == NULL) {
printf("Problme d'allocation mmoire.\n");
exit (-1);
}
strcpy(nouv->nom, cour1->nom);
nouv->suiv = retour;
retour = nouv;
}
/* dans tous les cas : on continue le parcours */
cour2 = cour2->suiv;
if ( (cour2==NULL) && (A2==1))
{
cour2 = L2->Retour;
A2 = 0;
}
}
cour1 = cour1->suiv;
if ( (cour1==NULL) && (A1==1))
{
cour1 = L1->Retour;
A1 = 0;
}

}
return retour;

An d'viter les doublons, on pourrait remplacer le code l'intrieur du test if (strcmp(cour1->nom,cour2->nom)
== 0) par l'appel une fonction qui ajoute dans une liste chane un lment que si ncessaire :
s_arret* Ajoute_vrif(s_arret* liste, char* nom_arret)
{
s_arret* cour=NULL;
s_arret* nouv=NULL;

cour=liste;
while ( (cour!=NULL) && (strcmp(cour->nom, nom_arret)!=0)
cour=cour->suiv;

Co
rrig

if (cour == NULL) /* nom_arret n'est pas dans la liste */


{
nouv = (s_arret*) malloc(sizeof(s_arret));
if (nouv == NULL) {
printf("Problme d'allocation mmoire.\n");
exit (-1);
}
strcpy(nouv->nom, nom_arret);
nouv->suiv = liste;
liste = nouv;
}
return liste;

L'appel se ferait avec l'instruction :

retour = Ajoute_vrif(retour, cour1->nom);

Vous aimerez peut-être aussi