-ed- C is a sharp tool Profil : Jeune recrue | aaargh a écrit :
Voici le code que l'on a fait j'ai tout mis ca fait surement bcp la !
|
Oui, tu aurais pu réduire au problème précis. Tant pis, tu vas te prendre une revue de code, ça ne fait pas de mal...
Citation :
il y a 600lignes en gros, maintenant on a des structures, comptes, banques ... ce que l'on doit faire c'est insérer les mots de passe pour les comptes : l'ecran indique qu'il faut que le titulaire rentre un mot de passe qu'il le confirme, puis a chaque utilisation du code il faut lui redemander et verifier s'il est bon, on veut faire un seul code pour chaque titulaire, qui pourra avoir plusieur comptes.
Sinon on doit pouvoir faire des virements d'un compte a l'autre mais c'est lamot de passe qui nous embete plus !
voilà j'espere vraiment que l'on pourra nous aider .
|
Voilà du code assez bien fait. Il y a quelques points à revoir, notamment au niveau des saisies, mais c'est plutôt bien analysé et bien construit, dans un esprit OO.
- Attention, la sauvegarde des données 'brutes' n'est pas portable.
http://mapage.noos.fr/emdel/notes.htm#enreg_struct
- Les entrées sont basées sur fgets(). C'est bien, mais c'est insuffisant. Il faut ensuite (et pas avant) nettoyer le flux si nécessaire et en profiter pour supprimer le \n. Je recommande la fonction fclean() (code minimum ci-après)
- Attention a ne pas sur-dimensionner les chaines de saisie (1k dans la mémoire auto à chaque fois, c'est beaucoup). La taille devrait être déterminée avec l'opérateur sizeof (tableaux statiques).
- Il est préférable de n'avoir qu'un return par fonction. Le code est plus clair et il y a moins de risque d'erreur de libération de ressource.
Ton code commenté et corrigé.
Code :
- /*
- Voici le code que l'on a fait j'ai tout mis ca fait surement bcp la !
- il y a 600lignes en gros, maintenant on a des structures, comptes, banques ...
- ce que l'on doit faire c'est insérer les mots de passe pour les comptes : l'ecran indique qu'il faut que le titulaire rentre un mot de passe qu'il le confirme, puis a chaque utilisation du code il faut lui redemander et verifier s'il est bon, on veut faire un seul code pour chaque titulaire, qui pourra avoir plusieur comptes.
- Sinon on doit pouvoir faire des virements d'un compte a l'autre mais c'est lamot de passe qui nous embete plus !
- voilà j'espere vraiment que l'on pourra nous aider .
- Aaargh
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <time.h>
- #define LONG_TITU 40
- #define MAX_COMPTES 256
- #define NB_OPS 4
- /* codage des operations */
- #define NO_OP 0
- #define OUVERTURE 1
- #define DEPOT 2
- #define RETRAIT 3
- #define CLOTURE 4
- /* codage des etats de compte */
- #define LIBRE 0
- #define OUVERT 1
- #define CLOS 2
- /* -ed-
- #ifdef linux
- #include <stdio_ext.h>
- #define PURGE(X) __fpurge(X)
- #else
- #ifdef __DARWIN_NULL
- #define PURGE(X) fpurge(X)
- #else
- #define PURGE(X) fflush(X)
- #endif
- #endif
-
- Non ! fflush() n'est defini que pour les flux entrants...
- */
- /* -ed- a appeler apres un fgets() */
- static void fclean (char *s, FILE * fp)
- {
- char *p = strchr (s, '\n');
- if (p != NULL)
- {
- *p = 0;
- }
- else
- {
- int c;
- while ((c = fgetc (fp)) != '\n' && c != EOF)
- {
- }
- }
- }
- /**************************************************************/
- /* le type "operation" */
- struct operation
- {
- double montant;
- int type; /* NO_OP, OUVERTURE... */
- time_t date; /* date au format "systeme" */
- };
- /* le type "compte" */
- struct compte
- {
- int numero;
- char titulaire[LONG_TITU];
- int etat; /* LIBRE, OUVERT, CLOS */
- double solde;
- struct operation ops[NB_OPS];
- };
- /* NB : dans le tableau ops, les operations sont classees par */
- /* ordre de saisie decroissant, la derniere operation saisie */
- /* est toujours ops[0] */
- /* le type "agence" */
- struct agence
- {
- double solde;
- int num_prochain_compte;
- struct compte comptes[MAX_COMPTES];
- };
- /**************************************************************/
- /* fonction d'initialisation de l'agence */
- /**************************************************************/
- /* -ed-
- void raz_agence (struct agence *ag)
-
- Fonction non exportee, donc 'static'
- */
- static void raz_agence (struct agence *ag)
- {
- int i;
- ag->solde = 0.;
- ag->num_prochain_compte = 0;
- for (i = 0; i < MAX_COMPTES; i++)
- ag->comptes[i].etat = LIBRE;
- }
- /* fonction de remise a zero d'un compte (utilise par purge) */
- static void raz_compte (struct compte *cpt)
- {
- int i;
- cpt->numero = 0;
- memset (cpt->titulaire, 0, LONG_TITU);
- cpt->etat = 0;
- cpt->solde = 0.;
- for (i = 0; i < NB_OPS; i++)
- {
- cpt->ops[i].montant = 0.;
- cpt->ops[i].type = NO_OP;
- cpt->ops[i].date = 0;
- }
- }
- /**************************************************************/
- /* fonctions de lecture/ecriture d'une agence dans un fichier */
- /**************************************************************/
- /* -ed-
- int charge_agence (char *nomfichier, struct agence *ag)
-
- voir main()
- */
- static int charge_agence (char const *nomfichier, struct agence *ag)
- {
- FILE *pf;
- size_t sz;
- int status;
- /* on ouvre le fichier en lecture seule */
- pf = fopen (nomfichier, "r" );
- if (pf == NULL)
- return -1;
- sz = sizeof (struct agence);
- /* on lit une structure de taille sz que l'on */
- /* stocke a l'adresse indiquee par ag */
- if (fread (ag, sz, 1, pf) == 1)
- status = 0;
- else
- status = -1;
- fclose (pf);
- return status;
- }
- /* -ed-
- int sauve_agence (char *nomfichier, struct agence *ag)
-
- voir main().
- */
- static int sauve_agence (char const *nomfichier, struct agence *ag)
- {
- FILE *pf;
- size_t sz;
- int status;
- /* on ouvre le fichier en (re)ecriture */
- pf = fopen (nomfichier, "w" );
- if (pf == NULL)
- return -1;
- sz = sizeof (struct agence);
- /* on ecrit la structure de taille sz stockee */
- /* a l'adresse indiquee par ag */
- if (fwrite (ag, sz, 1, pf) == 1)
- status = 0;
- else
- status = -1;
- fclose (pf);
- return status;
- }
- /*******************************************************/
- /* Diverses fonctions de recherche */
- /*******************************************************/
- /* le resultat est l'adresse du compte, NULL en cas de */
- /* non-existence du compte. Attention : le compte peut */
- /* etre CLOS ! */
- /* fonction de recherche d'un compte par son numero */
- static struct compte *cherche_cpt_num (struct agence *ag, int numcpt)
- {
- int i;
- for (i = 0; i < MAX_COMPTES; i++)
- if (((ag->comptes[i].etat == OUVERT) ||
- (ag->comptes[i].etat == CLOS)) &&
- (ag->comptes[i].numero == numcpt))
- return &(ag->comptes[i]);
- return 0;
- }
- /* fonction de recherche d'un compte par son titulaire */
- static struct compte *cherche_cpt_titu (struct agence *ag, char *titu)
- {
- int i;
- for (i = 0; i < MAX_COMPTES; i++)
- if (((ag->comptes[i].etat == OUVERT) ||
- (ag->comptes[i].etat == CLOS)) &&
- (!strcmp (ag->comptes[i].titulaire, titu)))
- return &(ag->comptes[i]);
- return 0;
- }
- /* fonction de recherche d'un compte libre */
- static struct compte *cherche_cpt_libre (struct agence *ag)
- {
- int i;
- for (i = 0; i < MAX_COMPTES; i++)
- if (ag->comptes[i].etat == LIBRE)
- return &(ag->comptes[i]);
- return 0;
- }
- /*******************************************************/
- /* fonctions de traitement */
- /*******************************************************/
- /* ouverture d'un compte pour titu a la date t */
- /* la fonction rend : numero de compte si tout est OK, */
- /* -1 si l'agence est "complete", -2 si le titulaire a */
- /* deja un compte */
- static int traite_ouverture (struct agence *ag, char *titu, time_t t)
- {
- int i;
- struct compte *cpt;
- /* on verifie d'abord que le titulaire n'a pas */
- /* deja un compte */
- cpt = cherche_cpt_titu (ag, titu);
- if (cpt)
- return -2;
- cpt = cherche_cpt_libre (ag);
- if (!cpt)
- return -1;
- /* on remplit les champs du compte cree */
- cpt->numero = ag->num_prochain_compte++;
- strncpy (cpt->titulaire, titu, LONG_TITU - 1);
- cpt->etat = OUVERT;
- cpt->solde = 0.;
- /* on remplit l'operation 0 de type OUVERTURE */
- cpt->ops[0].type = OUVERTURE;
- cpt->ops[0].date = t;
- cpt->ops[0].montant = 0.;
- /* on remplit les operations suivantes avec NO_OP */
- for (i = 1; i < NB_OPS; i++)
- cpt->ops[i].type = NO_OP;
- return cpt->numero;
- }
- /* fonction de traitement de l'operation op sur le compte */
- /* de numero numcpt de l'agence ag (op != OUVERTURE) */
- static int traite_operation (struct agence *ag, int numcpt,
- struct operation *op)
- {
- int i;
- struct compte *cpt;
- /* on cherche le compte de numero numcpt */
- cpt = cherche_cpt_num (ag, numcpt);
- /* test de validite : compte inexistant ou CLOS */
- if ((cpt == 0) || (cpt->etat == CLOS))
- return -1;
- switch (op->type)
- {
- case DEPOT:
- cpt->solde += op->montant;
- ag->solde += op->montant;
- break;
- case RETRAIT:
- if (cpt->solde < op->montant)
- return -1;
- cpt->solde -= op->montant;
- ag->solde -= op->montant;
- break;
- case CLOTURE:
- if (cpt->solde != 0)
- return -1;
- cpt->etat = CLOS;
- break;
- default:
- return -1;
- }
- /* on "decale" les operations du tableau ops */
- for (i = NB_OPS - 2; i >= 0; i--)
- cpt->ops[i + 1] = cpt->ops[i];
- cpt->ops[0] = *op;
- return 0;
- }
- /* fonction d'affichage du solde de l'agence */
- static void solde_agence (struct agence *ag)
- {
- printf ("Le solde de l'agence est %.2f\n", ag->solde);
- }
- /* fonction de "purge" de l'agence : libere les comptes */
- /* CLOS avant la date t */
- static void purge_agence (struct agence *ag, time_t t)
- {
- int i, nb;
- for (i = 0, nb = 0; i < MAX_COMPTES; i++)
- /* si le compte est CLOS, et que la cloture a eu */
- /* lieu avant "cur", on remet a zero le compte */
- if ((ag->comptes[i].etat == CLOS) && (ag->comptes[i].ops[0].date < t))
- {
- printf ("Purge du compte %d\n", ag->comptes[i].numero);
- raz_compte (&(ag->comptes[i]));
- nb++;
- }
- printf ("%d comptes purges\n", nb);
- }
- /* effectue un releve de l'operation op. le format est : */
- /* JJ/MM/AAAA HH:MM ouverture/cloture/[depot,retrait] de XX */
- /* on utilise localtime pour convertir les dates */
- static void releve_operation (struct operation *op)
- {
- struct tm *d;
- if (op->type == NO_OP)
- return;
- d = localtime (&(op->date));
- if (d == 0)
- fputs ("\tXX/XX/XXXX XX:XX ", stdout);
- else
- printf ("\t%02d/%02d/%04d %02d:%02d ",
- d->tm_mday, d->tm_mon + 1, d->tm_year + 1900,
- d->tm_hour, d->tm_min);
- switch (op->type)
- {
- case OUVERTURE:
- fputs ("ouverture\n", stdout);
- return;
- case CLOTURE:
- fputs ("cloture\n", stdout);
- return;
- case DEPOT:
- printf ("depot de %.2f E\n", op->montant);
- return;
- case RETRAIT:
- printf ("retrait de %.2f E\n", op->montant);
- return;
- }
- }
- /* fonction de releve du compte de numero numcpt */
- /* on affiche les informations du compte, puis les NB_OPS */
- /* (au plus) dernieres operations */
- static int releve_compte (struct agence *ag, int numcpt)
- {
- struct compte *cpt;
- int i;
- cpt = cherche_cpt_num (ag, numcpt);
- if (!cpt)
- return -1;
- printf ("Titulaire : %s\n", cpt->titulaire);
- printf ("Compte %d", cpt->numero);
- if (cpt->etat == CLOS)
- fputs (" [CLOTURE]\n", stdout);
- else
- printf (", solde %.2f E\n", cpt->solde);
- for (i = NB_OPS - 1; i >= 0; i--)
- releve_operation (&(cpt->ops[i]));
- return 0;
- }
- /*********************************************************/
- /* Diverses fonctions de saisie au clavier */
- /* ces fonctions rendent -1 en cas d'annulation (CTRL-D */
- /* frappe au clavier), sinon elles insistent indefiniment*/
- /* pour avoir une saisie "correcte" */
- /*********************************************************/
- static int saisie_num_cpt (void)
- {
- int num;
- char rep[128];
- for (;;)
- {
- fputs ("Numero de compte" " (CTRL-D pour annuler) ? ", stdout);
- if (!fgets (rep, sizeof rep, stdin))
- {
- /* -ed- fonction non standard. */
- clearerr (stdin);
- return -1;
- }
- fclean (rep, stdin);
- if (sscanf (rep, "%d", &num) == 1)
- return num;
- }
- }
- static int saisie_code_op (void)
- {
- char rep[1024];
- for (;;)
- {
- fputs ("D(epot), R(etrait), C(loture)"
- " (CTRL-D pour annuler) ? ", stdout);
- if (!fgets (rep, sizeof rep, stdin))
- {
- clearerr (stdin);
- return -1;
- }
- fclean (rep, stdin);
- switch (rep[0])
- {
- case 'D':
- return DEPOT;
- case 'R':
- return RETRAIT;
- case 'C':
- return CLOTURE;
- default:
- break;
- }
- }
- }
- static int saisie_titulaire (char *titu, size_t size)
- {
- fputs ("Titulaire (CTRL-D pour annuler) ? ", stdout);
- if (!fgets (titu, size, stdin))
- {
- clearerr (stdin);
- return -1;
- }
- fclean (titu, stdin);
- return 0;
- }
- static int saisie_montant (double *v)
- {
- char rep[32];
- for (;;)
- {
- fputs ("Montant" " (CTRL-D pour annuler) ? ", stdout);
- if (!fgets (rep, sizeof rep, stdin))
- {
- clearerr (stdin);
- return -1;
- }
- fclean (rep, stdin);
- if (sscanf (rep, "%lf", v) == 1)
- return 1;
- }
- }
- /* fonction de saisie de date */
- /* la date est saisie sous la forme JJ/MM/AAAA HH:MM */
- /* la fonction propose la date courante, si l'utilisateur*/
- /* ne tape rien (<Return> ou CTRL-D), on accepte cette */
- /* date courante */
- static time_t saisie_date (void)
- {
- time_t t;
- struct tm *d, buf;
- char rep[32];
- for (;;)
- {
- t = time (0);
- d = localtime (&t);
- fputs ("Date ", stdout);
- if (d)
- printf ("(%02d/%02d/%04d %02d:%02d) ? ",
- d->tm_mday, 1 + d->tm_mon, d->tm_year + 1900,
- d->tm_hour, d->tm_min);
- if (!fgets (rep, sizeof rep, stdin) || (rep[0] == '\n'))
- {
- clearerr (stdin);
- return t;
- }
- fclean (rep, stdin);
- if (sscanf (rep, " %d/%d/%d %d:%d",
- &(buf.tm_mday), &(buf.tm_mon), &(buf.tm_year),
- &(buf.tm_hour), &(buf.tm_min)) == 5)
- {
- buf.tm_mon--;
- buf.tm_year -= 1900;
- buf.tm_sec = 0;
- buf.tm_isdst = -1;
- return mktime (&buf);
- }
- }
- }
- /*********************************************************/
- /* Les differents menus pour saisir les infos et traiter */
- /*********************************************************/
- static void menu_recherche (struct agence *ag)
- {
- char titu[LONG_TITU];
- struct compte *cpt;
- int num;
- for (;;)
- {
- puts ("[Comptes/Recherche de compte]" );
- if (saisie_titulaire (titu, sizeof titu) == -1)
- return;
- cpt = cherche_cpt_titu (ag, titu);
- if (cpt)
- {
- printf ("compte %d, titulaire %s\n", cpt->numero, cpt->titulaire);
- return;
- }
- /* on essaie d'interpreter le titulaire */
- /* comme un numero de compte */
- if (sscanf (titu, "%d", &num) == 1)
- {
- cpt = cherche_cpt_num (ag, num);
- if (cpt)
- {
- printf ("compte %d, titulaire %s\n", cpt->numero, cpt->titulaire);
- return;
- }
- }
- fputs ("NON TROUVE\n", stdout);
- return;
- }
- }
- static void menu_saisie_op (struct agence *ag)
- {
- struct operation op;
- int num_cpt;
- for (;;)
- {
- puts ("[Comptes/Saisie d'operation]" );
- num_cpt = saisie_num_cpt ();
- if (num_cpt == -1)
- return;
- op.type = saisie_code_op ();
- if (op.type == -1)
- return;
- if (op.type != CLOTURE)
- if (saisie_montant (&(op.montant)) == -1)
- return;
- op.date = saisie_date ();
- if (traite_operation (ag, num_cpt, &op) == -1)
- printf ("Echec du traitement !\n" );
- else
- printf ("Traitement effectue !\n" );
- return;
- }
- }
- static void menu_releve (struct agence *ag)
- {
- int num_cpt;
- for (;;)
- {
- puts ("[Comptes/Releve de compte]" );
- num_cpt = saisie_num_cpt ();
- if (num_cpt == -1)
- return;
- if (releve_compte (ag, num_cpt) == -1)
- fputs ("COMPTE INEXISTANT\n", stdout);
- return;
- }
- }
- static void menu_ouverture (struct agence *ag)
- {
- char titu[LONG_TITU];
- int num;
- time_t t;
- for (;;)
- {
- puts ("[Comptes/Ouverture]" );
- if (saisie_titulaire (titu, sizeof titu) == -1)
- return;
- t = saisie_date ();
- switch (num = traite_ouverture (ag, titu, t))
- {
- case -2:
- puts ("CE TITULAIRE A DEJA UN COMPTE" );
- return;
- case -1:
- puts ("L'AGENCE EST COMPLETE" );
- return;
- default:
- printf ("compte %d cree\n", num);
- return;
- }
- }
- }
- static void menu_purge (struct agence *ag)
- {
- time_t tpurge;
- char dummy[4];
- puts ("[ATTENTION : purge des comptes (CTRL-D pour annuler)]" );
- if (!fgets (dummy, sizeof dummy, stdin))
- {
- clearerr (stdin);
- return;
- }
- fclean (dummy, stdin);
- tpurge = saisie_date ();
- purge_agence (ag, tpurge);
- }
- static void menu_comptes (struct agence *ag)
- {
- char rep[4];
- int choix;
- for (;;)
- {
- puts ("[Comptes]" );
- puts ("(1) recherche d'un numero de compte" );
- puts ("(2) saisie d'une operation" );
- puts ("(3) releve de compte" );
- puts ("(4) ouverture de compte" );
- puts ("(0) sortie" );
- fputs ("--> ", stdout);
- if (!fgets (rep, 1024, stdin))
- {
- clearerr (stdin);
- return;
- }
- fclean (rep, stdin);
- if (sscanf (rep, "%d", &choix) != 1)
- continue;
- switch (choix)
- {
- case 0:
- return;
- case 1:
- menu_recherche (ag);
- break;
- case 2:
- menu_saisie_op (ag);
- break;
- case 3:
- menu_releve (ag);
- break;
- case 4:
- menu_ouverture (ag);
- break;
- default:
- printf ("Mauvais choix %s !\n", rep);
- break;
- }
- }
- }
- static void menu_principal (struct agence *ag)
- {
- char rep[4];
- int choix;
- for (;;)
- {
- puts ("(1) consultation du solde agence" );
- puts ("(2) acces au menu 'comptes'" );
- puts ("(3) purge des comptes" );
- puts ("(4) SORTIE IMMEDIATE SANS SAUVEGARDE" );
- puts ("(5) remise a zero de l'agence" );
- printf ("(0) sortie\n--> " );
- if (!fgets (rep, sizeof rep, stdin))
- {
- clearerr (stdin);
- continue;
- }
- fclean (rep, stdin);
- if (sscanf (rep, "%d", &choix) != 1)
- continue;
- switch (choix)
- {
- case 0:
- return;
- case 1:
- solde_agence (ag);
- break;
- case 2:
- menu_comptes (ag);
- break;
- case 3:
- menu_purge (ag);
- break;
- case 4:
- exit (1);
- /*NOTREACHED*/ return;
- case 5:
- raz_agence (ag);
- break;
- default:
- break;
- }
- }
- return;
- }
- int main (int argc, char *argv[])
- {
- /* -ed-
- char *fic_agence;
-
- attention, une chaine litterale n'est pas modifiable.
- Il est preferable de qualifier en const (lecture seule).
- */
- char const *fic_agence;
- struct agence ag;
- if (argc == 1)
- fic_agence = "agence.dat";
- else
- fic_agence = argv[1];
- if (charge_agence (fic_agence, &ag) == -1)
- {
- char rep[4];
- perror (fic_agence);
- printf ("Initialise une agence vide (o/n) ?\n" );
- if (fgets (rep, sizeof rep, stdin) == NULL)
- {
- perror ("stdin" );
- fprintf (stderr, "STOP !!!\n" );
- return 2;
- }
- fclean (rep, stdin);
- if (rep[0] == 'o' || rep[0] == 'O' || rep[0] == 'y' || rep[0] == 'Y')
- raz_agence (&ag);
- else
- {
- fprintf (stderr, "STOP !!!\n" );
- return 2;
- }
- }
- menu_principal (&ag);
- if (sauve_agence (fic_agence, &ag) == -1)
- {
- perror (fic_agence);
- return 1;
- }
- return 0;
- }
|
Au fait, pas une ligne sur ton histoire de mot de passe. De plus, c'est pas très clair. il y a déjà unproblème de spec. En effet, Un mot de passe 'cient' n'a de sens que si le client consulte son compte. Or
d'une part, l'ergonomie est pas organisée en 'client/action', mais en action/client ce qui veut dire demander le numéro de lient à cjhaque opération.
Si il s'agit d'ajouter une fonction 'consultation par le client, il faut imaginer une succession d'écrans comme ceci :
Mon compte
-----------
- Compte existant
Nom : Mot de passe : - Nouveau compte
Nom : Mot de passe : Confirmation mot de passe : Opérations
----------
- Consultation
- Impression solde
- Impression relevé
- Quitter
|
quelque chose comme ça.
C'est à dire totalement autre chose (une autre application en faite) mais qui travaille sur le même fichier que celui de la banque.
C'est une application de gestion classique...
Message édité par -ed- le 04-12-2006 à 21:03:05 ---------------
Emmanuel Delahaye
Des infos sur la programmation et le langage C:
http://bien-programmer.blogspot.com/ http://mapage.noos.fr/emdel/
|