【问题标题】:Strange behaviour of getchar, is this implementation-defined behaviour?getchar 的奇怪行为,这是实现定义的行为吗?
【发布时间】:2021-04-05 23:51:05
【问题描述】:

我正在尝试打印一个整数平方表。目的是编写一个程序,在每 24 个方格后暂停,并要求用户打印 Enter 以继续。这并不太复杂,我已经用 C 语言“完成”了手头的任务。

我的担忧:当我编译和运行以下代码时,会出现一个看似无关紧要(但可以观察到)的小问题:

    #include <stdio.h>

    int main()
    {
      int i, n;

      printf("This Program prints a table of squares. \n");
      printf("Enter number of entries in table: ");
      scanf("%d", &n);

      for(i = 1; i <= n; i++) {
        if((i - 1) % 24 == 0 && i > 1) {
          printf("Press Enter to continue...");
            while(getchar() != '\n')
             ;   
        }   
        printf("%10d%10d\n", i, i*i);
      }

    }

我的输出是完美的,正是我想要的,除了对于 24 的第一个倍数(即 24)。出于某种原因,如果我选择一个大的 n,表格将完美打印出来,但只需要我从 48 开始按 Enter,第一个 printf 输出很奇怪,它不需要用户按任何键(更不用说 Enter )。它看起来像这样:

            24       576
    Press Enter to coninue...        25       625
            26       676

但是下次代码使用 printf 时,一切似乎都很完美,我需要按 Enter 继续,因为它应该是.. (代码后面的健康输出示例以及所有后续 24 的倍数)。

            48      2304
    Press Enter to coninue...
            49      2401

纠正这个问题的一件事是,如果我在 for 循环中的 printf 和 while 之间放置了一个额外的 getchar() 函数。所以代码完全一样,除了 for 循环现在看起来像这样:

for(i = 1; i <= n; i++) {
    if((i - 1) % 24 == 0 && i > 1) {
      printf("Press Enter to continue...");
      getchar();
        while(getchar() != '\n')
         ;   
    }   
    printf("%10d%10d\n", i, i*i);
  }

在这种情况下,代码可以完美运行。除了从 48 开始我需要按两次 Enter 键。大概这是因为我已经设置了额外的 getchar() 但是为什么我只需要在 i = 24 时按一次 Enter 呢?

我的猜测是这与(i - 1) % 24 参数有关,但我看不出问题出在哪里。这是 KNK C Programming A Modern Approach 第 7 章中的一个问题。我是一名自学成才的程序员。我希望我的问题易于理解,并且它阐明了关于 C 的一些重要内容。这可以被视为实现定义的行为吗?也许在另一台机器上我所描述的不会发生?如果不是,为什么不呢?

【问题讨论】:

  • scanf()(当您键入 "48&lt;ENTER&gt;" 时)将输入留在输入缓冲区中。第一个getchar() 处理待处理 &lt;ENTER&gt;。更喜欢将 fgets() 专门用于 ALL 用户输入(包括文本文件)
  • 这能回答你的问题吗? scanf() leaves the new line char in the buffer
  • 你为什么要使用scanf?像这样的参数应该来自argv
  • 我明白了,被告知 scanf 将输入留在输入缓冲区中是一个键。此外,我只想补充一点,我没有使用过fgets()argv,因为书中还没有提到它们。感谢您解决此问题。
  • @tommie997 scanf() 不会因为函数而离开'n',而是因为"%d" 格式在找到最后一个数字文本字符后停止读取。如果您输入 "48&lt;space&gt;&lt;blah&gt;" 将保留在 stdin

标签: c


【解决方案1】:

在调用scanf 之后,输入缓冲区中剩下一个换行符。这个换行符在第一次调用 getchar 时被拾取,导致它跳出 @9​​87654323@ 循环。

您想在scanf 调用之后通过循环getchar 来使用换行符,直到获得换行符为止。

scanf("%d", &n);
while (getchar() != '\n');

【讨论】:

  • 这是有道理的。我可以在scanf 之后和for 循环之前添加一个初步的getchar() 吗?
  • @tommie997 这正是上面的代码所做的。
  • 它并没有做更多的事情,因为它允许用户输入任何内容,直到他们按下 Enter。与仅放置 getchar()(没有 while 循环)相反,它只会在调用 scanf 后删除输入缓冲区中的一个不必要的换行符?
  • @tommie997 是的,如果有的话,它会消耗用户在数字后面输入的任何额外字符。
  • while (getchar() != '\n'); 在无限循环中,由于文件结束,getchar() 返回 EOF
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-20
  • 2019-06-24
  • 1970-01-01
  • 2014-10-06
相关资源
最近更新 更多