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

Entrees formatees

21 réponses
Avatar
candide
Bonjour,

Je ne connais quasiment pas les entrées formatées voilà pourquoi je vous serais
reconnaissant de bien vouloir me dire si ce bout de code est correct voire
utilisable, merci :



/* ---------------------------- */
#include <stdio.h>

int main(void)
{
char s[100] = "Paris %d Marseille %d";
int p, m;

scanf(s, &p, &m);
printf(s, p, m);
printf("\n");
return 0;
}
/* ---------------------------- */

la capture étant effectuée en console par exemple en entrant la chaîne
suivante :

Paris 5 Marseille 9


[Naturellement, et en violation de l'adage "never trust user input", je suppose
que l'utilisateur entre la chaîne "correctement" ie les deux villes
orthographiées exactement comme dans le source sinon ça affiche des scores non
conformes.]

L'affichage retourné est le suivant :

Paris 5 Marseille 9

10 réponses

1 2 3
Avatar
-ed-
On 3 sep, 22:56, candide wrote:
Bonjour,

Je ne connais quasiment pas les entrées formatées voilà pourquoi je vous serais
reconnaissant de bien vouloir me dire si ce bout de code est correct voir e
utilisable, merci :

/* ---------------------------- */
#include <stdio.h>

int main(void)
{
  char s[100] = "Paris %d Marseille %d";
  int p, m;

  scanf(s, &p, &m);
  printf(s, p, m);
  printf("n");
  return 0;}

/* ---------------------------- */

la capture étant effectuée en console par exemple en entrant la cha îne
suivante :

Paris     5 Marseille    9

[Naturellement, et en violation de l'adage "never trust user input", je s uppose
que l'utilisateur entre la chaîne "correctement" ie  les deux villes
orthographiées exactement comme dans le source sinon ça affiche des s cores non
conformes.]

L'affichage retourné est le suivant :

Paris 5 Marseille 9



Ca fonctionne et c'est correct, mais je coderais ça comme ça :

#include <stdio.h>

int main(void)
{
#define FMT "Paris %d Marseille %d"

int p, m;

scanf(FMT, &p, &m);
printf(FMT"n", p, m);

return 0;
}

pour laisser une chance au compilateur de vérifier le codage...

Ceci dit, les contraintes de saisies imposées à l'utilisateur sont
telles que ce code est inutilisable dans la vrai vie...

de plus, il convient de vérifier la valeur retournée par scanf() avant
d'utiliser les valeurs saisies.

int n = scanf(FMT, &p, &m);
if (n == 2)
{
printf(FMT"n", p, m);
}
Avatar
candide
-ed- a écrit :


Ca fonctionne et c'est correct,



OK, merci.


mais je coderais ça comme ça :

#include <stdio.h>

int main(void)
{
#define FMT "Paris %d Marseille %d"

int p, m;

scanf(FMT, &p, &m);
printf(FMT"n", p, m);

return 0;
}

pour laisser une chance au compilateur de vérifier le codage...

Ceci dit, les contraintes de saisies imposées à l'utilisateur sont
telles que ce code est inutilisable dans la vrai vie...

de plus, il convient de vérifier la valeur retournée par scanf() avant
d'utiliser les valeurs saisies.

int n = scanf(FMT, &p, &m);
if (n == 2)
{
printf(FMT"n", p, m);
}



Bien sûr, je ferais les choses de manières plus sécurisées si j'avais à coder ça
un autre jour que le dimanche, voire je parserais la chaînes donnée en entrée.
Mais je voulais juste savoir si ça existait voire si ça se faisait car j'ai
rarement vu ce genre d'utilisation de scanf().
Avatar
Antoine Leca
Le 03/09/2009 20:56, candide écrivit :
Je ne connais quasiment pas les entrées formatées voilà pourquoi je vous serais
reconnaissant de bien vouloir me dire si ce bout de code est correct voire
utilisable, merci :
/* ---------------------------- */
#include <stdio.h>

int main(void)
{
char s[100] = "Paris %d Marseille %d";
int p, m;

scanf(s, &p, &m);
printf(s, p, m);
printf("n");
return 0;
}
/* ---------------------------- */



