图书管理系统

问题描述
设计一个计算机管理系统完成图书管理基本业务。
每种书的登记内容包括书号、书名、著作者、现存量和库存量;
对书号建立索引表(线性表)以提高查找效率;
系统主要功能如下:
a) 采编入库:新购一种书,确定书号后,登记到图书帐目表中,如果表中已有,则只将库存量增加;
b) 借阅:如果一种书的现存量大于0,则借出一本,登记借阅者的书证号和归还期限,改变现存量;
c) 归还:注销对借阅者的登记,改变该书的现存量。
问题分析
利用函数式编程完成主要功能,对每种书的登记采用结构体储层,再用链表将其链接。,使用链表提高查询书的速度,对于借阅者的书证号和归还日期采用结构体数组储存。再借阅成功后,此书的现存量减一而库存量不变,再还书过后对结构体数组进行清除操作。
核心代码
储存书:该代码是对每一本书的储存,采用结构体的形式储存。

typedef struct BookShelf{    //每一本书的声明 
	char num[10];   //书号 
	char name[10];   //书名 
	char writer[10];  //书作者 
	int xiancun;  //现存量 
	int kucun;  //库存量 
}Book;

借阅者的信息:该代码是将每一个借阅者信息存进一个结构体数组中去,当还书过后,将借阅者信息进行覆盖实现删除功能。

struct Browwer{    //借阅者信息 
	int peoplenumber;   //书证号 
	int month;    //月 
	int date;    //日 
}B[100];

链表的声明:链表分为数据域和指向下一个结点的指针

typedef struct Lnode{    //链表的声明 
	Book data;
	struct Lnode *next;
}Lnode, *Linklist;

初始化链表:把头结点的next域指向空,如果已经为空的时候直接返回就可以

void EmptyList(Linklist L){   //初始化链表 
	if(L->next == NULL)
		return;
	else
		L->next = NULL;
}

生成一个结点:生成一个结点函数,方便其他函数调用,malloc申请结点指针空间,这里因为是char类型的数组的原因所以用strcpy函数进行赋值,剩余两个数据使用int类型的,所以可以直接赋值,把书的信息存储到这个结点中,这个的next域指向空。返回此节点。

Lnode *CreateNode(Book book1){      //生成一个结点 
	Lnode *pnext = (Lnode *)malloc(sizeof(Lnode));   //malloc申请结点指针空间 
	strcpy(pnext->data.num, book1.num);   //book1的数据赋值给结点 
	strcpy(pnext->data.name, book1.name);
	strcpy(pnext->data.writer, book1.writer);
	pnext->data.xiancun = book1.xiancun;
	pnext->data.kucun = book1.kucun;
	pnext->next = NULL;
	return pnext;
}

图书入库:采用尾插法插入数据,定义一个结点指针,当指针指向空时创建结点调用生成结点函数CreateNode(),如果不为空,则访问next域判断是否为空,最后再将当前结点next结点相连接。

void InsertBook(Linklist L, Book book1){   //尾插法插入数据 
	Lnode *pnow = L;   //结点指针 
	while((pnow->next != NULL)){      // 当链表指针指向空时
		pnow = pnow->next;
	}             
	Lnode *pnext = CreateNode(book1);    //结点创建 
	pnow->next = pnext;        //链接链表 
}

借书过程:定义一个信号量和一个结点。用while循环中的if(!(strcmp(p->data.num,book1.num)))进行判断当书号相同时,书被借出去了,书的库存量应该减一,信号量置0,退出while循环,如果不同,则使指针结点访问下一个数据域,当数据域指向空时,提示用户书本信息错误,信号量置0,退出while循环。

void LendBook(Linklist L, Book book1){   //借书过程 
	int count = 1;
	Lnode *p = L->next;   //p是一个结点 
	while(count){
		if(!(strcmp(p->data.num,book1.num))){    //比较书的书号 
			p->data.xiancun = p->data.xiancun - 1;
			count = 0;
		}
		else if(p->next==NULL){
			printf("书本信息错误\n");
			count = 0;
		}
		else
			p=p->next;
	}
}

显示图书信息:创建结点指针,用while循环控制,循环条件是结点指针不为空,在循环中输出书号,书名,著作者,现存量,库存量。结点指向下一个结点。

