【问题标题】:scanf takes extra parameter why?scanf 需要额外的参数,为什么?
【发布时间】:2015-08-24 16:09:28
【问题描述】:

我是 C++ 的新手,我过去常常扫描以获取输入参数。但是我给了两个输入参数。但是程序允许我输入额外的参数。请解释一下为什么会这样。请在下面找到我使用的代码。

#include <iostream>

int main(int argc, const char * argv[]) {

    int a,b;


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

    printf("a-> %i",a);
    printf("b-> %i",b);

    return 0;
}

输出(允许40作为额外参数)

20
    30
    40
    a-> 20b-> 30Program ended with exit code: 0

【问题讨论】:

  • 你要么使用 c++ 开发,要么使用 scanf。
  • 也许你们不熟悉 C++,但这实际上是有效的 C++,即使它也是有效的 C(事实并非如此,除非他有自己的名为 iostream 的头文件)。
  • @BenjaminLindley:好吧,它至少可以是有效的 C++。任何标准标头可以包含其他标准标头,因此 iostream 包括 scanfprintf 的声明是允许的,但不是您通常想要依赖的。
  • @JerryCoffin:非常正确。

标签: c++ c scanf


【解决方案1】:

scanf 为什么需要额外的参数?

这不是一个准确的结论。额外的输入留在输入流中。 scanf 不使用它。它在程序结束时被丢弃。

如果你有另一个scanf 行,

scanf("%d", &c);

40 将被读入c

【讨论】:

    【解决方案2】:

    在第二个 %i 之后,您的格式中有一个空格。 scanf 将读取额外的数据以匹配空间。删除空间,它应该可以按预期工作。

    【讨论】:

    • @JerryCoffin:消耗任意数量的空白是一种可见的效果,至少当输入来自用户输入终端时。
    • @JerryCoffin:不,事实上,这其中一种情况。 没有格式字符串中的空格,scanf 将在找到第二个数字的最后一位之后的第一个空格后立即返回。有了空格,scanf 在找到非空白字符(在本例中为“4”)之前不会返回。这准确地解释了 OP 所看到的行为。
    • @JerryCoffin:当我读到它时,OP 正在输入20&lt;ENTER&gt;30&lt;ENTER&gt;40&lt;ENTER&gt;。如果格式字符串末尾没有空格,scanf 将停在第二个&lt;ENTER&gt;,永远不会给 OP 输入 40 的机会。如果他在同一行输入所有数字,我会看到你的观点。但是,正如他所展示的那样,输出表明并非如此。
    • @BenjaminLindley:重读之后,我想你可能是对的。
    【解决方案3】:

    在与 Benjamin Lindley 的 cmets 讨论之后,我想我最初可能误解了这个问题的意图。

    也许问题不在于您允许输入第三个输入的原因,而在于为什么您需要scanf之前输入第三个输入是满意。

    在那种情况下,我认为@Dale Wilson 的回答基本上是正确的(虽然解释有点短)。

    scanf 格式字符串中的空格意味着 scanf 将跳过 所有 个连续的空格。按键盘上的 enter 键通常被解释为在输入流中输入一个换行符,这被认为是空格。

    由于格式字符串中的尾随空格,他需要输入一些不是空格的字符才能让scanf返回,所以即使他没有需要或希望程序读取第三个参数,他需要输入 something,scanf 可以/将识别为输入中与格式字符串中的尾随空格匹配的空格的结尾。那个“东西”是什么并不重要,除了它不能是空格(空格、换行符、制表符、垂直制表符,可能还有其他取决于语言环境)。


    下面的文字是我最初的回答,但经过讨论和重读,我认为它错过了OP可能打算问的重点,所以虽然它说的是真的,但我怀疑它是否真的有用。

    C 和 C++ 都将标准输入视为基本上是一个文件。他们不能(也不会试图)控制您在标准输入中输入的数据。他们所能做的就是在读取数据后决定如何处理(如果有的话)。

    在这种情况下,您根本没有要求读取该数据,因此它被忽略了。

    程序的标准输入有点像程序是一个人站在繁忙的街道上,周围有数百人。该程序可以听他们说什么,也可以不听——但实际上不能做任何事情来阻止他们所有人说话。同样在这里,程序可以读取或不读取某些输入,但无法阻止您输入它不想要或不关心的额外输入。

    【讨论】:

      【解决方案4】:

      你写scanf的方式是完全错误的,应该避免。

      代替你的scanf:

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

      你应该使用这个:

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

      避免在scanf 中使用空格或除 %datatype 之外的任何其他内容。

      你想要的工作代码:

      #include <iostream>
      using namespace std;
      #include <stdio.h>
      
      int main(int argc, const char *argv[]) {
          int a, b;
      
          scanf("%i%i", &a, &b);
      
          printf("a-> %i", a);
          printf("b-> %i", b);
      
          return 0;
      }
      

      【讨论】:

        【解决方案5】:

        在 C 中,调用者和被调用者必须在调用之前就将多少参数压入堆栈达成一致。

        scanf 也不例外,它采用可变数量的参数,基本上由提供的格式字符串确定。 scanf 扫描格式说明符并期望为每个指定格式对应一个变量的地址。

        在你编写的测试程序中

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

        这意味着从输入缓冲区stdin中,检索两个整数并将它们放在a和b的地址处。但是,没有什么可以阻止您在标准输入中写入更多字符,这些可以通过随后调用 scanf 来读取。

        通常应避免使用scanf 进行键盘输入,而是使用fgets() 来指定输入的最大大小,然后使用sscanf() 从缓冲区中读取数据。

        char buffer[128];
        if (fgets(buffer,sizeof(buffer),stdin) != NULL)
        {
          if (sscanf( buffer, "%i %i", &a, &b) == 2)
          {
            printf( "the numbers are %i and %i\n", a,b );
          }
        }
        

        请注意,您包含 C++ 标头但根本不使用它,您可能希望删除该包含或完全更改代码并改用 cin/cout。

        【讨论】:

          【解决方案6】:

          虽然scanf方便易用,但请注意

          • 不会为您检查输入参数(因此,检查用户的输入参数是您的责任)

          因此,当你在做的时候

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

          scanf 只会“扫描”输入,直到它认为它已经完成。

          因此,您应该像这样检查输入

          if (scanf("%i %i", &a, &b) != 2) {
              /* throw error and exit */
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-13
            • 1970-01-01
            • 1970-01-01
            • 2020-08-20
            • 1970-01-01
            • 2018-08-14
            相关资源
            最近更新 更多