在 C 语言中 getchar() 中使用 EOF (Ctrl + D)

The use of EOF (Ctrl + D) in getchar() in C

提问人:Hiểu Nam 提问时间:7/26/2023 最后编辑:ptsHiểu Nam 更新时间:7/26/2023 访问量:73

问:

我正在阅读K&R中的第1.9节,我不明白在下面实现的代码中使用EOF

#include <stdio.h>
#define MAXLINE 1000            /* maximum input line length */

int mymygetline(char line[], int maxline);
void copy(char to[], char from[]);

/* print the longest input line */
int main()
{
    int len;                      /* current line length */
    int max;                      /* maximum length seen so far */
    char line[MAXLINE];           /* current input line */
    char longest[MAXLINE];        /* longest line saved here */
    max = 0;

    while ((len = mymygetline(line, MAXLINE)) > 0) {
        if (len > max) {
            max = len;
            copy(longest, line);
        }
    }
    if (max > 0)                  /* there was a line */
        printf("%s", longest);
    return 0;
}

/* mymygetline: read a line into s, return length */
int mymygetline(char s[], int lim)
{
    int c, i;
    for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
        s[i] = c;
    if (c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
    int i;
    i = 0;
    while ((to[i] = from[i]) != '\0')
        ++i;
}

我试过什么:

  • 初始程序运行良好,输入标记带有“\n”的差异行很容易理解
  • 当我第一次尝试以内联方式输入 EOF 时,它只是结束最近的输入流并将 getchar() 设置为输入流的等待模式。

问题:

  • 当我两次内联输入 EOF 时,第一个 EOF 是否只是像“\n”或其他机制一样,或者我只是在这里遗漏了一些东西。
C eof getchar

评论

2赞 jps 7/26/2023
在深入研究高级主题之前,请优先学习如何使用缩进和空行来格式化代码以直观地构建代码。这不仅是一个美观的问题,而且可以帮助你自己和你的代码的读者更快地理解它,也有助于避免错误。
1赞 David C. Rankin 7/26/2023
此外,使用 Ctrl + d 假定您使用的是 Linux,如果不是这种情况,请指定您正在使用的操作系统和编译器。在 Linux 上,Ctrl + d 在输入缓冲区中生成手册。由于您的读取循环作为 test-clause 进行检查,因此循环将在第一次遇到 时退出(无论是手动生成还是当它用尽 中的字符时)。所以你运行你的程序,例如 然后按 Ctrl + D,程序应立即退出。EOF(c = getchar ()) != EOF && c != '\n'EOFstdin./myprog
1赞 Armali 7/26/2023
@Hiểu Nam – 从某种意义上说,不仅第一个,而且每个 EOF 都像一个“\n”(假设 EOF 指的是按下的组合键,而不是宏)——它会导致缓冲输入从操作系统移交给程序。紧随其后的类型化 EOF 只会导致移交空输入,库会将其解释为输入的结束。
1赞 David C. Rankin 7/26/2023
唯一需要第二个ctrl + d的情况是,如果您在按ctrl + d之前不小心输入了另一个字符,例如。然后被看到并返回一个值,因此再次调用它。现在,当您在空行上按ctrl + d时,它会立即返回。例如,如果您键入(其中是生成字符的 Enter 键),则在按下 ctrl + d 时将立即退出。"dog[ctrl + d]"EOFmymygetline()> 0"dog[Enter][ctrl + d]"[Enter]'\n'
1赞 David C. Rankin 7/26/2023
底线是 -- 如果按 ctrl + d 时该行不为空,则返回一个大于零的值并再次调用。要求您再次输入 Ctrl + Dmymygetline()

答:

1赞 pts 7/26/2023 #1

以下是按键传播到代码 (mymygetline()) 函数的方式:

  • 用户按下该键。
  • 键盘接收按键,并向类 Unix 操作系统发送某种包含键码的事件。
  • 操作系统确定应将事件路由到终端(这包括 GUI 上的终端仿真器窗口)。操作系统将事件转换为字节序列,并将其发送到终端。
  • 终端可能会进行更多的转换和缓冲。默认情况下,它会缓冲(即不让通过)字节,直到收到换行符或特殊内容(例如对应于 Ctrl-D 的字符)。
  • 程序中的 libc 代码(由 getchar(3) 调用)从终端读取一系列字节。当终端处于缓冲状态时, libc 代码会阻塞 read(2) 系统调用。一旦终端刷新,read(2) 就会同时接收到许多字节,通常是整行后跟换行符,或者是 EOF 指示符(read(2) 返回 0)。
  • 您的代码 (mymygetline()) 从 getchar(3) 接收 read(2) 读取的字节,一次一个字节。一旦没有更多的字节可用,libc 代码就会再次调用 read(2),它会阻塞,直到有更多的字节出现。

如果用户按下 Ctrl-D,read(2) 返回到目前为止缓冲的字节数(如果有的话),后续的 read(2)(由第二个 Ctrl-D 触发)返回 0,这会导致 getchar(3) 返回 EOF。