Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

débutant avec fgetc, fscanf, fprintf

7 réponses
Avatar
bpascal123
Hello cyberspace,

Je dois =E9crire un code qui lit un fichier et recopie le contenu
(enregistrement par enregistrement) dans un autre fichier. Je suis
arriv=E9 =E0 copier sur l'autre fichier sans trop de mal. Au d=E9part, j'ai
fait appel =E0 feof avec while ( !feof(P_SOURCE) !=3D EOF ) fscanf fichier
source...fprintf fichier destination ... . Je me suis rendu compte de
cette mani=E8re qu'=E0 chaque fois, dans le fichier destination, il y
avait un un "=FF" en fin fichier en derni=E8re ligne. Je me demande si
quelqu'un n'a pas d=E9j=E0 rencontr=E9 l'affichage de ce carat=E8re (=FF) ?=
Est-
ce que c'est une repr=E9sentation de EOF ?

Bref, j'ai pu r=E9soudre cette situation avec while ( (c =3D
fgetc(P_SOURCE)) !=3D EOF ) ... Au niveau de l'=E9criture du fichier tout
se d=E9roule normalement et le r=E9sultat est ce que j'attends que =E7a soi=
t
enregistrement par enregistrement ou caract=E8re par caract=E8re...

Maintenant je souhaite afficher =E0 l'=E9cran (dans le terminal) le
fichier destinatation et alors tout ce qui cha=EEne de caract=E8re
s'affiche comme pr=E9vu mais les %d ne s'affichent pas comme pr=E9vu.
Voici les fonctions que j'utilise :


void ReadAndCopyRec( FILE *FP_SOURCE, FILE *FP_DESTI, int FTicket,
char FName[], char FPren[] )
{
while ( !feof(FP_SOURCE) )
{
fscanf(FP_SOURCE, "%d\n%s\n%s\n", &FTicket, FName, FPren) ;
fprintf(FP_DESTI, "%d\n%s\n%s\n", FTicket, FName, FPren) ;
}
}

void DisplayRec( FILE *FP_DESTI, int FTicket, char FName[], char
FPren[],
int nmax)
{
int c ;

while ( (c =3D fgetc(FP_DESTI)) !=3D EOF )
{
fscanf(FP_DESTI, "%d\n%s\n%s\n", &FTicket, FName, FPren) ;
printf("%d\n%s\n%s\n", FTicket, FName, FPren) ;
}
}

Faire appel =E0 ces 2 fonctions fonctionne bien pour ce qui est de la
copie dans le fichier destination, par contre l'affichage =E0 l'=E9cran
avec DisplayRec n'est pas celui de la copie ni du source pour %d,
FTicket. Le num=E9ro de FTicket devien 0 =E0 l'affichage =E9cran alors qu'i=
l
est bien celui du fichier source dans le fichier destination.

Avec int FTicket[] dans les fonctions et (FTicket+i) dans fscanf et
FTicket[i] pour printf (...int i =3D 0 et i++ dans while) pour une
lecture par adresse, le r=E9sultat est diff=E9rent sans =EAtre meilleur.

Une id=E9e?

Merci,
Pascal

7 réponses

Avatar
-ed-
On 22 août, 03:24, ""
wrote:
Hello cyberspace,

Je dois écrire un code qui lit un fichier et recopie le contenu
(enregistrement par enregistrement) dans un autre fichier. Je suis
arrivé à copier sur l'autre fichier sans trop de mal. Au départ, j' ai
fait appel à feof avec while ( !feof(P_SOURCE) != EOF ) fscanf fichie r
source...fprintf fichier destination ... . Je me suis rendu compte de
cette manière qu'à chaque fois, dans le fichier destination, il y
avait un un "ÿ" en fin fichier en dernière ligne. Je me demande si
quelqu'un n'a pas déjà rencontré l'affichage de ce caratère (ÿ) ? Est-
ce que c'est une représentation de EOF ?



