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
Laurent Deniau
Erwann ABALEA wrote:
Bonjour,

On Thu, 11 Nov 2004, James Kanze wrote:


"Charlie Gordon" writes:

|> C: printf("x=%d, y=%dn", x, y);
|> C++: cout << "x=" << x << ", y=" << y << "n";
|> Javascript: document.write("x=" + x + ", y=" + y + "n");
|> Perl: print("x=$x, y=$yn");

|> Il faut bien reconnaitre que Perl est de loin le plus lisible.

Il faut comparer ce qui est comparable. Ajoutons un peu de formattage,
par exemple, pour sortir des expressions :

Basic: PRINT USING "x = ###0.00, y = 00", x * PI, y - 2
C : printf( "x = %6.2f, y = %02dn", x * PI, y - 2 ) ;
C++ : std::cout << "x = " << std::fix << std::setprecision( 2 )
<< std::setw( 6 ) << x * PI << ", y = " << std::setfill( '0' )
<< std::setw( 2 ) << y - 2 << std::endl ;
ou C++ : std::cout << "x = " << FmtFix( 6, 2 ) << x * PI
<< FmtZeroFill( 2 ) << y - 2
<< std::endl ;



En Perl, ça donne ceci...
définition du format:
format STDOUT > x = @###.##, y = @0#
$x, $y
.

Et à chaque fois qu'on veut sortir des infos selon ce format, on renseigne
$x et $y, et on fait:
write;

