问题
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