首页 > 其他分享 >关于学生信息管理系统的优化

关于学生信息管理系统的优化

时间:2024-05-27 20:32:02浏览次数:19  
标签:fp arr name 学生 stu file offset 信息管理系统 优化

关于学生信息管理系统的优化

优化1:更改引导用户创建数据库的方案

    FILE *fp = fopen(file_name, "r");
    char s[100];
    int n;
    if (fp == NULL) {
        printf("未检测到数据库,请问是否创建(y / n)?");
        scanf("%s", s);
        printf("\n");
        if(s[0] == 'y') {
            printf("Please enter how many data items there are in total?(请输入共有多少项数据?) : ");
            scanf("%d", &n);
            printf("\n");
            FILE *p = fopen(file_name, "w");
            fclose(p);
            for (int i = 0; i < n; i++) {
                create_file();
            }
        }
    }
    else {
        stu_cnt = read_from_file(stu_arr);
    }
    fclose(fp);

利用读的特性,来检查数据库是否存在,如果不存在则引导用户创建数据库。

优化2:实现数据的单条修改操作

之前的方法是利用w打开文件使文件清空,然后写入更新后的数据。
优化后实现数据的单条修改。

typedef struct Student {
    long offset; //记录数据在文件中的位置
    char name[20];
    int age;
    int class;
    float height;
} Student;

更改结构体,增加记录数据在文件中位置的变量offset。

int read_from_file(Student *arr) {
    int i = 0;
    FILE *fp = fopen(file_name, "r");
    if (fp == NULL) return i;
    while (1) {
        long offset = ftell(fp);
        if (fscanf(fp, "%s", arr[i].name) == EOF) break;
        fscanf(fp, "%d%d%f", 
        	&arr[i].age,
        	&arr[i].class,
        	&arr[i].height
        );
        arr[i].offset = offset;
        fgetc(fp); //吞掉换行符
        i += 1;
    }
    fclose(fp);
    return i;
}

在从文件中读数据的代码段中维护offset的值。

注意细节:当读取完一行数据后,文件指针的位置位于一行数据末尾的换行符那里。需要用fgetc()来吞掉换行符。

void student_add() {
    printf("add new item : (name, age, class, height)\n");
    printf("mysql > ");
    scanf("%s%d%d%f",
        stu_arr[stu_cnt].name, 
        &stu_arr[stu_cnt].age, 
        &stu_arr[stu_cnt].class, 
        &stu_arr[stu_cnt].height
    );
    output_arr_file(stu_arr + stu_cnt, 1);
    stu_cnt += 1;
    int n = printf("add a astudent success!\n");
    printf("\n");
    for (int i = 0; i < n; i++) {
        printf("-");
    }
    printf("\n\n");
    return ;
}

那么如何维护在添加学生时数据的偏移量信息呢 ?

