【问题标题】:Accept numeric values only in C仅在 C 中接受数值
【发布时间】:2020-05-14 01:20:21
【问题描述】:

我正在尝试读取 numeric only 值,然后该值将执行特定函数,具体取决于使用 switch 语句的值。
我知道我可以使用while(option < 0 || option >3 || option != 99),但是有解决方法吗?

个人作品:

do
{
  printf("Please choose an option :\n0. Create Database\n1.Add New Student \n2. Show All Students \n3.Delete Student\n99.Exit\n");
  scanf("%d", &option);
} while (!isdigit(option));

由于某种原因它不起作用。

【问题讨论】:

  • "option 3 || option != 99" 永远为真;删除“option != 99”然后它应该可以工作:“while(option 3)”
  • Alexander Voliotis,不符合条件的输入应该怎么办?错误信息,忽略,退出代码?
  • @Abdurrahim 尽管您还必须刷新无效输入
  • 您将整数视为字符。我清楚地明白为什么那行不通。也许您可以检查 scanf 的返回值?

标签: c numeric


【解决方案1】:

您的主要问题是,如果scanf 由于某种原因(例如输入x)未能读取任何数字,它将返回零(成功扫描的项目数),而不是填充@987654324 @,并且(这是杀手)将输入指针留在与开始之前相同的位置。

不幸的是,这意味着,当您返回获取另一个数字时,它只会尝试重新读取有问题的数据,并且可能会进入无限循环而不允许更多输入。

scanf 系列适用于格式化数据,没有什么比用户输入更未格式化了:-)

您的最佳 选择是使用坚如磐石的输入功能进入一条线,然后只需检查该线 以查看它是否有效。这样的功能可以找到here。将其纳入您的需求将为您提供以下内容:

#include <stdio.h>
#include <string.h>

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2

static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

#include <ctype.h>  // only needed for isdigit, not for above code.

int main(void) {
    int option;

    do {
        // Only allowed up to two characters (plus '\0').

        char buff[3];
        int result = getLine(
           "Menu\n"
           "   0. Create Database\n"
           "   1. Add New Student\n"
           "   2. Show All Students\n"
           "   3. Delete Student\n"
           "  99. Exit\n"
           "Please choose option: ",
           buff, sizeof(buff));

        // No point continuing on EOF, input stream is closed.

        if (result == NO_INPUT) {
            puts("\n*** End of input");
            return 1;
        }

        // All faults just restart operation: too long, too short,
        // non-digits.

        if (result == TOO_LONG) continue;
        if (! isdigit(buff[0])) continue;
        if (buff[1] != '\0' && ! isdigit(buff[1])) continue;

        // Now get the integer representation and continue unless valid.

        sscanf(buff, "%d", &option);
    } while (option != 99 && (option < 0 || option > 3));                                                                                                                                                        

    printf("You chose %d\n", option);
    return 0;
}

而且,是的,我知道我说过你应该检查来自 scanf 的返回值,但在我发布的代码的情况下没有必要,因为你已经确定你正在扫描的字符串是有效的一位或两位数。

【讨论】:

    【解决方案2】:

    就像卡尔说的: isdigit 仅用于检查单个字符,此处不应用于从 scanf 获得的 int 值。

    为了归档你的需求,我们可以使用scanf获取一个字符串,然后使用strtol转换成int,检查endptr确认如果有任何无效字符。

    代码可能是这样的:

        int option;
        char str[8];
        char *endp;
        do{
            printf("Please choose an option :\n0. Create Database\n1.Add New Student \n2. Show All Students \n3.Delete Student\n99.Exit\n");
            scanf("%7s", str);
            option = strtol(str,&endp,10);
        } while (*endp);
    

    【讨论】:

    • 当你只需要两个字符加上换行符时为什么要7
    • 可以是任意数字,只要保证小于str的大小(即8个字符)且大于2。更大的数字可以使它更健壮一些,因为用户可以输入数字a更大的数字。
    【解决方案3】:

    这是我使用 scanf 能想到的最完整、最安全的解决方案:

    int option;
    int status;
    char tailchar;
    
    status = 2;
    tailchar = '\n';
    do {
        if(tailchar != '\n' || status != 2){
            for (int c=getchar(); c!='\n' && c!=EOF; c=getchar());
        }
        printf("Please choose an option:\n"
            " 0. Create Database\n"
            " 1. Add New Student \n"
            " 2. Show All Students \n"
            " 3. Delete Student\n"
            "99. Exit\n");
        status = scanf(" %d%c", &option, &tailchar);
    } while (status != 2 || option < 0 || (option >3 && option != 99));
    if(tailchar != '\n'){
        for (int c=getchar(); c!='\n' && c!=EOF; c=getchar());
    }
    

    它只接受有效的选项,并在要求再次选择之前清除用户的任何错误输入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 1970-01-01
      • 1970-01-01
      • 2016-07-31
      • 2016-11-03
      • 2019-02-10
      相关资源
      最近更新 更多