【C语言】学生管理系统

  大家好,欢迎来到我的博客总结应用。在上一篇博客中,我写了有关结构体和内存操作函
数的总结,这些博客记录了我的学习、思考和经验。为了更好地总结和回顾这些内容,在此
篇博客中,我编写了”学生管理系统“来帮助我整理和应用上一篇博客的总结知识点。在这个
”学生管理系统“中,我列举了九条不同的标题和内容来进行说明,以下便是我的总结整理。

文章目录

  • 一、定义学生信息的结构体
  • 二、主函数逻辑
  • 三、添加学生信息
  • 四、删除学生信息
  • 五、修改学生信息
  • 六、显示学生列表
  • 七、查询学生信息
  • 八、退出程序
  • 九、完整代码及补充

一、定义学生信息的结构体

添加必要的头文件和声明,之后定义学生信息结构体。

学生信息结构体中含有必要的学生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;
}

注意,学生管理系统是需要手动退出的一个页面,所以很多操作都是在一个循环里面。

  1. 输出学生管理系统的文字页面

    按照一定格式输出文字,将其美观排版后输出即可

    // 文字页面
    printf("--------学生管理系统--------\n");
    printf("\t1. 添加学生信息\n");
    printf("\t2. 删除学生信息\n");
    printf("\t3. 修改学生信息\n");
    printf("\t4. 显示学生列表\n");
    printf("\t5. 查找学生信息\n");
    printf("\t0. 退出系统\n");
    printf("请选择操作:");
    
  2. 选择对应的功能

    使用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");
    }
    
    1. 暂停并清空控制台

      为了让输出界面和输出的结果更加直观,所以要求暂停程序观看,之后清空控制台以达到简洁直观的目的

      // 暂停程序
      system("pause");
      // 清空控制台
      system("cls");
      

三、添加学生信息

  1. 录入学生信息

    添加学生信息这一环节主要是创建一个结点,结点中含有填写完的信息,然后把这个结点放在链表之中。

    // 添加学生信息
    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;}
    }
    
  2. 插入结点的方法

    插入节点的两个方法:头插法和尾插法

    • 头插法:将结点放在头部,使之成为新的头结点

      // 头插法
      // 无论有没有头结点都可以
      newStudent->next = *head;
      *head = newStudent;
      
    • 尾插法:不断地将结点插在链表尾部

      // 尾插法:将结点插入在链表之后
      // 情况一,没有头结点
      if (*head == NULL) 
      { *head = newStudent;
      } // 情况二,有头结点
      else 
      {Student *temp = *head;// 一直找到最后一个结点while (temp->next != NULL) {temp = temp->next;}temp->next = newStudent;
      }
      
  3. 避免重复录入学生信息

    为了不重复录入学生信息,定义一个IsExistId函数,该函数的实现就是遍历链表,判断链表中是否存在待录入学生的id,如果存在,返回1;否则,返回0。

    int IsExistId(Student *head, int id) {while (head != NULL) {if (head->id == id) {return 1;}}return 0;
    }
    

四、删除学生信息

  1. 删除学生信息

    这意味着将去除链表中指定学生信息的结点,然后释放内存。

    // 删除学生信息
    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);}}
    
  2. 删除学生信息结点有两个位置区分

    • 头结点位置:删除头结点后,头结点的下一位即为头结点
    • 其他位置:待删除结点的前一位,它的下一位是待删除结点的下一位
    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);}
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/657278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Facebook的创新征程:社交媒体的演进之路

在当今数字化时代&#xff0c;社交媒体已经成为人们生活中不可或缺的一部分&#xff0c;而Facebook作为社交媒体领域的巨头&#xff0c;一直在不断创新和演进。本文将深入探讨Facebook的创新征程&#xff0c;追溯其社交媒体的发展历程&#xff0c;探讨其对用户、社会和数字时代…

echart 实现自定义地图

先上效果图 需求&#xff1a;自定义区域平面图&#xff0c;支持区域高亮 // 2D详情const initChartsMapItemB async (flow: any, mapbg: any) > {// mapbg 为svg的地址 import mapbg from //assets/json/map/F42d.svgconst svgData (await request.get(mapbg)) as anye…

WPF应用程序(.Net Framework 4.8) 国际化

1、新建两个资源字典文件zh-CN.xaml和en-US.xaml&#xff0c;分别存储中文模板和英文模板 (1) zh-CN.xaml <ResourceDictionary xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml&q…

(delphi11最新学习资料) Object Pascal 学习笔记---第4章第1节(过程和函数)

第4章 过程与函数 ​ Object Pascal 语言&#xff08;以及 C 语言的类似功能&#xff09;强调的另一个重要思想是例程的概念&#xff0c;例程基本上是一系列具有唯一名称的语句&#xff0c;可以多次调用。例程&#xff08;或函数&#xff09;通过名称来调用&#xff0c;这样就…

基于链表实现贪吃蛇游戏

本文中&#xff0c;我们将使用链表和一些Win32 API的知识来实现贪吃蛇小游戏 一、功能 &#xff08;1&#xff09;游戏载入界面 &#xff08;2&#xff09;地图的绘制 &#xff08;3&#xff09;蛇身的移动和变长 &#xff08;4&#xff09;食物的生成 &#xff08;5&…

阿里云盘分享多文件方法

1、单次分享不超过100个文件/文件夹 2、分享的文件夹目录不超过15个子文件夹层级 3、文件夹里面的总文件数量不能超过4000个 其实限制的条件蛮高的&#xff0c;但是对于这么大容量的网盘&#xff0c;稍微一分享就会超过条件限制&#xff0c;有的人会拆分为好几个文件多次分享&a…

