了解scanf行为

时间:2017-05-31 16:01:33

标签: c loops

我是C编程的新手。我的先生给了这个代码来找到最多n个数字。当我这样做时,事情是完美的,即在行上写一个数字 - 输入数字的数字,并在输入数字时输入数字,如7 8 9 10。

#include <stdio.h>
main()
{
    int n, max, number, i;
    printf("Type the number of numbers");
    scanf("%d", &n);
    if(n>0)
    {
        printf("Type the numbers");
        scanf("%d",&number);
        max=number;
        for(i=1; i<n; i++)
        {
            scanf("%d", &number);
            if(number>max)
                max=number;
        }
        printf("MAX=%d \n", max);
    }
}

但如果我写下假设 - 5 8 9 10 7 6 - 那么程序就会理解它 - 它输入n = 5然后输入数字= 8然后循环执行数字更改为9然后数字更改为10到6然后gves max。

那么 scanf 如何在这里工作?虽然它们是用空格连续写成的,但它是单独的数字?

6 个答案:

答案 0 :(得分:1)

"%d"原因中的scanf("%d",&number);有3个阶段将用户文字输入扫描到int

  1. 0个或更多领先的白色空格,如' ''\n''\t'以及其他一些空格,会被阅读并弃置。

  2. 读取"123""-123""+123"等数字文本,直到读取非数字字符为止。 (或文件结束或罕见的输入错误)。

  3. 将非数字字符放回stdin进行后续输入调用。

  4. 如果步骤2成功读取至少1位数,则该函数返回1.良好代码检查返回值。

    if (scanf("%d",&number) != 1) Handle_UnexpectedInput();
    

    重要的是,'\n'对于scanf("%d",&number);并不是那么特别。它就像一个分隔符,就像另一个空格或非数字文本。

    '\n'会导致缓冲的stdin接受用户输入的,以便通过各种scanf()来电进行处理。

答案 1 :(得分:1)

这里是关于scanf如何从用户角度运作的简化说明(不过分简化,我希望):

论证分为两部分:

  1. 第一部分是“格式字符串”。该字符串至少由 一种格式说明符。最简单的形式是说明符开头 %后跟一个指定类型的字母 你期望的变量(“%d” - 我期待一个整数)。该 指定符的数量必须匹配参数和类型的数量 在第二部分。

  2. 第二部分由位置存储器的一个或多个地址组成 您输入的数据将被存储在哪里。指向类型必须 匹配说明符。

  3. 调用时,函数将重复以下步骤,从第一个说明符和第一个指针开始,直到检测到格式字符串结束:

    1. 读取并丢弃任何空格,直到找到非空白字符(空格:空格,制表符,NL,至少);
    2. 读取第一个空白字符或与当前说明符的预期输入不匹配的字符;
    3. 将它们转换为当前说明符的类型和
    4. 将结果存储在当前指针指向的位置。
    5. 有三种典型的初学者错误会导致未定义的行为(崩溃,最有可能):

      1. 您忘记了地址操作符&
      2. 说明符和类型不匹配。
      3. 说明符的数量与指针的数量不匹配。
      4.   int d;
          scanf( "%d", d ); // no &
          scanf_s( "%s", &d ); // s do not match int
          scanf_s( "%d%d", &d ); // too many specifiers
        

答案 2 :(得分:1)

From the horse's mouth

7.21.6.2 fscanf功能
...作为转换规范的指令定义了一组匹配的输入序列,如 下面针对每个说明符进行描述。转换规范在。中执行 以下步骤:

8跳过输入的空白​​字符(由 isspace 函数指定),除非 规范包括 [ c n 说明符。 284)

9除非规范包含 n 说明符,否则将从流中读取输入项。一个 输入项被定义为输入字符的最长序列,不超过 任何指定的字段宽度,它是匹配输入序列的前缀,或者是匹配输入序列的前缀。 285) 输入项目之后的第一个字符(如果有)仍未读取。如果输入的长度 item为零,指令的执行失败;这种情况是匹配失败,除非 文件结束,编码错误或读取错误阻止了流的输入,其中 这是输入故障。

10除说明符的情况外,输入项目(或者,在%n 指令的情况下, 输入字符数)转换为适合转换说明符的类型。如果 输入项不是匹配的序列,指令的执行失败:这 条件是匹配失败。除非通过 * 指示分配抑制,否则 转换结果放在下面第一个参数指向的对象中 尚未收到转换结果的format参数。如果是这个对象 没有合适的类型,或者无法表示转换结果 在对象中,行为未定义 ...
12转换说明符及其含义如下:

d 匹配可选的带符号十进制整数,其格式与
相同 期望 strtol 函数的主题序列,值为10 对于
基本论点。相应的参数应该是指向 有符号整数 ... 284)这些空白字符不计入指定的字段宽度。

285) fscanf 将最多一个输入字符推回到输入流上。因此,有些序列 强制 strtol 等可接受的 fscanf 是不可接受的。

scanf的处理完全相同;唯一的区别是scanf始终从标准输入读取。

示例:

假设您键入 Space Space Space 1 2 3 输入以响应第一个提示;然后输入流包含序列{' ', ' ', ' ', '1', '2', '3', '\n'}。当您致电scanf( "%d", &n );时,scanf会读取并丢弃前导空格,然后读取并匹配序列{'1', '2', '3'},将其转换为整数值123,并指定结果到n。由于转换和分配成功,scanf返回1.

如果输入流包含序列{' ', ' ', ' ', '1', '2', '.', '3', '\n'}scanf读取并丢弃前导空格,则读取并匹配序列{'1', '2'},将其转换为整数值{{1} },并将结果分配给12。输入流仍将包含n。由于转换和分配成功,{'.', '3', '\n'}将返回1.

如果输入流包含序列scanf,则没有匹配的字符序列({'.', '3', '\n'}不是十进制整数中的有效字符)。 '.'scanf保持未读状态,并保持.的值不变。由于转换和分配没有成功,n返回0表示匹配失败

如果在读取任何匹配字符之前在输入流上发出文件结尾信号,或者如果还有其他输入错误,scanf不会将任何新值分配给scanf,返回n以指示输入失败

答案 3 :(得分:0)

按键盘时,您将在计算机上填充缓冲区。 scanf将读取连续数据的数量,直到它命中一个空格,所以“1234 43”,在代码scanf(“%d”)上你说“读一个号”,1234是一个号码,就是它的内容。

但是如果你有一个循环再次执行scanf,那么数字“43”当前在读取缓冲区中,而scanf将不停地读取它。

scanf的手册没有解释这一点,对于新手来说理解为什么应用程序没有停在那里读取新号码有点令人困惑。

答案 4 :(得分:0)

让我尽可能简单地解释......

scanf从标准输入流stdin读取字节。

假设你提供的输入是"23 67 21 99\n" (\ n是从你按Enter键时开始的)

然后对scanf的每次下一次调用都将从这个输入缓冲区开始读取,它将解释所看到的内容("%d"等),而将输入分隔为空字符。这可以是新行,空格,制表符等。

虽然仍有字节需要读取,但scanf等待您输入。这就是这里发生的事情。

答案 5 :(得分:0)

让我们保持简单。我假设你对缓冲区或stdin一无所知。 scanf用于从用户获取输入。无论何时键入数字并按键盘上的“空格”或“输入”,该数字都会输入程序以进一步显示。当您输入 scanf(“%d”,&amp; n); 时,表示从用户处输入整数,并在地址上存储 变量n