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...
"Richard Delorme" wrote in message news:4188b604$0$15755$
Laisse tomber scanf(). Pas une fonction de débutant (ni même d'expérimenté...)
Bah... il suffit de lire la doc...
Il ne suffit pas de la lire pour la comprendre... Il ne suffit pas de la comprendre pour se servir de scanf sans se tromper Il ne suffit pas d'utiliser correctement scanf pour faire des saisies réellement contrôlées
Je suis bien d'accord avec Emmanuel, laisse tomber scanf.
Chqrlie.
"Richard Delorme" <abulmo@nospam.fr> wrote in message
news:4188b604$0$15755$7a628cd7@news.club-internet.fr...
Laisse tomber scanf(). Pas une fonction de débutant (ni même
d'expérimenté...)
Bah... il suffit de lire la doc...
Il ne suffit pas de la lire pour la comprendre...
Il ne suffit pas de la comprendre pour se servir de scanf sans se tromper
Il ne suffit pas d'utiliser correctement scanf pour faire des saisies réellement
contrôlées
Je suis bien d'accord avec Emmanuel, laisse tomber scanf.
"Richard Delorme" wrote in message news:4188b604$0$15755$
Laisse tomber scanf(). Pas une fonction de débutant (ni même d'expérimenté...)
Bah... il suffit de lire la doc...
Il ne suffit pas de la lire pour la comprendre... Il ne suffit pas de la comprendre pour se servir de scanf sans se tromper Il ne suffit pas d'utiliser correctement scanf pour faire des saisies réellement contrôlées
Je suis bien d'accord avec Emmanuel, laisse tomber scanf.
Chqrlie.
Charlie Gordon
"Hamiral" wrote in message news:4187e613$0$15756$
fgets(nom, NOMBRE_DE_CARACTERE_MAX, stdin);
Dans ce cas-là il faudra déclarer nom comme suit : char nom[NOMBRE_DE_CARACTERES_MAX + 1]; ou char* nom = malloc( NOMBRE_DE_CARACTERES_MAX + 1 );
Sinon fgets va faire boum quand elle va ajouter le ' ' en fin de chaîne ...
Faux : le parametre de fgets est la taille du tableau destination. fgets n'y stockera pas plus de taille-1 chars et toujours un NUL final. En revanche, si tu veux que la saisie puisse autoriser des noms de longueur NOMBRE_DE_CARACTERES_MAX, il faut allouer le buffer de saisie avec 2 caractères supplémentaires : 1 pour le 'n' et 1 autre pour le ' ' final.
char buf[NOMBRE_DE_CARACTERES_MAX + 2]; if (fgets (buf, sizeof(buf), fp)) { /* enlever le 'n' final */ char *p; if ((p = strchr(buf, 'n')) != NULL) *p = ' '; /* stocker le nom ... */ }
A noter que l'absence de 'n' dans le buffer après fgets peut avoir 2 causes : - Le fichier n'est pas terminé par un 'n', et nous venons de lire la dernière ligne. - La ligne était top longue pour le buffer, et une partie de la ligne n'a pas été lue. C'est un problème qu'il faut gérer ici parce que sinon la fin de la ligne sera lue dans la lecture suivante causant un décalage regrettable entre les données et l'attente du programme.
Même un problème aussi simple est compliqué à implémenter correctement en C.
Chqrlie.
"Hamiral" <hamiral@hamham.fr> wrote in message
news:4187e613$0$15756$7a628cd7@news.club-internet.fr...
fgets(nom, NOMBRE_DE_CARACTERE_MAX, stdin);
Dans ce cas-là il faudra déclarer nom comme suit :
char nom[NOMBRE_DE_CARACTERES_MAX + 1];
ou
char* nom = malloc( NOMBRE_DE_CARACTERES_MAX + 1 );
Sinon fgets va faire boum quand elle va ajouter le ' ' en fin de chaîne ...
Faux : le parametre de fgets est la taille du tableau destination. fgets n'y
stockera pas plus de taille-1 chars et toujours un NUL final.
En revanche, si tu veux que la saisie puisse autoriser des noms de longueur
NOMBRE_DE_CARACTERES_MAX, il faut allouer le buffer de saisie avec 2 caractères
supplémentaires : 1 pour le 'n' et 1 autre pour le ' ' final.
char buf[NOMBRE_DE_CARACTERES_MAX + 2];
if (fgets (buf, sizeof(buf), fp)) {
/* enlever le 'n' final */
char *p;
if ((p = strchr(buf, 'n')) != NULL)
*p = ' ';
/* stocker le nom ... */
}
A noter que l'absence de 'n' dans le buffer après fgets peut avoir 2 causes :
- Le fichier n'est pas terminé par un 'n', et nous venons de lire la dernière
ligne.
- La ligne était top longue pour le buffer, et une partie de la ligne n'a pas
été lue. C'est un problème qu'il faut gérer ici parce que sinon la fin de la
ligne sera lue dans la lecture suivante causant un décalage regrettable entre
les données et l'attente du programme.
Même un problème aussi simple est compliqué à implémenter correctement en C.
Dans ce cas-là il faudra déclarer nom comme suit : char nom[NOMBRE_DE_CARACTERES_MAX + 1]; ou char* nom = malloc( NOMBRE_DE_CARACTERES_MAX + 1 );
Sinon fgets va faire boum quand elle va ajouter le ' ' en fin de chaîne ...
Faux : le parametre de fgets est la taille du tableau destination. fgets n'y stockera pas plus de taille-1 chars et toujours un NUL final. En revanche, si tu veux que la saisie puisse autoriser des noms de longueur NOMBRE_DE_CARACTERES_MAX, il faut allouer le buffer de saisie avec 2 caractères supplémentaires : 1 pour le 'n' et 1 autre pour le ' ' final.
char buf[NOMBRE_DE_CARACTERES_MAX + 2]; if (fgets (buf, sizeof(buf), fp)) { /* enlever le 'n' final */ char *p; if ((p = strchr(buf, 'n')) != NULL) *p = ' '; /* stocker le nom ... */ }
A noter que l'absence de 'n' dans le buffer après fgets peut avoir 2 causes : - Le fichier n'est pas terminé par un 'n', et nous venons de lire la dernière ligne. - La ligne était top longue pour le buffer, et une partie de la ligne n'a pas été lue. C'est un problème qu'il faut gérer ici parce que sinon la fin de la ligne sera lue dans la lecture suivante causant un décalage regrettable entre les données et l'attente du programme.
Même un problème aussi simple est compliqué à implémenter correctement en C.
Chqrlie.
Charlie Gordon
"Anthony Fleury" wrote in message news:4187e28b$0$30787$
Pourquoi ? et bien parce que scanf a laissé le caractère 'n' qui est tapé derrière le nombre pour valider la première saisie, et quand il regarde l'entrée standard il va retrouver ce caractère et le prendre pour la saisie d'après. Conclusion il va « ignorer » (du point de vue de l'utilisateur) la saisie d'après :-)
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');
Achtung Minen !
Ceci est une boucle infinie dans le cas ou la fin de fichier est rencontrée sans qu'un 'n' soit lu.
Il faut écrire :
while ((c = getc(fp)) != EOF && c!= 'n') continue;
Chqrlie.
PS: le continue redondant est là pour éviter le statement vide, que je préfère ne jamais utiliser, en particulier sur la même ligne que le while ou le for.
"Anthony Fleury" <fleury_anthony@_hotmail.com_> wrote in message
news:4187e28b$0$30787$636a15ce@news.free.fr...
Pourquoi ? et bien parce que scanf a laissé le caractère 'n' qui est tapé
derrière le nombre pour valider la première saisie, et quand il regarde
l'entrée standard il va retrouver ce caractère et le prendre pour la saisie
d'après. Conclusion il va « ignorer » (du point de vue de l'utilisateur) la
saisie d'après :-)
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');
Achtung Minen !
Ceci est une boucle infinie dans le cas ou la fin de fichier est rencontrée sans
qu'un 'n' soit lu.
Il faut écrire :
while ((c = getc(fp)) != EOF && c!= 'n')
continue;
Chqrlie.
PS: le continue redondant est là pour éviter le statement vide, que je préfère
ne jamais utiliser, en particulier sur la même ligne que le while ou le for.
"Anthony Fleury" wrote in message news:4187e28b$0$30787$
Pourquoi ? et bien parce que scanf a laissé le caractère 'n' qui est tapé derrière le nombre pour valider la première saisie, et quand il regarde l'entrée standard il va retrouver ce caractère et le prendre pour la saisie d'après. Conclusion il va « ignorer » (du point de vue de l'utilisateur) la saisie d'après :-)
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');
Achtung Minen !
Ceci est une boucle infinie dans le cas ou la fin de fichier est rencontrée sans qu'un 'n' soit lu.
Il faut écrire :
while ((c = getc(fp)) != EOF && c!= 'n') continue;
Chqrlie.
PS: le continue redondant est là pour éviter le statement vide, que je préfère ne jamais utiliser, en particulier sur la même ligne que le while ou le for.
Charlie Gordon
"Richard Delorme" wrote in message news:4187e3b3$0$15755$
Saisir une ligne avec scanf est toutefois possible. P.ex. :
La signification de tout ceci : 80[^n] lit tous les caractères jusqu'au (et à l'exclusion de) fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale d'une chaine stockable dans adresse, tel qu'il est défini ici. Le second %*[^n] sert à lire le reste ligne (si elle est trop longue), tout en ne stockant pas le résultat. Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas encore lu. Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de saisie si celle-ci n'est pas une constante explicite ? Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le préprocesseur pour cela. Si c'est une expression, ça va pas le faire, et si cette expression n'est pas constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s" de printf qui dans scanf a une toute autre signification (encore une incohérence regrettable de la libc, que la norme n'a pas comblée, préférant sans doute dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Par ailleurs, le texte de la norme contient un exemple que je reproduis ici :
EXAMPLE 2 The call: #include <stdio.h> /* ... */ int i; float x; char name[50]; fscanf(stdin, "%2d%f%*d %[0123456789]", &i, &x, name); with input: 56789 0123 56a72 will assign to i the value 56 and to x the value 789.0, will skip 0123, and will assign to name the sequence 56 . The next character read from the input stream will be a.
C'est quand même incroyable que des saletés de ce genre soient citées en exemple dans la norme : ce code contient une erreur patente : la lecture de 'name' n'est pas contrôlée. Des données suffisamment bien travaillées permettront de faire faire à peu près n'importe quoi au programme qui execute ce code. Le format "%49[0123456789]" aurait été nécessaire ici, ou éventuellement "%49[0-9]". De toute façon le texte de l'explication du 'maximum field width' n'est pas suffisamment clair, et il n'est pas repris pour l'explication des formats 's' et '['.
Conclusion : laisser tomber cette daube de scanf.
Chqrlie.
"Richard Delorme" <abulmo@nospam.fr> wrote in message
news:4187e3b3$0$15755$7a628cd7@news.club-internet.fr...
Saisir une ligne avec scanf est toutefois possible. P.ex. :
La signification de tout ceci :
80[^n] lit tous les caractères jusqu'au (et à l'exclusion de)
fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale
d'une chaine stockable dans adresse, tel qu'il est défini ici.
Le second %*[^n] sert à lire le reste ligne (si elle est trop longue),
tout en ne stockant pas le résultat.
Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas
encore lu.
Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de
saisie si celle-ci n'est pas une constante explicite ?
Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le
préprocesseur pour cela.
Si c'est une expression, ça va pas le faire, et si cette expression n'est pas
constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf
avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s"
de printf qui dans scanf a une toute autre signification (encore une incohérence
regrettable de la libc, que la norme n'a pas comblée, préférant sans doute
dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Par ailleurs, le texte de la norme contient un exemple que je reproduis ici :
EXAMPLE 2 The call:
#include <stdio.h>
/* ... */
int i; float x; char name[50];
fscanf(stdin, "%2d%f%*d %[0123456789]", &i, &x, name);
with input:
56789 0123 56a72
will assign to i the value 56 and to x the value 789.0, will skip 0123, and will
assign to name the
sequence 56 . The next character read from the input stream will be a.
C'est quand même incroyable que des saletés de ce genre soient citées en exemple
dans la norme : ce code contient une erreur patente : la lecture de 'name' n'est
pas contrôlée. Des données suffisamment bien travaillées permettront de faire
faire à peu près n'importe quoi au programme qui execute ce code. Le format
"%49[0123456789]" aurait été nécessaire ici, ou éventuellement "%49[0-9]". De
toute façon le texte de l'explication du 'maximum field width' n'est pas
suffisamment clair, et il n'est pas repris pour l'explication des formats 's' et
'['.
La signification de tout ceci : 80[^n] lit tous les caractères jusqu'au (et à l'exclusion de) fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale d'une chaine stockable dans adresse, tel qu'il est défini ici. Le second %*[^n] sert à lire le reste ligne (si elle est trop longue), tout en ne stockant pas le résultat. Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas encore lu. Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de saisie si celle-ci n'est pas une constante explicite ? Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le préprocesseur pour cela. Si c'est une expression, ça va pas le faire, et si cette expression n'est pas constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s" de printf qui dans scanf a une toute autre signification (encore une incohérence regrettable de la libc, que la norme n'a pas comblée, préférant sans doute dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Par ailleurs, le texte de la norme contient un exemple que je reproduis ici :
EXAMPLE 2 The call: #include <stdio.h> /* ... */ int i; float x; char name[50]; fscanf(stdin, "%2d%f%*d %[0123456789]", &i, &x, name); with input: 56789 0123 56a72 will assign to i the value 56 and to x the value 789.0, will skip 0123, and will assign to name the sequence 56 . The next character read from the input stream will be a.
C'est quand même incroyable que des saletés de ce genre soient citées en exemple dans la norme : ce code contient une erreur patente : la lecture de 'name' n'est pas contrôlée. Des données suffisamment bien travaillées permettront de faire faire à peu près n'importe quoi au programme qui execute ce code. Le format "%49[0123456789]" aurait été nécessaire ici, ou éventuellement "%49[0-9]". De toute façon le texte de l'explication du 'maximum field width' n'est pas suffisamment clair, et il n'est pas repris pour l'explication des formats 's' et '['.
Conclusion : laisser tomber cette daube de scanf.
Chqrlie.
Charlie Gordon
"Pascal" wrote in message news:4187f796$0$6275$
Si je tape 3, j'ai ça sur mon écran : ...
0 - Quitter le programme
Rep : 3 Entrer votre nom : Entrer votre prenom :
En gros, la première réponse, "nom" a été sauté, et il est directement passé au prenom. Ensuite (adresse,tel, mail) ça se passe normalement. Où est l'erreur??
A mon avis, tu ne "tapes" pas 3, mais 3 <entree> Je ne sais pas comment tu lis le nombre dans ton programme, mais tu laisses vraisemblablement le 'n' dans le buffer d'entrée et la saisie suivante (lecture du nom) lit directement ce 'n' et passe à la suite.
Chqrlie.
"Pascal" <pascal@spam.org> wrote in message
news:4187f796$0$6275$626a14ce@news.free.fr...
Si je tape 3, j'ai ça sur mon écran :
...
0 - Quitter le programme
Rep : 3
Entrer votre nom : Entrer votre prenom :
En gros, la première réponse, "nom" a été sauté, et il est directement
passé au prenom. Ensuite (adresse,tel, mail) ça se passe normalement. Où
est l'erreur??
A mon avis, tu ne "tapes" pas 3, mais 3 <entree>
Je ne sais pas comment tu lis le nombre dans ton programme, mais tu laisses
vraisemblablement le 'n' dans le buffer d'entrée et la saisie suivante (lecture
du nom) lit directement ce 'n' et passe à la suite.
En gros, la première réponse, "nom" a été sauté, et il est directement passé au prenom. Ensuite (adresse,tel, mail) ça se passe normalement. Où est l'erreur??
A mon avis, tu ne "tapes" pas 3, mais 3 <entree> Je ne sais pas comment tu lis le nombre dans ton programme, mais tu laisses vraisemblablement le 'n' dans le buffer d'entrée et la saisie suivante (lecture du nom) lit directement ce 'n' et passe à la suite.
Chqrlie.
Laurent Deniau
Charlie Gordon wrote:
"Richard Delorme" wrote in message news:4187e3b3$0$15755$
Saisir une ligne avec scanf est toutefois possible. P.ex. :
La signification de tout ceci : 80[^n] lit tous les caractères jusqu'au (et à l'exclusion de) fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale d'une chaine stockable dans adresse, tel qu'il est défini ici. Le second %*[^n] sert à lire le reste ligne (si elle est trop longue), tout en ne stockant pas le résultat. Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas encore lu. Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de saisie si celle-ci n'est pas une constante explicite ? Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le préprocesseur pour cela. Si c'est une expression, ça va pas le faire, et si cette expression n'est pas constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s" de printf qui dans scanf a une toute autre signification (encore une incohérence regrettable de la libc, que la norme n'a pas comblée, préférant sans doute dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Par ailleurs, le texte de la norme contient un exemple que je reproduis ici :
EXAMPLE 2 The call: #include <stdio.h> /* ... */ int i; float x; char name[50]; fscanf(stdin, "%2d%f%*d %[0123456789]", &i, &x, name); with input: 56789 0123 56a72 will assign to i the value 56 and to x the value 789.0, will skip 0123, and will assign to name the sequence 56 . The next character read from the input stream will be a.
C'est quand même incroyable que des saletés de ce genre soient citées en exemple dans la norme : ce code contient une erreur patente : la lecture de 'name' n'est pas contrôlée. Des données suffisamment bien travaillées permettront de faire faire à peu près n'importe quoi au programme qui execute ce code. Le format "%49[0123456789]" aurait été nécessaire ici, ou éventuellement "%49[0-9]". De toute façon le texte de l'explication du 'maximum field width' n'est pas suffisamment clair, et il n'est pas repris pour l'explication des formats 's' et '['.
Conclusion : laisser tomber cette daube de scanf.
Je suis d'accord que ca aurait put etre mieux pense. Mais cela doit tout de meme etre pratique pour que C++ (Boost) et Java (PrintStream) cherchent a refaire la meme chose (en plus securise certes).
J'ai toujours ete tres etonne de voir le manque de sysmetrie dans les I/O du C, tant sur les familles de fonctions que sur les formats utilises. En particulier ca n'aurait pas ete tres difficile de faire en sorte que l'ensemble des fonctions soit sysmetrique et complet. C99 a travaille dans ce sens, mais c'est pas suffisant...
a+, ld.
Charlie Gordon wrote:
"Richard Delorme" <abulmo@nospam.fr> wrote in message
news:4187e3b3$0$15755$7a628cd7@news.club-internet.fr...
Saisir une ligne avec scanf est toutefois possible. P.ex. :
La signification de tout ceci :
80[^n] lit tous les caractères jusqu'au (et à l'exclusion de)
fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale
d'une chaine stockable dans adresse, tel qu'il est défini ici.
Le second %*[^n] sert à lire le reste ligne (si elle est trop longue),
tout en ne stockant pas le résultat.
Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas
encore lu.
Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de
saisie si celle-ci n'est pas une constante explicite ?
Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le
préprocesseur pour cela.
Si c'est une expression, ça va pas le faire, et si cette expression n'est pas
constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf
avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s"
de printf qui dans scanf a une toute autre signification (encore une incohérence
regrettable de la libc, que la norme n'a pas comblée, préférant sans doute
dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Par ailleurs, le texte de la norme contient un exemple que je reproduis ici :
EXAMPLE 2 The call:
#include <stdio.h>
/* ... */
int i; float x; char name[50];
fscanf(stdin, "%2d%f%*d %[0123456789]", &i, &x, name);
with input:
56789 0123 56a72
will assign to i the value 56 and to x the value 789.0, will skip 0123, and will
assign to name the
sequence 56 . The next character read from the input stream will be a.
C'est quand même incroyable que des saletés de ce genre soient citées en exemple
dans la norme : ce code contient une erreur patente : la lecture de 'name' n'est
pas contrôlée. Des données suffisamment bien travaillées permettront de faire
faire à peu près n'importe quoi au programme qui execute ce code. Le format
"%49[0123456789]" aurait été nécessaire ici, ou éventuellement "%49[0-9]". De
toute façon le texte de l'explication du 'maximum field width' n'est pas
suffisamment clair, et il n'est pas repris pour l'explication des formats 's' et
'['.
Conclusion : laisser tomber cette daube de scanf.
Je suis d'accord que ca aurait put etre mieux pense. Mais cela doit tout
de meme etre pratique pour que C++ (Boost) et Java (PrintStream)
cherchent a refaire la meme chose (en plus securise certes).
J'ai toujours ete tres etonne de voir le manque de sysmetrie dans les
I/O du C, tant sur les familles de fonctions que sur les formats
utilises. En particulier ca n'aurait pas ete tres difficile de faire en
sorte que l'ensemble des fonctions soit sysmetrique et complet. C99 a
travaille dans ce sens, mais c'est pas suffisant...
La signification de tout ceci : 80[^n] lit tous les caractères jusqu'au (et à l'exclusion de) fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale d'une chaine stockable dans adresse, tel qu'il est défini ici. Le second %*[^n] sert à lire le reste ligne (si elle est trop longue), tout en ne stockant pas le résultat. Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas encore lu. Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de saisie si celle-ci n'est pas une constante explicite ? Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le préprocesseur pour cela. Si c'est une expression, ça va pas le faire, et si cette expression n'est pas constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s" de printf qui dans scanf a une toute autre signification (encore une incohérence regrettable de la libc, que la norme n'a pas comblée, préférant sans doute dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Par ailleurs, le texte de la norme contient un exemple que je reproduis ici :
EXAMPLE 2 The call: #include <stdio.h> /* ... */ int i; float x; char name[50]; fscanf(stdin, "%2d%f%*d %[0123456789]", &i, &x, name); with input: 56789 0123 56a72 will assign to i the value 56 and to x the value 789.0, will skip 0123, and will assign to name the sequence 56 . The next character read from the input stream will be a.
C'est quand même incroyable que des saletés de ce genre soient citées en exemple dans la norme : ce code contient une erreur patente : la lecture de 'name' n'est pas contrôlée. Des données suffisamment bien travaillées permettront de faire faire à peu près n'importe quoi au programme qui execute ce code. Le format "%49[0123456789]" aurait été nécessaire ici, ou éventuellement "%49[0-9]". De toute façon le texte de l'explication du 'maximum field width' n'est pas suffisamment clair, et il n'est pas repris pour l'explication des formats 's' et '['.
Conclusion : laisser tomber cette daube de scanf.
Je suis d'accord que ca aurait put etre mieux pense. Mais cela doit tout de meme etre pratique pour que C++ (Boost) et Java (PrintStream) cherchent a refaire la meme chose (en plus securise certes).
J'ai toujours ete tres etonne de voir le manque de sysmetrie dans les I/O du C, tant sur les familles de fonctions que sur les formats utilises. En particulier ca n'aurait pas ete tres difficile de faire en sorte que l'ensemble des fonctions soit sysmetrique et complet. C99 a travaille dans ce sens, mais c'est pas suffisant...
a+, ld.
Antoine Leca
En cmfv8i$pqd$, Charlie Gordon va escriure:
Par ailleurs, le texte de la norme contient un exemple que je ...
C'est quand même incroyable que des saletés de ce genre soient citées en exemple dans la norme : ce code contient une erreur patente :
Laquelle ?
la lecture de 'name' n'est pas contrôlée.
Ce n'est pas une erreur (à ma connaissance). Les exemples de la norme ne sont pas des exemples de bon usage du langage ou de bon goût: ce sont des exemples de comportement attendu ou pas; de ce fait certains sont tordus et d'autres carrément incompréhensibles.
Des données suffisamment bien travaillées permettront de faire faire à peu près n'importe quoi au programme qui execute ce code.
On s'en moque. En fait, au vu de cet exemple, le programmeur normal devrait être effrayé par la complexité de scanf et donc fuir, ce qui est plutôt sain, non ?
éventuellement "%49[0-9]".
Non légal.
Conclusion : laisser tomber cette daube de scanf.
La daube, c'est bon. Et plus elle est élaborée, meilleur c'est. ;-)
Antoine
En cmfv8i$pqd$1@reader1.imaginet.fr, Charlie Gordon va escriure:
Par ailleurs, le texte de la norme contient un exemple que je
...
C'est quand même incroyable que des saletés de ce genre soient citées
en exemple dans la norme : ce code contient une erreur patente :
Laquelle ?
la lecture de 'name' n'est pas contrôlée.
Ce n'est pas une erreur (à ma connaissance).
Les exemples de la norme ne sont pas des exemples de bon usage du langage ou
de bon goût: ce sont des exemples de comportement attendu ou pas; de ce fait
certains sont tordus et d'autres carrément incompréhensibles.
Des données suffisamment bien travaillées permettront de faire
faire à peu près n'importe quoi au programme qui execute ce code.
On s'en moque. En fait, au vu de cet exemple, le programmeur normal devrait
être effrayé par la complexité de scanf et donc fuir, ce qui est plutôt
sain, non ?
éventuellement "%49[0-9]".
Non légal.
Conclusion : laisser tomber cette daube de scanf.
La daube, c'est bon. Et plus elle est élaborée, meilleur c'est. ;-)
C'est quand même incroyable que des saletés de ce genre soient citées en exemple dans la norme : ce code contient une erreur patente :
Laquelle ?
la lecture de 'name' n'est pas contrôlée.
Ce n'est pas une erreur (à ma connaissance). Les exemples de la norme ne sont pas des exemples de bon usage du langage ou de bon goût: ce sont des exemples de comportement attendu ou pas; de ce fait certains sont tordus et d'autres carrément incompréhensibles.
Des données suffisamment bien travaillées permettront de faire faire à peu près n'importe quoi au programme qui execute ce code.
On s'en moque. En fait, au vu de cet exemple, le programmeur normal devrait être effrayé par la complexité de scanf et donc fuir, ce qui est plutôt sain, non ?
éventuellement "%49[0-9]".
Non légal.
Conclusion : laisser tomber cette daube de scanf.
La daube, c'est bon. Et plus elle est élaborée, meilleur c'est. ;-)
Antoine
Jean-Marc Bourguet
Laurent Deniau writes:
Je suis d'accord que ca aurait put etre mieux pense. Mais cela doit tout de meme etre pratique pour que C++ (Boost) et Java (PrintStream) cherchent a refaire la meme chose (en plus securise certes).
Pour les sorties, l'interet principal de l'utilisation des formats est l'internationalisation et la possibilite de mettre les parametres dans des ordres differents suivant les langages.
-- Jean-Marc FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc Site de usenet-fr: http://www.usenet-fr.news.eu.org
Laurent Deniau <Laurent.Deniau@cern.ch> writes:
Je suis d'accord que ca aurait put etre mieux pense. Mais cela doit tout de
meme etre pratique pour que C++ (Boost) et Java (PrintStream) cherchent a
refaire la meme chose (en plus securise certes).
Pour les sorties, l'interet principal de l'utilisation des formats est
l'internationalisation et la possibilite de mettre les parametres dans
des ordres differents suivant les langages.
--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Je suis d'accord que ca aurait put etre mieux pense. Mais cela doit tout de meme etre pratique pour que C++ (Boost) et Java (PrintStream) cherchent a refaire la meme chose (en plus securise certes).
Pour les sorties, l'interet principal de l'utilisation des formats est l'internationalisation et la possibilite de mettre les parametres dans des ordres differents suivant les langages.
-- Jean-Marc FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc Site de usenet-fr: http://www.usenet-fr.news.eu.org
Emmanuel Delahaye
Charlie Gordon wrote on 05/11/04 :
Il faut écrire :
while ((c = getc(fp)) != EOF && c!= 'n') continue;
le continue redondant est là pour éviter le statement vide, que je préfère ne jamais utiliser, en particulier sur la même ligne que le while ou le for.
Je mets
while ((c = getc(fp)) != EOF && c!= 'n') { }
En fait, je mets toujours les {}
-- 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"
Charlie Gordon wrote on 05/11/04 :
Il faut écrire :
while ((c = getc(fp)) != EOF && c!= 'n')
continue;
le continue redondant est là pour éviter le statement vide, que je préfère
ne jamais utiliser, en particulier sur la même ligne que le while ou le for.
Je mets
while ((c = getc(fp)) != EOF && c!= 'n')
{
}
En fait, je mets toujours les {}
--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html
while ((c = getc(fp)) != EOF && c!= 'n') continue;
le continue redondant est là pour éviter le statement vide, que je préfère ne jamais utiliser, en particulier sur la même ligne que le while ou le for.
Je mets
while ((c = getc(fp)) != EOF && c!= 'n') { }
En fait, je mets toujours les {}
-- 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"
Richard Delorme
"Richard Delorme" wrote in message news:4187e3b3$0$15755$
Saisir une ligne avec scanf est toutefois possible. P.ex. :
La signification de tout ceci : 80[^n] lit tous les caractères jusqu'au (et à l'exclusion de) fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale d'une chaine stockable dans adresse, tel qu'il est défini ici. Le second %*[^n] sert à lire le reste ligne (si elle est trop longue), tout en ne stockant pas le résultat. Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas encore lu. Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de saisie si celle-ci n'est pas une constante explicite ? Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le préprocesseur pour cela. Si c'est une expression, ça va pas le faire, et si cette expression n'est pas constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s" de printf qui dans scanf a une toute autre signification (encore une incohérence regrettable de la libc, que la norme n'a pas comblée, préférant sans doute dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Il me semble qu'il y a des discussions pour utiliser %.*s, voire un autre opérateur symétrique avec printf.
[...]
Conclusion : laisser tomber cette daube de scanf.
Des gens pensent le contraire, et qu'il faut laisser tomber fgets() en faveur de scanf :
La signification de tout ceci :
80[^n] lit tous les caractères jusqu'au (et à l'exclusion de)
fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale
d'une chaine stockable dans adresse, tel qu'il est défini ici.
Le second %*[^n] sert à lire le reste ligne (si elle est trop longue),
tout en ne stockant pas le résultat.
Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas
encore lu.
Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de
saisie si celle-ci n'est pas une constante explicite ?
Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le
préprocesseur pour cela.
Si c'est une expression, ça va pas le faire, et si cette expression n'est pas
constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf
avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s"
de printf qui dans scanf a une toute autre signification (encore une incohérence
regrettable de la libc, que la norme n'a pas comblée, préférant sans doute
dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Il me semble qu'il y a des discussions pour utiliser %.*s, voire un
autre opérateur symétrique avec printf.
[...]
Conclusion : laisser tomber cette daube de scanf.
Des gens pensent le contraire, et qu'il faut laisser tomber fgets() en
faveur de scanf :
La signification de tout ceci : 80[^n] lit tous les caractères jusqu'au (et à l'exclusion de) fin-de-ligne ('n'), et à concurrence de 80 caractères, taille maximale d'une chaine stockable dans adresse, tel qu'il est défini ici. Le second %*[^n] sert à lire le reste ligne (si elle est trop longue), tout en ne stockant pas le résultat. Enfin, le getchar() qui suit lit le caractère 'n' qu'on avait pas encore lu. Enfin, on vérifie avec n_lu qu'une adresse a bien été entrée.
C'est bien gentil, mais comment fait-on pour spécifier la taille du buffer de saisie si celle-ci n'est pas une constante explicite ? Si c'est une macro, c'est déjà acrobatique et illisible d'utiliser le préprocesseur pour cela. Si c'est une expression, ça va pas le faire, et si cette expression n'est pas constante...
Il y a bien une solution qui consiste à construire la chaine de format de scanf avec un snprintf, mais j'aurais préféré une syntaxe plus directe du genre "%*s" de printf qui dans scanf a une toute autre signification (encore une incohérence regrettable de la libc, que la norme n'a pas comblée, préférant sans doute dégoiser sans fin sur les conversions multibyte wchar_t avec le prefixe l ;-)
Il me semble qu'il y a des discussions pour utiliser %.*s, voire un autre opérateur symétrique avec printf.
[...]
Conclusion : laisser tomber cette daube de scanf.
Des gens pensent le contraire, et qu'il faut laisser tomber fgets() en faveur de scanf :