La définition du format permet des choses plus souples (multilignes, avec
ou sans répétition d'un motif, ...).
Ca n'est pas tout à fait équivalent, puisque cette méthode ne permet pas
de reproduire le "%02d" (ici c'est un "%03d"). Pour reproduire le "%02d",
c'est plus compliqué.

C'est bien la première fois que je vois un truc plus compliqué en Perl,
tiens.


La doc de Perl precise que les formats sont fait pour du formattage
simple de rapport. Si c'est un peu complique, il faut se taper le code a
la main et on retrouve du simili-C a-la printf.

a+, ld.


Avatar
James Kanze
Laurent Deniau writes:

|> James Kanze wrote:
|> > "Charlie Gordon" writes:
|> > |> "Jean-Marc Bourguet" wrote in message
|> > |> news:
|> > |> > drkm writes:
|> > |> > > Jean-Marc Bourguet writes:
|> > |> > > > "Charlie Gordon" writes:
|> > |> > > >> L'utilisation de + en
|> > |> > > >> javascript ne donne pas de résultat satisfaisant non
|> > |> > > >> plus...
|> > |> > > > + est clairement de l'abus.
|> > |> > > Que fait-il ?
|> > |> > Je ne connais pas javascript, mais utiliser + pour effectuer
|> > |> > des E/S comme à l'air de l'indiquer Charlie c'est pire que
|> > |> > du Perl...
|> > |> Non, + fait juste la concaténation des chaines en javascript.
|> > |> Le problème est à la fois une question de lisibilité et un
|> > |> problème de typage. On peut comparer la lisibilité respective
|> > |> de :

|> > |> C: printf("x=%d, y=%dn", x, y);
|> > |> C++: cout << "x=" << x << ", y=" << y << "n";
|> > |> Javascript: document.write("x=" + x + ", y=" + y + "n");
|> > |> Perl: print("x=$x, y=$yn");
|> > |> Il faut bien reconnaitre que Perl est de loin le plus lisible.

|> > Il faut comparer ce qui est comparable. Ajoutons un peu de
|> > formattage, par exemple, pour sortir des expressions :

|> > Basic: PRINT USING "x = ###0.00, y = 00", x * PI, y - 2
|> > C : printf( "x = %6.2f, y = %02dn", x * PI, y - 2 ) ;
|> > C++ : std::cout << "x = " << std::fix << std::setprecision( 2 )
|> > << std::setw( 6 ) << x * PI << ", y = " << std::setfill( '0' )
|> > << std::setw( 2 ) << y - 2 << std::endl ;
|> > ou C++ : std::cout << "x = " << FmtFix( 6, 2 ) << x * PI
|> > << FmtZeroFill( 2 ) << y - 2
|> > << std::endl ;
|> > (Le deuxième forme en C++ utilise les manipulateurs « maison ».
|> > Dans la pratique, je ne crois pas qu'on fasse des sorties
|> > formattées en C++ sans de manipulateurs maison.)

|> Si tu veux que la comparaison soit honnete, tu ne devrais pas
|> utiliser tes formateurs maison car dans ce cas les autres languages
|> aussi peuvent faire mieux.

La différence, c'est que les iostreams ont été conçu avec l'idée en tête
que l'utilisateur pourrait faire ses propres manipulateurs. C'est plutôt
l'exception (ou des exercises de l'école) où on ne le fait pas.

Mais ce n'était pas réelement mon propos. Au fond, j'ai introduit mes
propres manipulateurs surtout pour les fins de la discussion qui
suivait, sur les balises logiques.

|> Par exemple en C on pourrait ecrire:

|> std_cout
|> ->str("x =") ->fix(6,2) ->dbl(x*PI)
|> ->str("y =") ->fill(2,'0') ->dbl(y-2)
|> ->chr('n');

|> que je trouve tout aussi lisible. Perso ce n'est pas ce que
|> j'utilise parce que j'ai besoin de formatage beaucoup plus complexe,
|> c'est juste pour l'exemple.

Pourquoi pas. Si je voulais vraiement faire ce genre d'argument, j'aurai
pris GB_Format, qui est 100% compatible avec les chaînes de formattages
X/Open (pré C99, c-à-d sans le formattage hex des flottants). On peut le
faire en C++. Mais je voulais plutôt une discussion plus général, sur
une question du genre : qu'est-ce qui fait qu'une technique de
formattage est bien ou non ?

--
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
Laurent Deniau
James Kanze wrote:
Laurent Deniau writes:

|> James Kanze wrote:
|> > "Charlie Gordon" writes:
|> > |> "Jean-Marc Bourguet" wrote in message
|> > |> news:
|> > |> > drkm writes:
|> > |> > > Jean-Marc Bourguet writes:
|> > |> > > > "Charlie Gordon" writes:
|> > |> > > >> L'utilisation de + en
|> > |> > > >> javascript ne donne pas de résultat satisfaisant non
|> > |> > > >> plus...
|> > |> > > > + est clairement de l'abus.
|> > |> > > Que fait-il ?
|> > |> > Je ne connais pas javascript, mais utiliser + pour effectuer
|> > |> > des E/S comme à l'air de l'indiquer Charlie c'est pire que
|> > |> > du Perl...
|> > |> Non, + fait juste la concaténation des chaines en javascript.
|> > |> Le problème est à la fois une question de lisibilité et un
|> > |> problème de typage. On peut comparer la lisibilité respective
|> > |> de :

|> > |> C: printf("x=%d, y=%dn", x, y);
|> > |> C++: cout << "x=" << x << ", y=" << y << "n";
|> > |> Javascript: document.write("x=" + x + ", y=" + y + "n");
|> > |> Perl: print("x=$x, y=$yn");
|> > |> Il faut bien reconnaitre que Perl est de loin le plus lisible.

|> > Il faut comparer ce qui est comparable. Ajoutons un peu de
|> > formattage, par exemple, pour sortir des expressions :

|> > Basic: PRINT USING "x = ###0.00, y = 00", x * PI, y - 2
|> > C : printf( "x = %6.2f, y = %02dn", x * PI, y - 2 ) ;
|> > C++ : std::cout << "x = " << std::fix << std::setprecision( 2 )
|> > << std::setw( 6 ) << x * PI << ", y = " << std::setfill( '0' )
|> > << std::setw( 2 ) << y - 2 << std::endl ;
|> > ou C++ : std::cout << "x = " << FmtFix( 6, 2 ) << x * PI
|> > << FmtZeroFill( 2 ) << y - 2
|> > << std::endl ;
|> > (Le deuxième forme en C++ utilise les manipulateurs « maison ».
|> > Dans la pratique, je ne crois pas qu'on fasse des sorties
|> > formattées en C++ sans de manipulateurs maison.)

|> Si tu veux que la comparaison soit honnete, tu ne devrais pas
|> utiliser tes formateurs maison car dans ce cas les autres languages
|> aussi peuvent faire mieux.

La différence, c'est que les iostreams ont été conçu avec l'idée en tête
que l'utilisateur pourrait faire ses propres manipulateurs. C'est plutôt
l'exception (ou des exercises de l'école) où on ne le fait pas.