Autant on peut souvent se permettre d'ignorer la valeur de retour pour
printf, autant avec scanf ce n'est pas DU TOUT une bonne idée.

Ici, ton programme va déraper (comportement indéfini pour utilisation de
variable non initialisée, en l'occurrence m) dès lors qu'il y a la
moindre erreur de saisie en entrée.

Il est donc indispensable d'écrire pour le moins
if( 2!=scanf(s, &p, &m) ) return!0;


D'autre part part, si dans ce cas-là le parallèle entre les
spécifications de format permet d'utiliser la même chaîne, ce n'est pas
toujours le cas, surtout dès que tu augmentes les contraintes sur le
format d'entrée (pour « attraper » certains cas limites...)


la capture étant effectuée en console par exemple en entrant la chaîne
suivante :

Paris 5 Marseille 9

[Naturellement, et en violation de l'adage "never trust user input", je suppose
que l'utilisateur entre la chaîne "correctement" ie les deux villes
orthographiées exactement comme dans le source sinon ça affiche des scores non
conformes.]



Oui. Ce qui montre bien que scanf N'est PAS destinée à être utilisé pour
l'entrée console, mais bien pour relire des flux texte créés
antériorement avec printf.


L'affichage retourné est le suivant :

Paris 5 Marseille 9



... qui est une entrée correcte pour le programme, CQFD.



Antoine
Avatar
candide
Antoine Leca a écrit :

Il est donc indispensable d'écrire pour le moins
if( 2!=scanf(s, &p, &m) )



OK, je retiens cette idée (qui figurait aussi dans la réponse de -ed-).


Oui. Ce qui montre bien que scanf N'est PAS destinée à être utilisé pour
l'entrée console, mais bien pour relire des flux texte créés
antériorement avec printf.



C'est en effet plus ou moins l'idée de ce que je codais (mais pas en Python, je
voulais juste savoir par curiosité comme on faisait en C) : on a un jeu, avec
des scores dans un fichier texte, avec par exemple une ligne du genre

Meilleur score : 17


et on veut à jour le score sans s'obliger à réécrire toute la ligne.

D'une façon générale, je trouve que les sources d'apprentissage (au sens large y
compris les cours dans les facs ou ecoles) du langage C ne font pas un usage
assez limité et contrôlé des entrées. L'apprentissage des entrées cause un grand
ralentissement dans l'apprentissage et si le but est d'apprendre le langage, on
peut s'en passer 99 cas sur 100. En plus on les apprend sur l'entrée standard
("la console") ce qui est plein de pièges et de frustrations alors que tu
sembles nous dire que ce n'est pas le bon usage de scanf() ... En outre, ces
mêmes sources d'apprentissage passent sous silence pour la plupart comment on
peut exploiter le retour de scanf() pour gérer de façon plus sûre les entrées.
Je signale au passage, que le livre de Delannoy qu'on critique de façon trop
systématique traite copieusement de cette question.
Avatar
Mickaël Wolff
-ed- a écrit :
Ceci dit, les contraintes de saisies imposées à l'utilisateur sont
telles que ce code est inutilisable dans la vrai vie...



Certainement parce que scanf n'est pas fait pour la saisie manuelle
d'information, mais à été créé pour traiter des flux d'entrée.

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
Avatar
Antoine Leca
Le 04/09/2009 10:08, candide écrivit :
D'une façon générale, je trouve que les sources d'apprentissage (au sens large y
compris les cours dans les facs ou ecoles) du langage C ne font pas un usage
assez limité et contrôlé des entrées.



D'une façon générale, les cours d'apprentissage entrent progressivement
dans un sujet. Par exemple, on n'apprend pas à prendre une épingle à
cheveux au frein à main lorsqu'on apprend à conduire.

Cependant, il est toujours difficile de doser correctement cette
progrssivité, en particulier parce que le professeur ne contrôle pas
exactement l'utilisation qui sera faite de la technique apprise
(et parfois l'élève non plus ne contrôle pas).
Ainsi, toujours pour rester dans le domaine de la conduite, il me semble
que l'on apprend à faire un démarrage en côte et un créneau... ce qui
est inutile pour de nombreuses personnes. Idem pour de nombreux panneaux
du Code de la route.


L'apprentissage des entrées cause un grand
ralentissement dans l'apprentissage et si le but est d'apprendre le langage, on
peut s'en passer 99 cas sur 100.



Euh... il faut quand même des données pour qu'un programme informatique
serve à quoi que ce soit; et elles sont souvent ailleurs que dans les
résultats créés par le programme. Donc il est nécessaire dans plus de
80% des cas de maîtriser les entrées.


En plus on les apprend sur l'entrée standard
("la console") ce qui est plein de pièges et de frustrations alors que tu
sembles nous dire que ce n'est pas le bon usage de scanf() ...



scanf() est plein de pièges. Pour les frustations, je te laisse décider.
scanf() est un bon outil pour apprendre le langage, c'est quand même une
des manière les plus rapides de pouvoir donner des valeurs numériques
différentes à un programme pour voir comment il réagit.
Ce qui se passe, c'est que lorsque on progresse dans l'apprentissage du
langage, il faut probablement apprendre à se passer de scanf(); quite à
y revenir (beaucoup) plus tard, et apprendre alors les subtilités des
spécifications de format (genre %[).

Pour en revenir à la conduite, c'est (c'était?) la même chose avec les
créneaux : lorsque tu apprends, c'est une bonne façon de comprendre (un
peu) comment se comporte un véhicule à roues avant directrices lorsqu'il
est en marche arrière ; plus tard, tu oublies cette technique qui ne
sert à rien... jusqu'au jour où tu es muté à Paris (ou tu t'achètes un
4×4 de 4,80 m, le résultat est le même, tu es obligé de devoir te garer
dans un espace à peine plus grand de 20 cm que ton véhicule) !


