【问题标题】:fseek(binaryFile, 0, 1) stops a while loop from being an infinite loopfseek(binaryFile, 0, 1) 将 while 循环停止为无限循环
【发布时间】:2021-06-11 20:07:50
【问题描述】:

下面的代码取自有关学生的文件数据,并为指定组的第一个科目的成绩添加一个点。但是,在执行此操作的 while 循环中, fseek(binaryFile, 0, 1) 可防止循环成为无限循环。我发现 fseek(binaryFile, 0, 1) 用于从写入模式转到读取模式,但我不明白它是如何工作的以及它如何防止无限循环。

#include <stdio.h>

typedef struct
{
    int identificationNumber;
    char name[30];
    int year;
    int group;
    int numberOfGrades;
    int grades[15];
} Student;

void main()
{
    FILE *binaryFile;
    Student student;

    char fileName[20];
    printf("Enter the binary file name (.dat): ");
    gets(fileName);

    binaryFile = fopen(fileName, "rb+");

    if (!binaryFile)
    {
        printf("The file could not be opened");
    }
    else
    {
        int groupNumberWanted;
        printf("Enter the group number: ");
        scanf("%d", &groupNumberWanted);

        while (!feof(stdin))
        {
            rewind(binaryFile);
            fread(&student, sizeof(Student), 1, binaryFile);
            int doesGroupExist = 0;

            while (!feof(binaryFile))
            {
                if (groupNumberWanted == student.group)
                {
                    doesGroupExist = 1;
                    if (student.grades[0] < 10)
                    {
                        student.grades[0] = student.grades[0] + 1;
                    }
                    fseek(binaryFile, ftell(binaryFile) - sizeof(Student), 0);
                    fwrite(&student, sizeof(Student), 1, binaryFile);
                    fseek(binaryFile, 0, 1); // without this line, the while loop is an infinite loop
                }
                fread(&student, sizeof(Student), 1, binaryFile);
            }

            if (doesGroupExist == 0)
            {
                printf("The group wasn't found.\n");
            }

            printf("Enter the group number: ");
            scanf("%d", &groupNumberWanted);
        }
        fclose(binaryFile);
    }
}

【问题讨论】:

  • feof 不是用于检查文件是否已到达末尾。读/写函数的返回值通过返回 NULL 字符串、EOF 或指示读取了零字节来实现。
  • 为了清楚起见,请使用常量SEEK_SET|CUR|END,我们很多人都不会记住它的数值。 (我没有。)
  • 请参阅man page 了解更多信息,上面写着“当您从写入切换到读取时,您必须使用对 fflush 或文件定位函数的干预调用。” i> 假设的“无限循环”大概是不这样做的结果。
  • 至于你的问题:如果"r+""w+" 模式希望你在改变模式时进行定位,那就是这样做的。如果你不这样做,然后在阅读时没有得到正确的结果,那是你的错。没有什么要理解的,这只是事情在幕后实现的方式。 (一般来说,我看到实现数据库的初学者经常使用的"+" 模式,狂野的fseek 跳跃等等。我认为最好有两个数据库加载/保存函数并在内存中进行所有操作.)

标签: c file while-loop fseek


【解决方案1】:

C 标准要求在输入和输出操作和文件定位函数之间插入对 fflush 函数或文件定位函数(fseekfsetposrewind)的调用在输出和输入操作之间。

标准中的相关部分是

当使用更新模式打开文件时('+' 作为第二个或第三个 上述模式参数值列表中的字符),输入和 可以在关联的流上执行输出。然而,输出 在没有介入调用的情况下,不应直接跟随输入 fflush 函数或文件定位函数(fseek、fsetpos、 或倒带),并且输入不得直接跟随输出而不 对文件定位函数的干预调用,除非输入 操作遇到文件结尾。打开(或创建)文本文件 使用更新模式可能会在某些情况下打开(或创建)二进制流 实现。

来自https://port70.net/~nsz/c/c11/n1570.html#7.21.5.3p7


关于代码的一些旁注:

  • void main() { /* ... */ } 不是定义 main 函数的正确方法。
  • gets 不再存在于 C 语言中。即使它存在,也必须使用 fgets(或另一个设置读取字符数限制的函数)来代替。
  • while (!feof(fp)) { /* ... */ } 不是用于迭代流中记录的正确循环结构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-28
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 1970-01-01
    相关资源
    最近更新 更多