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

[C/Unix] lecture d'un fichier structuré

10 réponses
Avatar
Brice
Bonjour


je suis débutant en programmation et encore plus en C. Ayant un peu de
temps j'ai décidé d'apprendre la C par moi-même grâce à de la doc
trouvée sur le ouèbe (d'ailleurs au passage si vous avez des bons liens
sur le sujet, je suis preneur -;).

J'essaie de lire un fichier structuré pour maniper un peu fscanf. Mon
fichier est :

dupond vilebrequin 10 1000
dupond bielle 5 1000
dupond palier 6 1000
martin vilebrequin 2 3000
martin bielle 8 1000
martin palier 10 1000
polo rlts 10 20
bobby vilebrequin 2 1000


Mon prog doit simplement scanner les lignes et les imprimer sur l'écran
avec un printf, j'ai donc le prog suivant:


#include<stdio.h>

int main()
{
FILE *fi;
char nom[80];
char article[80];
int nombre,prix;

if ((fi=fopen("data5.8.1","r")) == NULL)
{
printf ("Impossile d'ouvrir le fichier\n");
}
else
{
while(fscanf(fi,"%s %s %d %d", nom, article,&nombre, &prix) != EOF);
{
printf("%s %s %d %d\n",nom,article,nombre,prix);
printf("\n");
}
fclose(fi);
}
}




mais le petit-père ne m'affiche que la dernière ligne... je comprends
pas pourquoi et mon programme est identique à la correction donnée dans
ma doc. Donc je me demande si ça vient de mon prog ou alors de la
manière donc est codé mon fichier (fait à la main avec vim), il me
semble que les "fins de lignes" sous unix (Debian linux pour moi)
sont codées un peu bizarrement ou du moins differemment de sous
windaube.

Merci,

--
Brice
Debian GNU/Linux testing (Linux user nb. 372699)
-----
"Unix IS user friendly, it is just selective about who his friends are"

10 réponses

Avatar
fabrizio
while(fscanf(fi,"%s %s %d %d", nom, article,&nombre, &prix) != EOF);


Enlève le point-virgule de la ligne ci-dessus. Ça devrait mieux
fonctionner.

Avatar
Christophe PEREZ
Le Thu, 18 Aug 2005 16:15:23 +0200, Brice a écrit:

while(fscanf(fi,"%s %s %d %d", nom, article,&nombre, &prix) != EOF);
{
printf("%s %s %d %dn",nom,article,nombre,prix);
printf("n");
}
fclose(fi);
}


Je ne connais pas (plus) grand chose au C, mais je doute que le ";" final
de ta ligne "while" soit bien désiré. Car à mon avis, il boucle
justement tant qu'il n'a pas atteint la fin du fichier, puis affiche les
dernières valeurs récupérées.
Si tu enlèves le ";", ça pourrait aller mieux, à condition qu'il n'y
ait pas d'autres erreurs ;-)

--
Christophe PEREZ
Écrivez moi sans _faute !

Avatar
Brice
On 2005-08-18, fabrizio wrote:
while(fscanf(fi,"%s %s %d %d", nom, article,&nombre, &prix) != EOF);


Enlève le point-virgule de la ligne ci-dessus. Ça devrait mieux
fonctionner.



merci c'était ça... je me sens un peu con de ne pas l'avoir vu celle-là!


--
Brice
Debian GNU/Linux testing (Linux user nb. 372699)
-----
"Unix IS user friendly, it is just selective about who his friends are"


Avatar
Nicolas George
Brice wrote in message
:
j'ai donc le prog suivant:


Les autres ont bien indiqué le problème, mais quelques corrections sur le
reste s'imposent.

printf ("Impossile d'ouvrir le fichiern");


Il y a trois erreurs ici :

- D'une part, cette ligne affiche un message d'erreur sur la sortie
standard ; les messages d'erreur doivent aller sur la sortie d'erreur, de
manière à ne pas se mélanger. Donc fprintf(stderr, ...), ou autre.

- D'autre part, la nature de l'erreur n'est pas indiquée : impossible de
savoir si on s'est trompé dans le nom du fichier, qui n'est alors pas
trouvé, si les permissions ne sont pas bonnes, s'il y a une erreur
physique sur disque, etc. La fonction perror est une solution à ça ;
strerror en est une autre.

- Enfin, le programme signale l'erreur par un message, mais pas par son code
de retour. La convention est qu'un programme ait un code de retour de 0
s'il a fait correctement ce qui était attendu de lui, et autre sinon.

while(fscanf(fi,"%s %s %d %d", nom, article,&nombre, &prix) != EOF);


L'utilisation de %s dans un scanf est un buffer overflow ambulant : aucune
vérification n'est faite que les chaînes lues tiennent bien dans les tampons
qui leur sont alloués. Le C standard ne propose pas de solution toute faite
pour résoudre convenablement le problème. Il est possible de borner la
taille des champs, ou d'allouer dynamiquement un tableau assez grand.