La première chose à faire avant d'utiliser une fonction est de lire sa
doc et de la comprendre. Relit la doc de feof() et tu verras qu'elle
ne fait pas ce que tu crois.

Pour déterminer si on est arrivé en fin de fichier, on teste la valeur
retournée par la fonction de lecture. Il n'y a pas d'alternative.

Bref, j'ai pu résoudre cette situation avec while ( (c =
fgetc(P_SOURCE)) != EOF ) ... Au niveau de l'écriture du fichier tout
se déroule normalement et le résultat est ce que j'attends que ça s oit
enregistrement par enregistrement ou caractère par caractère...



Effectivement c'est une solution correcte. (test de la valeur
retournée par fgetc()). D'ailleurs, pour une copie simple, on peut
simplifier par :

while (fgetc(P_SOURCE) != EOF )
...

Maintenant je souhaite afficher à l'écran (dans le terminal) le
fichier destination et alors tout ce qui chaîne de caractère
s'affiche comme prévu mais les %d ne s'affichent pas comme prévu.
Voici les fonctions que j'utilise :

void ReadAndCopyRec( FILE *FP_SOURCE, FILE *FP_DESTI, int FTicket,
                                                                                 char FName[], char FPren[] )
{
        while ( !feof(FP_SOURCE) )
        {
                fscanf(FP_SOURCE, "%dn%sn%sn", &FTicke t, FName, FPren) ;
                fprintf(FP_DESTI, "%dn%sn%sn", FTicket , FName, FPren) ;
        }

}



Encore une fois feof() ne fait pas ce que tu crois. ... Il faut tester
la valeur retournée par la fonction de lecture (ici, fscanf()). Et pas
de devinettes. LIRE LA DOC. D'autre part, les 'n' dans le formatage
de fscanf() ne font pas non plus ce que tu crois. Ça perturbe tout...
A retirer. Il ne faut pas programmer au hasard, mais se conformer
strictement à la doc...
Avatar
kikonc
a écrit dans le message de groupe de discussion
:
Hello cyberspace,


