在检查新行时使用 fscanf 填充文件中的结构数组(反馈)

Filling an array of struct from a file with fscanf while checking new line (feedback)

我有一个 .txt 文件,其中每一行都是这样的:

id name surname 78 99 101 12 33 44

每一行我都需要填充一个Student的结构。 surname 之后的数字必须存储在结构数组 Lesson 中。第一个数字(例如 78)是一个结构字段,第二个数字(99)是另一个结构字段。姓氏后面的对最多可以有 8 个。我有点困惑,因为我不知道会有多少对,我找到了这个方法,但不确定我检查换行符 (\n) 的方式是否正确。

typedef struct Lesson
{
    int hour;
    int time;
}Lesson;

typedef struct Student
{
    int id;
    char name_and_surname[100];
    Lesson lessons[8];
    struct Student *next;
}Student; 

Student s;

while (fscanf(fp, "%d %s %s", &s.id, s.name_and_surname, tmp) == 3)
{
    int i = 0;
    strcat(s.name_and_surname, " ");
    strcat(s.name_and_surname, tmp);
    while ((ch = fgetc(fp) != '\n') && fscanf(fp, "%d %d", &s.lessons[i].hour, &s.lessons[i].time) == 2) 
      {
            i++;
      }
       
       //add s to a linked list
}

我觉得只要你知道Lesson的输入必须是成对的,不会是奇数就可以了。 在这种情况下,您可以用 0 或 null 甚至 -1 左右填充数组 lessons 的末尾。你这样做是因为你可能想在之后打印它。 类似的东西:

for (j = 0; j < i; j++)
{
    s.lessons[j].hour = 0;
    s.lessons[j].time = 0;
}

正如我在评论中所说,如果您的输入被组织为每行一条记录且格式可变的行,那么最好一次读取整行,也许使用 fgets(),并且然后将结果解析到它的字段中。有许多可供选择的解析方法,其中包括 sscanf()strtok()strtol().

如果您必须通过fscanf()直接扫描每个字段来完成这项工作,那么这是可能的,但很麻烦。您提出的特定方法并不可靠:它不会识别带有尾随空格的行上的换行符,也不会识别因尾随数字为奇数而格式错误的行。

例如,您可以改用这样的东西:

/*
 * Scan one int from file 'fp' into the location pointed to by 'dest',
 * skipping any leading whitespace other than newlines.
 *
 * Returns:
 *  1   on success
 *  0   if a non-numeric field is found before the next newline
 *  EOF if end of file or end of line is reached without encountering
 *      an input field, or on error
 */
int scan_one_number(FILE *fp, int *dest) {

    // skip leading whitespace, but stop at a newline
    while (1) {
        int c = fgetc(fp);
        
        if (c == EOF || c == '\n') {
            // terminate on error, end-of-file, or end-of-line
            return EOF;
        } else if (!isspace(c)) {
            // a non-whitespace character

            // push it back onto the stream
            if (ungetc(c, fp) != c) {
                // error
                return EOF;
            }

            // break out of the loop
            break;
        } // else it's non-newline whitespace; ignore it
    }

    // attempt to scan a decimal integer
    return fscanf(fp, "%d", dest);
}

这将允许您使用 scanf 一次扫描一个数字,识别行尾和格式错误的输入。