C编程:如何检查用户是否仅在以下表达式中输入了数值?

时间:2015-02-21 06:25:40

标签: c validation date exception scanf

我将以某种日期作为用户的输入,格式如下:mm / dd / yyyy。

如何确定用户仅输入数值,如果没有,则再次提示他输入有效日期。我已根据输入的值检查日期是否有效,但如果用户输入的值不是完全数字,则程序崩溃。

请帮忙......

守则:

int x=0;
printf("\nEnter the date of birth(mm/dd/yyyy):");
do
{
    scanf("%d/%d/%d",&add.dob.month,&add.dob.day,&add.dob.year);
    if((add.dob.month<13 && add.dob.month>0) && (add.dob.day>0 && add.dob.day<32) && (add.dob.year<2016))
    {
        x=1;
    }
    else
    {
        printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
    }
}while(x!=1);

5 个答案:

答案 0 :(得分:3)

有几个问题。如果使用scanf 检查其返回。除了数字有效性检查之外,还存在在用户输入除整数之外的事件时需要刷新输入缓冲区的问题。虽然有几种方法可以做到这一点,但保持您的方法的一种方法只是预先形成您正在进行的检查,然后使用第二个do/while循环手动刷新输入缓冲区。您还可以转换逻辑并测试任何一个条件是否为真,强制另一个提示日期。如上所述,有很多方法可以解决这个问题。将此视为您收到的其他答案之一。

int c = 0;          /* value to test for end of input buffer */

printf("\nEnter the date of birth(mm/dd/yyyy):");

while ((scanf("%d/%d/%d",&add.dob.month,&add.dob.day,&add.dob.year) != 3) ||
       (add.dob.month < 1) || 
       (add.dob.month > 12 ) ||
       (add.dob.day < 1 ) ||
       (add.dob.day > 31) ||
       (add.dob.year < 1) || 
       (add.dob.year > 2015))
{
    printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
    do { c = getchar(); } while (c != '\n' && c != EOF);  /* flush input buffer */
}

如上所述,从stdin读取信息的一种稍微强大的方法是使用fgetsgetline将日期作为字符串读入缓冲区,然后解析来自缓冲区的月,日,年信息。这也可以通过多种方式完成。由于您最终将从字符转换为十进制,您也可以使用strtol来解析和转换,而不是使用指针踩下字符串或使用strtokstrsep解析(因为每个都需要在分离后转换为十进制)。这是一个提供相当强大的解决方案的快速示例。除了mm-dd-yyyy之外,它还允许将日期输入为mm.dd.yyymm/dd/yyyy

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

#define SZDATE 12

int main (void) {

    int mm = 0;                     // month/day/year values
    int dd = 0;
    int yyyy = 0;
    int gooddate = 0;               // flag signifying valid date
    char datestr[SZDATE] = {0};     // buffer to hold input string
    char *p = NULL;                 // pointer to use with strtol
    char *endptr = NULL;            // end pointer for strtol
    long val = 0;                   // long value for strtol

    while (gooddate == 0)
    {
        printf("\nEnter the date of birth (mm/dd/yyyy): ");

        /* read string with fgets */
        fgets (datestr, SZDATE-1, stdin);

        /* test sufficient length */
        if (strlen (datestr) < 8) {
            printf ("\n insufficient date length entered, try again.\n");
            continue;
        }

        /* parse month value with strtol (with error checking) */
        errno = 0;
        val = strtol (datestr, &endptr, 10);
        if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
            || (errno != 0 && val == 0)
            || (endptr == datestr)
            || (*endptr != '/' && *endptr != '-' && *endptr != '.')
            || (val < 1)
            || (val > 12)) {
                printf ("\n invalid month entered, try again.\n");
                continue;
        }
        mm = (int) val;     /* set month on successful conversion   */

        p = ++endptr;       /* set p to start of day, reset endptr  */
        endptr = NULL;

        /* parse day value with strtol (with error checking) */
        errno = 0;
        val = strtol (p, &endptr, 10);
        if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
            || (errno != 0 && val == 0)
            || (endptr == p)
            || (*endptr != '/' && *endptr != '-' && *endptr != '.')
            || (val < 1)
            || (val > 31)) {
                printf ("\n invalid day entered, try again.\n");
                continue;
        }
        dd = (int) val;     /* set day on successful conversion     */

        p = ++endptr;       /* set p to start of year, reset endptr */
        endptr = NULL;

        /* parse year value with strtol (with error checking) */
        errno = 0;
        val = strtol (p, &endptr, 10);
        if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
            || (errno != 0 && val == 0)
            || (endptr == p)
            || (*endptr != '\n' && *endptr != 0)
            || (val < 1900)
            || (val > 2015)) {
                printf ("\n invalid year entered, try again.\n");
                continue;
        }
        yyyy = (int) val;   /* set year on successful conversion    */

        gooddate = 1;       /* set gooddate flag ending loop        */
    }

    printf ("\n valid date is: %d/%d/%d\n\n", mm, dd, yyyy);

    return 0;
}

