读取输入数据并检查其有效性的通用宏
Common macro to read input data and check its validity
我在Stack Overflow上看到许多类似的问题重复出现,它们都与从stdin读取一个输入数据项并检查其有效性有关。
数据可以是整型"%d"
,双型"%f"
,字符串"%s"
,无符号整型"%u"
…
我想开发一个通用的宏,可以用于这些问题的多数。
问题示例1
OP可以问:
- 扫描输入数据
- 数据应该是整数,所以
11a
,aaa
,aa44
,…不允许输入。只允许后跟空格的整数(参考isspace()) - 其他条件可能出现在问题中,如:输入整数应该是
>3
和<15
问题示例二
OP可以问:
- 扫描输入数据
- 数据应该是双的,所以
11.2a
,aaa
,aa44.3
,…不允许输入。只允许双引号后跟空格(参考isspace()) - 其他条件可能出现在问题中,如:输入双精度应该是
>3.2
和<15.0
是否可能开发一个像
这样的通用宏?#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND)
// FORM: format of the input data like "%d", "%lf", "%s"
// X: address where to store the input data
// COND: condition to add in the check of the input data
....
// example of calling the macro in the main()
int a;
SCAN_ONEENTRY_WITHCHECK("%d", &a,(a>3 && a<15))
宏应该扫描数据,如果下列条件之一不为真,则打印一条消息给用户,要求他再次输入。并重复该操作,直到用户输入有效数据?
标准:
- 输入数据类型应与格式 相同
- 输入数据后面应该有isspace() 中指示的空白。
- 输入数据应在
COND
条件下有效
这个问题的简单答案是
#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
作为输入,那么上面的代码将导致一个无限循环,因为没有清理stdin,因为aaa
的输入没有被scanf(" %d", &a)
捕获。因此,如果用户输入这样的输入,我们必须添加一些东西来清理stdin。添加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)
。在这种情况下,我们不需要清理stdin,因为它已经被清理过了,否则用户将被要求输入数据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 : %dn", decision);
printf("Input unsigned double: ");
SCAN_ONEENTRY_WITHCHECK("%lf",&q, (q == (unsigned int) q));
printf("You have entered good input : %lfn", q);
printf("Input name: ");
SCAN_ONEENTRY_WITHCHECK("%s",buf, (strcmp(buf,"kallel")==0));
printf("You have entered good input : %sn", 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 : %dn", 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
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 2D数组来自文本输入,中间有空格
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 检查输入是否不是整数或数字
- 正在尝试了解输入验证循环
- 读取文件并输入到矢量中
- C++如何通过用户输入删除列表元素
- 用c++从输入文件中读取另一行
- 读取文件的最后一行并输入到链接列表时出错
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何使用用户输入在C++中正确填充2D数组
- C++MySQL C api用户输入行
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 用户定义函数中的指针和输入
- 如何在C++中检查2D数组中负值的输入验证
- 如何从 Python 扩展检查输入变量的有效性
- 使用正则表达式检查输入的有效性
- QLineEdit with QValidator:不管输入的有效性如何,对编辑完成做出反应
- 读取输入数据并检查其有效性的通用宏
- 检查输入有效性