程序设计基础(C)大作业——学籍管理系统(3)(完)

xiaoxiao2021-02-28  105

最后,将写完的代码贴上来

一点说明: 1、目前还有一些bug,在ID被判重复后输入0,有时会使得程序崩溃,时间原因尚未解决 2、中英文的注释混杂,并不是一个好习惯。写的过程中试图让自己以全英文注释,并严格按格式注释。但由于时间关系或英文水平的限制,既没有按照格式来注释,也没有做到全英文。 3、链表的建立、validate并不是很让我满意,感觉还有可以优化的地方。 4、sort用了选择排序,find只是逐个比较来查找,并没有学到什么新的算法,也没有搜一搜适合链表的查找算法。这里或许可以做很多优化。 5、文件的读写过于频繁。还不会随机读写,或许这里也可以进一步优化。 6、之所以主界面里面没有单独的排序功能,是因为添加、更新数据后都会重新排序一次并保存在文件中。 7、交互界面并不令我满意。很简陋。 8、在前期没有把函数的实现方法想明白,导致main.c中controller函数很复杂。或许可以改进一下delete、update等函数,使得代码更简洁,重复代码更少。并且使得variance、delete、update等函数用法更加一致。 9、程序写完之后才意识到没有输出均值,于是临时添加全局变量m_ave。 10、在学生姓名发生重复时,无法同时查找到这些学生。

——————————————

20170508修复了update时无法更新的问题。

——————————————

20170520结构体可以用=直接赋值,可以将swap函数省略了但还没有改

——————————————

app.c

