【问题标题】:Unexpected behaviour of scanfscanf 的意外行为
【发布时间】:2017-05-08 10:01:38
【问题描述】:

我想将两个整数作为输入并输出它们的和。当给定两个整数作为输入时,该代码可以正常工作。但是,当我将一个非整数值作为第一个值的输入(比如 2.3)并按 Enter 键时,程序不会等待第二个输入并产生一个奇怪的输出。

你能告诉我为什么会这样吗?

#include <stdio.h>

int main()
{
    int a, b;
    scanf(" %d%d", &a, &b);

    int c = a +b;
    printf("%d\n", c);

    return 0;
}

【问题讨论】:

  • scanf() 返回什么值?
  • 提示:The value has a meaning。并且根据该值,您可以知道您的未初始化变量是否仍然具有不确定的值。
  • scanf() 返回成功读取的值的数量。在您的情况下,当输入为 2.3 时,它返回 1,因为只有 2 被正确读取。但是,当您将两个数字都输入为整数时,它会返回 2,因为它会正确读取两个整数。

标签: c scanf


【解决方案1】:

给定输入2.3,格式字符中的空格会导致跳过任何空格(没有空格),第一个%d 会导致读取2 的值。下一个要读取的字符将是.,它将保留在缓冲区中。 scanf(),在处理第二个%d 时会遇到那个'.',认为该字符不是整数值的一部分,并终止读取,再次将'.' 留在待读取的流中。

因此scanf(" %d%d", &amp;a, &amp;b) 的净效果是将2 读取为a,而b 没有变化。

除非您的代码执行某些操作来读取 '.'(例如使用 %c 格式读取它),否则 . 将继续在流中,并且每次后续使用 %d 都会在同样的方式。

您的代码没有检查来自scanf() 的返回值,但如果检查了,则会检测到问题的另一个后果。然后scanf() 的返回值将是1,表示成功读取了一个值(a)。如果整数ab都被成功读取,则返回值2

由于bmain() 中未初始化,访问其值会产生未定义的行为,而scanf() 不会改变这一事实。未定义行为的一种可能后果是您看到的“奇怪输出”。

【讨论】:

    【解决方案2】:

    当您给scanf 一些它无法解析的输入时,它不会使您的程序崩溃。相反,它会在其返回值中报告错误。具体来说,如果你输入2.3scanf将能够将2读入a,但遇到点时会停止解析。

    任何未读取的变量都可能保持原来的状态。在您的情况下,b 可能保持未初始化状态。从未初始化的变量中读取是“未定义的行为”(我建议使用谷歌搜索它是什么)。特别是,您的程序可以崩溃、格式化您的硬盘驱动器,或者之后输出看起来很奇怪的垃圾。

    【讨论】:

      【解决方案3】:

      使用scanf的返回值

      if (scanf("%d%d", &a, &b) != 2) exit(EXIT_FAILURE);
      

      【讨论】:

        【解决方案4】:

        看看 scanf 做了什么 -
        从标准输入读取数据并根据参数格式将它们存储到附加参数指向的位置。

        此外,scanf() 返回成功读取的值的数量。
        您可以通过查看 scanf() 返回的值来查看哪些值被正确读取。 在用户输入 2.3 或任何其他此类值(形式为 integer.integer)的情况下,scanf() 返回 1。这意味着只有 2 被成功读取。在您的情况下,变量 a 被赋值为 2 而 b 具有一些垃圾值。 并且当执行加法时,该垃圾值被添加到 2。

        【讨论】:

          【解决方案5】:

          这是man 页面上关于scanf() 的内容

          RETURN VALUE
             On success, these functions return the number of input  items  success‐
             fully  matched  and  assigned;  this can be fewer than provided for, or
             even zero, in the event of an early matching failure.
          
             The value EOF is returned if the end of input is reached before  either
             the  first  successful conversion or a matching failure occurs.  EOF is
             also returned if a read error occurs, in which case the error indicator
             for the stream (see ferror(3)) is set, and errno is set to indicate the
             error.
          

          这一行:

          scanf(" %d%d", &a, &b); 
          

          应该返回 2。任何其他都表明有问题。

          建议:

          if( 2 != scanf( " %d %d", &a, &b ) )
          {
              // handle error
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-04-21
            • 1970-01-01
            • 1970-01-01
            • 2016-05-10
            • 2021-04-01
            • 1970-01-01
            • 2020-10-04
            相关资源
            最近更新 更多