在输入无效的情况下保护程序的问题与编程一样古老,在此站点上我发现了很多有关该问题的问题,但是对于我来说,没有任何帮助。
我有一个函数,可将值加载到浮点二维数组中。
void load_val(
float matrix[MAX_SIZE][MAX_SIZE],
const int line_num,
const int column_num
)
{
for (int i=0; i<line_num; ++i)
{
printf("Give number\n");
for (int j=0; j<column_num; ++j)
{
scanf("%f", &matrix[i][j]);
}
}
}
很明显,当用户输入字母时,程序进入无限循环。
对于该问题,我使用了两种解决方案,但均无效果。
第一个是利用scanf
在输入无效的情况下返回0的事实。
所以不是
scanf("%f", &matrix[i][j]);
我写了
while (scanf("%f", &matrix[i][j])==1);
但这仍然给了我无限循环。
另一种解决方案是仅使用"isdigit"
函数。
int h = scanf("%f", &matrix[i][j]);
if (isdigit(h)==0)
{
puts("INVALID");
j--;
}
但是我真的不想使用其他库,它也不起作用。 问题似乎是,在我什至无法检查输入是否有效之前,该程序就因输入而变得疯狂。
我什至尝试过
float h;
if (scanf("%f", &h)==1)
{
matrix[i][j]=h;
}
else
{
puts("INVALID");
j--;
};
仍然-无限循环。
在程序变得疯狂之前,如何检查此loop-inside-a-loop
中的无效输入?浮点类型可能有问题吗?
答案 0 :(得分:3)
问题在于,当您提供无效的输入时,scanf
不会将其从输入缓冲区中删除。每次您在循环中调用scanf
时,它将一次又一次地读取相同的输入。
因此,通常建议您使用fgets
读取整行,然后使用sscanf
来解析该行。
检查scanf
(或sscanf
)returns 是什么是检查其成功与否的正确方法。
答案 1 :(得分:2)
对于除n以外的每个转换说明符,最长的输入字符序列不超过任何指定的字段宽度,而该长度恰好是转换说明符所期望的或者是它所期望的序列的前缀,是从流。 此消费序列后的第一个字符(如果有)仍未读取。如果消费序列的长度为零或无法按上述指定转换消费序列,则除非文件结尾,否则匹配失败,编码错误或读取错误阻止了来自流的输入,在这种情况下,这是输入失败。
因此,如果scanf()
无法使用所有(或任何)字符,它们将保留在输入流中,而下一个scanf()
将以第一个字符失败的方式失败,依此类推。
为防止这种情况的发生,您可以从输入流中读取和丢弃字符,直到遇到换行符为止。
float value;
if(scanf("%f", value) != 1) {
int ch;
while((ch = getchar()) != EOF && ch != '\n');
}
答案 2 :(得分:1)
如果scanf
遇到与输入格式不匹配的字节,则这些字节将仅留在输入流中。重复呼叫scanf
只会停留在相同的无效字符处。如果要处理无效输入,最好将所有可用输入读入缓冲区(例如使用fgets
),然后在缓冲区上使用sscanf
(可能在循环中),以便可以前进缓冲区指针过去的无效输入。参见https://stackoverflow.com/a/5969401/982257