仔细检查与strtol次转化相关的检查。您可能想要添加更多内容。另外,尝试使用strtok等进行解析并进行比较。这只是将读取视为字符串然后解析的一种方法。它可以通过许多不同的方式完成。

答案 1 :(得分:2)

您应该检查scanf的返回值,看看它是否能够完成所有分配。如果没有,您需要在再次尝试之前使用用户的输入,否则您将尝试无限循环并且无法一遍又一遍地读取相同的输入。例如:

do {
    printf("\nEnter the date of birth(mm/dd/yyyy): ");
    fflush(stdout);
    if (scanf("%d/%d/%d", &month, &day, &year) != 3) {
        scanf("%*[^\n]"); // consume line from input, do not assign
    } else if (month < 13 && month > 0 && day < 32 && day > 0 && year < 2016) {
        break;
    }
    printf("Invalid date!\n");
} while (!feof(stdin));

另一方面,您缺少对日期有效性的检查,例如,用户仍然可以输入02/30 / -5。

编辑:参考下面评论中的讨论,这里对角落案件的处理很差;假设这是一个旨在始终在本地终端上交互运行的程序。为了正确处理输入,我强烈建议您从scanf切换到fgets(之后可能sscanf)。然后应检查fgets的返回值,并在那里处理错误,而不是可能有问题的feof检查。当然,scanf解决方案可以通过正确检查不同的返回值(例如EOF)来变得更加迂腐,但我认为它不值得。

答案 2 :(得分:2)

您可以查看scanf()返回值,以测试三个输入的值是否为int类型。

代码:

int returnval = scanf("%d/%d/%d",&input1, &input2, &input3);
if (returnval == 3)
{
    //The input is correct.
}
else
{
   printf("The input is not correct.");
   //The input is not correct.
}

答案 3 :(得分:1)

要检查scanf的返回值,它将返回读取的输入数量 只需说输入1输入2和输入3是整数

int isValid = 0;
while (!isValid)
{
    isValid = scanf("%d/%d/%d",&input1, &input2, &input3);
    if(isValid != 3)
    {
        printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
    }
    else
    {
        // the user entered integers
        if((add.dob.month<13 && add.dob.month>0) && (add.dob.day>0 && add.dob.day<32) && (add.dob.year<2016))
        {
        }
        else
        {
            isValid = 0; // it didn't pass your date validation but it did pass integer validation 
        }
    }
}

如果用户输入字符或字符串或任何非整数的内容,则scanf将返回0并且您可以使其循环。如果将if部分留空,我使用了非常糟糕的if / else,它会更好地否定每一个,但这是一个不同的故事。故事的道德只是检查scanf返回什么,如果它返回&gt; 1,用户输入数字,如果返回0,则他们尝试输入字母并且失败。

答案 4 :(得分:1)

您可以扫描输入,然后通过strtol()之类的函数对其进行解析。 strtol()会告诉您是否包含所有数字或混合数字。 这将为您节省一些麻烦,最后您需要做的就是检查数字边界。

请查看atoi() — string to int

的答案