用于读取输入数据并检查其有效性的通用宏

时间:2013-04-03 16:31:39

标签: c++ c macros

我在Stack Overflow上看到许多类似的问题被重复,它们与从 stdin 读取一个输入数据项有关,并检查其有效性。

数据可以是整数"%d",双"%f",字符串"%s",无符号整数"%u" ...

我想开发一个可以用于这些问题的多数的通用宏。

问题示例1

OP可以问:

  • 扫描输入数据
  • 数据应为整数,因此不允许11aaaaaa44,...输入。只允许整数后跟一个空格(参考isspace()
  • 问题中可能存在其他条件:输入整数应为>3<15

问题示例2

OP可以问:

  • 扫描输入数据
  • 数据应加倍,以便11.2aaaaaa44.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

1 个答案:

答案 0 :(得分:1)

这个问题的快速答案将是

#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 。如果我们检查下一个charachter是否是一个空格(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)

可以通过此link

解释在宏中添加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