这篇文章的一些修正已经更新:修正版
文章目录
- C语言 & 网吧管理系统
- 总起. 功能以及代码排版要求
- 7. 系统
- 7.1 主函数设计~
- 7.2 开启系统后登录
- 7.2.1 输入
- 7.2.2 初始化+导入
- 7.2.3 遍历链表~
- 7.3 登录后操作
- 7.3.1 ※函数指针数组(C进阶语法)
- 7.3.2 登录成功显示
- 7.3.3 选择操作环节
- 7.4 关闭系统~exitOut
- 7.4.1 更新管理员链表
- 7.4.2 退出操作文件 - Exit.c
- 7.5 测试
- 6. 权限管理~
- 6.1 主体函数设计
- 6.2 菜单(Menu.c)
- 6.2.1 菜单文件 - Menu.c
- 6.3 删除管理员函数
- 6.4 增加管理员 + 权限设置
- 6.4.1 找到尾巴节点进行尾插~~
- 6.4.2 设置权限
- 6.5 退出操作
- 6.5 测试
- 2. 计费标准~
- 2.1 计费标准结构体
- 2.2 主体函数设计
- 2.2.1 函数指针数组~
- 2.2.2 文件读取函数文件-Carry.c
- 2.3 菜单(Menu.c)
- 2.4 新增计费标准
- 2.5 查询计费标准
- 2.6 删除计费标准
- 2.7 修改计费标准
- 2.8 退出操作
- 2.9 测试
- 1. 卡管理~
- 1.1 卡这个整体对应的结构体~
- 1.2 主体函数设计
- 1.2.1 函数指针数组
- 1.2.2 文件读取函数~
- 1.3 菜单(Menu.c)
- 1.4 添加卡
- 1.4.1 对于卡数为0 的情况
- 1.5 查询卡
- 1.5.1 打印一个
- 1.5.1.1 通过卡的类型打印对应的名字
- 1.5.2 打印全部
- 1.6 注销卡~
- 1.6.1 确认注销
- 1.7 退出操作
- 1.8 测试
- 4. 费用管理~
- 4.1 主体函数设计
- 4.2 充值
- 4.3 退费
- 4.4 退出操作
- 4.5 测试
- 3. 计费管理
- 3.1 两个记录性结构体~
- 3.1.1 Consume 消费记录(basis.h)
- 3.1.2 Puncher 上机记录(basis.h)
- 3.2 主体函数设计~
- 3.2.1 读取文件操作
- 3.2.1.1 consumeCarry(Carry.c)
- 3.2.1.2 puncherCarry(Carry.c)
- 3.3 菜单
- 3.4 上机
- 3.4.1 上机记录函数clockIn(ChargeManage.c)
- 3.5 下机
- 3.5.1 transfer(计费标准转化秒数函数 ChargeManage.c)
- 3.5.2 局部变量:gap
- 3.5.3 下机消费记录函数settlement(ChargeManage.c)
- 3.6 退出操作
- 3.6.1 消费单表的更新
- 3.6.2 上机记录数据表
- 3.7 补充:注销导致的强制下机计费
- 3.7.1 强制下机消费记录函数 off (CardManage.c)
- 3.8 测试
- 5. 查询统计
- 5.1 主体函数设计
- 5.1.1 函数指针数组
- 5.2 菜单
- 5.3 查询单一卡一段时间的消费~
- 5.3.1 细讲判断时间段方法~
- 5.4 查询所有卡一段时间的总消费
- 5.5 查询统计近一年来每个月的营销额以及上机次数~
- 5.5.1 引入 Date 年月结构体(basis.h)
- 5.5.2 引入全局变量:润平年月份日数对应数组~
- 5.5.3 判断闰年函数以及判断年月函数~
- 5.5.4 推导近12个月
- 5.5.5 建立文本文档记录 + 打印到屏幕~
- 5.5.6 遍历12次打印表格~
- 5.6 退出操作
- 5.7 测试~
重要前提: 你在下面学习的过程将可能会比较困惑,但是很大可能结合其后面所讲的内容,可以解决你的问题! 耐心耐心耐心
序号 | 模块 | 功能 | 说明 |
---|---|---|---|
1.1 | 添加卡 | 输入卡号、密码、开卡金额等卡信息,将卡信息保存到data文件夹的card.txt文件中 | |
1.2 | 卡管理 | 查询卡 | 根据输入的卡号,查询卡号相同的卡信息,并以表格形式显示在控制台中 |
1.3 | 注销卡 | 根据输入的卡号、密码,将对应卡的状态改为注销,注销卡不能进行上机 | |
2.1 | 新增计费标准 | 输入计费标准的信息,将输入的计费标准保存到data文件夹的rate.txt文件中 | |
2.2 | 计费标准管理 | 查询计费标准 | 根据上机时间,查询对应的计费标准 |
2.3 | 删除计费标准 | 从计费标准文件data文件夹的rate.txt文件中,删除一条计费标准 | |
2.4 | 修改计费标准 | 修改一条计费标准 | |
3.1 | 计费管理 | 上机 | 根据输入的卡号、密码,判断该卡能否上机,如果能上机,则保存计费信息 |
3.2 | 下机 | 根据输入下机卡的卡号,进行下机结算操作 | |
4.1 | 费用管理 | 充值 | 给一条已经存在的卡进行充值。 |
4.2 | 退费 | 将卡中余额返回给用户 | |
5.1 | 查询消费记录 | 查询一张卡在一段时间内的消费记录 | |
5.2 | 查询统计 | 统计总营业额 | 统计一段时间内,总营业额 |
5.3 | 统计月营业额 | 统计一年中,每个月上机次数、总营业额,将统计结果保存到文本文件中,并以列表形式显示在控制台中。 | |
6.1 | 添加管理员 | 超级管理员添加一个管理员信息 | |
6.2 | 权限管理 | 删除管理员 | 超级管理员删除一个管理员信息 |
6.3 | 配置权限 | 添加管理员时,配置管理员的权限 | |
7.1 | 系统 | 登录 | 超级管理员和管理员登录系统 |
7.2 | 退出 | 超级管理员和管理员退出系统 |
开启系统:
退出选择:
建立一个源文件test.c
,头文件basis.h
此时在头文件已有信息:
重点说明:不同源文件的信息只需要在头文件申明就好,因为每个源文件都包含了这个basis.h头文件~
#pragma once//防止重复包含头文件
//不要在这个文件开始运行程序~~~会报错!
//并且上方列表如无出现test.c,也会报错
#define _CRT_SECURE_NO_WARNINGS 1
//系统头文件
#include
#include //动态内存分配函数~
void menu();
此时在源文件test.c
已有信息:
#include "basis.h"//用双引号:第一步在本目录下查找头文件,第二步,在系统中查找头文件
//系统头文件一般用< >,一步到位直接在系统中查找头文件~~
int main() {
int input = 0;
do {
menu();
scanf("%d", &input);
switch (input) {
case 1:
signIn();//选择开启系统进入登录页面~~~
break;
case 0:
printf("退出成功\n");//退出减少简单的退出,程序彻底的结束了~
break;
default:
printf("请重新输入\n");//输入错误了~
break;
}
} while (input);
return 0;
}
这里用到了常见的多次选择算法~
实现每次从关闭系统之后选择是否继续开启系统~
建立一个源文件Menu.c
,存放所有的菜单~
现在已有信息:
void menu() {
printf("***************\n");
printf("1. 管理员登录 \n");
printf("0. 退出\n");
printf("***************\n");
}
signIn()
函数void signIn() {
printf("请输入编号,姓名以及六位密码:>");
int id = 0;
char name[10] = { 0 };
char password[7] = { 0 };
int retscan = scanf("%d%s%s", &id, name, password);
if (retscan == 0) {
printf("\n由于输入错误,系统崩坏\n");
exit(0);
}
//错误输入会死循环的原因在于,格式化输入错误
//-----------------------------
FILE* pf = fopen("data\\manager.txt", "rb");
if (pf == NULL) {
init();
pf = fopen("data\\manager.txt", "rb");
}
fread(&managerNumber, sizeof(int), 1, pf);
if (managerNumber == 0) {
fclose(pf);
init();
pf = fopen("data\\manager.txt", "rb");
}
Manager* pm = (Manager*)malloc(sizeof(Manager));
fread(pm, sizeof(Manager), 1, pf);
Manager* cur = pm;
head = pm;
for (int i = 1; i < managerNumber; i++) {
Manager* newOne = (Manager*)malloc(sizeof(Manager));
fread(newOne, sizeof(Manager), 1, pf);
newOne->next = NULL;
cur->next = newOne;
cur = cur->next;
}
fclose(pf);
//-----------------------------
cur = pm;
while (cur != NULL) {
if (id == cur->id
&& strcmp(cur->name, name) == 0
&& strcmp(cur->password, password) == 0) {
letUsGo(cur);
return;
}
cur = cur->next;
}
printf("您暂且不是管理员或者您的卡号密码错误\n");//能到这里必然就是登录失败的~
}
不用担心, 下面是细节分析!
printf("请输入编号,姓名以及六位密码:>");
int id = 0;//编号
char name[10] = { 0 };//姓名
char password[7] = { 0 };//密码
int retscan = scanf("%d%s%s", &id, name, password);//返回值为正常输入的元素个数~
//如果输入失败,里面退出
if (retscan == 0) {
printf("\n由于输入错误,系统崩坏\n");
exit(0);//库函数,exit(0)代表安全退出~
}
//错误输入会死循环的原因在于,格式化输入错误
引入结构体Manager
(basis.h)
//管理员,typedef -- 换名字~
typedef struct Manager {
int id;//编号
char name[10];//名字
char password[7];//密码
char limits[8];//权限
struct Manager* next;//后驱
}Manager;
FILE* pf = fopen("data\\manager.txt", "rb");
if (pf == NULL || managerNumber == 0) {
init();//初始化函数
pf = fopen("data\\manager.txt", "rb");//要重写打开哦~
}
fread(&managerNumber, sizeof(int), 1, pf);
Manager* pm = (Manager*)malloc(sizeof(Manager));
fread(pm, sizeof(Manager), 1, pf);
Manager* cur = pm;
head = pm;
for (int i = 1; i < managerNumber; i++) {
Manager* newOne = (Manager*)malloc(sizeof(Manager));
fread(newOne, sizeof(Manager), 1, pf);
newOne->next = NULL;
cur->next = newOne;
cur = cur->next;
}
fclose(pf);
对于读取失败或者管理员的个数为0的情况下,进行初始化
引入全局变量:managerNumber
head
managerNumber
(test.c)
计算已有管理员的个数
放在源文件中,然后头文件声明
int managerNumber = 0;//源文件中
extern managerNUmber;
head
(basis.h)(必须放在Manager结构体定义之后)
存储已有管理员,作为头结点代表整条链表
方便后续释放空间以及更新管理员信息二进制文件~
放在头文件中(指针应该放在头文件),原因不做解释
Manager* head;
初始化函数(test.c)
重点说明:每一个二进制文件的前四个字节,我默认放的都是元素个数 !
*建立存放manager信息的二进制文件~==》*manager.txt
据学校要求,放置在data文件中,必须提前建立~
malloc
库函数~ 申请堆区空间,函数栈帧销毁此~
字符串拷贝用strcpy
库函数
void init() {
FILE* pfr = fopen("data\\manager.txt", "wb");//自动建立二进制文件
//选取二进制文件是因为读取写入最方便安全~~~
Manager* pm1 = (Manager*)malloc(sizeof(Manager));
Manager* pm2 = (Manager*)malloc(sizeof(Manager));
Manager* pm3 = (Manager*)malloc(sizeof(Manager));
Manager* pm4 = (Manager*)malloc(sizeof(Manager));
Manager* pm5 = (Manager*)malloc(sizeof(Manager));
Manager* pm6 = (Manager*)malloc(sizeof(Manager));
pm1->id = 0;
strcpy(pm1->name, "小马");
strcpy(pm1->password, "123456");
strcpy(pm1->limits, "1111111");
pm2->id = -1;
strcpy(pm2->name, "小张");
strcpy(pm2->password, "123456");
strcpy(pm2->limits, "1111111");
pm3->id = -2;
strcpy(pm3->name, "老师");
strcpy(pm3->password, "123456");
strcpy(pm3->limits, "1111111");
pm4->id = 1;
strcpy(pm4->name, "小卡拉");
strcpy(pm4->password, "123456");
strcpy(pm4->limits, "1110000");
pm5->id = 2;
strcpy(pm5->name, "小空多尼");
strcpy(pm5->password, "123456");
strcpy(pm5->limits, "1111110");
pm6->id = 3;
strcpy(pm6->name, "小林");
strcpy(pm6->password, "123456");
strcpy(pm6->limits, "1111110");
managerNumber = 6;
fwrite(&managerNumber, sizeof(int), 1, pfr);//给6个
fwrite(pm1, sizeof(Manager), 1, pfr);
fwrite(pm2, sizeof(Manager), 1, pfr);
fwrite(pm3, sizeof(Manager), 1, pfr);
fwrite(pm4, sizeof(Manager), 1, pfr);
fwrite(pm5, sizeof(Manager), 1, pfr);
fwrite(pm6, sizeof(Manager), 1, pfr);
fclose(pfr);
}
初始化默认加入三个超级管理员,三个普通管理员~
超级管理员编号小于等于0~ ,普通管理员编号默认大于0~
超级管理员权限全是1~
存入文件,成员next 是没有价值的,下次读取这个地址也没用~
对于读取成功,进行内容导入~
改变全局变量managerNumber
fread(&managerNumber, sizeof(int), 1, pf);
此时文件不可能没有内容,因为经过初始化了
Manager* pm = (Manager*)malloc(sizeof(Manager));
fread(pm, sizeof(Manager), 1, pf);
Manager* cur = pm;
head = pm;//用全局head -> 记录头结点地址~
读取文件并关闭文件~
for (int i = 1; i < managerNumber; i++) {
Manager* newOne = (Manager*)malloc(sizeof(Manager));
fread(newOne, sizeof(Manager), 1, pf);
newOne->next = NULL;
cur->next = newOne;
cur = cur->next;
}
fclose(pf);
#include
(basis.h) cur = pm;//回到链表首~
while (cur != NULL) {
if (id == cur->id
&& strcmp(cur->name, name) == 0
&& strcmp(cur->password, password) == 0) {
letUsGo(cur);//登录成功后的操作~
return;
}
cur = cur->next;//走向下一步~
}
printf("您暂且不是管理员或者您的卡号密码错误\n");//能到这里必然就是登录失败的~
letUsGo()
(test.c)void letUsGo(Manager* pm) {
int input = 0;
//函数列表~
//操作相关函数~
//返回值参数列表都相同~
void(*opera[7])(Manager*) =
{
exitOut, cardManage,
chargeStandard, chargeManage,
expenseManage, searchStatistics,
limitsManage
};
printf("--------------------------\n");
time_t t = time(NULL);
printf("%s\n于%s登录系统\n", pm->name, ctime(&t));
printf("--------------------------\n");
do {
systemMenu(pm);
scanf("%d", &input);
if (pm->limits[input] != '1') {
printf("你并没有权限");
}
else {
opera[input](pm);
//管理员链表的free,在退出登录时free
}
} while (input);
}
对于一个函数而言,其函数名实际上就是一个函数指针,并且函数指针的地址还是本身~
函数指针形式: 用(*p)
去替换函数名位置
void exitOut(Manager* pm)
===》void (*p)(Manager*)
那么函数指针数组就是(*opera[])
去替换函数名位置~
即void (*opear[])(Manager*)
这个数组中的内容都是同一类函数的函数名~
用这个p
指针可以直接调用这个函数
exitOut(pm)
<=> opera[0](pm)
<=> p0(pm)
//下标对应好哦!
void(*opera[7])(Manager*) =
{
exitOut, cardManage,
chargeStandard, chargeManage,
expenseManage, searchStatistics,
limitsManage
};
这些是后续的操作的函数名列表~
对于为什么用函数指针,是为了让代码更加简洁,并且提高运行速率(空间换时间);
#include
(basis.h)
time()
和 ctime()
&(time(NULL))
,一个确切的值怎么可以被取地址?只有变量/常量可以 printf("--------------------------\n");
time_t t = time(NULL);
printf("%s\n于%s登录系统\n", pm->name, ctime(&t));
printf("--------------------------\n");
引入菜单systemMenu(pm)
(Menu.c)
void systemMenu(Manager* pm) {
//通过编号确认管理员类型~
if (pm->id <= 0) {
printf("你好,超级管理员,%s!\n", pm->name);
}
else {
printf("你好,普通管理员,%s!\n", pm->name);
}
//根据权限判断~~
printf("******************\n");
if (pm->limits[0] == '1') {
printf("0. 退出系统\n");//所有人都有这个功能,要怎么设计呢,随后揭晓~
}
if (pm->limits[1] == '1') {
printf("1. 卡管理\n");
}
if (pm->limits[2] == '1') {
printf("2. 计费标准管理\n");
}
if (pm->limits[3] == '1') {
printf("3. 计费管理\n");
}
if (pm->limits[4] == '1') {
printf("4. 费用管理\n");
}
if (pm->limits[5] == '1') {
printf("5. 查询统计\n");
}
if (pm->limits[6] == '1' && pm->id <= 0) {
printf("6. 权限管理\n");
}
printf("******************\n");
}
只有有权限的内容才会显示!
还是老样子~==》多次输入确认算法
int input = 0;
do {
systemMenu(pm);
scanf("%d", &input);
//确保是否有权限(因为可能菜单没显示,他也选了~这不就是卡bug了吗)
if (pm->limits[input] != '1') {
printf("你并没有权限");
}
else {
opera[input](pm);//调用特定下标的函数~~~
//管理员链表的free,在退出登录时free,不能在退出权限设置的时候free,这样会导致pm被释放,后续无法操作
//有个误区,就是每次操作的退出,都要对直接影响的链表进行保存释放~权限设置函数确实直接影响了管理员链表
//但是不能在那个时候释放~
//这里看不懂无所谓,等权限设置函数讲完之后在看
}
} while (input);
选择0调用退出函数并结束循环~
引入void exitOut(Manager* pm)
(Exit.c)
即这里的opera[0]~
void exitOut(Manager* pm) {
time_t t = time(NULL);
printf("--------------------------\n");
printf("%s\n于%s退出系统\n", pm->name, ctime(&t));
printf("--------------------------\n");
exitOutManager();
//在这里就可以将管理员链表进行更新了,因为这里代表了此管理员操作的终结,此管理员有可能新增或者删除过管理员~
}
退出的时候使用时间函数,报告时间,模拟实际情况~
在这里退出,是因为这一步结束后,应该是别的管理员进入系统了,所以更新管理员链表,让新添加的管理员可以紧接着进入~
exitOutManager
(Exit.c)
void exitOutManager() {
printf("退出成功\n");
FILE* pf = fopen("data\\manager.txt", "wb");
fwrite(&managerNumber, sizeof(int), 1, pf);
//记录管理员名单
Manager* cur = head;
while (cur != NULL) {
fwrite(cur, sizeof(Manager), 1, pf);
Manager* tmp = cur;//通过寄存器做中介
cur = cur->next;
free(tmp);
}
//在这里一定要关闭,不然只会到程序结束,内容才会从缓存区传入文件!!!
fclose(pf);
pf = NULL;
}
limitsManage()
(LimitsManage.c)void limitsManage(Manager* pm) {
int input = 0;
do {
menu6_1();//菜单
scanf("%d", &input);
switch (input) {
case 0 :
printf("退出成功\n"); //退出就是简简单单的退出~
break;
case 1:
add(pm);//增加函数
break;
case 2 :
delete(pm);//删除函数
break;
default :
printf("输入错误\n");
break;
}
} while (input);
}
选择增减 菜单~
void menu6_1() {
printf("******************\n");
printf("0. 退出此操作\n");
printf("1. 添加管理员\n");
printf("2. 删除管理员\n");
printf("******************\n");
}
权限设置 菜单~
void menu6_2(Manager* pm) {
printf("******************\n");
printf("1. 卡管理权限\n");
printf("2. 计费标准管理权限\n");
printf("3. 计费管理权限\n");
printf("4. 费用管理权限\n");
printf("5. 查询统计权限\n");
printf("0. 结束本次操作\n");
printf("******************\n");
}
delect
(LimitsManage.c)
只需要用探路指针遍历就好~
void delete(Manager* pm) {
printf("请输入管理员的编号,姓名:>");
//由于此操作只能由超级管理员操作并且超级管理员在最前面,
//所以在这里往后遍历就好,但是不能删除超级管理员
int id = 0;
char name[10] = { 0 };
Manager* cur = pm;
do {
scanf("%d%s", &id, name);
if (id <= 0) {
printf("无法删除!\n");//这里绝对是不行的!!!因为超级管理员的编号<=0~
}
} while (id <= 0);
while (cur->next != NULL) {
if(id == cur->next->id && strcmp(name, cur->next->name) == 0){
Manager* rubbish = cur->next;
cur->next = rubbish->next;
free(rubbish);
printf("删除成功\n");
managerNumber--;
return;
}
cur = cur->next;
}
printf("此人并不是管理员\n");
}
无法删除超级管理员~
输入编号姓名删除管理员
遍历链表查找(由于编号唯一,理当只删一个,不应该在添加管理员时使用相同编号,但是我这个项目不会查重
add
(LimitsManage.c)void add(Manager* pm) {
printf("请输入新增管理员的编号,姓名,六位密码:>");
Manager* cur = pm;
while (cur->next != NULL) {
cur = cur->next;
}
int id = 0;
char name[10];
char password[7];
scanf("%d%s%s", &id, name, password);
if (id <= 0) {
printf("普通管理员的id理应大于0!\n");
return;
}
else {
cur->next = (Manager*)malloc(sizeof(Manager));
cur = cur->next;
cur->id = id;
strcpy(cur->name, name);
strcpy(cur->password, password);
strcpy(cur->limits, "0000000");
cur->next = NULL;
}
int input = 0;
menu6_2(pm);
printf("请输入要为其设置的权限:>");
do {
scanf("%d", &input);
if (input <= 5 && input >= 0) {
cur->limits[input] = '1';
}
else {
printf("输入失败\n");
}
} while (input);
printf("添加成功\n");
managerNumber++;
}
printf("请输入新增管理员的编号,姓名,六位密码:>");
Manager* cur = pm;
while (cur->next != NULL) {
cur = cur->next;
}
int id = 0;
char name[10];
char password[7];
scanf("%d%s%s", &id, name, password);
if (id <= 0) {
printf("普通管理员的id理应大于0!\n");
return;
}
else {
cur->next = (Manager*)malloc(sizeof(Manager));
cur = cur->next;
cur->id = id;
strcpy(cur->name, name);
strcpy(cur->password, password);
strcpy(cur->limits, "0000000");//默认全为0~
cur->next = NULL;
}
此时的cur指向的就是新增节点~
通过多次输入选项,对对应的权限进行设置
按0的时候,会直接将0下标的那个权限设置为1,顺带因此退出了本次操作
不能赋予增减管理员设置的权限~
managerNumber++;
管理员数+1
int input = 0;
menu6_2(pm);//菜单~~~
printf("请输入要为其设置的权限:>");
do {
scanf("%d", &input);
if (input <= 5 && input >= 0) {
cur->limits[input] = '1';
}
else {
printf("输入失败\n");
}
} while (input);
printf("添加成功\n");
managerNumber++;
※注意:管理员链表的更新应该在这个管理员退出系统的时候才能更新,否则此管理员被释放了,无法继续后面的操作!并且新增的管理员才能进入系统~
新源文件ChargeStandard.c 源码在这里:网吧管理系统/ChargeStandard.c · 游离态
Standard
(basis.h)//计费标准
typedef struct Standard {
int type;//1 2 3 4
int state;//决定此卡是否能办
double price;//标准单价
}Standard;
chargeStandard
(ChargeStandard.c )void chargeStandard(Manager* pm) {
int input = 0;
Standard* pcs = standardCarry();
void (*func[5])(Standard*) = { exitOutStandard, addStandard, search, delStandard, modify};
do {
menu2_1();//菜单~
scanf("%d", &input);
if (input <= 4 && input >= 0) {
func[input](pcs);
}
else {
printf("请重新输入\n");
}
} while (input);
}
我将所有的结构体(信息)文件读取操作,都放在一个源文件中,方便管理~
源码在这里:网吧管理系统/Carry.c · 游离态
这里的 Standard* pcs = standardCarry();
的含义就是从文件中读取~
并且返回值为对应的首元素堆区地址
Standard* standardCarry() {
FILE* pf = fopen("data\\rate.txt", "rb");
Standard* pcs = (Standard*)malloc(4 * sizeof(Standard));
if (pf == NULL) {
pf = fopen("data\\rate.txt", "wb");
fwrite(pcs, sizeof(Standard), 4, pf);
fclose(pf);
}
else {
fread(pcs, sizeof(Standard), 4, pf);
fclose(pf);
}
return pcs;
}
增删查改操作菜单:
void menu2_1() {
printf("******************\n");
printf("0. 退出\n");
printf("1. 新增计费标准\n");
printf("2. 查询计费标准\n");
printf("3. 删除计费标准\n");
printf("4. 修改计费标准\n");
printf("******************\n");
}
卡的类型清单:
void menu2_2() {
printf("******************\n");
printf("1. 年卡\n");
printf("2. 月卡\n");
printf("3. 日卡\n");
printf("4. 时卡\n");
printf("******************\n");
}
addStandard
(ChargeStandard.c)
pcs[input - 1].state = 1;
arr[i] == *(arr + i)
void addStandard(Standard* pcs) {
int input = 0;
menu2_2();
printf("请输入待增加的计费标准的类型:>");
scanf("%d", &input);
if (input <= 4 && input >= 1 && pcs[input - 1].state != 1) {
printf("请输入你的计费标准单价是多少元:>");
scanf("%lf", &pcs[input - 1].price);
pcs[input - 1].state = 1;
printf("新增成功\n");
}
else {
printf("此标准无法加入,“可能”是已有此标准,但可进行修改操作\n");
}
}
search
(ChargeStandard.c)
void search(Standard* pcs) {
int input = 0;
menu2_2();
printf("请输入待查看的计费标准的类型:>");
scanf("%d", &input);
if (input <= 4 && input >= 1 && pcs[input - 1].state == 1) {
printf("计费标准为:");
change(input);
printf("=》单位时间内收费%.2lf元\n", pcs[input - 1].price);
}
else {
printf("暂无此标准\n");
}
}
delStandard
(ChargeStandard.c)
选择卡的类型
存在此标准,就删除
pcs[input - 1].state = 0;
不存在就报失败~
void delStandard(Standard* pcs) {
int input = 0;
menu2_2();
printf("请输入待删除计费标准的类型:>");
scanf("%d", &input);
if (input <= 4 && input >= 1 && pcs[input - 1].state == 1) {
pcs[input - 1].state = 0;
printf("删除成功\n");
}
else {
printf("删除失败\n");
}
}
modify
(ChargeStandard.c)
void modify(Standard* pcs) {
int input = 0;
menu2_2();
printf("请输入待修改计费标准的类型:>");
scanf("%d", &input);
if (input <= 4 && input >= 1 && pcs[input - 1].state == 1) {
printf("请输入你的调整后的计费标准单价是多少元:>");
scanf("%lf", &pcs[input - 1].price);
printf("修改成功\n");
}
else {
printf("暂无此标准\n");
}
}
exitOutStandard
(Exit.c)
func[0]
void exitOutStandard(Standard* pcs) {
FILE* pf = fopen("data\\rate.txt", "wb");
fwrite(pcs, sizeof(Standard), 4, pf);
free(pcs);
fclose(pf);
}
//卡
typedef struct Card {
int id;//卡号
char password[7];//六位密码
double balance;//开卡金额-->余额,卡的种类决定了这个金额
int effect; // 1-->未注销,非1-->已注销
int cardType;//卡的种类---计费方案
long long upTime;//上机间点
int state;//上机与否?
struct Card* next;//后继
}Card;
卡号
密码
余额
效应—注销与否
卡的类型—计费标准
上机的时间的时间戳~(64位长整形)
状态—上机了与否
后继节点—构造链表
cardManage
(CardManage.c)
cardNumber
(CardManager.c)卡数~void cardManage(Manager* pm) {
int input = 0;
Card* pc = cardCarry();
void (*func[4])(Card*) =
{ exitOutCard, addCard, searchCard, logOffCard };
do {
menu1_1();
scanf("%d", &input);
if (input >= 0 && input <= 3) {
func[input](pc);
}
else {
printf("输入失败\n");
}
} while (input);
}
cardCarry
(Carry.c)
Card* cardCarry() {
FILE* pf = fopen("data\\card.txt", "rb");
Card* pc = (Card*)malloc(sizeof(Card));//堆区空间,不会被收回
if (pf == NULL) {
pf = fopen("data\\card.txt", "wb");
fwrite(&cardNumber, sizeof(int), 1, pf);
fclose(pf);
}
else {
fread(&cardNumber, sizeof(int), 1, pf);
fread(pc, sizeof(Card), 1, pf);
Card* cur = pc;
for (int i = 1; i < cardNumber; i++) {
Card* newOne = (Card*)malloc(sizeof(Card));
fread(newOne, sizeof(Card), 1, pf);
newOne->next = NULL;
cur->next = newOne;
cur = cur->next;
}
}
return pc;
}
※注意:如果文件中没有东西,这pc指针中堆区空间仍然是原始的~后续应该通过卡的个数对此情况进行处理!!!
添查销操作菜单
void menu1_1() {
printf("******************\n");
printf("1. 添加卡\n");
printf("2. 查询卡\n");
printf("3. 注销卡\n");
printf("0. 退出\n");
printf("******************\n");
}
查询操作选项菜单
void menu1_2() {
printf("******************\n");
printf("1. 打印全部卡\n");
printf("2. 查询具体卡\n");
printf("0. 退出\n");
printf("******************\n");
}
选择卡的类型罗列清单
void menu1_3(Standard* pcs) {
printf("************************************\n");
for (int i = 1; i <= 4; i++) {
printf("%d. ", i);
change(i);
if (pcs[i - 1].state == 1) {
printf("==》单位时间内收费%.2lf元\n", pcs[i - 1].price);
}
else {
printf("==》(计费标准)暂未被开发\n");
}
}
printf("0. 退出\n");
printf("************************************\n");
}
注销提示菜单
void menu1_4() {
printf("******************\n");
printf("1. 注销卡\n");
printf("0. 退出\n");
printf("※ 特别注意:注销后无法恢复!\n※ 必须由管理员重新办卡\n※ 管理员请据情况进行余额转移\n");
printf("******************\n");
}
addCard
(CardManage.c)
newOne
–新节点void addCard(Card* pc) {
Standard* pcs = standardCarry();
printf("卡的类型有如下可选(开卡金额不得少于卡的类型对应的单价!)\n");
int input = 0;
do {
menu1_3(pcs);
printf("请输入卡的类型:>");
scanf("%d", &input);
if (input != 0) {
Card* newOne = (Card*)malloc(sizeof(Card));
printf("请依次输入新卡的卡号,密码,开卡金额\n");
scanf("%d%s%lf", &newOne->id, newOne->password, &newOne->balance);
newOne->cardType = input;
if (pcs[newOne->cardType - 1].state != 1 || newOne->balance < pcs[newOne->cardType].price) {
printf("添加失败,“可能”是因为开卡金额不足或者此类卡未被开发\n");
free(newOne);
}
else {
newOne->effect = 1;
newOne->next = NULL;
if (cardNumber == 0) {
memcpy(pc, newOne, sizeof(Card));
}
else {
Card* cur = pc;
while (cur->next != NULL) {
cur = cur->next;
}
cur->next = newOne;
}
cardNumber++;
printf("添加成功\n");
}
}
} while (input);
printf("退出成功\n");
}
memcpy(pc, newOne, sizeof(Card));
searchCard
(CardManage.c)
void searchCard(Card* pc) {
int input = 0;
do {
menu1_2();
scanf("%d", &input);
switch (input) {
case 1:
printAll(pc);
break;
case 2:
printOne(pc);
break;
case 0:
printf("退出成功\n");
break;
default:
printf("输入失败\n");
break;
}
} while (input);
}
printOne
(CardManage.c)
void printOne(Card* pc) {
printf("请输入你要查询的卡号:>");
int id = 0;
scanf("%d", &id);
Card* cur = pc;
while (cardNumber != 0 && cur != NULL) {
if (cur->id == id) {
printf("+------+------+-------------+-------+---------+---------+\n");
printf("|%-6s|%6s|%13s|%7s|%9s|%9s|\n", "卡号", "密码", "余额", "效应", "卡的种类", "状态");
printf("+------+------+-------------+-------+---------+---------+\n");
printf("|%-6d|%6s|%13.2lf|", cur->id, cur->password, cur->balance);
//8.2lf代表这小数,总共站位控制在9(不足的时候补齐,足够的时候不用补齐)
if (cur->effect == 1) {
printf("%7s| ", "未注销");
}
else {
printf("%7s| ", "已注销");
}
change(cur->cardType);
if (cur->state == 1) {
printf("|%9s|\n", "上机中");
}
else {
printf("|%9s|\n", "未上机");
}
printf("+------+------+-------------+-------+---------+---------+\n");
printf("查找成功\n");
return;
}
cur = cur->next;
}
printf("查找失败,“可能”是因为暂无此卡\n");
}
change
(ChargeStandard.c)
void change(int i) {
switch (i) {
case 1:
printf("年卡");
break;
case 2:
printf("月卡");
break;
case 3 :
printf("日卡");
break;
case 4 :
printf("时卡");
break;
default:
break;
}
}
void printAll(Card* cur) {
printf("+------+------+-------------+-------+---------+---------+\n");
printf("|%-6s|%6s|%13s|%7s|%9s|%9s|\n", "卡号", "密码", "余额", "效应", "卡的种类", "状态");
printf("+------+------+-------------+-------+---------+---------+\n");
while (cur != NULL) {
printf("|%-6d|%6s|%13.2lf|", cur->id, cur->password, cur->balance);
//8.2lf代表这小数,总共站位控制在9(不足的时候补齐,足够的时候不用补齐)
if (cur->effect == 1) {
printf("%7s| ", "未注销");
}
else {
printf("%7s| ", "已注销");
}
change(cur->cardType);
if (cur->state == 1) {
printf("|%9s|\n", "上机中");
}
else {
printf("|%9s|\n", "未上机");
}
printf("+------+------+-------------+-------+---------+---------+\n");
cur = cur->next;
}
printf("查找成功\n");
}
logOffCard
(CardManage.c)
void logOffCard(Card* pc) {
int input = 0;
do {
menu1_4();
scanf("%d", &input);
if (input) {
logOff(pc);
}
else {
printf("退出成功\n");
}
} while (input);
}
logOff
(CardManager.c)
void logOff(Card* pc) {
Card* cur = pc;
int id = 0;
char password[7];
printf("请输入待注销卡的卡号以及对应密码:>");
scanf("%d%s", &id, password);
while (cur != NULL && cardNumber != 0) {
if (id == cur->id && strcmp(password, cur->password) == 0) {
cur->effect = 0;
printf("注销成功\n");
if (cur->state == 1) {
printf("已强制下机\n");
Consume* psu = consumeCarry();
off(cur, psu);
exitOutConsume(psu);
}
return;
}
cur = cur->next;
}
printf("注销失败,“可能”是因为暂无此卡\n");
}
exitOutCard
(Exit.c)
数据导入data(必须自己建立)文件的card.txt二进制文件中
如果卡数为0,那么只讲0导入文件即可,因为这个节点不为NULL但是不是有效数据!
不为0遍历链表导入数据,并且用相同的方法释放空间~
void exitOutCard(Card* pc) {
FILE* pf = fopen("data\\card.txt", "wb");
fwrite(&cardNumber, sizeof(int), 1, pf);
if (cardNumber == 0) {
return;
}
while (pc != NULL) {
fwrite(pc, sizeof(Card), 1, pf);
Card* tmp = pc;
pc = pc->next;
free(tmp);
}
fclose(pf);
}
expenseManage
(ExpenseManage.c)
void expenseManage(Manager* pm) {
int input = 0;
Card* pc = cardCarry();
do {
menu4_1();
scanf("%d", &input);
switch (input) {
case 1:
recharge(pc);
break;
case 2:
refunt(pc);
break;
case 0:
exitOutCard(pc);
printf("退出成功\n");
break;
default:
printf("请重新输入\n");
break;
}
} while (input);
}
recharge
(ExpenseManage.c)
void recharge(Card* pc) {
printf("请输入待充值卡的卡号:>");
int id = 0;
scanf("%d", &id);
while (pc != NULL) {
if (pc->id == id) {
printf("请输入充值金额:>");
double money = 0.0;
scanf("%lf", &money);
pc->balance += money;
printf("充值成功\n");
printf("\n注意:如果是因为欠费导致的账号注销,注销的卡已作废\n"
"此次充值若余额恢复非负,管理员请据情况接办理新卡并且余额保留\n");
return;
}
pc = pc->next;
}
printf("充值失败,“可能”暂无此卡\n");
}
refunt
(ExpenseManage.c)
void refunt(Card* pc) {
printf("请输入待退费卡的卡号:>");
int id = 0;
scanf("%d", &id);
while (pc != NULL) {
if (pc->id == id && pc->effect == 1) {//负值时必然注销
pc->balance = 0.0;
printf("退费成功\n");
return;
}
pc = pc->next;
}
printf("退费失败,“可能”暂无此卡或者此卡已被注销\n");
}
接下来是比较复杂的两个环节,计费管理以及查询统计~
计费管理操作上机下机,下机的时候计费~
引入新的源文件:ChargeManage.c
源码在这:网吧管理系统/ChargeManage.c · 游离态
typedef struct Consume {
int id;//卡号
long long timeNode;//时间节点
double money;//下机则为实际收费,合理是相同的
struct Consume* next;//后继
}Consume;
//上机记录
typedef struct Puncher {
int id;//卡号
long long timeNode;//时间节点
struct Puncher* next;//后继
}Puncher;
chargeManage
(ChargeManage.c)
引入新的全局变量
orderNumber
消费单数~workNumber
上机记录数据数~导入卡号,消费记录,上机记录~
根据菜单进行选择~
void chargeManage(Manager* pm) {
int input = 0;
Card* pc = cardCarry();
Consume* psu = consumeCarry();
Puncher* ppu = puncherCarry();
do {
menu3_1();
scanf("%d", &input);
switch (input) {
case 1 :
onComputer(pc, ppu);
break;
case 2 :
offComputer(pc, psu);
break;
default:
printf("输入错误\n");
break;
case 0:
exitOutCard(pc);
exitOutConsume(psu);
exitOutPuncher(ppu);
printf("退出成功\n");
break;
}
} while (input);
}
Consume* consumeCarry() {
FILE* pf = fopen("data\\consume.txt", "rb");
Consume* psu = (Consume*)malloc(sizeof(Consume));//堆区空间,不会被收回
if (pf == NULL) {
pf = fopen("data\\consume.txt", "wb");
fwrite(&orderNumber, sizeof(int), 1, pf);
fclose(pf);
}
else {
fread(&orderNumber, sizeof(int), 1, pf);
fread(psu, sizeof(Consume), 1, pf);
Consume* cur = psu;
for (int i = 1; i < orderNumber; i++) {
Consume* newOne = (Consume*)malloc(sizeof(Consume));
fread(newOne, sizeof(Consume), 1, pf);
newOne->next = NULL;
cur->next = newOne;
cur = cur->next;
}
}
return psu;
}
Puncher* puncherCarry() {
FILE* pf = fopen("data\\puncher.txt", "rb");
Puncher* ppu = (Puncher*)malloc(sizeof(Puncher));//堆区空间,不会被收回
if (pf == NULL) {
pf = fopen("data\\puncher.txt", "wb");
fwrite(&workNumber, sizeof(int), 1, pf);
fclose(pf);
}
else {
fread(&workNumber, sizeof(int), 1, pf);
fread(ppu, sizeof(Puncher), 1, pf);
Puncher* cur = ppu;
for (int i = 1; i < workNumber; i++) {
Puncher* newOne = (Puncher*)malloc(sizeof(Puncher));
fread(newOne, sizeof(Puncher), 1, pf);
newOne->next = NULL;
cur->next = newOne;
cur = cur->next;
}
}
return ppu;
}
上下机操作菜单
提醒顾客过早下机会导致浪费~
void menu3_1() {
printf("****************************************\n");
printf("※ 请提示顾客:时间较长的卡请勿过早下机\n"
"电脑时刻开着呢,不需要再次上机\n");
printf("0. 退出\n");
printf("1. 上机\n");
printf("2. 下机\n");
printf("****************************************\n");
}
conComputer
(ChargeMange.c)
void onComputer(Card* pc, Puncher* ppu) {
printf("请输入卡号与密码:>");
Card* cur = pc;
int id = 0;
char password[7];
scanf("%d%s", &id, password);
while (cardNumber != 0 && cur != NULL) {
if (cur->id == id && strcmp(password, cur->password) == 0) {
if (cur->effect != 1) {
printf("此卡已被注销,无法上机\n");
return;
}
else {
if (cur->state == 1) {
printf("已经是上机状态,本次操作失效\n");
}
cur->state = 1;
time_t t = time(NULL);
cur->upTime = t;
//上机记录~~
clockIn(cur, ppu);
//上机记录~~
printf("--------------------------\n");
printf("上机成功\n");
printf("时间:%s", ctime(&t));
printf("--------------------------\n");
}
return;
}
cur = cur->next;
}
printf("上机失败,“可能”原因是此卡暂为开通\n");
}
void clockIn(Card* cur, Puncher* ppu) {
Puncher* newOne = (Puncher*)malloc(sizeof(Puncher));
newOne->id = cur->id;
newOne->next = NULL;
newOne->timeNode = cur->upTime;
if (workNumber == 0) {
memcpy(ppu, newOne, sizeof(Puncher));
}
else {
Puncher* current = ppu;
while (current->next != NULL) {
current = current->next;
}
current->next = newOne;
}
workNumber++;
}
offnComputer
(ChargeMange.c)
void offComputer(Card* pc, Consume* psu) {
printf("请输入卡号与密码:>");
Card* cur = pc;
int id = 0;
char password[7];
scanf("%d%s", &id, password);
Standard* pcs = standardCarry();
while (cardNumber != 0 && cur != NULL) {
if (cur->id == id && strcmp(password, cur->password) == 0) {
if (cur->state == 0) {
printf("已经是下机状态,本次操作失效\n");
return;
}
if (pcs[cur->cardType - 1].state == 1) {//未上机
time_t t = time(NULL);
long long longTime = t - cur->upTime;
double gap = 1.0 * longTime / transfer(cur->cardType);
if (gap != (int)gap) {
gap = (int)gap + 1;
}
//记录收益记录~~
settlement(cur, psu, t, gap, pcs);
//记录收益记录~~
cur->state = 0;
if (cur->balance < 0) {
printf("此卡已欠费,账号已被注销,请充值缴费\n");
cur->effect = 0;
}
printf("--------------------------\n");
printf("下机成功, 账户已更新\n");//下机则结算
printf("时间:%s", ctime(&t));
printf("--------------------------\n");
}
else {
printf("下机失败~请补充计费标准~\n");
}
exitOutStandard(pcs);//释放空间
return;
}
cur = cur->next;
}
printf("下机失败,“可能”原因是此卡暂为开通\n");
}
//3600------1h
//86400-----1day
//2592000---1month//默认30天
//31536000--1year//默认365天
long long transfer(int i) {
switch (i) {
case 1 :
return 31536000;
case 2 :
return 2592000;
case 3 :
return 86400;
case 4 :
return 3600;
}
}
time_t t = time(NULL);
long long longTime = t - cur->upTime;
double gap = 1.0 * longTime / transfer(cur->cardType);
if (gap != (int)gap) {
gap = (int)gap + 1;//不足进1~
}
void settlement(Card* cur, Consume* psu, time_t t, double gap, Standard* pcs) {
double benifit = gap * pcs[cur->cardType - 1].price;
cur->balance -= benifit;
Consume* newOne = (Consume*)malloc(sizeof(Consume));
newOne->id = cur->id;
newOne->money = benifit;
newOne->next = NULL;
newOne->timeNode = t;
if (orderNumber == 0) {
memcpy(psu, newOne, sizeof(Consume));
}
else {
Consume* current = psu;
while (current->next != NULL) {
current = current->next;
}
current->next = newOne;
}
orderNumber++;
}
exitOutConsume(
Exit.c)
数据导入data(必须自己建立)文件的consume.txt二进制文件中
如果卡数为0,那么只讲0导入文件即可,因为这个节点不为NULL但是不是有效数据!
不为0遍历链表导入数据,并且用相同的方法释放空间~
void exitOutConsume(Consume* psu) {
FILE* pf = fopen("data\\consume.txt", "wb");
fwrite(&orderNumber, sizeof(int), 1, pf);
if (orderNumber == 0) {
return;
}
while (psu != NULL) {
fwrite(psu, sizeof(Consume), 1, pf);
Consume* tmp = psu;
psu = psu->next;
free(tmp);
}
fclose(pf);
}
exitOutPunche
(Exit.c)
数据导入data(必须自己建立)文件的puncher.txt二进制文件中
如果卡数为0,那么只讲0导入文件即可,因为这个节点不为NULL但是不是有效数据!
不为0遍历链表导入数据,并且用相同的方法释放空间~
void exitOutPuncher(Puncher* ppu) {
FILE* pf = fopen("data\\puncher.txt", "wb");
fwrite(&workNumber, sizeof(int), 1, pf);
if (workNumber == 0) {
return;
}
while (ppu != NULL) {
fwrite(ppu, sizeof(Puncher), 1, pf);
Puncher* tmp = ppu;
ppu = ppu->next;
free(tmp);
}
fclose(pf);
}
导入消费单表
记录强制下机消费记录
释放更新消费单consume.txt~
void off(Card* pc, Consume* psu) {
printf("由于此次下机非主动下机,所以此次消费以按比例计算\n");
Standard* pcs = standardCarry();
time_t t = time(NULL);
long long longTime = t - pc->upTime;
double gap = 1.0 * longTime / transfer(pc->cardType);
settlement(pc, psu, t, gap, pcs);
pc->state = 0;
}
searchStatistics
(SearchStatistics.c)
void searchStatistics(Manager* pm) {
int input = 0;
Card* pc = cardCarry();
void (*func[4])(Card * pc) =
{ exitOutStatistics, searchConsume, statisticsTime, statisticsMonths };
do {
menu5_1();
scanf("%d", &input);
if (input <= 3 && input >= 0) {
func[input](pc);
}
else {
printf("输入失败\n");
}
} while (input);
}
void menu5_1() {
printf("******************\n");
printf("0. 退出\n");
printf("1. 查询消费记录\n");
printf("2. 统计总营业额\n");
printf("3. 统计月营业额\n");
printf("******************\n");
}
void menu5_2() {
printf("******************\n");
printf("1. 最近一年\n");
printf("2. 最近一月\n");
printf("3. 最近一天\n");
printf("******************\n");
}
searchConsume
(SearchStatistics.c)
输入卡号,探路指针找到对应卡~
找不到报无~
void searchConsume(Card* pc) {
//三个选择,最近一天,最近一月,最近一年
printf("请输入一张卡的卡号:>");
int id = 0;
scanf("%d", &id);
Card* cur1 = pc;
while (cardNumber != 0 && cur1 != NULL) {
if (id == cur1->id) {
menu5_2();
int number = 0;
printf("请选择一个时间段(距现在):>");
scanf("%d", &number);
long long gapTime = transfer(number);
Consume* psu = consumeCarry();
Consume* cur2 = psu;
printf("+------+-------------+\n");
printf("|%-6s|%13s|\n", "卡号", "消费/元");
printf("+------+-------------+\n");
while (cur2 != NULL) {
Consume* tmp = cur2;
if (cur2->id == id && time(NULL) - cur2->timeNode <= gapTime) {
printf("|%-6d|%13.2lf| 结算时间===>%s", cur2->id, cur2->money, ctime(&cur2->timeNode));
printf("+------+-------------+\n");
}
cur2 = cur2->next;
free(tmp);
}
return;
}
cur1 = cur1->next;
}
printf("查询失败,暂无此卡\n");
}
statisticsTime
(SearchStatistics.c)
void statisticsTime(Card* pc) {
menu5_2();
int number = 0;
printf("请选择一个时间段统计总营业额(距现在):>");
scanf("%d", &number);
Consume* psu = consumeCarry();
Consume* cur = psu;
printf("+------+-------------+\n");
printf("|%-6s|%13s|\n", "卡号", "消费/元");
printf("+------+-------------+\n");
double sum = 0;
long long gapTime = transfer(number);
while (cur != NULL) {
Consume* tmp = cur;
if (time(NULL) - cur->timeNode <= gapTime) {
printf("|%-6d|%13.2lf| 结算时间===>%s", cur->id, cur->money, ctime(&cur->timeNode));
printf("+------+-------------+\n");
sum += cur->money;
}
cur = cur->next;
free(tmp);
}
printf("|%-6s|%13.2lf|\n", "共计", sum);
printf("+------+-------------+\n");
}
statisticsMonths
(SearchStatistics.c)
void statisticsMonths(Card* pc) {
Date date = judgeMonth(time(NULL));
int year = date.year;
int month = date.month;
Date dates[12];
dates[11] = date;
for (int i = 10; i >= 0; i--) {
month--;
if (month == 0) {
year--;
month = 12;
}
dates[i].timestamp = dates[i + 1].timestamp - months[judgeLeapYear(year)][month] * 86400;
dates[i].month = month;
dates[i].year = year;
}
FILE* pf = fopen("data\\statisticsMonths.txt", "w");
Consume* psu = consumeCarry();
Puncher* ppu = puncherCarry();
Consume* cur = psu;
Puncher* current = ppu;
//做成哈希,还有这样做,构建的过程都要O(N^2)
//这里是下机计费,所以很有可能上机次数多但是收益少
fprintf(pf, "+-------+---------------+---------------+\n");
fprintf(pf, "|%-7s|%15s|%15s|\n", "Month", "Hands-on times", "Total turnover");
fprintf(pf, "+-------+---------------+---------------+\n");
printf("+-------+--------+-------------+\n");
printf("|%-7s|%8s|%13s|\n", "年月份", "上机次数", "月总营销额/元");
printf("+-------+--------+-------------+\n");
for (int i = 0; i < 12; i++) {
cur = psu;
current = ppu;
Date d = dates[i];
long long min = d.timestamp;
long long max = min + months[judgeLeapYear(d.year)][d.month] * 86400;
double sum = 0.0;
int count = 0; //上机次数
//消费与上机次数统计
while (orderNumber != 0 && cur != NULL &&
workNumber != 0 && current != NULL) {
if (cur->timeNode < max && cur->timeNode >= min) {
sum += cur->money;
}
if (current->timeNode < max && current->timeNode >= min) {
count++;
}
cur = cur->next;
current = current->next;
}
while (orderNumber != 0 && cur != NULL) {
if (cur->timeNode < max && cur->timeNode >= min) {
sum += cur->money;
}
cur = cur->next;
}
while (workNumber != 0 && current != NULL) {
if (current->timeNode < max && current->timeNode >= min) {
count++;
}
current = current->next;
}
fprintf(pf, "|%4d.%2d|%15d|%15.2lf|\n", d.year, d.month, count, sum);
fprintf(pf, "+-------+---------------+---------------+\n");
printf("|%4d.%2d|%8d|%13.2lf|\n", d.year, d.month, count, sum);
printf("+-------+--------+-------------+\n");
}
fclose(pf);
//free掉
exitOutConsume(psu);
exitOutPuncher(ppu);
}
//日期年月
typedef struct {
int year;
int month;
long long timestamp;//首时间戳
}Date;
months
(SearchStatistics.c)
int months[2][13] = { { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} };
judgeLeapYear
(Searchstatistics.c)
judgeMonth
(SearchStatistics.c)
int judgeLeapYear(int year) {
return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
}
Date judgeMonth(long long timeStamp) {
long long times = 1672502400;
int year = 2023;
int month = 1;
int i = 0;
while ((times += months[judgeLeapYear(year)][month] * 86400) <= timeStamp) {
i++;
month = i % 12 + 1;
if (month == 1) {
year++;
}
}
long long timestamp = times - months[judgeLeapYear(year)][month] * 86400;
Date date = { year, month, timestamp};
return date;
}
dates
数组 dates[i].timestamp = dates[i + 1].timestamp - months[judgeLeapYear(year)][month] * 86400;
Date date = judgeMonth(time(NULL));
int year = date.year;
int month = date.month;
Date dates[12];
dates[11] = date;
for (int i = 10; i >= 0; i--) {
month--;
if (month == 0) {
year--;
month = 12;
}
dates[i].timestamp = dates[i + 1].timestamp - months[judgeLeapYear(year)][month] * 86400;
dates[i].month = month;
dates[i].year = year;
}
"data\\statisticsMonths.txt"
,建立文本文档~,用“w”
FILE* pf = fopen("data\\statisticsMonths.txt", "w");
Consume* psu = consumeCarry();
Puncher* ppu = puncherCarry();
Consume* cur = psu;
Puncher* current = ppu;
//做成哈希,还有这样做,构建的过程都要O(N^2)
//这里是下机计费,所以很有可能上机次数多但是收益少
fprintf(pf, "+-------+---------------+---------------+\n");
fprintf(pf, "|%-7s|%15s|%15s|\n", "Month", "Hands-on times", "Total turnover");
fprintf(pf, "+-------+---------------+---------------+\n");
printf("+-------+--------+-------------+\n");
printf("|%-7s|%8s|%13s|\n", "年月份", "上机次数", "月总营销额/元");
printf("+-------+--------+-------------+\n");
for (int i = 0; i < 12; i++) {
cur = psu; //回到一开始
current = ppu; //回到一开始
Date d = dates[i];
long long min = d.timestamp;
long long max = min + months[judgeLeapYear(d.year)][d.month] * 86400;
double sum = 0.0;
int count = 0; //上机次数
//消费与上机次数统计
while (orderNumber != 0 && cur != NULL &&
workNumber != 0 && current != NULL) {
if (cur->timeNode < max && cur->timeNode >= min) {
sum += cur->money;
}
if (current->timeNode < max && current->timeNode >= min) {
count++;
}
cur = cur->next;
current = current->next;
}
while (orderNumber != 0 && cur != NULL) {
if (cur->timeNode < max && cur->timeNode >= min) {
sum += cur->money;
}
cur = cur->next;
}
while (workNumber != 0 && current != NULL) {
if (current->timeNode < max && current->timeNode >= min) {
count++;
}
current = current->next;
}
fprintf(pf, "|%4d.%2d|%15d|%15.2lf|\n", d.year, d.month, count, sum);
fprintf(pf, "+-------+---------------+---------------+\n");
printf("|%4d.%2d|%8d|%13.2lf|\n", d.year, d.month, count, sum);
printf("+-------+--------+-------------+\n");
}
fclose(pf);
//free掉
exitOutConsume(psu);
exitOutPuncher(ppu);
总共遍历个12次
最后,关闭文件(如果不关闭,那么数据就只会在程序的终结才能从缓存区导入文件!)
//释放空间
exitOutConsume(psu);
exitOutPuncher(ppu);
void exitOutStatistics(Card* pc) {
printf("退出成功\n");
}
文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭!这是我的代码仓库!(在马拉圈的23.3里)马拉圈2023年三月: 大学生代码仓库
全部源码具体位置:网吧管理系统 . 游离态