long output_arr_file(Student *arr, int n) {
    FILE *fp = fopen(file_name, "a");
    fseek(fp, 0, SEEK_END); //设置指针在文件的末尾
    long offset = ftell(fp);
    for (int i = 0; i < n; i++) {
    	fprintf(fp, "%s %d %d %.2f\n", 
    		arr[i].name, arr[i].age,
    		arr[i].class, arr[i].height
    	); 
    fclose(fp);
    return offset;
}

通过修改output_arr_file函数的返回值来维护偏移量信息。

void student_delete() {
    if (stu_cnt == 0) {
        printf("There is no student.\n");
        return ;
    }
    int id;
    student_list();
    do {
       printf("delete id : ");
       scanf("%d", &id);
    } while (id < 0 || id >= stu_cnt);
    printf("confirm (y / n) : ");
    fflush(stdin);
    char s[100];
    scanf("%s", s);
    if(s[0] != 'y') return ;
    for (int i = id + 1; i < stu_cnt; i++) {
        stu_arr[i - 1] = stu_arr[i];
    }
    stu_cnt -= 1;
    restore_data_to_file(stu_arr, stu_cnt);
    return ;
}
    for (int i = id + 1; i < stu_cnt; i++) {
        stu_arr[i - 1] = stu_arr[i];
    }

在删除学生信息的这段代码将会导致偏移量信息的错误。

    for (int i = id + 1; i < stu_cnt; i++) {
        long offset = stu_arr[i - 1].offset;
        stu_arr[i - 1] = stu_arr[i];
        stu_arr[i - 1].offset = offset;
    }

改为不更新数据偏移量。

void student_modify() {
    int id;
    student_list();
    do {
       printf("modify id : ");
       scanf("%d", &id);
    } while (id < 0 || id >= stu_cnt);
    printf("modify the item : (name, age, class, height)\n");
    scanf("%s%d%d%f",
        stu_arr[id].name, 
        &stu_arr[id].age, 
        &stu_arr[id].class, 
        &stu_arr[id].height
    );
    restore_data_to_file(stu_arr, stu_cnt);
    return ;
}

当前代码为清空文件并更新数据,但不会更新偏移量。
实现一个方法来维护数据的偏移量。

void modify_data_to_file(Student *stu) {
    FILE *fp = fopen(file_name, "r+");
    fseek(fp, stu->offset, SEEK_SET);
    fprintf(fp, "%s %d %d %.2f\n",
    	stu->name, 
    	stu->age, 
    	stu->class, 
    	stu->height
    );
    fclose(fp);
    return ;
}

当然这种方法有一个bug:如果文件中的学生数据是固定长度的,那么直接覆盖是可行的。如果记录是可变长度的,这种方法可能会导致文件内容出错。

#define output_format = "%10s%4d%4d%7.2f"

实现等宽输入。

void modify_data_to_file(Student *stu) {
    FILE *fp = fopen(file_name, "r+");
    fseek(fp, stu->offset, SEEK_SET);
    fprintf(fp, output_format,
    	stu->name, 
    	stu->age, 
    	stu->class, 
    	stu->height
    );
    fclose(fp);
    return ;
}
long output_arr_file(Student *arr, int n) {
    FILE *fp = fopen(file_name, "a");
    fseek(fp, 0, SEEK_END);
    long offset = ftell(fp);
    for (int i = 0; i < n; i++) {
    	fprintf(fp, output_format "\n", 
    		arr[i].name, arr[i].age,
    		arr[i].class, arr[i].height
    	); 
    fclose(fp);
    return offset;
}

优化3:实现数据的二进制存储

为什么要用二进制存储?

  1. 存储效率高
    二进制存储直接以机器码的形式存储数据,而不是将数据转换为可读的文本形式。这意味着同样的数据占用的存储空间更少。例如,整数在二进制形式下只需要4个字节,而在文本形式下可能需要更多的字节来表示。
  1. 读写速度快
    由于二进制存储不需要进行格式转换,读写速度通常比文本存储更快。特别是在处理大量数据时,这种速度优势更加明显。
  1. 数据精度高
    在二进制存储中,数据不会因为转换为文本而丢失精度。对于浮点数和其他精度敏感的数据类型尤其重要。
const char *file_name = "student_data.dat";

更改文件后缀名。

int read_from_file(Student *arr) {
    int i = 0;
    FILE *fp = fopen(file_name, "rb");
    if (fp == NULL) return i;
    while (1) {
        long offset = ftell(fp);
        if (fread(&arr[i], sizeof(Student), 1, fp) == 0) break;
        arr[i].offset = offset;
        i += 1;
    }
    fclose(fp);
    return i;
}

fread的返回值代表了成功读入几个字节。
二进制文件不必吞掉换行符。

long output_arr_file(Student *arr, int n) {
    FILE *fp = fopen(file_name, "ab");
    fseek(fp, 0, SEEK_END);
    long offset = ftell(fp);
    fwrite(arr, sizeof(Student), n ,fp);
    fclose(fp);
    return offset;
}
void modify_data_to_file(Student *stu) {
    FILE *fp = fopen(file_name, "rb+");
    fseek(fp, stu->offset, SEEK_SET);
    fwrite(stu, sizeof(Student), 1, fp);
    fclose(fp);
    return ;
}

文件打开方式改为操作二进制文件的,把fprintf改为fwrite,把fscanf改为fread。

小结

恭喜你!完成了学生信息管理系统的优化,向着C语言的殿堂更近了一步。

标签:fp,arr,name,学生,stu,file,offset,信息管理系统,优化
From: https://blog.csdn.net/2301_80927620/article/details/139221410

相关文章

  • C语言——学生信息管理系统——船长版
    C语言——学生信息管理系统概要完成第一个小项目,学生信息管理系统整体架构流程实现增,删,改,查,四个操作代码实现必要准备:typedefstructStudent{charname[20];intage;intclass;floatheight;}Student;#defineMAX_ARR10000intstu_cnt=......
  • 基于SSM+JSP的学生公寓管理系统
    !!!有需要的小伙伴可以通过文章末尾名片咨询我哦!!! ......
  • Unity性能优化——其他合集
     本节将详细介绍在收集性能分析数据之前不应使用的优化。可能的原因是这些优化在实现时非常耗费精力,在提高性能的同时可能会损害代码整洁性或可维护性,或者解决的可能仅仅是特定的范围内才存在的问题。多维数组与交错数组如该 StackOverflow文章所述,遍历交错数组通常比遍历多......
  • 一文搞定大学生所需的计算机基础知识
    大学计算机目录大学计算机第1章计算与计算思维1.1计算及计算工具的发展1.2计算的自动化1.2.1图灵与图灵机1.2.2冯诺依曼体系结构1.2.3现代计算机的发展1.3计算机与信息社会1.4计算思维及计算思维能力培养第2章计算机系统2.1计算机中数据的表示与运算2.1.1数制及数......
  • Python面向对象——创建类:学生成绩等级
    题目:不同分数对应等级,score>=90分为“优秀”,80<=score<90为“良好”,70<=score<80为“中等”,60<=score<70为“及格”,score<60为“不及格”。1学习创建类采用classclassPerson:#创建类country="Chinese"#类属性,可以通过类名来访问def__init__(......
  • 【白鲸优化算法】 tent、chebyshev、Singer、Logistic、Sine, Circle多种混沌初始化的
     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......
  • 【白鲸优化算法】 tent、chebyshev、Singer、Logistic、Sine, Circle多种混沌初始化的
     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......
  • JVM 参数优化
    1.JVM参数优化1.1.查看JVM默认参数1.2.关键JVM参数1.3.最终参数优化结果1.JVM参数优化1.1.查看JVM默认参数java-XX:+PrintFlagsInitial1.2.关键JVM参数JVM总体上可以分成三类:-:标准参数,比如-verbose:gc这类表示标准实现,所有的虚拟机都需要实......
  • Springboot Redis 性能优化(基于 Lettuce)
    1.SpringbootRedis性能优化(基于Lettuce)1.1.为什么是Lettuce1.2.参数优化1.2.0.1.SpringbootRedis所有参数项1.2.1.最终参数配置1.SpringbootRedis性能优化(基于Lettuce)1.1.为什么是LettuceSpringboot2.x.x开始默认使用lettuce作为redis客户......
  • 适合大学生低成本创业的又一个项目推荐(宿舍小卖部)
    ​ 大学生的时间是非常充裕的,这也导致了大学生非常的懒惰,每天除了娱乐(打游戏,针对大部分人),也没有其它爱好了,就连吃饭都要抽时间来吃,所以这就给同学在宿舍做点小生意带来了机会,特别是晚上,需求量特别的大,尤其是在特殊情况下不能外出的时候,宿舍小卖部的需求会更加旺盛。因此,开设宿舍小......