scanf & puts

Le
Aziz
Bonjour,

Avec gcc sous linux, ce petit code me donne un resultat que je ne comprends
pas du tout. Je serais content si vous m'expliquez la raison.

#include <stdio.h>

int main(void)
{
char c1, c2;
int i;

puts("Entrez i:");
scanf("%d", &i);

scanf("%c %c", &c1, &c2);
printf("%c %c", c1, c2);

return 0;
}

Execution:
<debut>
Entrez i1:
3
A B

A
<fin>
Vos réponses
Trier par : date / pertinence
jz
Le #551762
Aziz wrote:
Bonjour,

Avec gcc sous linux, ce petit code me donne un resultat que je ne comprends
pas du tout. Je serais content si vous m'expliquez la raison.

#include
int main(void)
{
char c1, c2;
int i;

puts("Entrez i:");
scanf("%d", &i);

scanf("%c %c", &c1, &c2);
printf("%c %cn", c1, c2);

return 0;
}

Execution:
<debut>
Entrez i1:
3
A B

A
<fin>



scanf laisse 'n' dans le buffer du clavier après la lecture de i. Donc
il reste à lire "nA C". Tu retrouves donc 'n' dans c1 et 'A' dans c2,
alors que 'B' est oublié. Le résultat de printf en découle.

Il faut lire attentivement la doc de scanf dont les comportements ne
sont pas toujours intuitifs (mais parfaitement documentés).

Il faudrait écrire scanf(" %c %c", &c1, &c2); pour que le résultat soit
correct. L'espace en plus vire *les* blancs (n, esp et tab) avant de
lire. Par contre tu ne peux plus lire le caractère 'espace'. Si tu en as
besoin il faut lire les caractères un par un et les analyser toi même.

A+
Jacques

Emmanuel Delahaye
Le #551761
In 'fr.comp.lang.c', Aziz
Bonjour,

Avec gcc sous linux, ce petit code me donne un resultat que je ne comprends
pas du tout. Je serais content si vous m'expliquez la raison.

#include
int main(void)
{
char c1, c2;
int i;

puts("Entrez i:");
scanf("%d", &i);

scanf("%c %c", &c1, &c2);
printf("%c %cn", c1, c2);

return 0;
}

Execution:
<debut>
Entrez i1:


Je mets ce '1' sur le compte des fautes de frappes... (préférer le copier
collé...)

3
A B

A
<fin>


Ce comportement est parfaitement normal. Pour y voir plus clair, je te
conseille d'écrire plutôt:

printf("'%c' '%c'n", c1, c2);

Tu obtiendras alors:
Entrez i:
3
A B
'
' 'A'

On voit donc parfaitement que le caractère lu par le premier "%c" est un
'n'. C'est normal. Le premier scanf() a laissé trainer le 'n' dans stdin.
L'utilisation maîtrisée et sûre des fontions scanf() est plutôt complexe et
déconseillée aux débutants. Pour saisir un entier, j'utilise 2 fonctions
basées sur fgets() et strtol():

#include #include #include
static int get_str (char *s, size_t size)
{
int err = fgets (s, size, stdin) == NULL;

if (!err)
{
char *p = strchr (s, 'n');
if (p)
{
*p = 0;
}
else
{
int c;
while ((c = getchar ()) != 'n' && c != EOF)
{
}
err = 1;
}
}
return err;
}

static int get_int (int *pi)
{
char s[32];
int err = get_str (s, sizeof s);

if (!err && pi)
{
err = strlen (s) == 0;

if (!err)
{
*pi = (int) strtol (s, NULL, 10);
}
}
return err;
}

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Emmanuel Delahaye
Le #551760
In 'fr.comp.lang.c', jz
scanf laisse 'n' dans le buffer du clavier après la lecture de i. Donc


Hum... Parlons plutôt de stdin. Sur le carte électronique pour laquelle je
travaille actuellement, stdin est un port série...

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

jz
Le #551759
Emmanuel Delahaye wrote:
In 'fr.comp.lang.c', jz

scanf laisse 'n' dans le buffer du clavier après la lecture de i. Donc



Hum... Parlons plutôt de stdin. Sur le carte électronique pour laquelle je
travaille actuellement, stdin est un port série...



Je te l'accorde avec plaisir :)

... mais dans le cas présent je répondais à Aziz, et vu sa question je
doute très fortement qu'il soit en train d'écrire un pilote de carte
quelconque.

Quant à toi je pense je pense que tu as assez de recul pour savoir que
stdin est un flux comme tant d'autres et ne pas te lancer des débats
sémantiques ridicules qui ne feraient qu'embrouiller un peu plus des
programmeurs moins aguerris.

Au fait, est-ce que tu interroges ta carte avec "puts("Entrez i:");" ?

A+


Aziz
Le #551758
Aziz wrote:

Bonjour,

Avec gcc sous linux, ce petit code me donne un resultat que je ne
comprends pas du tout. Je serais content si vous m'expliquez la raison.



Merci beaucoup pour les reponses...

Horst Kraemer
Le #551521
On Sat, 17 Jan 2004 19:08:17 +0200, Aziz

scanf("%c %c", &c1, &c2);


Un remarque à part. Ne mets *jamais* des espaces autour d'une
spécification de lecture (%c ou %d etc.) si tu ne sais pas pourqoi tu
le fais. Tout caractère dans la chaine de formattage a une
signification, y inclus les espaces.

scanf("%c%c", &c1, &c2);

n'est pas la même chose que

scanf("%c %c", &c1, &c2);

