大家好,欢迎来到我的博客总结应用。在上一篇博客中,我写了有关结构体和内存操作函
数的总结,这些博客记录了我的学习、思考和经验。为了更好地总结和回顾这些内容,在此
篇博客中,我编写了”学生管理系统“来帮助我整理和应用上一篇博客的总结知识点。在这个
”学生管理系统“中,我列举了九条不同的标题和内容来进行说明,以下便是我的总结整理。
文章目录
- 一、定义学生信息的结构体
- 二、主函数逻辑
- 三、添加学生信息
- 四、删除学生信息
- 五、修改学生信息
- 六、显示学生列表
- 七、查询学生信息
- 八、退出程序
- 九、完整代码及补充
一、定义学生信息的结构体
添加必要的头文件和声明,之后定义学生信息结构体。
学生信息结构体中含有必要的学生id、学生姓名和学生成绩,除此之外,也可以自行添加一些其他信息,如学生家庭年龄,学生住址,学生班级,学生教师,学生所属学校等
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 学生信息结构体
typedef struct _Student {int id;float score; /* 数据域 */char name[50];struct Student *next; /* 指针域 */
} Student;int isExistId(Student **head, int id);
void freeMemory(Student *head);void addStudent(Student **head);
void deleteStudent(Student **head);
void updateStudent(Student **head);
void printStudent(Student **head);
void searchStudent(Student **head);
可以将数据域和指针域分开来定义,使结构逻辑更加严整。
typedef struct _Student {int id;float score;char name[50];
} Student;// 嵌套结构体
typedef struct _StuNode {Student stu;struct _Node *next;
} StuNode;
二、主函数逻辑
主函数主要负责输出学生管理系统的文字页面、选择对应的功能、暂停并清空控制台
int main()
{int choice;Student *head = NULL; // 学生链表头指针while (1){// 暂停程序system("pause");// 清空控制台system("cls");printf("--------学生管理系统--------\n");printf("\t1. 添加学生信息\n");printf("\t2. 删除学生信息\n");printf("\t3. 修改学生信息\n");printf("\t4. 显示学生列表\n");printf("\t5. 查找学生信息\n");printf("\t0. 退出系统\n");printf("请选择操作:");// 输入非数字字符,清空输入缓冲区if (scanf("%d", &choice) != 1){while (getchar() != '\n');printf("无效的操作,请重新选择。\n");continue;}// 当输入数字字符后,防止缓冲区中的字符影响自己的选择while (getchar() != '\n');switch (choice){case 1:addStudent(&head); // 添加学生信息break;case 2:deleteStudent(&head); // 删除学生信息break;case 3:updateStudent(&head); // 更新学生信息break;case 4:printStudent(&head); // 打印学生信息break;case 5:searchStudent(&head); // 搜索学生信息break;case 0:printf("感谢使用学生管理系统,再见!\n");freeMemory(head); // 释放内存,防止内存泄漏exit(0);default:printf("无效操作,请重新选择。\n");}}return 0;
}
注意,学生管理系统是需要手动退出的一个页面,所以很多操作都是在一个循环里面。
-
输出学生管理系统的文字页面
按照一定格式输出文字,将其美观排版后输出即可
// 文字页面 printf("--------学生管理系统--------\n"); printf("\t1. 添加学生信息\n"); printf("\t2. 删除学生信息\n"); printf("\t3. 修改学生信息\n"); printf("\t4. 显示学生列表\n"); printf("\t5. 查找学生信息\n"); printf("\t0. 退出系统\n"); printf("请选择操作:");
-
选择对应的功能
使用switch语句,每一种case对应一种功能,此外还需要一定的防御性编程,如选择时要求输入数字字符,消除输入数字字符的后面其他无关字符的影响
// 输入非数字字符,清空输入缓冲区 if (scanf("%d", &choice) != 1) {while (getchar() != '\n');printf("无效的操作,请重新选择。\n");continue; }// 当输入数字字符后,防止缓冲区中的字符影响自己的选择 while (getchar() != '\n'); switch (choice) {case 1:addStudent(&head); // 添加学生信息break;case 2:deleteStudent(&head); // 删除学生信息break;case 3:updateStudent(&head); // 更新学生信息break;case 4:printStudent(&head); // 打印学生信息break;case 5:searchStudent(&head); // 搜索学生信息break;case 0:printf("感谢使用学生管理系统,再见!\n");freeMemory(head); // 释放内存,防止内存泄漏exit(0);default:printf("无效操作,请重新选择。\n"); }
-
暂停并清空控制台
为了让输出界面和输出的结果更加直观,所以要求暂停程序观看,之后清空控制台以达到简洁直观的目的
// 暂停程序 system("pause"); // 清空控制台 system("cls");
-
三、添加学生信息
-
录入学生信息
添加学生信息这一环节主要是创建一个结点,结点中含有填写完的信息,然后把这个结点放在链表之中。
// 添加学生信息 void addStudent(Student **head) {int id;printf("请输入学生id: ");scanf("%d", &id);// 判断是否重复录取学生信息if (IsExistId(head, id)) {printf("已存在id为%d的学生信息!\n", id);return;}// 开辟空间,并填写信息Student *newStudent = (Student *) malloc(sizeof(Student));newStudent->next = NULL;char name[50];float score;printf("请输入学生姓名: ");scanf("%s", name);printf("请输入学生分数: ");scanf("%f", &score);newStudent->id = id;/* 注意字符串赋值的方式 */strcpy(newStudent->name, name);newStudent->score = score;// 尾插法:将结点插入在链表之后if (*head == NULL) {*head = newStudent;} else {Student *temp = *head;while (temp->next != NULL) {temp = temp->next;}temp->next = newStudent;} }
-
插入结点的方法
插入节点的两个方法:头插法和尾插法
-
头插法:将结点放在头部,使之成为新的头结点
// 头插法 // 无论有没有头结点都可以 newStudent->next = *head; *head = newStudent;
-
尾插法:不断地将结点插在链表尾部
// 尾插法:将结点插入在链表之后 // 情况一,没有头结点 if (*head == NULL) { *head = newStudent; } // 情况二,有头结点 else {Student *temp = *head;// 一直找到最后一个结点while (temp->next != NULL) {temp = temp->next;}temp->next = newStudent; }
-
-
避免重复录入学生信息
为了不重复录入学生信息,定义一个IsExistId函数,该函数的实现就是遍历链表,判断链表中是否存在待录入学生的id,如果存在,返回1;否则,返回0。
int IsExistId(Student *head, int id) {while (head != NULL) {if (head->id == id) {return 1;}}return 0; }
四、删除学生信息
-
删除学生信息
这意味着将去除链表中指定学生信息的结点,然后释放内存。
// 删除学生信息 void deleteStudent(Student **head) {int id;Student *temp = *head;// 待删除结点的前一个结点,用于指向待删除结点的下一个结点Student *prev = NULL; printf("请输入要删除的学生id: ");scanf("%d", &id);// 遍历链表,查找要删除的学生结点位置while (temp != NULL && temp->id != id) {prev = temp;temp = temp->next;}// 说明链表为空,或者到了链表尾部,即没有找到指定学生idif (temp == NULL) {printf("未找到学生id为%d的记录。\n", id);return;}// 如果找到了要删除的学生,从链表中删除它else{if (prev == NULL) {// 删除头节点*head = temp->next;} else {prev->next = temp->next;}free(temp);printf("已删除学生id为%d的记录。\n", id);}}
-
删除学生信息结点有两个位置区分
- 头结点位置:删除头结点后,头结点的下一位即为头结点
- 其他位置:待删除结点的前一位,它的下一位是待删除结点的下一位
if (prev == NULL) {// 删除头节点*head = temp->next; } else {prev->next = temp->next; }free(temp);
五、修改学生信息
遍历链表,找到待修改信息的学生id即可修改学生信息
// 修改学生信息
void updateStudent(Student **head)
{int id;Student *temp = *head;printf("请输入要修改信息的学生id: ");scanf("%d", &id);while (temp != NULL && temp->id != id){temp = temp->next;}// 要么链表为空,要么已经到链表尾部,这两种情况都是未找到idif (temp == NULL){printf("未找到学生id为%d的记录。\n", id);}else{printf("请输入新的姓名和成绩:\n");scanf("%s %f", temp->name, &temp->score);printf("已更新学生id为%d的信息。\n", id);}
}
六、显示学生列表
遍历链表,将学生信息一个个打印出来。这个过程是按照链表的插入顺序进行打印输出的,还可以自己实现按照id大小排序进行输出,抑或着按照学生成绩大小排序进行输出。
// 打印学生信息
void printStudent(Student **head)
{if (*head == NULL){printf("暂未录入学生信息\n");return;}printf("\n学生信息如下:\n");Student *temp = *head;while (temp != NULL){printf("ID:%d,姓名:%s,成绩:%.2f\n", temp->id, temp->name, temp->score);temp = temp->next;}
}
七、查询学生信息
本质上还是遍历链表,查看是否存在指定id的人
void searchStudent(Student **head) {int id;Student *temp = *head;printf("输入待搜索学生的id: ");scanf("%d", &id);while(temp != NULL && temp->id != id) {temp = temp->next;}if (temp == NULL) {printf("查无此id:%d信息。", id);} else {printf("id: %d name: %s score: %.2f\n", id, temp->name, temp->score);}
}
八、退出程序
退出程序只需要在switch中添加一个选项即可,在这个选项中有exit。当然,退出程序前,要主动释放内存,避免内存泄漏。
以下这个函数也i将添加在含有exit选项中。
// 释放内存空间
void freeMemory(Student *head)
{Student *temp;while (head != NULL){temp = head;head = head->next;free(temp);}
}
九、完整代码及补充
以上就是学生管理系统的大致代码,之后若是学习了文件管理相关的函数,还可以将文件导出保存,将其他的对应格式的学生信息文件导入进行管理。除了文件管理相关的函数,我们还可以将数据导入到数据库中,这些都是之后将会学习的知识。
-
完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h>// 学生信息结构体 typedef struct Student {int id;float score; /* 数据域 */char name[50];struct Student *next; /* 指针域 */ } Student;int isExistId(Student **head, int id); void freeMemory(Student *head);void addStudent(Student **head); void deleteStudent(Student **head); void updateStudent(Student **head); void printStudent(Student **head); void searchStudent(Student **head);int main() {int choice;Student *head = NULL; // 学生链表头指针while (1){// 暂停程序system("pause");// 清空控制台system("cls");printf("--------学生管理系统--------\n");printf("\t1. 添加学生信息\n");printf("\t2. 删除学生信息\n");printf("\t3. 修改学生信息\n");printf("\t4. 显示学生列表\n");printf("\t5. 查找学生信息\n");printf("\t0. 退出系统\n");printf("请选择操作:");// 输入非数字字符,清空输入缓冲区if (scanf("%d", &choice) != 1){while (getchar() != '\n');printf("无效的操作,请重新选择。\n");continue;}// 当输入数字字符后,防止缓冲区中的字符影响自己的选择while (getchar() != '\n');switch (choice){case 1:addStudent(&head); // 添加学生信息break;case 2:deleteStudent(&head); // 删除学生信息break;case 3:updateStudent(&head); // 更新学生信息break;case 4:printStudent(&head); // 打印学生信息break;case 5:searchStudent(&head); // 搜索学生信息break;case 0:printf("感谢使用学生管理系统,再见!\n");freeMemory(head); // 释放内存,防止内存泄漏exit(0);default:printf("无效操作,请重新选择。\n");}}return 0; }// 添加学生信息 void addStudent(Student **head) {int id;printf("请输入学生id: ");scanf("%d", &id);// 判断是否重复录取学生信息if (isExistId(head, id)){printf("已存在id为%d的学生信息!\n", id);return;}// 开辟空间,并填写信息Student *newStudent = (Student *)malloc(sizeof(Student));newStudent->next = NULL;char name[50];float score;printf("请输入学生姓名: ");scanf("%s", name);printf("请输入学生分数: ");scanf("%f", &score);newStudent->id = id;/* 注意字符串赋值的方式 */strcpy(newStudent->name, name);newStudent->score = score;// 尾插法:将结点插入在链表之后if (*head == NULL){*head = newStudent;}else{Student *temp = *head;while (temp->next != NULL){temp = temp->next;}temp->next = newStudent;} }// 删除学生信息 void deleteStudent(Student **head) {int id;Student *temp = *head;// 待删除结点的前一个结点,用于指向待删除结点的下一个结点Student *prev = NULL;printf("请输入要删除的学生id: ");scanf("%d", &id);// 遍历链表,查找要删除的学生结点位置while (temp != NULL && temp->id != id){prev = temp;temp = temp->next;}// 如果找到了要删除的学生,从链表中删除它if (temp == NULL){printf("未找到学生id为%d的记录。\n", id);return;}else{if (prev == NULL){// 删除头节点*head = temp->next;}else{prev->next = temp->next;}free(temp);printf("已删除学生id为%d的记录。\n", id);} }// 修改学生信息 void updateStudent(Student **head) {int id;Student *temp = *head;printf("请输入要修改信息的学生id: ");scanf("%d", &id);while (temp != NULL && temp->id != id){temp = temp->next;}// 要么链表为空,要么已经到链表尾部,这两种情况都是未找到idif (temp == NULL){printf("未找到学生id为%d的记录。\n", id);}else{printf("请输入新的姓名和成绩:\n");scanf("%s %f", temp->name, &temp->score);printf("已更新学生id为%d的信息。\n", id);} }// 打印学生信息 void printStudent(Student **head) {if (*head == NULL){printf("暂未录入学生信息\n");return;}printf("\n学生信息如下:\n");Student *temp = *head;while (temp != NULL){printf("ID: %d\t 姓名: %s\t 成绩: %.2f\n", temp->id, temp->name, temp->score);temp = temp->next;} }// 释放内存空间 void freeMemory(Student *head) {Student *temp;while (head != NULL){temp = head;head = head->next;free(temp);} }// 判断链表中是否存在指定学生id int isExistId(Student **head, int id) {Student *temp = *head;while (temp != NULL){if (temp->id == id){return 1;}temp = temp->next;}return 0; }void searchStudent(Student **head) {int id;Student *temp = *head;printf("输入待搜索学生的id: ");scanf("%d", &id);while(temp != NULL && temp->id != id) {temp = temp->next;}if (temp == NULL) {printf("查无此id:%d信息。\n", id);} else {printf("id: %d name: %s score: %.2f\n", id, temp->name, temp->score);} }