OVH Cloud OVH Cloud

printf et scanf

102 réponses
Avatar
Pascal
Bonjour,

J'ai des pb bizarres : dans une fonction j'ai besoin que l'utilisateur
me donne plusieurs infos, je fais donc des printf("question") et des scanf.

Sur les 3 premieres questions, ca marche bien, sur les 2 dernières, le
programme les affiche, mais le scanf ne semble pas marcher. Pourtant le
scanf recup sur les 5 fois un char *. C'est un bug? D'ailleurs si je ne
mets pas de \n sur le printf, parfois c'est encore pire...
voici un ex :
char *nom;
printf("nom\n");
scanf("%s", nom);
etc .. prenom, adress, tel, mail...

Parfois le scanf est comme sauté. Dans une autre fonction, je fais la
meme chose : une question, une reponse. Il m'affiche bien la question,
mais le scanf comme s'il était inactif, le programme ne me laisse pas
répondre, et passe à l'instruction suivante...

10 réponses

Avatar
Anthony Fleury
Richard Delorme wrote:

Donc préferer fgets() :
fgets(nom, NOMBRE_DE_CARACTERE_MAX, stdin);
En quoi :

scanf("%" #NOMBRE_DE_CARACTERE_MAX "s", nom);
est moins sûr ?


En rien, mais en général ceux qui utilisent scanf font des scanf("%s"...);
et ensuite c'est une question de goût, je trouve plus simple à écrire et
plus « parlante » la fonction fgets(). Mais les goûts et les couleurs...

Une solution pour éviter ceci (si tu persistes et/ou est obligé
d'utiliser scanf()) est de vider le buffer d'entrée après toute saisie
avec scanf() :

while(fgetc(stdin) != 'n');
On peut faire ça avec un scanf :

scanf("%d%*[^n]", &nombre); getchar();
C'est plus sûr que ton while qui peut boucler indéfiniment s'il
rencontre un EOF.


Oui je l'ai signalé dans un autre post. Il est bon de dire qu'il faudrait
vérifier le retour de fgetc() en effet.
Et je dois dire ne pas être super familier avec ces écritures de scanf().
J'ai signalé la méthodes dont j'étais « sûr » pour ne pas dire une bêtise
avec scanf... Enfin merci pour le complément.

Anthony
--
Alan Turing thought about criteria to settle the question of whether
machines can think, a question of which we now know that it is about as
relevant as the question of whether submarines can swim.
-- Dijkstra


Avatar
James Kanze
Laurent Deniau writes:

[...]

|> Tu omets egalement le probleme de performance de sscanf dans le cas
|> ou la chaine de charactere est longue. Probleme que j'ai deja
|> souleve ici-meme. La combinaison fgets+sscanf n'est pas garantie
|> d'etre plus rapide que fscanf directement, bien que ce soit
|> generalement le but recherche de cette construction.

Le but récherché de cette construction, c'est prèsque toujours de
simplifier la résynchronisation en cas d'erreur, pas la vitesse.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Avatar
Emmanuel Delahaye
James Kanze wrote on 03/11/04 :
Laurent Deniau writes:
Tu omets egalement le probleme de performance de sscanf dans le cas
ou la chaine de charactere est longue. Probleme que j'ai deja
souleve ici-meme. La combinaison fgets+sscanf n'est pas garantie
d'etre plus rapide que fscanf directement, bien que ce soit
generalement le but recherche de cette construction.



Le but récherché de cette construction, c'est prèsque toujours de
simplifier la résynchronisation en cas d'erreur, pas la vitesse.


Absolutely.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"C is a sharp tool"



Avatar
Emmanuel Delahaye
Anthony Fleury wrote on 02/11/04 :
fflush(stdin);


hum, Lire la FAQ ! fflush(stdin) n'est pas utile, vu que stdin en général
n'est pas un flux accessible en écriture. Le moyen de le vider c'est le
fameux while du dessus, en gros fflush sur stdin ne sert à rien et n'a
aucun effet.


Pire que ça, c'est un UB. En clair, sur certaines machines,(Unixoides),
ça plante.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"C is a sharp tool"


Avatar
Pierre Maurette
Anthony Fleury a écrit:

Hamiral wrote:


fgets() reads in at most one less than size characters
Mais c'est pas possible ça, la deuxième fois que je poste un ânerie plus

grosse que moi sur ce groupe. Pourant j'avais lu la manpage juste
avant de poster, pour être sûr. Mais j'ai dû lire un peu vite, j'ai
sauté le "one less" ...
Mea culpa, je posterai plus avant de lire 7 fois la manpage
correspondante.


Y'a pas de mal, je suis loin d'être le dernier à en dire (merci au passage à
ceux qui me corrigent et donc me font progresser).
De plus, il y a tellement de fonctions « bizarres » dans la manipulation de
chaines (cf les discussions sur strncpy et strncat)
[HS]

Justement. J'ai le sentiment, certainement erronné, que beaucoup de
ces fonctions sont plus sources d'emmerdements que facteurs de gain de
temps. J'ai vraiment l'impression que quand on a compris la base,
c'est à dire ce qu'est une chaîne, l'allocation/libération de mémoire,
tableaux, pointeurs, durée de vie, il est plus simple et plus sûr d'en
écrire une version adaptée à son besoin que de se prendre la tête avec
le fonctionnement garanti des fonctions de la librairie standard. Un
exemple: et si j'envoie un NULL à strcat(), etc. Bien entendu,
beaucoup de fonctions appelant l'OS (E/S en particulier) sont
indispensables.
[/HS]
--
Pierre



Avatar
Emmanuel Delahaye
Richard Delorme wrote on 03/11/04 :
Donc préferer fgets() :

fgets(nom, NOMBRE_DE_CARACTERE_MAX, stdin);


En quoi :
scanf("%" #NOMBRE_DE_CARACTERE_MAX "s", nom);


Le # fonctionne hors d'une macro ? Première nouvelle...

#include <stdio.h>

#define X 5

int main (void)
{
printf ("%" #X "sn", "hello");

return 0;
}

Compilateur: Default compiler
Building Makefile: "D:Dev-CppMakefile.win"
Exécution de make...
make.exe -f "D:Dev-CppMakefile.win" all
gcc.exe -D__DEBUG__ -c main.c -o main.o -I"C:/DEV-CPP/include" -W -Wall
-O2 -ansi -DTEST -g3 main.c: In function `main':
main.c:8: syntax error at '#' token
main.c:8: parse error before numeric constant gcc.exe -D__DEBUG__
main.o -o "Projet1.exe" -L"C:/DEV-CPP/lib" C:/Dev-Cpp/lib/libws2_32.a
-g3 Exécution terminée

est moins sûr ?


Problème de resynchronisation en cas d'erreur.
Problème du 'n' pendant...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"C is a sharp tool"


Avatar
Richard Delorme
Richard Delorme wrote on 03/11/04 :

Donc préferer fgets() :
fgets(nom, NOMBRE_DE_CARACTERE_MAX, stdin);



En quoi :
scanf("%" #NOMBRE_DE_CARACTERE_MAX "s", nom);



Le # fonctionne hors d'une macro ? Première nouvelle...


<mauvaise foi = on>
Comment sais-tu que la ligne que j'ai écrit ne suit pas la ligne suivante :
#define lit_nom(nom, NOMBRE_DE_CARACTERE_MAX)
?
</mauvaise foi = off>

est moins sûr ?


Problème de resynchronisation en cas d'erreur.


parce que fgets() est plus simple à synchroniser ?

Problème du 'n' pendant...


A mon avis plus facile à résoudre avec scanf qu'avec fgets.

--
Richard



Avatar
Laurent Deniau
James Kanze wrote:
Laurent Deniau writes:

[...]

|> Tu omets egalement le probleme de performance de sscanf dans le cas
|> ou la chaine de charactere est longue. Probleme que j'ai deja
|> souleve ici-meme. La combinaison fgets+sscanf n'est pas garantie
|> d'etre plus rapide que fscanf directement, bien que ce soit
|> generalement le but recherche de cette construction.

Le but récherché de cette construction, c'est prèsque toujours de
simplifier la résynchronisation en cas d'erreur, pas la vitesse.


qu'est ce que tu appelles la resynchronisation ?

a+, ld.

Avatar
Antoine Leca
En cmcnd8$d2l$, Laurent Deniau va escriure:
<sscanf>
Le but récherché de cette construction, c'est prèsque toujours de
simplifier la résynchronisation en cas d'erreur, pas la vitesse.


qu'est ce que tu appelles la resynchronisation ?


Quand tu as une erreur sur la chaîne d'entrée (donc un résultat pas attendu
comme valeur retournée par xscanf), avec sscanf pas de souci, tu peux
recommencer autant de fois que tu le veux; avec fscanf, tu ne sais pas où tu
en es dans le flux, la seule vraie posssibilité c'est rewind et relire tout
depuis le début :-( (en terme applicatif, cela devient: « la base de données
est corrumpue, veuillez lancer le programme de maintenance »).


Antoine


Avatar
Laurent Deniau
Antoine Leca wrote:
En cmcnd8$d2l$, Laurent Deniau va escriure:
<sscanf>

Le but récherché de cette construction, c'est prèsque toujours de
simplifier la résynchronisation en cas d'erreur, pas la vitesse.


qu'est ce que tu appelles la resynchronisation ?



Quand tu as une erreur sur la chaîne d'entrée (donc un résultat pas attendu
comme valeur retournée par xscanf), avec sscanf pas de souci, tu peux
recommencer autant de fois que tu le veux; avec fscanf, tu ne sais pas où tu
en es dans le flux, la seule vraie posssibilité c'est rewind et relire tout
depuis le début :-( (en terme applicatif, cela devient: « la base de données
est corrumpue, veuillez lancer le programme de maintenance »).


pourquoi ne pas mettre un %n avant chaque conversion (et eventuellement
apres). Un fseek te permettrait de revenir a la derniere conversion
correcte.

a+, ld.