À noter également que cette ligne ne teste pas du tout la possibilité que le
fichier ne soit pas formaté tel que prévu.

Ces problèmes n'existent pas si les données sont considérées comme de
confiance, mais ce n'est jamais une bonne idée de partir sur cette route :
il y aura toujours quelqu'un pour réutiliser le programme en environnement
hostile.

}


Le programme termine la fonction main, qui retourne un int et pas void, sans
passer par un return avec une valeur. En C99, cette construction est
autorisée spécifiquement pour main, mais je trouve que ce n'est pas une
bonne idée de se servir de cette fonctionnalité.

Avatar
Brice
On 2005-08-18, Nicolas George <nicolas$ wrote:
Brice wrote in message
:
j'ai donc le prog suivant:


Les autres ont bien indiqué le problème, mais quelques corrections sur le
reste s'imposent.

printf ("Impossile d'ouvrir le fichiern");


Il y a trois erreurs ici :

- D'une part, cette ligne affiche un message d'erreur sur la sortie
standard ; les messages d'erreur doivent aller sur la sortie d'erreur, de
manière à ne pas se mélanger. Donc fprintf(stderr, ...), ou autre.

- D'autre part, la nature de l'erreur n'est pas indiquée : impossible de
savoir si on s'est trompé dans le nom du fichier, qui n'est alors pas
trouvé, si les permissions ne sont pas bonnes, s'il y a une erreur
physique sur disque, etc. La fonction perror est une solution à ça ;
strerror en est une autre.

- Enfin, le programme signale l'erreur par un message, mais pas par son code
de retour. La convention est qu'un programme ait un code de retour de 0
s'il a fait correctement ce qui était attendu de lui, et autre sinon.

while(fscanf(fi,"%s %s %d %d", nom, article,&nombre, &prix) != EOF);


L'utilisation de %s dans un scanf est un buffer overflow ambulant : aucune
vérification n'est faite que les chaînes lues tiennent bien dans les tampons
qui leur sont alloués. Le C standard ne propose pas de solution toute faite
pour résoudre convenablement le problème. Il est possible de borner la
taille des champs, ou d'allouer dynamiquement un tableau assez grand.

À noter également que cette ligne ne teste pas du tout la possibilité que le
fichier ne soit pas formaté tel que prévu.

Ces problèmes n'existent pas si les données sont considérées comme de
confiance, mais ce n'est jamais une bonne idée de partir sur cette route :
il y aura toujours quelqu'un pour réutiliser le programme en environnement
hostile.

}


Le programme termine la fonction main, qui retourne un int et pas void, sans
passer par un return avec une valeur. En C99, cette construction est
autorisée spécifiquement pour main, mais je trouve que ce n'est pas une
bonne idée de se servir de cette fonctionnalité.




je vais tacher de me souvenir de tes remarques et d'inclure un return 0;
à la fin de mes main() mais bon comme je l'ai dit ça fait 2 jours que je
me suis mis au c... donc patience, ça va venir ce genre de raffinements
mais le truc pour l'instant est de faire de petites broutilles pour
tester le langage et en apprendre la syntaxe. Les raffinements ne
peuvent avoir lieu que si j'ai des bases, me tromperais-je?


Merci en tout cas pour les remarques!

ps: si vous avez des bons liens, je suis preneur!

--
Brice
Debian GNU/Linux testing (Linux user nb. 372699)
-----
"Unix IS user friendly, it is just selective about who his friends are"


Avatar
Stephane Zuckerman
On Thu, 18 Aug 2005, Brice wrote:

je vais tacher de me souvenir de tes remarques et d'inclure un return 0;


Mieux : un "return EXIT_SUCCESS;" ou un "return EXIT_FAILURE;" (si on veut
juste savoir si le programme a bien réussi ou pas, ce sont les deux codes
- inclus dans stdlib.h - qui existent officiellement). Bien sûr, dans un
environnement UNIX, on s'attend à ce qu'un programme renvoie 0 en cas de
succès. Mais bon, si on peut faire encore plus portable, hein ... :-)

à la fin de mes main() mais bon comme je l'ai dit ça fait 2 jours que je
me suis mis au c... donc patience, ça va venir ce genre de raffinements
mais le truc pour l'instant est de faire de petites broutilles pour
tester le langage et en apprendre la syntaxe. Les raffinements ne
peuvent avoir lieu que si j'ai des bases, me tromperais-je?


