fgets() 在空字符串上不 return NULL

fgets() does not return NULL on empty string

出于代码安全原因,我最近尝试使用 fgets() 而不是 scanf() 来读取字符串。我使用了在这里找到的一个简单函数来检查错误(无输入和输入太长)。问题是每当我按下 "ENTER" 而实际上没有写任何东西时, fgets() 不会 return NULL 并且我的程序无法显示 NO_INPUT 错误.

这是main.cpp

#include <stdlib.h>
#include <stdio.h>

#include "utilities.h"

int main() {
    int rc;
    char str[20];

    rc = getLine("Enter string: ", str, sizeof(str));
    if(rc == NO_INPUT) {
        printf("[ERROR] No input\n\n");
    } else if(rc == TOO_LONG) {
        printf("[ERROR] Input is too long\n\n");
    } else {
        printf("This is your input: \"%s\"\n\n", str);
    }

    system("pause");
}

这是utilities.h

#include <stdio.h>
#include <string.h>

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2

int getLine(const char *msg, char *buff, size_t len) {  
    if(msg != NULL) {
        printf("%s", msg);
        fflush(stdout);
    }

    if(fgets(buff, len, stdin) == NULL /*[+]*/ || strcmp(buff, "\n") == 0) {
        //[-] fflush(stdin);
        return NO_INPUT;
    } else if(buff[strlen(buff)-1] != '\n') {
        //[-] fflush(stdin);
        return TOO_LONG;
    } else {
        buff[strlen(buff)-1] = '[=12=]';
        //[-] fflush(stdin);
        return OK;
    }
}

这是输出:

输入字符串:
这是您的输入:“”

按任意键继续 。 . . 

我通过将 utilities.h 中的第一个 if 语句替换为 if(fgets(buff, len, stdin) == NULL || strcmp(buff, "\n") == 0) 解决了我的问题。这样做,我的程序将检查输入错误或空字符串和 return NO_INPUT 标志。


感谢所有发表评论的人和@Peter 的回答。我在 utilities.h 中添加了上述 if 语句,并删除了每个 fflush(stdin) 事件。代码现在如上所示。

您 "fixed" 的问题是认为行尾应该被视为输入结束。

NULLfgets() 的指示,它在从文件(或流)读取时遇到错误或输入结束。空行既不是错误也不是输入结束的标记。人类(在键盘上打字)可能会选择将换行符解释为输入结束,但计算机程序不会 - 毕竟,没有什么能阻止用户输入多行输入。

实际上,fgets() 读取一行并用 '\n' 字符指示该行的结尾。比方说,我们有一个包含

的文件
ABC

DE

FGHIJ

(空行穿插在三行文本中,后面是文件末尾)。

我们还假设 buffer 是一个包含五个 char 的数组,并且我们使用 fgets(buffer, 5, file).

形式的连续语句读取该文件

那么 fgets(buffer, 5, file) 每次调用会做什么。好吧,1 代表第一次调用,2 代表第二次调用,依此类推,我们将看到

的结果
  1. "ABC\n"存入buffer;
  2. "\n"存入buffer; (第一个空行)
  3. "DE\n"存入buffer;
  4. "\n"存入buffer; (第二个空行)
  5. "FGHI"存入buffer;
  6. "J\n"存入buffer;和
  7. fgets() returns NULL,没有任何内容存储到 buffer.

前六个调用将全部 return &buffer[0] - 而不是 NULL - 因为从文件读取时没有遇到错误。即使输入中有两个空行。比缓冲区长的最后一行(已计算 '\n')分两部分读取。

顺便说一下,您的代码正在使用 fflush(stdin)。不幸的是,fflush() 只在 OUTPUT 流或文件上定义了行为。在 stdin (或任何输入流)上使用它会产生未定义的行为。如果它实际上是在丢弃输入(它对 C 标准库的某些实现所做的),那么您很幸运——在现实世界的编译器中,结果行为不会丢弃输入。