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

Posted

技术标签:

【中文标题】在检查新行时使用 fscanf 从文件中填充结构数组(反馈)【英文标题】:Filling an array of struct from a file with fscanf while checking new line (feedback) 【发布时间】:2021-08-23 20:36:29 【问题描述】:

我有一个 .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


【问题讨论】:

如果行具有可变格式(例如您描述的不同数量的字段),那么fscanf 是解析它们的糟糕选择。通常情况下,通过fgets 一次读取一行并解析结果字符串是一种更可靠的选择。 namesurname 可以包含空格或数字吗?文件格式是你设计的还是你老师强加的? @fpiette 我的老师。它没有指定name_and_surname。我想如果我从 fgets 解析一个包含所有行的字符串,就像其他建议的那样,这将是一个问题。 fscanf 也是必需的吗? 【参考方案1】:

正如我在 cmets 中所说,如果您的输入被组织为每行一条记录,并使用可变格式行,那么最好一次读取一整行,可能使用 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 一次扫描一个数字,识别行尾和格式错误的输入。

【讨论】:

不是问题的答案! 什么问题,@fpiette?最接近问题的是“我不知道会有多少对,我找到了这种方法,但不确定我检查换行符 (\n) 的方式是否良好。”这个答案直接回应了这一点,从第二段开始,对 OP 提出的方法提出批评,并为不会受到相同批评的替代方案提供基础。另外,OP似乎很满意。 我的意思是标题:“Filling a array of struct from a file”。 @fpiette,标题不表达问题,并且随附的文本不支持将标题解释为不仅仅是为帖子提供一般上下文。但是,无论如何,如果您有一个您认为对 OP 想知道的内容更敏感的答案,请随意编写自己的答案。【参考方案2】:

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

for (j = 0; j < i; j++)

    s.lessons[j].hour = 0;
    s.lessons[j].time = 0;

【讨论】:

以上是关于在检查新行时使用 fscanf 从文件中填充结构数组(反馈)的主要内容,如果未能解决你的问题,请参考以下文章

oracle触发器在表中插入新行时更新新的视图行

从asp到json和jquery的新行

Postgres 检查是不是插入了任何新行

C语言文件读取fscanf(),该怎么处理

使用 fscanf 时防止缓冲区溢出

使用 fscanf,将文件扫描到 C 中的结构中,但第一个参数已经失败