图书管理系统

https://gitee.com/x-0ne/library_system.git

1.设计模块及其功能

   

 2.设计函数名(见名知意)

 

 3.工具函数(每个模块基本都需要用到的函数)

// 缓冲区清理
void clear_stdin(void)
{
	stdin->_IO_read_ptr = stdin->_IO_read_end;
}
// 带休眠时间的字符串输出 显示延时
void put_str(const char* str,float sec)
{
	printf("%s\n",str);
	usleep(sec*1000000);
}
// 任意键继续
void anykey_continue(void)
{
	clear_stdin();
	puts("按任意键继续...");
	getch();
}
// 获取指令
char get_cmd(char start,char end)
{
	puts("----------------");
	printf("请输入指令:");
	
	clear_stdin();
	for(;;)
	{
		char cmd = getch();
		if(start <= cmd && cmd <= end)
		{
			printf("%c\n",cmd);
			return cmd;
		}
	}
}
// 安全的字符串输入
char* get_str(char* str,size_t size)
{
	if(NULL == str || 1 >= size)
		return NULL;

	// 清理输入缓冲区
	clear_stdin();

	// 以安全的方式读取size-1个字符
	fgets(str,size,stdin);

	// 计算字符串的长度
	size_t len = strlen(str);
	if(str[0]=='\n') return NULL;
	// 判断最后一个字符是否是\n
	if('\n' == str[len-1])
		// 删除'\n'
		str[len-1] = '\0';
	else
 		// 清理输入缓冲区
		while('\n' != getchar());
	

	return str;	
}
// 用于初始化ID,首次调用有效
void init_id(const char* path,unsigned int id)
{
	if(0 == access(path,F_OK))
		return;
	
	FILE* fp = fopen(path,"w");
	if(NULL == fp)
	{
		put_str("初始化ID失败,请检查path路径参数!",1);
		return;
	}
	
	fwrite(&id,sizeof(id),1,fp);
	fclose(fp);
}
// 从指定的路径读取ID,自加后再回写
unsigned int get_id(const char* path)
{
	FILE* fp = fopen(path,"r+");
	if(NULL == fp)
	{
		put_str("获取ID失败,请检查path参数!",1);
		return -1;
	}
	
	unsigned int id;
	fread(&id,sizeof(id),1,fp);
	id++;
	
	rewind(fp); //指针重新放到文件的开头
	fwrite(&id,sizeof(id),1,fp);
	fclose(fp);
	
	return id-1;
}
// 安全的密码输入 输入长度超过size则返回空指针
char* get_pwd(char* passwd,size_t size)
{
	clear_stdin();
	
	size_t cnt = 0;
	while(cnt>=0)
	{
		passwd[cnt] = getch();
		if(10 == passwd[cnt])
		{
			break;
		}
		else if(127 == passwd[cnt])
		{
			if(cnt > 0)
			{
				cnt--;
				printf("\b \b");
			}
		}
		else
		{
			cnt++;
			printf("*");
		}
	}
	if(cnt>size-1)	return NULL;
	passwd[cnt] = '\0';
	printf("\n");
	return passwd;
}

4.宏定义

#define Display     15                  //一页显示多少个
#define PATH_MAX    30            //路径长度30
#define PASSWD_LEN  11         //密码长度10
#define MANAGER_MAX 100    //普通管理员上限    
#define READER_MAX 1000     //读者上限
#define BOOK_MAX   5000        //图书上限
#define Delay_Time 1.5              //延时时间

#define MANAGER_ID  2023000   //管理员id初始化
#define READER_ID   11111          //读者id初始化
#define BOOK_ID     100000          //图书id初始化

#define SUPER_PATH      ".super.dat"             //超级管理员信息文件路径
#define MANAGER_PATH    ".manager.dat"    //普通管理员信息文件路径
#define READER_PATH        ".reader.dat"       //读者信息文件路径
#define BOOK_PATH       ".book.dat"               //图书信息文件路径

#define MANAGER_ID_PATH    ".manager_id.dat"  //普通管理员id存放路径
#define READER_ID_PATH    ".reader_id.dat"         //读者id存放路径
#define BOOK_ID_PATH    ".book_id.dat"                //图书id存放路径

