Ajouter solution_commentées_fin_exo_4/main.c
This commit is contained in:
parent
4e7104dd9b
commit
4e0abdcf4a
463
solution_commentées_fin_exo_4/main.c
Normal file
463
solution_commentées_fin_exo_4/main.c
Normal file
@ -0,0 +1,463 @@
|
||||
/**
|
||||
* Carnet d'adresses en C
|
||||
*
|
||||
* Ce programme implémente un carnet d'adresses simple permettant de :
|
||||
* - Ajouter des contacts avec leurs informations personnelles
|
||||
* - Afficher la liste des contacts
|
||||
* - Sauvegarder/charger les contacts depuis un fichier
|
||||
*
|
||||
* Concepts abordés :
|
||||
* - Structures en C
|
||||
* - Allocation dynamique de mémoire
|
||||
* - Manipulation de fichiers
|
||||
* - Saisie utilisateur
|
||||
* - Structures imbriquées
|
||||
*/
|
||||
|
||||
#include <stdio.h> // Entrées/sorties standard
|
||||
#include <stdlib.h> // Pour malloc, realloc, etc.
|
||||
#include <string.h> // Pour strtok, etc.
|
||||
|
||||
/* Définition des constantes */
|
||||
#define MAX_CONTACTS 100 // Nombre maximum de contacts initial
|
||||
#define MAX_NOM 50 // Longueur maximale pour un nom
|
||||
#define MAX_PRENOM 50 // Longueur maximale pour un prénom
|
||||
#define MAX_TELEPHONE 15 // Longueur maximale pour un numéro de téléphone
|
||||
#define MAX_RUE 100 // Longueur maximale pour le nom de rue
|
||||
#define MAX_CODE_POSTAL 10 // Longueur maximale pour un code postal
|
||||
#define MAX_VILLE 50 // Longueur maximale pour un nom de ville
|
||||
#define MAX_PAYS 50 // Longueur maximale pour un nom de pays
|
||||
#define MAX_TYPE_TEL 20 // Longueur maximale pour le type de téléphone
|
||||
#define MAX_TELEPHONES 3 // Nombre maximum de téléphones par contact
|
||||
|
||||
/* Définition des constantes pour le menu */
|
||||
#define CHOIX_AJOUTER 1 // Option pour ajouter un contact
|
||||
#define CHOIX_AFFICHER 2 // Option pour afficher les contacts
|
||||
#define CHOIX_RECHERHER 4 // Option pour rechercher (non implémentée)
|
||||
#define CHOIX_QUITTER 27 // Option pour quitter le programme
|
||||
|
||||
/**
|
||||
* Structure pour stocker un numéro de téléphone
|
||||
* Chaque téléphone contient un type (ex: "Mobile", "Travail") et un numéro
|
||||
*/
|
||||
typedef struct{
|
||||
char type[MAX_TYPE_TEL]; // Type de téléphone (Mobile, Domicile, etc.)
|
||||
char numero[MAX_TELEPHONE]; // Numéro de téléphone
|
||||
}Telephone;
|
||||
|
||||
/**
|
||||
* Structure pour stocker une adresse complète
|
||||
* Contient les informations classiques d'une adresse postale
|
||||
*/
|
||||
typedef struct{
|
||||
char rue[MAX_RUE]; // Numéro et nom de rue
|
||||
char codePostal[MAX_CODE_POSTAL]; // Code postal
|
||||
char ville[MAX_VILLE]; // Ville
|
||||
char pays[MAX_PAYS]; // Pays
|
||||
}adresse;
|
||||
|
||||
/**
|
||||
* Structure principale d'un contact
|
||||
* Contient les informations personnelles, téléphones et adresse
|
||||
*/
|
||||
typedef struct {
|
||||
char nom[MAX_NOM]; // Nom de famille
|
||||
char prenom[MAX_PRENOM]; // Prénom
|
||||
int nbtel; // Nombre de téléphones pour ce contact
|
||||
Telephone tel[MAX_TELEPHONES]; // Tableau de téléphones (max 3)
|
||||
adresse lieu; // Adresse du contact
|
||||
} Contact;
|
||||
|
||||
/* Exemple de code commenté mais non exécuté (pour démonstration)
|
||||
int a;
|
||||
Contact truc;
|
||||
truc.prenom = "valentin"; // Erreur: on ne peut pas affecter directement une chaîne à un tableau
|
||||
truc.lieu.ville="limoges"; // Erreur: même problème
|
||||
adresse mon_adresse;
|
||||
truc.lieu=mon_adresse; // OK: affectation de structure à structure
|
||||
*/
|
||||
|
||||
/* Prototypes des fonctions */
|
||||
/**
|
||||
* Ajoute un nouveau contact dans le tableau de contacts
|
||||
* @param contacts Tableau de contacts
|
||||
* @param nbContacts Pointeur vers le nombre actuel de contacts
|
||||
*/
|
||||
void ajouterContact(Contact *contacts, int *nbContacts);
|
||||
|
||||
/**
|
||||
* Affiche tous les contacts existants
|
||||
* @param contacts Tableau de contacts
|
||||
* @param nbContacts Nombre actuel de contacts
|
||||
*/
|
||||
void afficherContacts(Contact *contacts, int nbContacts);
|
||||
|
||||
/**
|
||||
* Sauvegarde les contacts dans un fichier texte au format CSV
|
||||
* @param contacts Tableau de contacts à sauvegarder
|
||||
* @param nbContacts Nombre de contacts
|
||||
* @param filename Nom du fichier de sauvegarde
|
||||
*/
|
||||
void sauvegarderContacts(Contact *contacts, int nbContacts, const char *filename);
|
||||
|
||||
/**
|
||||
* Charge les contacts depuis un fichier
|
||||
* @param contacts Tableau de contacts à remplir
|
||||
* @param nbContacts Pointeur vers le nombre de contacts (sera modifié)
|
||||
* @param filename Nom du fichier à charger
|
||||
* @param capacite Pointeur vers la capacité du tableau (pour agrandir si nécessaire)
|
||||
*/
|
||||
void chargerContacts(Contact *contacts, int *nbContacts, const char *filename, int *capacite);
|
||||
|
||||
/**
|
||||
* Agrandit le tableau de contacts quand il est plein
|
||||
* @param contacts Pointeur vers le pointeur du tableau (double pointeur car on modifie le pointeur)
|
||||
* @param capacite Pointeur vers la capacité actuelle (sera modifié)
|
||||
*/
|
||||
void agrandirTableauContacts(Contact **contacts, int *capacite);
|
||||
|
||||
/**
|
||||
* Fonction principale
|
||||
*/
|
||||
int main() {
|
||||
Contact *contacts; // Déclaration du pointeur vers le tableau de contacts
|
||||
|
||||
// Allocation dynamique initiale du tableau de contacts
|
||||
contacts = malloc(MAX_CONTACTS * sizeof(Contact));
|
||||
|
||||
int capacite = MAX_CONTACTS; // Capacité initiale du tableau
|
||||
|
||||
// Vérification de l'allocation mémoire
|
||||
if (contacts == NULL) {
|
||||
printf("L'allocation mémoire n'a pas marché \n");
|
||||
return 1; // Sortie avec code d'erreur
|
||||
}
|
||||
|
||||
int nbContacts = 0; // Initialisation du nombre de contacts
|
||||
|
||||
// Chargement des contacts depuis le fichier
|
||||
chargerContacts(contacts, &nbContacts, "contacts.txt", &capacite);
|
||||
|
||||
int choix;
|
||||
do {
|
||||
// Affichage du menu
|
||||
printf("\n%d. Ajouter un contact\n", CHOIX_AJOUTER);
|
||||
printf("%d. Afficher les contacts\n", CHOIX_AFFICHER);
|
||||
printf("%d. Quitter\n", CHOIX_QUITTER);
|
||||
printf("Votre choix : ");
|
||||
scanf("%d", &choix);
|
||||
getchar(); // Pour éviter le problème de buffer avec scanf (consomme le '\n')
|
||||
|
||||
// Traitement du choix de l'utilisateur
|
||||
switch (choix) {
|
||||
case CHOIX_AJOUTER:
|
||||
ajouterContact(contacts, &nbContacts);
|
||||
sauvegarderContacts(contacts, nbContacts, "contacts.txt");
|
||||
break;
|
||||
case CHOIX_AFFICHER:
|
||||
afficherContacts(contacts, nbContacts);
|
||||
break;
|
||||
case CHOIX_QUITTER:
|
||||
printf("Au revoir !\n");
|
||||
break;
|
||||
default:
|
||||
printf("Choix invalide, veuillez réessayer.\n");
|
||||
}
|
||||
} while (choix != 3); // ATTENTION: Incohérence avec CHOIX_QUITTER=27
|
||||
|
||||
// Libération de la mémoire (MANQUANTE dans le code original !)
|
||||
// free(contacts); // Cette ligne devrait être ajoutée
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction pour ajouter un contact au carnet d'adresses
|
||||
* Demande à l'utilisateur de saisir toutes les informations nécessaires
|
||||
*/
|
||||
void ajouterContact(Contact *contacts, int *nbContacts) {
|
||||
// Vérification si le tableau est plein
|
||||
if (*nbContacts >= MAX_CONTACTS) {
|
||||
printf("Le carnet d'adresses est plein !\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Saisie du nom
|
||||
printf("Nom : ");
|
||||
fgets(contacts[*nbContacts].nom, 50, stdin);
|
||||
strtok(contacts[*nbContacts].nom, "\n"); // Supprime le caractère newline
|
||||
|
||||
// Saisie du prénom
|
||||
printf("Prénom : ");
|
||||
fgets(contacts[*nbContacts].prenom, 50, stdin);
|
||||
strtok(contacts[*nbContacts].prenom, "\n");
|
||||
|
||||
// Saisie du nombre de téléphones
|
||||
printf("Combien de numéros de téléphone à ajouter ? (min 1 max 3)");
|
||||
scanf("%d", &contacts[*nbContacts].nbtel);
|
||||
getchar(); // Consomme le caractère newline
|
||||
|
||||
// Validation du nombre de téléphones
|
||||
while (contacts[*nbContacts].nbtel < 1 || contacts[*nbContacts].nbtel > 3) {
|
||||
printf("Combien de numéros de téléphone à ajouter ? (min 1 max 3)");
|
||||
scanf("%d", &contacts[*nbContacts].nbtel);
|
||||
getchar();
|
||||
}
|
||||
|
||||
// Saisie des informations pour chaque téléphone
|
||||
for (int i = 0; i < contacts[*nbContacts].nbtel; i++) {
|
||||
printf("Téléphone n° %d: ", i+1);
|
||||
fgets(contacts[*nbContacts].tel[i].numero, 15, stdin);
|
||||
strtok(contacts[*nbContacts].tel[i].numero, "\n");
|
||||
|
||||
printf("Type du téléphone n° %d: ", i+1);
|
||||
fgets(contacts[*nbContacts].tel[i].type, 20, stdin);
|
||||
strtok(contacts[*nbContacts].tel[i].type, "\n");
|
||||
}
|
||||
|
||||
// Saisie des informations d'adresse
|
||||
printf("Rue: ");
|
||||
fgets(contacts[*nbContacts].lieu.rue, 100, stdin);
|
||||
strtok(contacts[*nbContacts].lieu.rue, "\n");
|
||||
|
||||
printf("Code Postal: ");
|
||||
fgets(contacts[*nbContacts].lieu.codePostal, 10, stdin);
|
||||
strtok(contacts[*nbContacts].lieu.codePostal, "\n");
|
||||
|
||||
printf("ville: ");
|
||||
fgets(contacts[*nbContacts].lieu.ville, 50, stdin);
|
||||
strtok(contacts[*nbContacts].lieu.ville, "\n");
|
||||
|
||||
printf("Pays: ");
|
||||
fgets(contacts[*nbContacts].lieu.pays, 50, stdin);
|
||||
strtok(contacts[*nbContacts].lieu.pays, "\n");
|
||||
|
||||
// Incrémentation du nombre de contacts
|
||||
(*nbContacts)++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction pour afficher tous les contacts enregistrés
|
||||
* Le format d'affichage dépend du nombre de téléphones
|
||||
*/
|
||||
void afficherContacts(Contact *contacts, int nbContacts) {
|
||||
// Vérification s'il y a des contacts à afficher
|
||||
if (nbContacts == 0) {
|
||||
printf("Aucun contact enregistré.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parcours et affichage de tous les contacts
|
||||
for (int i = 0; i < nbContacts; i++) {
|
||||
// Format d'affichage différent selon le nombre de téléphones
|
||||
switch (contacts[i].nbtel) {
|
||||
case 1:
|
||||
// Contact avec 1 téléphone
|
||||
printf("%d. %s %s - %s:%s - %s %s %s %s\n", i + 1,
|
||||
contacts[i].nom,
|
||||
contacts[i].prenom,
|
||||
contacts[i].tel[0].type,
|
||||
contacts[i].tel[0].numero,
|
||||
contacts[i].lieu.rue,
|
||||
contacts[i].lieu.codePostal,
|
||||
contacts[i].lieu.ville,
|
||||
contacts[i].lieu.pays);
|
||||
break;
|
||||
case 2:
|
||||
// Contact avec 2 téléphones
|
||||
printf("%d. %s %s - %s:%s - %s:%s - %s %s %s %s\n", i + 1,
|
||||
contacts[i].nom,
|
||||
contacts[i].prenom,
|
||||
contacts[i].tel[0].type,
|
||||
contacts[i].tel[0].numero,
|
||||
contacts[i].tel[1].type,
|
||||
contacts[i].tel[1].numero,
|
||||
contacts[i].lieu.rue,
|
||||
contacts[i].lieu.codePostal,
|
||||
contacts[i].lieu.ville,
|
||||
contacts[i].lieu.pays);
|
||||
break;
|
||||
case 3:
|
||||
// Contact avec 3 téléphones
|
||||
printf("%d. %s %s - %s:%s - %s:%s- %s:%s - %s %s %s %s\n", i + 1,
|
||||
contacts[i].nom,
|
||||
contacts[i].prenom,
|
||||
contacts[i].tel[0].type,
|
||||
contacts[i].tel[0].numero,
|
||||
contacts[i].tel[1].type,
|
||||
contacts[i].tel[1].numero,
|
||||
contacts[i].tel[2].type,
|
||||
contacts[i].tel[2].numero,
|
||||
contacts[i].lieu.rue,
|
||||
contacts[i].lieu.codePostal,
|
||||
contacts[i].lieu.ville,
|
||||
contacts[i].lieu.pays);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction pour sauvegarder les contacts dans un fichier CSV
|
||||
* Le format de sauvegarde dépend du nombre de téléphones
|
||||
*/
|
||||
void sauvegarderContacts(Contact *contacts, int nbContacts, const char *filename) {
|
||||
// Ouverture du fichier en mode écriture
|
||||
FILE *file = fopen(filename, "w");
|
||||
if (!file) {
|
||||
printf("Erreur d'ouverture du fichier.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Écriture de chaque contact dans le fichier
|
||||
for (int i = 0; i < nbContacts; i++) {
|
||||
// Format d'écriture différent selon le nombre de téléphones
|
||||
switch (contacts[i].nbtel) {
|
||||
case 1:
|
||||
// Contact avec 1 téléphone (les champs vides sont représentés par des ';' consécutifs)
|
||||
fprintf(file, "%s;%s;%s;%s;;;;;%s;%s;%s;%s\n",
|
||||
contacts[i].nom,
|
||||
contacts[i].prenom,
|
||||
contacts[i].tel[0].type,
|
||||
contacts[i].tel[0].numero,
|
||||
contacts[i].lieu.rue,
|
||||
contacts[i].lieu.codePostal,
|
||||
contacts[i].lieu.ville,
|
||||
contacts[i].lieu.pays);
|
||||
break;
|
||||
case 2:
|
||||
// Contact avec 2 téléphones
|
||||
fprintf(file, "%s;%s;%s;%s;%s;%s;;;%s;%s;%s;%s\n",
|
||||
contacts[i].nom,
|
||||
contacts[i].prenom,
|
||||
contacts[i].tel[0].type,
|
||||
contacts[i].tel[0].numero,
|
||||
contacts[i].tel[1].type,
|
||||
contacts[i].tel[1].numero,
|
||||
contacts[i].lieu.rue,
|
||||
contacts[i].lieu.codePostal,
|
||||
contacts[i].lieu.ville,
|
||||
contacts[i].lieu.pays);
|
||||
break;
|
||||
case 3:
|
||||
// Contact avec 3 téléphones
|
||||
fprintf(file, "%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s\n",
|
||||
contacts[i].nom,
|
||||
contacts[i].prenom,
|
||||
contacts[i].tel[0].type,
|
||||
contacts[i].tel[0].numero,
|
||||
contacts[i].tel[1].type,
|
||||
contacts[i].tel[1].numero,
|
||||
contacts[i].tel[2].type,
|
||||
contacts[i].tel[2].numero,
|
||||
contacts[i].lieu.rue,
|
||||
contacts[i].lieu.codePostal,
|
||||
contacts[i].lieu.ville,
|
||||
contacts[i].lieu.pays);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fermeture du fichier
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction pour charger les contacts depuis un fichier CSV
|
||||
* Gère les différents formats selon le nombre de téléphones
|
||||
*/
|
||||
void chargerContacts(Contact *contacts, int *nbContacts, const char *filename, int *capacite) {
|
||||
// Ouverture du fichier en mode lecture
|
||||
FILE *file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
printf("Fichier introuvable\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialisation du compteur de contacts
|
||||
*nbContacts = 0;
|
||||
char ligne[500]; // Buffer pour lire une ligne du fichier
|
||||
|
||||
// Lecture du fichier ligne par ligne
|
||||
while (*nbContacts < *capacite && fgets(ligne, sizeof(ligne), file)) {
|
||||
// Tentative de lecture d'un contact avec 1 téléphone
|
||||
if (sscanf(ligne, "%49[^;];%49[^;];%19[^;];%14[^;];;;;;%99[^;];%9[^;];%49[^;];%49[^\n]",
|
||||
contacts[*nbContacts].nom,
|
||||
contacts[*nbContacts].prenom,
|
||||
contacts[*nbContacts].tel[0].type,
|
||||
contacts[*nbContacts].tel[0].numero,
|
||||
contacts[*nbContacts].lieu.rue,
|
||||
contacts[*nbContacts].lieu.codePostal,
|
||||
contacts[*nbContacts].lieu.ville,
|
||||
contacts[*nbContacts].lieu.pays) == 8)
|
||||
{
|
||||
contacts[*nbContacts].nbtel = 1;
|
||||
(*nbContacts)++;
|
||||
}
|
||||
// Tentative de lecture d'un contact avec 2 téléphones
|
||||
else if (sscanf(ligne, "%49[^;];%49[^;];%19[^;];%14[^;];%19[^;];%14[^;];;;%99[^;];%9[^;];%49[^;];%49[^\n]",
|
||||
contacts[*nbContacts].nom,
|
||||
contacts[*nbContacts].prenom,
|
||||
contacts[*nbContacts].tel[0].type,
|
||||
contacts[*nbContacts].tel[0].numero,
|
||||
contacts[*nbContacts].tel[1].type,
|
||||
contacts[*nbContacts].tel[1].numero,
|
||||
contacts[*nbContacts].lieu.rue,
|
||||
contacts[*nbContacts].lieu.codePostal,
|
||||
contacts[*nbContacts].lieu.ville,
|
||||
contacts[*nbContacts].lieu.pays) == 10)
|
||||
{
|
||||
contacts[*nbContacts].nbtel = 2;
|
||||
(*nbContacts)++;
|
||||
}
|
||||
// Tentative de lecture d'un contact avec 3 téléphones
|
||||
else if (sscanf(ligne, "%49[^;];%49[^;];%19[^;];%14[^;];%19[^;];%14[^;];%19[^;];%14[^;];%99[^;];%9[^;];%49[^;];%49[^\n]",
|
||||
contacts[*nbContacts].nom,
|
||||
contacts[*nbContacts].prenom,
|
||||
contacts[*nbContacts].tel[0].type,
|
||||
contacts[*nbContacts].tel[0].numero,
|
||||
contacts[*nbContacts].tel[1].type,
|
||||
contacts[*nbContacts].tel[1].numero,
|
||||
contacts[*nbContacts].tel[2].type,
|
||||
contacts[*nbContacts].tel[2].numero,
|
||||
contacts[*nbContacts].lieu.rue,
|
||||
contacts[*nbContacts].lieu.codePostal,
|
||||
contacts[*nbContacts].lieu.ville,
|
||||
contacts[*nbContacts].lieu.pays) == 12)
|
||||
{
|
||||
contacts[*nbContacts].nbtel = 3;
|
||||
(*nbContacts)++;
|
||||
}
|
||||
|
||||
// Vérification si le tableau est plein et agrandissement si nécessaire
|
||||
if (*nbContacts >= *capacite) {
|
||||
agrandirTableauContacts(&contacts, capacite);
|
||||
}
|
||||
}
|
||||
|
||||
// Fermeture du fichier
|
||||
fclose(file);
|
||||
printf("%d contacts chargés avec succès.\n", *nbContacts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction pour agrandir le tableau de contacts
|
||||
* Double la capacité du tableau quand il est plein
|
||||
*/
|
||||
void agrandirTableauContacts(Contact **contacts, int *capacite) {
|
||||
// Calcul de la nouvelle capacité (double de l'ancienne)
|
||||
int nouvelleCapacite = (*capacite) * 2;
|
||||
|
||||
// Réallocation du tableau avec la nouvelle taille
|
||||
Contact *pointeurContactTemporaire = realloc(*contacts, nouvelleCapacite * sizeof(Contact));
|
||||
|
||||
// Vérification si la réallocation a réussi
|
||||
if (pointeurContactTemporaire == NULL) {
|
||||
printf("La réallocation mémoire n'a pas fonctionné\n");
|
||||
} else {
|
||||
// Mise à jour de la capacité et du pointeur
|
||||
*capacite = nouvelleCapacite;
|
||||
*contacts = pointeurContactTemporaire;
|
||||
printf("Réallocation mémoire réussie. Nouvelle capacité = %d\n", *capacite);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user