code de débutant, ça tient debout
Le
bpascal123
Bonjour cyberespace,
Pour une fois, ce code fonctionne. J'ai une version sans pointeurs ni
fonctions d'écriture de fichier, dans tout les cas, le mécanisme est
le même. Je ne vois pas pour ce code ce que les pointeurs peuvent
apporter de plus mais peut-être c'est un avantage de connaître un peu
les pointeurs sans avoir envie d'aller trop loin dans ce langage.
Je cherche juste à savoir si je prends de bonnes habitudes, c'est
surtout au niveau de la saisie.
Merci
/*
Ce prg cree un fichier avec des enregistrements dont le nombre varie
selon ce qu'entre l'utilisateur.
*/
#include <stdio.h> /* getchar putchar getc printf fprint fopen fclose
*/
#include <stdlib.h> /* strtol */
#define CMAXREC 20 /* nbr d'enreg. max*/
#define CMAXCAR 30 /* nbr de caracteres max. */
void ReadTxt(char FTxt[]) ;
void ReadSaveToFile(FILE *FP_FILE) ;
void ReadFile1(FILE *FP_FILE) ;
void ReadFile2(FILE *FP_FILE) ; /* fscanf fprintf printf */
long int ConvToDigit(char FTxt[]) ;
int main(void)
{
FILE *MP_FILE ;
char MP_Name[] = "/media/XP/code_c/FamFile.txt" ;
printf("Ce prg cree un fichier avec des enregistrements dont le nbr
varie"
"selon ce qu'entre l'utilisateur.") ;
if ((MP_FILE = fopen(MP_Name, "w")) == NULL)
{
printf("Erreur ouverture fichier.") ;
exit(EXIT_FAILURE) ;
}
ReadSaveToFile(MP_FILE) ;
fclose(MP_FILE) ;
if ((MP_FILE = fopen(MP_Name, "r")) == NULL)
{
printf("Erreur de lecture du fichier") ;
exit(EXIT_FAILURE) ;
}
ReadFile1(MP_FILE) ;
fclose(MP_FILE) ;
printf("") ;
return 0 ;
}
void ReadTxt(char FTxt[])
{
int i ;
int c ;
for (i = 0 ; ((c = getchar()) != '') ; i++)
{
if (i < CMAXCAR)
FTxt[i] = c ;
else
{
while(getchar() != '') ;
break ;
}
}
FTxt[i] = '\0' ;
}
void ReadSaveToFile(FILE *FP_FILE)
{
char MFBuff[CMAXCAR] ;
char MFPrePere[CMAXCAR] ;
char MFPreMere[CMAXCAR] ;
char MFPreEnf[CMAXCAR] ;
char rep1 ;
int nb_rec, i ;
long int nb_enf ;
rep1 = 'x' ;
nb_rec = 0 ;
do
{
printf("Enregistrement (o/n) ? ") ;
rep1 = getc(stdin) ;
while (getchar() != '') ;
if (rep1 == 'o' && nb_rec < CMAXREC)
{
printf("Prenom du pere : ") ;
ReadTxt(MFPrePere) ;
printf("Prenom de la mere : ") ;
ReadTxt(MFPreMere) ;
fprintf(FP_FILE, "%s%s", MFPrePere, MFPreMere) ;
printf("Nombre d'enfants : ") ;
ReadTxt(MFBuff) ;
nb_enf = ConvToDigit(MFBuff) ;
if (nb_enf > 0)
{
for (i = 0 ; i < nb_enf ; i++)
{
printf("Enfant %d : ", i+1) ;
ReadTxt(MFPreEnf) ;
fprintf(FP_FILE, "%s", MFPreEnf) ;
nb_rec++ ;
}
}
nb_rec++ ;
}
} while (rep1 == 'o') ;
}
long int ConvToDigit(char FTxt[])
{
char *p ;
long int rslt ;
rslt = strtol(FTxt, &p, 10) ;
return rslt ;
}
void ReadFile1(FILE *FP_FILE)
{
int c ;
while ((c = getc(FP_FILE)) != EOF)
putchar(c) ;
}
void ReadFile2(FILE *FP_FILE) /* Pour info : ca ne marche car le nbr
de prenom enfant est variable donc different de 3 (variable déclarée)
*/
{
char FPrePere[CMAXCAR] ;
char FPreMere[CMAXCAR] ;
char FPreEnf[CMAXCAR] ;
while (fscanf(FP_FILE, "%s%s%s", FPrePere, FPreMere, FPreEnf) == 3)
printf("%s%s%s", FPrePere, FPreMere,FPreEnf) ;
}
Pour une fois, ce code fonctionne. J'ai une version sans pointeurs ni
fonctions d'écriture de fichier, dans tout les cas, le mécanisme est
le même. Je ne vois pas pour ce code ce que les pointeurs peuvent
apporter de plus mais peut-être c'est un avantage de connaître un peu
les pointeurs sans avoir envie d'aller trop loin dans ce langage.
Je cherche juste à savoir si je prends de bonnes habitudes, c'est
surtout au niveau de la saisie.
Merci
/*
Ce prg cree un fichier avec des enregistrements dont le nombre varie
selon ce qu'entre l'utilisateur.
*/
#include <stdio.h> /* getchar putchar getc printf fprint fopen fclose
*/
#include <stdlib.h> /* strtol */
#define CMAXREC 20 /* nbr d'enreg. max*/
#define CMAXCAR 30 /* nbr de caracteres max. */
void ReadTxt(char FTxt[]) ;
void ReadSaveToFile(FILE *FP_FILE) ;
void ReadFile1(FILE *FP_FILE) ;
void ReadFile2(FILE *FP_FILE) ; /* fscanf fprintf printf */
long int ConvToDigit(char FTxt[]) ;
int main(void)
{
FILE *MP_FILE ;
char MP_Name[] = "/media/XP/code_c/FamFile.txt" ;
printf("Ce prg cree un fichier avec des enregistrements dont le nbr
varie"
"selon ce qu'entre l'utilisateur.") ;
if ((MP_FILE = fopen(MP_Name, "w")) == NULL)
{
printf("Erreur ouverture fichier.") ;
exit(EXIT_FAILURE) ;
}
ReadSaveToFile(MP_FILE) ;
fclose(MP_FILE) ;
if ((MP_FILE = fopen(MP_Name, "r")) == NULL)
{
printf("Erreur de lecture du fichier") ;
exit(EXIT_FAILURE) ;
}
ReadFile1(MP_FILE) ;
fclose(MP_FILE) ;
printf("") ;
return 0 ;
}
void ReadTxt(char FTxt[])
{
int i ;
int c ;
for (i = 0 ; ((c = getchar()) != '') ; i++)
{
if (i < CMAXCAR)
FTxt[i] = c ;
else
{
while(getchar() != '') ;
break ;
}
}
FTxt[i] = '\0' ;
}
void ReadSaveToFile(FILE *FP_FILE)
{
char MFBuff[CMAXCAR] ;
char MFPrePere[CMAXCAR] ;
char MFPreMere[CMAXCAR] ;
char MFPreEnf[CMAXCAR] ;
char rep1 ;
int nb_rec, i ;
long int nb_enf ;
rep1 = 'x' ;
nb_rec = 0 ;
do
{
printf("Enregistrement (o/n) ? ") ;
rep1 = getc(stdin) ;
while (getchar() != '') ;
if (rep1 == 'o' && nb_rec < CMAXREC)
{
printf("Prenom du pere : ") ;
ReadTxt(MFPrePere) ;
printf("Prenom de la mere : ") ;
ReadTxt(MFPreMere) ;
fprintf(FP_FILE, "%s%s", MFPrePere, MFPreMere) ;
printf("Nombre d'enfants : ") ;
ReadTxt(MFBuff) ;
nb_enf = ConvToDigit(MFBuff) ;
if (nb_enf > 0)
{
for (i = 0 ; i < nb_enf ; i++)
{
printf("Enfant %d : ", i+1) ;
ReadTxt(MFPreEnf) ;
fprintf(FP_FILE, "%s", MFPreEnf) ;
nb_rec++ ;
}
}
nb_rec++ ;
}
} while (rep1 == 'o') ;
}
long int ConvToDigit(char FTxt[])
{
char *p ;
long int rslt ;
rslt = strtol(FTxt, &p, 10) ;
return rslt ;
}
void ReadFile1(FILE *FP_FILE)
{
int c ;
while ((c = getc(FP_FILE)) != EOF)
putchar(c) ;
}
void ReadFile2(FILE *FP_FILE) /* Pour info : ca ne marche car le nbr
de prenom enfant est variable donc different de 3 (variable déclarée)
*/
{
char FPrePere[CMAXCAR] ;
char FPreMere[CMAXCAR] ;
char FPreEnf[CMAXCAR] ;
while (fscanf(FP_FILE, "%s%s%s", FPrePere, FPreMere, FPreEnf) == 3)
printf("%s%s%s", FPrePere, FPreMere,FPreEnf) ;
}