void Showbooks(Linklist L){   //显示图书信息 
	Lnode *p = L->next;
	while(p != NULL){
		printf("书本书号%s\n", p->data.num);
		printf("%s书本书名%s\n", p->data.num, p->data.name);
		printf("%s书本著作者%s\n", p->data.num, p->data.writer);
		printf("%s书本现存量%d\n", p->data.num, p->data.xiancun);
		printf("%s书本库存量%d\n", p->data.num,p->data.kucun);
		p = p->next;
	}
} 

还书过程:其过程与借书原理差不多,定义一个信号量和一个结点。用while循环中的if(!(strcmp(p->data.num,book1.num)))进行判断当书号相同时,书被借出去了,书的库存量应该加一,信号量置0,退出while循环,如果不同,则使指针结点访问下一个数据域,当数据域指向空时,提示用户书本信息错误,信号量置0,退出while循环。

void BackBook(Linklist L, Book book1, Browwer B[], int i){   //还书过程 
	int count = 1;
	Lnode *p = L->next;
	while(count){
		if(!(strcmp(p->data.num,book1.num))){
			p->data.xiancun = p->data.xiancun + 1;
			count = 0;
			DeletePeople(B, i); 
		}
		else if(p->next==NULL){
			printf("书本信息错误\n");
			count = 0;
		}
		else
			p=p->next;
	}
}

添加已有的图书:定义信号量,用while循环,创建头节点指针,当输入的书号与存储在结构体中的书号相同时,库存量加一,使信号量置为零,从而退出循环。

void AddBook(Linklist L, Book book1,int i){   //库存增加书过程 
	int count = 1;
	Lnode *p = L->next;
	while(count){
		if(!(strcmp(p->data.num,book1.num))){
			p->data.kucun = p->data.kucun + i;
			count = 0; 
		} 
	}
}

借书信息:利用for循环访问储存借书的结构体数组并输出。

void ShowBorrow(Browwer B[], int a){   //借书信息 
	for(int i = 0; i < a; i++){
		printf("借阅者书证号:%d\n", B[i].peoplenumber);
		printf("还书日期:%d月%d号\n", B[i].month, B[i].date);
	}
}

删除借阅人信息:再还书过后,将借阅人的信息覆盖为零。(这一部分我写的有很大问题,暂时没找到有效的方法解决)

void DeletePeople(Browwer B[], int b){   //删除借阅人信息 
		B[b].peoplenumber = 0;
		B[b].month = 0;
		B[b].date = 0; 
} 

退出:输入零直接退出

case '0' : {
				printf("退出系统成功\n");
				count = 0;
			}

Main代码:

int main(){
	Linklist *head;
	Lnode L;
	EmptyList(&L);
	char choice;
	int count = 1;
	int m;
	int number;
	while(count){
		printf("+++++++++++++++图书管理系统+++++++++++\n");
    	printf("+------------------------------------+\n");
		printf("+(请按相应的数字键选择您所需要的操作)+\n");
		printf("+------------------------------------+\n");
		printf("+ 1.图书入库            2.借阅   +\n");
		printf("+ 3.归还                4.借阅者信息  +\n");
		printf("+ 5.显示图书            0.退出   +\n");
		printf("+ 6.库存里增加图书\n");
		rewind(stdin);
		scanf("%c", &choice);
		switch(choice) {
			case '1' : {
				printf("你想输入多少种类书籍\n");
				scanf("%d", &number);
				for(int i = 0; i < number; i++){
					Book book1;
					printf("请输入书号\n");
					rewind(stdin);           //rewind(stdin)清除标准输入的按键缓冲区。rewind函数是把指定流的读写指针重新指向开头 
					scanf("%s", &book1.num); 
					printf("请输入书名\n");
					rewind(stdin);
					scanf("%s", &book1.name);
					printf("请输入著作者\n");
					rewind(stdin);
					scanf("%s", &book1.writer);
					printf("请输入现存量\n");
					rewind(stdin);
					scanf("%d", &book1.xiancun);
					book1.kucun = book1.xiancun;
					InsertBook(&L, book1);
					printf("第%d次录入完成\n", i + 1);
				} 
				break;
			}	 
			case '2' : {
				Book book1;
				int i = 1;
				int k = 0; 
				do{
					printf("请输入你的书证号\n");
					rewind(stdin);
					scanf("%d", &B[k].peoplenumber);
					printf("请输入你想借阅书的书号\n");
					rewind(stdin);
					scanf("%s", &book1.num);
					printf("请输入你的归还日期\n");
					rewind(stdin);
					scanf("%d %d", &B[k].month, &B[k].date);
					k++; 
					printf("是否继续添加,请输入1 or 0\n");
					rewind(stdin);
					scanf("%d", &i);
					LendBook(&L, book1);
					m = k;
				}while(i);
				printf("借阅成功\n"); 
				break;
			}
			case '3' : {
					Book book1;
					int ShuZhengHao;
					int i;
					char SH[10];
					printf("请输入你的书证号\n");
					scanf("%d", &ShuZhengHao);
					printf("请输入你借阅书的书号\n");
					scanf("%s", &book1.num);
					for(i = 0; i < m; i++){
						if(ShuZhengHao == B[i].peoplenumber){
							BackBook(&L, book1, B , i);
						}
					}
				break;
			}
			case '4' :{
				ShowBorrow(B,m); 
				printf("借书信息查询成功\n");
				break;
			}
			case '5':{
				Showbooks(&L);
				printf("图书信息查询成功\n");
				break;
			} 
			case '6':{
					Book book1;
					int i;
					printf("请输入书号\n");
					rewind(stdin);           //rewind(stdin)清除标准输入的按键缓冲区。rewind函数是把指定流的读写指针重新指向开头 
					scanf("%s", &book1.num); 
					printf("请输入增加量\n");
					rewind(stdin);
					scanf("%d", &i);
					AddBook(&L,book1,i);
					printf("添加成功\n"); 
				break;
			}  
			case '0' : {
				printf("退出系统成功\n");
				count = 0;
			}
			default : 
				printf("你输入的有误\n"); 
				break; 
		}
	
	}
	return 0;
}