#define MANAGER_Export_File  "manager.txt"  //管理员导出文件
#define READER_Export_File   "read.txt"           //读者导出文件
#define BOOK_Export_File     "book.txt"             //图书导出文件

.xxxx.dat 是隐藏的二进制文件

5.部分函数

1.超级管理员第一次登陆系统

int load_super(void)
{
	sup=calloc(1,sizeof(Str_super));
	FILE* fp = fopen(SUPER_PATH,"r"); 
	if(NULL == fp)
	{
		//fp = fopen(SUPER_PATH,"w");
		printf("第一次登录超级管理员!\n");
		printf("请输入管理员的姓名:");
		if(!get_str(sup[0].name,sizeof(sup[0].name)))
		{
			put_str("\n用户名空,设置失败!",Delay_Time);
			return 0;
		}
		char passwd1[Length],passwd2[Length];
		printf("请输入初始密码(%d位以内):",PASSWD_LEN-1);
		if(!get_pwd(passwd1,PASSWD_LEN))
		{
			put_str("\n密码长度过长,初始密码设置失败!",Delay_Time);
			return 0;
		}
		printf("请再次输入初始密码:");
		get_pwd(passwd2,PASSWD_LEN);
	
		if(strcmp(passwd1,passwd2))
		{
			put_str("\n两次输入的密码不符,设置失败!",Delay_Time);
			sup=NULL;
			return 0;
		}
		
		memcpy(sup[0].pwd,passwd1,sizeof(sup[0].pwd));
		fp = fopen(SUPER_PATH,"w");
		fwrite(sup,sizeof(Str_super),1,fp);
		put_str("超级管理员设置成功!",Delay_Time);
	}
	else
		fread(sup,sizeof(Str_super),1,fp); 
	fclose(fp);
	fp=NULL;
	return 1;
}

2.加载和保存管理员信息

void load_manager(void)  //加载管理者数据
{
	FILE* fp = fopen(MANAGER_PATH,"r"); //以只读打开该文件 文件必须存在
	if(NULL == fp) //如果失败 就创建一个
	{
		fp = fopen(MANAGER_PATH,"w"); //这里还需要判断一下是否是空指针
		return;
	}
	Manager_cnt = fread(man,sizeof(str_manager),MANAGER_MAX,fp); 
  //size_t(返回成功读取的对象个数) fread( void *buffer(指向要读取的数组中首个对象的指针), size_t size(每个对象的大小), size_t count(要读取的对象个数), FILE *stream(目标文件指针) );
	fclose(fp);
	fp=NULL;
}

void save_manager(void) //保存管理者数据
{
	FILE* fp = fopen(MANAGER_PATH,"w");//以只写打开文件,若文件存在则文件长度清为零,即内容消失;若文件不存在则创建该文件。
	if(NULL == fp)
	{
		put_str("保存管理员信息失败!",Delay_Time);
		return;
	}
	//put_str("保存管理员信息成功!",1);
	fwrite(man,sizeof(str_manager),Manager_cnt,fp);
	fclose(fp);
}

3.翻页显示管理员名单

static void list_manager_super()
{
	if(0 == Manager_cnt)
	{
		put_str("还没有管理员哦!",Delay_Time);
		return;
	}
	for(int i=0; i<Manager_cnt/(Display+1)+1; i++)  //i表示有几页
	{
		system("clear");
		printf(" id     姓名             工作岗位");
		printf("\n");
		for(int j=0;j<Display;j++)  //Display表示每页显示多少个
		{
			if(man[i*Display+j].id==0) break;
			printf("%-7u %-16s\t",
				man[i*Display+j].id,   
				man[i*Display+j].name);
			if('t'==man[i*Display+j].job) printf("图书管理员\n");
			else printf("读者管理员\n");
		}
		printf("j:上一页  k:下一页  l:退出  -----当前页数:%d-----\n",i+1);
		switch(get_cmd('j','l'))  //这里用到了工具函数
		{
			case 'k': i=(i==Manager_cnt/(Display+1))?(i-1):i; break;
			case 'j': i=(i==0)?-1:(i-2); break;
		    default:  return;
		}
	}
}

4.读者预约图书

