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

Saisie avec fgets et sscanf

6 réponses
Avatar
Eric Guirbal
Bonjour,

Je viens de passer douze heures en vain à comprendre un bug concernant la
saisie d'un float avec fgets et sscanf. Voici le code et un exemple
d'execution. Je pourrais perfectionner ma saisie en m'inspirant de l'exemple
donné par E. Delahaye dans la faq, mais j'aimerais comprendre le
comportement de ma programme.

5 * Saisie des notes obtenues par un patineur et affichage de sa moyenne
6 *
7 */
8
9
10 #include <stdio.h>
11 #include <stdlib.h>
12
13 #define NB_JUGES 5
14 #define NOTE_MIN 1.0
15 #define NOTE_MAX 6.0
16
17
18 int
19 main (void)
20 {
21 float somme = 0;
22 float moyenne;
23 float note;
24 char saisie[5];
25 int i;
26
27 printf ("\n---------- Saisie des notes du patineur ---------\n\n\n");
28 for (i = 0; i < NB_JUGES; i++)
29 {
30 while (1)
31 {
32 printf ("Note du juge no.%d: ", i + 1);
33 if (fgets (saisie, sizeof(saisie), stdin) == NULL)
34 {
35 fprintf (stderr, "Fin de fichier inattendu \n");
36 return (1);
37 }
38 if (sscanf (saisie, "%f", &note) != 1)
39 printf ("\nErreur, un nombre svp\n");
40 else
41 {
42 if ((note >= NOTE_MIN) && (note <= NOTE_MAX))
43 break;
44 printf ("\nErreur, un nombre entre %.2f et %.2f svp\n",
45 NOTE_MIN, NOTE_MAX);
46 }
47 printf ("debug: note = %f\n\n", note);
48 }
49 somme += note;
50 }
51 moyenne = somme / NB_JUGES;
52 printf ("\nMoyenne du patineur: %.2f\n\n", moyenne);
53 return EXIT_SUCCESS;
54 }
55


eric@indiana:~/informatique/langageC/seance3$ ./patineur1

---------- Saisie des notes du patineur ---------


Note du juge no.1: 3.5
Note du juge no.2: 4.80
Note du juge no.3:
Erreur, un nombre svp
debug: note = 4.800000

Note du juge no.3: 3.75
Note du juge no.4:
Erreur, un nombre svp
debug: note = 3.750000

Note du juge no.4: f

Erreur, un nombre svp
debug: note = 3.750000

Note du juge no.4: 2.4682
Note du juge no.5:
Erreur, un nombre entre 1.00 et 6.00 svp
debug: note = 82.000000

Note du juge no.5: 3

Moyenne du patineur: 3.50


Merci beaucoup pour votre aide.

--
Eric

6 réponses

Avatar
MagicalTux
Le Fri, 13 Jan 2006 20:14:07 +0100, Eric Guirbal a écrit :
Bonjour,

Je viens de passer douze heures en vain à comprendre un bug concernant la
saisie d'un float avec fgets et sscanf. Voici le code et un exemple
d'execution. Je pourrais perfectionner ma saisie en m'inspirant de l'exemple
donné par E. Delahaye dans la faq, mais j'aimerais comprendre le
comportement de ma programme.


Le bug est simple, et est lié a la taille du buffer de saisi.

Supposont la note 2.4682. Notre buffer fait 5 de taille. On peut donc y
faire entrer "2.46" (ne jamais oublier le final). Toutefois il reste
82 dans le "buffer" système. Cette valeur est obtenue a l'appel suivant
de fgets().

La solution : augmenter saisie[5] a une valeur un peu plus grande.


--
MagicalTux - Developpement PHP, C et un peu de tout
http://ookoo.org/

Avatar
Emmanuel Delahaye
Je viens de passer douze heures en vain à comprendre un bug concernant la
saisie d'un float avec fgets et sscanf. Voici le code et un exemple
d'execution. Je pourrais perfectionner ma saisie en m'inspirant de l'exemple
donné par E. Delahaye dans la faq, mais j'aimerais comprendre le
comportement de ma programme.


