/** * 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 // Entrées/sorties standard #include // Pour malloc, realloc, etc. #include // 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 3 // 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); free(contacts); 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); } }