Mais ce n'était pas réelement mon propos. Au fond, j'ai introduit mes
propres manipulateurs surtout pour les fins de la discussion qui
suivait, sur les balises logiques.

|> Par exemple en C on pourrait ecrire:

|> std_cout
|> ->str("x =") ->fix(6,2) ->dbl(x*PI)
|> ->str("y =") ->fill(2,'0') ->dbl(y-2)
|> ->chr('n');

|> que je trouve tout aussi lisible. Perso ce n'est pas ce que
|> j'utilise parce que j'ai besoin de formatage beaucoup plus complexe,
|> c'est juste pour l'exemple.

Pourquoi pas. Si je voulais vraiement faire ce genre d'argument, j'aurai
pris GB_Format, qui est 100% compatible avec les chaînes de formattages
X/Open (pré C99, c-à-d sans le formattage hex des flottants). On peut le
faire en C++. Mais je voulais plutôt une discussion plus général, sur
une question du genre : qu'est-ce qui fait qu'une technique de
formattage est bien ou non ?


- la simplicite,
- la flexibilite,
- la robustesse,
- la rapidite.

Maintenant que j'ai repondu a ta question, on fait quoi? ;-)

Le probleme (comme d'habitude), c'est de trouver l'interface qui repond
aux qualites ci-dessus.

De mon cote, j'utilise des formateurs dans le cadre de protocol
(equivalent des interfaces Java). La double indirection combinee avec le
dynamic binding des protocols me permet de tout faire mais c'est un peu
lourd a manipuler pour les types de base (surtout parce que je suis en
C, en C++ cela pourrait etre syntaxiquement plus simple) et c'est un peu
plus lent que les stdio sur les tres petits objets qui n'ont (presque)
pas de formatage (char).

Par exemple, pour ecrire un objet:

pcalln(obj, Fio, out, stream, format);

si le protocol Fio n'est pas supporte par obj, il leve une exception
eBadCast sinon il invoque la methode Fio.out de obj qui elle meme
renvoie la balle au formater par:

calln(format, out, stream, self); // self est obj dans Fio.out

et le formateur qui hormis le fait qu'il implemente les methodes in et
out, fait ce qu'il veut pour ecrire obj sur le stream. Le stream n'est
pas necessairement un fichier.

Certain formater sont tres complexes et peuvent etre de vrai parseur
bases par exemple sur l'introspection des objets a lire/ecrire plus une
configuration dynamique.

Pour noter cette interface par rapport aux criteres cites je mettrais:

simplicite 4/5 (toute la complexite est dans le formateur)
flexibilite 5/5 (pas vu de cas impossible a traite)
robustesse 5/5 (depend du formateur)
rapidite 4/5 (depend du formateur et du stream)

J'aurais aime avoir 5/5 pour la simplicite, mais c'est pas le cas car la
configuration des formateurs peut etre complexe s'il l'est lui meme.

La rapidite depend surtout de la taille des objets a lire/ecrire. Sur un
char c'est penalisant. Sur un parseur XML c'est completement
negligeable. Mais en general tout cela va sur une I/O generalement lent
(FILE, Socket, DB, ...).

La robustesse depend du temps que l'on est pret a investir dans
l'implementation du formateur. Si c'est pour faire des printf, c'est pas
5/5 ;-)

call = invocation de methode (avec n s'il y a des arguments)
pcall = invocation de methode de protocol

a+, ld.

PS. 1ere fois que je te fais un reply a la mesure de la longueur de tes
posts :-)

Avatar
James Kanze
Laurent Deniau writes:

|> James Kanze wrote:
|> > Laurent Deniau writes:

|> > Pourquoi pas. Si je voulais vraiement faire ce genre d'argument,
|> > j'aurai pris GB_Format, qui est 100% compatible avec les chaînes
|> > de formattages X/Open (pré C99, c-à-d sans le formattage hex des
|> > flottants). On peut le faire en C++. Mais je voulais plutôt une
|> > discussion plus général, sur une question du genre : qu'est-ce qui
|> > fait qu'une technique de formattage est bien ou non ?

|> - la simplicite,
|> - la flexibilite,
|> - la robustesse,
|> - la rapidite.

|> Maintenant que j'ai repondu a ta question, on fait quoi? ;-)

