年底搞个基于C语言的运动会学生志愿者管理系统

举报
苏州程序大白 发表于 2022/01/07 19:09:06 2022/01/07
【摘要】 目录博主介绍💂 个人主页:苏州程序大白💂 个人社区:CSDN全国各地程序猿🤟作者介绍:中国DBA联盟(ACDU)成员,CSDN全国各地程序猿(媛)聚集地管理员。目前从事工业自动化软件开发工作。擅长C#、Java、机器视觉、底层算法等语言。2019年成立柒月软件工作室,2021年注册苏州凯捷智能科技有限公司💬如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)和C#、Halcon、py...

目录

博主介绍

在这里插入图片描述

💂 个人主页:苏州程序大白
💂 个人社区:CSDN全国各地程序猿
🤟作者介绍:中国DBA联盟(ACDU)成员,CSDN全国各地程序猿(媛)聚集地管理员。目前从事工业自动化软件开发工作。擅长C#、Java、机器视觉、底层算法等语言。2019年成立柒月软件工作室,2021年注册苏州凯捷智能科技有限公司
💬如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)和C#、Halcon、python+opencv、VUE、各大公司面试等一些订阅专栏哦
🎗️ 承接软件APP、小程序、网站等开发重点行业应用开发(SaaS、PaaS、CRM、HCM、银行核心系统、监管报送平台、系统搭建、人工智能助理)、大数据平台开发、商业智能、App开发、ERP、云平台、智能终端、产品化解决方案。测试软件产品测试、应用软件测试、测试平台及产品、测试解决方案。运维数据库维护(SQL Server 、Oracle、MySQL)、 操作系统维护(Windows、Linux、Unix等常用系统)、 服务器硬件设备维护、网络设备维护、 运维管理平台等。运营服务IT咨询 、IT服务、业务流程外包(BPO)、云/基础设施的管理、线上营销、数据采集与标注、内容管理和营销、设计服务、本地化、智能客服、大数据分析等。
💅 有任何问题欢迎私信,看到会及时回复
👤 微信号:stbsl6,微信公众号:苏州程序大白

🍇背景

1、基本掌握面向过程程序设计的基本思路和方法;

2、达到熟练掌握C语言的基本知识和技能;

3、能够利用所学的基本知识和技能,解决简单的程序设计问题;

4、独立进行程序的编写,为后续学习及课程做好准备。


🍇环境

本程序开发所使用的环境:

  • Visual Studio 2010

  • Community版

  • Windows10 Professional操作系统

🍇要求

为了迎接某市运动会,请你学习C语言中相关知识,帮助组委会设计一个运动会志愿者信息管理系统,包含以下主要功能(不限于以下):

  • 实现对志愿者信息的管理,包括添加志愿者信息(姓名,学号,联系方式等等),查询志愿者信息,删除志愿者信息;

  • 实现运动会场馆的管理,包括添加场馆信息,查询场馆信息,删除场馆信息;

  • 实现通过文件保存志愿者信息;

  • 实现每个场馆对应不同志愿者的分配管理(例如,田径场需要4位志愿者,射击馆需要2位志愿者);

  • 实现志愿者和场馆信息的快速查询统计功能,可以根据最后志愿服务时间评选最美志愿者;

  • 除以上基本功能外,可根据各位同学自己设定的需求自行添加。


🍇数据结构

