Ctrl-Z 在使用 getchar() [duplicate] 读取输入时行为异常

Ctrl-Z behaving strangely when reading input with getchar() [duplicate]

提问人:Prashant Gupta 提问时间:9/27/2017 最后编辑:chqrliePrashant Gupta 更新时间:9/27/2017 访问量:940

问:

我无法理解它的工作方式。请解释以下输出并说明原因。CtrlZ

#include <stdio.h>

int main (void) {
    int ch, i = 0;

    while ((ch = getchar()) != EOF)
        i++;

    printf("\n%d", i);
    return 0;
}

输入 1:

my  
^Z 

输出 1:

3  

输入 2:

my^Zmy  
my  
^Z  

输出 2:

6  

输入 3:

my^Zmy  
my^Z  
^Z  

输出 3:

6  
C Windows EOF

评论

0赞 jwodder 9/27/2017
你用的是什么操作系统?
0赞 John Bollinger 9/27/2017
...在 Windows 上。在大多数其他操作系统上,^Z 根本没有特别的意义。
2赞 Keith Thompson 9/27/2017
@JohnBollinger:在类Unix系统上,^Z通常会暂停当前进程。
0赞 Jean-François Fabre 9/27/2017
从重复的链接:With Windows, the CTRLz can be entered anywhere on the line, but still needs to be followed by a newline.
1赞 John Bollinger 9/27/2017
当然,你是对的,@KeithThompson。我应该提出一个更狭隘的主张。

答:

1赞 Dúthomhas 9/27/2017 #1

行尾 (EOL) 字符也由 读取和计数,因此它包含在计数中。getchar()

Ctrl-Z 组合键

控制台输入通常(并且在 Windows 上)行缓冲,这意味着在用户按 之前,您的程序不会看到任何内容。Enter

因此,您可以在任何地方键入,但在您按下之前,文本不会发送到程序的输入缓冲区进行读取。^ZEnter

操作系统问题

在 Linux(和其他 *nixen)上,EOL 字符是 LF ()。 但在 Windows 上,它是一个字符序列:CR LF ()。'\n'"\r\n"

为了使相同的代码在 *nix 和 Windows 上都有效,当 C 打开控制台文件流时,它会在文本模式下进行,该模式在其他方面与二进制模式相同,只是 CR LF 仅作为 LF 报告给您。因此,上面的实验报告了三个字符('m'、'y' 和 '\n'),而不是四个。

2赞 Jean-François Fabre 9/27/2017 #2

“为什么它没有在第一个停止,在为什么 getchar() 在控制台上不将 return 识别为 EOF?CTRL-z

在 Windows 中,可以在行上的任何位置输入 ,但仍然需要后跟换行符。CTRLz

这说明了情况 1 ( + 换行符) => 3 个字符my

对于其他输入,很明显,停止输入的是最后一个,后跟换行符。似乎不是唯一的一行,直到行尾才删除它后面的字符,这将解释这两种情况下的结果。CTRLzCTRLz6

0赞 Michael Burr 9/27/2017 #3

在 Windows 命令行上,默认行为为:

  • ^Z 仅在行首时表现为 EOF
  • 如果 ^Z 位于行中的其他位置,则 ^Z 后面的字符将从流中删除(包括导致缓冲区发送到应用程序的换行符),但不会引发 EOF 条件。但是,^Z 字符本身仍由流返回。

此外,控制台不会立即对 ^Z 字符执行操作 - 该行仍处于缓冲状态,并且在按下返回键之前不会发送到应用程序。

请记住,您的程序会计算换行符,因此:

  • 在示例 1 中,有一个换行符是结果的一部分3
  • 在示例 2 中,计算第一个 ^Z,不计算第一行的后半部分,并且计算(仅)第二行的换行符
  • 在示例 3 中,计算前两个 ^Z 字符,不计算换行符,不计算第一行的后半部分

在 Unix 系统上,^D 被用作控制台上的 EOF 字符,它的行为是标准化的(与 Windows 的行为略有不同):

[EOF是]输入上的特殊字符,如果 ICANON 标志已设置。接收到时,所有等待读取的字节 立即传递到进程,无需等待换行符, 并且 EOF 被丢弃。因此,如果没有字节等待( 是,EOF 发生在一行的开头),字节计数为零 应从 read() 返回,表示文件结束 指示。

主要区别在于,在 Unix 上,EOF 键不会等待按下回车键。另一个区别是,在 Windows 上,如果 EOF 不在行的开头,则 ^Z 字符将显示在流中。