rewind(stdin)函数作用[参照scanf缓冲区]
源程序:

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<stdlib.h>

typedef struct BookShelf{    //每一本书的声明 
	char num[10];   //书号 
	char name[10];   //书名 
	char writer[10];  //书作者 
	int xiancun;  //现存量 
	int kucun;  //库存量 
}Book;

typedef struct Lnode{    //链表的声明 
	Book data;
	struct Lnode *next;
}Lnode, *Linklist;

struct Browwer{    //借阅者信息 
	int peoplenumber;   //书证号 
	int month;    //月 
	int date;    //日 
}B[100];

void EmptyList(Linklist L){   //初始化链表 
	if(L->next == NULL)
		return;
	else
		L->next = NULL;
} 

void DeletePeople(Browwer B[], int b){   //删除借阅人信息 
		B[b].peoplenumber = 0;
		B[b].month = 0;
		B[b].date = 0; 
} 

Lnode *CreateNode(Book book1){      //创建一个结点 
	Lnode *pnext = (Lnode *)malloc(sizeof(Lnode));   //malloc申请结点指针空间 
	strcpy(pnext->data.num, book1.num);   //book1的数据赋值给结点 
	strcpy(pnext->data.name, book1.name);
	strcpy(pnext->data.writer, book1.writer);
	pnext->data.xiancun = book1.xiancun;
	pnext->data.kucun = book1.kucun;
	pnext->next = NULL;
	return pnext;
}

void InsertBook(Linklist L, Book book1){   //尾插法插入数据 
	Lnode *pnow = L;   //结点指针 
	while((pnow->next != NULL)){      // 当链表指针指向空时
		pnow = pnow->next;
	}             
	Lnode *pnext = CreateNode(book1);    //结点创建 
	pnow->next = pnext;        //链接链表 
}

void LendBook(Linklist L, Book book1){   //借书过程 
	int count = 1;
	Lnode *p = L->next;   //p是一个结点 
	while(count){
		if(!(strcmp(p->data.num,book1.num))){    //比较书的书号 
			p->data.xiancun = p->data.xiancun - 1;
			count = 0;
		}
		else if(p->next==NULL){
			printf("书本信息错误\n");
			count = 0;
		}
		else
			p=p->next;
	}
}

void BackBook(Linklist L, Book book1, Browwer B[], int i){   //还书过程 
	int count = 1;
	Lnode *p = L->next;
	while(count){
		if(!(strcmp(p->data.num,book1.num))){
			p->data.xiancun = p->data.xiancun + 1;
			count = 0;
			DeletePeople(B, i); 
		}
		else if(p->next==NULL){
			printf("书本信息错误\n");
			count = 0;
		}
		else
			p=p->next;
	}
}

void Showbooks(Linklist L){   //显示图书信息 
	Lnode *p = L->next;
	while(p != NULL){
		printf("书本书号%s\n", p->data.num);
		printf("%s书本书名%s\n", p->data.num, p->data.name);
		printf("%s书本著作者%s\n", p->data.num, p->data.writer);
		printf("%s书本现存量%d\n", p->data.num, p->data.xiancun);
		printf("%s书本库存量%d\n", p->data.num,p->data.kucun);
		p = p->next;
	}
} 