En outre, ces
mêmes sources d'apprentissage passent sous silence pour la plupart comment on
peut exploiter le retour de scanf() pour gérer de façon plus sûre les entrées.



Parce qu'_au départ_, c'est un détail superfétatoire. Mais je pensais
que tu en étais à la troisième étape (si l'on suit le développement
ci-dessus), et là cela devient _indispensable_.

Pour ma parabole du créneau, l'équivalent serait de contrôler ce qui se
passe derrière le véhicule. Pour le permis, lorsque tu le fais dans un
Z.I. déserte avec 200 m de libre, ce n'est pas un vrai souci. À Paris
avec le véhicule de ton conjoint, c'est un détail qui compte...


Antoine
Avatar
espie
Perso, scanf est tellement capricieux que je ne m'en sers presque jamais.
Ca ne marche que pour des lectures "inflexibles". En cas d'erreur, c'est
dur de revenir en arriere !

La quasi-totalite des programmes que j'ai en production ecrits en C,
utilisent du fgetc ou du fgets pour recuperer les choses caractere par
caractere, plus un parseur fait main, ou genere a coup de lex et yacc pour
recuperer les donnees qui m'interessent. Les fonctions telles que strtol
et assimilees permettent d'eviter la peniblitude de la lecture de nombres
a la main...
Avatar
espie
In article <h7qrf2$7e9$,
Antoine Leca wrote:
scanf() est plein de pièges. Pour les frustations, je te laisse décider.
scanf() est un bon outil pour apprendre le langage, c'est quand même une
des manière les plus rapides de pouvoir donner des valeurs numériques
différentes à un programme pour voir comment il réagit.



Ouais, bof. En general, c'est plus rentable d'apprendre rapidement
main(int arg, char *argv[]) allie a atoi() et assimiles.

Ca evite le syndrome du programme de debutant qui pose des questions sur
son terminal pour des trucs qui devraient etre des parametres en ligne
de commande...
Avatar
candide
Antoine Leca a écrit :
Le 04/09/2009 10:08, candide écrivit :
D'une façon générale, je trouve que les sources d'apprentissage (au sens large y
compris les cours dans les facs ou ecoles) du langage C ne font pas un usage
assez limité et contrôlé des entrées.



D'une façon générale, les cours d'apprentissage entrent progressivement
dans un sujet.



