From 39ae3cffce41494a31ca7c07e05a8c48f236d76f Mon Sep 17 00:00:00 2001 From: Pyesgo Date: Thu, 26 Dec 2024 12:52:42 +0800 Subject: [PATCH] bug fix. --- data.bin | 0 data.txt | 4 -- main.c | 204 ++++++++++++++++++++++++++++++++---------------------- student.c | 46 ++++++------ student.h | 4 +- 5 files changed, 145 insertions(+), 113 deletions(-) create mode 100644 data.bin delete mode 100644 data.txt diff --git a/data.bin b/data.bin new file mode 100644 index 0000000..e69de29 diff --git a/data.txt b/data.txt deleted file mode 100644 index 47432d0..0000000 --- a/data.txt +++ /dev/null @@ -1,4 +0,0 @@ -1 张三 77.000000 -2 李四 45.000000 -3 王五 25.000000 -5 彩六 56.299999 diff --git a/main.c b/main.c index 1459abb..f5e11bb 100644 --- a/main.c +++ b/main.c @@ -2,49 +2,28 @@ #include -#define NAME_MAX_LEN 40 -#define DATA_TITLE "学号\t名字\t成绩\n" +#define NAME_MAX_LEN 80 + +#define INFO_TITLE "学号\t姓名\t选修课\t实验课\t必修课\t总分" +#define INFO_FORMAT "%u\t%s\t%.1f\t%.1f\t%.1f\t%.1f" +#define INFO_DATA_FILE "data.bin" #define print_with_format(format, ...) \ printf("\t\t" format, ##__VA_ARGS__) +#define print(str) \ + print_with_format("%s\n", str) -/* 定义一个全局学生列表,用来存储所有学生的信息 */ -static StudentList student_list; +#define print_without_endline(str) \ + print_with_format("%s", str) +#define print_student_info_title() \ + print(INFO_TITLE) -/* 清理标准输入(stdin)的多余字符 */ -void clear_stdin(void) -{ - /* 获取字符直到为换行符时(回车)停止 */ - while (getchar() != '\n') - continue; -} - -/* 自定义输出格式 - * 参数: - * - string 要打印的字符串 - * - end 末尾要追加的字符(一般为换行符), - * 省得每次printf后面加'\n'了,哈哈 - */ -void priv_print(char *string, char end) -{ - printf("\t\t%s%c", string, end); -} -/* 自定义输出,默认追加换行符 - * 相当于 printf("...其他字符\n") - */ -void print(char *str) -{ - priv_print(str, '\n'); -} +/* 定义一个全局学生列表,用来存储所有学生的信息 */ +static StudentList student_list; -/* 自定义输出(不追加换行符)*/ -void print_nonew_line(char *str) -{ - priv_print(str, '\0'); -} /* 展示菜单 */ void show_menu(void) @@ -60,7 +39,7 @@ void show_menu(void) print("| 8.显示所有学生信息 |"); print("| 0.退出系统 |"); print("|-----------------------------------------|"); - print_nonew_line("请选择<0-8> -> "); + print_without_endline("请选择<0-8> -> "); } /* 显示所传入的学生信息 @@ -108,17 +87,9 @@ void show_student(StudentObject object) if (attr.info.name == NULL) return; - /* 这行应该不用解释,输出信息 */ - print_with_format("%d\t%s\t%.1f\n", attr.info.num, attr.info.name, attr.scores.total); -} - -/* 展示标题 - * 即“学号 姓名 成绩” - */ -void show_title(void) -{ - /* 调用了无追加换行符的print */ - print_nonew_line(DATA_TITLE); + print_with_format(INFO_FORMAT "\n", attr.info.num, attr.info.name, + attr.scores.optional, attr.scores.experimental, + attr.scores.required, attr.scores.total); } /* 把记录中的所有学生信息显示到屏幕上 */ @@ -183,8 +154,8 @@ void show_all_student(void) /* 此时返回“object”为学生列表中的第一个“学生对象” */ object = student_list_generate(&list_generator); - /* 先显示一下标题 */ - show_title(); + + print_student_info_title(); /* 循环迭代学生列表里的元素(直到最后一个停止) */ while (object != NULL) { @@ -198,13 +169,32 @@ void show_all_student(void) } } +/* 清理标准输入(stdin)的多余字符 */ +void clear_stdin(void) +{ + /* 获取字符直到为换行符时(回车)停止 */ + while (getchar() != '\n') + continue; +} + +unsigned char getchar_lower_case(void) +{ + unsigned char got_char; + + got_char = getchar(); + if ((got_char > 64) && (got_char < 91)) + got_char += 0x20; + + return got_char; +} + /* 从标准输入(一般是控制台)中读取字符 * 参数: * - attr 学生的属性,是一个指针(要修改内容就要用到指针) * - name_max_length 名字最大长度(主要是限制从控制台获取的名字长度) */ -void get_student_from_stdin(StudentAttribute *attr, - student_base_t name_max_length) +void get_student_info_from_stdin(StudentAttribute *attr, + student_base_t name_max_length) { /* 字符串的偏移量, * 通俗讲就是字符串中第几个字符的意思 @@ -217,7 +207,7 @@ void get_student_from_stdin(StudentAttribute *attr, unsigned char got_char; /* 无追加换行符打印 */ - print_nonew_line("请输入学生姓名: "); + print_without_endline("请输入学生姓名: "); /* 先将字符串偏移置零, * 使其指向字符串的第一个字符 @@ -244,7 +234,7 @@ void get_student_from_stdin(StudentAttribute *attr, */ offset = 0; print_with_format("超出名字最大长度%d个字符!", name_max_length - 1); - print_nonew_line("请重新输入:"); + print_without_endline("请重新输入:"); /* 清除多余的字符 */ clear_stdin(); } @@ -258,37 +248,69 @@ void get_student_from_stdin(StudentAttribute *attr, */ *((attr->info.name) + offset) = '\0'; - print_nonew_line("请输入学号: "); + print_without_endline("请输入学号: "); scanf("%d", &(attr->info.num)); - print_nonew_line("请输入该学生的成绩: "); - scanf("%f", &(attr->scores.total)); + print_without_endline("请输入选修课成绩:"); + scanf("%f", &(attr->scores.optional)); + + print_without_endline("请输入必修课成绩:"); + scanf("%f", &(attr->scores.required)); + + print_without_endline("请输入实验课成绩:"); + scanf("%f", &(attr->scores.experimental)); + + student_object_scores_sum(attr); } void insert_student(void) { StudentAttribute attr; + StudentObject object; unsigned char name[NAME_MAX_LEN]; attr.info.name = name; - get_student_from_stdin(&attr, NAME_MAX_LEN); - student_list_append(student_list, &attr); - show_title(); - show_student(student_list_get_last(student_list)); + clear_stdin(); + get_student_info_from_stdin(&attr, NAME_MAX_LEN); + object = student_list_append(student_list, &attr); + if (object == NULL) { + print("申请内存失败,未能成功添加该学生信息"); + return; + } + + print_student_info_title(); + show_student(object); } void remove_student(void) { StudentAttribute attr; + StudentObject object; - print_nonew_line("请输入要删除的学号:"); - scanf("%d", &(attr.info.num)); + clear_stdin(); + print_without_endline("请输入要删除的学号:"); + scanf("%u", &(attr.info.num)); + + object = student_list_get_with_num(student_list, attr.info.num); + if (object == NULL) { + print("未找到该学号的学生"); + return; + } + + print("找到如下学生:"); + print_student_info_title(); + show_student(object); - if (student_list_remove_with_num(&student_list, attr.info.num) == STUDENT_OK) - print("成功删除!"); - else - print("学生不存在"); + clear_stdin(); + print_without_endline("确认删除吗?[Y/N] "); + if (getchar_lower_case() == 'y') { + student_list_remove(&student_list, object); + print("已执行删除!"); + print("请在返回主菜单后选择序号“1”进行录入以保存设置"); + } else { + print("用户取消,未执行删除"); + } } void find_student(void) @@ -296,7 +318,8 @@ void find_student(void) StudentAttribute attr; StudentObject object; - print_nonew_line("请输入要查找的学号:"); + clear_stdin(); + print_without_endline("请输入要查找的学号:"); scanf("%d", &(attr.info.num)); object = student_list_get_with_num(student_list, attr.info.num); @@ -305,7 +328,7 @@ void find_student(void) return; } - show_title(); + print_student_info_title(); show_student(object); } @@ -326,9 +349,9 @@ void modify_student(void) StudentObject object; unsigned char name[NAME_MAX_LEN]; - print_nonew_line("请输入要修改学生的学号:"); - scanf("%d", &(attr.info.num)); clear_stdin(); + print_without_endline("请输入要修改学生的学号:"); + scanf("%u", &(attr.info.num)); object = student_list_get_with_num(student_list, attr.info.num); if (object == NULL) { @@ -336,29 +359,36 @@ void modify_student(void) return; } + print("找到如下学生:"); + print_student_info_title(); + show_student(object); + attr.info.name = name; - get_student_from_stdin(&attr, NAME_MAX_LEN); + + clear_stdin(); + get_student_info_from_stdin(&attr, NAME_MAX_LEN); student_object_modify(object, &attr); - show_title(); + print("成功修改"); + print_student_info_title(); show_student(object); } void pause(void) { - print_nonew_line("按下回车键继续..."); + print_without_endline("按下回车键继续..."); clear_stdin(); getchar(); } void load_from_file(void) { - int fstat; FILE *fp; + int fstat; StudentAttribute attr; unsigned char name[NAME_MAX_LEN]; - fp = fopen("data.txt", "r"); + fp = fopen(INFO_DATA_FILE, "rb"); if (fp == NULL) { print("data文件不存在!"); return; @@ -366,12 +396,15 @@ void load_from_file(void) print("检测到data文件,准备导入"); } + fstat = ~EOF; attr.info.name = name; while (fstat != EOF) { - fstat = fscanf(fp, "%u\t%s\t%f", &(attr.info.num), attr.info.name, &(attr.scores.total)); + fstat = fscanf(fp, "%s", attr.info.name); if (fstat == EOF) continue; + fgetc(fp); + fread(&(attr.info.num), 1, (sizeof(StudentAttribute) - sizeof(unsigned char *)), fp); student_list_append(student_list, &attr); } @@ -387,11 +420,16 @@ void save_to_file(void) StudentAttribute attr; if (student_list_is_empty(student_list)) { - print("当前无学生信息录入"); - return; + clear_stdin(); + print("注意:当前为空列表,将清空文件原有的所有数据"); + print_without_endline("确认继续吗?[Y/N] "); + if (getchar_lower_case() != 'y') { + print("用户取消,未修改文件"); + return; + } } - fp = fopen("data.txt", "w"); + fp = fopen(INFO_DATA_FILE, "wb"); if (fp == NULL) { print("打开文件失败!"); return; @@ -401,7 +439,11 @@ void save_to_file(void) object = student_list_generate(&list_generator); while (object != NULL) { student_object_attr_export(object, &attr); - fprintf(fp, "%u\t%s\t%f\n", attr.info.num, attr.info.name, attr.scores.total); + + fprintf(fp, "%s", attr.info.name); + fputc(' ', fp); + fwrite(&(attr.info.num), 1, (sizeof(StudentAttribute) - sizeof(unsigned char *)), fp); + object = student_list_generate(&list_generator); } @@ -429,22 +471,18 @@ int main(void) pause(); break; case '2': - clear_stdin(); find_student(); pause(); break; case '3': - clear_stdin(); remove_student(); pause(); break; case '4': - clear_stdin(); modify_student(); pause(); break; case '5': - clear_stdin(); insert_student(); pause(); break; diff --git a/student.c b/student.c index da9cfc3..64b96d1 100644 --- a/student.c +++ b/student.c @@ -11,7 +11,7 @@ struct _student_list { #define list_next_is_null(list_addr) \ (((list_addr)->next) == NULL) #define list_is_empty(list_addr) \ - ((((list_addr)->student.info.name) == NULL) && list_next_is_null(list_addr)) + (((*((unsigned int *)(list_addr))) == 0) && (list_next_is_null(list_addr))) #define list_generate_next(list_addr_variable) \ list_addr_variable = ((list_addr_variable)->next) @@ -202,8 +202,8 @@ struct _student_object *student_list_get_with_num(struct _student_list *list, return NULL; } -student_ret_t student_list_append(struct _student_list *list, - struct _student_object *attr) +struct _student_object *student_list_append(struct _student_list *list, + struct _student_object *attr) { struct _student_object *object; @@ -211,8 +211,9 @@ student_ret_t student_list_append(struct _student_list *list, object = (struct _student_object *)list; } else { object = student_object_create(); + if (object == NULL) - return STUDENT_MEM_ERROR; + return object; if (! list_next_is_null(list)) list = (struct _student_list *)student_list_get_last(list); @@ -221,13 +222,13 @@ student_ret_t student_list_append(struct _student_list *list, student_object_copy(attr, object); student_object_name_copy(attr, object); - return STUDENT_OK; + return object; } student_ret_t student_list_remove(struct _student_list **list, struct _student_object *object) { - struct _student_list *previous_list_node, *current_list_node; + struct _student_list *previous_list_node; if ((struct _student_object *)(*list) == object) { if (list_next_is_null(*list)) { @@ -237,28 +238,26 @@ student_ret_t student_list_remove(struct _student_list **list, } else { *list = (*list)->next; student_object_free(object); + return STUDENT_OK; } - return STUDENT_OK; } - /* list head */ - previous_list_node = (struct _student_list *)student_list_generate(&(*list)); - /* list->next */ - current_list_node = (struct _student_list *)student_list_generate(&(*list)); + previous_list_node = &(**list); + list = &((*list)->next); - while (current_list_node != NULL) { - if (current_list_node == (struct _student_list *)object) { - if (! list_next_is_null(current_list_node)) - previous_list_node->next = current_list_node->next; - else + while (*list != NULL) { + if (*list == (struct _student_list *)object) { + if (list_next_is_null(*list)) previous_list_node->next = NULL; + else + previous_list_node->next = (*list)->next; student_object_free(object); return STUDENT_OK; } - previous_list_node = current_list_node; - current_list_node = (struct _student_list *)student_list_generate(&(*list)); + previous_list_node = *list; + list = &((*list)->next); } return STUDENT_CAN_NOT_REMOVE; @@ -335,7 +334,7 @@ void student_object_scores_sum(struct _student_object *object) member_count = sizeof(struct _student_scores) / sizeof(float); member_count -= 1; - f32_object = (float *)object; + f32_object = (float *)(&(object->scores)); object->scores.total = 0; while (member_count--) @@ -366,15 +365,14 @@ void student_list_sort_by_score(struct _student_list *list) void student_list_delete(struct _student_list *list) { - if (list_is_empty(list)) { - free(list); - return; - } + if (list_is_empty(list)) + goto free_self; while (student_list_remove(&list, (struct _student_object *)list) != STUDENT_CAN_NOT_REMOVE) continue; - + +free_self: free(list); } diff --git a/student.h b/student.h index fa4a9ab..c1a3deb 100644 --- a/student.h +++ b/student.h @@ -39,11 +39,11 @@ void student_object_swap(StudentObject __restrict object0, void student_object_attr_export(StudentObject __restrict object, StudentAttribute *__restrict attr); void student_object_modify(StudentObject object, StudentAttribute *attr); -void student_object_scores_sum(StudentObject object); +void student_object_scores_sum(StudentAttribute *attr); student_base_t student_object_get_name_length(StudentObject object); -student_ret_t student_list_append(StudentList list, StudentAttribute *attr); +StudentObject student_list_append(StudentList list, StudentAttribute *attr); student_ret_t student_list_remove(StudentList *__restrict list, StudentObject object); student_ret_t student_list_remove_with_num(StudentList *__restrict list,