使用C程序读取输入时存在小Bug

5
我本以为这个程序已经运行良好,但仔细查看输出文件后,我发现计算中出现了一些“看起来随机”的错误。在找到所有错误的数字后,我发现这些错误有一个奇怪的模式,我无法解释或找出原因,尽管我感觉它与二进制代码存储在内存中有关。
该程序应读取一个文本文件,其中每行都是数据,每行都遵循以下格式:三个字母('pre'或'pos'),然后是两个代表学校ID的字母,两个代表班级的数字(有4种可能的组合,51、52、61或62),最后是两位数字表示学生ID。这部分构成了数据条目的ID标签。标签后面是18个单个数字的整数,范围从0到2。这些是学生在考试中每道题目上获得的分数。下面是单个数据输入的示例,要处理的文本文件每个有100行。
问题出在当程序读取数据行时,大多数情况下都能正确读取并按预期执行,但如果ID标签的最后两位数字是08或09,则程序会认为学生的ID号码是0,并且测试的第一个分数分别是8或9,这当然是不可能的,因为学生能够得到的最高分数是2。我查看了一下,确实在每个ID为08或09的学生中,都出现了这个错误。低ID(01到07)也能正常运行,高于09的ID也一样……那么为什么只有这两个数字?我觉得这很不寻常。
这是我第二次在SO上提交这个程序,第一次是因为用户输入导致了各种问题,所以有人建议先使用fgets然后再使用scanf解析数据,我按照这个方法做了,让程序工作起来了(我以为..直到我仔细查看输出数据时才发现这个问题)。
我正在使用C语言编写代码,我不是程序员,而是英语教授,所以显然并不知道C语言的全部知识。因此,请不要担心我的程序中存在的其他问题(因为我知道有很多),除非您认为它会导致其他错误。代码相当冗长,因此我将省略所有简单的int变量声明,仅在这里专注于有问题的部分。
int main()
{
char pp[4];
char school[3];
int class;
int student;
int a;
int b;
int c;
int d;
int e;
int f;
int g;
int h;
int i;
int j;
int k;
int l;
int m;
int n;
int o;
int p;
int q;
int r;

//several lines skipped here...//


while (fgets(buf, sizeof buf, stdin) != NULL) {
  int count = sscanf(buf, "%3s%2s%2i%2i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", 
    pp, school, &class, &student, &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r);
  if (count != 22) {
    printf("Error %d (TBD relevant text)\n", count);
    break;
  }
    runtotal = (a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r);
    average = (float)runtotal / 18;
    grouptotal = grouptotal + runtotal;
    xscore = (float)runtotal - trueavg;
    xscoresqr = (float)xscore * xscore;
    runxscore = (float)runxscore + xscoresqr;

//more happens inside this while loop here... I edited it out for this post//



counter++;
    printf ("%i.\n", counter);
    printf ("%s%s-%i-%i -- %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i %1i\n", pp, school, class, student, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r);
    printf ("Total score: %i\n", runtotal);
    printf ("Average: %f\n", average);
    printf ("Running Total: %i\n\n", grouptotal);
}
//the while loop ends here//

我认为问题在于读取和存储缓冲区中的数据...也许是这个原因...

为了给你一个好的例子,这里是输入和输出的一部分... 输入 ...

preHI5214 1 0 0 1 0 2 2 2 1 0 0 0 2 2 2 1 2 2
preKO5211 0 0 0 1 1 0 1 1 1 0 0 0 1 1 0 0 0 0
preIS5109 0 0 0 1 0 1 1 0 0 0 0 0 0 1 1 0 1 0
preSA6211 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 1 2 1
preSA6209 0 0 0 1 0 0 1 1 2 0 0 0 1 1 0 0 0 0
preHI6205 0 0 0 1 1 0 1 1 1 0 0 0 0 1 1 0 2 1
preKO5212 0 0 0 1 1 0 1 0 0 0 0 0 0 1 1 0 0 0
preSA6210 0 0 0 1 1 0 1 0 0 0 0 0 0 1 1 0 0 0
preHI6208 0 1 0 1 1 0 1 0 0 0 0 0 0 0 1 0 0 1
preKO5209 0 0 0 1 1 0 1 1 0 0 0 0 1 1 0 0 0 0
preHI5211 0 0 0 1 1 0 1 2 1 0 0 1 1 1 1 1 0 0
preKO6217 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1 0 0 0
preIS5108 0 0 0 1 1 0 1 1 0 0 0 0 1 1 1 0 1 1

and the output... ...

88.
preHI-52-14 -- 1 0 0 1 0 2 2 2 1 0 0 0 2 2 2 1 2 2
Total score: 20
Average: 1.111111
Running Total: 932

89.
preKO-52-11 -- 0 0 0 1 1 0 1 1 1 0 0 0 1 1 0 0 0 0
Total score: 7
Average: 0.388889
Running Total: 939

90.
preIS-51-0 -- 9 0 0 0 1 0 1 1 0 0 0 0 0 0 1 1 0 1
Total score: 15
Average: 0.833333
Running Total: 954

91.
preSA-62-11 -- 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 1 2 1
Total score: 11
Average: 0.611111
Running Total: 965

92.
preSA-62-0 -- 9 0 0 0 1 0 0 1 1 2 0 0 0 1 1 0 0 0
Total score: 16
Average: 0.888889
Running Total: 981

93.
preHI-62-5 -- 0 0 0 1 1 0 1 1 1 0 0 0 0 1 1 0 2 1
Total score: 10
Average: 0.555556
Running Total: 991

94.
preKO-52-12 -- 0 0 0 1 1 0 1 0 0 0 0 0 0 1 1 0 0 0
Total score: 5
Average: 0.277778
Running Total: 996

95.
preSA-62-10 -- 0 0 0 1 1 0 1 0 0 0 0 0 0 1 1 0 0 0
Total score: 5
Average: 0.277778
Running Total: 1001

96.
preHI-62-0 -- 8 0 1 0 1 1 0 1 0 0 0 0 0 0 0 1 0 0
Total score: 13
Average: 0.722222
Running Total: 1014

97.
preKO-52-0 -- 9 0 0 0 1 1 0 1 1 0 0 0 0 1 1 0 0 0
Total score: 15
Average: 0.833333
Running Total: 1029

98.
preHI-52-11 -- 0 0 0 1 1 0 1 2 1 0 0 1 1 1 1 1 0 0
Total score: 11
Average: 0.611111
Running Total: 1040

99.
preKO-62-17 -- 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1 0 0 0
Total score: 5
Average: 0.277778
Running Total: 1045

100.
preIS-51-0 -- 8 0 0 0 1 1 0 1 1 0 0 0 0 1 1 1 0 1
Total score: 16
Average: 0.888889
Running Total: 1061

如果您看一下以下五个条目的输入和输出数据,您就会非常清楚地明白我的意思...preIS5109、preSA6209、preHI6208、preKO5209和preIS5108。
那么我该怎么纠正呢?

1
你的代码问题可能很小,但是你的问题描述却很大。请尽量简化问题描述,只保留最少量的相关信息以便重现问题。没有人愿意花费1小时仅仅为了帮助你阅读一个问题描述。 - Ivaylo Strandjev
声称这个问题需要一个小时才能解决是夸大其词了。@IvayloStrandjev - alk
1个回答

6

请使用%2d代替%2i

当与%i格式说明符匹配时,以0开头的任何数字都被解释为八进制。 对于只包含数字 0 到 7 的数字,这并不重要,但包含8或9的数字不是有效的八进制,导致%2i输入匹配失败。


1
如果输入以 0x0X 开头,那么 %i 将会读取十六进制数。 - ajay
1
最好全部使用 %d。%i 只是一个等待发生意外的错误。 - david.pfx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接