【问题标题】:confusing with buffer and EOF and getchar与缓冲区、EOF 和 getchar 混淆
【发布时间】:2015-03-13 22:37:34
【问题描述】:

我用 getchar()putchar()'\n' 和 EOF(在 Visual Studio 中)测试了很多情况,以更好地了解缓冲和 getchar 的工作原理。

如果我的代码

int c;
printf("Enter character\n");
/* 1 - number for explaining steps */
c = getchar();
putchar(c);

/* 2 */
c = getchar();
putchar(c);

printf("hi");

在这段代码中,如果我输入字符 a 并按 Enter,它将显示

 a
 hi

这意味着当我按下输入时,'\n' 也将保存在缓冲区中,然后缓冲区中的第一项(a)转到第一个c=getchar() 并打印a;然后缓冲区中的第二项 (\n) 转到第二项 c=getchar() 并打印新行。

我的结论是 '\n' 保存在缓冲区中,这不是命令在按 Enter 时能够转到新行的结果,因为我为此测试了另一个代码:

while ((c = getchar()) != '\n')
    putchar(c);
printf("hi");

在这段代码中,当我输入a 并按回车键时,它会打印ahi,而新行不打印,这意味着当a 传递给getchar() 时,putchar() 会打印它然后当getchar()获取'\n',循环终止,循环内的putchar() 不打印新行,因此该命令不是新行的原因。

现在我想测试另一个代码:

  int c;
  while ((c = getchar()) != EOF)
    putchar(c);
  printf("hi");
  return 0;

如果我通过它abc 和 EOF 的信号(在我的系统中 ^Z (Ctrl+Z)),它将显示abc->。如果我们像前面的代码一样看它: abc-1(or every thing else shows eof)'\n' 应该已保存在缓冲区中,首先 a 转到第一个 getchar (第一次循环有效) b 传递给第二个 getchar 然后 c 传递到第三个 - 然后 -1应该有已传递给c=getchar() 它违反了条件,循环应该终止。

但是,它会打印 -> 并继续循环,并且不会打印新行(缓冲区中的最后一项)。 相反,当我只是ctr +zc=getchar() 从缓冲区读取EOF 符号时,循环终止并打印了新行,那么为什么它打印新行? 它读取 EOF,它不应该读取缓冲区中的任何其他内容 在这种情况下。

【问题讨论】:

  • 最后一段几乎完全是一个句子/问题;可以重新格式化一下吗?
  • 在以后的问题中,以及一般地传递​​代码,您可以将步骤#1 之类的内容放在代码 cmets 中。当您谈论第 1 步时,程序员会知道查看 cmets,它可以防止我们的内部 C 编译器在我们阅读您的代码时发出嘶嘶声。
  • 最后一个例子,c处理完后,下一个字符是'-'而不是'-1'。您确定 '>" 不是您在终端中的提示符吗?
  • 请注意,第一个循环示例仅测试换行符,如果您在按 Enter 之前键入两次 Control-Z 将会遇到问题。对于出现的->,我没有很好的解释。这可能是终端驱动程序所做的事情,尽管这不太可能。我没有运行测试的 Windows 系统。

标签: c buffer eof getchar


【解决方案1】:

您对输入如何首先读取a 然后是第一个示例中的换行符的概述基本上是正确的。就getchar() 而言,换行符是一个完全正常的字符;确实,没有异常字符。 getchar() 可以返回任何适合 char 的 8 位值,以及一个称为 EOF 的附加值。这就是为什么它的返回值必须存储在int 中,正如您所做的那样。

当底层 read() 系统调用返回 0 个字节可供读取或出现错误时,标准 I/O 函数返回 EOF。

当您在 Windows 上键入 abcControl-Z(在 Unix 上键入 Control-D),然后:

  1. 终端驱动程序使当前在其缓冲区 (abc) 中的字符可用于read() 系统调用。
  2. read() 系统调用使用这些字符填充标准 I/O 缓冲区。
  3. 连续的getchar() 调用返回abc
  4. 下一个getchar() 等待更多输入。

这不是 EOF;它只是将行上的字符刷新到程序中。要获得 EOF 的效果,您必须在 abc 之后连续键入两次 Control-Z。第一个将刷新abc;第二个将生成一个 0 字节的 read(),表示 EOF。

当按下换行符 (Enter) 时,终端驱动程序也会使输入可用。如果在输入 Enter 后立即输入 Control-Z,则所有待输入的零字符都从终端发送到程序,因此 read() 返回 0,因此标准 I/O 包报告EOF。

请注意,在您按下回车键或 EOF 指示之前,您可以使用退格键和其他编辑选项编辑行中的数据,包括删除所有数据。一旦您按下回车键或 EOF 指示,您将无法再编辑提供给 read() 的数据。

类似的行为发生在 Unix 上;您键入 EOF 指示两次以终止输入中线;一次在行首终止输入。

Stack Overflow 上有很多相关的问题,包括这些:

【讨论】:

  • 另一个很好的答案!
  • 不错的答案。但是我问的是我们应该在 ^c 之后按 Enter 键并第一次按的窗口不会刷新我在 linux 中测试的缓冲区,它的工作原理很明显,但在 windows 中我没有不知道它为什么打印 ('->') 以及为什么它不打印新行,以及为什么如果我按下 ^c 按下没有任何其他字符的情况下它会在终止循环后打印新行我不希望读取缓冲区的其余部分。
  • 我无法编辑最后的评论更改 ^c 与 ^z 抱歉。我应该提到它在输入'abc ^ z'时打印'->'按回车。
  • 仅供参考:如果我发现我在评论中犯了错误但它不再可编辑,并且如果还没有回复,那么我将复制评论并添加一个新的,经过编辑的版本,然后删除旧版本。如果删除评论会扰乱其他 cmets 的流程,我会忍受拼写错误。
猜你喜欢
  • 1970-01-01
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多