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
drkm
"Charlie Gordon" writes:

"drkm" wrote in message
news:

Mais Boost.Format permet justement de spécifier l'ordre dans la
chaîne de formatage, sans modifier l'ordre des opérandes dans les
sources. Et il utilise bien les IOStreams standards, non ?

Le GB_Format de James également, si je ne m'abuse.


Oui, on peut écrire ou utiliser une librairie pour faire cela. Je parlais des
IOStreams du standard.


Moi aussi. Les IOStreams ne permettent pas de réordonnement
directement par leur interface. Si tu veux le fournir, il te faut
l'implémenter.

Pour moi, dans ce sens, utiliser les IOStreams ne signifie pas
« utiliser l'opérateur << dans l'instruction de sortie », mais faire
en sorte que ce que l'on implémente ne se serve que de l'interface de
std::ostream, de manière à pouvoir être utilisé avec tout type basé
sur cette dernière.

En C:

printf("alphabetically: red %d, yellow: %dn", red, yellow);

en C++:

cout << "alphabetically: red " << red << ", yellow: " << yellow << "n";


Je suppose que tu pensais plutôt à quelque chose comme :

printf( "alphabetically: %s, %sn" , red , yellow ) ;

Comment faire pour changer l'ordre pour le français, sans recompiler ni avoir
recours à une tierce librairie.


En implémentant toi-même cette bibliothèque tierce ;-)

On peut le faire avec du code spécifique, mais c'est lourd.


Bof.

std::ostream & out = any_std_ostream_derived_object ;
std::string red = "red" ;
std::string yellow = "yellow" ;

out << GB_Format( "alphabetically : %1$s, %2$s" )
.with( red )
.with( yellow )
<< std::endl ;

out << boost::format( "alphabetically : %1%, %2%" )
% red
% yellow
<< std::endl ;

red = "rouge" ;
yellow = "jaune" ;

out << GB_Format( "par ordre alphabétique : %2$s, %1$s" )
.with( red )
.with( yellow )
<< std::endl ;

out << boost::format( "par ordre alphabétique : %2%, %1%" )
% red
% yellow
<< std::endl ;

Je ne vois pas en quoi c'est plus lourd que d'utiliser printf.

--drkm


Avatar
drkm
"Charlie Gordon" writes:

Enfin pour ce qui est de la flexibilité pour la traduction avec changement
d'ordre des paramètres, des quatre seuls C et Perl s'y prêtent


Non. Voir les pistes que j'ai données.

--drkm

Avatar
James Kanze
"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.) Je ne sais pas pour les autres langages, mais
je suis près à admettre qu'ils fassent plus lisible que le C++ (surtout
la première version, strictement standard).

Ceci dit, il y a plusieurs points à considérer :

- On peut faire mieux que le C. Le Basic, par exemple (qui s'inspire
en simplifiant les clause PICTURE du Cobol). L'avantage du système
Basic est particulièrement perceptible quand on fait des tableaux
(avec une police à chasse fixe) -- le nombre de caractères dans le
format correspond chaque fois au nombre de caractères à sortir. On
met les formats les uns audessus des autres, et on voit tout de
suite à quoi ressemble la table, par exemple :

HEADER$ = " etiquette1 etiquette2 "
LINE$ = " ###0.00 ###00"
ENTRELIGNE$ = " ------- -----"

(Mais qui de nos jours sort quoique ce soit destiné à l'utilisateur
avec une police à chasse fixe ?)

