图书馆管理系统(C、数据结构、哈希表、文件IO)

发布于:2023-02-06 ⋅ 阅读:(655) ⋅ 点赞:(0)

目录

技术路线

实现效果展示

​程序主体

 1.头文件部分

 2.自定义函数定义部分

 3.main函数部分

注意


技术路线

数据结构、哈希表、文件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 后查看