void ReadAndCopyRec( FILE *FP_SOURCE, FILE *FP_DESTI, int FTicket,
char FName[], char FPren[] )
{
while ( !feof(FP_SOURCE) )



...


void DisplayRec( FILE *FP_DESTI, int FTicket, char FName[], char
FPren[],
int nmax)
{
int c ;

while ( (c = fgetc(FP_DESTI)) != EOF )


...

Mais c'est une blague ! Remplacer feof par fgetc ... après c'est normal que
cela ne puisse fonctionner de la même façon, en tant que comptable cela
devrait te sauter aux yeux !


Avec int FTicket[] dans les fonctions et (FTicket+i) dans fscanf et
FTicket[i] pour printf (...int i = 0 et i++ dans while) pour une
lecture par adresse, le résultat est différent sans être meilleur.



Avant d'arriver à l'arithmétique des pointeurs, il faudrait déjà comme le
dit "ed" réussir à comprendre la doc sur les fonctions les plus simples.
Avatar
bpascal123
EOF...

J'ai lu la doc, en tant que comptable, il semble que feof ait un
passif non négligeable... :) Je dis en tant que comptable car certains
pensent que la comptablité se fait avec un cahier, une règle de
préférence longue pour tracer des traits, un bic et une calculatrice
ou une bonne tête pour le calcul de tête ... je pense que ce n'est pas
le sujet de cette discussion

Bref, d'après la doc ou plutôt des recherches, feof peut afficher 2
fois le dernier enregistrement lu, la 2ème fois est dû au premier
appel de la fonction à l'intérieur de la boucle test qui renvoie faux
et crée un "doublon" par un second affichage du dernier enregistrement
qui ne devrait pas avoir lieu...

Voilà ce que j'ai fait et c'est très bizarre mais j'ai cru un moment
que cette solution me suffisait pour mon niveau mais en fait c'est
encore moins fonctionnel :

void ReadAndCopyRec(FILE *FP_SOURCE, FILE *FP_DESTI, int FTicket, char
FName[], char FPren[])
{
while (1)
{
fscanf(FP_SOURCE, "%d%s%s", &FTicket, FName, FPren) ;
if ( feof(FP_SOURCE) )
break ;
fprintf(FP_DESTI, "%dn%sn%sn", FTicket, FName, FPren) ;
}
}

void DisplayRec(FILE *FP_DESTI, int FTicket, char FName[], char
FPren[] )
{
int i = 0 ;
while (1)
{
fscanf(FP_DESTI, "%d%s%s", &FTicket, FName, FPren) ;
if ( feof(FP_DESTI) )
break ;
printf("nTicket no. %d ", FTicket) ;
printf("nNom du titulaire : %s", FName ) ;
printf("nPrenom du titulaire : %s", FPren) ;
i++ ;
}
}

j'ai enlevé les n de la lecture de fscanf, c'est sûre qu'avec la
méthode de saisie plus haut, ça fonctionne. Mais ici avec feof à cett e
position, c'est juste un désordre, soit une boucle infinie, soit une
répétition de 100x puis stop à un chiffre nombre entré dans le corp s
du programme main...

A qui peut aider,
merci
Avatar
Antoine Leca
écrivit :
A qui peut aider,



On va voir si on peut essayer¹.

fscanf(FP_DESTI, "%d%s%s", &FTicket, FName, FPren) ;



En C, fscanf est une fonction qui retourne un résultat. Ce résultat, tu
ne PEUX PAS faire comme s'il n'existe pas (comme tu pourrais le faire
avec printf): if FAUT vérifier que la fonction a bien fonctionné comme
prévu, et en l'occurrence elle devrait renvoyer 3 (le nombre d'objet
lus), ou encore EOF (si tu es à la fin de fichier au début de la lecture
: avantage, cela économise un appel à feof() ensuite !) ;
une autre valeur doit être prise en compte et annuler le reste du
traitement, cela indique une erreur dans les données.

Une manière de faire est d'écrire :

#include <assert.h>

/* ... */