typedef struct sfield{ //场馆信息结构体
    int fieldId; //场馆节点唯一数字id(int)
    char fieldName[30]; //场馆名字(char[30])
    char startTime[20]; //开始时间(char[20])
    int lastTime; //持续时间(int)
    int maxVolunteer; //需要志愿者数量(int)
    int joinedVolunteer[MAX1]; //保存已加入志愿者信息(int[MAX1])  (MAX1=100)
    struct sfield* head; //节点头部指针,指向上一个节点(struct sfield*)
    struct sfield* next; //节点尾部指针,指向下一个节点(struct sfield*)
}field;
typedef struct svolunteer{ //志愿者信息结构体
    int volunteerId; //志愿者节点唯一数字id(int)
    char volunteerName[30]; //志愿者名字(char[30])
    char idNum[20]; //志愿者学号(char[20])
    char phoneNum[20]; //志愿者手机号(char[20])
    int joinedField[MAX2]; //保存志愿者加入场馆唯一id(int[MAX2]) (MAX2=20)
    int serviceTime; //志愿服务时长(int)
    struct svolunteer* head; //节点头部指针,指向上一个节点(struct svolunteer*)
    struct svolunteer* next; //节点尾部指针,指向下一个节点(struct svolunteer*)
}volunteer;

本程序使用两类结构体,分别储存志愿者信息(Volunteer)和场馆信息(Field)。每个结构体准备了指向上一个节点与下一个节点的指针,用于创建动态链表。如果要自行修改为使用数组储存数据,则可以不用这些指针。

🍇定义功能函数

void startUp();//初始化函数,将数据链表头结点头尾部初始化,数据部分清零,防止出错
int readFile(); //读取已保存的数据文件,若不存在则建立
int saveFile(); //储存已保存的数据文件,若不存在则建立
void newField(); 
//新增场馆信息
void newVolunteer(); //新增志愿者信息
void changeField(field*); //修改场馆信息
void changeVolunteer(); //修改志愿者信息
void deleteField(); //删除场馆信息
void deleteVolunteer(); //删除志愿者信息
void bind(); //注册志愿活动
void unbind(); //注销志愿活动
void showMenu(); //显示主菜单
void manageField(); //显示场地管理菜单
void manageVolunteer(); //显示志愿者管理菜单
field* selectFieldById(int); //通过唯一ID查找场馆指针
field* selectFieldByName(char*); //通过场馆名字查找场馆指针
volunteer* selectVolunteerById(int); //通过唯一ID查找志愿者指针
volunteer* selectVolunteerByName(char*); //通过志愿者名字查找志愿者指针
volunteer* selectVolunteerByIdNum(char*); //通过志愿者学号查找志愿者指针
volunteer* selectVolunteerByPhoneNum(char*); //通过志愿者手机号查找志愿者指针
void showField(field*); //显示指定场馆信息
void showVolunteer(volunteer*); //显示指定志愿者信息
void showAllField(); //显示所有场馆信息
void showAllVolunteer(); //显示所有志愿者信息
void findOutTopVolunteer(); //根据志愿服务时长寻找“最美志愿者”
void filePrintMenu(); //显示文件格式化输出菜单
void outPutFile(char*, int); //显示文件格式化输出菜单

🍇运行结果截图

1、启动程序:

2、添加场馆信息:

3、添加志愿者信息:

4、修改运动馆信息:

5、注册志愿活动:

6、注册志愿活动时输入错误数据:

7、场馆满员后注册志愿活动:

8、查询所有志愿者信息:

9、寻找最美志愿者:

10、格式化输出文件:

附:格式化输出的文件内容:

🍇函数模块功能介绍

1、场馆信息管理

