463 lines
17 KiB
C

/**
* 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);
}
}