fgets()在空字符串上不返回NULL

时间:2016-10-23 09:53:29

标签: 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 . . . 

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

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

1 个答案:

答案 0 :(得分:3)

您“修复”的问题是相信行尾会被视为输入结束。

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

实际上,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中没有任何内容。
  8. 前六个调用都将返回&buffer[0] - 而不是NULL - 因为从文件中读取时没有遇到错误。即使输入中有两个空行。最后一行比缓冲区长(计算'\n')分为两部分。

    顺便提一下,您的代码正在使用fflush(stdin)。不幸的是,fflush()仅在OUTPUT流或文件上定义了行为。在stdin(或任何输入流)上使用它会给出未定义的行为。如果它实际上丢弃了输入(它与C标准库的某些实现一样),那么你很幸运 - 有真实的编译器,其结果行为不会丢弃输入。