前言
实践周用C语言做了一个综合程序设计,感觉收获还挺多的,索性直接开源了,也方便以后有同学做类似的项目能有个参考。这个程序实现的功能如下:
1. 管理员功能
-
查看学生上机状态:管理员可以查看指定学生的上机状态(上机或下机)。
-
修改学生卡信息:
-
修改学生卡状态:管理员可以修改学生卡的状态(正常、挂失、冻结)。
-
充值:管理员可以为学生卡充值,但充值金额会暂时存储在充值金额中,不会立即并入余额。
-
重置密码:管理员可以重置学生卡的密码。
-
-
添加卡:管理员可以添加新的学生卡信息,并自动创建相应的上机记录文件和上机状态文件。
-
注销卡:管理员可以注销学生卡信息,删除相应的文件。
2. 学生功能
-
登录:学生可以通过输入学号和密码登录系统。
-
查询学生卡信息:学生可以查看自己的卡号、姓名、学号、余额和状态等信息。
-
修改学生卡密码:学生可以修改自己的卡密码。
-
查询上机记录:学生可以查询自己的上机记录,包括日期、开始时间、上机地点、上机时长、上机费用和状态等信息。
-
上机和下机:
-
上机:学生登录后自动上机,系统开始计时。
-
下机:学生退出系统时自动下机,系统计算上机时长和费用,并自动扣费。
-
3. 其他功能
-
获取当前时间:程序可以获取当前时间,并将其格式化为字符串。
-
获取IP地址:程序可以获取当前设备的IP地址。
-
清屏:程序可以清屏,提供更好的用户体验。
-
清除输入缓冲区:程序可以清除输入缓冲区,防止输入错误。
4. 文件操作
-
读取和写入学生卡信息:程序可以从文件中读取和写入学生卡信息。
-
读取和写入上机记录:程序可以从文件中读取和写入上机记录。
-
读取和写入上机状态:程序可以从文件中读取和写入上机状态。
5. 安全机制
-
密码错误次数限制:学生密码输入错误次数达到3次后,系统会提示联系管理员。
-
卡状态检查:学生在登录时会检查卡的状态,如果卡被冻结或挂失,则无法登录。
6. 自动扣费
-
下机时自动扣费:学生在下机时,系统会根据上机时长自动计算费用并从余额中扣除。
7. 用户界面
-
菜单显示:程序会根据用户身份显示不同的菜单选项。
-
提示信息:程序会根据用户的操作显示相应的提示信息。
8. 错误处理
-
输入错误处理:程序会对用户的错误输入进行处理,并提示重新输入。
设计的主要难点有:含多行固定格式数据的文本文档的数据读取,数据修改,行数识别。
#define _CRT_SECURE_NO_WARNINGS 1
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include<winsock2.h>
#include<windows.h>
#pragma comment(lib,"ws2_32.lib") // 静态库
#define MAX_LINE_LENGTH 256//定义上级文件每一行的最大长度
// 定义一个结构体来存储时间信息
typedef struct TimeInfo {
int year;
int month;
int day;
int hour;
int minute;
} TimeInfo;
TimeInfo timeInfo;
typedef struct card
{
char id[10];//卡号
int password;
char name[50];//姓名
char number[50];//学号
double recharge;//充值金额
double remain;//余额
int state;//状态 0:正常 1:挂失 2:冻结
} Card;
Card card;
Card card_temp;
typedef struct record
{
char id[10];//卡号
char date[25];//上机日期
char start_time[15];//开始时间
char address[15];//上机地点
int duration;//上机时长/min
double fee;//上机费用/元
int state;//状态 0:上机 1:下机
} Record;
Record record;
Record record_temp;
// 封装获取当前时间的函数,并返回TimeInfo结构体
TimeInfo getCurrentTime() {
time_t currentTime;
struct tm* localTime;
TimeInfo timeInfo;
time(¤tTime);
localTime = localtime(¤tTime);
timeInfo.year = localTime->tm_year + 1900;
timeInfo.month = localTime->tm_mon + 1;
timeInfo.day = localTime->tm_mday;
timeInfo.hour = localTime->tm_hour;
timeInfo.minute = localTime->tm_min;
return timeInfo;
}
//将结构体里的时间参数格式化为字符串
char* format_time(TimeInfo timeInfo, char* date,char* start_time,int code)
{
if (code == 0)//返回日期
{
// 使用sprintf将TimeInfo格式化为字符串
sprintf(date, "%04d年%02d月%02d日",
timeInfo.year,
timeInfo.month,
timeInfo.day);
return date;
}
else if (code == 1)//返回开始时间
{
// 使用sprintf将TimeInfo格式化为字符串
sprintf(start_time, "%02d:%02d",
timeInfo.hour,
timeInfo.minute);
return start_time;
}
}
//IP地址获取函数
void findIP(char* ip, int size)
{
WORD v = MAKEWORD(1, 1);
WSADATA wsaData;
WSAStartup(v, &wsaData); // 加载套接字库
struct hostent* phostinfo = gethostbyname("");
char* p = inet_ntoa(*((struct in_addr*)(*phostinfo->h_addr_list)));
strncpy(ip, p, size - 1);
ip[size - 1] = '\0';
WSACleanup();
}
//清屏函数
void clearScreen()
{
//system("cls");
}
//清除缓冲区函数
void clear_input_buffer() {
int c;
// 使用一个循环来读取并丢弃输入缓冲区中的字符,直到遇到换行符或EOF
while ((c = getchar()) != '\n' && c != EOF) {
// 这里不需要对c做任何处理,只是读取并丢弃它
}
// 如果缓冲区中还有换行符,也将其丢弃(尽管在某些情况下可能希望保留它)
// 注意:在某些实现中,如果输入是从文件或管道重定向的,可能不会有换行符
// 在这种情况下,这个额外的读取操作可能是不必要的,但通常不会造成伤害
if (c == '\n') {
// 可以选择性地再次读取并丢弃换行符,或者什么都不做
// 在这个特定的函数中,我们选择不执行任何额外操作,因为换行符已被读取
// 如果需要,可以在这里添加额外的逻辑来处理换行符
}
// 注意:如果输入是从非交互式源(如文件)获取的,并且没有换行符,
// 这个函数可能会一直阻塞,等待EOF或换行符。在那种情况下,可能需要不同的逻辑。
}
//读取学生卡数据
int read_card(char* filename, Card* card)
{
char temp[50];
FILE* fp;
char suffix[10] = "card.txt";
Card card1;
snprintf(temp, sizeof(temp), "%s%s", filename, suffix);
fp = fopen(temp, "r");
if (fp == NULL)
{
printf("未找到对应用户!\n");
return 0;
}
while (!feof(fp))
{
fscanf(fp, "%s %d %s %s %lf %lf %d", &card1.id, &card1.password, card1.name, &card1.number, &card1.recharge, &card1.remain, &card1.state);
//必须要用指针赋值,否则就歇逼
strcpy(card->id, card1.id);
card->password = card1.password;
strcpy(card->name, card1.name);
strcpy(card->number, card1.number);
card->recharge = card1.recharge;
card->remain = card1.remain;
card->state = card1.state;
return 1;
}
fclose(fp);
}
//管理员添加学生卡信息
int add_card(Card* card)
{
printf("请输入卡号: \n");
scanf("%s", card->id);
printf("请输入密码: \n");
scanf("%d", &card->password);
printf("请输入姓名: \n");
scanf("%s", card->name);
printf("请输入学号: \n");
scanf("%s", card->number);
printf("请输入充值金额: \n");
scanf("%lf", &card->recharge);
printf("请输入余额: \n");
scanf("%lf", &card->remain);
printf("请输入状态(0:正常 1:挂失 2:冻结): \n");
scanf("%d", &card->state);
char temp[50];
FILE* fp;
char suffix[10] = "card.txt";
// 使用 snprintf 来安全地拼接字符串
snprintf(temp, sizeof(temp), "%s%s", card->number, suffix);
fp = fopen(temp, "w");
if (fp == NULL) {
printf("无法打开文件!\n");
return 0;
}
fprintf(fp, "%s %d %s %s %lf %lf %d\n", card->id, card->password, card->name, card->number, card->recharge, card->remain, card->state);
fclose(fp);
printf("添加成功!\n");
return 1;
}
//添加学生卡信息后,系统自动添加相应的上机记录文件和上级状态文件
int AddFile(char* number) {
// 打开或创建文件
char temp1[50];
char temp2[50];
FILE* fp;
char suffix1[20] = "record.txt";
char suffix2[10] = "state.txt";
snprintf(temp1, sizeof(temp1), "%s%s", number, suffix1);
snprintf(temp2, sizeof(temp2), "%s%s", number, suffix2);
fp = fopen(temp1, "w");
if (fp == NULL) {
perror("无法创建文件");
return 0; // 返回错误码
}
fclose(fp);
fp = fopen(temp2, "w");
if (fp == NULL) {
perror("无法创建文件");
return 0; // 返回错误码
}
fclose(fp);
return 1; // 成功返回1
}
//管理员注销学生卡信息
int delete_card(Card* card)
{
printf("请输入要注销的学生卡所属学生的学号: \n");
scanf("%s", card->number);
char temp[50];
char suffix[10] = "card.txt";
// 使用 snprintf 来安全地拼接字符串
snprintf(temp, sizeof(temp), "%s%s", card->number, suffix);
// 尝试删除文件
if (remove(temp) == 0) {
printf("学生卡数据文件 %s 已成功删除。\n", temp);
return 1;
}
else {
perror("删除文件时出错!\n");
return 0;
}
}
//管理员修改学生卡信息
//修改学生卡状态(正常,挂失,冻结),充值,重制密码
//状态码选择操作
int update_card(Card* card, char* target_number, int code)
{
char temp[50];
char suffix[10] = "card.txt";
// 使用 snprintf 来安全地拼接字符串
snprintf(temp, sizeof(temp), "%s%s", target_number, suffix);
FILE* fp_read = fopen(temp, "r");
FILE* fp_write = tmpfile(); // 使用临时文件来存储修改后的内容
if (!fp_read || !fp_write)
{
perror("无法打开文件!");
if (fp_read) fclose(fp_read);
if (fp_write) fclose(fp_write);
return 0;
}
while (fscanf(fp_read, "%s %d %s %s %lf %lf %d", card->id, &card->password, card->name, card->number, &card->recharge, &card->remain, &card->state) == 7)
{
if (strcmp(card->number, target_number) == 0)
{
// 找到目标卡,根据状态码进入不同行动分支
if (code == 0)//修改学生卡状态
{
printf("学生卡当前状态为:%d \n", card->state);
printf("请输入想要修改的状态(0:正常 1:挂失 2:冻结): \n");
scanf("%d", &card->state);
}
/*
关于充值
管理员可以充值学生卡余额,但金额会暂时存储在充值金额中,不会立即并入余额
只有在学生登录时才会执行并入操作,并将充值金额清零
*/
else if (code == 1)//充值
{
printf("当前充值金额为:%lf: \n",card->recharge);
printf("请输入充值金额: \n");
scanf("%lf", &card->recharge);
}
else if (code == 2)//重置密码
{
printf("当前密码为: %d \n",card->password);
printf("请输入新密码: \n");
scanf("%d", &card->password);
}
}
fprintf(fp_write, "%s %d %s %s %lf %lf %d\n", card->id, card->password, card->name, card->number, card->recharge, card->remain, card->state);
}
fclose(fp_read);
// 将临时文件的内容写回原文件
rewind(fp_write);
fp_read = fopen(temp, "w"); // 重新以写模式打开原文件
if (!fp_read)
{
perror("无法重新打开文件以写入!");
fclose(fp_write);
return 0;
}
char buffer[100];
while (fgets(buffer, sizeof(buffer), fp_write))
{
fputs(buffer, fp_read);
}
fclose(fp_read);
fclose(fp_write);
return 1; // 修改成功
}
//转移充值金额
int transfer_recharge(Card* card, char* target_number)
{
char temp[50];
char suffix[10] = "card.txt";
// 使用 snprintf 来安全地拼接字符串
snprintf(temp, sizeof(temp), "%s%s", target_number, suffix);
FILE* fp_read = fopen(temp, "r");
FILE* fp_write = tmpfile(); // 使用临时文件来存储修改后的内容
if (!fp_read || !fp_write)
{
perror("无法打开文件!");
if (fp_read) fclose(fp_read);
if (fp_write) fclose(fp_write);
return 0;
}
while (fscanf(fp_read, "%s %d %s %s %lf %lf %d", card->id, &card->password, card->name, card->number, &card->recharge, &card->remain, &card->state) == 7)
{
if (strcmp(card->number, target_number) == 0)
{
// 找到目标卡,将充值金额转移到余额中
card->remain = card->remain + card->recharge;
card->recharge = 0;
}
fprintf(fp_write, "%s %d %s %s %lf %lf %d\n", card->id, card->password, card->name, card->number, card->recharge, card->remain, card->state);
}
fclose(fp_read);
// 将临时文件的内容写回原文件
rewind(fp_write);
fp_read = fopen(temp, "w"); // 重新以写模式打开原文件
if (!fp_read)
{
perror("无法重新打开文件以写入!");
fclose(fp_write);
return 0;
}
char buffer[100];
while (fgets(buffer, sizeof(buffer), fp_write))
{
fputs(buffer, fp_read);
}
fclose(fp_read);
fclose(fp_write);
return 1; // 转移成功
}
//结束时自动扣费
int consume(Card* card, char* target_number,double fee)
{
char temp[50];
char suffix[10] = "card.txt";
// 使用 snprintf 来安全地拼接字符串
snprintf(temp, sizeof(temp), "%s%s", target_number, suffix);
FILE* fp_read = fopen(temp, "r");
FILE* fp_write = tmpfile(); // 使用临时文件来存储修改后的内容
if (!fp_read || !fp_write)
{
perror("无法打开文件!");
if (fp_read) fclose(fp_read);
if (fp_write) fclose(fp_write);
return 0;
}
while (fscanf(fp_read, "%s %d %s %s %lf %lf %d", card->id, &card->password, card->name, card->number, &card->recharge, &card->remain, &card->state) == 7)
{
if (strcmp(card->number, target_number) == 0)
{
card->remain = card->remain - fee;
}
fprintf(fp_write, "%s %d %s %s %lf %lf %d\n", card->id, card->password, card->name, card->number, card->recharge, card->remain, card->state);
}
fclose(fp_read);
// 将临时文件的内容写回原文件
rewind(fp_write);
fp_read = fopen(temp, "w"); // 重新以写模式打开原文件
if (!fp_read)
{
perror("无法重新打开文件以写入!");
fclose(fp_write);
return 0;
}
char buffer[100];
while (fgets(buffer, sizeof(buffer), fp_write))
{
fputs(buffer, fp_read);
}
fclose(fp_read);
fclose(fp_write);
return 1; // 修改成功
}
//学生读取上机记录(可根据次数读取)
int read_record(char* filename, Record* record, int target_line)
{
int line_count = 0;
char line[MAX_LINE_LENGTH];
char temp[50];
FILE* fp;
char suffix[10] = ".txt";
Record record1;
snprintf(temp, sizeof(temp), "%s%s", filename, suffix);
fp = fopen(temp, "r");
if (fp == NULL)
{
printf("未找到对应用户!\n");
return 0;
}
while (!feof(fp))
{
// 使用fgets逐行获取文件总行数
while (fgets(line, sizeof(line), fp) != NULL)
{
line_count++;
}
printf("上机总次数为:%d\n", line_count);
// 重新定位到文件开头
rewind(fp);
if (!(target_line > 0)||(target_line > line_count))
{
printf("输入不合规!\n");
return 0;
}
for (int i = 1; i <= target_line; i++)
{
fscanf(fp, "%s %s %s %s %d %lf %d\n", record1.id, record1.date, record1.start_time, record1.address, &record1.duration, &record1.fee, &record1.state);
if (i == target_line)
{
//必须要用指针赋值,否则就歇逼
strcpy(record->id, record1.id);
strcpy(record->date, record1.date);
strcpy(record->start_time, record1.start_time);
strcpy(record->address, record1.address);
record->duration = record1.duration;
record->fee = record1.fee;
record->state = record1.state;
return 1;
}
}
}
fclose(fp);
}
//更新上机记录
int write_record(char* number, Record* record, Card* card,int duration,double fee,int state)
{
char temp[50];
FILE* fp;
char suffix[10] = ".txt";
snprintf(temp, sizeof(temp), "%s%s", number, suffix);
fp = fopen(temp, "a+");
if (fp == NULL)
{
printf("未找到对应用户!\n");
return 0;
}
fprintf(fp, "%s %s %s %s %d %.2lf %d\n", card->id, record->date, record->start_time, record->address, duration, fee, state);
fclose(fp);
printf("添加成功!\n");
return 1;
}
//显示学生卡基本信息
void show_message(Card* card)
{
printf("以下是您的信息:\n");
printf("卡号:%s\n", card->id);
printf("姓名:%s\n", card->name);
printf("学号:%s\n", card->number);
//printf("充值金额:%.2f\n", card->recharge);
printf("余额:%.2f\n", card->remain);
printf("状态(0:正常 1:挂失 2:冻结):%d\n", card->state);
printf("\n");
}
//显示上机记录
void show_record(Record* record)
{
printf("以下是您的上机记录:\n");
printf("日期:%s\n", record->date);
printf("开始时间:%s\n", record->start_time);
printf("上机地点:%s\n", record->address);
printf("上机时长:%d分钟\n", record->duration);
printf("上机费用:%lf元\n", record->fee);
printf("状态(0:上机 1:下机):%d\n", record->state);
printf("\n");
}
//修改上机状态
int update_state(char* target_number, Record* record, int code)
{
char temp[50];
char suffix[10] = "state.txt";
// 使用 snprintf 来安全地拼接字符串
snprintf(temp, sizeof(temp), "%s%s", target_number, suffix);
FILE* fp_read = fopen(temp, "r");
FILE* fp_write = tmpfile(); // 使用临时文件来存储修改后的内容
if (!fp_read || !fp_write)
{
perror("无法打开文件!");
if (fp_read) fclose(fp_read);
if (fp_write) fclose(fp_write);
return 0;
}
while (fscanf(fp_read, "%d\n",&record->state) == 1)
{
if (code == 0)//学生上机
{
printf("当前上机状态为:0(上机)\n");
record->state = 0;
}
else if (code == 1)//学生下机
{
record->state = 1;
}
fprintf(fp_write, "%d\n", record->state);
}
fclose(fp_read);
// 将临时文件的内容写回原文件
rewind(fp_write);
fp_read = fopen(temp, "w"); // 重新以写模式打开原文件
if (!fp_read)
{
perror("无法重新打开文件以写入!");
fclose(fp_write);
return 0;
}
char buffer[100];
while (fgets(buffer, sizeof(buffer), fp_write))
{
fputs(buffer, fp_read);
}
fclose(fp_read);
fclose(fp_write);
return 1; // 修改成功
}
//管理员读取上机状态
int read_state(char* target_number, Record* record)
{
char temp[50];
FILE* fp;
char suffix[10] = "state.txt";
Record record1;
snprintf(temp, sizeof(temp), "%s%s", target_number, suffix);
fp = fopen(temp, "r");
if (fp == NULL)
{
printf("未找到对应用户!\n");
return 0;
}
while (!feof(fp))
{
fscanf(fp, "%d", &record1.state);
//必须要用指针赋值,否则就歇逼
record->state = record1.state;
return 1;
}
fclose(fp);
}
//显示管理员菜单
void menu_admin1()
{
printf("请选择您想要进行的操作:\n");
printf("\n");
printf("0. 查看学生上机状态\n");
printf("1. 修改学生卡信息\n");
printf("2. 添加卡\n");
printf("3. 注销卡\n");
printf("4. 退出系统\n");
printf("\n");
}
//管理员操作函数
void admin_opration(char* choice_admin)
{
if (strcmp(choice_admin, "0") == 0)
{
//查看学生上机状态
char target_number[10];
printf("请输入您要查询的学生学号: \n");
scanf("%s", target_number);
Record record_temp;
read_state(target_number, &record_temp);
if (record_temp.state == 0)
{
printf("该学生当前状态为:上机\n");
}
else if (record_temp.state == 1)
{
printf("该学生当前状态为:下机\n");
}
else
{
printf("该学生当前状态为:未知\n");
}
}
else if (strcmp(choice_admin, "1") == 0)
{
while (1)
{
//在这里判断code的值的不合格输入
printf("\n");
//printf("请输入您要修改的学生卡所有人的学号: \n");
char target_number[10];
int code;//状态码
//scanf("%s", target_number);
printf("请输入您要进行的操作(0:修改状态,1:充值,2:重置密码): \n");
scanf("%d", &code);
//清除缓存,防止界面bug
clear_input_buffer();
printf("请输入您要修改的学生卡所有人的学号: \n");
scanf("%s", target_number);
if (code != 0 && code != 1 && code != 2)
{
printf("输入错误,请重新输入!\n");
continue;
}
else
{
int update_card_res = update_card(&card_temp,target_number, code);//接受update_card函数的返回值,接收到0表示修改失败
if (update_card_res == 0)
{
printf("遇到问题,请重新输入!\n");
continue;
}
else
{
printf("修改成功!\n");
printf("\n");
break;
}
}
}
}
else if (strcmp(choice_admin, "2") == 0)
{
//添加卡
add_card(&card_temp);
//创建对应文件
AddFile(&card_temp);
}
else if (strcmp(choice_admin, "3") == 0)
{
//注销卡
delete_card(&card_temp);
}
else if (strcmp(choice_admin, "4") == 1)
{
printf("不合规的输入,请重新输入!\n");
printf("\n");
}
}
int readcard_res;//接受readcard函数的返回值,接收到0表示未找到对应用户,则后续不输出密码信息
int readrecord_res;//接受readrecord函数的返回值,接收到0表示未找到对应次数的上机记录,则后续不输出上机记录信息
//计算时间差所用变量
time_t start_time, end_time;
int difference;//存储时间的差值
char date[25];
char time1[15];
//主函数
int main()
{
char number[50];
int password_in = 0;
char choice[10];
char choice_admin[10];
char choice_stu[10];
const char admin_key[10] = "666777";
int attempt = 0;//密码尝试次数
while (1)
{
printf("\n");
clearScreen();
printf("欢迎使用校园卡管理系统!\n");
printf("若想以管理员身份登录,请输入管理员密钥;若以学生身份登陆,请输入1.\n");
scanf("%s", &choice);
//管理员身份登录
if (strcmp(choice,admin_key) == 0)
{
clearScreen();
printf("欢迎使用校园卡管理系统!\n");
while (1)
{
//显示菜单
menu_admin1();
scanf("%s", choice_admin);
//管理员操作
admin_opration(choice_admin);
//退出选项
if (strcmp(choice_admin, "4") == 0)
{
printf("您是否想退出本系统?(y/n)\n");
char draw;
scanf(" %c", &draw); // 读取单个字符,并跳过前导空白
if (draw == 'y' || draw == 'Y')
{
printf("欢迎下次使用!\n");
printf("\n");
break;
}
else
{
continue;
}
}
//break;
}
continue;//回到开头,重新输入
}
//学生身份登录
else if (strcmp(choice, "1") == 0)
{
clearScreen();
printf("请输入学号: ");
scanf("%s", number);
printf("请输入密码: ");
scanf("%d", &password_in);
readcard_res = read_card(number, &card);
if ((password_in == card.password) && (readcard_res == 1) && (card.state == 0))
{
printf("登陆成功!\n");
Sleep(1000);
//获取开始时间,并存储在结构体中
timeInfo = getCurrentTime();
//格式化为字符串
format_time(timeInfo, date, time1, 0);
format_time(timeInfo, date, time1, 1);
update_state(number, &record, 0);//学生上机
time(&start_time);//开始计时
/*
这里修改登录的学生卡结构体的数据
将充值金额存入余额,并清零充值金额
应注意,处于冻结和挂失状态的卡不执行此命令!
*/
transfer_recharge(&card, number);
while (1)
{
printf("\n");
printf("请输入您要进行的操作(0:查询学生卡信息 1:修改学生卡密码,2:查询上机记录 3.退出系统): \n");
scanf("%s", choice_stu);
if (strcmp(choice_stu, "0") == 0)
{
show_message(&card);
continue;
}
else if (strcmp(choice_stu, "1") == 0)
{
update_card(&card, number,2);//学生修改密码
continue;
}
else if (strcmp(choice_stu, "2") == 0)
{
int target_line;
printf("请输入您要查询第几次上机记录: \n");
scanf("%d", &target_line);
readrecord_res = read_record(number, &record, target_line);
if (readrecord_res == 0)
{
continue;
}
show_record(&record);
continue;
}
else if (strcmp(choice_stu, "3") == 0)
{
//空语句,以直接进入最后的退出界面
}
else
{
printf("输入错误! 请重新输入!\n");
continue;
}
//登出选项
printf("您是否想退出本系统?(y/n)\n");
char draw;
scanf(" %c", &draw); // 读取单个字符,并跳过前导空白
if (draw == 'y' || draw == 'Y')
{
printf("欢迎下次使用!\n");
update_state(number, &record, 1);//学生下机
time(&end_time);
difference = difftime(end_time, start_time);//计算时间差,强转为整型
//计价标准: 1s=>0.01元(示例)
double fee = (double)difference * 0.01;
printf("本次上机时长为%f分钟,费用为%.2lf元。\n", difference/60.0, fee);
printf("您的余额为%.2lf元。\n", card.remain - difference*0.01);
//实现自动扣费
consume(&card, number,fee);
Record* r1 = &record_temp;
char ip[20] = { 0 };
findIP(ip, sizeof(ip));//地址
//更新上机记录(有bug,待修复)
strcpy(r1->date, date);
strcpy(r1->start_time, time1);
//strcpy(r1->address, ip);
strcpy(r1->address, "教二302");
write_record(number, r1, &card,difference/60,fee,0);
break;
}
else
{
continue;
}
break;
}
}
else
{
if ((card.state == 1)||(card.state == 2))
{
printf("该卡已被冻结或挂失,请联系管理员!\n");
continue;
}
if (readcard_res == 1)
{
printf("密码错误!\n");
attempt++;
if (attempt == 3)
{
printf("密码输入错误次数过多,请联系管理员!\n");
break;
}
}
printf("\n");
continue;
}
}
//输入错误处理
else
{
printf("输入错误! 请重新输入!\n");
printf("\n");
continue;//回到开头,重新输入
}
break; //退出循环
}
return 0;
}