"%c%c" lit les prochains deux caractères consécutifs tandis que
"%c %c" lit et convertit le prochain caractère, lit et ignore tous les
caractères "blancs" qui suivent (espace,TAB,ENTREE) et lit et
convertit le deuxième caractère non blanc. c.a.d. si tu entres

A B<ENTREE>

scanf("%c%c", &c1, &c2) lira A et ' ' tandis que
scanf("%c %c", &c1, &c2) lira A et B.

--
Horst

Aziz
Le #551518

... mais dans le cas présent je répondais à Aziz, et vu sa question je
doute très fortement qu'il soit en train d'écrire un pilote de carte
quelconque.



Je te remercie encore une fois pour ta reponse, oui je suis pas en train
d'ecrire un pilote de carte, mais je suis pas de meme a mes premiers essais
de programmation. En fait j'etais en train de faire mon devoir des graphes
et pour cela l'utilisateur entre les vertices, i, c'etait le nombre de
vertice, et ce comportement dont j'ignorais de scanf a boulverse tout le
code avec de fautes de segmentations, j'ai essaye a isoler le propleme et
appercu qu'il s'agissait de deux scanf consecutif, et j'ai poste une
version simplifie ici.

J'explique tout cela pour dire que (a mon avis) M. Delahaye a raison
d'indiquer ces nuances. Et meme ci c'est un vrai debutant qui pose la
question, il peut s'en servir...

Comme vous pouvez la remarquer, francais n'est pas ma langage maternelle, si
vous ne comprenez pas du tout de quoi je parle, laissez tomber :)


Quant à toi je pense je pense que tu as assez de recul pour savoir que
stdin est un flux comme tant d'autres et ne pas te lancer des débats
sémantiques ridicules qui ne feraient qu'embrouiller un peu plus des
programmeurs moins aguerris.

Au fait, est-ce que tu interroges ta carte avec "puts("Entrez i:");" ?

A+


jz
Le #551517
Aziz wrote:
... mais dans le cas présent je répondais à Aziz, et vu sa question je
doute très fortement qu'il soit en train d'écrire un pilote de carte
quelconque.




Je te remercie encore une fois pour ta reponse, oui je suis pas en train
Il n'y a pas de quoi.


d'ecrire un pilote de carte, mais je suis pas de meme a mes premiers essais
de programmation. En fait j'etais en train de faire mon devoir des graphes
et pour cela l'utilisateur entre les vertices, i, c'etait le nombre de
vertice, et ce comportement dont j'ignorais de scanf a boulverse tout le
code avec de fautes de segmentations, j'ai essaye a isoler le propleme et
appercu qu'il s'agissait de deux scanf consecutif, et j'ai poste une
version simplifie ici.


C'est vraiment une excellente démarche.


J'explique tout cela pour dire que (a mon avis) M. Delahaye a raison
d'indiquer ces nuances. Et meme ci c'est un vrai debutant qui pose la
question, il peut s'en servir...


Je n'ai absolument pas dit qu'il avait tort.

Je sais bien que j'ai utilisé trop hativement le mot clavier à la place
de stdin, tout simplement parce que le problème concernait manifestement
l'utilisation de scanf pour une saisie au clavier, et que je n'ai pas
cherché à extrapoler.

J'ai pour habitude d'essayer de ne pas mélanger les problèmes, au risque
de faire quelques entorses à la rigueur. J'ai donc considéré uniquement
cette fichue syntaxe de scanf qui a piégé et piégera encore des
générations de programmeurs, débutants ou non (sans que cela soit le
moins du monde péjoratif).

Bien sûr que la question des flots de données est primordiale en C, mais
elle me semble assez secondaire pour ce problème particulier.

Comme vous pouvez la remarquer, francais n'est pas ma langage maternelle, si
vous ne comprenez pas du tout de quoi je parle, laissez tomber :)



Si si, tu es tout à fait compréhensible et j'aimerais savoir être aussi
clair dans une autre langue que la mienne :)

A+
Jacques


Emmanuel Delahaye
Le #551516
In 'fr.comp.lang.c', jz
scanf laisse 'n' dans le buffer du clavier après la lecture de i. Donc


Hum... Parlons plutôt de stdin. Sur le carte électronique pour laquelle
je travaille actuellement, stdin est un port série...


Je te l'accorde avec plaisir :)

... mais dans le cas présent je répondais à Aziz, et vu sa question je
doute très fortement qu'il soit en train d'écrire un pilote de carte
quelconque.


Ai-je parlé de pilote de carte? Je rappelle simplement que stdin n'est
forcément connecté à un clavier, et que dans ce contexte, la notion de
'buffer clavier' est erronée.

Quant à toi je pense que tu as assez de recul pour savoir que
stdin est un flux comme tant d'autres et ne pas te lancer des débats
sémantiques ridicules qui ne feraient qu'embrouiller un peu plus des
programmeurs moins aguerris.


Utiliser le mot juste est le contraire de l'embrouille...

Au fait, est-ce que tu interroges ta carte avec "puts("Entrez i:");" ?


What? C'est plutôt ma carte qui envoie des chaines au terminal en appelant
puts()...

Pour interroger ma carte, je tape des commandes sur le terminal, et la carte
les récupère avec fgets()...

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/



Randolf Carter
Le #551514
Il faudrait écrire scanf(" %c %c", &c1, &c2); pour que le résultat
soit

correct. L'espace en plus vire *les* blancs (n, esp et tab) avant de
lire.


Une autre solution du même genre mais peut être moins propre :
rajouter l'espace dans le scanf précédant...

scanf("%d ", &i);

--
- Randolf

Publicité
Poster une réponse
Anonyme