学生信息管理系统
这是我们老师的一个大作业,要求如下:
综合训练项目一 线性结构综合训练
目的和要求:线性结构是最基础,也是最重要的一种结构,通过此项训练让学生掌握线性结构的知识;要求编程实现学生成绩管理系统,使学生掌握线性结构的存储 及相关算法设计;设有一个学生文件,其结构为:学号、姓名、数学成绩、英语成绩、计算机成绩、总分、平均分、排名。要求用顺序和链式两种方式进行存储,并 在此基础上实现学生成绩的录入、保存、计算总分和平均分、排名、查询、统计等基本功能。
我最初的代码在:http://my.oschina.net/iamhere/blog/340999
而我现在写的带libxml2的代码如下:
test.c//程序入口,目前只是测试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;
}
student.h//学生结构及其操作定义
/**
* @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_ */
student.c//学生操作实现
#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;
}
studentList.h//学生列表定义及其操作声明
/**
* @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_ */
studentList.c//学生列表操作实现
#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;
}
stuxml.h//xml操作声明
/** @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_ */
stuxml.c//xml操作实现
#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;
}
输入的文件文件:以Tab键作为分隔符
1001 小代码 34 45 56
1002 老狼 25 16 56
1003 行者 34 13 77
1004 天涯 34 18 88
1005 散人 34 99 56
输出的XML文件:
<?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>