CentOS 7 部署 ZeroTier Moon 节点

ZeroTier是一套使用UDP协议构建的SD-WAN网络软件&#xff0c;其主要有三部分组成&#xff1a;行星服务器Planet、月亮服务器Moon、客户端节点LEFA&#xff0c;行星服务器是ZeroTier的根节点&#xff0c;可以采用ZeroTier官方的服务器&#xff0c;也可以使用开源代码自行搭建 月…

基于python的城市旅游数据采集分析系统

基于python的城市旅游数据采集分析系统 "A Python-based City Tourism Data Collection and Analysis System" 下载链接&#xff1a;基于python的城市旅游数据采集分析系统 目录 目录 2 摘要 3 关键词 4 第一章 引言 4 1.1 研究背景 4 1.2 国内外研究现状 5 1.3 研究…

sql注入之union联合注入

一、Union注入 联合查询注入是联合两个表进行注入攻击&#xff0c;使用关键词 union select 对两个表进行联合查询。两个表的字段数要相同&#xff0c;不然会出现报错。列数相同 union 特性是显示两张表 我们就可以吧第一个参数变为------负--的 或者不存在的值 就行了 显示就…

JAVA处理类似饼状图占比和100%问题,采用最大余额法

前言&#xff1a; 在做数据统计报表的时候&#xff0c;有两种方式解决占比总和达不到100%或者超过100%问题。 第一种方式是前端echart图自带的算分框架。 第二种方式是java后端取处理这个问题。 现存问题&#xff1a; 前端通过饼状图的方式去展示各个分类的占比累加和为100%问题…

公司宣传电子画册的制作方法

​制作公司宣传电子画册是一种非常有效的方式&#xff0c;可以展示公司的形象和产品&#xff0c;同时也可以吸引更多的潜在客户。不仅低碳环保&#xff0c;还省了不少人力和财力&#xff0c;只要一个二维码、一个链接就能随时随地访问公司的宣传画册。以下是一些制作电子画册的…

Jmeter学习系列之三:测试计划详细介绍

目录 前言 步骤1:启动JMeter窗口 步骤2:添加/删除测试计划元素 步骤3:加载并保存测试计划元素。 步骤4:配置树元素 步骤5:保存JMeter测试计划 步骤6:运行JMeter测试计划

TSINGSEE青犀视频智慧电梯管理平台,执行精准管理、提升乘梯安全

一、方案背景 随着城市化进程的不断加快&#xff0c;我国已经成为全球最大的电梯生产和消费市场&#xff0c;电梯也成为人们日常生活中不可或缺的一部分。随着电梯数量的激增&#xff0c;电梯老龄化&#xff0c;维保数据不透明&#xff0c;物业管理成本高&#xff0c;政府监管…

openGauss学习笔记-211 openGauss 数据库运维-高危操作一览表

文章目录 openGauss学习笔记-211 openGauss 数据库运维-高危操作一览表211.1 禁止操作211.2 高危操作 openGauss学习笔记-211 openGauss 数据库运维-高危操作一览表 各项操作请严格遵守指导书操作&#xff0c;同时避免执行如下高危操作。 211.1 禁止操作 表1中描述在产品的操…

【golang】22、functional options | 函数式编程、闭包

文章目录 一、配置 Option1.1 options1.2 funcitonal options 一、配置 Option 1.1 options https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html I’ve been trying on and off to find a nice way to deal with setting options in a…

人机认知何时、何处趋同?何时、何处趋异?

对于“算法与人类认知的差异”&#xff0c;人机认知是否应该趋同还是趋异&#xff0c;这是一个复杂的问题&#xff0c;没有简单的答案。 一方面&#xff0c;人机认知的趋同可以使人类能够更好地理解和利用算法的能力&#xff0c;从而提高工作效率和生活质量。趋同意味着人类可以…

数学公式OCR识别php 对接mathpix api 使用公式编译器

数学公式OCR识别php 对接mathpix api 一、注册账号官网网址&#xff1a;https://mathpix.com 二、该产品支持多端使用注意说明&#xff08;每月10次&#xff09; 三、api 对接第一步创建create keyphp对接api这里先封装两个请求函数&#xff0c;get 和post &#xff0c;通过官方…

20240130在ubuntu20.04.6下卸载NVIDIA显卡的驱动

20240130在ubuntu20.04.6下卸载NVIDIA显卡的驱动 2024/1/30 12:58 缘起&#xff0c;为了在ubuntu20.4.6下使用whisper&#xff0c;以前用的是GTX1080M&#xff0c;装了535的驱动。 现在在PDD拼多多上了入手了一张二手的GTX1080&#xff0c;需要将安装最新的545的驱动程序&#…

VxTerm:SSH工具中的中文显示和乱码时的相关信息和一些基本的知识

当我们写的程序含有控制台(Console)输出时&#xff0c;如果输入内容包含中文时&#xff0c;我们一般需要知道下面的信息&#xff0c;才能正确的搞清楚怎么处理中文显示的问题&#xff1a; 1、实际程序或文件中的实际编码&#xff1a; Linux下的应用程序和文本文件&#xff0c;…

CVE-2024-0352 likeshop v2.5.7文件上传漏洞分析

本次的漏洞研究基于thinkPHP开发开的一款项目..... 漏洞描述 Likeshop是Likeshop开源的一个社交商务策略的完整解决方案&#xff0c;开源免费版基于thinkPHP开发。Likeshop 2.5.7.20210311及之前版本存在代码问题漏洞&#xff0c;该漏洞源于文件server/application/api/contr…