在我写的一个程序中,有一个scanf()
的调用,它读取一个存储金钱的长十进制数字。
do {
fflush(stdin);
printf("What is the number?\n");
} while (scanf("%Lf", &n.amt) == 0);
然而,在调试时,我看到n.amt
等于0.如果我输入100
,为什么它显示它读为零?起初,我使用的是float
,我将其更改为long double
,但此问题仍然存在。
这一点也很明显,因为这些数据后来被写入文件,0也被写入那里。
答案 0 :(得分:1)
代码有几个问题。
首先,正如已经指出的那样,fflush(stdin)是未定义的行为。虽然可以为特定实现记录其输入流的行为(使用glibc,fflush(stdin)刷新未读输入),但这不是可移植行为。
删除fflush()不够。如果scanf()获得类似'%lF'的格式规范,并且在跳过输入流中的任何空格后,下一个字符将无法转换为请求的格式规范(它不是数字,例如,小数点或+/-符号表示'%lF'格式规范)下一个字符实际上仍未读取,如果没有其他格式规范已成功转换,则scanf()将返回0.如果再次循环,未读的字符仍然无法转换,所以最终会出现无限循环。
我从不喜欢使用scanf(),因为处理这种错误情况总是很尴尬。
我更喜欢使用fgets()来将整行输入读入缓冲区,如果你坚持,使用sscanf()来解析它。使用这种方法,错误恢复语义将很容易实现。
答案 1 :(得分:1)
获取数字输入时,防止空字符串([enter])或垃圾输入而不会导致有点棘手使用scanf
时,在空白行上输入。以下内容将该值作为字符串读取,并在没有挂起的情况下防止无输入和垃圾输入。只有在使用strtod
转换为双倍值时才会继续(您可以将strtold
替换为long double):
#include <stdio.h>
#include <stdlib.h>
int main () {
char amount[50] = {0};
char *ep = NULL;
double n_amt = 0.0;
do {
/* protect against [enter] and garbage as input */
while (printf ("\nEnter the amount of money in the transaction: $ ") &&
scanf ("%49[^\n]%*c", amount) == 0 && getchar()) ;
/* convert to double */
n_amt = strtod (amount, &ep);
/* loop if no valid conversion */
} while ( &amount[0] == ep );
printf ("\n n.amt = %lf\n\n", n_amt);
return 0;
}
<强>输出:强>
$ ./bin/scanf_double
Enter the amount of money in the transaction: $
Enter the amount of money in the transaction: $ lsdkfj
Enter the amount of money in the transaction: $ 123.45
n.amt = 123.450000
注意:您最好将钱作为整数值而不是浮点值处理。您最好使用fgets
或getline
来阅读amount
而不是scanf
,但该示例的目的是提供scanf
解决方案。< / p>
使用fgets
等效输入
do {
printf ("\nEnter the amount of money in the transaction: $ ");
fgets (amount, MAXL, stdin);
n_amt = strtod (amount, &ep);
} while ( &amount[0] == ep );