【问题标题】:Where does `getchar()` store the user input?`getchar()` 在哪里存储用户输入?
【发布时间】:2010-11-03 12:13:29
【问题描述】:

我已经开始阅读“The C Programming Language”(K&R),但我对getchar() 函数有疑问。

例如这段代码:

#include <stdio.h>

main()
{
  int c;

  c = getchar();
  putchar(c);
  printf("\n");   
}

键入toomanychars + CTRL+D (EOF) 只打印t。我认为这是意料之中的,因为它是第一个引入的角色。

然后这段代码:

#include <stdio.h>

main()
{
  int c;

  while((c = getchar()) != EOF) 
    putchar(c);
}

键入toomanychars + CTRL+D (EOF) 打印toomanychars

我的问题是,如果我只有一个 char 变量,为什么会发生这种情况?其余的字符存储在哪里?

编辑:

感谢大家的回答,我现在开始明白了……只有一个问题:

第一个程序在给出 CTRL+D 时退出,而第二个程序打印整个字符串,然后等待更多用户输入。为什么它等待另一个字符串而不像第一个那样退出?

【问题讨论】:

  • 您的第二种方法只会循环到 EOF。 CTRL+D (在典型的 unix 系统上)不会导致 EOF,除非你在它自己的一行上点击它。写完字符后按 CTRL+D 不会导致 EOF

标签: c loops io kernighan-and-ritchie


【解决方案1】:

getchar 从标准输入中获取单个字符,在本例中为键盘缓冲区。

在第二个示例中,getchar 函数位于 while 循环中,该循环一直持续到遇到 EOF,因此它将继续循环并检索字符(并将字符打印到屏幕)直到输入变成空的。

getchar 的连续调用将获得来自输入的连续字符。

哦,不要因为问这个问题而感到难过——当我第一次遇到这个问题时我也很困惑。

【讨论】:

  • 它是在遇到while(c = getchar()) 语句后立即开始循环,还是等待按下回车然后循环?从我所见,它只在我们按下回车后才执行while() 循环的主体。我的问题是:getchar() 是否使while() 循环等到enterCTRL+D(在我的系统上)被按下之后才返回while() 循环然后执行主体的其余部分.
【解决方案2】:

它将输入流视为文件。就好像您打开一个包含文本“toomanychars”的文件并一次读取或输出一个字符。

在第一个示例中,在没有 while 循环的情况下,就像您打开一个文件并读取第一个字符,然后将其输出。但是,第二个示例将继续读取字符,直到它收到文件结束信号(在您的情况下为 ctrl+D),就像它从磁盘上的文件中读取一样。


在回复您更新的问题时,您使用的是什么操作系统?我在我的 Windows XP 笔记本电脑上运行它,它运行良好。如果我按 Enter 键,它会打印出我到目前为止的内容,换行,然后继续。 (getchar() 函数在您按下回车之前不会返回,即在调用它时输入缓冲区中没有任何内容)。当我按CTRL+Z(Windows 中的 EOF)时,程序终止。请注意,在 Windows 中,EOF 必须位于其自身的一行中,才能在命令提示符中算作 EOF。我不知道这种行为是否在 Linux 或您可能正在运行的任何系统中被模仿。

【讨论】:

  • @Carson,没错! EOF 必须在它自己的行中。非常感谢!
  • 不客气。我也为此苦苦挣扎,但多亏了 SO :)
【解决方案3】:

这里有些东西被缓冲了。例如putchar 写入的 stdout FILE* 可能是 line.buffered。当程序结束(或遇到换行符)时,这样的 FILE* 将被 fflush()'ed 并且您将看到输出。

在某些情况下,您正在查看的实际终端可能会缓冲输出直到换行,或者直到终端本身被指示刷新它的缓冲区,这可能是当前前台程序退出的情况,因为它想要呈现一个新提示。

现在,这里的实际情况很可能是缓冲的输入(除了输出:-))当您按下按键时,它会出现在您的终端窗口上。但是终端不会将这些字符发送到您的应用程序,它会缓冲它,直到您使用 Ctrl+D 指示它作为输入结束,也可能是换行符。 这是另一个可供玩玩和思考的版本:

int main() {
  int c;
   while((c = getchar()) != EOF) {
     if(c != '\n')
        putchar(c);
   }
    return 0;
}

尝试为您的程序输入一个句子,然后按 Enter。如果您注释掉,请执行相同操作 if(c != '\n') 也许您可以确定您的输入、输出或两者是否以某种方式缓冲。 如果您像这样运行上述内容,这将变得更加有趣: ./mytest | ./mytest

(作为旁注,请注意 CTRD+D 不是字符,也不是 EOF。但在某些系统上,它会导致关闭输入流,这将再次引发 EOF 任何试图从流中读取的人。)

【讨论】:

    【解决方案4】:

    您的第一个程序只读取一个字符,将其打印出来,然后退出。您的第二个程序有一个循环。它一次又一次地读取一个字符并将它们打印出来,直到它读取一个 EOF 字符。在任何给定时间只存储一个字符。

    【讨论】:

      【解决方案5】:

      您只使用变量c 一次包含一个字符。

      使用putchar(c) 显示第一个字符 (t) 后,通过将下一个字符 (o) 分配给变量 c,您会忘记 c 的值,替换前一个字符值 (t)。

      【讨论】:

        【解决方案6】:

        代码在功能上等同于

        main(){
          int c;
          c = getchar();
          while(c != EOF) {
            putchar(c);
            c = getchar();
          }
        }
        

        您可能会发现这个版本更容易理解。将赋值放在条件中的唯一原因是避免输入 'c=getchar()' 两次。

        【讨论】:

          【解决方案7】:

          对于您更新的问题,在第一个示例中,只读取了一个字符。它永远不会到达 EOF。程序终止,因为在完成 printf 指令后它无事可做。它只读取一个字符。打印它。换行。然后终止,因为它无事可做。它不会读取多个字符。

          然而,在第二个代码中,getchar 和 putchar 存在于 while 循环中。在这种情况下,程序继续一个一个地读取字符(因为它是由循环执行的),直到到达 EOF 字符(^D)。此时,它匹配 c!=EOF 并且由于不满足条件,它退出循环。现在没有更多的语句要执行。所以程序在此时终止。

          希望这会有所帮助。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-08-06
            • 2023-03-19
            • 2018-05-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多