两周的时间完成了这个作业,学生成绩管理系统。题目的要求是从文件中读取班级成绩原始记录,文件内容包括ID、姓名、语文成绩、数学成绩、平均成绩。要实现的功能有显示学生成绩信息,按照学生平均成绩进行排序,录入新的学生成绩记录,删除学生成绩记录这4个主要的功能。
拿到这个题目之后,第一考虑就是用链表来做,链表的结点是一个结构体,把学生的个人信息和成绩信息存放在这个结构体中。系统要求的功能也可以一一的转化为对于链表的操作。
(1)显示学生成绩就可以转化成循环链表,打印链表中每一个结点信息。
(2)按照学生平均成绩进行排序可以转化成,根据链表结点中平均成绩的值对链表进行重新排序,排序可以用冒泡排序的方法。
(3)录入新的学生成绩记录,可以转化成插入结点操作。
(4)删除学生成绩记录,可以转化成删除结点的操作。
1.系统界面和功能展示
根据题目的要求,设计了系统的主界面,
1、显示学生成绩信息
2、插入学生成绩信息
3.删除学生成绩信息
4、按照平均成绩排序
2、各功能代码
(1)头文件和结点结构体的定义
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #define MAX 10 typedef struct student * Student; static Student head; /*链表结点结构 *ID: 学生编号 *name: 学生姓名 *chgrade: 学生语文成绩 *mathgrade:学生数学成绩 *avegrade:学生平均成绩 *next: 下一个结点指针 * */ struct student { Student next; int ID; char name[MAX]; float chgrade; float mathgrade; float avegrade; };
(2)主函数,主界面的显示和各部分功能函数的调用
主函数主要就是界面的设计,主界面设计里一个主要的问题就是,一个功能实现之后,程序还是要运行,而不是退出程序,因此需要设计一个while循环,一直循环,只有用户想要退出该界面的时候,选择退出才退出。主函数中另外一个设计是判断程序运行的时候是否选择要打开的成绩文件,如果没有选择要打开的成绩文件,程序退出。该部分代码如下:
int main(int argc, char *argv[ ]) { int number = 0; int count = 0; int ID; char name[MAX]; if(argc < 2) { printf("input wrong, please check "); exit(1); } read_file(argv[1]); /*循环显示主选项单*/ while(number != 5) { printf("please select the option: "); printf("1.Display all student's info "); printf("2.Sort by average "); printf("3.Insert a new info "); printf("4.Delete a record "); printf("5.Quit "); printf("Please input your choices : "); scanf("%d", &number); if(number == 1) { print(); } if(number == 2) { ave(head); } if(number == 3) { insert(); } if(number == 4) { /*循环显示删除选项单*/ while(count != 3) { printf("Please choose the way "); printf("1.Delete by ID "); printf("2.Delete by name "); printf("3.exit "); printf("Your choice:"); scanf("%d", &count); if(count == 1) { printf("Pleas input the ID "); scanf("%d", &ID); del_ID(head,ID); } if(count == 2) { printf("Please input the name "); scanf("%s",name); printf("%s ", name); del_name(head, name); } if(count < 0 || count >3) { printf("please input right number "); } } count = 0; } } return 0; }
(3)成绩录入,在链表中插入结点
插入结点函数先从外部输入要插入结点的信息,然后进行插入链表的操作。本质上来说就是给结点赋值。先判断头结点是否为空,如果头结点为空,直接将结点信息赋值给头结点,头结点指向空结点;如果头结点不为空,找到链表中最后一个结点,将最后一个结点中的next指针指向要插入的结点,然后将要插入的信息赋值给新插入的结点,新插入的结点指向空,具体代码如下所示。
int insert() { int ID; char name[MAX]; float chgrade; float mathgrade; float avegrade; int i; printf("Please input the new info (ID name chgrade mathgrade avegrade) : "); scanf("%d %s%f%f%f", &ID, &name, &chgrade, &mathgrade, &avegrade); printf("input %d %s %f %f %f successfully ", ID, name ,chgrade, mathgrade, avegrade); printf(" "); Student p, q; p = head; if(p != NULL) { while(p->next != NULL) { p = p->next; } } q = (Student)malloc(sizeof(struct student)); if(q == NULL) return -1; q->next = NULL; q->ID = ID; for(i = 0; i < MAX; i++) { q->name[i] = name[i]; } q->chgrade = chgrade; q->mathgrade = mathgrade; q->avegrade = avegrade; if(p == NULL) { head = q; return 1; } p->next = q; }
(4)排序,按照平均成绩的高低排序
按照平均成绩排序就将按照平均成绩值的大小对链表进行冒泡排序,平均成绩低的结点在前边,平均成绩高的结点在后边。设置两个结构体指针,一个被对比的,一个是对比的,对比的指针向后移,被对比的指针在对比的指针循环完一次之后向后挪一次。也就是两个while循环,内循环循环对比的指针,是“冒泡”的过程,外循环循环被对比的指针。
int ave(struct student *head) { struct student *p1; struct student *p2; struct student *p3; int ID; float chgrade; float mathgrade; char name[MAX]; float avegrade; int count = 0; int i; if(head == NULL) { printf("no grades "); return head; } p1 = head; if(p1->next == NULL) { printf("success "); return head; } p2 = p1->next; while(p1->next != NULL) { while(p2 != NULL) { if(p1->avegrade < p2->avegrade) { p2 = p2->next; } else { ID = p2->ID; for(i = 0; i < MAX; i++) { name[i] = p2->name[i]; } mathgrade = p2->mathgrade; chgrade = p2->chgrade; avegrade = p2->avegrade; p2->ID = p1->ID; for(i = 0; i < MAX; i++) { p2->name[i] = p1->name[i]; } p2->chgrade = p1->chgrade; p2->mathgrade = p1->mathgrade; p2->avegrade = p1->avegrade; p1->ID = ID; //p1-> name = name; for(i = 0; i < MAX; i++) { p1->name[i] = name[i]; } p1->chgrade = chgrade; p1-> mathgrade = mathgrade; p1->avegrade = avegrade; p2 = p2->next; } } p1 = p1->next; p2 = p1->next; } print(); return head; }
(5)删除结点,删除学生信息,可以按照ID也可以按照姓名
按照学生ID删除学生信息,遍历链表查到链表中要删除的结点,然后将该结点的前一个结点的next指针指向改结点的下一个结点,释放该节点,代码如下。
int del_ID(struct student *head, int ID) { struct student *p1; struct student *p2; if(head == NULL) { printf("no grades "); return head; } p1 = head; while(p1->ID != ID && p1->next != NULL) { p2 = p1; p1 = p1->next; } if(p1->ID == ID) { if(p1 == head) { head = p1->next; } else { p2->next = p1->next; } free(p1); p1 = NULL; printf("delete %d success ", ID); } else { printf("%d not been found! "); } return head; } 按照学生姓名删除学生信息跟按照ID删除学生信息类似,区别在于遍历链表的时候,一个是找ID相同的结点,一个是寻找姓名相同的结点,代码如下。 int del_name(struct student *head, char name[MAX]) { struct student *p1; struct student *p2; if(head == NULL) { printf("no grades "); return head; } p1 = head; while(strcmp(p1->name,name) != 0 && p1->next != NULL) { p2 = p1; p1 = p1->next; } if(strcmp(p1->name,name) == 0) { if(p1 == head) { head = p1->next; } else { p2->next = p1->next; } free(p1); p1 = NULL; printf("delete %s successfully ", name); } else { printf("%s not be found", name); } print(); return head; }
(6)打印链表,显示学生成绩
遍历整个链表,分别按照一定的格式打印出链表中每个结点的信息,其中包括学生ID、学生姓名、学生数学成绩、学生语文成绩、学生平均成绩,代码如下。
int print(void) { int i = 1; Student p = head; printf("/***************************************************/ "); printf("seq ID NAME CHGRADE MATHGRADE AVEGRADE "); while(p != NULL) { printf("%d: %d %s %f %f %f ", i, p->ID, p->name, p->chgrade, p->mathgrade, p->avegrade); p = p->next; i++; } printf("/***************************************************/ "); } (7)读文件中的内容,插入链表 学生成绩存在txt文件中,txt文件都是以字符串的形式存储的,先将文件中的学生信息读出来分别存在字符串中,然后将相应的字符串转换成int型或者float型数字,然后将这些信息插入到链表中,具体代码如下。 int read_file(char *s) { FILE *fp; int n,i,j,k; int m = -1; Student p, q; int ID; //学生ID char name[MAX]; //学生姓名 float chgrade; //学生语文成绩 float mathgrade;//学生数学成绩 float avegrade; //学生平均成绩 char a[MAX]; //数组a,存储从文件中读出来的ID的字符串 char b[MAX]; //数组b,存储从文件中读出来的name的字符串 char c[MAX]; //数组c,存储从文件中读出来的chgrade的字符串 char d[MAX]; //数组d,存储从文件中读出来的mathgrade的字符串 char e[MAX]; //数组e,存储从文件中读出来的avegrade的字符串 fp = fopen(s, "r"); if(fp == NULL) { perror("fail to fopen"); exit(1); } while(j != -1) { j = fscanf(fp, " %[^ ] %[^ ] %[^ ] %[^ ] %[^ ]", a, b, c, d, e); m++; } fclose(fp); fp = fopen(s, "r"); if(fp == NULL) { perror("fail to fopen"); exit(1); } for(k = 0; k < m; k++) { n = fscanf(fp, " %[^ ] %[^ ] %[^ ] %[^ ] %[^ ]", a, b, c, d, e); ID = atoi(a); for(i = 0; i < MAX; i++) { name[i] = b[i]; } chgrade = atof(c); mathgrade = atof(d); avegrade = atof(e); p = head; if(p != NULL) { while(p->next != NULL) { p = p->next; } q = (Student)malloc(sizeof(struct student)); if(q == NULL) return -1; q->next = NULL; q->ID = ID; for(i = 0; i < MAX; i++) { q->name[i] = name[i]; } q->chgrade = chgrade; q->mathgrade = mathgrade; q->avegrade = avegrade; p->next = q; } else { q = (Student)malloc(sizeof(struct student)); if(q == NULL) return -1; q->next = NULL; q->ID = ID; for(i = 0; i < MAX; i++) { q->name[i] = name[i]; } q->chgrade = chgrade; q->mathgrade = mathgrade; q->avegrade = avegrade; head = q; } } }
两周的时间完成了这个小的作业,感觉长进了很多,从以前的抄写程序到自己写程序的过程中也意识到考虑问题的不全面,但是也是这两周一点一点的摸索找到了自己的解决问题的方法。编程在基础东西掌握了之后,最后还是逻辑思维的区别。
最后,代码综合起来如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #define MAX 10 typedef struct student * Student; static Student head; /*链表结点结构 *ID: 学生编号 *name: 学生姓名 *chgrade: 学生语文成绩 *mathgrade:学生数学成绩 *avegrade:学生平均成绩 *next: 下一个结点指针 * */ struct student { Student next; int ID; char name[MAX]; float chgrade; float mathgrade; float avegrade; }; /*成绩录入,在链表中插入结点*/ int insert() { int ID; char name[MAX]; float chgrade; float mathgrade; float avegrade; int i; printf("Please input the new info (ID name chgrade mathgrade avegrade) : "); scanf("%d %s%f%f%f", &ID, &name, &chgrade, &mathgrade, &avegrade); printf("input %d %s %f %f %f successfully ", ID, name ,chgrade, mathgrade, avegrade); printf(" "); Student p, q; p = head; if(p != NULL) { while(p->next != NULL) { p = p->next; } } q = (Student)malloc(sizeof(struct student)); if(q == NULL) return -1; q->next = NULL; q->ID = ID; for(i = 0; i < MAX; i++) { q->name[i] = name[i]; } q->chgrade = chgrade; q->mathgrade = mathgrade; q->avegrade = avegrade; if(p == NULL) { head = q; return 1; } p->next = q; } /*从文件中读取数据,插入链表*/ int read_file(char *s) { FILE *fp; int n,i,j,k; int m = -1; Student p, q; int ID; //学生ID char name[MAX]; //学生姓名 float chgrade; //学生语文成绩 float mathgrade;//学生数学成绩 float avegrade; //学生平均成绩 char a[MAX]; //数组a,存储从文件中读出来的ID的字符串 char b[MAX]; //数组b,存储从文件中读出来的name的字符串 char c[MAX]; //数组c,存储从文件中读出来的chgrade的字符串 char d[MAX]; //数组d,存储从文件中读出来的mathgrade的字符串 char e[MAX]; //数组e,存储从文件中读出来的avegrade的字符串 fp = fopen(s, "r"); if(fp == NULL) { perror("fail to fopen"); exit(1); } while(j != -1) { j = fscanf(fp, " %[^ ] %[^ ] %[^ ] %[^ ] %[^ ]", a, b, c, d, e); m++; } fclose(fp); fp = fopen(s, "r"); if(fp == NULL) { perror("fail to fopen"); exit(1); } for(k = 0; k < m; k++) { n = fscanf(fp, " %[^ ] %[^ ] %[^ ] %[^ ] %[^ ]", a, b, c, d, e); ID = atoi(a); for(i = 0; i < MAX; i++) { name[i] = b[i]; } chgrade = atof(c); mathgrade = atof(d); avegrade = atof(e); p = head; if(p != NULL) { while(p->next != NULL) { p = p->next; } q = (Student)malloc(sizeof(struct student)); if(q == NULL) return -1; q->next = NULL; q->ID = ID; for(i = 0; i < MAX; i++) { q->name[i] = name[i]; } q->chgrade = chgrade; q->mathgrade = mathgrade; q->avegrade = avegrade; p->next = q; } else { q = (Student)malloc(sizeof(struct student)); if(q == NULL) return -1; q->next = NULL; q->ID = ID; for(i = 0; i < MAX; i++) { q->name[i] = name[i]; } q->chgrade = chgrade; q->mathgrade = mathgrade; q->avegrade = avegrade; head = q; } } } /*按照平均成绩排序 *使用的排序方法是冒泡排序 *两个结构体指针,在冒泡过程中一个不动,一个向后挪与不动的指针进行比较 *外层while循环是向后移动冒泡的不动指针 *内层while循环是冒泡的过程 * */ int ave(struct student *head) { struct student *p1; struct student *p2; struct student *p3; int ID; float chgrade; float mathgrade; char name[MAX]; float avegrade; int count = 0; int i; if(head == NULL) { printf("no grades "); return head; } p1 = head; if(p1->next == NULL) { printf("success "); return head; } p2 = p1->next; /*while(p1 != NULL) { count++; p1 = p1->next; } printf("%d ", count); p1 = head; p2 = p1->next;*/ while(p1->next != NULL) { while(p2 != NULL) { if(p1->avegrade < p2->avegrade) { p2 = p2->next; } else { ID = p2->ID; for(i = 0; i < MAX; i++) { name[i] = p2->name[i]; } mathgrade = p2->mathgrade; chgrade = p2->chgrade; avegrade = p2->avegrade; p2->ID = p1->ID; //p2->name = p1->name; for(i = 0; i < MAX; i++) { p2->name[i] = p1->name[i]; } p2->chgrade = p1->chgrade; p2->mathgrade = p1->mathgrade; p2->avegrade = p1->avegrade; p1->ID = ID; //p1-> name = name; for(i = 0; i < MAX; i++) { p1->name[i] = name[i]; } p1->chgrade = chgrade; p1-> mathgrade = mathgrade; p1->avegrade = avegrade; p2 = p2->next; } } p1 = p1->next; p2 = p1->next; } print(); return head; } /*按照学生ID删除学生信息*/ int del_ID(struct student *head, int ID) { struct student *p1; struct student *p2; if(head == NULL) { printf("no grades "); return head; } p1 = head; while(p1->ID != ID && p1->next != NULL) { p2 = p1; p1 = p1->next; } if(p1->ID == ID) { if(p1 == head) { head = p1->next; } else { p2->next = p1->next; } free(p1); p1 = NULL; printf("delete %d success ", ID); } else { printf("%d not been found! "); } return head; } /*按照学生姓名删除学生信息*/ int del_name(struct student *head, char name[MAX]) { struct student *p1; struct student *p2; if(head == NULL) { printf("no grades "); return head; } p1 = head; while(strcmp(p1->name,name) != 0 && p1->next != NULL) { p2 = p1; p1 = p1->next; } if(strcmp(p1->name,name) == 0) { if(p1 == head) { head = p1->next; } else { p2->next = p1->next; } free(p1); p1 = NULL; printf("delete %s successfully ", name); } else { printf("%s not be found", name); } print(); return head; } /*打印链表,显示出学生成绩*/ int print(void) { int i = 1; Student p = head; printf("/***************************************************/ "); printf("seq ID NAME CHGRADE MATHGRADE AVEGRADE "); while(p != NULL) { printf("%d: %d %s %f %f %f ", i, p->ID, p->name, p->chgrade, p->mathgrade, p->avegrade); p = p->next; i++; } printf("/***************************************************/ "); } /*主函数*/ int main(int argc, char *argv[ ]) { int number = 0; int count = 0; int ID; char name[MAX]; if(argc < 2) { printf("input wrong, please check "); exit(1); } read_file(argv[1]); /*循环显示主选项单*/ while(number != 5) { printf("please select the option: "); printf("1.Display all student's info "); printf("2.Sort by average "); printf("3.Insert a new info "); printf("4.Delete a record "); printf("5.Quit "); printf("Please input your choices : "); scanf("%d", &number); if(number == 1) { print(); } if(number == 2) { ave(head); } if(number == 3) { insert(); } if(number == 4) { /*循环显示删除选项单*/ while(count != 3) { printf("Please choose the way "); printf("1.Delete by ID "); printf("2.Delete by name "); printf("3.exit "); printf("Your choice:"); scanf("%d", &count); if(count == 1) { printf("Pleas input the ID "); scanf("%d", &ID); del_ID(head,ID); } if(count == 2) { printf("Please input the name "); scanf("%s",name); printf("%s ", name); del_name(head, name); } if(count < 0 || count >3) { printf("please input right number "); } } count = 0; } } return 0; }