Dans la plupart des cours de C, scanf() est une des premières fonctions présentée aux débutants. Malgré son apparence d'utilisation "facile", elle est dur à maîtriser et demande une surcharge de code (pour résoudre tous les problèmes qu'elle cause par son utilisation).
Nous allons donc, étudier cette fonction, et voir quels problèmes se posent lors de son utilisation.
Les attributs de conversion
scanf() demande une chaîne à un utilisateur et s'occupe de le convertir grâce aux
attributs de conversion qui sont spécifiés par le programmeur.
Généralement, on utilise ces différents attributs :
- %ld pour une conversion vers une variable de type long.
- %lf pour un type double.
- %s pour saisir une chaîne.
Il existe beaucoup de ces attributs, je fournis ceux qui sont le plus utilisés, vous pouvez trouver une liste plus complète en tapant
man scanf dans votre moteur de recherche.
Les problèmes
Oui, il existe des problèmes en relation avec une mauvaise utilisation de scanf(), nous allons traiter des deux problèmes les plus courants dans l'utilisation de scanf().
Entrer des caractères inattendus dans un appel à scanf()
Nous allons prendre un exemple très simple, vous voulez que l'utilisateur entre un nombre et vous voulez le récupérer dans une variable.
Quoi de plus simple avec notre ami scanf() !
Code : C 1
2
3
4
5
6
7
8
9
10
11
12 | #include <stdio.h>
int main (void)
{
int nombre;
printf("Entre un nombre s'il-te-plait : \n");
scanf("%d", &nombre);
printf("Merci ! le nombre que vous avez tape est %d", nombre);
return 0;
}
|
Ce qui donne après compilation et exécution :
Code : Console | Entre un nombre s'il-te-plait :
50
Merci ! Le nombre que vous avez tape est 50 |
Jusque-là, rien d'anormal.
Maintenant, relançons notre programme mais cette fois-ci en entrant quelques caractères :
Code : Console | Entre un nombre s'il-te-plait : dgsgcbv
[...] |
On entre dans une boucle infinie, ce problème est très embêtant.
Mais il ne faut pas en vouloir à scanf, elle fait son job. Le problème, c'est qu'elle a été conçue pour avoir des saisies dîtes "formatées" (d'où le nom : scan
formatted) c'est-à-dire, une saisie qui respecte caractère pour caractère ce que vous avez mis dans son appel (donc pour une saisie de chiffre, elle ne cherche pas à savoir si c'est un nombre ou pas, elle le stocke quand même dans votre int).
Entrer une chaîne de caractères
Vous souhaitez que l'utilisateur entre une chaîne dans votre programme ? Ok, on utilise scanf.
Code : C 1
2
3
4
5
6
7
8
9
10
11
12 | #include <stdio.h>
int main (void)
{
char chaine[20];
printf("Ecris une phrase s'il-te-plait : \n");
scanf("%s", chaine);
printf("Tu as entre : '%s'", chaine);
return 0;
}
|
On teste notre programme :
Code : Console | Ecris une phrase s'il-te-plait :
Salut ça va ?
Tu as entre : 'Salut' |

Oui, scanf n'a pris que le premier mot de notre phrase !
Pourquoi ? C'est très simple, avec l'utilisation du format %s, scanf supprime tous les espaces qu'il juge inutiles (avant ou après le premier mot de la chaîne), le comportement est facile à deviner, scanf ne prend que le premier mot (avant le premier espace) et le stocke dans la chaîne.
Où sont les caractères restants ? Dans le flux d'entrée standard,
stdin.
Et cela pose problème, effectivement, lors du prochain appel à scanf, les caractères non extraits (qui ne sont pas dans la chaîne) se trouvent dans stdin et vont directement se stocker dans la chaîne sans que l'utilisateur n'ait rien à demander.
Pour "manger" les caractères restants, on va tout simplement les lire, car ils sont non lus.
Pour cela, on va utiliser la macro très utilisée : getchar() (ou la fonction fgetc(stdin) ).
On va coder ça dans une fonction :
Code : C | static void purger(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
{}
}
|
On va tester ça avec un petit programme :
Code : C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | #include <stdio.h>
static void purger(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
{}
}
int main (void)
{
char chaine[20], chaine2[20];
printf("Ecris une phrase s'il-te-plait : \n");
scanf("%s", chaine);
printf("Tu as entre : '%s'", chaine);
purger();
printf("\nEcris une autre phrase s'il-te-plait : \n");
scanf("%s", chaine2);
printf("\nTu as entre : '%s'", chaine2);
purger();
return 0;
}
|
Et l'exécution :
Code : Console | Ecris une phrase s'il-te-plait :
Salut ça va ?
Tu as entre : 'Salut'
Ecris une autre phrase s'il-te-plait :
Bien et toi ?
Tu as entre : 'Bien' |
On voit que ce problème est résolu !
Vous avez vu le gros des problèmes. Vous voulez résoudre ça ? C'est parti pour la seconde partie !