在虚拟机里展示功能如下
#include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define HEAD_INFO "学号\t姓名\t性别\t年龄\t语文\t数学\t英语\t体育\t总分\t平均分\n" #define HEAD_INFO2 "学号\t姓名\t性别\t年龄\t语文\t数学\t英语\t体育\n" // 定义学生信息数据结构 struct student { // 学号 int num; // 姓名 char name[20]; //性别 char sex[20]; //年龄 int age; // 语文 int chinese; // 数学 int math; // 英语 int english; // 体育 int pe; // 总分 int total; //平均分 double average; }; // 定义链表结点结构类型 struct node { struct student stu; struct node *next; }; // 定义各种功能函数 // 显示功能菜单 void showMenu(); //读取存档 void readStudent(struct node *head); // 录入信息 void addStudent(struct node *head); // 删除信息 void deleteStudent(struct node *head); // 查询信息 void queryStudent(struct node *head); // 修改信息 void modifyStudent(struct node *head); // 成绩排序 void sortStudent(struct node *head); // 显示所有 void showStudent(struct node *head); // 保存信息 void saveStudent(struct node *head); // 退出 void exitProgram(struct node *head); //进度条 void proc(); // 定义链表基本操作函数 struct node *readStudentmessage(struct node *head); struct node *createStudentNode(struct student *stu); struct node *insertStudentNode(struct node *head, struct student *stu); struct node *createStudentList(); void freeStudentList(struct node* head); struct node *queryStudentListByNum(struct node* head, int num); struct node *queryStudentListByName(struct node* head, char *name); int deleteStudentListByNum(struct node* head, int num); int getStudentListLength(struct node* head); struct node *sortStudentListByTotal(struct node *head); struct node *sortStudentListByAverage(struct node *head); void printStudentListInfo(struct node* head); void saveStudentListToFile(struct node* head); void error(const char* err); struct node *readStudentmessage(struct node *head);
students.c
#include "student.h" int main() { // 创建学生成绩空链表保存信息 struct node* list = createStudentList(); // 显示功能主菜单 showMenu(); char a[10]; while (1) { printf("\n请输出0-9,回车结束!\n"); if (fgets(a, 10, stdin) != NULL) { switch (a[0]) { case '0': exitProgram(list); break; case '1': addStudent(list); break; case '2': deleteStudent(list); break; case '3': queryStudent(list); break; case '4': modifyStudent(list); break; case '5': sortStudent(list); break; case '6': showStudent(list); break; case '7': saveStudent(list); break; case '8': showMenu(); break; case '9': readStudent(list); break; default: printf("请重新输入正确的功能数字0-9!\n"); } } showMenu(); } return 0; } // 创建学生成绩结点 struct node *createStudentNode(struct student *stu) { struct node* p = (struct node*)calloc(1,sizeof(struct node)); if(stu != NULL) { struct student *s = &(p->stu); if(p != NULL) { //存放信息 s->num = stu->num; strcpy(s->name, stu->name); strcpy(s->sex, stu->sex); s->age = stu ->age; s->chinese = stu->chinese; s->math = stu->math; s->english = stu->english; s->pe = stu->pe; // 计算总成绩 s->total = s->chinese + s->math + \ s->english + s->pe; s->average = s->total*1.0/4; p->next = NULL; } } return p; } // 表尾增加学生成绩 struct node *insertStudentNode(struct node *head, struct student *stu) { struct node *node = NULL; if(head != NULL) { node = createStudentNode(stu); // struct student *s = &(node->stu); if(node != NULL) { struct node* p = head; while(p->next != NULL) // 循环找到链表最后的结点 p = p->next; p->next = node; } } return node; } // 创建带头结点的学生成绩空链表 struct node *createStudentList() { // 创建头结点 return createStudentNode(NULL); } // 释放学生成绩链表内存空间 void freeStudentList(struct node* head) { struct node* p = head; while(p != NULL) { head = p->next; free(p); p = head; } } // 根据学号查找学生成绩 struct node *queryStudentListByNum(struct node* head, int num) { struct node *p = NULL; if(head != NULL) { p = head->next; while(p != NULL) { if(p->stu.num == num) //找到则返回指针地址 break; p = p->next; } } return p; } // 根据姓名查找学生成绩 struct node *queryStudentListByName(struct node* head, char *name) { struct node *p = NULL; if(head != NULL) { p = head->next; while(p != NULL) { if(strcmp(p->stu.name, name) == 0) break; p = p->next; } } return p; } // 根据学号删除学生成绩 int deleteStudentListByNum(struct node* head, int num) { // p保存当前结点,pre保存前一个结点 struct node *p = NULL, *pre = NULL; // 返回结果0或1 int status = 0; if(head != NULL) { pre = head; p = head->next; while(p != NULL) { if(p->stu.num == num) { pre->next = p->next; p->next = NULL; free(p); status = 1; break; } p = p->next; } } return status; } // 获取学生成绩链表的长度 int getStudentListLength(struct node* head) { int n = 0; struct node *p = NULL; if(head != NULL) { p = head->next; while(p != NULL) { n++; p = p->next; } } return n; } // 按总分从高到低排序学生成绩 struct node *sortStudentListByTotal(struct node *head) { if(head != NULL) { struct node *p1, *p2, *max; struct student s; p1 = head; // 简单选择排序 // 直接交换信息,不改变结点 while((p1=p1->next) != NULL) { max = p1; p2 = p1; while((p2=p2->next) != NULL) { if((p2->stu).total > (max->stu).total) max = p2; } if(max != p1) { s = p1->stu; p1->stu = max->stu; max->stu = s; } } } return head; } // 按平均分从小到大排序学生成绩 struct node *sortStudentListByAverage(struct node *head) { if(head != NULL) { struct node *p1, *p2, *min; struct student s; p1 = head; // 简单选择排序 // 直接交换信息,不改变结点 while((p1=p1->next) != NULL) { min = p1; p2 = p1; while((p2=p2->next) != NULL) { if((p2->stu).average < (min->stu).average) min = p2; } if(min != p1) { s = p1->stu; p1->stu = min->stu; min->stu = s; } } } return head; } // 打印出链表所有结点保存的学生信息 void printStudentListInfo(struct node* head) { struct node* p = head->next; printf(HEAD_INFO); struct student *s; while(p != NULL) { s = &(p->stu); printf("%d\t%s\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%.2lf\n", s->num, s->name, s->sex,\ s->age, s->chinese, s->math, s->english, s->pe, \ s->total,s->average); p = p->next; } printf("\n"); } // 文件保存学生成绩链表所有信息 void saveStudentListToFile(struct node* head) { if(head != NULL) { struct node *p = head->next; FILE* fp = fopen("students.txt", "w+"); if(fp != NULL) { struct student *s; while(p != NULL) { s = &(p->stu); fprintf(fp,"%d\t%s\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%.2lf\n", s->num, s->name, s->sex, \ s->age, s->chinese, s->math, s->english, s->pe, \ s->total,s->average); p = p->next; } fclose(fp); }else { error("打开students文件失败,请检查!\n"); } } } //文件读取txt中所有信息 struct node *readStudentmessage(struct node *head) { struct student stu; FILE* fp ; if((fp=fopen("students.txt","r"))==NULL) { perror("open failed"); printf("没有存档的信息\n"); return NULL; } int ret; while(1) { ret=fscanf(fp,"%d%s%s%d%d%d%d%d%d%lf", &stu.num, stu.name, stu.sex, \ &stu.age,&stu.chinese, &stu.math,\ &stu.english,&stu.pe,&stu.total,&stu.average); if(ret==-1) break; insertStudentNode(head,&stu); } // return &new_node->stu; fclose(fp); } void showMenu() //主菜单界面 { printf("\t*************欢迎使用学生成绩管理系统*************\t\n"); printf("\t* 1:录入成绩 2:删除成绩 *\t\n"); printf("\t* 3:查询成绩 4:修改成绩 *\t\n"); printf("\t* 5:成绩排序 6:显示所有 *\t\n"); printf("\t* 7:保存成绩 8:显示菜单 *\t\n"); printf("\t* 9:读取存档 0:退出系统 *\t\n"); printf("\t**************************************************\t\n"); printf("\n"); } // 录入信息 void addStudent(struct node *head) { printf("请您按提示依次输入图书信息(以空格分隔):\n"); printf(HEAD_INFO2); char a[1024]; struct student stu; if (fgets(a, 1024, stdin) != NULL && sscanf(a, "%d%s%s%d%d%d%d%d", &stu.num, stu.name, stu.sex, \ &stu.age,&stu.chinese, &stu.math,\ &stu.english,&stu.pe) >= 8) { if (queryStudentListByNum(head, stu.num) != NULL) printf("该学生成绩信息已经存在,无法增加!\n"); else { insertStudentNode(head, &stu); printf("学生【%d\t%s】的信息添加成功!\n", stu.num, stu.name); } } else { printf("输入格式有误,请重新输入!\n"); } } // 删除信息 void deleteStudent(struct node *head) { printf("请输入要删除的学生学号:"); char a[1024]; int num; if (fgets(a, 1024, stdin) != NULL && sscanf(a, "%d", &num) != EOF) //EOP表示读取到最后 { if (deleteStudentListByNum(head, num)) { printf("学号%d对应的学生信息删除成功!\n", num); } else { printf("学号%d对应的学生信息不存在!\n", num); } } else { printf("输入格式有误,请重新输入!\n"); } } // 查询信息 void queryStudent(struct node *head) { printf("请选择查询方式:1.学号查询 2.姓名查询 \n"); char a[1024]; if (fgets(a, 1024, stdin) != NULL) { if(a[0] == '1') { printf("请输入学生学号:"); int num; if (fgets(a, 1024, stdin) != NULL && \ sscanf(a, "%d", &num) != EOF) { struct node *p = queryStudentListByNum(head, num); if(p == NULL) { printf("未查到学号%d对应的学生信息!\n", num); } else { struct student *s = &(p->stu); printf(HEAD_INFO); printf("%d\t%s\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%.2lf\n", s->num, s->name, s->sex, s->age,\ s->chinese, s->math, s->english, s->pe, \ s->total,s->average); } }else { printf("输入格式有误,请重新输入!\n"); } }else if(a[0] == '2') { printf("请输入学生姓名:"); char name[20]; if (fgets(a, 1024, stdin) != NULL && sscanf(a, "%s", name) != EOF) { struct node *p = queryStudentListByName(head, name); if(p == NULL) { printf("未查到姓名%s对应的学生信息!\n", name); } else { struct student *s = &(p->stu); printf(HEAD_INFO); printf("%d\t%s\t%s\t%d\t%d\t%d\t%d\t%d\t%.2lf\n", s->num, s->name, s->sex, \ s->chinese, s->math, s->english, s->pe, \ s->total,s->average); } } else { printf("输入格式有误,请重新输入!\n"); } } else { printf("输入格式有误,请重新输入!\n"); } } } // 修改信息 void modifyStudent(struct node *head) { printf("请输入要修改的学生学号:"); char a[1024]; int num; if (fgets(a, 1024, stdin) != NULL && \ sscanf(a, "%d", &num) != EOF) { struct node *p = queryStudentListByNum(head, num); if (p == NULL) { printf("学号%d对应的学生信息不存在!\n", num); }else { struct student *s = &(p->stu); printf("学号%d对应的学生信息如下:\n", num); printf(HEAD_INFO); printf("%d\t%s\t%d\t%d\t%d\t%d\t%d\t%.2lf\n", s->num, s->name, \ s->chinese, s->math, s->english, s->pe, \ s->total,s->average); printf("请依次输入修改后信息,不变的信息请同样输入:\n"); printf("姓名\t语文\t数学\t英语\t体育\n"); struct student stu; if (fgets(a, 1024, stdin) != NULL && \ sscanf(a, "%s%d%d%d%d", stu.name, &stu.chinese, \ &stu.math, &stu.english, &stu.pe) >= 5) { strcpy(s->name, stu.name); s->chinese = stu.chinese; s->math = stu.math; s->english = stu.english; s->pe = stu.pe; // 计算成绩 s->total = stu.chinese + stu.math + \ stu.english + stu.pe; s->average = s->total*1.0/4; printf("修改成功,修改后信息如下:\n"); printf(HEAD_INFO); printf("%d\t%s\t%s\t%d\t%d\t%d\t%d\t%d\t%.2lf\n", s->num, s->name, s->sex, \ s->chinese, s->math, s->english, s->pe, \ s->total,s->average); }else { printf("输入格式有误,请重新输入!\n"); } } }else { printf("输入格式有误,请重新输入!\n"); } } // 成绩排序 void sortStudent(struct node *head) { printf("请选择排序方式:1.总分从高到低排序 2.平均分从低到高排序 \n"); char a[1024]; if (fgets(a, 1024, stdin) != NULL) { if(a[0] == '1') { sortStudentListByTotal(head); printStudentListInfo(head); }else if(a[0] == '2') { sortStudentListByAverage(head); printStudentListInfo(head); }else { printf("输入格式有误,请重新输入!\n"); } }else { printf("输入格式有误,请重新输入!\n"); } } // 显示所有 void showStudent(struct node *head) { printStudentListInfo(head); printf("当前系统总共有%d条学生成绩记录!\n", getStudentListLength(head)); printf("\n"); } // 保存信息 void saveStudent(struct node *head) { saveStudentListToFile(head); printf("保存成功,信息存放在students.txt文件!\n"); } // 读取信息 void readStudent(struct node *head) { readStudentmessage(head); printf("正在读取存档中........\n"); proc(); printf("读取成功\n"); usleep(1000*50); printf("------------------------------------\n"); } //进度条 void proc() { int i; printf(">>"); for(i=1;i<=100;i++) { if(i<11) printf(">"); printf("\b\b\b%d%%",i); fflush(stdout); usleep(1000*30); } printf("\n"); } // 退出 void exitProgram(struct node *head) { freeStudentList(head); printf("ByeBye....~~\n"); exit(0); }
kernel_list.h
#ifndef __DLIST_H #define __DLIST_H /* This file is from Linux Kernel (include/linux/list.h) * and modified by simply removing hardware prefetching of list items. * Here by copyright, credits attributed to wherever they belong. * Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu) */ /* * Simple doubly linked list implementation. * * Some of the internal functions (“__xxx”) are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ /** * container_of - cast a member of a structure out to the containing structure * * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) /* * These are non-NULL pointers that will result in page faults * under normal circumstances, used to verify that nobody uses * non-initialized list entries. */ #define LIST_POISON1 ((void *) 0x00100100) #define LIST_POISON2 ((void *) 0x00200) // 内核标准链表:小结构体 struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) // 初始化小结构体,让其自己形成一个双向循环 // ptr ->小结构体地址 #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } /** * list_add – add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ // 将新节点new插入到以head为首的链表的开头 头插法 static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /** * list_add_tail – add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ // 将新节点new插入到以head为首的链表的末尾 尾插法 // 要插入的节点的小结构体的地址 头节点的小结构体地址 static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev;//e->next->prev = e->prev prev->next = next;//e->prev->next = e->next } /** * list_del – deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ // 将entry指向的节点,从链表中剔除出去 static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = (void *) 0;//NULL entry->prev = (void *) 0;//NULL } /** * list_del_init – deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_move – delete from one list and add as another’s head * @list: the entry to move * @head: the head that will precede our entry */ // 将节点list移动到以head为首的链表的开头 static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } /** * list_move_tail – delete from one list and add as another’s tail * @list: the entry to move * @head: the head that will follow our entry */ // 将节点list移动到以head为首的链表的末尾 static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } /** * list_empty – tests whether a list is empty * @head: the list to test. */ //判断链表是否只有一个头节点 static inline int list_empty(struct list_head *head) { return head->next == head; } static inline void __list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } /** * list_splice – join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head); } /** * list_splice_init – join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitiallised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head); INIT_LIST_HEAD(list); } } /** * list_entry – get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ // 小结构体指针ptr转换成大结构体指针p: p = list_entry(ptr, type, member) // 小结构体指针 大结构数据类型 小结构体变量名 #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ // 从头开始往后遍历链表(遍历过程中,不可以将节点删除) // 小结构体的地址 #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ // 从尾开始往前遍历链表 #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ // 从头开始往后遍历链表(遍历过程中,可以将节点删除) // (可以被删除的节点)前置节点 后置节点 头节点 #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) // 从尾开始往前遍历链表(遍历过程中,可以将节点删除) // (可以被删除的节点)前置节点 后置节点 头节点 #define list_for_each_tail_safe(pos, n, head) \ for (pos = (head)->prev, n = pos->prev; pos != (head); \ pos = n, n = pos->prev) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe – iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop counter. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif