C语言程序设计:模拟校园卡系统

前言

       实践周用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(&currentTime);
	localTime = localtime(&currentTime);

	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;
}

 


总结

没啥好总结的,代码肯定有不完善的地方,仅供参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值