http://mapage.noos.fr/emdel/notes.htm#saisie
http://mapage.noos.fr/emdel/notes.htm#fichiers

24 char saisie[5];


Pourquoi 5 ?

33 if (fgets (saisie, sizeof(saisie), stdin) == NULL)
Pour saisir


9.99<enter>

soit

{'9','.','9','9','n',0}

il faut 6 caractères. Si il n'y a la place qur pour 5, fgets() va
laisser le 'n'. Comme tu ne le testes pas, le prochain appel de fgets()
ne sera pas blocant...

Pourquoi est-tu si radin ? Met 8 ou 16 char et c'est OK.

--
A+

Emmanuel Delahaye

Avatar
Guillaume R.
Salut
Pourquoi est-tu si radin ? Met 8 ou 16 char et c'est OK
J'ai souvent ce problème aussi, y'a til un moyen d'allouer

dynamiquement l'espace dont j'ai ou peux avoir besoin pour une chaine
donnée?
Par exemple la même s'il met 16 un ptit malin pourra toujours bloquer
le prog en saisissant 20 caractères par exemple.
Y'a t-il une solution pour allouer dynamiquement ces espaces en C?

Avatar
Harpo
Guillaume R. wrote:

Salut
Pourquoi est-tu si radin ? Met 8 ou 16 char et c'est OK
J'ai souvent ce probl




Avatar
Emmanuel Delahaye
Pourquoi est-tu si radin ? Met 8 ou 16 char et c'est OK


J'ai souvent ce probl�me aussi, y'a til un moyen d'allouer
dynamiquement l'espace dont j'ai ou peux avoir besoin pour une chaine
donn�e?


Ben oui. malloc()... n

Par exemple la m�me s'il met 16 un ptit malin pourra toujours bloquer
le prog en saisissant 20 caract�res par exemple.


Il ne va rien bloquer si le programmeur lit les conseils d'utilisation
que j'ai donné dans articles dont j'ai fourni les liens.

Y'a t-il une solution pour allouer dynamiquement ces espaces en C?


On peut écrire une fonction de saisie qui alloue/réalloue dynamiquement
ce qu'il faut. Il faut écrire un petit algo qui évite de réallouer à
chaque caractère (disons, pas doublage... on commence par 8, puis on
agrandit à 16, 32 etc. selon les besoins...). C'est un exercice
'semi-avancé' courant en C... En plus, on se retrouve avec une fonction
de saisie solide et souple, ce qui est *très* pratique (penser à libérer
le bloc après usage, bien sûr, on est pas des brutes...)

Genre :

char *getline_dyn(void);

Le suffixe '_dyn' est un aide mémoire : penser à libérer le bloc...

--
A+

Emmanuel Delahaye


Avatar
Harpo
Emmanuel Delahaye wrote:


Y'a t-il une solution pour allouer dynamiquement ces espaces en C?


On peut écrire une fonction de saisie qui alloue/réalloue
dynamiquement ce qu'il faut. Il faut écrire un petit algo qui évite de
réallouer à chaque caractère (disons, pas doublage... on commence par
8, puis on agrandit à 16, 32 etc. selon les besoins...).


C'est petit de commencer à moins de 256.

C'est un
exercice 'semi-avancé' courant en C... En plus, on se retrouve avec
une fonction de saisie solide et souple, ce qui est *très* pratique
(penser à libérer le bloc après usage, bien sûr, on est pas des
brutes...)


Je préfère utiliser une bibliothèque comme GNU Getline, l'utilisateur
peut utiliser les touches up et down pour accéder à l'historique de ce
qu'il a déjà entré et aussi plein de choses fournies par la
bibliothèque.
En plus, ça marchait bien depuis longtemps à la fin du millénaire
dernier.

--
http://harpo.free.fr/