Exercices corrigés td4 algorithmique et programmation 2 gest
Télécharger PDFAlgorithmique et Programmation 2
Ce document est un support de Travaux Dirigés (TD n°4) pour le module I132 : Algorithmique et programmation 2, destiné aux étudiants du parcours MIP (S3) pour l'année universitaire 2017/2018, préparé par Pr. S. ANTER.
Description de l'Exercice : Gestion d'un Groupe d'Étudiants
L'exercice propose de manipuler un groupe d'étudiants. Chaque étudiant est représenté par la structure suivante en langage C :
typedef struct {
char nom [20];
char prenom [20];
float note ;
} Etudiant ;
Cette structure définit un type `Etudiant` contenant le nom, le prénom et la note d'un étudiant. Le groupe d'étudiants est défini comme un tableau de taille fixe :
#define NMAX 5
Etudiant groupe [ NMAX ] ;
Les questions suivantes demandent de définir différentes fonctions pour gérer ce groupe d'étudiants :
- Définir la fonction `Etudiant lire()` permettant de créer et de retourner un étudiant dont le nom, le prénom et la note sont lus au clavier.
- Définir la fonction `Etudiant creer(char* nom, char* prenom, float note)` permettant de créer et de retourner un étudiant dont le nom, le prénom et la note sont passés en arguments.
- Définir la fonction `void afficher(Etudiant e)` permettant d'afficher l'étudiant
epassé en paramètre. - Définir la fonction `void lire_groupe(Etudiant groupe[], int n)` permettant de remplir le tableau
groupe(supposé déjà créé) par des étudiants dont les données sont lues au clavier (penser à utiliser la fonction `lire`). - En utilisant le formalisme pointeur, définir la fonction `void afficher_groupe(Etudiant groupe[], int n)` permettant d'afficher tous les étudiants du groupe.
- Définir la fonction `float moyenne(Etudiant groupe[], int n)` recevant en arguments un tableau d'étudiants ainsi que leur nombre et retournant la moyenne de toutes les notes des étudiants.
- Définir la fonction `Etudiant getMajorant(Etudiant groupe[], int n)` permettant de renvoyer l'étudiant majorant du groupe (celui ayant la meilleure note).
- Définir la fonction `float getNote(Etudiant groupe[], int n, char* nom)` permettant de retourner la note de l'étudiant dont le nom est passé en argument (-1 si ce nom n'existe pas).
- Définir la fonction `void trier_par_note(Etudiant groupe[], int n)` permettant de trier les étudiants par ordre croissant de leurs notes.
- Définir la fonction `void trier_par_nom(Etudiant groupe[], int n)` permettant de trier les étudiants par ordre croissant de leurs noms.
- Définir la fonction `void augmenter(Etudiant groupe[], int n)` permettant d'augmenter de 2 la note de tous les étudiants dont le nom commence par "AL".
- Définir la fonction `void sauvegarder(Etudiant groupe[], int n, char* nom_fichier)` permettant de sauvegarder les informations de tous les étudiants dans un fichier texte.
- Définir la fonction `void sauvegarder_bin(Etudiant groupe[], int n, char* nom_fichier)` permettant de sauvegarder les informations de tous les étudiants dans un fichier binaire.
- Définir la fonction `void lire_bin(char* nom_fichier, int n)` permettant de lire et d'afficher le contenu du fichier binaire dont le nom est passé en argument.
- Donner un programme principal (`main`) de test.
Corrigé du TD n°4 - Exercice 1
Ce corrigé fournit les implémentations des fonctions demandées ainsi qu'un programme principal pour les tester.
Structure et Inclusions
#include <stdio.h>
#include <string.h>
#define NMAX 5
typedef struct {
char nom [20];
char prenom [20];
float note ;
} Etudiant ;
Les en-têtes `stdio.h` sont nécessaires pour les opérations d'entrée/sortie standard, et `string.h` pour la manipulation des chaînes de caractères (comparaison, etc.). `NMAX` est une constante qui définit la taille maximale du groupe d'étudiants.
Fonction `lire()` : Lecture d'un Étudiant
Etudiant lire () {
Etudiant E;
printf ("Nom : ") ;
scanf ("%s",E.nom) ;
printf ("Prénom : ") ;
scanf ("%s",E.prenom) ;
printf (" Note : ") ;
scanf ("%f" ,&E.note) ;
return E;
}
Cette fonction lit le nom, le prénom et la note d'un étudiant depuis l'entrée standard (clavier) et retourne une structure `Etudiant` initialisée avec ces valeurs. Pour des raisons de sécurité, l'utilisation de `fgets` plutôt que `scanf` pour les chaînes est généralement recommandée afin d'éviter les débordements de tampon.
Fonction `lire_groupe()` : Remplir le Groupe d'Étudiants
void lire_groupe ( Etudiant groupe [] , int n) {
int i;
for (i=0;i<n;i++) {
printf ("\nÉtudiant %d : \n",i+1) ;
groupe [i]= lire () ;
}
}
Cette fonction itère `n` fois, appelant `lire()` à chaque tour de boucle pour remplir séquentiellement un tableau d'étudiants. Le paramètre `n` spécifie le nombre d'étudiants à lire.
Fonction `afficher_groupe()` : Affichage du Groupe d'Étudiants (avec pointeurs)
void afficher_groupe ( Etudiant groupe [] , int n) {
Etudiant * p;
for (p= groupe ;p< groupe +n;p++) {
printf ("Nom : %s ",p->nom) ;
printf (" Prénom : %s ",p->prenom) ;
printf (" Note : %f\n",p->note) ;
}
}
Cette fonction parcourt le tableau d'étudiants en utilisant un pointeur (`p`) pour accéder et afficher les informations de chaque étudiant. L'opérateur `->` est utilisé pour accéder aux membres de la structure via un pointeur.
Fonction `moyenne()` : Calcul de la Moyenne du Groupe
float moyenne ( Etudiant groupe [] , int n) {
float s=0;
int i;
for (i=0;i<n;i++)s+= groupe [i]. note ;
return s/n;
}
Elle calcule la somme des notes de tous les étudiants et la divise par leur nombre (`n`) pour obtenir la moyenne du groupe. Il est important de s'assurer que `n` n'est pas nul pour éviter une division par zéro.
Fonction `getMajorant()` : Trouver l'Étudiant Majorant
Etudiant getMajorant ( Etudiant groupe [] , int n) {
int i,k=0;
for (i=1;i<n;i++)
if ( groupe [i]. note > groupe [k]. note ) k=i;
return groupe [k];
}
Cette fonction identifie et retourne l'étudiant ayant la note la plus élevée dans le groupe. Elle initialise l'indice `k` à 0 (le premier étudiant) et met à jour `k` si un étudiant ultérieur (`groupe[i]`) a une note supérieure à celle de l'étudiant actuellement considéré comme majorant (`groupe[k]`).
Fonction `getNote()` : Récupérer la Note par Nom
float getNote ( Etudiant groupe [] , int n, char * nom) {
int i;
for (i=0;i<n;i++)
if ( strcmp ( groupe [i]. nom ,nom ) ==0) return groupe [i]. note ;
return -1;
}
Elle recherche un étudiant par son nom. La fonction `strcmp()` est utilisée pour comparer les chaînes de caractères. Si le nom est trouvé, la note de l'étudiant est retournée. Si aucun étudiant ne correspond au nom donné, la fonction retourne -1.
Fonction `trier_par_note()` : Trier les Étudiants par Note
void trier_par_note ( Etudiant groupe [] , int n) {
int i, j, k;
Etudiant aux;
for (i=0;i<n -1;i++) {
k=i;
for (j=i+1;j<n;j++) if ( groupe [j]. note < groupe [k]. note ) k=j;
aux= groupe [i];
groupe [i]= groupe [k];
groupe [k]= aux ;
}
}
Cette fonction implémente un algorithme de tri par sélection. Elle parcourt le tableau, trouve l'étudiant avec la note minimale dans la partie non triée et l'échange avec l'élément courant, triant ainsi les étudiants par ordre croissant de leurs notes.
Fonction `trier_par_nom()` : Trier les Étudiants par Nom
void trier_par_nom ( Etudiant groupe [] , int n) {
int i, j, k;
Etudiant aux;
for (i=0;i<n -1;i++) {
k=i;
for (j=i+1;j<n;j++) if ( strcmp ( groupe [j]. nom , groupe [k]. nom) <0) k=j;
aux= groupe [i];
groupe [i]= groupe [k];
groupe [k]= aux ;
}
}
Similaire à `trier_par_note`, cette fonction utilise également un tri par sélection. La différence majeure est qu'elle utilise `strcmp()` pour comparer les noms des étudiants, permettant ainsi de les trier par ordre alphabétique croissant.
Fonction `augmenter()` : Augmenter les Notes des Étudiants Commençant par "AL"
void augmenter ( Etudiant groupe [] , int n) {
int i;
for (i=0;i<n;i++)
if ( strncmp ( groupe [i]. nom ,"AL" ,2) ==0) groupe [i]. note +=2;
}
Cette fonction parcourt le groupe et augmente de 2 points la note de tout étudiant dont le nom commence par la séquence de caractères "AL". La fonction `strncmp()` est utilisée pour comparer un nombre spécifié de caractères au début de la chaîne.
Fonction `sauvegarder()` : Sauvegarder dans un Fichier Texte
void sauvegarder ( Etudiant groupe [] , int n, char * nom_fichier ) {
FILE * f;
int i;
f= fopen ( nom_fichier ,"w") ;
for (i=0;i<n;i++)
fprintf (f,"%s %s %.2f\n",groupe [i]. nom , groupe [i]. prenom , groupe [i]. note ) ;
fclose (f) ;
}
Ouvre un fichier en mode écriture (`"w"`), puis écrit les informations de chaque étudiant (nom, prénom, note formatée à deux décimales) sur une nouvelle ligne dans ce fichier texte. Il est crucial de toujours vérifier si `fopen` retourne `NULL` pour gérer les erreurs potentielles d'ouverture de fichier. N'oubliez pas de fermer le fichier avec `fclose()`.
Fonction `sauvegarder_bin()` : Sauvegarder dans un Fichier Binaire
void sauvegarder_bin ( Etudiant groupe [] , int n, char * nom_fichier ) {
FILE * f;
int i;
f= fopen ( nom_fichier ,"wb") ;
fwrite (groupe , sizeof ( Etudiant ) ,n,f) ;
fclose (f) ;
}
Ouvre un fichier en mode écriture binaire (`"wb"`) et écrit l'intégralité du tableau `groupe` en une seule opération, en utilisant `fwrite`. C'est une méthode efficace pour stocker des structures de données directement dans leur format mémoire, ce qui est souvent plus rapide et plus compact que le format texte.
Fonction `lire_bin()` : Lire et Afficher depuis un Fichier Binaire
void lire_bin ( char * nom_fichier , int n) {
FILE * f;
Etudiant groupe [ NMAX ];
f = fopen ( nom_fichier ,"rb") ;
fread (groupe , sizeof ( Etudiant ) ,n,f) ;
fclose (f) ;
afficher_groupe (groupe ,n) ;
}
Ouvre un fichier en mode lecture binaire (`"rb"`), lit les données binaires et les place dans un tableau `groupe` local. Ensuite, elle appelle `afficher_groupe()` pour afficher les étudiants lus. Il est crucial que la taille de `NMAX` dans `lire_bin` corresponde à la taille des données écrites par `sauvegarder_bin` pour une lecture correcte.
Programme Principal (`main`) de Test
int main () {
Etudiant groupe [ NMAX ];
char nom [20];
int n;
// La fonction 'creer' et la fonction 'afficher(Etudiant e)' ont été demandées mais ne sont pas implémentées dans ce corrigé.
// Etudiant e;
// e= lire () ;
// afficher (e) ; // Cette fonction n'est pas fournie
// e= creer ("Alami","Yasser",15) ; // Cette fonction n'est pas fournie
// afficher (e) ; // Cette fonction n'est pas fournie
printf (" Donner le nombre d'étudiants :") ;
scanf ("%d" ,&n) ;
lire_groupe (groupe ,n) ;
printf("\n--- Affichage du groupe ---\n");
afficher_groupe (groupe ,n) ;
printf ("Moyenne du groupe : %f\n",moyenne (groupe ,n) ) ;
printf ("Le majorant du groupe est : \n") ;
Etudiant majorant = getMajorant(groupe, n);
printf("Nom: %s, Prénom: %s, Note: %.2f\n", majorant.nom, majorant.prenom, majorant.note);
printf ("Donner le nom recherché:") ;
scanf ("%s",nom) ;
printf ("La note de %s est %.2f\n",nom , getNote (groupe ,n,nom ) ) ;
trier_par_note (groupe ,n) ;
sauvegarder (groupe ,n,"data1.txt") ; // Tri par note, puis sauvegarde
printf("\n--- Groupe trié par note et sauvegardé dans data1.txt ---\n");
afficher_groupe(groupe, n);
trier_par_nom (groupe ,n) ;
sauvegarder (groupe ,n,"data2.txt") ; // Tri par nom, puis sauvegarde
printf("\n--- Groupe trié par nom et sauvegardé dans data2.txt ---\n");
afficher_groupe(groupe, n);
augmenter (groupe ,n) ;
sauvegarder (groupe ,n,"data3.txt") ; // Augmentation des notes, puis sauvegarde
printf("\n--- Notes augmentées et groupe sauvegardé dans data3.txt ---\n");
afficher_groupe(groupe, n);
sauvegarder_bin (groupe ,n,"data.bin") ; // Sauvegarde binaire
printf("\n--- Groupe sauvegardé dans data.bin ---\n");
printf("\n--- Lecture et affichage depuis data.bin ---\n");
lire_bin ("data.bin",n) ; // Lecture et affichage depuis le fichier binaire
}
Le programme principal (`main`) orchestre les appels aux différentes fonctions pour démontrer leur fonctionnement. Il permet de lire des étudiants, afficher le groupe, calculer la moyenne, trouver le majorant, rechercher une note, puis effectue des tris, des modifications et des sauvegardes/lectures dans des fichiers texte et binaires.
Note : Les fonctions `creer()` et `afficher(Etudiant e)` ont été demandées dans l'énoncé mais ne sont pas fournies dans le corrigé ci-dessus. Pour un programme de test complet, il serait nécessaire de les implémenter. Les appels à ces fonctions dans le `main` ont été commentés, et une alternative de `printf` a été utilisée pour afficher l'étudiant majorant.
Foire Aux Questions (FAQ)
Qu'est-ce qu'une structure (`struct`) en C et à quoi sert `typedef` ?
Une structure en C est un type de données composite qui permet de regrouper plusieurs variables de types différents sous un même nom. Elle est utile pour représenter des entités complexes, comme un étudiant avec son nom, prénom et sa note. Le mot-clé `typedef` est utilisé pour créer un alias (un nouveau nom plus simple) pour un type de données existant, rendant le code plus lisible et plus facile à maintenir.
Quelle est la meilleure façon de gérer les chaînes de caractères lors de la lecture des entrées en C ?
Dans cet exercice, `scanf("%s", ...)` est utilisé pour lire les chaînes. Cependant, cette fonction peut entraîner des problèmes de sécurité, notamment des débordements de tampon, si l'entrée utilisateur est plus longue que la taille allouée pour la chaîne. Il est généralement recommandé d'utiliser `fgets()` avec `stdin` pour lire les chaînes, car elle permet de spécifier une taille maximale à lire, évitant ainsi les débordements.
Quelle est la différence entre la sauvegarde en fichier texte et en fichier binaire ?
La sauvegarde en fichier texte (`"w"`) écrit les données sous forme de caractères lisibles par un humain. Cela implique une conversion des types de données (par exemple, un `float` est converti en une séquence de caractères). La sauvegarde en fichier binaire (`"wb"`) écrit directement la représentation mémoire des données. Ce mode est généralement plus rapide et plus compact car aucune conversion n'est nécessaire, mais le fichier n'est pas lisible directement et nécessite la même structure pour être relu correctement avec des fonctions comme `fread()`.