目录
技术路线
数据结构、哈希表、文件IO
通过C语言进行程序设计,有用到数据结构中的哈希表,通过哈希表对图书进行有规则地存放,并且使用文件IO的操作实现对图书馆中各种图书信息的更改。系统分为分有一个主界面和多个子界面,实现后的效果可以界面切换自如,子界面中设计有学生入口以及管理员入口,管理员入口的进入需要输入账号密码,这些功能都是结合实际设计的,实现的功能有,在管理员端可以实现对图书的入库、出库、图书的查询(编号查询、书名查询),其实就是对图书信息文件的读写操作,只需要定时更新数据即可,另外,在学生用户入口,该工程实现了借书系统和还书系统。
实现效果展示
每次的进入,都会实时显示共有的藏书和已经借出的书,在设计的时候,每经过一次管理员或者学生的操作,都会实时更新图书馆数据的.txt文件,进行重新写入,所以能做到实时性。
关于哈希表,哈希函数的设计,本项目是通过书本的编号,进行对书本编号值的不同,经由哈希函数处理,然后所得下标作为对应的在哈希表中的位置。
进行数据的查询,实际上是做了一种对图书馆图书数据文件的读取,然后进行一个匹配的过程
程序主体
头文件部分
#ifndef _LIBRARY_H
#define _LIBRARY_H
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#define N 26 //哈希表中所要创建的指针数组大小
enum res
{
HASHNULL = -4,
MALLOCERROR,
FAIL,
FLAG,
OK,
};
//定义一个学生信息结构体(借书)
typedef struct Stu
{
char name[30];//学生姓名
int ID; //学生学号
char data[30]; //借出的时间
}stu;
//书籍借出时间如果能直接调用系统时间自然是最好的。(这个是我努力优化的方向)
//定义一个图书信息结构体
typedef struct Book
{
char number[20];//编号也是和书的信息相关,如A13-1-2022,哈希检索时用的是这个第一个字母的阿斯克码值
char name[30];//书名
char place[30];//固定格式,如:A区13号书架上层
stu state; //用学生信息定义状态说明,有信息表已借出,无信息表示未借出
}data_type;
//哈希表的节点
typedef struct Linknode
{
data_type book;
struct Linknode *pnext;
}lknode;
//哈希表构成
typedef struct Hash
{
lknode *arr[N];
int count;
}hash;
hash *createHash();
int hashfun(char *number);
int insertBook(hash *phash,data_type item);
int deleteBook(hash *phash,char *bknumber);
void showInformation(lknode *pnode);
int searchbook1(hash *phash,char *bkname);
int searchbook2(hash *phash,char *bknumber);
stu change_data(lknode *ptemp);
int borrow_book(hash *phash,char *bkname);
int return_book(hash *phash,char *bknumber);
int destoryHash(hash **phash);
void show_bknumber(hash *phash);
int developer_information();
int load(hash *phash);
int update(hash *phash);
int interface1(hash *phash);
int interface2(hash *phash);
int judge(int id);
#endif
自定义函数定义部分
此处将所有的自定义函数都放一块了
#include"../include/library.h"
//创建哈希表
//创建一个哈希表数据类型的指针,并通过malloc开辟空间
hash *createHash()
{
hash *phash = NULL;
phash = (hash *)malloc(sizeof(hash));
if(NULL == phash)
{
perror("malloc error");
return NULL;
}
memset(phash,0,sizeof(hash));//哈希表初始化
return phash;
}
//定义哈希表规则
int hashfun(char *number)
{
int a = number[0];
return a-65;
}
//图书入库,向哈希表填入元素
int insertBook(hash *phash,data_type item)
{
if(NULL == phash)
{
return HASHNULL;
}
int index = hashfun(item.number);//通过哈希函数获得存储下标
//创建存储图书信息的链表节点
lknode *pnew = (lknode*)malloc(sizeof(lknode));
if(NULL == pnew)
{
perror("malloc error");
return MALLOCERROR;
}
memset(pnew,0,sizeof(pnew));
pnew->book = item;//结构体变量的直接赋值
//将新增的图书信息节点插入链表,先保障后面不丢失
pnew->pnext = phash->arr[index];//头插法
phash->arr[index] = pnew;
phash->count++; //插入一本图书后,库里的图书总数加一
return OK;
}
//书籍出库(删除书),通过书的编号给书办理出库
int deleteBook(hash *phash,char *bknumber)
{
if(NULL == phash)
{
return HASHNULL;
}
int pos = hashfun(bknumber);
//头节点这有点特殊,单独拿出来判断了
lknode *phead = phash->arr[pos];
if(0 == strcmp(phead->book.number,bknumber))
{
phash->arr[pos] = phead->pnext;
return OK;
}
int i;
lknode *ptemp;
for(i = 0;i < N;i++)
{
ptemp = phash->arr[i];
while(NULL != ptemp)
{
if(0 == strcmp(ptemp->pnext->book.number,bknumber))//ptemp只定位到要删除节点的前一个
{
lknode *pnew_temp = ptemp->pnext;//新定义的这个指针指向要删除的节点处
ptemp->pnext = pnew_temp->pnext;
free(pnew_temp);
phash->count--;
return OK;
}
ptemp = ptemp->pnext;
}
}
printf("所要删除书籍不存在");
return FAIL;
}
//图书查询,显示哈希表某一节点的信息(也就是某一本书的信息),要借书你肯定是要查位置的
//通过书名找书
int searchbook1(hash *phash,char *bkname)
{
if(NULL == phash)
{
return HASHNULL;
}
int i;
lknode *ptemp;
//以下程序是遍历哈希表
for(i = 0;i < N;i++)
{
ptemp = phash->arr[i];
while(NULL != ptemp)//最后一个尾节点也是一本书,也得判断进去
{
printf("%s\n",bkname);
if(0 == strcmp(ptemp->book.name,bkname))
{
showInformation(ptemp);
return OK;
}
ptemp = ptemp->pnext;
}
}
//在经历了上一个遍历判断后没找见的话说明就没有这本书
printf("图书馆没有这本书\n");
return FAIL;
}
//通过书籍编号查找
int searchbook2(hash *phash,char *bknumber)
{
if(NULL == phash)
{
return HASHNULL;
}
int i;
lknode *ptemp;
for(i = 0;i < N;i++)
{
ptemp = phash->arr[i];
while(NULL != ptemp)//最后一个尾节点也是一本书,也得判断进去
{
if(0 == strcmp(ptemp->book.number,bknumber))
{
showInformation(ptemp);
return OK;
}
ptemp = ptemp->pnext;
}
}
//在经历了上一个遍历判断后没找见的话说明就没有这本书
printf("图书馆没有这本书\n");
return FAIL;
}
//打印节点信息,也就是显示一本书的信息
void showInformation(lknode *pnode)
{
printf("书名:%s\n",pnode->book.name);
printf("书籍编号:%s\n",pnode->book.number);
printf("存放位置:%s\n",pnode->book.place);
if(0 == pnode->book.state.ID)
{
printf("书籍未借出\n");
}
else
{
printf("书籍已出借\n");
printf("出借人:%s\n",pnode->book.state.name);
printf("出借人学号:%d\n",pnode->book.state.ID);
printf("出借时间:%s\n",pnode->book.state.data);
}
}
//借书函数
int borrow_book(hash *phash,char *bkname)
{
if(NULL == phash)
{
return HASHNULL;
}
int i;
lknode *ptemp;
//以下程序是遍历哈希表
for(i = 0;i < N;i++)
{
ptemp = phash->arr[i];
while(NULL != ptemp)//最后一个尾节点也是一本书,也得判断进去
{
if(0 == strcmp(ptemp->book.name,bkname))
{
ptemp->book.state = change_data(ptemp);
return OK;
}
ptemp = ptemp->pnext;
}
}
printf("图书馆中没有这本书\n");
return FAIL;
}
//借书时改变一个节点的数据,写入借阅者信息
//传入的参数是一个节点
stu change_data(lknode *ptemp)
{
stu student;
memset(&student,0,sizeof(stu));
printf("--------------信息登记--------------\n");
printf("姓名:");
scanf("%s",student.name);
printf("学号:");
scanf("%d",&student.ID);
printf("借阅时间:");
scanf("%s",student.data);
return student;
}
//还书函数
//通过书籍编号先找到
int return_book(hash *phash,char *bknumber)
{
if(NULL == phash)
{
return HASHNULL;
}
int i;
lknode *ptemp;
for(i = 0;i < N;i++)
{
ptemp = phash->arr[i];
while(NULL != ptemp)//最后一个尾节点也是一本书,也得判断进去
{
if(0 == strcmp(ptemp->book.number,bknumber))
{
memset(&(ptemp->book.state),0,sizeof(stu));
printf("还书成功");
return OK;
}
ptemp = ptemp->pnext;
}
}
printf("未匹配到书籍信息,请检查是否输入有误\n");
return FAIL;
}
//释放哈希表
int destoryHash(hash **phash)
{
if(NULL == *phash)
{
return HASHNULL;
}
lknode *ptemp1 = NULL;
lknode *ptemp2 = NULL;
int i;
for(i = 0; i < N; i++)
{
ptemp1 = ptemp2 = (*phash)->arr[i];
while(NULL != ptemp2)
{
ptemp1 = ptemp1->pnext;
free(ptemp2);
ptemp2 = ptemp1;
}
}
free(*phash);
*phash = NULL;
return OK;
}
//---------------------------------------以下是主函数界面下的一些函数封装--------------------------------------------
//--------------------------------------包括,导入库,导出库,操作界面函数-------------------------------------------
//每次开启之前你要做图书信息库的导入
int load(hash *phash)
{
data_type bookdata;//文件IO操作时用作缓存
int fo = open("library.txt",O_RDONLY | O_CREAT ,0664);//打开数据库文件,不存在就创建
if(fo < 0)
{
perror("open error");
return FAIL;
}
else
{
while(1)
{
int fr = read(fo,&bookdata,sizeof(data_type));
if(0 == fr)
{
break;
}
else if(fr < 0)
{
perror("read error");
return FAIL;
}
else
{
insertBook(phash,bookdata);
}
}
}
close(fo);//图书数据导入完后关闭程序
return OK;
}
//操作结束后的图书馆数据库更新
int update(hash *phash)
{
int fo = open("library.txt",O_WRONLY);
if(fo < 0)
{
perror("open error");
}
else
{
int i;
for(i = 0; i < N; i++)
{
lknode *ptemp = phash->arr[i];
while(NULL != ptemp)
{
int fw = write(fo,&(ptemp->book),sizeof(data_type));
if(fw < 0)
{
perror("write error");
}
ptemp = ptemp->pnext;
}
}
}
return OK;
}
//管理员界面的子函数,通过主界面调用该函数,主界面函数放在了主函数里
int interface1(hash *phash)
{
int op,op2;
data_type item;
memset(&item,0,sizeof(data_type));
char bknumber[30]="\0";
int flag = 0;
system("clear");
while(1)
{
system("clear");
printf("------------管理员用户模式------------\n\n");
printf("(1)图书入库登记\n\n");
printf("(2)图书出库删除\n\n");
printf("(3)返回\n");
scanf("%d",&op);
switch(op)
{
case(1):
printf("请输入图书编号(格式如A13-1-2002):");
scanf("%s",item.number);
printf("请输入书籍名称:");
scanf("%s",item.name);
printf("请输入图书存放位置:");
scanf("%s",item.place);
flag = insertBook(phash,item);
if(OK == flag)
{
printf("--------------入库成功--------------\n");
}
else
{
printf("--------------入库失败--------------\n");
}
printf("press 1 continue\n");
place1:
scanf("%d",&op2);
if(1 == op2)
{
break;
}
else
{
goto place1;
}
case(2):
printf("请输入出库图书编号:");
scanf("%s",bknumber);
flag = deleteBook(phash,bknumber);
if(OK == flag)
{
printf("--------------出库成功--------------\n");
}
else
{
printf("--------------出库失败--------------\n");
}
printf("press 1 continue\n");
place2:
scanf("%d",&op2);
if(1 == op2)
{
break;
}
else
{
goto place2;
}
case(3):
return FLAG;
}
}
return OK;
}
//学生用户界面的子函数,通过主界面调用该函数,主界面函数放在了主函数里
int interface2(hash *phash)
{
int op,op2;
char bknumber[30]="\0";
char bkname[30]="\0";
int flag = 0;
system("clear");
while(1)
{
system("clear");
printf("------------学生用户模式----------------\n\n");
printf("(1)书籍查询(书名查询)\n\n");
printf("(2)书籍查询(编号查询)\n\n");
printf("(3)借书\n\n");
printf("(4)还书\n\n");
printf("(5)返回\n");
scanf("%d",&op);
switch(op)
{
case(1):
printf("请输入你要查询的书名:");
scanf("%s",bkname);
flag = searchbook1(phash,bkname);
if(OK == flag)
{
printf("--------------查询成功--------------\n");
}
else
{
printf("--------------查询失败--------------\n");
}
printf("press 1 continue\n");
place3:
scanf("%d",&op2);
if(1 == op2)
{
break;
}
else
{
goto place3;
}
case(2):
printf("请输入你要查询的书籍编号:");
scanf("%s",bknumber);
flag = searchbook2(phash,bknumber);
if(OK == flag)
{
printf("--------------查询成功--------------\n");
}
else
{
printf("--------------查询失败--------------\n");
}
printf("press 1 continue\n");
place4:
scanf("%d",&op2);
if(1 == op2)
{
break;
}
else
{
goto place4;
}
case(3):
printf("请输入要借阅的书名:");
scanf("%s",bkname);
system("clear");
flag = borrow_book(phash,bkname);
if(OK == flag)
{
printf("--------------借阅成功--------------\n");
}
else
{
printf("--------------借阅失败--------------\n");
}
printf("press 1 continue\n");
place5:
scanf("%d",&op2);
if(1 == op2)
{
break;
}
else
{
goto place5;
}
case(4):
printf("请输入归还书籍编号:");
scanf("%s",bknumber);
flag = return_book(phash,bknumber);
if(OK == flag)
{
printf("--------------归还成功--------------\n");
}
else
{
printf("--------------归还失败--------------\n");
}
printf("press 1 continue\n");
place6:
scanf("%d",&op2);
if(1 == op2)
{
break;
}
else
{
goto place6;
}
case(5):
return FLAG;
}
}
return OK;
}
//显示图书馆中藏书总量,以及借出总数
void show_bknumber(hash *phash)
{
printf("(馆内共有藏书%d本,",phash->count);
int i,num=0;
lknode *ptemp;
//以下程序是遍历哈希表
for(i = 0;i < N;i++)
{
ptemp = phash->arr[i];
while(NULL != ptemp)//最后一个尾节点也是一本书,也得判断进去
{
if(0 != ptemp->book.state.ID)
{
num++;
}
ptemp = ptemp->pnext;
}
}
printf("已借出%d本)\n",num);
}
//显示版本信息
int developer_information()
{
int op;
system("clear");
printf("版本号:图书管理系统1.0\n\n");
printf("开发者:22041吴泽翔\n\n");
printf("地址:华清远见西安中心\n\n");
printf("联系方式:0914-2338030\n\n");
printf("\t\t按1返回\n");
scanf("%d",&op);
if(1 == op)
{
return FLAG;
}
else
{
return FAIL;
}
}
//输入密码判断是否可进入管理员模式
int judge(int id)
{
int mima = 0;
int op;
begin:
system("clear");
printf("密码:");
scanf("%d",&mima);
if(id == mima)
{
return OK;
}
else
{
printf("密码有误\n");
printf("\n");
}
printf("重输请按1,返回上一级请按2\n");
printf("请输入你的选择:");
mid:
scanf("%d",&op);
if(1 == op)
{
goto begin;
}
else if(2 == op)
{
return FLAG;
}
else
{
printf("输入有误,请重新输入:");
goto mid;
}
}
/*
//--------------------------------------------进入管理员界面的密码设计------------------------------------------------//
//---------------------------------用到了密码本的导入,可以修改密码,更新密码本--------------------------------------//-
//----------------------------------------------该功能尚未实现完成---------------------------------------------------//
//每次开启之前进行账号密码的导入
int loadPassword(id pw)
{
int fo = open("password.txt",O_RDONLY | O_CREAT ,0664);//打开数据文件,不存在就创建
if(fo < 0)
{
perror("open error");
return FAIL;
}
else
{
int fr = read(fo,&pw,sizeof(id));
if(fr < 0)
{
perror("read error");
return FAIL;
}
}
close(fo);
return OK;
}
//操作结束后的密码数据库更新
int updatePassword(id pw)
{
int fo = open("password.txt",O_WRONLY);
if(fo < 0)
{
perror("open error");
return FAIL;
}
else
{
int fw = write(fo,&pw,sizeof(id));
if(fw < 0)
{
perror("write error");
return FAIL;
}
}
return OK;
}
int judge()
{
int mima = 0;
int op;
begin:
system("clear");
printf("密码:");
scanf("%d",&mima);
if(password == mima)
{
return OK;
}
else
{
printf("密码有误\n");
printf("\n");
}
printf("重输请按1,返回上一级请按2\n");
printf("请输入你的选择:");
mid:
scanf("%d",&op);
if(1 == op)
{
goto begin;
}
else if(2 == op)
{
return FLAG;
}
else
{
printf("输入有误,请重新输入:");
goto mid;
}
}
*/
main函数部分
#include"../include/library.h"
int main()
{
hash *phash = createHash();//创建哈希表
load(phash);//每次开启之前你要做图书信息库的导入
int id = 123;//设定管理员模式的密码
int op;
int flag;
while(1)
{
start:
system("clear");
system("date");
printf("\n");
printf("欢迎使用图书管理系统");
show_bknumber(phash);
printf("\n");
printf("(1)管理员用户入口\n\n");
printf("(2)学生用户入口\n\n");
printf("(3)版本信息\n\n");
printf("(4)退出系统\n\n");
scanf("%d",&op);
if(4 == op)
{
break;
}
switch(op)
{
case(1):
flag = judge(id);
if(flag == FLAG)
{
goto start;
}
flag = interface1(phash);
if(flag == FLAG)
{
goto start;
}
break;
case(2):
flag = interface2(phash);
if(flag == FLAG)
{
goto start;
}
break;
case(3):
flag = developer_information();
if(flag == FLAG)
{
goto start;
}
break;
}
}
update(phash);//操作结束后,更新图书库的信息
destoryHash(&phash);//销毁哈希表
return 0;
}
注意
该工程是在linux环境下编写的,部分函数可能windows下没有,倘若你是windows环境,该文档仅供参考。
另:若使用者需运行该程序,仍需自己新建工程,配置合适的Makefile文件,进行工程文件的运行
希望这篇文章能够给你提供帮助,如有问题,还请指出,我会及时更改,谢谢大家。
本文含有隐藏内容,请 开通VIP 后查看