大家好,欢迎来到我的博客总结应用。在上一篇博客中,我写了有关结构体和内存操作函
数的总结,这些博客记录了我的学习、思考和经验。为了更好地总结和回顾这些内容,在此
篇博客中,我编写了”学生管理系统“来帮助我整理和应用上一篇博客的总结知识点。在这个
”学生管理系统“中,我列举了九条不同的标题和内容来进行说明,以下便是我的总结整理。
添加必要的头文件和声明,之后定义学生信息结构体。
学生信息结构体中含有必要的学生id、学生姓名和学生成绩,除此之外,也可以自行添加一些其他信息,如学生家庭年龄,学生住址,学生班级,学生教师,学生所属学校等
#include
#include
#include
// 学生信息结构体
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;
}
// 说明链表为空,或者到了链表尾部,即没有找到指定学生id
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);
}
}
删除学生信息结点有两个位置区分
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;
}
// 要么链表为空,要么已经到链表尾部,这两种情况都是未找到id
if (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
#include
#include
// 学生信息结构体
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;
}
// 要么链表为空,要么已经到链表尾部,这两种情况都是未找到id
if (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);
}
}