Buffer scanf

Fermé
Ed Edson - 8 oct. 2013 à 11:03
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 - 8 oct. 2013 à 15:00
Bonjour à vous, amis programmeurs,

J'ai fait du C il y a longtemps maintenant. Je m'y remets mais ce scanf me perturbe.

Par exemple :
...
printf("Entrez un char: ");
scanf("%c", &monChar1);
printf("\n Vous avez entre: %c", monChar1);
printf("\n Entrez encore un char:");
scanf("%d", &monChar2);
printf("\n Vous avez entre: %c", monChar2);
...

ça donne ça quand on lance le programme
# Entrez un char: tralala
#Vous avez entre: t
#Entrez un un char:
#Vous avez entre: r


Je ne me souviens pourtant pas avoir du rajouter des flush de buffer ou des getch lors de la saisie de char, "dans le temps"

Comment est-ce que vous faites, vous ?

Salutations,

Ed

A voir également:

3 réponses

Bonjour, as-tu essayé avec %s à a place de %c?

Le scanf attend un caractère avec %c et non pas une chaine de caractère.
C'est pour cela qu'il lit le premier caractère (t) puis passe au scanf suivant qui lit le deuxième caractère (r).
Si tu mets d'autres scanf, tu devrais lire caractère par caractère le reste de ton entrée standard.
Si tu remplaces le %c par un %s, si je me souviens bien, le scanf attend non pas un caractère mais une chaine de caractère, il lira donc l'entrée standard jusqu'à la fin de la chaine.

Cordialement.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
8 oct. 2013 à 14:56
Sauf que %s ne stockera pas le \n, donc il y aura le même problème.
Dans ce cas plutôt utiliser fgets et prévoir nu buffer assez grand.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
8 oct. 2013 à 14:57
La solution est de vider le buffer clavier :


int c;
while ( (c=getchar()) != '\n') && c != EOF );

Cdlt,
0
[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 1 096
Modifié par [Dal] le 8/10/2013 à 15:04
Salut Ed Edson,

Ce n'est pas trivial de saisir une chaine en C.

1.

Je complète la réponse de orinym, qui dit très exactement qu'il conviendrait d'utiliser %s au lieu de %c si tu veux récupérer plus qu'un caractère.

Cependant, il faut savoir qu'avec simplement "%s", scanf s'arrêtera en fin de ligne, mais aussi au premier "blanc" trouvé (espace ou tabulation), en laissant le reste dans le flux.

Vois la documentation de scanf.

Donc, si la chaîne que tu veux récupérer comporte des espaces, par exemple "Bonjour toi", tu ne récupères que "Bonjour\0" et " toi\n" restent dans le flux.

2.

De plus, comme tu n'as pas montré le type de tes variables "monChar1" et "monChar2" (et que, si on se fie au nom, il y a des chances que tu aies affecté un type "char"), il faudra aussi que la variable soit, non pas un "char", mais un pointeur sur char pointant sur une zone mémoire allouée disposant de suffisamment d'espace pour accueillir l'entrée.

Tu peux faire cela comme cela pour disposer d'un espace te permettant de stocker 255 caractères plus le caractère terminal \0 (cf. https://www.commentcamarche.net/contents/118-langage-c-les-chaines-de-caracteres) :

char st[256];
ou

char * st;
st = malloc(256);
/* faire qq chose avec st */
free(st);

que tu utilises l'une ou l'autre méthode, "st" sera déjà un pointeur (sur char), et tu n'auras donc pas à préfixer la variable "st" de & dans ton scanf.

3.

Cependant scanf est complexe à utiliser, et délicate à utiliser de manière sûre afin d'obtenir une saisie de texte au clavier en C (même si paradoxalement, c'est une des fonction qu'on enseigne en premier aux personnes qui apprennent le C pour effectuer une saisie intéractive sur le terminal...). Si tu ne fais pas ce qu'il faut :

- tu ne contrôles pas le nombre de caractères pris en compte par scanf (qui ne va pas vérifier toute seule si la capacité du tampon n'est pas dépassée), ce qui peut conduire à un débordement de mémoire, donc un plantage, corruption de données, voire un problème de sécurité
- tu te retrouves avec des caractères qui trainent dans le flux stdin ('\n' n'est pas capturée) et qu'il faut purger

fgets est plus facile à utiliser pour opérer ce contrôle (il faudra retirer le '\n', en revanche, qui est capturé par fgets).

Autrement, on peut faire avec scanf comme cela, avec un spécificateur de taille et un spécificateur de classe excluant '\n' :

char st[256]={0};
char c;

if (scanf("%255[^\n]",st) == 1) {
while ((c = getchar()) != '\n' && c != EOF)
/* purge de stdin */ ;
}

De cette façon, tu n'utilises pas %s qui s'arrête aux blancs, tu limites la taille de la saisie prise en compte à une taille maximale ou au premier '\n' rencontré (exclu). La boucle while qui suit est la façon classique de purger le flux stdin, pour que le '\n' qui reste dans le flux (et/ou les caractères excédant éventuellement la taille spécifiée), soient purgés et ne se retrouvent pas capturés au prochain scanf.

ouf !


Dal
0