Verilog笔记（一） —— 常用的给连续信号延时的手段
使用verilog进行编程时，经常会遇到需要对连续信号进行延时处理的情况，这里记录一下常用的给信号进行延时打拍的手段。 方案一：使用多个寄存器采用时序逻辑依次赋值，如下： /****************************************************************\ 此方案使用了3倍数据位宽的寄存器，实现了延迟2拍输出数据的效果 \****************************************************************/ module aaa( input clk, input rst_n, input [7:0]data_in, output [7:0]data_out ); reg [7:0]data_delay_1, data_delay_2, data_delay_3; always @(posedge clk or negedge rst_n) if(!rst_n) begin data_delay_1 <= 8'h0; data_delay_2 <= 8'h0; data_delay_3 <= 8'h0; end else begin data_delay_1 <= data_in; data_delay_2 <= data_delay_1; data_delay_3 <= data_delay_2; end assign data_out = data_delay_3; endmodule 方案优点：延时拍数较少时方便阅读，常见于需要延时一两拍的场景下。 方案缺点：延时拍数较多时阅读性变差。 至于资源占用其实在FPGA综合布线时会被自动优化成移位寄存器形式。 方案二：使用移位寄存器 待补充，先鸽了，总而言之就是使用shift_ram巴拉巴拉巴拉...
基于nonebotV2与go-cqhttp，写一个属于自己的QQ机器人 介绍 要写一个属于自己的QQ机器人，首先要了解QQ机器人的组成原理，不同组件实现的功能以及实现方式。 组件名 作用 描述 go-cqhttp 无头客户端 与QQ服务器连接，模拟真实QQ客户端，与自己的后端逻辑框架（即头）进行交互，实现各种消息通知的收发 nonebot2 “头骨” 接受无头客户端发送来的消息，提供封装好的方法供开发者编写处理逻辑，相当于“头骨”，起框架作用 这篇文章 （个系列） 会基于以上框架，自行编写处理逻辑，实现自己想要的功能 注意 nonebot是使用python3来编写的框架，后续的所有相关代码都是基于在nonebot可以运行的python环境（python3 >= 3.7）下编写与测试。虽然python相对比较容易入门，编写这样的机器人还是需要有少许编程基础知识的，完全没有任何相关概念的人尽早右上退出吧（~虽然我自己也就是个半吊子水平~）。 环境 编写环境是Windows10,amd64,python3.8 本文编写时所使用框架版本：nonebot 2.0.0a9,go-cqhttp v0.9.39 安装所需环境： nonebot: pip3 install nonebot go-cqhttp: https://github.com/Mrs4s/go-cqhttp/releases 注意根据自己的系统、处理器架构来挑选对应的可执行文件 例如： Windows系统，AMD64架构，则下载后缀为windows-amd64.exe的文件 Linux系统，I386架构，则下载后缀为linux-i386的文件 go-cqhttp配置 在go-cqhttp可执行文件同目录下创建config.hjson，按照如下模板修改信息配置 /* go-cqhttp 默认配置文件 */ { // QQ号 uin: 12345678 // QQ密码 password: "这里填机器人QQ密码" // 是否启用密码加密 encrypt_password: false // 加密后的密码, 如未启用密码加密将为空, 请勿随意修改. password_encrypted: "" // 是否启用内置数据库 // 启用将会增加10-20MB的内存占用和一定的磁盘空间 // 关闭将无法使用 撤回 回复 get_msg 等上下文相关功能 enable_db: true // 访问密钥, 强烈推荐在公网的服务器设置 access_token: "" // 重连设置 relogin: { // 是否启用自动重连 // 如不启用掉线后将不会自动重连 enabled: true // 重连延迟, 单位秒 relogin_delay: 3 // 最大重连次数, 0为无限制 max_relogin_times: 0 } // API限速设置 // 该设置为全局生效 // 原 cqhttp 虽然启用了 rate_limit 后缀, 但是基本没插件适配 // 目前该限速设置为令牌桶算法, 请参考: // https://baike.baidu.com/item/%E4%BB%A4%E7%89%8C%E6%A1%B6%E7%AE%97%E6%B3%95/6597000?fr=aladdin _rate_limit: { // 是否启用限速 enabled: false // 令牌回复频率, 单位秒 frequency: 1 // 令牌桶大小 bucket_size: 1 } // 是否忽略无效的CQ码 // 如果为假将原样发送 ignore_invalid_cqcode: false // 是否强制分片发送消息 // 分片发送将会带来更快的速度 // 但是兼容性会有些问题 force_fragmented: false // 心跳频率, 单位秒 // -1 为关闭心跳 heartbeat_interval: 0 // HTTP设置 http_config: { // 是否启用正向HTTP服务器 enabled: false // 服务端监听地址 host: 0.0.0.0 // 服务端监听端口 port: 5700 // 反向HTTP超时时间, 单位秒 // 最小值为5，小于5将会忽略本项设置 timeout: 0 // 反向HTTP POST地址列表 // 格式: // { // 地址: secret // } post_urls: {} } // 正向WS设置 ws_config: { // 是否启用正向WS服务器 enabled: false // 正向WS服务器监听地址 host: 0.0.0.0 // 正向WS服务器监听端口 port: 6700 } // 反向WS设置 ws_reverse_servers: [ // 可以添加多个反向WS推送 { // 是否启用该推送 enabled: true // 反向WS Universal 地址 // 注意 设置了此项地址后下面两项将会被忽略 // 留空请使用 "" reverse_url: ws://127.0.0.1:8080/cqhttp/ws // 反向WS API 地址 reverse_api_url: ws://you_websocket_api.server // 反向WS Event 地址 reverse_event_url: ws://you_websocket_event.server // 重连间隔 单位毫秒 reverse_reconnect_interval: 3000 } ] // 上报数据类型 // 可选: string array post_message_format: array // 是否使用服务器下发的新地址进行重连 // 注意, 此设置可能导致在海外服务器上连接情况更差 use_sso_address: false // 是否启用 DEBUG debug: true // 日志等级 log_level: "" // WebUi 设置 web_ui: { // 是否启用 WebUi enabled: false // 监听地址 host: 127.0.0.1 // 监听端口 web_ui_port: 9999 // 是否接收来自web的输入 web_input: true } } 其中要注意的是反向WS相关设置 原理： nonebot框架与无头客户端的连接逻辑是nonebot启动一个Websocket服务端，然后QQ无头客户端主动连接至nonebot开启的WS服务端，并通过WS协议推送消息、调用API，对于无头客户端来说，主动连接至已有的WS服务器就算作是反向WS服务端，所以要根据nonebot的相关信息配置好反向WS相关配置 配置项 说明 enabled 开关，当然是填true啊，否则下列配置直接就是无意义的 reverse_url 目标服务器的url，如果你的nonebot与go-cqhttp运行在同一台主机上，这里就可以填写为ws://运行nonebot机器的地址:端口号/适配器名称/ws，如果是同一台机器，地址可以填为127.0.0.1端口号与适配器名称取决于nonebot的配置，后文会写。 运行go-cqhttp 以上配置文件配置完毕后，运行go-cqhttp的可执行文件： Windows下：使用powershell终端 ~（真别用CMD了）~ 打开可执行文件所在目录，执行./文件名 如果出现类似设备锁、安全验证等提示，按照提示完成步骤即可。出现成功提示后，代表你的QQ无头客户端已经成功运行了。 运行一个最小的nonebot实例 在要编写机器人处理程序的目录下新建文件，名为bot.py，内容如下填写 import nonebot from nonebot.adapters.cqhttp import Bot as CQHTTPBot nonebot.init() driver = nonebot.get_driver() driver.register_adapter("cqhttp", CQHTTPBot) # 这里的第一个参数即为前文提到的“适配器名称”，要相互对应 nonebot.load_builtin_plugins() if __name__ == "__main__": nonebot.run(host="0.0.0.0",port=8080) # 第一个参数代表监听地址，如果你的nonebot与go-cqhttp运行在同一个机器上，这里可以填写为127.0.0.1 # 如果在同一局域网则可以填写局域网所在网段网络号，例如`192.168.1.0` # 而如果两个程序相互处于公网状态，则填写`0.0.0.0`吧，表示监听所有地址。 # 第二个参数代表端口号，与前文go-cqhttp配置中的端口号相对应。 如果没有出错，python3 bot.py运行nonebot，nonebot 所在的控制台应该会输出类似下面的内容（两条访问日志）： 09-14 21:31:16 [INFO] uvicorn | ('127.0.0.1', 12345) - "WebSocket /cqhttp/ws" [accepted] 09-14 21:31:16 [INFO] nonebot | WebSocket Connection from CQHTTP Bot 你的QQ号 Accepted! 这表示 CQHTTP 协议端已经成功地使用 CQHTTP 协议连接上了 NoneBot。 现在，尝试向你的机器人账号发送如下内容： /echo hello world! 到这里如果一切 OK，你应该会收到机器人给你回复了 你好，世界。这一历史性的对话标志着你已经成功地运行了一个 NoneBot 的最小实例。 结束 基本机器人的创建教程到此为止，后续文章会尝试从编写第一个自己的插件来记录。 未完待续
前言 不得不说handsome这款主题确实还挺美观方便的，只是有部分小问题需要自行修改，比如侧边栏自带广告位很适合拿来放置一些自定义小部件，但他会自带一个“广告”标题在上方（即使放的内容根本就不是广告），让人有点不爽。下面写出如何去除或修改该标题方法。 步骤 来到网站目录，typecho下handsome主题的目录路径为 /usr/themes/handsome/打开该目录下的component目录，修改sidebar.php 如果你未曾修改过该文件的话，待修改内容在文件的第106行附近 <?php if ($this->options->adContentSidebar != ""): ?> <?php _me("广告") ?> <?php $this->options->adContentSidebar(); ?> <?php endif; ?> 如果要删除这个标题，则将 <?php _me("广告") ?> 这一整行删除，如果要修改内容为自定义内容，修改“广告”二字为自己想要内容，最后保存即可。 效果对比 修改前： 修改后
C语言线性单链表的建立与简单使用
实验内容 编写程序完成单链表的下列基本操作： 建立一个长度为n的单链表。 插入新结点。 删除某一个结点。 打印输出La中的结点元素值。 实验方法 数据产生 通过随机数函数获得数据，或通过赋值方法确定数据。 线性表的插入与删除 线性表在本次实验中是动态变化，插入、删除元素，为使线性表任保持有序性，必须要找到元素插入或删除的位置。 源代码 /******************** > File Name: ll.c > Author:Raoby > School:WUST_EEA_1801班 > Myblog:www.raobee.com > Mail:1458096930@qq.com > Created Time: 2020年06月03日 星期三 21时22分23秒 ********************/ #include <stdlib.h> #include <stdio.h> #include <math.h> #include <time.h> typedef struct sNode { int data; struct sNode* next; }Node; int creat(Node* head, int length) //创建新链表 { //根据输入的指针作为头部，创建长度为length，数据为随机数的链表 int i; //计数局部变量 Node* p2,*p1 = head; //局部指针变量 srand((unsigned int)time(NULL)); for (i = 0; i < length; i++) { if (p2 = (Node*)malloc(sizeof(Node))) { //申请内存成功 p2->data = rand(); p2->next = NULL; //此步此处其实可以忽略，因为循环体中都会赋值 p1->next = p2; p1 = p2; } else { //申请内存出现问题，退出循环体，清除已分配的区域并返回-1错误码 break; } } if (i < length) { //未达到循环条件便退出，认为是分配内存错误，清除已分配区域 p1 = head->next; while (p1) { p2 = p1->next; free(p1); p1 = p2; } return -1; } p1->next = NULL; //末尾节点指针设为空 return 0; //创建成功 } int insert(Node* head, int place, int data) //输入插入至第place位，原本place位及之后数据向后移 { int i; Node* p2, * p1 = head; if (place <= 0) //输入数据位置有误 { return -1; } //定位至第place号节点前一位 for (i = 0; i < place-1; i++) { if (!p1->next) { return -1; //输入数据越界 } p1 = p1->next; } p2 = p1->next; p1->next = (Node*)malloc(sizeof(Node)); p1->next->next = p2; p1->next->data = data; return 0; } int delete(Node* head, int place) { int i; Node* p2,*p1 = head; p2 = p1; if (place <= 0) //输入数据位置有误 { return -1; } //定位至第place号节点前一位 for (i = 0; i < place; i++) { p2 = p1; p1 = p1->next; if (!p1) //若p1变为空指针，即输入位置越界，删除失败，返回-1 { return -1; } } p2->next = p1->next; //被删除节点上节点连接至下节点 free(p1); return 0; } int* show(Node* head, int place) //查询指定节点数据函数，查询成功返回指定节点数据指针 { int i; Node* p = head; if (place <= 0) //输入数据位置有误 { return NULL; } for (i = 0; i < place; i++) { p = p->next; if (!p) //若p变为空指针，即输入位置越界，查询失败，返回空指针 { return NULL; } } return &(p->data); } int change(Node* head, int place, int NewData) { int i; Node* p = head; if (place <= 0) //输入数据位置有误 { return -1; } for (i = 0; i < place; i++) { p = p->next; if (!p) //若p变为空指针，即输入位置越界，查询失败，返回-1 { return -1; } } p->data = NewData; return 0; } int main() { int choose = 1, length,ret,*pret,input1,input2; Node* gnode=malloc(sizeof(Node)); printf("请输入要新增的单链表长度，输入非正整数自动退出："); scanf("%d", &length); if (length <= 0) { printf("运行结束"); return 0; } if (ret = creat(gnode, length)) { //如果返回值不为0会进入此处，即创建链表失败 printf("创建失败！\n可能是内存不足，返回值：%d\n",ret); return 0; } while (choose) { system("cls"); //清空屏幕 printf("请输入一个选项\n1.在链表指定位置新增节点\n2.删除指定节点\n3.查看指定位置节点数据\n4.修改指定位置节点数据\n0.退出程序\n请输入:"); scanf("%d", &choose); switch (choose) { case 1: { printf("输入要插入的位数与数据，用半角逗号分割，原本此位若有数据会向后移:"); scanf("%d,%d", &input1, &input2); if (input1 <= 0) { printf("输入有误，退出插入\n"); } else { if (ret = insert(gnode, input1, input2)) { //返回值不为零代表出错 switch (ret) { case -1: { printf("输入位置越界！\n"); break; } default: { printf("插入出错，错误码：%d", ret); } } } else { printf("插入成功！\n"); } } system("pause"); break; } case 2: { printf("输入要删除数据位置:"); scanf("%d", &input1); if (input1 <= 0) { printf("输入有误，退出插入\n"); } else { if (ret = delete(gnode, input1)) { //返回值不为零代表出错 switch (ret) { case -1: { printf("输入位置越界！\n"); break; } default: { printf("删除出错，错误码：%d", ret); } } } else { printf("删除数据成功！\n"); } } system("pause"); break; } case 3: { printf("输入要查看节点位置:"); scanf("%d", &input1); if (input1 <= 0) { printf("输入有误，退出插入\n"); } else { if (!(pret = show(gnode, input1))) { //返回值为零代表出错 printf("查看数据出错！\n"); } else { printf("第%d位的数据为:%d\n",input1,*pret); } } system("pause"); break; } case 4: { printf("输入要修改的位数与数据，用半角逗号分割:"); scanf("%d,%d", &input1, &input2); if (input1 <= 0) { printf("输入有误，退出插入\n"); } else { if (ret = change(gnode, input1, input2)) { //返回值不为零代表出错 switch (ret) { case -1: { printf("输入位置越界！\n"); break; } default: { printf("修改出错，错误码：%d", ret); } } } else { printf("修改成功！\n"); } } system("pause"); break; } } } printf("运行结束！\n"); return 0; }
基于C语言的军运会学生志愿者管理系统 关键词：C语言、课程设计、军运会志愿者管理系统 一、背景 基本掌握面向过程程序设计的基本思路和方法； 达到熟练掌握C语言的基本知识和技能； 能够利用所学的基本知识和技能，解决简单的程序设计问题； 独立进行程序的编写，为后续学习及课程做好准备。 二、环境 本程序开发所使用的环境为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()函数。先设置几个变量供寻找时临时使用，如设置 longestTime为0，然后遍历志愿者信息链表（头节点：全局变量 _VOLUNTEERS），遍历到的节点如果 serviceTime与 longestTime相同，则向临时的 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编译器对于字符串中空字符默认的特性），所以本程序直接生成的数据文件并不具备有良好的可读性，为了解决这一问题，本程序额外加入了“格式化输出文件”功能（自主添加的额外功能），将数据以人类可阅读的形式格式化输出。 七、源代码 [scode type="yellow"] 以下代码均为本人（Raoby) 原创，欢迎本着学习目的参考借鉴，禁止直接盗用为自己的作品（虽然我也管不着你）。 [/scode] [scode type="yellow"]本作品为本人自行完成的一份课程设计，提交后便没有再进行过修改或是debug，如果出现bug严重影响使用请自行修改，如果有兴趣可以联系我讨论。联系可用本站评论或是邮件至admin@raobee.com[/scode] 源代码 [collapse status="false" title="C语言军运会志愿者管理系统.c"] #include <stdlib.h> #include <stdio.h> #include <string.h> #define MAX1 100 //设置单场馆最大参加志愿者人数100 #define MAX2 20 //设置个人默认最大参加项目数量20 typedef struct sfield{ //场馆信息结构体 int fieldId; //场馆节点唯一数字ID char fieldName[30]; //场馆名字 char startTime[20]; //开始时间 int lastTime; //持续时间（分钟） int maxVolunteer; //需要志愿者数量 int joinedVolunteer[MAX1]; //保存已加入志愿者信息 struct sfield* head; //节点头部指针 struct sfield* next; //节点尾部指针 }field; typedef struct svolunteer{ //志愿者信息结构体 int volunteerId; //志愿者节点唯一数字ID char volunteerName[30]; //志愿者名字 char idNum[20]; //志愿者学号 char phoneNum[20]; //志愿者手机号 int joinedField[MAX2]; //志愿者加入场馆唯一ID数组 int serviceTime; //志愿者服务时长 struct svolunteer* head; //节点头部指针 struct svolunteer* next; //节点尾部指针 }volunteer; //声明函数 void startUp(); //初始化函数 int readFile(); //读取文件 int saveFile(); //储存文件 void newField(); //新增场馆 void newVolunteer(); //新增志愿者 void changeField(field*); //修改场馆 void changeVolunteer(volunteer*); //修改志愿者 void deleteField(field*); //删除场馆 void deleteVolunteer(volunteer*); //删除志愿者 void bind(); //注册志愿活动 void unbind(); //注销志愿活动 void showMenu(); //显示主菜单 void manageField(); //显示场地管理菜单 void manageVolunteer(); //显示志愿者管理菜单 void filePrintMenu(); //显示文件格式化输出菜单 void outputFile(char*,int); //自定义文件输出 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(); //寻找最美志愿者 //初始化全局变量 field * _FIELD; //分配场馆信息头部节点 volunteer * _VOLUNTEER; //分配志愿者信息头部节点 void startUp(){ system("title 军运会管理系统--by Raoby"); //设置窗口标题 system("color 70"); _FIELD=(field*)malloc(sizeof(field)); _VOLUNTEER=(volunteer*)malloc(sizeof(volunteer)); _FIELD->head=NULL; _VOLUNTEER->head=NULL; _FIELD->next=NULL; _VOLUNTEER->next=NULL; readFile(); } //函数定义部分 int saveFile(){ int fieldLength,volunteerLength,i; FILE* fp1,*fp2; field _TEMP1; volunteer _TEMP2; field* p1=_FIELD->next; volunteer* p2=_VOLUNTEER->next; fp1=fopen("fieldData.txt","w"); fclose(fp1); fp1=fopen("fieldData.txt","a"); for(fieldLength=0;p1;p1=p1->next){ fieldLength++; } fp2=fopen("volunteerData.txt","w"); fclose(fp2); fp2=fopen("volunteerData.txt","a"); for(volunteerLength=0;p2;p2=p2->next){ volunteerLength++; } p1=_FIELD->next; p2=_VOLUNTEER->next; i=0; while(i++<fieldLength){ memcpy((void*)&_TEMP1,p1,sizeof(field)-2*sizeof(field*)); if(!fwrite((void*)&_TEMP1,sizeof(field)-2*sizeof(field*),1,fp1)){ fclose(fp1); fp1=fopen("fieldData.txt","w"); fclose(fp1); return EOF; } p1=p1->next; } fclose(fp1); printf("已保存%d个场馆数据\n",i-1); i=0; while(i++<volunteerLength){ memcpy((void*)&_TEMP2,p2,sizeof(volunteer)-2*sizeof(volunteer*)); if(!fwrite((void*)&_TEMP2,sizeof(volunteer)-2*sizeof(volunteer*),1,fp2)){ fclose(fp2); fp1=fopen("volunteerData.txt","w"); fclose(fp2); return EOF; } p2=p2->next; } fclose(fp2); printf("已保存%d个志愿者数据\n",i-1); //system("pause"); return 1; } int readFile(){ int fieldLength=0,volunteerLength=0; FILE* fp1,*fp2; field _TEMP1; volunteer _TEMP2; field* p1=_FIELD; volunteer* p2=_VOLUNTEER; if(!(fp1=fopen("fieldData.txt","r"))){ fp1=fopen("fieldData.txt","w"); fclose(fp1); }else{ for(fieldLength=0;fread((void*)&_TEMP1,sizeof(field)-2*sizeof(field*),1,fp1);fieldLength++){ p1->next=(field*)malloc(sizeof(field)); memcpy(p1->next,&_TEMP1,sizeof(field)-2*sizeof(field*)); p1->next->head=p1; p1->next->next=NULL; p1=p1->next; } fclose(fp1); } if(!(fp2=fopen("volunteerData.txt","r"))){ fp2=fopen("volunteerData.txt","w"); fclose(fp2); }else{ for(volunteerLength=0;fread((void*)&_TEMP2,sizeof(volunteer)-2*sizeof(volunteer*),1,fp2);volunteerLength++){ p2->next=(volunteer*)malloc(sizeof(volunteer)); memcpy(p2->next,&_TEMP2,sizeof(volunteer)-2*sizeof(volunteer*)); p2->next->head=p2; p2->next->next=NULL; p2=p2->next; } fclose(fp2); } /*printf("共有%d个场馆数据\n",fieldLength); printf("共有%d个志愿者数据\n",volunteerLength);*/ //system("pause"); return 1; } field* selectFieldById(int id){ //通过唯一id查找场馆指针 field* p=_FIELD; do{ if(p->fieldId==id){ return p; } p=p->next; }while(p); return NULL; } field* selectFieldByName(char* name){ //通过场馆名字查找场馆指针 field* p=_FIELD; do{ if(!strcmp(p->fieldName,name)){ return p; } p=p->next; }while(p); return NULL; } volunteer* selectVolunteerById(int id){ //通过唯一id查找志愿者指针 volunteer* p=_VOLUNTEER; do{ if(p->volunteerId==id){ return p; } p=p->next; }while(p); return NULL; } volunteer* selectVolunteerByName(char* name){ //通过志愿者名字查找志愿者指针 volunteer* p=_VOLUNTEER; do{ if(!strcmp(p->volunteerName,name)){ return p; } p=p->next; }while(p); return NULL; } volunteer* selectVolunteerByIdNum(char* idNum){ //通过志愿者学号查找志愿者指针 volunteer* p=_VOLUNTEER; do{ if(!strcmp(p->idNum,idNum)){ return p; } p=p->next; }while(p); return NULL; } volunteer* selectVolunteerByPhoneNum(char* phoneNum){ //通过志愿者手机号查找志愿者指针 volunteer* p=_VOLUNTEER; do{ if(!strcmp(p->phoneNum,phoneNum)){ return p; } p=p->next; }while(p); return NULL; } void manageField(){ //显示场地管理菜单 int tmp,tmp2; char input[50]; field* _TEMP; system("cls"); printf("\t\t\t****************************************\t\t\t\n"); printf("\t\t\t\t1.新增场馆\n"); printf("\t\t\t\t2.修改场馆\n"); printf("\t\t\t\t3.删除场馆\n"); printf("\t\t\t\t4.查询指定场馆信息\n"); printf("\t\t\t\t0.返回主菜单\n"); printf("\t\t\t****************************************\t\t\t\n"); printf("\n请选择要执行的操作："); scanf("%d",&tmp); switch(tmp){ case 1:newField();break; case 2: printf("请输入修改场馆原名\n不输入直接回车返回主菜单\n"); getchar();gets(input); if(!input[0]){ return; } system("cls"); if(_TEMP=selectFieldByName(input)){ changeField(_TEMP); }else{ printf("抱歉，未能找到名称为\"%s\"的场馆\n",input); system("pause"); return; } break; case 3: printf("请输入要删除的场馆原名\n不输入直接回车返回主菜单\n"); getchar();gets(input); if(!input[0]){ return; } system("cls"); if(_TEMP=selectFieldByName(input)){ deleteField(_TEMP); }else{ printf("抱歉，未能找到名称为\"%s\"的场馆\n",input); system("pause"); return; } break; case 4: printf("请输入场馆名字\n不输入直接回车返回主菜单\n"); getchar();gets(input); if(!input[0]){ return; } system("cls"); if(_TEMP=selectFieldByName(input)){ showField(_TEMP); }else{ printf("抱歉，未能找到名称为\"%s\"的场馆\n",input); system("pause"); return; } break; } } void manageVolunteer(){ //显示志愿者管理菜单 int tmp,tmp2; char input[50]; volunteer* _TEMP; system("cls"); printf("\t\t\t****************************************\t\t\t\n"); printf("\t\t\t\t1.新增志愿者\n"); printf("\t\t\t\t2.修改志愿者\n"); printf("\t\t\t\t3.删除志愿者\n"); printf("\t\t\t\t4.查询指定志愿者信息\n"); printf("\t\t\t\t0.返回主菜单\n"); printf("\t\t\t****************************************\t\t\t\n"); printf("\n请选择要执行的操作："); scanf("%d",&tmp); switch(tmp){ case 1:newVolunteer();break; case 2: printf("请输入修改志愿者学号\n不输入直接回车返回主菜单\n"); getchar();gets(input); if(!input[0]){ return; } system("cls"); if(_TEMP=selectVolunteerByIdNum(input)){ changeVolunteer(_TEMP); }else{ printf("抱歉，未能找到学号为\"%s\"的志愿者\n",input); system("pause"); return; } break; case 3: printf("请输入要删除的志愿者学号\n不输入直接回车返回主菜单\n"); getchar();gets(input); if(!input[0]){ return; } system("cls"); if(_TEMP=selectVolunteerByIdNum(input)){ deleteVolunteer(_TEMP); }else{ printf("抱歉，未能找到学号为\"%s\"的志愿者\n",input); system("pause"); return; } break; case 4: printf("请输入志愿者学号\n不输入直接回车返回主菜单\n"); getchar();gets(input); if(!input[0]){ return; } system("cls"); if(_TEMP=selectVolunteerByIdNum(input)){ showVolunteer(_TEMP); }else{ printf("抱歉，未能找到学号为\"%s\"的志愿者\n",input); system("pause"); return; } break; } } void newField(){ char input[100]; char temp[10][50]; char* temp2; int i; field* p=_FIELD; printf("请输入要新建场馆的名字,开始时间,持续时间,需要志愿者人数，用英文半角逗号\",\"来隔开\n直接输入0并回车退出新增场馆\n请输入\n\t"); //scanf("%s",input); getchar();gets(input); if(input[0]=='0'){ printf("输入完毕！\n"); system("pause"); return ; } temp2=strtok(input,","); if(!temp2){ printf("输入有误！"); system("pause"); return ; } strcpy(temp[0],temp2); for(i=1;i<4;i++){ temp2=strtok(NULL,","); if(!temp2){ printf("输入有误！"); system("pause"); return ; } strcpy(temp[i],temp2); } if(selectFieldByName(temp[0])){ printf("已存在名字为\"%s\"的同名场馆，请重新输入！\n",temp[0]); system("pause"); return ; } i=1; while(p->next){ i++; p=p->next; } p->next=(field*)malloc(sizeof(field)); p->next->head=p; p->next->next=NULL; p->next->fieldId=i; strcpy(p->next->fieldName,temp[0]); strcpy(p->next->startTime,temp[1]); memset(p->next->joinedVolunteer,0,sizeof(_FIELD->joinedVolunteer)); p->next->lastTime=atoi(temp[2]); p->next->maxVolunteer=atoi(temp[3]); saveFile(); printf("新增场馆成功！\n\n\t场馆名：%s\n\t开始时间：%s\n\t持续时间：%d\n\t需要志愿者人数：%d\n\n",temp[0],temp[1],atoi(temp[2]),atoi(temp[3])); system("pause"); } void newVolunteer(){ char input[100]; char temp[10][50]; char* temp2; int i; volunteer* p=_VOLUNTEER; printf("请输入要添加志愿者的名字,学号,手机号，用英文半角逗号\",\"来隔开\n直接输入0并回车退出新增志愿者\n请输入\n\t"); //scanf("%s",input); getchar();gets(input); if(input[0]=='0'){ printf("输入完毕！\n"); system("pause"); return ; } temp2=strtok(input,","); if(!temp2){ printf("输入有误！"); system("pause"); return ; } strcpy(temp[0],temp2); for(i=1;i<3;i++){ temp2=strtok(NULL,","); if(!temp2){ printf("输入有误！"); system("pause"); return ; } strcpy(temp[i],temp2); } if((selectVolunteerByIdNum(temp[1]))||(selectVolunteerByPhoneNum(temp[2]))){ printf("已存在学号为\"%s\"或手机号为\"%s\"的志愿者，请重新输入！\n",temp[1],temp[2]); system("pause"); return ; } i=1; while(p->next){ i++; p=p->next; } p->next=(volunteer*)malloc(sizeof(volunteer)); p->next->head=p; p->next->next=NULL; p->next->volunteerId=i; strcpy(p->next->volunteerName,temp[0]); strcpy(p->next->idNum,temp[1]); strcpy(p->next->phoneNum,temp[2]); memset(p->next->joinedField,0,sizeof(_VOLUNTEER->joinedField)); p->next->serviceTime=0; saveFile(); printf("新增志愿者成功！\n\n\t志愿者名：%s\n\t学号：%s\n\t手机号：%s\n\n",temp[0],temp[1],temp[2]); system("pause"); } void changeField(field* p){ int temp; char input[50]; system("cls"); printf("当前场馆信息：\n"); printf("\t场馆名称：%s\t开始时间：%s\t持续时间：%d\t需求志愿者数量：%d\n",p->fieldName,p->startTime,p->lastTime,p->maxVolunteer); printf("请选择要修改项目：\n\t1.名称\n\t2.开始时间\n\t3.持续时间\n\t4.需求志愿者数量\n\t0.返回主界面"); scanf("%d",&temp); switch(temp) { case 1: printf("原数值：%s\n请输入新的值，直接回车取消修改：",p->fieldName); getchar();gets(input); if(!input[0]){ printf("取消修改\n"); system("pause"); return; } if(selectFieldByName(input)){ printf("已存在名称为： %s 的场馆，请更换名称",input); system("pause"); return; } strcpy(p->fieldName,input); printf("已将场馆名称修改为：%s\n",input); system("pause"); break; case 2: printf("原数值：%s\n请输入新的值，直接回车取消修改：",p->startTime); getchar();gets(input); if(!input[0]){ printf("取消修改\n"); system("pause"); return; } strcpy(p->startTime,input); printf("已将开始时间修改为：%s\n",input); system("pause"); break; case 3: printf("原数值：%d\n请输入新的值，直接回车取消修改：",p->lastTime); getchar();gets(input); if(!input[0]){ printf("取消修改\n"); system("pause"); return; } p->lastTime=atoi(input); printf("已将持续时间修改为：%d\n",atoi(input)); system("pause"); break; case 4: printf("原数值：%d\n请输入新的值，直接回车取消修改：",p->maxVolunteer); getchar();gets(input); if(!input[0]){ printf("取消修改\n"); system("pause"); return; } p->maxVolunteer=atoi(input); printf("已将需要志愿者数量修改为：%d\n",atoi(input)); system("pause"); break; default:return; } saveFile(); } void changeVolunteer(volunteer* p){ int temp; char input[50]; system("cls"); printf("当前志愿者信息：\n"); printf("\t姓名：%s\t学号：%s\t手机号：%s\n",p->volunteerName,p->idNum,p->phoneNum); printf("请选择要修改项目：\n\t1.姓名\n\t2.学号\n\t3.手机号\n\t0.返回主界面"); scanf("%d",&temp); switch(temp) { case 1: printf("原数值：%s\n请输入新的值，直接回车取消修改：",p->volunteerName); getchar();gets(input); if(!input[0]){ printf("取消修改\n"); system("pause"); return; } strcpy(p->volunteerName,input); printf("已将志愿者姓名修改为：%s\n",input); system("pause"); break; case 2: printf("原数值：%s\n请输入新的值，直接回车取消修改：",p->idNum); getchar();gets(input); if(!input[0]){ printf("取消修改\n"); system("pause"); return; } if(selectVolunteerByIdNum(input)){ printf("已存在学号为： %s 的志愿者，修改失败",input); system("pause"); return; } strcpy(p->idNum,input); printf("已将学号修改为：%s\n",input); system("pause"); break; case 3: printf("原数值：%s\n请输入新的值，直接回车取消修改：",p->phoneNum); getchar();gets(input); if(!input[0]){ printf("取消修改\n"); system("pause"); return; } strcpy(p->phoneNum,input); printf("已将志愿者手机号修改为：%s\n",input); system("pause"); break; default:return; } saveFile(); } void deleteField(field* p){ //删除指定场馆 int id,i; char temp1; field *p1,*p2; volunteer *p3; id=p->fieldId; system("cls"); printf("当前场馆信息：\n"); printf("\t场馆名称：%s\t开始时间：%s\t持续时间：%d\t需求志愿者数量：%d\n",p->fieldName,p->startTime,p->lastTime,p->maxVolunteer); printf("请确认是否要删除！(Y/N)"); scanf("%c",&temp1); if(temp1!='Y'){ printf("取消删除！\n"); system("pause"); return; } //删除所有志愿者中此场馆的注册记录并减少相应志愿时长 for(p3=_VOLUNTEER->next;p3;p3=p3->next){ for(i=0;p3->joinedField[i];i++){ if(p3->joinedField[i]==id){ p3->serviceTime-=p->lastTime; if(!p3->joinedField[i+1]){ p3->joinedField[i]=0; }else{ for(;p3->joinedField[i+1];i++){ p3->joinedField[i]=p3->joinedField[i+1]; } p3->joinedField[i]=0; } break; } } } p1=p->head,p2=p->next; if(p2){ p1->next=p2; p2->head=p1; free(p); }else{ p1->next=NULL; free(p); } saveFile(); printf("删除成功！\n"); system("pause"); return; } void deleteVolunteer(volunteer* p){ //删除指定志愿者 int id,i; char temp1; volunteer *p1,*p2; field *p3; id=p->volunteerId; system("cls"); printf("当前志愿者信息：\n"); printf("\t姓名：%s\t学号：%s\t手机号：%d\n",p->volunteerName,p->idNum,p->phoneNum); printf("请确认是否要删除！(Y/N)"); scanf("%c",&temp1); if(temp1!='Y'){ printf("取消删除！\n"); system("pause"); return; } //删除所有场馆中此志愿者的注册记录 for(p3=_FIELD->next;p3;p3=p3->next){ for(i=0;p3->joinedVolunteer[i];i++){ if(p3->joinedVolunteer[i]==id){ if(!p3->joinedVolunteer[i+1]){ p3->joinedVolunteer[i]=0; }else{ for(;p3->joinedVolunteer[i+1];i++){ p3->joinedVolunteer[i]=p3->joinedVolunteer[i+1]; } p3->joinedVolunteer[i]=0; } break; } } } p1=p->head,p2=p->next; if(p2){ p1->next=p2; p2->head=p1; free(p); }else{ p1->next=NULL; free(p); } saveFile(); printf("删除成功！\n"); system("pause"); return; } void showField(field* p){ //根据id显示场馆信息 int i; volunteer* p1; printf("\n场馆信息：\n"); printf("\n\t场馆id\t场馆名字\t\t开始时间\t持续时间\t最大志愿者人数\n"); printf("\t%d\t%s\t\t\t%s\t\t%d\t\t%d\n",p->fieldId,p->fieldName,p->startTime,p->lastTime,p->maxVolunteer); printf("\n场馆已加入志愿者名单：\n"); printf("\t志愿者id\t志愿者姓名\t志愿者学号\t志愿者手机号\t\t志愿服务时长\n"); for(i=0;p->joinedVolunteer[i];i++){ p1=selectVolunteerById(p->joinedVolunteer[i]); printf("\t%d\t\t%s\t\t%s\t%s\t\t%d\n",p1->volunteerId,p1->volunteerName,p1->idNum,p1->phoneNum,p1->serviceTime); } printf("\n共%d个已加入志愿者\n",i); system("pause"); } void showVolunteer(volunteer* p){ //根据id显示志愿者信息 int i; field* p1; printf("\n\t志愿者id\t姓名\t\t学号\t手机号\t志愿服务时长\n"); printf("\t%d\t\t%s\t\t\t%s\t\t%s\t\t%d\n",p->volunteerId,p->volunteerName,p->idNum,p->phoneNum,p->serviceTime); printf("\n该志愿者已加入的志愿服务场馆：\n"); printf("\t场馆id\t场馆名字\t\t开始时间\t\t持续时间\n"); for(i=0;p->joinedField[i];i++){ p1=selectFieldById(p->joinedField[i]); printf("\t%d\t%s\t%s\t%s\t\t%d\n",p1->fieldId,p1->fieldName,p1->startTime,p1->lastTime); } printf("\n共%d个已加入志愿服务场馆\n",i); system("pause"); } void showAllField(){ //显示所有场馆信息 field* p=_FIELD->next; int i; printf("\t场地id\t场地名字\t\t开始时间\t持续时间\t最大志愿者人数\n"); for(i=0;p;p=p->next,i++){ printf("\t%d\t%s\t\t\t%s\t\t%d\t\t%d\n",p->fieldId,p->fieldName,p->startTime,p->lastTime,p->maxVolunteer); } printf("\n共%d个场馆数据\n",i); system("pause"); } void showAllVolunteer(){ //显示所有志愿者信息 volunteer* p=_VOLUNTEER->next; int i; printf("\t志愿者id\t志愿者姓名\t志愿者学号\t志愿者手机号\t\t志愿服务时长\t\n"); for(i=0;p;p=p->next,i++){ printf("\t%d\t\t%s\t\t%s\t%s\t\t%d\n",p->volunteerId,p->volunteerName,p->idNum,p->phoneNum,p->serviceTime); } printf("\n共%d个志愿者数据\n",i); system("pause"); } void bind(){ //注册志愿活动 char temp1; char input[100]; char temp[10][50]; char* temp2; int i,j; field* p1; volunteer* p2; system("cls"); printf("\t\t注册志愿活动\n"); printf("\t请分别输入活动场馆名字,志愿者姓名,志愿者学号，用英文半角逗号分隔\n退出注册输入0\n\t"); getchar();gets(input); if(input[0]=='0'){ return ; } temp2=strtok(input,","); if(!temp2){ printf("输入有误！"); system("pause"); return ; } strcpy(temp[0],temp2); for(i=1;i<3;i++){ temp2=strtok(NULL,","); if(!temp2){ printf("输入有误！"); system("pause"); return ; } strcpy(temp[i],temp2); } if(p2=selectVolunteerByIdNum(temp[2])){ if(p2==selectVolunteerByName(temp[1])){ if(p1=selectFieldByName(temp[0])){}else{ printf("未找到名字为%s的场馆信息\n",temp[0]); system("pause"); return; } }else{ printf("学号为%s的志愿者信息与姓名%s不对应\n",temp[2],temp[1]); system("pause"); return; } }else{ printf("未找到学号为%s的志愿者信息\n",temp[2]); system("pause"); return; } for(i=0;imaxVolunteer;i++){ if(p1->joinedVolunteer[i]==p2->volunteerId){ printf("该志愿者已加入该场活动，不能重复添加\n"); system("pause"); return; } if(!p1->joinedVolunteer[i]){ break; } } if(!(p1->maxVolunteer-i)){ printf("该场馆服务名额已满！"); system("pause"); return; } for(j=0;j<sizeof(_VOLUNTEER->joinedField)/sizeof(int);j++){ if(p2->joinedField[i]==p1->fieldId){ printf("该志愿者已加入该场活动，不能重复添加\n"); system("pause"); return; } if(!p2->joinedField[j]){ break; } } if(!(sizeof(_VOLUNTEER->joinedField)/sizeof(int)-j)){ printf("该志愿者已达到志愿服务数量上限！"); system("pause"); return; } printf("\n场馆信息：\n\t场馆ID：%d\n\t场馆名字：%s\n\t开始时间：%s\n\t持续时间：%d\n\t剩余志愿者名额：%d\n",p1->fieldId,p1->fieldName,p1->startTime,p1->lastTime,p1->maxVolunteer-i); printf("\n志愿者信息：\n\t志愿者ID：%d\n\t志愿者姓名：%s\n\t学号：%s\n\t手机号：%s\n\t已进行志愿服务时间：%d\n\t剩余最大志愿服务数量：%d\n",p2->volunteerId,p2->volunteerName,p2->idNum,p2->phoneNum,p2->serviceTime,sizeof(_VOLUNTEER->joinedField)/sizeof(int)-j); printf("\n\t是否确认要注册该志愿活动？（Y/N）\n"); scanf("%c",&temp1); if(temp1!='Y'){ printf("取消注册！\n"); system("pause"); return; } p1->joinedVolunteer[i]=p2->volunteerId; p2->joinedField[j]=p1->fieldId; p2->serviceTime=p2->serviceTime+p1->lastTime; saveFile(); printf("注册成功！\n"); system("pause"); } void unbind(){ //注销志愿活动 char temp1; char input[100]; char temp[10][50]; char* temp2; int i,j,m,n,q; field* p1; volunteer* p2; system("cls"); printf("\t\t注销志愿活动\n"); printf("\t请分别输入活动场馆名字,志愿者姓名,志愿者学号，用英文半角逗号分隔\n退出注销输入0\n\t"); getchar();gets(input); if(input[0]=='0'){ return ; } temp2=strtok(input,","); if(!temp2){ printf("输入有误！"); system("pause"); return ; } strcpy(temp[0],temp2); for(i=1;i<3;i++){ temp2=strtok(NULL,","); if(!temp2){ printf("输入有误！"); system("pause"); return ; } strcpy(temp[i],temp2); } if(p2=selectVolunteerByIdNum(temp[2])){ if(p2==selectVolunteerByName(temp[1])){ if(!(p1=selectFieldByName(temp[0]))){ printf("未找到名字为%s的场馆信息\n",temp[0]); system("pause"); return; } }else{ printf("学号为%s的志愿者信息与姓名%s不对应\n",temp[2],temp[1]); system("pause"); return; } }else{ printf("未找到学号为%s的志愿者信息\n",temp[2]); system("pause"); return; } for(i=0,m=-1;imaxVolunteer;i++){ if(p2->volunteerId==p1->joinedVolunteer[i]){ m=i; } } if(m<0){ printf("该志愿者未加入该场活动，无法注销\n"); system("pause"); return; } for(j=0,n=-1;j<sizeof(_VOLUNTEER->joinedField)/sizeof(int);j++){ if(p1->fieldId==p2->joinedField[j]){ n=j; } } if(n<0){ printf("该志愿者未加入该场活动，无法注销\n"); system("pause"); return; } for(;m<i;m++){ p1->joinedVolunteer[m]=p1->joinedVolunteer[m+1]; } p1->joinedVolunteer[m]=0; for(;n<j;n++){ p2->joinedField[n]=p2->joinedField[n+1]; } p2->joinedField[m]=0; p2->serviceTime=p2->serviceTime-p1->lastTime; saveFile(); printf("注销成功！"); system("pause"); } void findOutTopVolunteer(){ //寻找最美志愿者 int longestTime=0; int i,n; volunteer *p1; volunteer *np[10]; memset(np,0,10*sizeof(volunteer*)); system("cls"); for(p1=_VOLUNTEER->next;p1;p1=p1->next){ if(longestTime==p1->serviceTime){ for(i=0;np[i];i++); np[i]=p1; } if(longestTimeserviceTime){ longestTime=p1->serviceTime; memset(np,0,sizeof(np)); np[0]=p1; } } for(n=0;np[n];n++); printf("共有%d个“最美志愿者”\n\n志愿服务时长为：%d分钟\n\n",n,longestTime); for(i=0;i<n;i++){ printf("\t姓名：%s\t学号：%s\t手机号：%s\n",np[i]->volunteerName,np[i]->idNum,np[i]->phoneNum); } system("pause"); } void filePrintMenu(){ //格式化输出文件菜单 int step1=0,step2=0,choose=0,outputType=0,inttmp1; char outputPath[256],temp[256],input[256]; memset(input,0,sizeof(input)); while(1){ system("cls"); printf("\t\t格式化输出文件\n\n"); printf("\t当前已完成设置项：\n"); if(step1){ printf("\t\t1.输出路径：%s\t√\n",outputPath); }else{ printf("\t\t1.输出路径\t×\n"); } if(step2){ printf("\t\t2.输出数据："); switch(outputType){ case 1:printf("志愿者信息");break; case 2:printf("场馆信息");break; case 3:printf("志愿时长排名");break; } printf("\t√\n"); }else{ printf("\t\t2.输出数据\t×\n"); } if((step1+step2)==2){ printf("\n\t3.开始输出\n"); } printf("\n\n请选择配置项，输入0退出："); scanf("%d",&choose); switch(choose){ case 0: return; case 1: printf("请输入文件的输出位置（包含文件名）\n若输入0则直接在程序所在目录输出\"output.txt\""); getchar();gets(input); if(input[0]=='0'){ strcpy(input,"output.txt"); } printf("输出位置：%s\n\t请确认是否设置此地址（Y/N）",input); if('Y'==getchar()){ strcpy(outputPath,input); step1=1; memset(input,0,sizeof(input)); printf("已设置输出地址！\n"); system("pause"); }else{ memset(input,0,sizeof(input)); system("pause"); } break; case 2: printf("请输入要输出的数据：\n\t1.志愿者信息\n\t2.场馆信息\n"); scanf("%d",&inttmp1); if((inttmp1>=0)&&(inttmp1<=2)){ outputType=inttmp1; step2=1; }else{ printf("输入有误！\n"); system("pause"); } break; case 3: if((step1+step2)==2){ outputFile(outputPath,outputType); printf("输出完成！\n"); system("pause"); return; }else{ printf("您还未完成所有配置，不能输出\n"); } break; default: printf("输入有误！\n");system("pause");continue; } } } void outputFile(char* outputPath,int outputType){ int i; FILE *fp; volunteer *p1; field *p2; if(fp=fopen(outputPath,"r")){ printf("指定的路径已存在文件！覆盖（Y）或取消输出（N）？\n"); getchar();if(getchar()!='Y'){ fclose(fp); printf("取消输出\n"); system("pause"); return; } } fp=fopen(outputPath,"w"); switch(outputType){ case 1: fprintf(fp,"志愿者信息\n%-20s%-40s%-30s%s","姓名","学号","手机号","服务时长（分钟）\n"); for(p1=_VOLUNTEER->next;p1;p1=p1->next){ fprintf(fp,"\n%-20s%-40s%-30s%-10d\n",p1->volunteerName,p1->idNum,p1->phoneNum,p1->serviceTime); if(p1->joinedField[0]){ fprintf(fp,"\t注册志愿服务的场馆：\n"); for(i=0;p1->joinedField[i];i++){ fprintf(fp,"\t\t\t%s\n",selectFieldById(p1->joinedField[i])->fieldName); } } } break; case 2: fprintf(fp,"场馆信息\n%-20s%-20s%-20s%s","名字","开始时间","持续时间（分钟）","最大志愿者人数\n"); for(p2=_FIELD->next;p2;p2=p2->next){ fprintf(fp,"\n%-20s%-20s%-20d%-10d\n",p2->fieldName,p2->startTime,p2->lastTime,p2->maxVolunteer); if(p2->joinedVolunteer[0]){ fprintf(fp,"\t注册志愿服务的志愿者（学号）：\n"); for(i=0;p2->joinedVolunteer[i];i++){ p1=selectVolunteerById(p2->joinedVolunteer[i]); fprintf(fp,"\t\t\t%s(%s)\n",p1->volunteerName,p1->idNum); } } } break; } fprintf(fp,"\n\t\t@军运会管理系统"); fclose(fp); } void showMenu(){ system("cls"); printf("\t\t\t****************************************\t\t\t\n"); printf("\t\t\t\t1.场馆管理\n"); printf("\t\t\t\t2.志愿者管理\n"); printf("\t\t\t\t3.列出场馆信息\n"); printf("\t\t\t\t4.列出已注册志愿者\n"); printf("\t\t\t\t5.注册志愿活动\n"); printf("\t\t\t\t6.注销志愿活动\n"); printf("\t\t\t\t8.格式化输出文件至指定目录\n"); printf("\t\t\t\t9.寻找最美志愿者\n"); printf("\t\t\t\t0.退出程序\n"); //printf("\t\t\tPS:调试阶段为防止数据错误已关闭自动保存至文件，如需保存在主菜单输入22后即可保存\n"); printf("\t\t\t****************************************\t\t\t\n"); } //主函数 int main(){ int tmp; startUp(); while(1){ showMenu(); printf("\t请输入要执行的操作："); scanf("%d",&tmp); switch(tmp) { case 0:exit(0);break; case 1:manageField();break; case 2:manageVolunteer();break; case 3:showAllField();break; case 4:showAllVolunteer();break; case 5:bind();break; case 6:unbind();break; case 8:filePrintMenu();break; case 9:findOutTopVolunteer();break; /*case 21:readFile();break; case 22:saveFile();break;*/ default:system("cls");printf("输入有误！");system("pause"); } } return 0; } [/collapse] 看完了还不点个赞评个论分个享打个赏啥的嘛~