这似乎应该是一件简单的事情,但经过几个小时的搜索我什么都没发现......
我有一个从stdin读取输入字符串并清理它的函数。问题是当我点击输入而没有输入任何内容时,它显然只是从输入缓冲区中读取了一些垃圾。
在以下示例中,提示是“输入?”并且在同一行之后发生的所有事情都是我输入的内容。提示后面的行回显了函数读取的内容。
首先,这是我在两次输入内容时会发生的事情。在这种情况下,该功能完全按预期工作。
input? abcd
abcd
input? efgh
efgh
其次,这是我第一次输入内容时会发生什么,但只是第二次输入:
input? abcd
abcd
input?
cd
以下是我两次点击进入时发生的事情:
input?
y
input?
y
每次重新运行时,都会返回'y'或'@'。由于显而易见的原因,'y'特别危险。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#define STRLEN 128
int main() {
char str[STRLEN];
promptString("input?", str);
printf("%s\n", str);
promptString("input?", str);
printf("%s\n", str);
return EXIT_SUCCESS;
}
void promptString(const char* _prompt, char* _writeTo) {
printf("%s ", _prompt);
fgets(_writeTo, STRLEN, stdin);
cleanString(_writeTo);
return;
}
void cleanString(char* _str) {
char temp[STRLEN];
int i = 0;
int j = 0;
while (_str[i] < 32 || _str[i] > 126)
i++;
while (_str[i] > 31 && _str[i] < 127) {
temp[j] = _str[i];
i++;
j++;
}
i = 0;
while (i < j) {
_str[i] = temp[i];
i++;
}
_str[i] = '\0';
return;
}
我尝试了各种方法(甚至是不安全的方法)刷新输入缓冲区(fseek,rewind,fflush)。没有人解决这个问题。
如何检测空输入以便我可以重新提示,而不是这种烦人且有潜在危险的行为?
答案 0 :(得分:4)
这部分cleanString
while (_str[i] < 32 || _str[i] > 126)
i++;
当字符串为空时,跳过\0
。
您应该将_str[i] != '\0'
添加到循环条件中。
要检测空字符串,只需在输入后检查它的长度:
do {
printf("%s ", _prompt);
fgets(_writeTo, STRLEN, stdin);
} while (strlen(_writeTo) < 2);
(与'\n'
比较两个fgets
放入缓冲区的末尾)
答案 1 :(得分:2)
为什么你有一堆带有前导下划线的变量名?那太讨厌了。
无论如何,您必须做的第一件事是检查fgets
的返回值。如果它返回NULL,则表示您没有得到任何输入。 (然后,您可以测试feof
或ferror
,找出您未获得输入的原因。)
继续cleanString
,你有一个while循环,它会消耗一系列不可打印的字符(你可以使用isprint
代替魔术数字),然后是while循环消耗一系列可打印的字符。如果输入字符串不包含一系列非printables,后跟一系列printables,那么您将消耗太多或者不够。为什么不使用单个循环?
while(str[i]) {
if(isprint(str[i]))
temp[j++] = str[i];
++i;
}
这保证在\0
终结符之前消耗整个字符串,并且它不能继续经过终结符,并且它将“好”字符复制到temp。我认为这就是你想要的。
你甚至不需要使用临时缓冲区,你可以从str[i]
复制到str[j]
,因为j
永远不会超过i
你永远不会覆盖你尚未处理的任何东西。