#include "final.h" /** *selectsort by cls & sub-by name *by cantjie */ stu *sort(stu *head) { //遍历链表,每次找出一个最小的节点,将其值与未排序节点的首个节点交换,这里需要一个指针标记值最小的节点。 stu *p1, *p2, *min; for (p1 = head->next; p1->next != NULL; p1 = p1->next) { min = p1; for (p2 = p1->next; p2; p2 = p2->next)//由前向后遍历,找出最小的节点 { if (p2->cls<min->cls) min = p2; else { if (p2->cls == min->cls) { if (strcmp(p2->name, p1->name) < 0) { swapStu(p1, p2); } } } } if (min != p1) swapStu(p1, min); } saveStu(head->next, 0); m_head = head; return head; } /** *检查id 是否重复,如果id重复,返回1。不重复返回0 */ int validate(stu *head, int id) { stu *p = head; int flag = 0;//因为会遇到自己,设置一个flag,当flag为2时表示有重复; while (p->next) { if (p->next->id == id) { if (flag) return 1; flag++; } p = p->next; } if (m_head != head) { p = m_head; if (p == NULL) return 0; while (p->next) { if (p->next->id == id) return 1; else p = p->next; } return 0; } } /** *计算方差,包含三种格式: *1、输入0,返回所有学生方差; *2、输入1,输入cls,返回该班学生的方差; *3、输入2,然后输入id范围,返回方差; *by cantjie */ float varianceStu(stu *head) { int flag = -1; int n = 0; int idmax=0, idmin=0;//for case 2 int id = 0;//for case 3 float var=0, sum=0, ave=0; int i = 0; stu *p = head; printf("\ninput 0 to get all students' variance"); printf("\ninput 1 to get variance of students of a class"); printf("\ninput 2 to get varicance of students of a range of ids\n"); scanf("%d", &flag); switch (flag) { case 0://全体方差 for (i = 0; i < m_n; i++) { sum += p->next->sum; p = p->next; } ave = sum / m_n; p = head; for (i = 0; i < m_n; i++) { var += (p->next->sum - ave)*(p->next->sum - ave); p = p->next; } var /= m_n; break; case 1://返回班级方差 printf("\nPlease input class:"); int cls = 0; scanf("%d", &cls); for (i = 0; i < m_n; i++) { if (p->next->cls == cls) { sum += p->next->sum; n++; } p = p->next; } ave = sum / n; p = head; for (i = 0; i < m_n; i++) { if (p->next->cls == cls) { var += (p->next->sum - ave)*(p->next->sum - ave); } p = p->next; } var /= n; break; case 2://id范围 printf("\nPlease input the range of ID:(from...to...)"); scanf("%d%d", &idmin, &idmax); if (idmin > idmax) return 0; p = head; n = 0; for (i = 0; i < m_n; i++) { if (p->next->id >= idmin && p->next->id <= idmax) { sum += p->next->sum; n++; } p = p->next; } ave = sum / n; p = head; for (i = 0; i < m_n; i++) { if (p->next->id >= idmin && p->next->id <= idmax) { var += (p->next->sum - ave)*(p->next->sum - ave); } p = p->next; } var /= n; break; //这个功能有问题。时间不够,放弃了 /* case 3://连续输入ID printf("\nPlease input student id:(input 0 to stop input)"); while (scanf("%d", &id)) { if (id == 0) break; for (i = 0; i < m_n; i++) { if (p->next->id == id) { n++; sum += p->next->sum; } p = p->next; } ave = sum / n; p = head; for (i = 0; i < m_n; i++) { if (p->next->id == id) { var += (p->next->sum - ave)*(p->next->sum - ave); } } var /= n; } break;*/ default: break; } m_ave=ave; return var; } /** *by cantjie */ stu *create()//创建或写入新的学生数据 { int i = 0; stu *head = NULL;//指向链表头,链表头一般不存信息。 stu *p1 = NULL, *p2 = NULL;//p1指向新创建的链表,p2是原链表的尾部 p1 = (stu *)malloc(LEN); if (p1 == NULL) { printf("\nFail to create it,please try again later.\n"); return NULL; } head = p1; head->id = -1; p2 = p1 = (stu *)malloc(LEN); if (p1 == NULL) { printf("\nFail to create it,please try again later.\n"); return NULL; } else { head->next = p1; p1->next = NULL; printf("\nPlease input student ID(0 to stop):"); scanf("%d", &(p1->id)); } if (p1->id == 0) { return 0; } while (p1->id != 0) { p2->next = p1; p1->next = NULL;//通过调试可以发现如果不加这两句命令,连着输入两次相同ID,validate无法检测出来 if (validate(head, p1->id)) { printf("\nThis id has already existed,please try again."); printf("\nPlease input student ID(0 to stop):"); scanf("%d", &(p1->id)); if (p1->id == 0) p2->next = NULL;//与上面那句命令对应 continue; } else { p2->next = p1; p2 = p1; printf("\nPlease input class:"); scanf("%d", &(p1->cls)); printf("\nPlease input name(no more than 20 characters):"); //scanf("%s", p1->name); 如果用scanf的话,无法保存空格 fflush(stdin);//当gets前面有scanf时,scanf余留下来的换行符会被gets读取,因此用fflush(stdin)刷新缓存区。 gets(p1->name); printf("\nPlease input scores of 3 subjects:"); p1->sum = 0; for (i = 0; i < 3; i++) { scanf("%f", &(p1->score[i])); p1->sum += p1->score[i]; } m_n++; p2->next = NULL; p1 = (stu *)malloc(LEN);//下面free的是这个p1 if (p1 == NULL) { printf("\nFail to create it,please try again later.\n"); return NULL; } else { printf("\nPlease input student ID(0 to stop):"); scanf("%d", &(p1->id)); } } } free(p1); saveStu(head->next, 1); return sort(readStu()); } /** *显示学生信息 */ void showStu(stu *p) { if (p == NULL) { printf("No such a student"); return; } printf("\n%-20s|]|]|%6.1f|%6.1f|%6.1f|%5.1f", p->name, p->id, p->cls, p->score[0], p->score[1], p->score[2], p->sum); } /** *删除学生信息 *传入的参数为要删除的学生的前一个学生的指针 *by cantjie */ void deleteStu(stu *p) { if (p == NULL) { printf("\nNo such a student."); return; } stu *temp = p->next; p->next = p->next->next; free(temp); saveStu(m_head->next, 0); m_n--; } /** *更新、修改学生信息 *传入的参数为要更改的学生的指针 *by cantjie */ void updateStu(stu *p) { if (p == NULL) { printf("\nNo such a student"); return; } showTitle(); showStu(p); int i, temp, temp2; printf("\nPlease input student ID:"); scanf("%d", &temp); if (temp == 0) return; if (temp != 0 && temp != p->id) { while (validate(m_head, temp)) { printf("\nThis id has already existed,please try again."); printf("\nPlease input student ID(0 to stop):"); scanf("%d", &temp); if (temp == 0) return; if (temp == p->id) break; } } p->id = temp; printf("\nPlease input class:"); scanf("%d", &(p->cls)); printf("\nPlease input name(no more than 20 characters):"); fflush(stdin);//当gets前面有scanf时,scanf余留下来的换行符会被gets读取,因此用fflush(stdin)刷新缓存区。 gets(p->name); printf("\nPlease input scores of 3 subjects:"); p->sum = 0; for (i = 0; i < 3; i++) { scanf("%f", &(p->score[i])); p->sum += p->score[i]; } saveStu(m_head->next, 0); sort(m_head); }

