//学生管理系统 完成时间2013 06 08 //大一第一次课程设计 #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 3 #define LEN (Student*) malloc(sizeof(Student)) /* 学生数据结构 */ typedef struct node { char num[20]; char name[15]; int score[N]; int sum; double ave; struct node *next; } Student; /* 头指针 */ Student *head = NULL; /* 临时指针 */ Student *tmp = NULL; /* 课程名称 */ char CLASSNAME[N][30] = {"大物", "高数", "c语言"}; /* 命令开关 */ int SWITCH[16] = {0}; /*所有的 函数声明 */ int Menu(); Student* Init(); int CheckNUM(char*); int CheckName(char*); int CheakScore(int score); int Same_NUM(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("LOOK...初始化成功\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; // 本来想取消复制函数,有一个问题,如果同时取消break 程序会奇怪的出死循环,还没有解决 2013 06 13 /* 排序,按总分排序并打印学生信息 */ 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("*********************************************************************\n"); printf("*********************************************************************\n"); 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("********************************************************************\n"); printf("请输入命令编号: "); scanf("%d", &n); return n; } /* 初始化 */ Student* Init() { int i; Student *head; head = LEN; head->next = NULL; /* 命令开关初始化 */ for (i = 1; i < 16; i++) { SWITCH[i] = 0; } SWITCH[1] = 1; SWITCH[6] = 1; return head; } /* 检查学号,要求必须是数字 */ int CheckNUM(char* s) { int i; if (strlen(s) == 0 || strlen(s) > 10) 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) > 15) 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 Same_NUM(char* s) { Student *p = head->next; while(p != NULL) { if (strcmp(s, p->num) == 0) return 1; p = p->next; } return 0; } /* 给p指向的节点输入信息 */ void InputNodeInfo(Student* p) { int i; fflush(stdin); //实验室人介绍说gcc 下没用 2013 06 07 早 /* 学号 */ printf("\n请输入学号: "); do { gets(p->num); if (!CheckNUM(p->num)) { printf("数据不标准,请重新输入学号: "); } else if (Same_NUM(p->num)) { printf("检测到此学号存在,请重新输入: "); } }while (!(CheckNUM(p->num) && !Same_NUM(p->num))); /* 姓名 */ printf("请输入姓名: "); do { gets(p->name); // getchar(); // 2013 06 13增加,会出现死循环现象 if (!CheckName(p->name)) { printf("数据不标准,请重新输入姓名: "); } } while (!CheckName(p->name)); /* 成绩 */ for (i = 0; i < N; 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])); getchar(); } /* 总分及平均分 */ //后面通过计算得出 p->sum = 0; p->ave = 0; } /* 输出p指向节点的信息 */ void OutputNodeInfo(Student* p) { int i; printf("\n"); printf("姓名: %s\n", p->name); printf("学号: %s\n", p->num); for (i = 0; i < N; 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指向的节点 */ //删除的思路,保留下自己需要的部分也就是删除不要(哲学思想 空) DeleteNode(Student* r) { Student *p = SearchFrontNode(r); p->next = r->next; } /* 头插法插入节点 */ void InsertBefore() { Student *s = LEN; InputNodeInfo(s); s->next = head->next; head->next = s; } /* 输入链表 */ void InputList() { int n; printf("有多少个学生信息要输入? "); scanf("%d", &n); getchar(); while (n--) //简化之后 { InsertBefore(); } } /* 按学号查找 */ Student* SearchID(char* num) { Student *p = head->next; while (p != NULL) { if (strcmp(p->num, num) == 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 (!(CheckNUM(str) || CheckName(str))) //多次修改 { printf("数据不标准,请重新输入姓名或学号: "); } } while (!(CheckNUM(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 { getchar(); 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 < N; i++) { sum += p->score[i]; } p->sum = sum; p->ave = sum * 1.0 /N; p = p->next; } } /* 比较学号 */ int CmpID(Student* a, Student* b, int k) { return strcmp(a->num, b->num); } /* 比较总分 */ 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) //直接应用的是逗号运算表达试的值为最后一个 P25 { Student *newhead = LEN; 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; } /* 将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; int i; Student *p; char file[20]; fflush(stdin); printf("请输入要保存的文件名: "); scanf("%s",file); getchar(); if ((fp = fopen(file, "wt")) == NULL) { printf("写文件错误.......!\n"); return; } for(p = head->next;p!=NULL;p=p->next) //此段中大括号的使用位置错误直接导致程序出现严重的段错误(linux实验室) { fprintf(fp,"%s %s\n",p->name,p->num ); for(i=0;i<=2;i++) { fprintf(fp,"%d\n",p->score[i]); } } 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("请输入文件名: "); getchar(); gets(file); if ((fp = fopen(file, "rt")) == NULL) { printf("对不起,无法打开文件!\n"); return; } /* 文件未结束时读入数据 */ while (!feof(fp)) { Student *s = LEN; fscanf(fp, "%s %s", s->name,s->num); for (i = 0; i < N; i++) { fscanf(fp, "%d\n", &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 = LEN; InputNodeInfo(tmp); SWITCH[12] = 1; } /* 分类统计 */ void Stat() { int i, j, n = 0; int sum[N] = {0}; Student *p = head->next; if (p == NULL) { printf("暂无学生信息,无法统计\n"); return; } /* 统计各科总分 */ while (p != NULL) { /* 记录学生总数 */ n++; for (i = 0; i < N; i++) { sum[i] += p->score[i]; } p = p->next; } /* 各科分别输出 */ for (i = 0; i < N; 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("第%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); }
学生管理系统
司联波