Poser une question


beaucoup à essayer le même code sans passer par l'écriture d'un
fichier. Mais j'ai trouvé difficile l'algorithme pour ça parce que le
fait que le nombre d'enfant peut varier rend le stockage en mémoire
plutôt difficile surtout pour une restitution à l'écran, il y a soit
un chevauchement en mémoire entre les enregistrements parents et les
enregistrements des enfants soit un écart et entre les 2 des contenus
mémoires "poubelle".
La seule solution me semble d'écrire dans un fichier tampon et de lire
ce fichier après saisie.
Peut-être sans passer par l'écriture/lecture de fichier, on peut faire
la même chose avec un tableau de pointeurs et realloc...
Pourquoi mp_file en majuscules ?
--
Ma coiffeuse est formidable - http://sonia.buvette.org/
-------------- Build: Debug in hello ---------------
Compiling: main.c
Linking console executable: binDebughello.exe
Output size is 64.89 KB
Process terminated with status 0 (0 minutes, 3 seconds)
0 errors, 0 warnings
C'est de bon augure ...
Ce prg cree un fichier avec des enregistrements dont le nbr varie
selon ce qu'entre l'utilisateur.
Erreur ouverture fichier.
Process returned 1 (0x1) execution time : 0.073 s
Press any key to continue.
Par contre ça, c'est bizarre. J'ai juste lancé le programme.
Présuppose que j'ai un répertoire "/media/XP/code_c/". Comme il n'y a
rien dans le code pour le créer, il faut informer l'utilisateur qu'il
doit le créer lui-même. C'est pas un problème de langage, mais de
définition du comportement du programme à réaliser.
Pour tester rapidement, j'ai donc remplacé par
char MP_Name[] = "/media/XP/code_c/FamFile.txt" ;
et ça donne, par exemple :
char MP_Name[] = "FamFile.txt" ;
Ce prg cree un fichier avec des enregistrements dont le nbr varie
selon ce qu'entre l'utilisateur.
Enregistrement (o/n) ? o
Prenom du pere : Homer
Prenom de la mere : Marge
Nombre d'enfants : 3
Enfant 1 : Bart
Enfant 2 : Lisa
Enfant 3 : Maggie
Enregistrement (o/n) ? n
Homer
Marge
Bart
Lisa
Maggie
Process returned 0 (0x0) execution time : 54.434 s
Press any key to continue.
Ce qui parait être un comportement correct. (à part que j'aurais mis
la question "enregistrement (o/n)" à la fin et non au début, donc avec
un do-while)
Le fichier créé contient :
Homer
Marge
Bart
Lisa
Maggie
Analysons maintenant le code.
Pour un fichier, ce n'est pas nécessaire.
Il n'est pas utile de séparer les prototypes si on définit les
fonctions avant de les utiliser
Habituellement, on utilise les majuscule pour les constantes. Que
signifie MP ?
Bien garder à l'esprit que "w" créée un nouveau fichier à chaque fo is.
"a" est probablement plus adapté ...
Pour garantir l'affichage, le texte doit être terminé par 'n'.
Il n'est pas forcément très utile de séparer l'ouverture/fermeture du
fichier et son utilisation. Souvent, on ne fait qu'une fonction, à
moins qu'une partie du code soit factorisable et utilisé plusieurs
fois. Mais comme on ne peut pas savoir dans la fonction, si le fichier
a été ouvert en "w", "a" ou "r", ça peut poser des problèmes
bizarres ...
Je n'aime pas beaucoup le recyclage sauvage de variable, mais
admettons...
OK.
Est-il bien utile de séparer ces tableaux ?
Il est rare d'utiliser un char tout seul. Seul cas connu : scanf()
avec "%c".
long int pour un nombre d'enfants, c'est un peu paranoïaque, non ? int
garantit 32767, c'est déjà pas mal, non ?
Bien, le vidage. rep1 devrait être de type int (le type retourné par
getc(). Est-ce si difficile de lire la doc des fonctions avant de les
utiliser ?)
C'est bien d'avoir fait une fonction de saisie.
Comme on enregistre quasiment à la volée, il n'était pas utile de
séparer les chaines de saisie, mais ça a le mérite d'être clair.
On aurait pu faire :
1 - prompt
2 - saisie
3 - enregistrement
par élément.
Oui, OK.
et voilà la séquence
1 - prompt
2 - saisie
3 - enregistrement
que tu aurais pu faire pour les parents, comme je l'ai indiqué au-
dessus ...
J'aurais mis la question de la répétition ici ...
J'aurais intégré l'ouverture et la fermeture, et j'aurais passé le no m
du fichier en paramètre. Ça fait un bloc autonome qui ne doit rien à
personne...
SI tu n'utilises pas p, autant mettre :
rslt = strtol(FTxt, NULL, 10) ;
Sinon, i faut apprendre à utiliser p correctement (lire la doc, poser
des questions précises ...). Il peut servir déterminer si la saisie a
été correcte.
OK. C'est une lecture 'brute' du fichier, mais c'est correct. J'aurais
intégré l'ouverture et la fermeture, et j'aurais passé le nom du
fichier en paramètre. Ça fait un bloc autonome qui ne doit rien à
personne...
Si tu veux ce type d'info, il faut organiser ton fichier de façon à
retrouver logiquement les informations à une place bien précise.
Il faut organiser le fichier en structures (famille) et en champs
(père, mère, nb-enfants, liste d'enfants). C'est surtout un problème
de conception.
Sinon, c'est pas mal du tout. (ça manque cependant de
sécurisation ...)
Je suis content de voir que tu as fait des progrès. Continue !
Celui-là est un piège classique : si l'utilisateur tape directement la
touche d'entrée ('n'), rep1 reçoit cette valeur, puis le programme va
se bloquer sur le getchar() suivant, et l'utilisateur ne comprendra pas
ce qui se passe.
Il ne faut donc pas entrer dans la boucle while() dans ce cas-là.
Compare avec la fonction ReadTxt(), où le piège n'intervient pas.
Logiquement, ici tu devrais vérifier que p est > FTxt (ce qui
indiquerait une entrée invalide) et que *p vaut le ' ' final (le cas
contraire indiquant que des caractères supplémentaires auraient été
introduits).
Oui. La solution logique est donc d'enregistrer ce nombre dans le
fichier, par exemple après le prénom des parents et avant ceux des enfants.
Non : cela ne passe pas s'il y a des espaces dans les prénoms.
En effet, si tu entres (après la réduction à 20 caractères)
Louis-Ferdinand
Marie-Josèphe Caroli
Marie Zéphirine
Louis Joseph Xavier
Xavier Marie Joseph
Louis Auguste
Louis Stanislas Xavi
Charles Philippe
Marie-Adélaïde Cloti
Élisabeth Philippine
la spécification %s, qui s'arrête sur les caractères d'espacement
(espace, tabulations ou saut de lignes) va découper cela en
1er-> Louis-Ferdinand
2e -> Marie-Josèphe
3e -> Caroli
4e -> Marie
5e -> Zéphirine
6e -> Louis
7e -> Joseph
8e -> Xavier
9e -> Xavier
10e-> Marie
11e-> Joseph
12e-> Louis
13e-> Auguste
14e-> Louis
15e-> Stanislas
16e-> Xavi
17e-> Charles
18e-> Philippe
19e-> Marie-Adélaïde
20e-> Cloti
21e-> Élisabeth
22e-> Philippine
qui n'est pas ce que tu veux...
Solutions : soit abandonner scanf, soit utiliser des trucs plus
compliqués comme [^n], ou encore filtrer les espaces (ici, on pourrait
accepter de mettre des virgules).
Antoine