fgets() and Ctrl+D, three times to end?

冷暖自知 提交于 2021-01-27 19:22:34

问题


I don't understand why I need press Ctrl+D for three times to send the EOF.

In addition, if I press Enter then it only took one Ctrl+D to send the EOF.

How Can I make the change so that only took one Ctrl+D then it can detect the EOF?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUF_SIZE 1024

int main(){
    char buffer[BUF_SIZE];
    size_t msgLength = 1;
    char *msg = malloc(sizeof(char) * BUF_SIZE);

    msg[0] = '\0';
    printf("Message: ");
    while (fgets(buffer, BUF_SIZE, stdin)){
        char *old = msg;
        msgLength += strlen(buffer);
        msg = realloc(msg, msgLength);

        strcat(msg, buffer);
    }
    return 0;
}

回答1:


The problem you are having is that terminals don't have EOFs -- they're not files, so "end of file" doesn't really make any sense. Instead, they have EOT (end of transmission -- Ctrl+D), which generally registers as an EOF to stdio due to a (happy?) accident.

Files on UNIX signal EOF by returning a size 0 read, and stdio treats any size 0 read as an EOF regardless of whether it is reading from a file or not. EOT causes a terminal to return immediately, which will be a size 0 read (triggering an EOF in stdio) if and only if the input buffer is empty.

The easiest solution is not to worry about it -- just let the user hit Ctrl+D multiple times if they want to signal an EOF here. It should only require two, unless you have odd timing issues going on.

If you really want to, you can attempt to figure out if an EOT was hit -- if the result of fgets does not fill the buffer and does not end with a newline, then the user hit EOT to transmit it, so you could test for that and break out of the loop. This fails if the user enters exactly enough data to fill the fgets buffer and then hits EOT. It can also fail if the user is "typing" too fast for the program to keep up (an EOT while the program is not actually waiting for input has no effect). I say "typing" since the terminal might be a pseudo-terminal with something faking very fast input on the other end (including EOTs)




回答2:


If you add this line as the first line in your loop, after the fgets, and run the program, perhaps it will be illuminating:

printf("GOT: [%s]\n", buffer);

The first two Ctrl+D are required to end the partial line you have entered, and then the third Ctrl+D, on a so far empty line, closes the input.



来源:https://stackoverflow.com/questions/43001734/fgets-and-ctrld-three-times-to-end

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!