这个问题的快速答案是
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND)\
while(scanf(" "FORM, X)<1 || !(COND))
printf("Invalid input, enter again: ");
用下面的方式在代码中调用上面的宏
int a;
SCAN_ONEENTRY_WITHCHECK("%d", &a, (a>3 && a<15))
相当于这个
int a;
while(scanf(" %d", &a)<1 || !(a>3 && a<15))
printf("Invalid input, enter again: ");
但是上面的答案是错误的,因为如果用户输入例如aaa
作为输入,那么上面的代码将导致无限循环,因为标准输入没有被清理,因为aaa
输入没有被scanf(" %d", &a)
. 所以如果用户输入这样的输入,我们必须添加一些清理标准输入的东西。添加scanf("%*[^\n]")
可能是一个解决方案。上面的代码将是
int a;
while(scanf(" %d", &a)<1 || !(a>3 && a<15)) {
scanf("%*[^\n]"); // clean stdin
printf("Invalid input, enter again: ");
}
但上面的代码仍然包含一个限制。例如,如果用户输入了一个有效的整数 ( 20
),并且该整数不遵守条件(a>3 && a<15)
。在这种情况下,我们不必清理标准输入,因为它已经被清理了,否则用户将被要求输入数据 2 次。问题可以通过以下解决方案解决:
int a;
int c;
while((c=(scanf(" %d", &a)<1)) || !(a>3 && a<15)) {
if (c) scanf("%*[^\n]"); // clean stdin
printf("Invalid input, enter again: ");
}
上面的代码不遵守标准input data should be followed by white space
,例如,如果用户10abc
作为输入输入,那么上面的代码将捕获 10 作为输入整数,并将清除其余部分abc
。如果我们检查下一个字符是否为空格(带isspace()
函数) ,则可以解决此问题
int a;
char tmp;
int c;
while((c=(scanf(" %d%c", &a, &tmp)!=2 || !isspace(tmp))) || !(a>3 && a<15)) {
if (c) scanf("%*[^\n]"); // clean stdin
printf("Invalid input, enter again: ");
}
现在,如果我们想回到宏。宏代码将是:
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
char tmp;\
int c;\
while ((c=(scanf(" "FORM"%c", X, &tmp)!=2 || !isspace(tmp)))\
|| !(COND)) {\
if (c) scanf("%*[^\n]");\
printf("Invalid input, please enter again: ");\
}\
} while(0)
do {...} while(0)
可以通过此链接解释添加宏
上面的宏可以用另一种方式编写
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
char tmp;\
while(((scanf(" "FORM"%c",X,&tmp)!=2 || !isspace(tmp)) && !scanf("%*[^\n]"))\
|| !(COND)) {\
printf("Invalid input, please enter again: ");\
}\
} while(0)
使用宏的示例:
int main()
{
int decision;
double q;
char buf[32];
printf("Input data, valid choice 1 or 0: ");
SCAN_ONEENTRY_WITHCHECK("%d",&decision,(decision==0 || decision==1));
printf("You have entered good input : %d\n", decision);
printf("Input unsigned double: ");
SCAN_ONEENTRY_WITHCHECK("%lf",&q, (q == (unsigned int) q));
printf("You have entered good input : %lf\n", q);
printf("Input name: ");
SCAN_ONEENTRY_WITHCHECK("%s",buf, (strcmp(buf,"kallel")==0));
printf("You have entered good input : %s\n", buf);
printf("Input data should be valid integer: ");
SCAN_ONEENTRY_WITHCHECK("%d",&decision,1);
// COND is 1 ==> we do not have any check in the input integer
printf("You have entered good input : %d\n", decision);
}
执行
$ ./test
Input data, valid choice 1 or 0: 4
Invalid input, please enter again: a4
Invalid input, please enter again: a1
Invalid input, please enter again: 1a
Invalid input, please enter again: 1
You have entered good input : 1
Input unsigned double: 2.3
Invalid input, please enter again: a.0a
Invalid input, please enter again: 2.0a
Invalid input, please enter again: a2.0
Invalid input, please enter again: 2.0
You have entered good input : 2.000000
Input name: an
Invalid input, please enter again: anyad
Invalid input, please enter again: adny
Invalid input, please enter again: any
You have entered good input : any
Input data should be valid integer: 2.5
Invalid input, please enter again: -454f
Invalid input, please enter again: -454
You have entered good input : -454