出于代码安全原因,我最近尝试使用 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)
事件。代码现在如上所示。
最佳答案
您“解决”的问题是认为行尾应被视为输入结束。
NULL
是 fgets()
的一个指示,它在从文件(或流)读取时遇到错误或输入结束。空行既不是错误也不是输入结束的标记。人类(在键盘上打字)可能会选择将换行符解释为输入结束,但计算机程序不会 - 毕竟,没有什么能阻止用户输入多行输入。
实际上,fgets()
读取一行并用 '\n'
字符指示该行的结尾。比方说,我们有一个文件包含
ABC
DE
FGHIJ
(空行穿插在三行文本中,后跟文件末尾)。
我们还让 buffer
是一个包含五个 char
的数组,并且我们使用 fgets(buffer, 5, file )
。
那么 fgets(buffer, 5, file)
在每次调用时会做什么。好吧,1 代表第一次调用,2 代表第二次调用,依此类推,我们将看到结果
"ABC\n"
存入buffer
;"\n"
存入buffer
; (第一个空行)"DE\n"
存入buffer
;"\n"
存入buffer
; (第二个空行)"FGHI"
存入buffer
;"J\n"
存入buffer
;和fgets()
返回NULL
,并且没有任何内容存储到buffer
中。
前六个调用将全部返回 &buffer[0]
- 而不是 NULL
- 因为从文件读取时没有遇到错误。即使输入中有两个空行。比缓冲区长的最后一行(包括 '\n'
在内)分两部分读取。
顺便说一下,您的代码正在使用 fflush(stdin)
。不幸的是,fflush()
仅在 OUTPUT 流或文件上定义了行为。在 stdin
(或任何输入流)上使用它会产生未定义的行为。如果它实际上是在丢弃输入(它对 C 标准库的某些实现所做的),那么您很幸运 - 现实世界中的编译器的结果行为不会丢弃输入。
关于c++ - fgets() 不会在空字符串上返回 NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40201620/