——————————————

common.c

#include "final.h" /** *通过学号或者姓名查找学生,用在其他函数中 *返回该学生前一个学生的指针 *重名问题暂时还没有解决,只能返回一个学生 *by cantjie */ stu *findStu(stu *head, int id, char *name) { if (id == 0) { while (head->next) { if (strcmp(head->next->name, name) == 0) return head; else head = head->next; } //printf("Cannot find a student named %s", name); return NULL; } else { while (head ->next) { if (head->next->id == id) return head; else head = head->next; } //printf("Cannot find a student whose id is %d", id); return NULL; } return 0; } /** *swap the two Stu structure *by cantjie */ void swapStu(stu *p1, stu *p2) { int tempi; float tempf; char tempc[20]; int i = 0; tempi = p1->id; p1->id = p2->id; p2->id = tempi; tempi = p1->cls; p1->cls = p2->cls; p2->cls = tempi; strcpy(tempc, p1->name); strcpy(p1->name, p2->name); strcpy(p2->name, tempc); for (i = 0; i < 3; i++) { tempf = p1->score[i]; p1->score[i] = p2->score[i]; p2->score[i] = tempf; } tempf = p1->sum; p1->sum = p2->sum; p2->sum = tempf; }

——————————————

file.c

#include "final.h" /** *每次删除或更新等操作后,要把内存里的数据写入文件,flag表示模式,为1表示追加,为0表示重写 *put data in memory into _FILENAME_ in harddisk,used every time update or delete the data *by cantjie */ void saveStu(stu *head, int flag) { if (!head) { return; } FILE *fp = NULL; if (flag == 1) fp = fopen(_FILENAME_, "ab"); else { if (flag == 0) fp = fopen(_FILENAME_, "wb"); } if (fp == NULL) { fp = fopen(_FILENAME_, "wb"); if (fp == NULL) { printf("\nCannot open or create the file"); return; } } do { fwrite(head, sizeof(stu), 1, fp); head = head->next; } while (head); fclose(fp); } /** *把文件里的数据读取到内存中 *put data in harddisk into memory *by cantjie */ stu *readStu() { stu *head = NULL, *tail = NULL, *p1 = NULL;//tail是原链表的尾,p1是新开辟的空间 FILE *fp; fp = fopen(_FILENAME_, "rb"); if (fp == NULL) { fp = fopen(_FILENAME_, "wb"); if (fp == NULL) printf("Fail to open or create %s in function readStu", _FILENAME_); return NULL; } m_n = 0; p1 = (stu *)malloc(LEN); if (p1 == NULL) { printf("Fail to allocate memory for a new stu structure in function readStu."); fclose(fp);//如果没有成功开辟内存,还要把文件关闭 return 0; } head = tail = p1; tail->next = NULL; while (!feof(fp)) { p1 = (stu *)malloc(LEN); if (p1 == NULL) { printf("Fail to allocate memory for a new stu structure in function readStu."); fclose(fp);//如果没有成功开辟内存,还要把文件关闭 return 0; } if (!fread(p1, sizeof(stu), 1, fp)) { free(p1); return head; } tail->next = p1; tail = p1; tail->next = NULL;//保证尾指向空 m_n++; } fclose(fp); m_head = head; return head; }