- Que faire quand il faut traduire le texte (pour
l'internationalisation) ? La solution C++ est, dans ce cas-ci,
totalement inutilisable. Dans un système Posix, en revanche, il y a
bien une extension à printf qui me permet d'écrire :
printf( "%2$02d = y, %1$6.2f = xn", x * PI, y - 2 ) ;
C'est parfois utile, mais il ne faut pas le sur-estimé non plus --
il y a toujours des problèmes du genre :
printf( "J'ai %d %sn", p->count, p->name ) ;
qui pose un problème -- si la phrase générée est correcte si
p->count > 1, elle ne le serait typiquement pas pour p->count == 1.
La solution classique que j'ai vue en anglais, c'est quelque chose
du genre :
printf( "J'ai %d %s%sn", p->count, p->name,
(p->count == 1) ? "" : "s" ) ;
Ce qui ne marche pas, évidemment, pour p->name == "fils" (ou
"child", en anglais). Et qui ne supporte pas la traduction en
allemand ni en italiens. Mieux serait :
printf( "J'ai %d %sn", p-count, p->name[ p->count == 1 ] ) ;
Mais il reste des problèmes avec des langues qui connaissent le duel
(l'arabe, je crois), ou des langues comme la russe, ou des comptes
comme 21, 31, etc., sont normalement suivi du singulier.

Au délà d'un certain niveau de complexité dans l'expression, la
seule solution reste du code propre pour chaque langue, dans un
objet dynamique qu'on charge selon la langue voulue.

- Enfin, un problème général : au fond, on ne veut pas avoir à dire
qu'on veut un flottant formatté en virgule fix, avec deux caractères
après le décimal. Logiquement, on aimerait plutôt dire qu'on veut
formatter le flottant comme une valeur de monnaie, ou comme une
mésure de je ne sais quoi, et spécifier les paramètres de formattage
ailleur (peut-être même dans un fichier de configuration). Et pour
faire ça, c'est la solution C++ qui le permet -- j'écris mes
manipulateurs FmtMoney et FmtSomethingElse, et puis j'écris :
std::cout << "x = " << FmtMoney( 6 ) << x
<< ", y = " << FmtSomethingElse( 4 ) << y
<< std::end ;
(Ceux qui s'y connaissent un peu dans le traitement de texte
reconnaîtront la distinction ici entre les balises logiques et les
balises physiques.)

|> Le problème de typage est causé par la combinaison du polymorphisme
|> de l'opérateur + et du typage dynamique des variables en javascript.
|> Il arrive souvent que les variables n'ont pas le type que le
|> programmeur intuite lorsqu'il écrit une expression. Or la sémantique
|> de l'addition des nombres et de la concaténation des chaines sont
|> fort différentes, comme la comparaison numérique et lexicographique.
|> Utiliser la meme syntaxe pour ces deux concepts est une source de
|> bugs.

Le problème, je crois, n'est pas l'utilisation de l'opérateur + pour le
concatentation (encore qu'on pourrait la trouver discutable), mais
plutôt les conversions implicites des valeurs numériques en chaîne de
caractères.

|> Ce problème ne se pose pas en C : il n'y a pas d'opérateur de
|> concaténation de chaines.

Ce qui est en soi un problème, si l'application veut qu'on concatène des
chaînes.

|> En C++ ou en java, le type des opérandes est mieux contrôlé par le
|> programmeur parce que le typage est statique. Mais il arrive quand
|> meme lors des comparaisons si les conventions de nommages ne sont
|> pas assez claires. Le grand classique est :

|> if (this->montant > this->montant_max) {
|> /* traiter l'erreur */
|> }

|> si ces champs sont des chaines, le code reste correct, mais la
|> sémantique change.

Parce qu'on a été assez bête pour défnir l'opérateur > sur des chaînes ?
(Je sais qu'en C++, mes chaînes pré-standard ne supportait pas les
opérateurs de comparaison. Je ne sais faire un ordre significatif aux
chaînes que dans le contexte de l'internationalisation.)

|> C++, javascript, et surtout PHP ont ce problème. Il peut meme se
|> produire en C !

Tout à fait :
char* p1 = "du texte" ;
char* p2 = "autre chose" ;
if ( p1 < p2 ) ...
Ici, le problème, c'est parce qu'on n'a pas de type pour les chaînes.
Dans les autres langages, c'est parce qu'on a surchargé les opérateurs
qu'il ne fallait pas sur les chaînes.

|> En Perl, les opérations de comparaisons numériques et
|> lexicographiques s'expriment avec des opérateurs différents. Pareil
|> pour l'addition et la concaténation.

|> Enfin pour ce qui est de la flexibilité pour la traduction avec
|> changement d'ordre des paramètres, des quatre seuls C et Perl s'y
|> prêtent, et encore pour C il faut une extension POSIX assez
|> illisible, et pour Perl c'est grâce à la recompilation que cela se
|> fait bien.

Et même dans ces deux cas, il peut y avoir des problèmes. Si tu donnes
des textes à un traducteur à traduire, il y a une risque non negligeable
qu'il modifie, par erreur, un des caractères de formattage. C'est bien
amusant, en C, de chercher un boggue qui n'apparaît qu'en locale
finlandais, parce que le traducteur (parce que ce n'est pas moi qui va
faire la traduction en finlandais) a changé un %d en %s lorsqu'il le
changer de place.

|> J'ai étudié comment faire une extension de syntaxe au langage C pour
|> supporter la substitution de variables dans les chaines, avec autant
|> que possible de bonnes propriétés pour la localisation sans
|> recompilation : on peut obtenir des résultats intéressants dans des
|> contextes spécifiques comme le formatage des sorties, mais pour le
|> cas général, il faut un mécanisme de gestion des chaines de
|> caractères dynamiques, qui a des implications assez lourdes partout.
|> Ce serait beaucoup plus facile à faire pour java.

Il y a un nombre de problèmes, et aucun langage au présent ne les résoud
tous de façon satisfaisant. Je me démande même si tous les problèmes ont
été compétement énoncés ; il faudrait peut-être commencer par une
spécification de ce qu'on veut accomplir.

--
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
James Kanze
drkm writes:

|> Jean-Marc Bourguet writes:

|> > drkm writes:

|> >> "Charlie Gordon" writes:

|> >> > Il est clair qu'en C++, le mécanisme des streams rend tout cela
|> >> > carrément impossible sans recompilation.

|> >> Que veux-tu dire ?

|> > Que si tu utilises les IOStreams et que tu veux modifier l'ordre
|> > de deux éléments dans un sortie (ce qui est possible simplement en
|> > changeant le format -- récupéré par le méchanisme de localisation
|> > -- avec un printf POSIX ou avec le formatage de boost) il faut
|> > modifier ton code et recompiler.

|> Mais Boost.Format permet justement de spécifier l'ordre dans la
|> chaîne de formatage, sans modifier l'ordre des opérandes dans les
|> sources. Et il utilise bien les IOStreams standards, non ?

|> Le GB_Format de James également, si je ne m'abuse.

Tout à fait, mais il ne sont pas standard. Et s'ils se basent sur des
iostream, ils formattent chaque champs séparement (dans un ostringstream
ou quelque chose de semblable). Le rassemblement de la chaîne complète
n'est pas fait par les iostream. (Au moins dans GB_Format, mais
j'imagine que boost::format fait à peu près pareil.)

--
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
James Kanze
Gabriel Dos Reis writes:

|> drkm writes:

|> | Jean-Marc Bourguet writes:

|> | > C'est la beauté des templates :-)

|> | Bof. En C, on a les macros de préprocesseur ;-)

|> T'as essayé ? semi ;-)

Oui:-). Et beauté n'est pas exactement le mot que je choisirais (pour la
solution à base de macros).

(Ceci dit, je ne comprends pas la rémarque de Jean-Marc dans ce cas
précis. L'implémentation originale de GB_Format n'utilisait pas de
template, pour la simple raison que le compilateur que j'avais à
l'époque ne les supportait pas. Et il n'utilisait pas de macro non plus.
En fait, le feature essentiel de C++ pour resoudre ce problème, c'est
plutôt le surcharge de l'opérateur.)

--
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
James Kanze
"Charlie Gordon" writes:

|> "drkm" wrote in message
|> news:
|> > Jean-Marc Bourguet writes:

|> > > drkm writes:

|> > >> "Charlie Gordon" writes:

|> > >> > Il est clair qu'en C++, le mécanisme des streams rend tout
|> > >> > cela carrément impossible sans recompilation.

|> > >> Que veux-tu dire ?

|> > > Que si tu utilises les IOStreams et que tu veux modifier
|> > > l'ordre de deux éléments dans un sortie (ce qui est possible
|> > > simplement en changeant le format -- récupéré par le
|> > > méchanisme de localisation -- avec un printf POSIX ou avec
|> > > le formatage de boost) il faut modifier ton code et
|> > > recompiler.

|> > Mais Boost.Format permet justement de spécifier l'ordre dans la
|> > chaîne de formatage, sans modifier l'ordre des opérandes dans les
|> > sources. Et il utilise bien les IOStreams standards, non ?

|> > Le GB_Format de James également, si je ne m'abuse.

|> Oui, on peut écrire ou utiliser une librairie pour faire cela. Je
|> parlais des IOStreams du standard.

|> En C:

|> printf("alphabetically: red %d, yellow: %dn", red, yellow);

|> en C++:

|> cout << "alphabetically: red " << red << ", yellow: " << yellow << "n";

|> Comment faire pour changer l'ordre pour le français, sans recompiler
|> ni avoir recours à une tierce librairie.

De la même façon qu'on traite des différences entre le pluriel et le
singulier. Si tu veux un ordre alphabètique, tu vas avoir une
implémentation par langue, de toute façon, parce qu'il te le faut pour
faire le tri alphabètique (qui lui aussi dépend du locale).

--
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
Jean-Marc Bourguet
James Kanze writes:

Gabriel Dos Reis writes:

|> drkm writes:

|> | Jean-Marc Bourguet writes:

|> | > C'est la beauté des templates :-)

|> | Bof. En C, on a les macros de préprocesseur ;-)

