Structures
Exercice 1
Annuaire
Accueil

du site

Projet "Annuaire"

Le but des exercices qui suivent est de vous familiariser avec les pratiques professionnelles de programmation.

Nous prenons comme exemple la programmation d'un annuaire.
Nous allons créer un programme qui permet de saisir, revoir ou éliminer des fiches d'informations personnelles d'employés d'une entreprise.
Vous pourrez détourner cet annuaire pour vous en faire un mémento personnel des coordonnées de vos amis

C'est en quelque sorte une base de données.

Cet exercice vous donnera des exemples précis et concrets des notions que nous avons énoncées dans les cours précédents et même des notions à venir telles que l'enregistrement et lecture de fichiers ou la réservation dynamique de méméoire..

Dans un premier temps, l'aplication sera du type console et lancée soit sur MS DOS, soit comme une commande [Démarrer] [Exécuter] de Windows..

Par la suite, nous en ferons une application Windows à part entière avec menus déroulants et boîtes de dialogue.

Plus loin la notion de programmation orientée 'objet sera appliquée à ce programme.

Dès le départ, nous organiserons le logiciel de manière modulaire afin que de bonnes habitudes de programmation soient acquises d'entrée de jeu.

Programme principal : "Annuaire.cpp" - Commentaires -


Nous présentons d'abord le texte source du programme principal, puis nous le commenterons.

//*************************************************************
//Programme "ANNUAIRE"
//FICHIER : Annuaire.cpp
//Programme principal
//*************************************************************

#include <stdio.h>
//Prototypes pour printf() scanf() getchar()

#include "Fiche.h"
//Définition du type de variable "Fiche"
//Prototypes pour SaisieFiche() et VisuFiche()


int main()
{
//Déclarations de variables
//-------------------------
//Réservation en mémoire locale
//dans la section de code (dynamique)
//Disparaissent en fin de programme

char entree;

// Variable F de type "Fiche" déclarée dans Fiche.cpp
// donc en dehors du présent fichier "Annuaire.cpp"
// d'où le qualificatif de classe "extern"

extern Fiche F;

//Boucle d'invite :
//---------------

 do
 {
  printf("\n\n Annuaire \n");
  printf("=========================\n");
  printf("Choix a votre disposition\n");
  printf("Saisir une fiche : S\n");
  printf("Visualiser cette fiche : V\n");
  printf("Quitter : Q\n");
  printf("Entrer votre choix : ");

  scanf("%c",&entree);
  rewind(stdin);

  switch(entree)
  {
   case 'S' :
   case 's' : SaisieFiche(&F);
   break;

   case 'V' :
   case 'v' : VisuFiche(F);
   break;

   case 'Q' :
   case 'q' :
   printf("\nSaisie & Visualisation terminees.\n");
   break;

   default : printf("\nEntrez S, V ou Q !\n");
   break;

  }
 }while((entree != 'Q')&&(entree != 'q'));


 printf("Au revoir et merci de nous avoir fait confiance.\n");
 getchar();
 return 0;
}


Affichage après exécution (copie d'écran de l'exécution réelle):

A la première invite nous avons tapé 'Z' :


Commentaires.

Structure de base de l'annuaire et fichier d'entête "Fiche.h"


Le fichier annuaire définit le type de variable Fiche est défini dans le fichier "Fiche.h"
:

....
typedef struct
{
 char Nom [CAR_MAX_NOM + 1];
 char Prenom[CAR_MAX_NOM + 1];
 . . . . . . etc . . . . . . .
}Fiche;
....

Ne confondons pas , la variable F de type Fiche, utilisée dans Annuaire.cpp,
est déclarée dans Fiche.cpp.
Répétons que "Fiche.h" en définit seulement le type.

On ne déclare pas de variable dans un fichier "xxx.h"
car ce type de fichier est destiné à être inclus
- "include "xxx.h" - dans de nombreux fichiers "zzz.cpp"
et que la variable serait redéclarée à chaque fois
ce qui occasionnerait des erreurs graves.