{
int r;

r = fscanf(FP_DESTI, "%d%s%s", &FTicket, FName, FPren);
if( r == EOF )
break;
assert(r == 3);


Nota : ce n'est pas du code industriel, mais cela suffit amplement pour
ce que tu fais ; on peut aussi écrire
if( r != 3 ) routine_d_erreur("machin", "truc");
mais assert() revient au même au point où tu es (et il n'est point
besoin d'écrire routine_d_erreur ;-) ).


Autre point sans relation, il manque
putchar('n');
à la fin de DisplayRec.


Antoine
_____
¹: on notera que je prend des précautions.
Avatar
-ed-
On 25 août, 02:16, ""
wrote:
EOF...

J'ai lu la doc, en tant que comptable, il semble que feof ait un



Bah on dirait pas. Tu n'as toujours compris que feof() ne servait pas
à déterminer la fin de lecture. A quoi ça sert qu'on te fournisse des
réponses si tu ne les lit pas ? J'ai indiqué comment on détermine la
fin de lecture. Fait le. Point.

Une fois la fin de lecture détectée (rappel : en testant la valeur
retournée par la fonction de lecture); on peut (mais c'est rarement
utile) déterminer la CAUSE de la fin de lecture en appelant feof() et
ferror(). Mais tout ça, c'est déjà la doc que tu devrais avoir lu. ne
pas se laisser intoxiquer par le nom des fonctions. Le C est un
langage industriel et non universitaire. Il n'a pas pour vocation
d'enseigner la programmation (donc pas du tout un langage de
débutant), mais de faire exactement ce pour quoi il a été conçu. LI RE
LA DOC DE TOUTES LES FONCTIONS AVANT DE LES UTILISER.

Une référence très sûre : http://www.opengroup.org/onlinepubs/79909 89775/

C'est en anglais, bien sûr ...

Et si tu ne comprends pas la doc, demande des explications.
Avatar
bpascal123
En fait, je suis "sur le cul".
Le dernier code que j'ai posté dans cette discussion a fonctionné au
moment ou je l'ai testé et puis peu de temps après, il y avait comme
je l'ai expliqué quelque chose qui ne se passait pas normalement...
une boucle infinie pour l'affichage certainement dûe à une écriture
dans le fichier infinie (un fichier texte qui devient 1, 2,15, 20 Mo
seconde après seconde...) parce que if ( feof(FP_SOURCE))...break ; ne
fonctionnait plus comme au moment ou je l'ai testé.

Donc, je lis vos posts, je vais voir la documentation même si je
trouve que la documentation n'est pas très bavarde...peut-être vous
parlé de K&R... j'ai été un peu paresseux et puis aussi ils ne sont
pas toujours très simples dans leurs explications à moins d'être
reposé...

Dans tout les cas, je me dis que fscanf n'est pas de mon niveau. Mais
je me lance avec le test suivant :

while(1)
{
if ( fscanf(FP_DESTI, "%d%s%s", (FTicket+i), FName, FPren) == 1 )
{
printf("nTicket no. %d...
...
}
else
break ;

De cette façon, ça fonctionne pour l'affichage à l'écran, mais pas
pour la copie d'un fichier vers un autre fichier. Pour copier d'un
fichier à l'autre, j'ai gardé if (feof(FP_SOURCE))...break

Pour l'instant, je n'ai pas testé if (r == EOF) break ...
assert(r==3).

Pour en revenir à fscanf, je vais essayer de trouver une alternative
peut-être plus lourde, comme avec fgets et atoi quand c'est pour un
entier ou pour plus de sécurité fgetc et strol je crois. Pour la
saisie de texte, je reprends plus ou moins ce qu'on m'avait dit dans
une discussion récente le getline du K&R avec la macro getchar() sans
size_t cependant car je ne réserve pas d'espace mémoire avec malloc.
Je crois comprendre que scanf n'est pas très sécurisé? C'est le cas d e
fscanf?

C'est pour dire que un peu dans la douleur, j'ai pu faire fonctionner
ce code ... qui ajoute des données dans un fichier destination après
avoir copié des données d'un fichier source...

Merci
Avatar
Antoine Leca
écrivit :
En fait, je suis "sur le cul".



[Pas le seul]

je me lance avec le test suivant :

while(1) {
if ( fscanf(FP_DESTI, "%d%s%s", (FTicket+i), FName, FPren) == 1 ) {


^^^^^^ ^
Là, je détecte comme un souci (ou une erreur de copier-coller)...

Par ailleurs, en terme de style je ne trouve pas cela très bon : la
comparaison n'est pas à un endroit où l'½il va regarder habituellement.
Ensuite, il faut prendre l'habitude d'écrire &FTicket[i] au lieu de
(FTicket+i) : c'est effectivement identique pour le compilateur, mais
pas pour nous pauvres humains ; et bien sûr, je suppose gratuitement ici
que tu as bien changé le type de FTicket, qui était un int auparavant et
qui semble maintenant être int[].


De cette façon, ça fonctionne pour l'affichage à l'écran,



Définit « fonctionne » ; il semble que ce soit très différent du sens
habituellement attribué à ce mot...


Pour en revenir à fscanf, je vais essayer de trouver une alternative
peut-être plus lourde, comme avec fgets et atoi



[ Me semble une bonne idée sur le fond. ]


Je crois comprendre que scanf n'est pas très sécurisé? C'est le cas de
fscanf?



Oublie les aspects de « sécurité ». C'est un peu comme les comparaisons
entre la sécurité d'une tronçonneuse et celle d'une scie radiale : avant
de s'occuper de ce niveau de détail, il faut d'abord apprendre à s'en
servir. De plus la « sécurité du langage C », c'est une mode.


Antoine