Je veux que le code s'exécute jusqu'à ce que l'utilisateur entre une valeur entière.
Le code fonctionne pour les tableaux char et char.
J'ai fait ce qui suit:
#include<stdio.h>
int main()
{
int n;
printf("Please enter an integer: ");
while(scanf("%d",&n) != 1)
{
printf("Please enter an integer: ");
while(getchar() != '\n');
}
printf("You entered: %d\n",n);
return 0;
}
Le problème est que si l'utilisateur entre une valeur flottante scanf
l'acceptera.
Please enter an integer: abcd
Please enter an integer: a
Please enter an integer: 5.9
You entered: 5
Comment éviter cela?
scanf()
.fgets()
pour obtenir une ligne entière.strtol()
pour analyser la ligne comme un entier, en vérifiant si elle a consommé la ligne entière.char *end;
char buf[LINE_MAX];
do {
if (!fgets(buf, sizeof buf, stdin))
break;
// remove \n
buf[strlen(buf) - 1] = 0;
int n = strtol(buf, &end, 10);
} while (end != buf + strlen(buf));
Utilisez fgets
et strtol
,
Un pointeur sur le premier caractère suivant la représentation entière dans s
est stocké dans l'objet pointé par p
, si *p
est différent de \n
alors vous avez une mauvaise entrée.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *p, s[100];
long n;
while (fgets(s, sizeof(s), stdin)) {
n = strtol(s, &p, 10);
if (p == s || *p != '\n') {
printf("Please enter an integer: ");
} else break;
}
printf("You entered: %ld\n", n);
return 0;
}
Je sais comment cela peut être fait en utilisant
fgets
etstrtol
, je voudrais savoir comment cela peut être fait en utilisantscanf()
(si possible).
Comme le disent les autres réponses, scanf
n'est pas vraiment adapté à cela, fgets
et strtol
est une alternative (bien que fgets
ait l'inconvénient que c'est difficile pour détecter un 0 octet dans l'entrée et impossible de dire ce qui a été entré après un 0 octet, le cas échéant).
Par souci d'exhaustivité (et en supposant qu'une entrée valide est un entier suivi d'une nouvelle ligne):
while(scanf("%d%1[\n]", &n, (char [2]){ 0 }) < 2)
Vous pouvez également utiliser %n
avant et après %*1[\n]
avec suppression d'affectation. Notez cependant (à partir de la page de manuel Debian ):
Ce n'est pas une conversion, bien qu'elle puisse être supprimée avec le
*
caractère de suppression d'affectation. La norme C dit: "Exécution d'un%n
la directive n'augmente pas le nombre d'affectations retourné à la fin de l'exécution "mais le Corrigendum semble contredire cela. Il est probablement sage de ne faire aucune hypothèse sur l'effet de%n
conversions sur la valeur de retour.
Essayez d'utiliser le modèle suivant dans scanf
. Il se lira jusqu'à la fin de la ligne:
scanf("%d\n", &n)
Vous n'aurez pas besoin de la getchar()
à l'intérieur de la boucle puisque scanf
lira toute la ligne. Les flottants ne correspondront pas au modèle scanf
et l'invite demandera à nouveau un entier.
Une solution possible consiste à y penser à l'envers: Acceptez un flottant en entrée et rejetez l'entrée si le flottant n'est pas un entier:
int n;
float f;
printf("Please enter an integer: ");
while(scanf("%f",&f)!=1 || (int)f != f)
{
...
}
n = f;
Bien que cela permette à l'utilisateur d'entrer quelque chose comme 12.0, ou 12e0, etc.
Si vous souhaitez utiliser scanf
, vous pouvez faire quelque chose comme ceci:
int val;
char follow;
int read = scanf( "%d%c", &val, &follow );
if ( read == 2 )
{
if ( isspace( follow ) )
{
// input is an integer followed by whitespace, accept
}
else
{
// input is an integer followed by non-whitespace, reject
}
}
else if ( read == 1 )
{
// input is an integer followed by EOF, accept
}
else
{
// input is not an integer, reject
}
Il est préférable d'utiliser fgets()
.
Pour résoudre uniquement en utilisant scanf()
pour la saisie, recherchez un int
et le char
suivant.
int ReadUntilEOL(void) {
char ch;
int count;
while ((count = scanf("%c", &ch)) == 1 && ch != '\n')
; // Consume char until \n or EOF or IO error
return count;
}
#include<stdio.h>
int main(void) {
int n;
for (;;) {
printf("Please enter an integer: ");
char NextChar = '\n';
int count = scanf("%d%c", &n, &NextChar);
if (count >= 1 && NextChar == '\n')
break;
if (ReadUntilEOL() == EOF)
return 1; // No valid input ever found
}
printf("You entered: %d\n", n);
return 0;
}
Cette approche ne ré-invite pas si l'utilisateur n'entre que des espaces blancs tels que Enter.