C 而依赖于扫描结果的循环过早结束

C 而依赖于扫描结果的循环过早结束,c,while-loop,scanf,C,While Loop,Scanf,我正在用C写一个简单的程序来计算成绩和平均成绩。我通过“xyz_output.txt”命令输出到另一个文本。输入文件中有100多行数据,但由于某种原因,程序一直在退出围绕输入第6行的循环。。。我已经检查了输入格式好几次,但我似乎不明白为什么它会过早退出。代码如下: #include <stdio.h> #include <string.h> #include <stdlib.h> int main() { char pp[4]; char s

我正在用C写一个简单的程序来计算成绩和平均成绩。我通过“xyz_output.txt”命令输出到另一个文本。输入文件中有100多行数据,但由于某种原因,程序一直在退出围绕输入第6行的循环。。。我已经检查了输入格式好几次,但我似乎不明白为什么它会过早退出。代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

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;
    float average;
    int runtotal;
    int grouptotal = 0;
    float groupaverage;
    int counter = 0;
    while (scanf("%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) == 22)
    {
        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;
        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);
    }
    groupaverage = (float)grouptotal / counter;
    printf ("Calculations complete.\nThe total score for this group was %i.\nThe average score for this group was %f.\n", grouptotal, groupaverage);
    return 0;
}

它似乎到达了“preHI5109”,但随后退出。我觉得这与我如何使用scanf有关,但我不确定我做错了什么。关于如何解决这个问题有什么建议吗?

读取数据文件的方法对错误对齐、解析和I/O问题非常敏感。建议更健壮的IO和解析,因为数据文件中肯定存在一些小错误。使用
fgets()
控制读取行定向数据

char buf[100];
while (fgets(buf, sizeof buf, stdin) != NULL) {
  int count = sscanf(buf, "%3s%2s%2i%2i %i %i %i %i /* ... */ %i %i", 
    pp, school, &class, &student, &a, &b, &c, /* ... */  &q, &r);
  if (count != 22) {
    printf("Error %d (TBD relevant text)\n", count);
    break;
  }
  /* continue with normal processing */
}
其他改进
inta[18]
而不是
inta;INTB
使用循环扫描、求和、打印18个元素。
使用
“%i”
而不是
“%1i”
1
是最小宽度,为什么有它


注意:如果输入文件是由一位教授提供的,那么我就不会感到惊讶,因为其中有一些故意不好的东西。教训:除非经过充分审查,否则不要相信数据输入。用户输入是错误的。

scanf
返回的数字是多少?你可以把它放在某处。。。。什么是
errno
?和
ferror(stdin)
?使用调试信息和所有警告(例如
gcc-g-Wall
)进行编译,并使用调试器(例如
gdb
)。你的操作系统和编译器是什么?也许使用
%n
格式控件可能会有所帮助。我会尝试快速存储返回并返回给您。没有任何错误,程序只是退出循环并在循环结束后执行最后的计算。请看,除非这是学习C的练习,否则没有理由使用C。正如@Basile所建议的,了解
scanf()
结果将有所帮助。进一步:
(scanf(“%3s%2s%2i%2i%i%i%i…”与
(scanf(“%3s%2s%2i%2i%i%i%i%i%i…”)相同。
“%i”
之前的空格可能有助于查看,但不会影响
scanf()
功能,因为
“%i”
无论如何都会占用前导空格。建议使用
fgets()阅读这些行。)
然后使用
sscanf()
进行解析。当然,数据文件中隐藏了一些散乱的
char
。谢谢chux,你的代码工作了(计数只需要22,而不是23)。我在输入文件上运行了它,它处理了所有100行数据。不过,出于学习目的,我很好奇为什么scanf会“看到”或不看到“看到”字符导致它出现故障?当用肉眼查看输入数据时,我找不到任何错误,那么scanf看到了什么而我没有看到?@Jason Sturgeon(23到22已修复)使用
fgets()
一次读取一行,有利于错误定位。文本文件当然是面向行的。假设一行的末尾有额外的
char
s
“z”
fgets()
将读取行(最多100行)和
sscanf()
将成功扫描,忽略多余的垃圾,愉快地进入下一行。您的原始代码将尝试将
z
读为
pp
,这将导致厄运。最终,
%i
将尝试扫描字母失败,并且不会继续进行。但在出现原始问题的地方,情况有点混乱。@Ja顺便说一句,为了提高效率,使用
sscanf()
工具:
int ch;sscanf(buf,“%3s%2s%2i…%i%i%c”
。通过添加
“%c”
,并且不增加22到23,您已经创建了句子。在上一次预期的
int
之后的任何非空格都会被检测到。(我在最初的回答中,有1/2个实现了这一点。)再次感谢chux。我实际上是一名语言学教授,所以编程远不是我的专长,但我涉足C主要是因为我听说大多数其他语言都是基于C语言的,如果你能用C语言编写代码,那么转换到其他语言就容易得多。用它来整理一些简单的数学问题研究似乎是一个很好的起点,也是一种在未来为自己节省数小时时间的方法。谢谢你幽默地回答我的问题。到时候我会让你的专业人士回到这一点上。
char buf[100];
while (fgets(buf, sizeof buf, stdin) != NULL) {
  int count = sscanf(buf, "%3s%2s%2i%2i %i %i %i %i /* ... */ %i %i", 
    pp, school, &class, &student, &a, &b, &c, /* ... */  &q, &r);
  if (count != 22) {
    printf("Error %d (TBD relevant text)\n", count);
    break;
  }
  /* continue with normal processing */
}