书的状态book_state 1:无预约在馆 2:有预约在馆 3:无预约离馆 4:有预约离馆
void  booking_book_reader(void)
{
	if((rea[ord_rea].borrow_book_num >=3)&&(rea[ord_rea].booking_book_num >=3))  //自己借阅数,预约数都大于等于3
	{
		put_str("借阅图书和预约图书均已达上限!!!",Delay_Time);
		return;
	}
    unsigned int book_id;
	int i;
    printf("请输入需要预约的图书id:");
    scanf("%u",&book_id);
    for(i=0;i<Book_cnt;i++)
    {
        if(book_id == boo[i].id) //系统里存在这个id的书
        {
			for(int j=0;j<3;j++) //for(int j=0;j<3;j++) //判断是否在自己借的书当中
			{
				if(rea[ord_rea].borrow_book_id[j]==book_id)
				{
					put_str("此图书已被自己借阅,不用预约",2);
					return;
				}
			}
			for(int j=0;j<3;j++) //判断是否在自己预约的书当中
			{
				if(rea[ord_rea].booking_book_id[j]==book_id)
				{
					put_str("此图书已被自己预约,不用重复预约",2);
					return;
				}
			}
            if((boo[i].book_state==1)&&(rea[ord_rea].borrow_book_num < 3)) // 无预约在馆 自己借书数小于3,直接借走 
            {
                printf("借书数不足3本,无需预约,已成功借阅该书本\n");
                for(int j=0;j<3;j++) //更新借的情况
                {
                    if(rea[ord_rea].borrow_book_id[j]==0)
                    {
                        rea[ord_rea].borrow_book_id[j] = book_id;
						rea[ord_rea].borrow_book_num++;
                        //printf("读者信息已更新\n");
						break;
                    }
                }
				for(int j=0;j<3;j++)  //更新预约的情况
                {
                    if(rea[ord_rea].booking_book_id[j]==book_id)
                    {
                        rea[ord_rea].booking_book_id[j] = 0;
						rea[ord_rea].booking_book_num--;
                        //printf("读者信息已更新\n");
						break;
                    }
                }
				boo[i].borrow_book_cnt ++;
                boo[i].borrowe_id = acc_rea;
				boo[i].booking_id = 0;
                boo[i].book_state =3; //无预约离馆
                //put_str("书本信息已更新!",3);
				_find_book_number(i);
				show_people_reader();
                return;
            }
            else if((boo[i].book_state==1||boo[i].book_state==3)&&(rea[ord_rea].booking_book_num < 3))// 无预约在馆 无预约离馆 自己预约数小于3
            {
				for(int j=0;j<3;j++)  //更新预约的情况
                {
                    if(rea[ord_rea].booking_book_id[j]==0)
                    {
                        rea[ord_rea].booking_book_id[j] = book_id;
						rea[ord_rea].booking_book_num++;
                        //printf("读者信息已更新\n");
						break;
                    }
                }
                boo[i].booking_id = acc_rea;
                boo[i].book_state +=1; 
                //put_str("书本信息已更新!",Delay_Time);
				printf("预约成功!\n");
				_find_book_number(i);
				show_people_reader();
            	return;
            }
            else if(rea[ord_rea].booking_book_num >=3)  //自己预约数大于3
            {
                put_str("预约图书已达上限,无法继续预约!",Delay_Time);
                return;
            }
            else
            {
                put_str("该图书暂时不在可预约状态!",Delay_Time);
                return;
            }
        }
    }
	if(i==Book_cnt)
	{
    	put_str("未检索到该图书,请检查id是否正确!",Delay_Time);
        return;
    }
    return;
}

6.遇到的问题Q及解决办法A

Q:缓冲区问题             

A:封装函数,清空缓冲区

Q:多文件编译时无法调用到结构体/函数 

A:检查声明所在的行数,在调用前确保编译器能看到声明。同时检查函数调用时是否缺少参数,函数名是否一致等等

Qfscanf读取格式化输入乱码问题

A:1、整型数组类型无法用fscanf一次性全部读取,解决方法是换fread2、没有正确申请内存,解决方法是用calloc按格式进行内存分配

Q:函数逻辑运行与预期不符

A检查符号,检查函数逻辑,打断点检查成功运行的片段,逐步筛查未成功执行语句/片段

Q:编译运行错误,报大量游离中文字符

A:检查标点符号,全部检查依然没解决,删除所有空格,替换为tab

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值