我是C的初学者,我遇到了一些我无法弄清楚的问题,并且无法在其他线程上找到解决方案。
我正在尝试使用以下代码从键盘输入/ txt文件中读取整数:
int grades[MAX_GRADES_LENGTH]={0}, histogram[HISTOGRAM_SIZE]={0}; int maxGradesHistogramBucket=0, median=0, gradesLength=0; double avg=0.0; int grade=0; printf("Enter grades:n"); while (scanf("%d",&grade) != EOF) { grades[gradesLength]=grade; gradesLength=gradesLength+1; }
我应该在grades []数组中设置这些“等级”并计算循环中数组的长度。
不知怎的,循环行为不端,似乎有些输入对循环没问题,但是对于某些输入(实际上大部分都是),scanf()不会得到EOF,无论它是文件的实际结尾,还是^ D终端中的命令。
我听说scanf()不是读取数据最可靠的方法,但遗憾的是我不能使用其他任何东西,因为我们没有在课堂上学过任何其他方法,所以我们只能在我们的作业中使用scanf()。
我试图用== 1
更改!= EOF
并且它们都一样。
输入
100 0 90 10 80 20 70 30 60 40 50
例如它工作正常。 但是对于输入:
0 50 100
循环是无限的。
我正在使用macbook pro btw(如果重要的话)。
有任何想法吗?
如果您键入一个字母而不是一个数字, scanf()
将返回0(如“零成功转换的数字”)而不是EOF(如“没有数据可读”)。 正确的测试是确保您获得预期数量的值 – 在这种情况下,1:
while (scanf("%d", &grade) == 1)
如果你需要知道你是否得到了EOF或者没有得到结果(但是读取该行的其余部分可能会清除问题),那么从scanf()
捕获返回值:
int rc; while ((rc = scanf("%d", &grade)) == 1) { } if (rc != EOF) …read the rest of the line, or at least the next character, before resuming the loop…
而且,如果你真的想,你可以写:
int rc; while ((rc = scanf("%d", &grade)) != EOF) { if (rc == 1) grades[gradesLength++] = grade; else { printf("Discarding junk: "); int c; while ((c = getchar()) != EOF && c != 'n') putchar(c); putchar('n'); if (c == EOF) break; } }
else
子句中的代码可以合理地放入函数中。 它还可能将消息报告给标准错误而不是标准输出。 让用户知道你反对的内容是有礼貌的。 您可以在换行前使用不同的测试( && !isdigit(c) && c != '+' && c != '-'
,使用isdigit()
。 但是,用户没有机会重新编辑他们放在字母后面的内容,因此您可能会误解他们的输入。 最好只丢掉输入线的其余部分,让它们重新开始。
正如chux所 指出的那样 ,在读取可能是整数的一部分的字符后,该字符需要被放回到输入流中。 因此,如果我要分析行的其余部分并重新开始扫描第一个实际上可能是整数的数据,我会考虑使用类似的东西:
#include static inline int could_be_integer(int c) { return isdigit(c) || c == '+' || c == '-'); }
然后else子句可能是:
else { printf("Discarding junk: "); int c; while ((c = getchar()) != EOF && c != 'n' && !could_be_integer(c)) putchar(c); putchar('n'); if (could_be_integer(c)) ungetc(c, stdin); else if (c == EOF) break; }
正如你所看到的,这会变得混乱。 有时候(正如评论中提到的Weather Vane ),用fgets()
读取一行更容易,然后在循环中使用sscanf()
(参见如何在循环中使用sscanf()
? )。 警惕有关使用fflush(stdin)
的建议; 它在任何地方都不会自动出错,但在正常情况下它无法在MacBook Pro上运行。
总的来说,简单地忽略输入线的其余部分通常是更好的界面决策。
这个对我有用。
我把你的片段包括在内:
#include #include #define MAX_GRADES_LENGTH 20 #define HISTOGRAM_SIZE 20 main() { int grades[MAX_GRADES_LENGTH]={0}, histogram[HISTOGRAM_SIZE]={0}; int maxGradesHistogramBucket=0, median=0, gradesLength=0; double avg=0.0; int grade=0; int i; printf("Enter grades:n"); while (scanf("%d",&grade) != EOF) { grades[gradesLength]=grade; gradesLength=gradesLength+1; } if (errno) perror("grade"); for (i = 0; i < gradesLength; ++i) { printf("%dn", grades[i]); } }
并运行它:
$ a.out Enter grades: 100 0 90 10 80 20 70 30 60 40 50 100 0 90 10 80 20 70 30 60 40 50 $ a.out Enter grades: 0 50 100 0 50 100 $
也许你正在寻找错误的地方。 也许这个bug出现在你的输出程序中?
就个人而言,如果必须这样做,考虑到scanf
返回时的一些不确定性,并且没有重写它,那么这个小的改变可能更可靠:
int i, r; printf("Enter grades:n"); while ((r = scanf("%d",&grade)) > 0)
以上就是c/c++开发分享而scanf EOF循环行为不当相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/522270.html