Je te donne une implémentation qui remplit toutes tes exigeances :

void
format( void* )
{
}

C'est simple, flexible, robuste et on ne peut plus rapide.

En fait, on était en train de comparer des syntaxes de formattage de
sortie. Or, pour comparer, il faut savoir quel sont les critères de
comparaison. J'accepte que la simplicité à l'utilisation est bien
quelque chose d'important, mais les autres critères que tu cites
tiennent plus de l'implémentation, non du syntaxe. En revanche, tu
n'adresses en rien le problème de base : formatter pour quoi faire ? Si
je n'ai pas besoin de l'internationalisation, par exemple, je peux bien
faire plus simple pour l'utlisateur.

|> Le probleme (comme d'habitude), c'est de trouver l'interface qui
|> repond aux qualites ci-dessus.

Avant de considérer ces qualités (qui en fait pour la plupart concerne
plus l'implémentation que l'interface), je dirais qu'il faut définir ce
qu'on veut accomplir avec l'interface.

--
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
Laurent Deniau
James Kanze wrote:
Laurent Deniau writes:

|> James Kanze wrote:
|> > Laurent Deniau writes:

|> > Pourquoi pas. Si je voulais vraiement faire ce genre d'argument,
|> > j'aurai pris GB_Format, qui est 100% compatible avec les chaînes
|> > de formattages X/Open (pré C99, c-à-d sans le formattage hex des
|> > flottants). On peut le faire en C++. Mais je voulais plutôt une
|> > discussion plus général, sur une question du genre : qu'est-ce qui
|> > fait qu'une technique de formattage est bien ou non ?

|> - la simplicite,
|> - la flexibilite,
|> - la robustesse,
|> - la rapidite.

|> Maintenant que j'ai repondu a ta question, on fait quoi? ;-)

Je te donne une implémentation qui remplit toutes tes exigeances :

void
format( void* )
{
}

C'est simple, flexible, robuste et on ne peut plus rapide.


simple, non. Ce n'est pas parce que je dois appeler une seule fonction
avec un seul argument que cela est simple. Ton void* doit pointer vers
qqchose qu'il faut configurer et qui doit contenir toute l'info
necessaire a la flexibilite demandee.

flexible, peut-etre. Ca depend de ce que tu mets derriere le void*. Mais
la fexibilite sera inversement proportionnelle a la simplicite.

robuste, idem.
rapide, idem.

En fait, on était en train de comparer des syntaxes de formattage de
sortie. Or, pour comparer, il faut savoir quel sont les critères de


Non, j'etais entrain de comparer quel sont les elements essentiels pour
pouvoir repondre aux criteres et d'y associer une interface simple.

comparaison. J'accepte que la simplicité à l'utilisation est bien
quelque chose d'important, mais les autres critères que tu cites


essentielle, mais moins que la flexibilite. Parce que si le programmeur
ne peut pas faire ce qu'il veut, il jette tout et recommence avec ses
classes/structures.

tiennent plus de l'implémentation, non du syntaxe. En revanche, tu


Au contraire. L'implementation n'a rien a voir. C'est pour cela que dans
mon exemple je ne sais rien de format (qui est une classe abstraite).
C'est une delegation complete. Le probleme est de savoir a qui je dois
deleguer le formatage, pas le formatage lui-meme.

n'adresses en rien le problème de base : formatter pour quoi faire ? Si
je n'ai pas besoin de l'internationalisation, par exemple, je peux bien
faire plus simple pour l'utlisateur.


L'internationalisation n'est pas le seul probleme de formatage, meme si
c'est un probleme tres complexe en soi. Mais je dirais que ca fait parti
de la couche 'bas niveau' du formatage, juste au dessus de la couche de
conversion et de bufferisation.

|> Le probleme (comme d'habitude), c'est de trouver l'interface qui
|> repond aux qualites ci-dessus.

Avant de considérer ces qualités (qui en fait pour la plupart concerne
plus l'implémentation que l'interface), je dirais qu'il faut définir ce
qu'on veut accomplir avec l'interface.


Formater des donnees de maniere generique quelque soit le format (inclus
binaire, xdr, texte et texte structure) avec la possibilite de l'etendre
facilement, avec (presque) aucun couplage entre les classes de donnees
et les classes de formatage pour avoir la possibilite d'introduire de
nouveaux formats pour une classe 'data' sans toucher a cette derniere.

Si je prends l'exemple des IOStream du C++, autant je trouve que les
couches existantes du C (transport, buffering & low-level formatting)
ont bien ete classerisees (structurees en classes, je sais pas ce qu'on
doit dire ;-)) autant je trouve que cote *formatage* il n'y a aucune
inovation et l'ensemble reste tres statique et complexe.

Je prefere l'approche ou a chaque Stream, on peut attacher un
StreamStyle qui fait le lien entre des classes et leur formatage. C'est
lui qui resoud le probleme de trouver le format a qui deleguer la tache
si l'utilisateur ne le fournit pas explicitement. En utilisant une
hierachie de format et de style on obtient un ensemble flexible avec un
minimum de code. Dommage pour le C++ parce que le principe des iword,
pword et xalloc fait deja la moitie du travail, mais ils auraient du
mettre des classes (des styles) au lieu de long et void*. La encore ils
avaient probablement trop en tete de vouloir pouvoir faire la meme chose
que le C (c'est une pure speculation, mais c'est l'impression que ca donne).

a+, ld.

Avatar
Emmanuel Delahaye
James Kanze wrote on 13/11/04 :
Je te donne une implémentation qui remplit toutes tes exigeances :

void
format( void* )
{
}

C'est simple, flexible, robuste et on ne peut plus rapide.


Ne compile pas. Il manque le nom du paramètre.

--
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
Charlie Gordon
"Emmanuel Delahaye" wrote in message
news:
James Kanze wrote on 13/11/04 :
Je te donne une implémentation qui remplit toutes tes exigeances :

void
format( void* )
{
}

C'est simple, flexible, robuste et on ne peut plus rapide.


Ne compile pas. Il manque le nom du paramètre.


Dommage, ne pas nommer le paramètre est pourtant une façon simple de dire qu'il
n'est pas utilisé !
Il semblerait que cette proposition n'ait pas été retenue pour être intégrée au
standard.
Qui en sait plus à ce sujet ?

Chqrlie.


Avatar
Laurent Deniau
Charlie Gordon wrote:
"Emmanuel Delahaye" wrote in message
news:

James Kanze wrote on 13/11/04 :

Je te donne une implémentation qui remplit toutes tes exigeances :

void
format( void* )
{
}

C'est simple, flexible, robuste et on ne peut plus rapide.


Ne compile pas. Il manque le nom du paramètre.



Dommage, ne pas nommer le paramètre est pourtant une façon simple de dire qu'il
n'est pas utilisé !
Il semblerait que cette proposition n'ait pas été retenue pour être intégrée au
standard.
Qui en sait plus à ce sujet ?


Quel est l'interet?

a+, ld.



Avatar
Charlie Gordon
"Laurent Deniau" wrote in message
news:cncg88$4su$
Charlie Gordon wrote:
"Emmanuel Delahaye" wrote in message
news:

James Kanze wrote on 13/11/04 :

Je te donne une implémentation qui remplit toutes tes exigeances :

void
format( void* )
{
}

C'est simple, flexible, robuste et on ne peut plus rapide.


Ne compile pas. Il manque le nom du paramètre.



Dommage, ne pas nommer le paramètre est pourtant une façon simple de dire
qu'il


n'est pas utilisé !
Il semblerait que cette proposition n'ait pas été retenue pour être intégrée
au


standard.
Qui en sait plus à ce sujet ?


Quel est l'interet?


Le prototype de la fonction peut etre fixé par des contraintes externes à
celle-ci,
On peut par exemple faire emettre un warning par le compilo quand une variable
est declaree mais pas utilisee.
Dans le cas des parametres de fonction, cela peut etre voulu.
Disposer d'une methode portable pour preciser cela n'est pas inutile.
Cela évite la tentation des extension sordides du style #pragma unused et
autres.

On a bien des unnamed bitfields

Qu'en est-il des champs de structure non nommés, des unions transparentes ?

Chqrlie




Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Quel est l'interet?


- Avoir un moyen portable de dire que c'est volontaire que le parametre
ne soit pas utilise. Ca evite les /*LINT:UNUSED*/ et autres pragmas.

- Supprimer une difference mineure avec le C++.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org