一、课题内容和要求
1、问题描述
本程序模拟根据上网清单、客户资料等生成客户上网账单的过程,该系统主要功能包括促销信息、待购信息的新增、删除、修改、查找等。所有数据都要利用文件系统保存,以备系统下次运行时使用。
2、功能要求
(1)文件管理和存储
- 用户资料文件,存放了用户名、用户帐号以及计费方式。
2) 上网记录文件,存放了所有用户的上网记录,内容包括用户帐号、上网起始时间和上网终止时间(格式:年月日小时分钟秒)。通常每个用户应有多条上网记录。
(2)功能需求 - 用户资料文件由程序设计人员预先从键盘上录入,用户资料文件中的数据记录 不得少于 15 条。
- 上网记录文件中的数据记录不得少于 150 条,首先录入一些上网记录信息,必 须有跨年、跨月份的上网记录。
- 用户资料文件及上网记录文件中的数据可随时增加或减少,程序不应进行限制 或限定。
- 对上网费用进行计算。首先由操作人员输入年份和月,然后由程序计算该月份 所有用户的上网费用并输出账单信息到指定文件夹
二、需求分析
上网计费系统的功能框架图如图所示。
(1)提供可操作的主菜单:输出菜单,用于显示以从文件中加载的总客户信息和若干个可选的功能选项。根据客户输入的选项来运行不同的功能,运行不同的函数。
(2)程序入口与菜单显示:构建mian()函数实现函数的入口,进入整个系统,调用菜单函数menu()进行显示并根据用户输入的选项调用相应的模块函数执行相应的内容。
(3)用户信息存储:用户信息不仅是用户ID等简单信息的存储以及增删查改,还涉及与用户相对应的用户卡,用户账户的信息存储与内容更新。本系统中通过构建用户结构体、用户卡结构体等的方式实现相关内容的存储,并且通过链式指针实现用户相关信息之间的调用与操作。
(4)上网时间获取与统计:通过getValue()函数调用库函数获取系统时间。后面被相应的获取年、月、日、时、分、秒函数调用,得到需要的时间戳信息。
(5)账户信息及更新:通过构建计算上机时长函数和计算费用函数,得到操作账户信息的基础信息,然后构建printbll()和calculateAllBill()函数进行用户账户信息的更新。
(6)具体程序实现,在后面的报告中都会涉及。
三、概要设计
1、主要存储结构
// 代码很烂,轻喷。注:仅供参考学习使用。
1. // 建立用户结构体
2. struct User {
3. char name[20];
4. char id[20];
5. int mode;
6. };
7. // 建立用户卡结构体
8. struct Record {
9. char id[20];
10. char start[20];
11. char end[20];
12. };
13. // 建立用户指针结构体
14. struct UserNode {
15. struct User user;
16. struct UserNode *next;
17. };
18. // 建立用户卡指针结构体
19. struct RecordNode {
20. struct Record record;
21. struct RecordNode *next;
22. };
23. // 建立用户卡,卡内信息结构体
24. struct UserBill {
25. char id[20];
26. char name[20];
27. float price;
28. struct UserBill *next;
29. };
四、源程序代码
// 代码很烂,轻喷。注:仅供参考学习使用。
//头文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
//全局变量定义
#define USER_FILE "user.txt"
#define RECORD_FILE "record.txt"
#define CONSOLE "CON"
// 建立用户结构体
struct User {
char name[20];
char id[20];
int mode;
};
// 建立用户卡结构体
struct Record {
char id[20];
char start[20];
char end[20];
};
// 建立用户指针结构体
struct UserNode {
struct User user;
struct UserNode *next;
};
// 建立用户卡指针结构体
struct RecordNode {
struct Record record;
struct RecordNode *next;
};
// 建立用户卡,卡内信息结构体
struct UserBill {
char id[20];
char name[20];
float price;
struct UserBill *next;
};
// 用户文件中获取信息构成结构体函数
struct UserNode* getUser() {
//输入重定向
freopen(USER_FILE, "r", stdin);
struct User user;
struct UserNode *head = (struct UserNode*)malloc(sizeof(struct UserNode));
struct UserNode *p = head;
//从文件读取数据
while (~scanf("%s%s%d", user.name, user.id, &user.mode)) {
struct UserNode *q = (struct UserNode*)malloc(sizeof(struct UserNode));
strcpy(q->user.name, user.name);
strcpy(q->user.id, user.id);
q->user.mode = user.mode;
p->next = q;
p = p->next;
}
p->next = NULL;
p = head->next;
// 回到标准输入
freopen("CON", "r", stdin);
return head;
}
// 构建添加用户函数
void addUser(char name[], char id[], int mode) {
// 文件指针
FILE* fp = fopen(USER_FILE, "a+");
// 输出到文件
fputs(name, fp);
fputs(" ", fp);
fputs(id, fp);
fputs(" ", fp);
char str[20];
itoa(mode, str, 10);
fputs(str, fp);
fputs("\n", fp);
// 关闭文件
fclose(fp);
}
// 构建用户信息函数
void printUser(struct UserNode *head) {
struct UserNode *p = head->next;
//打印用户
while (p) {
printf("%s %s %d\n", p->user.name, p->user.id, p->user.mode);
p = p->next;
}
}
// 构建用户信息记录函数
void printRecord(struct RecordNode *head) {
struct RecordNode *p = head->next;
//打印记录
while (p) {
printf("%s %s %s\n", p->record.id, p->record.start, p->record.end);
p = p->next;
}
}
// 构建删除用户函数
void deleteUser(char name[]) {
struct UserNode *head = getUser();
struct UserNode *pre = head;
struct UserNode *p = head->next;
//删除用户
while (p) {
if (strcmp(p->user.name, name) == 0) {
//链表删除
pre->next = p->next;
free(p);
break;
}
pre = pre->next;
p = p->next;
}
//输出重定向
freopen(USER_FILE, "w", stdout);
printUser(head);
//输出重定向
freopen(CONSOLE, "w", stdout);
}
// 构建查找用户函数
struct User * searchUser(char name[]) {
//输入重定向
freopen(USER_FILE, "r", stdin);
struct User user;
struct User *result = (struct User*) malloc(sizeof(struct User));
//搜索用户
while (~scanf("%s%s%d", user.name, user.id, &user.mode)) {
if (strcmp(user.name, name) == 0) {
// 找到用户
strcpy(result->id, user.id);
strcpy(result->name, user.name);
result->mode = user.mode;
break;
}
}
//回到标准输入
freopen(CONSOLE, "r", stdin);
return result;
}
// 构建写记录函数
void record() {
freopen(RECORD_FILE, "w", stdout);
struct Record record;
// 输入格式:0003 20151201170000 20151201193024 (卡号,年月日时分秒时分秒)
printf("用户ID:%s 开始:%s 结束:%s\n", record.id, record.start, record.end);
freopen(CONSOLE, "w", stdout);
printf("OK");
}
// 构建获取用户记录结构体函数
struct RecordNode* getRecord() {
freopen(RECORD_FILE, "r", stdin);
struct Record record;
struct RecordNode *head = (struct RecordNode*) malloc(sizeof(struct RecordNode));
struct RecordNode *p = head;
// 从文件读取
while (~scanf("%s%s%s", record.id, record.start, record.end)) {
struct RecordNode *q = (struct RecordNode*) malloc(sizeof(struct RecordNode));
strcpy(q->record.id, record.id);
strcpy(q->record.start, record.start);
strcpy(q->record.end, record.end);
//链表操作
p->next = q;
p = p->next;
}
p->next = NULL;
return head;
}
// 构建添加记录函数
void addRecord(char id[], char start[], char end[]) {
//输入重定向
FILE* fp = fopen(RECORD_FILE, "a+");
fputs(id, fp);
fputs(" ", fp);
fputs(start, fp);
fputs(" ", fp);
fputs(end, fp);
fputs("\n", fp);
fclose(fp);
}
// 构建搜索记录结构体函数
struct Record* searchRecord(char id[]) {
// 输入重定向
freopen(RECORD_FILE, "r", stdin);
struct Record record;
struct Record *result = (struct Record*) malloc(sizeof(struct Record));
while (~scanf("%s%s%s", record.id, record.start, record.end)) {
if (strcmp(record.id, id) == 0) {
strcpy(result->id, record.id);
strcpy(result->start, record.start);
strcpy(result->end, record.end);
}
}
freopen(CONSOLE, "r", stdin);
return result;
}
// 构建删除记录函数
void deleteRecord(char id[]) {
struct RecordNode *head = getRecord();
struct RecordNode *pre = head;
struct RecordNode *p = head->next;
while (p) {
if (strcmp(p->record.id, id) == 0) {
pre->next = p->next;
free(p);
break;
}
pre = pre->next;
p = p->next;
}
freopen(RECORD_FILE, "w", stdout);
printRecord(head);
freopen(CONSOLE, "w", stdout);
}
// 构建获取时间函数
int getValue(char time[], int offset, int size) { //调用函数获取时间
char value[20] = {0};
strncpy(value, time + offset, size);
return atoi(value);
}
// 构建获取年函数
int getYear(char time[]) {
return getValue(time, 0, 4); //调用上面getValue()函数进行“年 ”的获取
}
// 构建获取月函数
int getMonth(char time[]) {
return getValue(time, 4, 2); //调用上面getValue()函数进行“月 ”的获取
}
// 构建获取日函数
int getDay(char time[]) {
return getValue(time, 6, 2); //调用上面getValue()函数进行“日 ”的获取
}
// 构建获取时间函数
int getHour(char time[]) {
return getValue(time, 8, 2); //调用上面getValue()函数进行“时 ”的获取
}
// 构建获取分钟函数
int getMinite(char time[]) {
return getValue(time, 10, 2); //调用上面getValue()函数进行“分 ”的获取
}
// 构建获取秒函数
int getSecond(char time[]) {
return getValue(time, 12, 2); //调用上面getValue()函数进行“秒 ”的获取
}
// 构建通过ID获取用户结构体函数
struct User * searchUserById(char id[]) {
freopen(USER_FILE, "r", stdin);
struct User user;
struct User *result = (struct User*) malloc(sizeof(struct User));
while (~scanf("%s%s%d", user.name, user.id, &user.mode)) {
if (strcmp(user.id, id) == 0) {
strcpy(result->id, user.id);
strcpy(result->name, user.name);
result->mode = user.mode;
break;
}
}
freopen(CONSOLE, "r", stdin);
return result;
}
// 构建计算时长函数
int calcuateMinutes(struct Record record) {
int minutes = 0;
minutes += abs(getYear(record.end) - getYear(record.start)) * 365 * 24 * 60;
minutes += abs(getMonth(record.end) - getMonth(record.start)) * 30 * 24 * 60;
minutes += abs(getDay(record.end) - getDay(record.start)) * 24 * 60;
minutes += abs(getHour(record.end) - getHour(record.start)) * 60;
minutes += abs(getMinite(record.end) - getMinite(record.start)) * 60;
minutes += abs(getSecond(record.end) - getSecond(record.start)) / 60;
return minutes;
}
// 构建计算费用函数
float calculatePrice(struct Record record) {
float price = 0;
int minutes = calcuateMinutes(record);
struct User *user = searchUserById(record.id);
int month = abs(getMonth(record.end) - getMonth(record.start) + 12 * abs(getYear(record.end) - getYear(record.start))) + 1;
if (user->mode == 0) {
price = minutes * 0.03;
} else if (user->mode == 1) {
if (minutes > 30 * 24 * 60 * month) {
price = month * 50 + (minutes - month * 30 * 24 * 60) * 0.03;
} else {
price = month * 50;
}
} else if (user->mode == 2) {
if (minutes > 60 * 24 * 60* month) {
price = month * 95 + (minutes - month * 60 * 24 * 60) * 0.03;
} else {
price = month * 95;
}
} else if (user->mode == 3) {
if (minutes > 150 * 24 * 60* month) {
price = month * 200 + (minutes - month * 150 * 24 * 60) * 0.03;
} else {
price = month * 200;
}
} else {
price = month * 300;
}
return price;
}
// 构建账户函数
void printBill(struct UserBill *head) {
struct UserBill *p = head->next;
while (p) {
printf("%s %s %f\n", p->id, p->name, p->price);
p = p->next;
}
}
// 构建计算账户函数
void calculateAllBill(int year, int month) {
struct RecordNode *head = getRecord();
struct RecordNode *p = head->next;
struct UserBill *userHead = (struct UserBill*) malloc(sizeof(struct UserBill));
userHead->next = NULL;
struct UserBill *q = NULL, *pre;
float price;
while (p) {
//链表操作
if (getYear(p->record.start) == year && getMonth(p->record.start) == month) {
//计算费用
price = calculatePrice(p->record);
pre = userHead;
q = userHead->next;
//链表操作
while (q && q->id != p->record.id) {
q = q->next;
pre = pre->next;
}
if (!q) {
//新用户建立结点
q = (struct UserBill*) malloc(sizeof(struct UserBill));
strcpy(q->id, p->record.id);
strcpy(q->name, searchUserById(p->record.id)->name);
q->price = price;
q->next = NULL;
pre->next = q;
} else {
//累加
q->price += price;
}
}
p = p->next;
}
freopen("bill.txt", "w", stdout);
printBill(userHead);
freopen(CONSOLE, "w", stdout);
}
// 构建菜单函数
void menu() {
printf("[--- 按 1 to 添加用户---]\n");
printf("[--- 按 2 to 添加记录---]\n");
printf("[--- 按 3 to 删除用户---]\n");
printf("[--- 按 4 to 删除记录---]\n");
printf("[--- 按 5 to 搜索记录---]\n");
printf("[--- 按 6 to 搜索用户---]\n");
printf("[--- 按 7 to 生成账单---]\n");
}
// 程序主函数
int main(int argc, char const *argv[]) {
char ch;
char id[20], start[20], end[20], name[20];
int mode;
int year, month;
menu();
while (ch = getchar()) { //此处根据运行菜单函数后输入的数值进行相应的函数调用,实现相应功能。
fflush(stdin);
if (ch == '1') {
printf("添加用户\n");
fflush(stdin);
scanf("%s%s%d", name, id, &mode);
addUser(name, id, mode);
printf("成功添加!\n"); break;
} else if (ch == '2') {
printf("添加记录\n");
fflush(stdin);
scanf("%s%s%s", id, start, end);
addRecord(id, start, end);
printf("添加成功!\n"); break;
} else if (ch == '3') {
printf("删除用户\n");
fflush(stdin);
scanf("%s", name);
deleteUser(name);
printf("删除用户 %s 成功!\n", name); break;
} else if (ch == '4') {
printf("删除记录\n");
fflush(stdin);
scanf("%s", id);
deleteRecord(id);
printf("删除记录 %s 成功!\n", id); break;
} else if (ch == '5') {
printf("搜索记录\n");
fflush(stdin);
scanf("%s", id);
printf("%s %s\n", searchRecord(id)->start, searchRecord(id)->end); break;
} else if (ch == '6') {
printf("搜索用户\n");
fflush(stdin);
scanf("%s", name);
printf("%s\n", searchUser(name)->id); break;
} else if (ch == '7') {
printf("生成月度账单");
fflush(stdin);
scanf("%d%d", &year, &month);
calculateAllBill(year, month);
printf("生成成功\n"); break;
} else {
printf("输入错误!\n");break;
}
}
}
五、测试总结
此程序运行后按照先创建用户,然后再进行其他操作的方式运行就可以啦~
在实际的程序编写过程之中,小bug是在所难免的,但是下面这个bug给我带来的比较大的困扰,在对程序保存后再次打开运行程序时,编译不报错,反而报出源文件未编译的问题,这给我们小组的开发进程带来了很大的困扰。
解决方式:
程序运行的部分就不贴图啦。有兴趣的话,大家自己运行一下吧~
六、其他
以上以及博客中含有在校整理字样的博客内容,均是本人本科在校学习期间所写的代码,源文件以及数据文件等在个人主页资源区可以获取。本人水平很低,大佬轻喷。整理出来是为了帮助初学者学习的过程中,在有需要的情况下能够有所参考。再次声明:仅供学习交流使用。大家有什么问题,欢迎留言~