|> T'as essayé ? semi ;-)

Oui:-). Et beauté n'est pas exactement le mot que je choisirais (pour la
solution à base de macros).

(Ceci dit, je ne comprends pas la rémarque de Jean-Marc dans ce cas
précis.


Je faisais allusion qu'une solution à base de template
permet de gérer à la fois la position et la possibilité de
sortir des types défini par l'utilisateur.

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

Avatar
Laurent Deniau
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. 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.

a+, ld.

Avatar
Erwann ABALEA
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.

--
Erwann ABALEA - RSA PGP Key ID: 0x2D0EABD5
-----
En effet, les FAQ sont des "conseils d'utilisation"
et non des règles à respecter.
-+-BC in <http://neuneu.mine.nu> Si tu veux du CU, retourne à la FAQ-+-

Avatar
James Kanze
Jean-Marc Bourguet writes:

|> James Kanze writes:

|> > Gabriel Dos Reis writes:

|> > |> drkm writes:

|> > |> | Jean-Marc Bourguet writes:

|> > |> | > C'est la beauté des templates :-)

|> > |> | Bof. En C, on a les macros de préprocesseur ;-)

|> > |> T'as essayé ? semi ;-)

|> > Oui:-). Et beauté n'est pas exactement le mot que je choisirais
|> > (pour la solution à base de macros).

|> > (Ceci dit, je ne comprends pas la rémarque de Jean-Marc dans ce
|> > cas précis.

|> Je faisais allusion qu'une solution à base de template permet de
|> gérer à la fois la position et la possibilité de sortir des types
|> défini par l'utilisateur.

Disons que le template permet à fournir une fonction qui se base sur les
operator<< des flux standard, sans savoir d'avance tous les types pour
lesquels cet opérateur serait défini. Mais l'essentiel, à mon avis,
reste qu'on peut définir cet opérateur pour ces propres types.

(Il m'était arrivé une fois à programmer une extension à printf qui
supportait aussi les types définis par l'utilisateur. En gros, je
permettais une extension aux spécifications de formattage, du genre
%<...>. L'utilisateur pouvait alors inscrire des fonctions de formattage
à lui, sous un nom quelconque, et si le nom correspondait à ce qu'il y
avait entre les <...>, c'est cette fonction qui était appelée pour faire
le formattage. Et évidemment, les données étaient passées au moyen des
void*.)

--
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