Slyar
2009.12.1
学生成绩管理系统 C语言
*/
#include #include #include #define CLASS 6 #define MAXID 10 #define MAXNAME 15 #define MALLOC (Student*) malloc(sizeof(Student)) /* 学生数据结构 */ typedef struct node { char id[20]; char name[15]; int score[CLASS]; int sum; double ave; struct node *next; } Student; /* 头指针 */ Student *head = NULL; /* 临时指针 */ Student *tmp = NULL; /* 课程名称 */ char CLASSNAME[CLASS][30] = {"物理", "化学", "计算机", "英语", "数学", "体育"}; /* 命令开关 */ int SWITCH[16] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* 函数声明 */ int Menu(); Student* Init(); int CheckID(char*); int CheckName(char*); int CheakScore(int score); int IsSameID(char*); void InputNodeInfo(Student*); void OutputNodeInfo(Student*); Student* SearchFrontNode(Student*); void DeleteNode(Student*); void InsertBefore(); void InputList(); Student* SearchID(char*); Student* SearchName(char*); void SearchDeleteNode(); void OutList(); void SearchPrintNode(); void Compute(); int CmpID(Student*, Student*, int); int CmpSum(Student*, Student*, int); int CmpScore(Student*, Student*, int); Student* SearchMaxNode(int (*cmp)(Student*, Student*, int), int); Student* Sort(int (*cmp)(Student*, Student*, int), int); void OutputToFile(FILE*, Student*, int); void InsertAfter(Student*); void SaveToFile(); void LoadFile(); void CopyFile(); void InsertToFile(); void FreeList(Student* p); void Stat(); void Quit(); /* 主函数 */ int main() { int n; while (1) { n = Menu(); { if (n == 1 || n == 15 || SWITCH[1]) { switch (n) { /* 执行初始化 */ case 1: head = Init(); printf("初始化成功\\n"); break; /* 创建链表 */ case 2: InputList(); break; /* 删除记录 */ case 3: SearchDeleteNode(); break; /* 显示全部记录 */ case 4: system("cls"); OutList(); break; /* 查找记录 */ case 5: SearchPrintNode(); break; /* 保存文件 */ case 6: SaveToFile(); break; /* 读文件 */ case 7: if (SWITCH[6]) { head = Init(); LoadFile(); } else { printf("当前文件未保存\\n"); } break; /* 计算总分和均分 */ case 8: Compute(); SWITCH[8] = 1; printf("计算完毕\\n"); break; /* 插入记录 */ case 9: InsertBefore(); SWITCH[6] = 0; SWITCH[8] = 0; break; /* 复制文件 */ case 10: CopyFile(); break; /* 排序 */ case 11: if (SWITCH[8]) { head = Sort(CmpSum, 0); system("cls"); OutList(); } else { printf("请先计算总分!\\n"); } break; /* 追加记录 */ case 12: InsertToFile(); SWITCH[6] = 0; printf("追加完毕!\\n"); break; /* 索引 */ case 13: if (SWITCH[8]) { head = Sort(CmpID, 0); system("cls"); OutList(); } else { printf("请先计算总分!\\n"); } break; /* 分类合计 */ case 14: system("cls"); Stat(); break; /* 结束 */ case 15: Quit(); break; default: printf("无效命令!\\n"); fflush(stdin); } system("pause"); } else { printf("你必须首先初始化!\\n"); system("pause"); } } } system("pause"); return 0; } /* 菜单 */ int Menu() { int n; system("cls"); fflush(stdin); printf("【01】 初始化\\n"); printf("【02】 输入学生信息\\n"); printf("【03】 查找学号或姓名删除信息\\n"); printf("【04】 打印全部学生信息\\n"); printf("【05】 按姓名查找学生信息\\n"); printf("【06】 保存到文件\\n"); printf("【07】 从文件中读取学生信息\\n"); printf("【08】 计算所有学生的总分和平均分\\n"); printf("【09】 插入一个学生信息到链表中\\n"); printf("【10】 复制文件\\n"); printf("【11】 按总分排序并打印学生信息\\n"); printf("【12】 追加一个学生信息到文件中\\n"); printf("【13】 按学号索引学生信息\\n"); printf("【14】 分类汇总\\n"); printf("【15】 退出\\n"); printf("请输入命令编号: "); scanf("%d", &n); return n; } /* 初始化 */ Student* Init() { int i; Student *head; head = MALLOC; head->next = NULL; /* 命令开关初始化 */ for (i = 1; i < 16; i++) { SWITCH[i] = 0; } SWITCH[1] = 1; SWITCH[6] = 1; return head; } /* 检查学号 */ int CheckID(char* s) { int i; if (strlen(s) == 0 || strlen(s) > MAXID) return 0; for (i = 0; i < strlen(s); i++) { if (s[i] < '0' || s[i] > '9') return 0; } return 1; } /* 检查姓名 */ int CheckName(char* s) { int i; if (strlen(s) == 0 || strlen(s) > MAXNAME) return 0; for (i = 0; i < strlen(s); i++) { if (!(s[i] >= 'a' && s[i] <= 'z' || s[i] >= 'A' && s[i] <= 'Z')) return 0; } return 1; } /* 检查分数 */ int CheakScore(int score) { if (score > 100 || score <= 0) return 0; return 1; } /* 检查相同学号 */ int IsSameID(char* s) { Student *p = head->next; while(p != NULL) { if (strcmp(s, p->id) == 0) return 1; p = p->next; } return 0; } /* 给p指向的节点输入信息 */ void InputNodeInfo(Student* p) { fflush(stdin); /* 学号 */ printf("\\n请输入学号: "); do { gets(p->id); if (!CheckID(p->id)) { printf("数据违法,请重新输入学号: "); } else if (IsSameID(p->id)) { printf("已存在此学号,请重新输入: "); } }while (!(CheckID(p->id) && !IsSameID(p->id))); /* 姓名 */ printf("请输入姓名: "); do { gets(p->name); if (!CheckName(p->name)) { printf("数据违法,请重新输入姓名: "); } } while (!CheckName(p->name)); /* 成绩 */ int i; for (i = 0; i < CLASS; i++) { printf("请输入 %s 成绩: ", CLASSNAME[i]); do { fflush(stdin); scanf("%d", &p->score[i]); if (!CheakScore(p->score[i])) { printf("数据违法,请重新输入 %s 成绩: ", CLASSNAME[i]); } } while (!CheakScore(p->score[i])); } /* 总分及平均分 */ p->sum = -1; p->ave = -1; } /* 输出p指向节点的信息 */ void OutputNodeInfo(Student* p) { int i; printf("\\n"); printf("姓名: %s\\n", p->name); printf("学号: %s\\n", p->id); for (i = 0; i < CLASS; i++) { printf("%s 成绩: %d\\n", CLASSNAME[i], p->score[i]); } /* 计算过才输出 */ if (SWITCH[8]) printf("总分: %d\\n", p->sum); if (SWITCH[8]) printf("平均分: %.2lf\\n", p->ave); } /* 返回r的前一个节点 */ Student* SearchFrontNode(Student* r) { Student *p = head; while (p->next != r) p = p->next; return p; } /* 删除r指向的节点 */ void DeleteNode(Student* r) { Student *p = SearchFrontNode(r); p->next = r->next; } /* 头插法插入节点 */ void InsertBefore() { Student *s = MALLOC; InputNodeInfo(s); s->next = head->next; head->next = s; } /* 输入链表 */ void InputList() { int n; printf("有多少个学生信息要输入? "); scanf("%d", &n); while (n--) { InsertBefore(); } } /* 按学号查找 */ Student* SearchID(char* id) { Student *p = head->next; while (p != NULL) { if (strcmp(p->id, id) == 0) break; p = p->next; } return p; } /* 按姓名查找 */ Student* SearchName(char* name) { Student *p = head->next; while (p != NULL) { if (strcmp(p->name, name) == 0) break; p = p->next; } return p; } /* 按学号或姓名查找删除节点 */ void SearchDeleteNode() { Student *p; fflush(stdin); char str[20]; char sure[20]; /* 输入合法性判断 */ printf("请输入你要删除的学生的 姓名 或 学号: "); do { gets(str); if (!(CheckID(str) || CheckName(str))) { printf("数据违法,请重新输入姓名或学号: "); } } while (!(CheckID(str) || CheckName(str))); /* 判断是姓名还是学号 */ if (str[0] >= '0' && str[0] <= '9') { p = SearchID(str); if (p == NULL) { printf("对不起,找不到这个学号\\n"); } else { OutputNodeInfo(p); printf("确认删除? (输入\\"y\\"确认,任意键取消): "); if (strcmp(gets(sure), "y") == 0) { DeleteNode(p); printf("删除成功\\n"); SWITCH[6] = 0; } fflush(stdin); } } else { p = SearchName(str); if (p == NULL) { printf("对不起,找不到这个姓名\\n"); } else { OutputNodeInfo(p); printf("确认删除? (输入\\"y\\"确认,任意键取消): "); if (strcmp(gets(sure), "y") == 0) { DeleteNode(p); printf("删除成功!\\n"); SWITCH[6] = 0; } fflush(stdin); } } } /* 输出链表 */ void OutList() { Student *p = head->next; /* 空表处理 */ if (p == NULL) { printf("暂无学生信息!\\n"); } while (p != NULL) { OutputNodeInfo(p); p = p->next; } } /* 按姓名查找记录并打印 */ void SearchPrintNode() { Student *p = head->next; int ok = 1; char name[20]; fflush(stdin); /* 姓名合法性判断 */ printf("请输入你要查找的学生姓名: "); do { gets(name); if (!CheckName(name)) { printf("数据违法,请重新输入姓名: "); } } while (!CheckName(name)); /* 按姓名查找节点 */ while (p != NULL) { if (strcmp(p->name, name) == 0) { ok = 0; OutputNodeInfo(p); } p = p->next; } if (ok) { printf("对不起,找不到这个姓名\\n"); } } /* 计算总分和均分 */ void Compute() { int i; Student *p = head->next; while (p != NULL) { int sum = 0; for (i = 0; i < CLASS; i++) { sum += p->score[i]; } p->sum = sum; p->ave = sum * 1.0 / CLASS; p = p->next; } } /* 比较学号 */ int CmpID(Student* a, Student* b, int k) { return strcmp(a->id, b->id); } /* 比较总分 */ int CmpSum(Student* a, Student* b, int k) { return b->sum - a->sum; } /* 比较各科分数 */ int CmpScore(Student* a, Student* b, int k) { return b->score[k] - a->score[k]; } /* 选择最大元素 */ Student* SearchMaxNode(int (*cmp)(Student* a, Student* b, int k), int k) { Student *p = head->next; Student *max = p; while (p != NULL) { if (cmp(p, max, k) < 0) { max = p; } p = p->next; } return max; } /* 排序 */ Student* Sort(int (*cmp)(Student* a, Student* b, int k), int k) { Student *newhead = MALLOC; Student *p = newhead; Student *max; while (head->next != NULL) { max = SearchMaxNode(cmp, k); p->next = max; DeleteNode(max); p = p->next; } /* 表尾处理 */ p->next = NULL; return newhead; } /* 输出p指向节点的信息到文件 */ void OutputToFile(FILE* fp, Student* p, int newline) { int i; fprintf(fp, "%s\\n", p->name); fprintf(fp, "%s\\n", p->id); for (i = 0; i < CLASS - 1; i++) { fprintf(fp, "%d\\n", p->score[i]); } /* 尾行处理 */ if (newline) { fprintf(fp, "%d\\n", p->score[i]); } else { fprintf(fp, "%d", p->score[i]); } } /* 将s插入链表尾部 */ void InsertAfter(Student* s) { Student *p = head; while (p->next != NULL) p = p->next; s->next = NULL; p->next = s; } /* 保存到文件 */ void SaveToFile() { /* 处理追加表尾情况 */ if (SWITCH[12]) { InsertAfter(tmp); } FILE *fp; char file[20]; fflush(stdin); printf("请输入文件名: "); gets(file); if ((fp = fopen(file, "wt+")) == NULL) { printf("对不起,无法创建文件!\\n"); return; } Student *p = head->next; while (p != NULL) { if (p->next != NULL) { OutputToFile(fp, p, 1); } else { OutputToFile(fp, p, 0); } p = p->next; } printf("文件保存成功!\\n"); fclose(fp); SWITCH[6] = 1; /* 处理追加表尾情况 */ if (SWITCH[12]) { DeleteNode(tmp); SWITCH[12] = 0; } } /* 从文件中读入记录 */ void LoadFile() { int i; FILE *fp; char file[20]; fflush(stdin); printf("请输入文件名: "); gets(file); if ((fp = fopen(file, "rt")) == NULL) { printf("对不起,无法打开文件!\\n"); return; } /* 文件未结束时读入数据 */ while (!feof(fp)) { Student *s = MALLOC; fscanf(fp, "%s", s->name); fscanf(fp, "%s", s->id); for (i = 0; i < CLASS; i++) { fscanf(fp, "%d", &s->score[i]); } s->next = head->next; head->next = s; } printf("文件读取成功!\\n"); fclose(fp); } /* 复制文件 */ void CopyFile() { FILE *fp1, *fp2; char ch, file1[20], file2[20]; fflush(stdin); /* 读入源文件 */ printf("请输入源文件名: "); gets(file1); if ((fp1 = fopen(file1, "rb")) == NULL) { printf("对不起,无法打开文件!\\n"); return; } /* 读入目标文件 */ printf("请输入目标文件名: "); gets(file2); if ((strcmp(file1, file2) == 0) || ((fp2 = fopen(file2, "wb")) == NULL)) { printf("对不起,无法创建文件!\\n"); return; } /* 逐个字符拷贝 */ while (!feof(fp1)) { ch = fgetc(fp1); if (ch != EOF) fputc(ch, fp2); } fclose(fp1); fclose(fp2); printf("文件拷贝成功!\\n"); } /* 追加记录到文件中 */ void InsertToFile() { tmp = MALLOC; InputNodeInfo(tmp); SWITCH[12] = 1; } /* 分类统计 */ void Stat() { int i, j, n = 0; int sum[CLASS] = {0}; Student *p = head->next; if (p == NULL) { printf("暂无学生信息,无法统计\\n"); return; } /* 统计各科总分 */ while (p != NULL) { /* 记录学生总数 */ n++; for (i = 0; i < CLASS; i++) { sum[i] += p->score[i]; } p = p->next; } /* 各科分别输出 */ for (i = 0; i < CLASS; i++) { printf("%s 总均分: %.2lf\\n", CLASSNAME[i], sum[i] * 1.0 / n); head = Sort(CmpScore, i); j = 0; p = head->next; while (p != NULL) { j++; printf("NO.%d %s %d\\n", j, p->name, p->score[i]); p = p->next; } printf("\\n"); } } /* 释放链表 */ void FreeList(Student* p) { if (p->next != NULL) { FreeList(p->next); } free(p); } /* 退出 */ void Quit() { if (!SWITCH[6]) { printf("请先保存文件!\\n"); return; } if (head != NULL) { FreeList(head); } exit(0); }