进入场馆信息管理模块,显示该模块下可用的操作:新增、修改、删除场馆信息、根据场馆名查询指定场馆信息。

  • 新增场馆信息:调用 newField()函数,并且显示引导提示菜单,引导用户按格式输入要新增的场馆信息,本程序采用整行输入方式,用指定符号分割不同数据类型,最后将读入的输入字符串通过该指定符号进行分割,分割出几组字符串。首先检查字符串数量是否满足输入要求,如果有错误则会报错并退出该函数。若输入格式正确,下一步会调用 selectFieldByName(char*)函数寻找是否已有相同名字场馆信息,若返回非NULL值(即确实已经存在同名场馆),则提示用户该错误并退出本函数。上述检查完成后,通过一开始声明的全局变量 _FIELD找到储存场馆信息链表头结点,归递寻找至链表尾部,同时记录已有的节点数,最后在链表尾部分配新节点并连接上原链表尾,同时新节点的last指针记录原链表尾节点地址。调用 saveFile()函数,将已有的数据保存至磁盘,最后提示用户保存成功结果。

  • 修改场馆信息:先根据用户输入的场馆名,调用 selectFieldByName(char*)函数,若返回空值则提示用户未找到对应名字的链表,否则根据该函数返回的 field*类型指针,调用 changeField(field*)函数。调用此函数后,会先显示该场馆信息节点中记录的场馆信息,并提示用户输入要修改的数据类型。用户输入后,先检查输入是否有误,有误则报错并返回,无误则提示输入要修改成的数据,输入后第输入数据进行检查,无误则将该节点信息对应数据修改为用户输入,调用 saveFile()函数保存文件,最后提示修改成功。

  • 删除场馆信息:先根据用户输入的场馆名,调用 selectFieldByName(char*)函数,若返回空值则提示用户未找到对应名字的链表,否则根据该函数返回的 field*类型指针,调用 deleteField(field*)函数。调用该函数后,会先显示该场馆信息节点中记录的场馆信息,并再次向用户确认是否要删除该场馆信息,用户输入否则退出此函数。若确认删除,先根据该节点的next指针判断此节点是否为链表尾,若非节点尾,则根据该节点的head指针找到上一个节点,分别将 head指针对应的上一个节点中的 next指针指向该要删除节点的 next指针指向的下一个节点,将next指针指向的下一个节点中的 head指针指向该要删除的节点的 head指针指向的上一个节点的地址,接着遍历该节点中的 joinedVolunteer数组,寻找对应的已加入志愿者,找到后进入该志愿者节点,将其 joinedField数组中对应的此要删除节点的id记录删除掉,并将该志愿者的志愿服务时长减去该要删除节点的服务时间长度。待以上操作全部完成后,使用 free(void*)函数释放掉该要删除节点内存,然后调用 saveFile()函数将修改后的链表重新保存至文件。最后向用户返回删除成功提示。

  • 查询指定场馆信息:提示用户输入要查询的场馆名,然后调用 selectFieldByName(char*)函数,若返回空值,则提示未找到对应场馆信息,退出函数。若返回非空值,则根据返回的 field*类型指针,调用 showField(field*)函数,打印出对应场馆信息,并遍历该场馆节点中的 joinedVolunteer数组,通过其中记录的志愿者id,调用 selectVolunteerById(int)寻找每一个加入志愿者对应节点,然后打印出该志愿者信息。

2、志愿者信息管理

该模块功能其实与场馆信息管理功能基本一致,只不过操作对象由场馆链表变为了志愿者链表,其他基本可以类比,这里不再过多赘述。


3、志愿服务管理

该模块没有对应独立二级菜单,仅有的两个功能(注册志愿活动注销志愿活动)直接显示在主菜单,可以直接从主菜单进入。

注册志愿活动:提示用户分别输入要注册的志愿活动对应的场馆信息和志愿者信息,与新增场馆/志愿者信息类似,这里采用读入整行字符串,通过特殊字符串来分割这一整行字符串的方式读取用户输入数据,首先检查输入格式是否有误,确认无误后根据输入数据分别寻找对应的场馆与志愿者节点,此处在输入志愿者姓名后还要求输入学号,作为二次校验,防止输入错误导致的绑定错误,如果输入的姓名与学号不对应同一个志愿者信息节点,则返回错误提示。一切输入数据确认无误后,进行绑定,具体流程如下:

  • 在寻找到的输入场馆节点中的joinedVolunteer数组中进行查找,如果其中已存在对应输入的志愿者id,则提示不能重复绑定同一人并退出此绑定流程。

  • 在寻找到的输入场馆节点检测已加入志愿者是否已达到最大允许加入志愿者数量,若已达到则提示该活动名额已满并退出此绑定流程。

  • 在寻找到的输入志愿者节点中检测其已加入场馆数量是否已达到单个志愿者允许加入的最大场馆数量上限,若是则提示该志愿者志愿活动已达到上限。

  • 以上检查均没有错误后显示对应场馆信息以及志愿者信息,并向用户确认是否要注册该志愿活动,若否则退出注册流程。

  • 在寻找到的输入场馆节点中的joinedVolunteer数组中添加进寻找到的输入志愿者id,在寻找到的输入志愿者节点中的joinedField数组中添加寻找到的输入场馆id,并在寻找到的输入志愿者节点中的serviceTime(服务时间)加上对应场馆志愿活动时间。最后向用户返回注册成功的提示。