Le fichier "Annuaire.cpp" fait appel à deux fonctions :

   ....
   case 'S' :
   case 's' : SaisieFiche(&F);
   break;

   case 'V' :
   case 'v' : VisuFiche(F);
   break;

   ....

Ce même fichier "Fiche.h" contient les prototypes des fonctions SaisieFiche() et VisuFiche()

....
//Variable Fiche pasée par pointeur
void SaisieFiche(Fiche *);
void VisuFiche(Fiche *);

//Variable Fiche pasée par référence
void SaisieFiche(Fiche &);
void VisuFiche(Fiche &);
....

Nous rappelons que les prototypes sont des "fonctions sans corps {... }"
Il permettent au programme qui appelle ces fonctions,
ici le programme principal dans "Annuaire.cpp",
de déterminer les types des paramètres utilisés.
Le compilateur peut ainsi contrôler s'il y a erreur.

Les prototypes s'écrivent toujours dans un fichier inclus.
Lire dans "Annuaire.cpp" :

  ....
  #include "Fiche.h"
  //Définition du type de variable "Fiche"
  //Prototypes pour SaisieFiche() et VisuFiche()
  ....

Fichier : "Fiche.h"

/*************************************************************
//Programme "ANNUAIRE"
//FICHIER Fiche.h (Fiche.h version 1)
//Définition des types de variables rattachées aux fiches de l'annuaire
//Prototypes des fonctions associées
//*************************************************************

//=============================================================================
//Définition d'une structure de fiche pour l'annuuaire
//-----------------------------------------------------------------------------
#define CAR_MAX_NOM 64
#define CAR_MAX_DATE 18
#define CAR_MAX_ADRESSE 128
#define CAR_MAX_OBSERV 128
#define CAR_MAX_TEL 20
#define CAR_MAX_COURRIEL 64

typedef struct
{
char Nom [CAR_MAX_NOM + 1];
char Prenom[CAR_MAX_NOM + 1];
char Sexe; //'F' ou 'M'
char DateNaissance[CAR_MAX_DATE + 1];
char Adresse [CAR_MAX_ADRESSE + 1];
char Ville [CAR_MAX_NOM + 1];
int  CodePostal;
char TelDom [CAR_MAX_TEL + 1];
char TelMobile[CAR_MAX_TEL + 1];
char TelBureau[CAR_MAX_TEL + 1];
char Courriel [CAR_MAX_COURRIEL + 1];
bool Cadre;
double Taille; //Unité à préciser : le mètre.
char Observations[CAR_MAX_OBSERV + 1];
}Fiche;

//N.B. : les +1 à cause des terminateurs de chaîne (0)
//=============================================================================

//=============================================================================
//Prototypes des fonctions définies dans "Fiche_v1.cpp"
//-----------------------------------------------------------------------------
//Variable Fiche pasée par pointeur
void SaisieFiche(Fiche *);
void VisuFiche(Fiche *);

//Variable Fiche pasée par référence
void SaisieFiche(Fiche &);
void VisuFiche(Fiche &);

On a intérêt à grouper dans un seul fichier toutes les informations concernant les fiches de notre annuaire.
Nnous verrons p lus tard que cette manière d'écrire les programmes nous menera progressivement et tout naturellement à la notion d'objet (programmation orientée objet).

Prenons de bonnes habitudes de programmation dès le départ !

 

Fiche.cpp

Les prototypes ne suffisent pas, il faut que les fonctions soient définies.
Elles le sont dans le fichier "Fiche.cpp"

//*************************************************************
//Programme "ANNUAIRE"
//FICHIER Fiche.cpp
//Définitions des fonctions relatives à "Fiche"
//*************************************************************

#include <stdio.h>
//Prototypes pour printf() scanf() getchar()

#include "Fiche.h"
//Définition de la variable "Fiche"


//Le fichier "Annuaire.cpp" fait appel, à la ligne 28,
//
à une variable de type "Fiche" :
//
extern Fiche F;

//Nous devons donc déclarer F quelque part.
//Fiche.cpp est le fichier idéal pou ce faire,
// car il contient tout ce qui a trait aux fiches.
//Voici sa déclaration :

Fiche F;

//Fonctions de saisie des fiches
//------------------------------


//Version variable Fiche pasée par pointeur
void SaisieFiche(Fiche * pF)
{
 char Car; printf("\n* Saisie d'une fiche *\n");
 printf("Nom : ");
 scanf("%s",pF->Nom);//pF->Nom = pointeur de chaîne de caractères
 rewind(stdin); //Pour éviter les entrées clavier surabondantes  printf("Prenom : ");
 scanf("%s",pF->Prenom);//pF->Prenom = pointeur de chaîne
 rewind(stdin); //Pour éviter les entrées clavier surabondantes  printf("Sexe : ");
 scanf("%c",&(pF->Sexe));//pF->Sexe est une caractère pas un pointeur
 rewind(stdin); //Pour éviter les entrées clavier surabondantes  printf("Taille : ");
 scanf("%lf",&(pF->Taille));
 rewind(stdin); printf("Cadre ? (O/N) : ");
 scanf("%c",&Car);
 if((Car=='O') || (Car=='o'))
  pF->Cadre = true;
 else
  pF->Cadre = false;

 rewind(stdin); //Pour éviter les entrées clavier surabondantes
 printf("----------------------\n\n");
}

//Version variable Fiche pasée par référence
void SaisieFiche(Fiche &F)
{
 char Car; printf("\n* Saisie d'une fiche *\n");
 printf("Nom : ");
 scanf("%s",F.Nom);//F.Nom = pointeur de chaîne de caractères
 rewind(stdin); //Pour éviter les entrées clavier surabondantes  printf("Prenom : ");
 scanf("%s",F.Prenom);//F.Prenom = pointeur de chaîne
 rewind(stdin); //Pour éviter les entrées clavier surabondantes  printf("Sexe : ");
 scanf("%c",&(F.Sexe));//F.Sexe est une caractère pas un pointeur
 rewind(stdin); //Pour éviter les entrées clavier surabondantes  printf("Taille : ");
 scanf("%lf",&(F.Taille));
 rewind(stdin); printf("Cadre ? (O/N) : ");
 scanf("%c",&Car);
 if((Car=='O') || (Car=='o'))
  F.Cadre = true;
 else
  F.Cadre = false;
 rewind(stdin); //Pour éviter les entrées clavier surabondantes  printf("----------------------\n\n");
}

//Fonctions de visualisation des fiches
//-------------------------------------

//Version variable Fiche pasée par pointeur
void VisuFiche(Fiche *pF)
{
 printf("\n* Visualisation d'une fiche *\n");
 printf("Nom : %s%c",pF->Nom,'\n');
 printf("Prenom : %s%c",pF->Prenom,'\n');  if(pF->Sexe=='F'||pF->Sexe=='f')
  printf("Sexe : Feminin\n");
 else
 {
  if(pF->Sexe=='M'||pF->Sexe=='m'||pF->Sexe=='H'||pF->Sexe=='h')
   printf("Sexe : Masculin\n");
  else
   printf("Sexe : Erreur de saisie\n");
}
 scanf("%c",&(pF->Sexe));//pF->Sexe est une caractère pas un pointeur
 rewind(stdin); //Pour éviter les entrées clavier surabondantes  printf("Taille : %4.2lf%c",pF->Taille,'\n');

 if(pF->Cadre)
  printf("Categorie : Cadre\n");
 else
  printf("Categorie : Non cadre\n");
  printf("----------------------\n\n");
}

//Version variable Fiche pasée par référence
void VisuFiche(Fiche &F)
{
 printf("\n* Visualisation d'une fiche *\n");
 printf("Nom : %s%c",F.Nom,'\n');
 printf("Prenom : %s%c",F.Prenom,'\n');

 if(F.Sexe=='F'||F.Sexe=='f')
  printf("Sexe : Feminin\n");
 else
 {
  if(F.Sexe=='M'||F.Sexe=='m'||F.Sexe=='H'||F.Sexe=='h')
  printf("Sexe : Masculin\n");
 else
  printf("Sexe : Erreur de saisie\n");
 }

 printf("Taille : %4.2lf%c",F.Taille,'\n');
 if(F.Cadre)
  printf("Categorie : Cadre\n");
 else
  printf("Categorie : Non cadre\n");
 printf("----------------------\n\n");
}

Ne vous étonnez pas que seuls les champs Nom, Prénom, Sexe, Taille et Catégorie
soient saisis dans nos procédures.
J'ai voulu faire simple et donner un exemple de saisie de types différents
(chaîne de caractères, caractère, double et booléen)
Je fais confiance au Lecteur qui saura compléter de lui-même les champs restants !


Voici les copies d'écran que nous avons obtenues en lançant ce programme :

Commentaires - Retour au texte-source -

Programme principal

Je pense que la première chose à faire dans un programme est le squelette de l'application avant même d'écrire les fonctions qui le constituent.
On peut ainsi présenter très rapidement cette esquisse au client et cela permet de dissiper bien des malentendus.

Options prises dans le programme précédent:

  1. Afficher le titre une fois au départ "Annuaire"
  2. Indiquer clairement à l'opérateur les choix à sa disposition, sans oublier la manière dont il peut sortir du programme.
  3. A chaque choix on confirme par une petite phrase du genre "Visualisation d'une fiche". Ceci rassure à la fois l'opérateur et le programmeur qui peut ainsi vérifier d'entrée que son programme aiguille bien les divers choix.
  4. On met en place les actions à faire dans chaque choix par des procédures générales du type : VisuFiche() - SaisieFiche() -
    Bien entendu, on ne peut pas tout faire en même temps, si bien que ces procédures sont actuellement vides : on les programmera après.
  5. On neutralise toute fausse manoeuvre de l'opérateur (s'il ne tape ni S ni V ni Q) en prévenant l'opérateur de son erreur tout en lui laisant une nouvelle chance de bien faire.

Rappelez-vous que vous devez éviter à tout prix que le programme ne "plante".
Pour cela prévoyez toutes les bêtises que peut faire un manipulateur non expérimenté !

Algorithme

Il est indispensable de construire le programme principal sous forme d' algorithme (ici do...while();) ne serait-ce que pour autoriser l'opérateur à se reprendre en cas d'erreur sans avoir à relancer le programme.

On a décidé que seule la frappe de 'Q' permettrait de quitter définitivement le programme, tant que ce n'est pas le cas, on repropose les quatre choix à l'opérateur.

Choix multiples

La structure de contrôle "switch( ) { case : ... default;}" permet d'aiguiller le programme sur les procédures correspondant aux choix de l'opérateur.

Ces procédures ne sont pas encore écrites à ce stade. Leur place dans l'algorithme est néanmoins réservée.
Chacune d'elles pourra être programmée indépendament de l'algorithme général, testée en lançant le programme de la même manière que le fera l'opérateur.

Cette manière de programmer assure une plus grande tranquillité de programmation en permettant de se concentrer sur un seul problème à la fois.

Les tests en situation permettent d'assurer facilement une grande fiabilité au produit.

Fichiers inclus

Le fichier stdio.h (standard input output) contient les définitions relatives à certaines procédures d'entrée-sortie clavier-écran telles que printf() scant() gentchar() puts() "put string" qui permet d'afficher une chaîne alphanumérique à l'écran etc...

Le fichier "conio.h" (console in out) contient d'autres procédures d'entée-sortie clavier-écran telles que getch() "get character" pui permet de récupérer la dernière frappe du clavier.

Le fichier "ctype.h" contient des procédures de conversion telles que "toupper(char c)" retourne la majuscule de c, ou "tolower(char c)" qui retourne la minuscule de c.

Toutes ces procédures font partie des bibliothèques livrées avec le compilateur.

Remarquer que tous les fichiers connus du compilateur sont inclus à l'aide des signes < et > comme dans :
#include < stdio.h >

Le fichier "fiche_v1.h" n'est pas un fichier de librairie : nous l'avons écrit nous-mêmes et enregistré dnas le répertoire courant où se trouve également la source "Annuaire_v1.cpp".
L'inclusion se fait alors avec des guillemets : #include "fiches1.h"

Texte source

Voir fichier "Fiche.h"


La suite d'Annuaire'
Sommaire Langage C
Accueil

du site