La progressivité est une notion aux contours assez flous en fait et de toutes
façons ce n'est qu'un élément parmi beaucoup d'autres à prendre en considération.


Par exemple, on n'apprend pas à prendre une épingle à
cheveux au frein à main lorsqu'on apprend à conduire.



Je n'ai jamais dit le contraire. J'ai parlé de limiter et contrôler les notions
en rapport avec les E/S.


Euh... il faut quand même des données pour qu'un programme informatique
serve à quoi que ce soit;



Oui mais tu n'as pas compris mon point de vue : je ne cherche pas à améliorer la
conduite des automobilistes, je cherche juste à améliorer l'auto-école et faire
en sorte que l'automobiliste en ait le moins à apprendre lorsqu'il est sur la
route alors qu'il risque sa vie et celle des autres. Bon je cesse l'image de la
conduite car elle a ses limites. Ce que je reproche à la manière traditionnelle
d'apprendre (le C par exemple) c'est qu'on se retranche derrière l'argument
qu'on apprend "le C en programmant" (grosso modo la position de -ed-). Bien sûr
qu'on peut apprendre ainsi (des générations ont fait comme ça) mais à quel prix
!! Ça augmente considérablement le temps d'apprentissage parce que tu découvres
les difficultés au petit bonheur la chance, en fonction de ce que tu codes et
toutes les difficultés se présentent en même temps, ça te conduit à résoudre au
plus pressé parce que sinon tu n'avances pas, ça ne te permet pas de prendre du
recul. L'argument "c'est en forgeant qu'on devient forgeron" dispense juste de
faire une doc pensée, construite, navigable, etc. Moi je me rends compte du
temps énorme que j'ai perdu à apprendre le C parce que simplement les auteurs
font de la surcharge dans leur exposition si bien que le point que l'auteur
voulait expliquer est noyé dans un fatras que le lecteur ne parvient pas à
discerner de l'essentiel. Je n'en finirais pas de décrire toutes les
incongruités des manuels qui obscurcissent à loisir et toutes les incohérences
d'exposition. Et ce temps énorme que j'ai perdu des centaines de gens l'ont
perdu, il suffit de lire un peu les forums et sans compter que la fréquentation
des forums c'est juste la partie visible de l'iceberg. Il n'empêche que je pense
que l'apprentissage d'un langage de programmation doit se faire par la pratique
et en réalité, le bagage théorique nécessaire pour aborder la programmation (en
C en tous cas) est beaucoup plus limité que ce qu'on dit. Le problème de la
pratique est le choix des exemples. Et choisir des exemples efficaces n'est pas
si aisé et ça demande un vrai travail de conception.



et elles sont souvent ailleurs que dans les
résultats créés par le programme. Donc il est nécessaire dans plus de
80% des cas de maîtriser les entrées.





Avant d'apprendre la poésie j'apprends la prose. Je rappelle que le langage
n'est pas sa bibliothèque. Pour apprendre le langage, on n'a pas besoin de
connaitre les E/S (un minimum quand même si on veut afficher). Sinon, les
entrées/sorties sont enseignées dans un contexte d'une complexité (théorique en
particulier) paralysante : combien de tonnes de préliminaires pour lire ou
écrire dans un fichier qui sont des opérations assez simples en fait et très
motivantes quand on apprend (et beacoup plus puissantes que les E/S en console).




scanf() est un bon outil pour apprendre le langage,



Oui, comme la grève de la faim fait maigrir. Bon, dans des cas exceptionnels
peut-être. Pour moi, apprendre le langage via scanf() est un exemple typique de
surcharge d'apprentissage.

c'est quand même une
des manière les plus rapides de pouvoir donner des valeurs numériques
différentes à un programme pour voir comment il réagit.



Inutile, suffit de changer tes valeurs dans le code-source, c'est en fait
beaucoup moins cher payé et ça focalise sur l'apprentissage du langage.


Ce qui se passe, c'est que lorsque on progresse dans l'apprentissage du
langage, il faut probablement apprendre à se passer de scanf();



On peut même quasiment s'en passer