4、寻找最美志愿者

调用 findOutTopVolunteer()函数。先设置几个变量供寻找时临时使用,如设置 longestTime0,然后遍历志愿者信息链表(头节点:全局变量 _VOLUNTEERS),遍历到的节点如果 serviceTimelongestTime相同,则向临时的 volunteer*型指针数组的第一个无数据位添加进该节点的地址。然后继续向下遍历,如果遍历到的节点 serviceTime大于 longestTime,则将该节点 serviceTime值赋给 longestTime变量,并用 memset(void*,int,int)函数将原有的 volunteer*型指针数组清空,然后将其第一个数据位加入本节点的地址。最后遍历完成之后,最终打印出 volunteer*型指针数组中非空成员数量,记为“最美志愿者”个数,然后遍历该 volunteer*型指针数组,分别将节点对应成员信息打印出来作为“最美志愿者”信息,以及临时变量 longestTime作为“最美志愿者”的志愿服务时长也打印出来。

5、文件的存取

本程序只会在启动时首先自动执行的 startUp()函数中调用 readFile()函数对已保存文件进行读取,若数据文件不存在则建立数据文件然后退出 readFile()函数。先分别建立 field型volunteer型变量用以储存临时数据,打开“fieldData.txt”文件,使用 fread()函数按块读入已储存的数据内容,并将其存入 field型临时变量中,然后分配 field大小内存作为节点将该变量的值分别赋入节点中对应变量,并将上一个节点的 next指针指向本新分配节点,将本新分配节点的head指针指向上一个节点,将 next指针设为NULL。循环 fread()函数以及后面这一组操作,直到读取到文件尾,最后关闭文件。然后对 volunteer型数据进行相同的操作,此处类比。

在每一次新增、修改、删除操作(不论是对场馆信息还是志愿者信息)以及注册、注销志愿活动之后,都会调用 saveFile()函数对数据进行保存。若数据文件存在也会使用“w”模式将数据全部重新覆写,接着类似 readFile(),先建立临时变量,根据全局变量 _FIELD找到场馆信息链表头,然后遍历场馆信息链表,将每个节点中的数据部分(即除 head、next指针外的部分)拷贝到临时变量,然后调用 fwrite()函数将数据写入文件,直至链表遍历完毕,最后关闭文件。然后对 volunteer型数据进行相同的操作,此处类比。

本程序虽然没有使用“wb”类的二进制数据储存法,但是使用的 fwrite()函数是不会对非字符类型变量进行转换的,所以生成的数据文件虽以文本形式储存,但是其对应非char类型的数据位部分会显示乱码,而且字符串\0后未填满部分也会以“烫”字储存(因为VS编译器对于字符串中空字符默认的特性),所以本程序直接生成的数据文件并不具备有良好的可读性,为了解决这一问题,本程序额外加入了“格式化输出文件”功能(自主添加的额外功能),将数据以人类可阅读的形式格式化输出。

💫点击直接资料领取💫

在这里插入图片描述

这里有各种学习资料还有有有趣好玩的编程项目,更有难寻的各种资源。 ​ ​

❤️关注微信苏州程序大白公众号❤️



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。