这是我们老师的一个大作业,要求如下:
综合训练项目一 线性结构综合训练
目的和要求:线性结构是最基础,也是最重要的一种结构,通过此项训练让学生掌握线性结构的知识;要求编程实现学生成绩管理系统,使学生掌握线性结构的存储 及相关算法设计;设有一个学生文件,其结构为:学号、姓名、数学成绩、英语成绩、计算机成绩、总分、平均分、排名。要求用顺序和链式两种方式进行存储,并 在此基础上实现学生成绩的录入、保存、计算总分和平均分、排名、查询、统计等基本功能。
我最初的代码在:http://my.oschina.net/iamhere/blog/340999
而我现在写的带libxml2的代码如下:
#include<stdio.h> #include"stuxml.h" #include"studentList.h" int main( void ) { SL stulist = list_create_file( "student.txt" ); list_print( stulist ); man_create_list( stulist, "student.info.xml"); return 0; }
/** * @file student.h * 定义了保存学生信息的结构体\n * 操作学生信息的函数: * * * * @author 小代码 */ #ifndef STUDENT_H_ #define STUDENT_H_ #include<stdbool.h> /** * @brief 学生对象结构体定义 */ struct student { /** @brief 学号 */ int stu_id; /** @brief 姓名*/ char stu_name[10]; /** @brief 数学成绩 */ double stu_score_math; /** @brief 英语成绩 */ double stu_score_english; /** @brief 计算机成绩 */ double stu_score_computer; /** @brief 总成绩*/ double stu_score_sum; /** @brief 平均成绩 */ double stu_score_avg; /** @brief 排名 */ int stu_score_grade; /** @brief 直接前驱元素指针 */ struct student * prev; /** @brief 直接后继元素指针 */ struct student * next; }; /** @brief 学生结构体 */ typedef struct student STU; /** @brief 学生结构体指针 */ typedef struct student * Stu; /** * @brief 输出学生信息的标题 */ void print_title(); /** * @brief 创建一个学生信息对象 * * @param stu_id 学号 * @param stu_name 姓名 * @param stu_score_math 数学成绩 * @param stu_score_english 英语成绩 * @param stu_score_computer 计算机成绩 * * @return 指向学生对象结构体的指针 * @retval NULL 创建失败 */ Stu stu_create(int stu_id, char stu_name[20], double stu_score_math, double stu_score_english, double stu_score_computer); /** * @brief 输出一个学生的信息 * * 输出格式为每项占10个空格\n * 如果参数为空,则不输出任何内容 * * @param stu 要输出信息的学生对象 */ void stu_print(Stu stu); /** * @brief 比较两个学生的平均分 * * * @param stu1 * @param stu2 * * @return 比较结果 * @retval 1 stu1->stu_score_avg > stu2->stu_score_avg * @retval 0 stu1->stu_score_avg = stu2->stu_score_avg * @retval -1 stu1->stu_score_avg < stu2->stu_score_avg */ int stu_score_compare(Stu stu1, Stu stu2); /** * @brief 交换两个学生对象的所有成员的值 * * 交换成功则返回 0\n * 如果有任何一个参数为 NULL ,则返回-1 * * @param stu1 * @param stu2 * * @retval 0 交换成功 * @retval -1 交换失败 */ int stu_swap(Stu stu1, Stu stu2); #endif /* STUDENT_H_ */
#include"student.h" #include<stdio.h> #include<stdlib.h> #include<string.h> /** * @brief 输出学生信息的标题 */ void print_title() { printf("%-10s", "学号"); printf("%-10s", "姓名"); printf("%-10s", "数学"); printf("%-10s", "英语"); printf("%-10s", "计算机"); printf("%-10s", "总分"); printf("%-10s", "平均分"); printf("%-10s\n", "排名"); } /** * @brief 创建一个学生信息对象 * * @param stu_id 学号 * @param stu_name 姓名 * @param stu_score_math 数学成绩 * @param stu_score_english 英语成绩 * @param stu_score_computer 计算机成绩 * * @return 指向学生对象结构体的指针 * @retval NULL 创建失败 */ Stu stu_create(int stu_id, char stu_name[10], double stu_score_math, double stu_score_english, double stu_score_computer) { Stu stu = (Stu) malloc(sizeof(STU)); if ( NULL == stu) { printf("stu_create...动态分配内存失败!"); exit(-1); } stu->stu_id = stu_id; strcpy(stu->stu_name, stu_name); stu->stu_score_math = stu_score_math; stu->stu_score_english = stu_score_english; stu->stu_score_computer = stu_score_computer; stu->stu_score_sum = stu->stu_score_math + stu->stu_score_english + stu->stu_score_computer; stu->stu_score_avg = stu->stu_score_sum / 3; stu->stu_score_grade = -1; stu->prev = NULL; stu->next = NULL; return stu; } /** * @brief 输出一个学生的信息 * * 输出格式为每项占10个空格\n * 如果参数为空,则不输出任何内容 * * @param stu 要输出信息的学生对象 */ void stu_print(Stu stu) { if ( NULL == stu) { return; } printf("%-10d", stu->stu_id); printf("%-10s", stu->stu_name); printf("%-10.2f", stu->stu_score_math); printf("%-10.2f", stu->stu_score_english); printf("%-10.2f", stu->stu_score_computer); printf("%-10.2f", stu->stu_score_sum); printf("%-10.2f", stu->stu_score_avg); printf("%-10d", stu->stu_score_grade); putchar('\n'); } /** * @brief 比较两个学生的平均分 * * * @param stu1 * @param stu2 * * @return 比较结果 * @retval 1 stu1->stu_score_avg > stu2->stu_score_avg * @retval 0 stu1->stu_score_avg = stu2->stu_score_avg * @retval -1 stu1->stu_score_avg < stu2->stu_score_avg */ int stu_score_compare(Stu stu1, Stu stu2) { int result = 0; if (stu1->stu_score_sum > stu2->stu_score_sum) result = 1; if (stu1->stu_score_sum < stu2->stu_score_sum) result = -1; return result; } /** * @brief 交换两个学生对象的所有成员的值 * * 交换成功则返回 0\n * 如果有任何一个参数为 NULL ,则返回-1 * * @param stu1 * @param stu2 * * @retval 0 交换成功 * @retval -1 交换失败 */ int stu_swap(Stu stu1, Stu stu2) { if ( NULL == stu1 || NULL == stu2) { return -1; } int id_tmp = stu1->stu_id; stu1->stu_id = stu2->stu_id; stu2->stu_id = id_tmp; char name_tmp[10]; strcpy(name_tmp, stu1->stu_name); strcpy(stu1->stu_name, stu2->stu_name); strcpy(stu2->stu_name, name_tmp); double score_tmp = stu1->stu_score_math; stu1->stu_score_math = stu2->stu_score_math; stu2->stu_score_math = score_tmp; score_tmp = stu1->stu_score_english; stu1->stu_score_english = stu2->stu_score_english; stu2->stu_score_english = score_tmp; score_tmp = stu1->stu_score_computer; stu1->stu_score_computer = stu2->stu_score_computer; stu2->stu_score_computer = score_tmp; stu1->stu_score_sum = stu1->stu_score_math + stu1->stu_score_english + stu1->stu_score_computer; stu1->stu_score_avg = stu1->stu_score_sum / 3; stu2->stu_score_sum = stu2->stu_score_math + stu2->stu_score_english + stu2->stu_score_computer; stu2->stu_score_avg = stu2->stu_score_sum / 3; return 0; }
/** * @file * 定义了学生列表结构体 * * @author 小代码 */ #ifndef STUDENTLIST_H_ #define STUDENTLIST_H_ #include"student.h" #include<stdio.h> #include<stdbool.h> /** * @brief 学生列表结构体定义 * */ struct _stu_list { /** @brief 链表头指针 */ Stu head; /** @brief 链表尾指针 */ Stu last; }; /** @brief 学生链表 */ typedef struct _stu_list sl; /** @brief 指向学生链表的指针 */ typedef struct _stu_list * SL; /** * @brief 创建一个初始化的链表 * * @return 指向 _stu_list 的指针 * @retval NULL 创建失败 */ SL list_init(); /** * @brief 从文件创建一个学生列表 * @param file_name 含有学生信息的文本文件的文件名 * @return 返回学生列表 * @retval NULL 创建失败 */ SL list_create_file( char * file_name ); /** * @brief 销毁一个学生信息链表 * * @param stu_list 要销毁的链表的指针 */ void list_destroy(SL stu_list); /** * @brief 求学生信息链表的长度 * * @param stu_list 要求长度的学生信息链表 * * @return 学生信息链表 的长度 * @retval -1 参数为空 * */ int list_len( SL stu_list ); /** * @brief 判断一个链表是否为空 * * @param stu_list 要判断是否为空的链表 * * @retval true 为空 * @retval false 不为空 * */ bool list_is_empty( SL stu_list ); /** * @brief 在链表后追加一个元素 * * @param stu_list 要追加元素的链表 * @param stu 要追加的元素 * @return 返回的元素的指针 * @retval NULL 追加失败 */ Stu list_append(SL stu_list, Stu stu); /** * @brief 根据学生的学号删除一个学生的信息 * @param stu_list 保存学生信息的链表 * @param stu_id 要删除的学生的学号 * @return 返回被删除的学生 * @retval NULL 删除失败 */ Stu list_delete ( SL stu_list, int stu_id ); /** * @brief 输出一个链表的内容 * 如果链表为空或参数为NULl,则没有任何输出 * * @param stu_list 要打印的链表 */ void list_print( SL stu_list ); double list_score_sum(SL stu_list); double list_score_avg(SL stu_list); /** * @brief 根据学生号查的一个学生对象 * * @param stu_list 保存学生信息的链表 * @param stu_id 要查的的学生的学号 * @param stu 传出查询的学生 * @return 查找结果 * @retval -1 链表为空 * @retval 1 查询成功 * @retval 0 没有查到 */ int list_search_id(SL stu_list, int stu_id, Stu stu); /** * @brief 排序链表 * 使用选择排序法 * * @param stu_list 要排序的学生链表 */ void list_sort_avg(SL stu_list); /** * @brief 把一个学生信息链表写入到当前目录中的一个TXT文本文件 * 默认文件名为:student.txt\n * 根据排序的结果,从1开始对学生信息的 stu_score_grade 字段赋值 * @param stu_list 要写入到文件的学生链表 * @param file_name 械写入到的文件名 * @return 写入到文件中的链表的指针 */ FILE * list_save_txt(SL stu_list, char * file_name ); /** * @brief 列出平均分高于60的学生的信息 * @param stu_list 学生信息链表 * @return 分数高于60分的学生信息链表 * @note 返回一个链表的功能还未实现 */ SL list_pass(SL stu_list); #endif /* STUDENTLIST_H_ */
#include"studentList.h" #include"student.h" #include<stdio.h> #include<stdlib.h> #include<string.h> /** * @brief 创建一个初始化的链表 * * @return 指向 _stu_list 的指针 * @retval NULL 创建失败 */ SL list_init() { SL stu_list = (SL) malloc(sizeof(sl)); if ( NULL == stu_list) { printf("list_init..动态分配内存失败"); exit(-1); } stu_list->head = stu_create(0, " ", 0.0, 0.0, 0.0); stu_list->last = stu_create(0, " ", 0.0, 0.0, 0.0); stu_list->head->prev = NULL; stu_list->head->next = stu_list->last; stu_list->last->prev = stu_list->head; stu_list->last->next = NULL; return stu_list; } /** * @brief 从文件创建一个学生列表 * @param file_name 含有学生信息的文本文件的文件名 * @return 返回学生列表 * @retval NULL 创建失败 */ SL list_create_file( char * file_name ) { FILE * stu_file = fopen(file_name,"r"); if ( NULL == stu_file) { return NULL; } SL stu_list = list_init(); int stu_id = 0; char stu_name[10]; double stu_math = 0.0; double stu_english = 0.0; double stu_computer = 0.0; while ( EOF != fscanf(stu_file, "%d\t%s\t%lf\t%lf\t%lf", &stu_id, stu_name, &stu_math, &stu_english, &stu_computer)) { Stu stu = stu_create(stu_id, stu_name, stu_math, stu_english, stu_computer); // stu_print( stu ); list_append(stu_list, stu); } return stu_list; } /** * @brief 销毁一个学生信息链表 * * @param stu_list 要销毁的链表的指针 */ void list_destroy(SL stu_list) { if ( NULL == stu_list) { return; } if (list_is_empty(stu_list)) { free(stu_list); } Stu tmp = stu_list->head->next; while (tmp != stu_list->last) { Stu f = tmp; tmp->prev->next = tmp->next; tmp->next->prev = tmp->prev; tmp = f->next; free(f); } free(stu_list); } /** * @brief 求学生信息链表的长度 * * @param stu_list 要求长度的学生信息链表 * * @return 学生信息链表 的长度 * @retval -1 参数为空 * */ int list_len(SL stu_list) { if ( NULL == stu_list) { return -1; } int len = 0; if (list_is_empty(stu_list)) { len = 0; } Stu tmp = stu_list->head->next; while (tmp != stu_list->last) { len++; tmp = tmp->next; } return len; } /** * @brief 判断一个链表是否为空 * * @param stu_list 要判断是否为空的链表 * * @retval true 为空 * @retval false 不为空 */ bool list_is_empty(SL stu_list) { bool flags = false; if (stu_list->head->next == stu_list->last) { flags = true; } return flags; } /** * @brief 在链表后追加一个元素 * * @param stu_list 要追加元素的链表 * @param stu 要追加的元素 * @return 返回的元素的指针 * @retval NULL 追加失败 */ Stu list_append(SL stu_list, Stu stu) { if ( NULL == stu) { return NULL; } stu_list->last->prev->next = stu; stu->prev = stu_list->last->prev; stu->next = stu_list->last; stu_list->last->prev = stu; return stu; } /** * @brief 根据学生的学号删除一个学生的信息 * @param stu_list 保存学生信息的链表 * @param stu_id 要删除的学生的学号 * @return 返回被删除的学生 * @retval NULL 删除失败 */ Stu list_delete(SL stu_list, int stu_id) { if ( NULL == stu_list) { return NULL; } int len = list_len(stu_list); if (len < 0) { return NULL; } Stu stu = NULL; list_search_id(stu_list,stu_id, stu ); stu->next->prev = stu->prev; stu->prev->next = stu->next; free(stu); return NULL; } /** * @brief 输出一个链表的内容 * 如果链表为空或参数为NULl,则没有任何输出 * * @param stu_list 要打印的链表 */ void list_print(SL stu_list) { if (list_is_empty(stu_list)) { return; } print_title(); Stu tmp = stu_list->head->next; while (tmp != stu_list->last) { stu_print(tmp); tmp = tmp->next; } } double list_score_sum(SL stu_list) { double sum = 0.0; Stu tmp = stu_list->head->next; while (tmp != stu_list->last) { sum += tmp->stu_score_math + tmp->stu_score_english + tmp->stu_score_computer; tmp = tmp->next; } return sum; } double list_score_avg(SL stu_list) { return list_score_sum(stu_list) / list_len(stu_list); } int list_search_id(SL stu_list, int stu_id , Stu stu) { if (list_is_empty(stu_list)) { return -1; } Stu tmp = stu_list->head->next; // int i = 1; // int len = list_len( stu_list ); while (tmp != stu_list->last) { if( tmp->stu_id == stu_id ){ break; } tmp = tmp->next; } if (tmp == stu_list->last) { tmp = NULL; return 0; } stu->stu_id = tmp->stu_id; strcpy( stu->stu_name, tmp->stu_name); stu->stu_score_math = tmp->stu_score_math; stu->stu_score_english = tmp->stu_score_english; stu->stu_score_computer = tmp->stu_score_computer; return 1; } void list_sort_avg(SL stu_list) { if (list_is_empty(stu_list) || 1 == list_len(stu_list)) { return; } Stu stu = stu_list->head->next; Stu stu_next = stu->next; Stu end = stu_list->last->prev; while (stu != end) { // stu_print( stu ); stu_next = stu->next; while (stu_next != end->next) { if (stu->stu_score_avg < stu_next->stu_score_avg) { stu_swap(stu, stu_next); } stu_next = stu_next->next; } stu = stu->next; stu_next = stu_next->next; } stu = stu_list->head->next; int grade = 1; while (stu != stu_list->last) { stu->stu_score_grade = grade; grade++; stu = stu->next; } } FILE * list_save_txt(SL stu_list, char * file_name ) { if (list_is_empty(stu_list)) { return NULL; } FILE * fp = NULL; if ( NULL == (fp = fopen(file_name, "w"))) { printf("创建 !"); exit(-1); } Stu stu = stu_list->head->next; while (stu != stu_list->last) { char stu_info[1024]; sprintf(stu_info, "%d\t%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%d\n", stu->stu_id, stu->stu_name, stu->stu_score_math, stu->stu_score_english, stu->stu_score_computer, stu->stu_score_sum, stu->stu_score_avg, stu->stu_score_grade); // puts(stu_info); fputs(stu_info, fp); stu = stu->next; } if (0 != fclose(fp)) { puts("关闭文件失败!"); exit(-1); } return NULL; } SL list_pass(SL stu_list) { if (list_is_empty(stu_list)) { return NULL; } Stu stu = stu_list->head->next; while (stu != stu_list->last) { if (stu->stu_score_avg >= 60) { stu_print(stu); } stu = stu->next; } return NULL; }
/** @file stuxml.h * @brief 学生管理API */ #ifndef STUMAN_H_ #define STUMAN_H_ #include<libxml/tree.h> #include"studentList.h" /** @brief 创建一个学生信息的XML文件 * * @param xml_name 该文件的名字 ,默认为:student.man.xml * @return */ xmlDocPtr man_create_init( char * xml_name ); /** @brief 根据一个学生列表创建一个保存学生信息的XML文件 * * @param stulist 学生列表 * @param xml_name 文件名称 * @return */ xmlDocPtr man_create_list( SL stulist , char * xml_name ); /** @brief 根据学生创建一个子结点 * * @param stu 学生 * @return 创建的子结点 * @retval NULL 创建失败 */ xmlNodePtr man_create_node( Stu stu ); #endif /* STUMAN_H_ */
#include"stuxml.h" #include"student.h" #include"studentList.h" #include<libxml/tree.h> #include<libxml/parser.h> /** @brief 创建一个学生信息的XML文件 * * @param xml_name 该文件的名字 ,默认为:student.man.xml * @return */ xmlDocPtr man_create_init(char * xml_name) { //文档指针 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); xmlNodePtr root = xmlNewNode( NULL, BAD_CAST "stulist"); //设置XML文档的根属性 xmlDocSetRootElement(doc, root); //保存文档 int nRel = xmlSaveFile(xml_name, doc); if (nRel != -1) { printf("一个xml文档被创建,写入 %d 个字节\n", nRel); } return doc; } /** @brief 根据一个学生列表创建一个保存学生信息的XML文件 * * @param stulist 学生列表 * @param xml_name 文件名称 * @return */ xmlDocPtr man_create_list(SL stulist, char * xml_name) { if ( NULL == stulist) { puts("NULL == stulist"); return NULL; } xmlDocPtr doc = man_create_init(xml_name); xmlNodePtr root = xmlDocGetRootElement(doc); if (list_is_empty(stulist)) { puts("列表为空"); return doc; } Stu stu = stulist->head->next; while (stu != stulist->last) { xmlAddChild(root, man_create_node(stu)); stu = stu->next; } //保存文档 int nRel = xmlSaveFile(xml_name, doc); // if (nRel != -1) { // printf("一个xml文档被创建,写入 %d 个字节\n", nRel); // } // xmlSaveFileEnc( xml_name, doc, "UTF-8"); nRel = xmlSaveFormatFileEnc( xml_name, doc, "UTF-8",1); printf("一个xml文档被创建,写入 %d 个字节\n", nRel); xmlFreeDoc( doc ); return NULL; } /** @brief 根据学生创建一个子结点 * * @param stu 学生 * @return 创建的子结点 * @retval NULL 创建失败 */ xmlNodePtr man_create_node(Stu stu) { if ( NULL == stu) { return NULL; } char str[20]; //创建一个子结点 xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "student"); //设置 id 属性 sprintf(str, "%d", stu->stu_id); xmlNewProp(node, BAD_CAST "id", BAD_CAST str); //设置子结点 xmlNewTextChild(node, NULL, BAD_CAST "stuName", BAD_CAST stu->stu_name); sprintf(str, "%.2lf", stu->stu_score_math); xmlNewTextChild(node, NULL, BAD_CAST "stuMath", BAD_CAST str); sprintf(str, "%.2lf", stu->stu_score_english); xmlNewTextChild(node, NULL, BAD_CAST "stuEnglish", BAD_CAST str); sprintf(str, "%.2lf", stu->stu_score_computer); xmlNewTextChild(node, NULL, BAD_CAST "stuComputer", BAD_CAST str); sprintf(str, "%d", stu->stu_score_grade); xmlNewTextChild(node, NULL, BAD_CAST "stuGrade", BAD_CAST str); return node; }
1001 小代码 34 45 56 1002 老狼 25 16 56 1003 行者 34 13 77 1004 天涯 34 18 88 1005 散人 34 99 56
<?xml version="1.0" encoding="UTF-8"?> <stulist> <student id="1001"> <stuName>小代码</stuName> <stuMath>34.00</stuMath> <stuEnglish>45.00</stuEnglish> <stuComputer>56.00</stuComputer> <stuGrade>-1</stuGrade> </student> <student id="1002"> <stuName>老狼</stuName> <stuMath>25.00</stuMath> <stuEnglish>16.00</stuEnglish> <stuComputer>56.00</stuComputer> <stuGrade>-1</stuGrade> </student> <student id="1003"> <stuName>行者</stuName> <stuMath>34.00</stuMath> <stuEnglish>13.00</stuEnglish> <stuComputer>77.00</stuComputer> <stuGrade>-1</stuGrade> </student> <student id="1004"> <stuName>天涯</stuName> <stuMath>34.00</stuMath> <stuEnglish>18.00</stuEnglish> <stuComputer>88.00</stuComputer> <stuGrade>-1</stuGrade> </student> <student id="1005"> <stuName>散人</stuName> <stuMath>34.00</stuMath> <stuEnglish>99.00</stuEnglish> <stuComputer>56.00</stuComputer> <stuGrade>-1</stuGrade> </student> </stulist>