void ShowBorrow(Browwer B[], int a){   //借书信息 
	for(int i = 0; i < a; i++){
		printf("借阅者书证号:%d\n", B[i].peoplenumber);
		printf("还书日期:%d月%d号\n", B[i].month, B[i].date);
	}
}

void AddBook(Linklist L, Book book1,int i){   //库存增加书过程 
	int count = 1;
	Lnode *p = L->next;
	while(count){
		if(!(strcmp(p->data.num,book1.num))){
			p->data.kucun = p->data.kucun + i;
			count = 0; 
		} 
	}
}

int main(){
	Linklist *head;
	Lnode L;
	EmptyList(&L);
	char choice;
	int count = 1;
	int m;
	int number;
	while(count){
		printf("+++++++++++++++图书管理系统+++++++++++\n");
    	printf("+------------------------------------+\n");
		printf("+(请按相应的数字键选择您所需要的操作)+\n");
		printf("+------------------------------------+\n");
		printf("+ 1.图书入库            2.借阅   +\n");
		printf("+ 3.归还                4.借阅者信息  +\n");
		printf("+ 5.显示图书            0.退出   +\n");
		printf("+ 6.库存里增加图书\n");
		rewind(stdin);
		scanf("%c", &choice);
		switch(choice) {
			case '1' : {
				printf("你想输入多少种类书籍\n");
				scanf("%d", &number);
				for(int i = 0; i < number; i++){
					Book book1;
					printf("请输入书号\n");
					rewind(stdin);           //rewind(stdin)清除标准输入的按键缓冲区。rewind函数是把指定流的读写指针重新指向开头 
					scanf("%s", &book1.num); 
					printf("请输入书名\n");
					rewind(stdin);
					scanf("%s", &book1.name);
					printf("请输入著作者\n");
					rewind(stdin);
					scanf("%s", &book1.writer);
					printf("请输入现存量\n");
					rewind(stdin);
					scanf("%d", &book1.xiancun);
					book1.kucun = book1.xiancun;
					InsertBook(&L, book1);
					printf("第%d次录入完成\n", i + 1);
				} 
				break;
			}	 
			case '2' : {
				Book book1;
				int i = 1;
				int k = 0; 
				do{
					printf("请输入你的书证号\n");
					rewind(stdin);
					scanf("%d", &B[k].peoplenumber);
					printf("请输入你想借阅书的书号\n");
					rewind(stdin);
					scanf("%s", &book1.num);
					printf("请输入你的归还日期\n");
					rewind(stdin);
					scanf("%d %d", &B[k].month, &B[k].date);
					k++; 
					printf("是否继续添加,请输入1 or 0\n");
					rewind(stdin);
					scanf("%d", &i);
					LendBook(&L, book1);
					m = k;
				}while(i);
				printf("借阅成功\n"); 
				break;
			}
			case '3' : {
					Book book1;
					int ShuZhengHao;
					int i;
					char SH[10];
					printf("请输入你的书证号\n");
					scanf("%d", &ShuZhengHao);
					printf("请输入你借阅书的书号\n");
					scanf("%s", &book1.num);
					for(i = 0; i < m; i++){
						if(ShuZhengHao == B[i].peoplenumber){
							BackBook(&L, book1, B , i);
						}
					}
				break;
			}
			case '4' :{
				ShowBorrow(B,m); 
				printf("借书信息查询成功\n");
				break;
			}
			case '5':{
				Showbooks(&L);
				printf("图书信息查询成功\n");
				break;
			} 
			case '6':{
					Book book1;
					int i;
					printf("请输入书号\n");
					rewind(stdin);           //rewind(stdin)清除标准输入的按键缓冲区。rewind函数是把指定流的读写指针重新指向开头 
					scanf("%s", &book1.num); 
					printf("请输入增加量\n");
					rewind(stdin);
					scanf("%d", &i);
					AddBook(&L,book1,i);
					printf("添加成功\n"); 
				break;
			}  
			case '0' : {
				printf("退出系统成功\n");
				count = 0;
			}
			default : 
				printf("你输入的有误\n"); 
				break; 
		}
	
	}
	return 0;
}
 

总结
代码中存在很多问题,希望能与各位大佬多多交流。

  • 24
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

望北i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值