Disons que là il ne s'agit pas réellement de raffinements. Justement, il
s'agit de bases : si une fonction renvoie une valeur, il faut renvoyer une
valeur, coûte que coûte (par contre, mon délire avec
EXIT_{SUCCESS,FAILURE} oui, on peut l'oublier pour le moment ;-) ).

Globalement, le C est un langage très permissif, fait par et pour des gens
qui "savent ce qu'ils font". Il est à mon sens très dangereux de commencer
à programmer en C sans être très rigoureux dès le départ, car c'est un
langage qui regorge de comportements indéfinis.

ps: si vous avez des bons liens, je suis preneur!


Lire la FAQ de fr.comp.lang.c est un bon début, il y a énormément de trucs
vraiment sympa à connaître, ainsi que des liens vers des bouquins et
autres sites Internet. google : faq fclc .

--
"Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
que je veux !"
"The obvious mathematical breakthrough would be development of an easy
way to factor large prime numbers." (Bill Gates, The Road Ahead)

Avatar
Antoine Leca
En <news:,
Stephane Zuckerman va escriure:
On Thu, 18 Aug 2005, Brice wrote:

je vais tacher de me souvenir de tes remarques et d'inclure un
return 0;



Bonne idée.


<DELIRE cible="gourous, wizards">

Mieux : un "return EXIT_SUCCESS;" ou un "return EXIT_FAILURE;" (si on
veut juste savoir si le programme a bien réussi ou pas, ce sont les
deux codes - inclus dans stdlib.h - qui existent officiellement).
Bien sûr, dans un environnement UNIX, on s'attend à ce qu'un
programme renvoie 0 en cas de succès. Mais bon, si on peut faire
encore plus portable, hein ... :-)


return EXIT_SUCCESS;
et
return 0;
sont équivalents. Le second ne nécessite pas d'#inclure <stdlib.h> et est
plus rapide à taper :^).

(Les compilateurs qui, sur des machines où le résultat 0 signifie erreur, ne
transforment pas exit(0) en un code d'erreur non nul, sont plus rares que
ceux qui ne proposent pas <stdlib.h>. Donc en fait ta proposition est plutôt
moins portable; mais c'est très marginal.)

</DELIRE>


Antoine


Avatar
Stephane Zuckerman
On Fri, 19 Aug 2005, Antoine Leca wrote:

<DELIRE cible="gourous, wizards">

Mieux : un "return EXIT_SUCCESS;" ou un "return EXIT_FAILURE;" (si on
veut juste savoir si le programme a bien réussi ou pas, ce sont les
deux codes - inclus dans stdlib.h - qui existent officiellement).
Bien sûr, dans un environnement UNIX, on s'attend à ce qu'un
programme renvoie 0 en cas de succès. Mais bon, si on peut faire
encore plus portable, hein ... :-)


return EXIT_SUCCESS;
et
return 0;
sont équivalents. Le second ne nécessite pas d'#inclure <stdlib.h> et est
plus rapide à taper :^).

(Les compilateurs qui, sur des machines où le résultat 0 signifie erreur, ne
transforment pas exit(0) en un code d'erreur non nul, sont plus rares que
ceux qui ne proposent pas <stdlib.h>. Donc en fait ta proposition est plutôt
moins portable; mais c'est très marginal.)

</DELIRE>


Bon, j'aurai appris quelque chose. :-)
Mais pour moi le code de retour "correct" 0 n'était pas obligatoire en C
ISO... Du coup, restant sur la base du C ISO, je me suis dit que stdlib.h
était présent et que c'était la seule "vraie bonne valeur".

On ne m'y reprendra plus !

X-post & fu2 là où ça aurait dû commencer. :-)

--
"Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
que je veux !"
"The obvious mathematical breakthrough would be development of an easy
way to factor large prime numbers." (Bill Gates, The Road Ahead)


Avatar
Antoine Leca
En <news:de2709$jte$, Nicolas George va escriure:
printf ("Impossile d'ouvrir le fichiern");


Il y a trois erreurs ici :


J'en vois une quatrième: le mot correct est « Impossible ». ;-)


while(fscanf(fi,"%s %s %d %d", nom, article,&nombre, &prix) != EOF);


L'utilisation de %s dans un scanf est un buffer overflow ambulant :
aucune vérification n'est faite que les chaînes lues tiennent bien
dans les tampons qui leur sont alloués.


Certes. Mais si tu commences à corriger les problèmes de débordement, il
faudrait aussi s'ateller aux cas du genre

antoine clé de 12 6 1000
antoine villebrequin 0


Le C standard ne propose pas de solution toute faite pour résoudre
convenablement le problème.


Tout dépend ce que tu entends par « toute faite » et « convenablement ».
En l'occurence,

(n = fscanf(fi,"%79s %79s %d %d", nom, article,&nombre, &prix)) != 4

est déjà un progrès substanciel, non ?


d'allouer dynamiquement un tableau assez grand.


Avec fscanf (pas sscanf) ?


Antoine


Avatar
Jean-Louis Liagre
Antoine Leca wrote:
En <news:de2709$jte$, Nicolas George va escriure:

printf ("Impossile d'ouvrir le fichiern");


Il y a trois erreurs ici :


J'en vois une quatrième: le mot correct est « Impossible ». ;-)
...

Certes. Mais si tu commences à corriger les problèmes de débordement, il
faudrait aussi s'ateller aux cas du genre


Et une cinquième là -> "s'atteler" ;-)