c++ - fgets() 不会在空字符串上返回 NULL

标签 c++ c string null fgets

出于代码安全原因,我最近尝试使用 fgets() 而不是 scanf() 来读取字符串。我使用了在这里找到的一个简单函数来检查错误(无输入和输入太长)。问题是每当我在没有实际写任何东西的情况下按下“ENTER”时,fgets() 不会返回 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] = '\0';
        //[-] fflush(stdin);
        return OK;
    }
}

这是输出:

Enter string:
This is your input: ""

Press any key to continue . . . 

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


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

最佳答案

您“解决”的问题是认为行尾应被视为输入结束。

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() 返回 NULL,并且没有任何内容存储到 buffer 中。

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

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

关于c++ - fgets() 不会在空字符串上返回 NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40201620/

相关文章:

java - 我想将 java 中的 .txt 文件中的多个字符串解析为变量。最简单的方法是什么?

php - laravel 检索请求输入返回 null

c++ - 创建一个 N 维数组,其中 N 在运行时确定 (C++)

c++ - 如何在 QMainWindow 的默认布局中排列项目?

c - 为什么c语言编码会出现运行时错误?

c - 方法执行时 QEMU 崩溃

c - 如何使用 ghostscript 将 pdf 文件中的行读入 c 程序?

c++ - emplace_back 不适用于 std::vector<std::map<int, int>>

c++ - IAR 6.50 在项目构建时显示多个错误

Java - split(regex, limit) 方法实际上是如何工作的?