这里有几个问题。
首先是没有检查 scanf() 的返回值。如果输入可用,则 scanf 返回已分配的变量数,在这种情况下可以是 0 或 1(因为您只尝试分配一个变量)。如果用户输入非数字字符,则循环将重复执行而无需等待更多用户输入,因为有可用输入但它永远不会匹配您的“%d”转换。如果你想使用 scanf() 那么你必须检查返回值。如果返回值为零,则输入了一个非数字值,这意味着您必须通过读取直到行尾将该值从输入缓冲区中清除。如果返回值等于 EOF,那么要么发生了 I/O 错误,要么您到达了流的末尾。
例程 isdigit() 接受一个整数参数,但它希望该整数值代表一个字符。由于您使用 scanf() 将输入转换为整数,因此存储在 a 中的值不再代表字符;它代表一个实际数字。因此,只有当用户输入与数字字符对应的数字时,对 isdigit() 的调用才会返回真值。在我的语言环境中,这意味着只有当用户输入介于 48 和 57 之间的数字(包括 48 到 57)时,验证才会成功。如果您使用的是 scanf(),则不需要进行 isdigit() 检查,因为仅当用户输入数字值时,scanf() 才会返回值 1。
然而,老实说,如果我可以避免它,我不会使用 scanf() 来读取用户输入,因为如果用户输入错误则需要刷新输入缓冲区。我不完全确定您的要求是什么,但我假设您应该从命令行读取一个正整数并且位数无关紧要。
在这种情况下,您可能希望使用 fgets() 读取用户输入,然后使用 strtol() 将值转换为有符号长整数并同时执行验证:
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
int main () {
long result;
long len;
int is_valid = 0;
char buf[128];
char *arg;
char *end;
while (!is_valid) {
/* Prompt the user for the integer. */
printf("Enter a non-negative integer: ");
if (fgets(buf, sizeof(buf), stdin) == NULL) {
printf("Giving up so soon?\n");
break;
}
/* Verify that the input doesn't exceed our buffer length. */
len = strlen(buf);
if (buf[len] != '\n') {
printf("Input buffer length exceeded - aborting.\n");
exit(1);
}
/* Skip any leading whitespace. */
for (arg = buf; isspace(*arg); arg++);
/* Attempt to convert the argument. */
errno = 0;
result = strtol(arg, &end, 10);
if (errno == EINVAL) {
printf("Please enter a numeric value.\n");
continue;
}
if (errno == ERANGE) {
printf("Numeric value out of range.\n");
continue;
}
/* Check for non-whitespace characters after the end of the integer. */
for (; isspace(*end); end++);
if (*end != '\0') {
printf("Please enter a numeric value.\n");
continue;
}
/* Verify that the number is non-negative. */
if (result < 0) {
printf("Please enter a positive value.\n");
continue;
}
/* The number is valid. */
printf("Excellent!\n");
is_valid = 1;
}
return 0;
}
这并不完美。如果超过输入缓冲区长度则中止并不完全是用户友好的。但是,它应该处理验证问题。