Le gestionnaire repose sur une structure double niveau : une entité Personne encapsulant les données individuelles, et un conteneur Annuaire agrégeant ces entités avec un compteur de population.
Structure des données
typedef struct {
char identifiant[NOM_TAILLE];
int annees;
char genre[GENRE_TAILLE];
char numero[TELEPHONE_TAILLE];
char localisation[ADRESSE_TAILLE];
} Personne;
typedef struct {
Personne repertoire[CAPACITE];
int effectif;
} Annuaire;
Interface utilisateur
L'interaction se fait via une boucle infinie pilotée par un menu numéroté. Les opérations sont dispatchées par une énumération pour éviter les valeurs magiques.
typedef enum {
QUITTER = 0,
AJOUTER,
SUPPRIMER,
CONSULTER,
EDITER,
AFFICHER,
TRIER
} Commande;
void afficher_menu(void) {
printf("╔══════════════════════════════════════╗\n");
printf("║ 1. Insérer 2. Retirer ║\n");
printf("║ 3. Chercher 4. Mettre à jour ║\n");
printf("║ 5. Lister 6. Ordonner ║\n");
printf("║ 0. Terminer ║\n");
printf("╚══════════════════════════════════════╝\n");
}
Cycle de vie de l'annuaire
Initialisation
void preparer_annuaire(Annuaire* cible) {
assert(cible != NULL);
cible->effectif = 0;
memset(cible->repertoire, 0, sizeof(cible->repertoire));
}
Insertion d'un contact
La vérification de capacité précède la saisie séquentielle des champs. L'index d'insertion correspond à la position courante du compteur.
void inserer_personne(Annuaire* cible) {
assert(cible);
if (cible->effectif >= CAPACITE) {
printf("Capacité maximale atteinte\n");
return;
}
Personne* emplacement = &cible->repertoire[cible->effectif];
printf("Nom : ");
scanf("%s", emplacement->identifiant);
printf("Âge : ");
scanf("%d", &emplacement->annees);
printf("Sexe : ");
scanf("%s", emplacement->genre);
printf("Téléphone : ");
scanf("%s", emplacement->numero);
printf("Adresse : ");
scanf("%s", emplacement->localisation);
cible->effectif++;
printf("Enregistrement effectué\n");
}
Recherche et accès
Un service interne localise les entrées par correspondance nominale exacte. Il retourne l'indice ou une valeur sentinelle négative.
static int localiser_par_nom(const Annuaire* source, const char* reference) {
for (int position = 0; position < source->effectif; position++) {
if (strcmp(source->repertoire[position].identifiant, reference) == 0) {
return position;
}
}
return -1;
}
void consulter_personne(const Annuaire* source) {
assert(source);
char critere[NOM_TAILLE];
printf("Nom recherché : ");
scanf("%s", critere);
int position = localiser_par_nom(source, critere);
if (position < 0) {
printf("Aucune correspondance\n");
return;
}
const Personne* trouvee = &source->repertoire[position];
printf("%-20s %-4s %-6s %-14s %-25s\n",
"Nom", "Âge", "Sexe", "Téléphone", "Adresse");
printf("%-20s %-4d %-6s %-14s %-25s\n",
trouvee->identifiant, trouvee->annees,
trouvee->genre, trouvee->numero, trouvee->localisation);
}
Mutations
Suppression par décalage
L'effacement conserve l'ordre physique par translation des éléments suivants vers la gauche.
void retirer_personne(Annuaire* cible) {
assert(cible);
if (cible->effectif == 0) {
printf("Annuaire vide\n");
return;
}
char critere[NOM_TAILLE];
printf("Nom à supprimer : ");
scanf("%s", critere);
int position = localiser_par_nom(cible, critere);
if (position < 0) {
printf("Entrée introuvable\n");
return;
}
for (int curseur = position; curseur < cible->effectif - 1; curseur++) {
cible->repertoire[curseur] = cible->repertoire[curseur + 1];
}
cible->effectif--;
printf("Suppression confirmée\n");
}
Modification in-place
void actualiser_personne(Annuaire* cible) {
assert(cible);
char critere[NOM_TAILLE];
printf("Nom à modifier : ");
scanf("%s", critere);
int position = localiser_par_nom(cible, critere);
if (position < 0) {
printf("Entrée inexistante\n");
return;
}
Personne* cible_modif = &cible->repertoire[position];
printf("Nouveau nom : ");
scanf("%s", cible_modif->identifiant);
printf("Nouvel âge : ");
scanf("%d", &cible_modif->annees);
printf("Nouveau sexe : ");
scanf("%s", cible_modif->genre);
printf("Nouveau téléphone : ");
scanf("%s", cible_modif->numero);
printf("Nouvelle adresse : ");
scanf("%s", cible_modif->localisation);
printf("Mise à jour effectuée\n");
}
Présentation et organisation
Affichage tabulaire
void lister_contacts(const Annuaire* source) {
assert(source);
if (source->effectif == 0) {
printf("Aucun contact enregistré\n");
return;
}
printf("%-20s %-4s %-6s %-14s %-25s\n",
"Nom", "Âge", "Sexe", "Téléphone", "Adresse");
for (int position = 0; position < source->effectif; position++) {
const Personne* courant = &source->repertoire[position];
printf("%-20s %-4d %-6s %-14s %-25s\n",
courant->identifiant, courant->annees,
courant->genre, courant->numero, courant->localisation);
}
}
Tri par ordre alphabétique
L'algorithme de tri à bulles réorganise le tableau selon la comparaison lexicographique des identifiants.
void ordonner_repertoire(Annuaire* cible) {
for (int limite = cible->effectif - 1; limite > 0; limite--) {
for (int courant = 0; courant < limite; courant++) {
Personne* premier = &cible->repertoire[courant];
Personne* suivant = &cible->repertoire[courant + 1];
if (strcmp(premier->identifiant, suivant->identifiant) > 0) {
Personne tampon = *premier;
*premier = *suivant;
*suivant = tampon;
}
}
}
printf("Tri alphabétique terminé\n");
}
Programme principal
int main(void) {
Annuaire carnet;
preparer_annuaire(&carnet);
int instruction = 0;
do {
afficher_menu();
printf("Votre choix : ");
scanf("%d", &instruction);
switch (instruction) {
case QUITTER:
printf("Fermeture du programme\n");
break;
case AJOUTER:
inserer_personne(&carnet);
break;
case SUPPRIMER:
retirer_personne(&carnet);
break;
case CONSULTER:
consulter_personne(&carnet);
break;
case EDITER:
actualiser_personne(&carnet);
break;
case AFFICHER:
lister_contacts(&carnet);
break;
case TRIER:
ordonner_repertoire(&carnet);
break;
default:
printf("Option non reconnue\n");
}
} while (instruction != QUITTER);
return 0;
}
Limites et évolutions
L'implémentation actuelle utilise un tableau de taille fixe. L'allocation dynamique via malloc/realloc permettrait une capacité extensible à la volée. La persistance sur disque pourrait être ajoutée par sérialisation dans un fichier texte ou binaire.