在C语言中使用fgetc(stdin)时如何正确检测Ctrl-D输入?
问题分析与解决
核心错误原因
你代码的关键问题在于错误地将fgetc的int类型返回值直接赋值给char类型的缓冲区元素,再与EOF比较:
fgetc返回int类型,目的是区分EOF(值为-1,属于int)和所有合法字符(unsigned char范围的0-255,提升为int后是0-255)。- 若直接把这个
int值赋值给char数组元素:- 若系统默认
char是无符号类型,EOF(-1)会被转换为0xFF(255),再提升为int后是255,与EOF(-1)不相等,循环会持续执行,最终导致缓冲区越界,触发I/O错误,ferror返回真,从而打印"error"。 - 即使
char是有符号类型,这种写法也会把EOF这个非字符值写入缓冲区,浪费空间且可能引发后续处理逻辑错误。
- 若系统默认
正确实现方式
应该先将fgetc的返回值存入int变量,判断是否为EOF后,再决定是否存入缓冲区:
#include <stdio.h> #include <stdlib.h> #define INIT_BUF_SIZE 100 int main() { int read_chars = 0; int c; // 用int存储fgetc的返回值,正确区分EOF与合法字符 char *buf = malloc(INIT_BUF_SIZE * sizeof(char)); if (!buf) { perror("malloc failed"); return EXIT_FAILURE; } size_t buf_size = INIT_BUF_SIZE; while ((c = fgetc(stdin)) != EOF) { // 缓冲区扩容逻辑(示例) if (read_chars >= buf_size - 1) { // 留一个位置存字符串终止符 buf_size *= 2; char *new_buf = realloc(buf, buf_size * sizeof(char)); if (!new_buf) { perror("realloc failed"); free(buf); return EXIT_FAILURE; } buf = new_buf; } // 遇到换行符终止读取(示例) if (c == '\n') { break; } buf[read_chars] = (char)c; read_chars++; } // 循环结束后判断终止原因 if (feof(stdin)) { printf("eof\n"); buf[read_chars] = '\0'; // 给缓冲区添加字符串终止符 printf("读取内容: %s\n", buf); } else if (ferror(stdin)) { printf("error\n"); perror("读取失败"); } free(buf); return EXIT_SUCCESS; }
关键要点
- 用
int类型变量存储fgetc的返回值,确保能正确区分EOF和合法字符。 - 仅当返回值不是
EOF时,才将其转换为char存入缓冲区。 - 循环结束后,优先判断
feof(stdin):为真则是正常EOF(比如按下Ctrl-D);ferror(stdin)为真时,才是真正的I/O错误。
内容的提问来源于stack exchange,提问作者Spy
相关产品推荐
相关产品推荐

