【问题标题】:Check for correct input via scanf通过 scanf 检查输入是否正确
【发布时间】:2021-07-19 12:02:25
【问题描述】:

我有一个整数“n”,它负责稍后输入的数字数量。 我需要在这里检查任何不正确的输入。 'n' 的第一个 scanf 工作正常,但第二个有一些缺陷。 案例如下:

n = 3(例如)- 没关系

那我想scanf: 1 2 3 4

它将被扫描前 3 个值,但我需要抛出一个错误。

同样:1 2 3.5 -(最后一个数字是浮点数,但仍为 3)

还有一个字符:1 2 3g

if (scanf("%d", n) == 1 && getchar() == '\n') {
        if (n > NMAX || n < 0) {
            error = 1;
            return;
        }
        for (int i = 0; i < n; i++) {
            if (scanf("%d", p) == 1) {

唯一正确的输入是在for 循环中扫描的完全相同数量的整数(等于“n”)。

UPD:我只能使用 &lt;stdio.h&gt; 库以及 scanf

【问题讨论】:

  • 仅将fgets() 用于用户输入(可能后跟strtol()
  • fgets() 是标准库的一部分,它的原型在&lt;stdio.h&gt; header
  • 您可以手动解析来自fgets() 的字符串,而不是使用strtol() ... 甚至使用sscanf()。要点是:scanf() 是获取用户输入的坏工具......它可以在一些行为良好的环境中做到这一点(当 scanf 期望整数不是行为良好的环境时键入 "3.5"),但它缺乏(很多!)在处理错误输入时。
  • @Arzental 如果你不被允许使用scanf 以外的任何东西,那么你就不走运了。 scanf 是用户输入的糟糕选择。它不是为此而设计的。
  • @ryyker:提示在名称中:scan formatted 它旨在读取定义明确的数据文件,例如之前的那些通过printf()写的。 ;-)

标签: c scanf


【解决方案1】:

创建一个辅助函数来读取 int 并对其进行验证。

关键是要验证输入,形成一个辅助函数,您可以根据需要对其进行改进,例如在删除“only scanf”要求后使用fgets() 而不是scanf()

// Sample
// Return 1 on success
// Return EOF on end-of-file
// Else return 0
int read_int(int *i, int min, int max, int line) {
  long long num;
  int result = scan("%18lld", &num);  // Accept many out of int range input
  if (result == EOF) return result;  // or if (result < 0)

  if (line) {
    // consume the rest of the line
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF) {
      if (!isspace(ch)) { // or `ch != ' ' && `ch != '\t' && ...
        result == 0; 
      }
    }
  }

  if (result == 1) {
    if (num < min || num > max) {
      return  0; 
    }
    *i = (int) num; 
  }

  return result;
}
    

示例用法

if (read_int(&n, 0, NMAX, 1) != 1) {
  error = 1;
  return;
}
for (int i = 0; i < n; i++) {
  if (read_int(&p, INT_MIN, INT_MAX, i + 1 == n) != 1) {
    error = 1;
    return;
  }
  ...

注意:read_int() 不会捕获所有错误,只会捕获许多错误。一旦知道所有 OP 的限制和目标,就很容易改进。

【讨论】:

    【解决方案2】:

    尝试使用带有 scanf 的扫描集。 %1[\n] 最多会扫描一个换行符。 %99[ \t] 将扫描多达 99 个空格或制表符字符。如果字符不是换行符、空格或制表符,则在输入流中替换它。
    如果 scanf%d 无法扫描 int,它将返回 0scanf 也可以返回 EOF
    fgets 并使用 strtol 或其他方式解析是更好的解决方案。

    #include <stdio.h>
    
    int main ( void) {
        char space[100] = "";
        char newline[2] = "";
        int number = 0;
        int count = 0;
        int quantity = 3;
    
        printf ( "enter %d integers\n", quantity);
        while ( 1) {
            if ( 1 == scanf ( "%d", &number)) {
                ++count;
            }
            else {
                printf ( "could not parse an integer\n");
                break;
            }
            scanf ( "%99[ \t]", space);
            if ( 1 == scanf ( "%1[\n]", newline)) {
                if ( count == quantity) {
                    printf ( "scanned %d integers\n", quantity);
                    break;
                }
                else if ( count > quantity) {
                    printf ( "too many integers\n");
                    break;
                }
                else printf ( "enter another integer\n");
            }
        }
        return 0;
    }
    

    【讨论】:

    • 这是一个很好的答案,因为它完美地展示了我在另一条评论中所说的内容:“尝试使用 scanf 进行完整、强大的用户输入和错误检查,是要么是不可能的,要么就是如此复杂、令人困惑和困难,以至于不值得。”这个程序运行良好,并且满足要求——但它是扭曲的、不可读的和不可维护的。 (很抱歉没有投票,但我不能投票赞成这样的烂摊子,即使它回答了问题并证明了一点。)
    • 扫描并丢弃所有空格,tab,可以使用scanf ( "%*[ \t]");
    【解决方案3】:

    检查这是否有效

    while(n-1)
    {
        scanf("%d ",p);
        n-=1;
    }
    scanf("%d",p);
    //After this you can scan again to check if there is anything extra in input
    //and throw error accordingly
    

    【讨论】:

    • scanf 读取整数是容易的部分。那不是问题。这是检查任何额外的东西并抛出错误,这是困难的部分。 (此外,如果输入数字中有字符“x”,则此代码将进入无限循环。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多