——————————————

main.c

#include "final.h" #include<math.h> /** *显示学生信息前显示表头 */ void showTitle() { printf("\n%-20s|%5s|%5s|score1|score2|score3|sum", "name", "ID", "class", "score1", "score2", "score3", "sum"); } /** *用在main函数,输入功能后进入此函数 */ void controller(int flag) { //通过这里面的代码,或许可以考虑重新写一下findStu或重写deleteStu,updateStu int i = 0; int a = 0; stu *temp; float var; char name[20]; switch (flag) { case 1: if (m_head == NULL || m_head->next == NULL) { printf("\nNo student data."); break; } temp = m_head; printf("\ninput 0 to show all students' information"); printf("\nor input 1 and then an id or 2 and then a name to show one:"); scanf("%d", &a); if (a == 0) { showTitle(); while (temp->next) { showStu(temp->next); temp = temp->next; } } else { if (a == 1) { printf("id:"); scanf("%d", &a); if (a == 0) { printf("\n0 is not an legal ID."); break; } temp = findStu(m_head, a,NULL ); if (temp == NULL) { printf("\nNo such a student"); break; } showTitle(); showStu(temp->next); } else { if (a == 2) { printf("name:"); fflush(stdin); gets(name); temp = findStu(m_head, 0, name); if (temp == NULL) { printf("\nNo such a student"); break; } showTitle(); showStu(temp->next); } } } break; case 2: create(); break; case 3: if (m_head == NULL || m_head->next == NULL) { printf("\nNo student data."); break; } temp = m_head; printf("\ninput 1 and then an id or 2 and then a name to delete:"); scanf("%d", &a); if (a == 1) { printf("id:"); scanf("%d", &a); if (a == 0) { printf("\n0 is not an legal ID."); break; } deleteStu(findStu(m_head, a, NULL)); } else { if (a == 2) { printf("name:"); fflush(stdin); gets(name); deleteStu(findStu(m_head, 0, name)); } } break; case 4: if (m_head == NULL || m_head->next == NULL) { printf("\nNo student data."); break; } temp = m_head; printf("\ninput 1 and then an id or 2 and then a name to update:"); scanf("%d", &a); if (a == 1) { printf("id:"); scanf("%d", &a); updateStu(findStu(m_head, a, NULL)->next); } else { if (a == 2) { printf("name:"); fflush(stdin); gets(name); updateStu(findStu(m_head, 0, name)->next); } } break; case 5: if (m_head == NULL || m_head->next == NULL) { printf("\nNo student data."); break; } var=varianceStu(m_head); printf("average:%f,variance:%f,Standard Deviation:%f", m_ave,var, sqrt(var)); break; case 6: exit(0); } } /** *print function list *by cantjie */ void printFunctionList() { printf("\n_____________________________________"); printf("\n1.print students' information"); printf("\n2.add a new student"); printf("\n3.delete a student"); printf("\n4.update a student"); printf("\n5.show the analysis of students' grade"); printf("\n6.exit"); printf("\nInput a number to choose function:"); } /** *let user to choose function,after printing function list *by cantjie */ void chooseFunction() { int flag = 0; printFunctionList(); while (scanf("%d", &flag)) { if (flag < 1 && flag>6) { printf("\nError!"); printFunctionList(); continue; } else { controller(flag); printFunctionList(); } } } int main() { m_head=readStu(); chooseFunction(); return 0; }
转载请注明原文地址: https://www.6miu.com/read-40976.html

最新回复(0)