【问题标题】:C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf [duplicate]C:多个scanf,当我为一个scanf输入一个值时,它会跳过第二个scanf [重复]
【发布时间】:2021-12-22 08:53:46
【问题描述】:

我有这段代码(因为逻辑是家庭作业的一部分,所以省略了函数):

#include <stdio.h>

int main()
{
    char c = 'q';
    int size; 

    printf("\nShape (l/s/t):");
    scanf("%c",&c);

    printf("Length:"); 
    scanf("%d",&size);

    while(c!='q')
    {
        switch(c)
        {
            case 'l': line(size); break; 
            case 's': square(size); break;
            case 't': triangle(size); break; 
        }


        printf("\nShape (l/s/t):");
        scanf("%c",&c);

        printf("\nLength:"); 
        scanf("%d",&size);
    }

    return 0; 
}

前两个 Scanf 的工作很好,一旦我们进入 while 循环就没有问题,我有一个问题,当你应该被提示输入一个新的形状字符时,​​它反而跳到了 printf 的长度并等待从那里获取一个字符的输入,然后在循环的下一次迭代中获取一个小数。

预循环迭代:

Scanf:形状。效果很好
Scanf:长度。没问题

循环 1。

Scanf:形状。跳过这个
Scanf:长度。问题,这个 scanf 映射到形状 char。

循环 2
Scanf:形状。跳过这个
Scanf:长度。问题,这个 scanf 现在映射到大小 int 。

为什么要这样做?

【问题讨论】:

    标签: c scanf


    【解决方案1】:

    scanf("%c")ENTER 键读取换行符。

    当您键入15 时,您键入15,然后按ENTER 键。所以现在输入缓冲区中有三个字符。 scanf("%d") 读取15,将它们解释为数字15,但换行符仍在输入缓冲区中。 scanf("%c") 会立即读取这个换行符,然后程序会转到下一个scanf("%d"),并等待你输入一个数字。

    通常的建议是使用fgets 读取整行输入,并在单独的步骤中解释每行的内容。一个更简单的解决您当前问题的方法是在每个 scanf("%d") 之后添加一个 getchar()

    【讨论】:

    • 如果用户在数字后面不小心输入了一个空格(或其他垃圾),scanf("%d"); getchar(); 组合将失败。
    【解决方案2】:

    基本问题是scanf() 在缓冲区中的数字后面留下换行符,然后在下一次传递时用%c 读取它。实际上,这很好地说明了为什么我不使用scanf();我使用行阅读器(例如fgets())和sscanf()。更容易控制。

    您可以通过使用" %c" 而不是"%c" 作为格式字符串来拯救它。空白会导致 scanf() 在读取字符之前跳过空格(包括换行符)。

    但从长远来看,放弃scanf()fscanf() 并使用fgets() 或等价物加上sscanf() 会更容易。除此之外,当您使用整个字符串而不是 scanf() 失败后留下的小滴时,错误报告会容易得多。

    您还应该始终检查您是否获得了从scanf() 转换而来的值。输入失败——通常而且非常可怕。不要因为你没有检查就让它破坏你的程序。

    【讨论】:

      【解决方案3】:

      尝试在scanf中添加一个空格。

      scanf(" %d", &var);
      //     ^
      //   there
      

      这将导致scanf() 在匹配整数之前丢弃所有空格。

      【讨论】:

      • 根据section 7.21.6.2p8scanf通常会在匹配整数之前丢弃所有空格,无论如何,以这种格式字符串呈现空格毫无意义:"输入空白字符(由 isspace 函数指定)将被跳过,除非规范包含 [、c 或 n 说明符。”
      • 这不能解决问题。 %d 已经跳过了前导空白字符。
      【解决方案4】:

      使用函数

      void seek_to_next_line( void )
      {
          int c;
          while( (c = fgetc( stdin )) != EOF && c != '\n' );
      }
      

      清除输入缓冲区。

      【讨论】:

      • 这个功能不错。为了可读性,我会将空语句(单个分号)放在单独的行上。
      • 我也喜欢这个,但我认为最好不要使用“flush”这个词,因为它在标准中有一个既定的定义,与使用相矛盾这里。也许seek_to_next_line 会是一个更具描述性的名字?
      • 进行@Sebivor 提议的更改。
      • 也将其放在这里,因为我无法添加自己的答案,这是我看到的最佳答案:scanf("%*[^\n]"); getchar();。如果你愿意,你可以把它包装成一个函数。这个答案没有任何好处;两者在技术上都很好,虽然答案更容易维护,在这种情况下这是一把双刃剑;通常我们倾向于编写更易于维护的代码,但是对于更简单版本的白痴可能更有可能被修改为不正确的东西……你知道我在说什么……某种优化。为每个工作选择正确的工具,对吗?
      【解决方案5】:

      在对scanf 的第一次调用完成后,'\n' 字符仍留在输入流中,因此对scanf() 的第二次调用将其读入。使用getchar()

      【讨论】:

        【解决方案6】:

        当您键入形状并 ENTER 时,该形状被第一个 scanf 消耗,但 ENTER 不是!第二个 scanf 需要一个数字,因此,ENTER 被跳过,因为被认为是一个空格,并且 scanf 等待一个有效的输入(一个数字),它再次被 ENTER 终止。好吧,这个数字被消耗了,但 ENTER 不是,所以 while 内的第一个 scanf 使用它并且你的形状提示被跳过......这个过程重复。您必须在 scanfs 中添加另一个 %c 来处理 ENTER 键。我希望这会有所帮助!

        【讨论】:

          【解决方案7】:

          你也可以使用 scanf("%c%*c", &amp;c); 读取两个字符并忽略最后一个字符(在本例中为 '\n')

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-10-16
            • 1970-01-01
            • 2014-08-06
            • 1970-01-01
            • 2011-08-30
            相关资源
            最近更新 更多