quite à
y revenir (beaucoup) plus tard, et apprendre alors les subtilités des
spécifications de format (genre %[).



Oui, beaucoup plus tard et surtout lorsqu'on a suffisamment d'aisance avec la
doc (le point le plus important en fait).


Pour en revenir à la conduite, c'est (c'était?) la même chose avec les
créneaux : lorsque tu apprends, c'est une bonne façon de comprendre (un
peu) comment se comporte un véhicule à roues avant directrices lorsqu'il
est en marche arrière ;



A-t-on besoin de le comprendre ? La plupart du temps, on ne comprend pas au sens
où tu sembles l'entendre, on se contente de "sentir le créneau". Enseigner c'est
donner les bonnes interfaces et bien sûr masquer l'implémentation.


plus tard, tu oublies cette technique qui ne
sert à rien... jusqu'au jour où tu es muté à Paris (ou tu t'achètes un
4×4 de 4,80 m, le résultat est le même, tu es obligé de devoir te garer
dans un espace à peine plus grand de 20 cm que ton véhicule) !




Et bien je doute que ce tu as appris avant la mutation te soit d'une grande
utilité, faut déjà être capable d'apprécier à l'oeil 20cm sur 4.80m, c'est du 4%.




Parce qu'_au départ_, c'est un détail superfétatoire. Mais je pensais
que tu en étais à la troisième étape (si l'on suit le développement
ci-dessus), et là cela devient _indispensable_.




Pour le superfétatoire, je suis d'accord puisque j'ai parlé de limiter et
controler tout recours à des fonctions d'entrées. Pour le reste, non, je n'en
suis pas à cette étape-là car il me suffit de savoir que je saurais le faire
s'il fallait le faire (et sauf besoin particulier, je n'y serai pas : je ne suis
pas programmeur au long cours). En revanche, je note que la littérature est de
peu d'aide sur le sujet (je suis presque sûr que le K&R est très avare sur la
question).



Pour ma parabole du créneau, l'équivalent serait de contrôler ce qui se
passe derrière le véhicule.



Sauf que tu ne passes pas 80% (ton chiffre de tout à l'heure) de ton temps à
faire des créneaux.

Pour le permis, lorsque tu le fais dans un
Z.I. déserte avec 200 m de libre, ce n'est pas un vrai souci. À Paris
avec le véhicule de ton conjoint, c'est un détail qui compte...




C'est ça le problème des analogies (la cuisine est aussi une métaphore
fréquente) : si tu ne sais pas faire un créneaux avec un 4x4 avec une marge de
manoeuvre de 4% (ou si tu ne veux pas encourir le risque de le faire), dans la
vie réelle, tu vas adapter ton comportement : tu changeras de voiture, tu
prendras le métro, tu utiliseras un parking. Il n'en reste pas vrai qu'on
n'apprend pas tout à l'auto-école.
Avatar
Marc Boyer
Le 04-09-2009, candide a écrit :
Antoine Leca a écrit :

D'une façon générale, je trouve que les sources d'apprentissage
(au sens large y compris les cours dans les facs ou ecoles) du
langage C ne font pas un usage assez limité et contrôlé des entrées.



Le problème, c'est qu'une maîtrise fiable des entrées est un problème
difficile par nature. D'une autre côté, d'un point de vue pédagogique
il est préférable de pouvoir faire quelques entrées/sorties dans les
exos.

Dès lors, à moins d'avoir vraiment pleins d'heures devant soit,
il va falloir faire des compromis.

L'apprentissage des entrées cause un grand
ralentissement dans l'apprentissage et si le but est d'apprendre
le langage, on peut s'en passer 99 cas sur 100.



Ah ? Franchement, nous nous étions posé la question des E/S sur
notre programme de langage C et la question de faire des programmes
sans entrées avait été évoquée, et vite rejettée...
Nous avions aussi pensé à des entrées dédiées enseignement
int NEWBIE_getInt(void);
mais ce n'était pas très satisfaisant.

En plus on les apprend sur l'entrée standard
("la console") ce qui est plein de pièges et de frustrations alors que tu
sembles nous dire que ce n'est pas le bon usage de scanf() ...



Oui, mais quelles autres solutions pour lire des entrées en C avec
des débutants ?

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
1 2 3