Skip to content

信息学实验室作业(三)

更新: 2025/3/15 字数: 0 字 时长: 0 分钟

一、实验目的

本次实验聚焦于二进制文件处理,旨在熟练运用C语言标准库<stdio.h>中的freadfwritefseek等函数,实现对包含学生信息的二进制文件的创建、数据读取与写入、成绩修正、不及格成绩处理以及文件内容查看等操作,进而深入理解二进制文件的特性及文件操作原理,提升文件处理编程能力。

二、实验内容

创建一个二进制文件,该文件由包含学生信息的结构体组成。结构体包含学生姓名、成绩数量以及不超过五个成绩的数组。根据补考结果对文件内容进行修正,在此过程中输出所有不及格成绩并获取新的成绩。同时,实现对文件内容的查看功能。

三、实现思路

  1. 定义学生结构体:设计一个结构体来存储学生的各项信息,包括姓名、成绩数量和成绩数组,以便后续对学生数据进行统一管理和操作。
  2. 创建二进制文件并录入学生信息:使用fopen函数以二进制写入模式("wb")打开文件。若文件打开成功,将预先设定的学生信息通过fwrite函数逐笔写入文件。写入完成后,使用fclose函数关闭文件,确保数据安全保存。
  3. 根据补考结果修正成绩:以二进制读写模式("rb+")重新打开文件。利用fseek函数结合循环,遍历文件中的每一个学生结构体。读取学生成绩,判断是否存在不及格成绩(假设成绩低于60分为不及格)。若有不及格成绩,输出该成绩并提示用户输入补考后的新成绩。使用fseek函数将文件指针定位到该不及格成绩对应的位置,使用fwrite函数将更新后的成绩写回文件。
  4. 查看文件内容:以二进制读取模式("rb")打开文件。通过循环使用fread函数读取文件中的每个学生结构体,并将学生的姓名、成绩数量和成绩等信息按一定格式输出到控制台,以便直观查看文件内容。

四、代码实现

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

#define MAX_NAME_LENGTH 50
#define MAX_SCORES 5

// 定义学生结构体
typedef struct {
    char name[MAX_NAME_LENGTH];
    int scoreCount;
    float scores[MAX_SCORES];
} Student;

// 创建二进制文件并录入学生信息
void createStudentFile(const char *filename) {
    FILE *file = fopen(filename, "wb");
    if (file == NULL) {
        perror("无法打开文件");
        return;
    }

    Student students[] = {
        {"张三", 3, {70, 50, 80}},
        {"李四", 2, {40, 90}},
        {"王五", 3, {60, 65, 55}}
    };

    int numStudents = sizeof(students) / sizeof(students[0]);
    for (int i = 0; i < numStudents; i++) {
        fwrite(&students[i], sizeof(Student), 1, file);
    }

    fclose(file);
}

// 根据补考结果修正成绩
void correctScores(const char *filename) {
    FILE *file = fopen(filename, "rb+");
    if (file == NULL) {
        perror("无法打开文件");
        return;
    }

    Student student;
    float newScore;
    while (fread(&student, sizeof(Student), 1, file) == 1) {
        for (int i = 0; i < student.scoreCount; i++) {
            if (student.scores[i] < 60) {
                printf("学生 %s 的成绩 %.2f 不及格,请输入补考后的成绩: ", student.name, student.scores[i]);
                scanf("%f", &newScore);
                student.scores[i] = newScore;
            }
        }
        // 将文件指针移动到当前学生结构体的起始位置
        fseek(file, -sizeof(Student), SEEK_CUR);
        // 写入修改后的学生结构体
        fwrite(&student, sizeof(Student), 1, file);
    }

    fclose(file);
}

// 查看文件内容
void viewStudentFile(const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (file == NULL) {
        perror("无法打开文件");
        return;
    }

    Student student;
    while (fread(&student, sizeof(Student), 1, file) == 1) {
        printf("姓名: %s\n", student.name);
        printf("成绩数量: %d\n", student.scoreCount);
        printf("成绩: ");
        for (int i = 0; i < student.scoreCount; i++) {
            printf("%.2f ", student.scores[i]);
        }
        printf("\n\n");
    }

    fclose(file);
}

int main() {
    const char *filename = "students.dat";

    // 创建二进制文件并录入学生信息
    createStudentFile(filename);

    // 根据补考结果修正成绩
    correctScores(filename);

    // 查看文件内容
    viewStudentFile(filename);

    return 0;
}

五、代码解释

  1. 结构体定义Student结构体包含name(姓名)、scoreCount(成绩数量)和scores(成绩数组)三个成员,用于存储单个学生的相关信息,方便后续在文件操作中对学生数据进行整体处理。
  2. createStudentFile函数:该函数接受一个文件名作为参数。使用fopen函数以二进制写入模式打开文件,如果文件打开失败,通过perror函数输出错误信息并返回。函数内部定义了一个包含多个学生信息的数组,通过循环遍历该数组,使用fwrite函数将每个学生的结构体信息写入文件。最后,使用fclose函数关闭文件,确保数据写入磁盘。
  3. correctScores函数:此函数接受文件名作为参数,以二进制读写模式打开文件。在循环中,使用fread函数读取文件中的每个学生结构体。对于每个学生的成绩数组,遍历判断是否有不及格成绩。若有,提示用户输入补考后的新成绩,更新结构体中的成绩。通过fseek函数将文件指针定位到需要修改的成绩位置,使用fwrite函数将新成绩写回文件。修改完成后,调整文件指针位置,以便继续读取下一个学生的信息。循环结束后,关闭文件。
  4. viewStudentFile函数:该函数接受文件名作为参数,以二进制读取模式打开文件。在循环中,使用fread函数读取文件中的每个学生结构体,并将学生的姓名、成绩数量和成绩等信息按特定格式输出到控制台。循环结束后,关闭文件。
  5. main函数:在main函数中,定义了文件名。首先调用createStudentFile函数创建并初始化学生信息文件;接着调用correctScores函数根据补考结果修正学生成绩;最后调用viewStudentFile函数查看修正后的文件内容。

六、编译与运行

  1. 将上述代码保存为一个.c文件,例如student_grades.c
  2. 在命令行中,使用gcc编译器对代码进行编译,命令为gcc student_grades.c -o student_grades。编译成功后会生成一个可执行文件student_grades
  3. 运行生成的可执行文件,命令为./student_grades。运行过程中,根据提示输入补考后的成绩。程序运行结束后,可在控制台查看修正后的学生信息。

七、实验总结

通过本次实验,成功掌握了二进制文件的基本操作,包括文件的创建、数据的写入与读取、文件指针的定位以及结构体在二进制文件中的应用。在实验过程中,遇到了文件指针定位不准确、数据覆盖错误等问题,通过仔细检查代码和查阅资料,深入理解了fseek函数的工作原理和文件操作的细节,最终解决了问题。这不仅提高了对二进制文件处理的编程能力,还培养了在面对复杂问题时的调试和解决问题的能力。未来,将进一步探索二进制文件在更复杂数据管理场景中的应用,如大规模数据存储与检索,以提升自己的编程技能。