武汉理工大学C语言实验图书馆系统——追求卓越
实验内容
实验要求我就不说了老师应该都给你们说的很清楚了(其实是我忘了)
由于本次实验是组队编程,所以你们要cv也记得考虑接口的问题。
开发环境
macOS 10.14 Xcode
使用bug 10的各位同学直接运行可能会出一点小问题。
建议将代码导入工程阅读,体现代码结构
说明
以下代码均由我一人完成,代码除了相应的文字显示外没有实现任何功能,只是设计出了整个系统的整体框架,以及所有接口的预留;接口的统一便于团队后续的功能实现。这篇文章的目的是给不知道从何开始编写的同学们一个参考,而不是直接cv之后就可以交。(所以说为什么叫追求卓越)(这个工程绝对是我这辈子写过的注释最多的一个)(乐)
代码
源文件
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Welcome.h"
#include "global.h"
int main()
{
FILE* fp = NULL;
Librarians boss;
char pwd[8] = { "boot" };
fp = fopen(ppPathReaderLib, "rb");
if (fp == NULL)
{
fp = fopen(ppPathReaderLib, "wb");
if (fp == NULL)
{
printf("error");
return 0;
}
boss.Level = 0;
boss.LibrarianID = 000;
strcpy(boss.LibrarianPwd, pwd);
boss.nDel = 0;
fwrite(&boss, sizeof(Librarians), 1, fp);
fclose(fp);
}
else fclose(fp);
welcome();
Login();
return 0;
}
Welcome.c
#include "Welcome.h"
#include "global.h"
/**
读者端菜单选择
此处将登陆时的读者结构体传递过来,便于读者信息的输出
*/
void ReaderMenu(Readers* reader)
{
int menuNum;
OutputReaderMenu();
do
{
puts("请输入菜单编号");
printf(">");
scanf("%d", &menuNum);
switch (menuNum)
{
case 1:
// insert code here...
// 读者信息
OutputReaderInfo(reader);
break;
case 2:
// insert code here...
// 已借书目
OutputBorrowedInfo(reader);
break;
case 3:
// insert code here...
// 查询图书
InquireBook();
break;
case 4:
// insert code here...
// 借阅归还图书
Borrow_ReturnBook(reader);
break;
case 0:
// insert code here...
//退出
puts("----------退出----------");
break;
default:
// insert code here...
puts("非法输入!");
break;
}
} while (menuNum);
}
/**
管理员端菜单选择
此处将登陆时的管理员结构体传递过来,便于读者信息的输出
注意!!!!!!!!!!!!
在视频中没有给出管理员相关功能函数的存放位置,所以我新建了一个视频中没有的 Librarian.c 文件及其头文件,
并将管理员相关操作放入其中
*/
void LibrarianMenu(Librarians* librarian)
{
int menuNum;
OutputLibMenu();
do
{
puts("请输入菜单编号");
printf(">");
scanf("%d", &menuNum);
switch (menuNum)
{
case 1:
// insert code here...
// 管理员信息
OutputLibInfo(librarian);
break;
case 2:
// insert code here...
// 读者管理
ManageReader(librarian);
break;
case 3:
// insert code here...
// 图书管理
ManageBook(librarian);
break;
case 4:
// insert code here...
// 管理员管理
ManageLib(librarian);
break;
case 0:
// insert code here...
//退出
puts("----------退出----------");
break;
default:
// insert code here...
puts("非法输入!");
break;
}
} while (menuNum);
}
/**
此函数功能为输出一段欢迎语,系统启动时调用此函数
*/
void welcome(void)
{
puts("Welcome to the Library Manager System!");
}
/**
输出读者端菜单
*/
void OutputReaderMenu(void)
{
puts("读者端");
puts("----------菜单----------");
puts("1.读者信息");
puts("2.已借书目");
puts("3.查询图书");
puts("4.借阅图书");
puts("0.退出\n");
}
/**
输出读者查询图书相应功能
*/
void InquireBookMenu(void)
{
puts("1.按图书名查询");
puts("2.按图书编号查询");
puts("0.返回上一级");
}
void InquireBookMENU(void)
{
puts("1.按书名");
puts("2.按编号");
}
/**
输出读者借阅图书相应功能
*/
void ReaderBorrowMenu(void)
{
puts("1.借阅");
puts("2.归还");
puts("0.返回上一级");
}
/**
输出管理员端顶层菜单
*/
void OutputLibMenu(void)
{
puts("管理员端");
puts("----------菜单----------");
puts("1.管理员信息");
puts("2.读者管理");
puts("3.图书管理");
puts("4.管理员管理");
puts("0.退出\n");
}
/**
输出读者管理相应菜单
*/
void ManageReaderMenu(void)
{
puts("1.读者查询");
puts("2.读者删除");
puts("3.读者修改");
puts("4.读者添加");
puts("0.返回上一级");
}
/**
输出图书管理相应菜单
*/
void ManageBookMenu(void)
{
puts("1.图书查询");
puts("2.图书删除");
puts("3.图书修改");
puts("4.图书添加");
puts("0.返回上一级");
}
/**
输出管理员管理相应菜单
*/
void ManageLibMenu(void)
{
puts("1.管理员查询");
puts("2.管理员删除");
puts("3.管理员修改");
puts("4.管理员添加");
puts("0.返回上一级");
}
Login.c
/**
登录模块
在菜单中直接调用的是 void Login(void) 函数
登录模块分为两部分,分别为读者登录和管理员登录;
读者登录调用 ReaderLogon 函数,管理员登录调用 LibrarianLogon 函数;
两个函数内部实现的逻辑应类似
*/
#include "Login.h"
#include "global.h"
/**
登录函数用户层,用于判断是读者登录还是管理员登录
*/
void Login(void)
{
int log = 3;
int IDnum = 0;
while (log != 0)
{
printf("读者登录请输入1,管理员登录请输入2,退出系统请输入0.\n");
printf(">");
scanf("%d", &log);
switch (log)
{
case 0:
printf("----------退出系统----------\n");
break;
case 1:
printf("请输入ID:\n>");
scanf("%d", &IDnum);
ReaderLogin(InquireReaderByID(IDnum));
// 此处调用按ID查询读者
break;
case 2:
printf("请输入ID:\n>");
scanf("%d", &IDnum);
LibrarianLogin(InquireLibByID(IDnum));
// 此处调用按ID查询管理员
break;
default:
printf("非法的输入!\n");
break;
}
}
}
/**
读者登录函数
*/
void ReaderLogin(Readers* reader)
{
char pwd[10];
printf("请输入密码:\n>");
scanf("%s", pwd);
if (reader != NULL)
{
if ((strcmp(pwd, reader->ReaderPwd) == 0)&&(reader->nDel==0))
{
printf("登录成功!\n");
// 这里可以输出一些相关信息,例如姓名,ID号,登录时间等
printf("读者ID:%d\n",reader->ReaderID);
// insert code here..
ReaderMenu(reader);
}
else
printf("ID号或者密码不正确!\n");
}
else
printf("ID号或者密码不正确!\n"); // 这里的输出也可以替换成 ”此卡号不存在“ 之类的,随意
}
/**
管理员登录函数
逻辑与读者登录函数类似
*/
void LibrarianLogin(Librarians* librarian)
{
char pwd[10];
printf("请输入密码:\n>");
scanf("%s", pwd);
if (librarian != NULL)
{
if (strcmp(pwd, librarian->LibrarianPwd) == 0)
{
printf("登录成功!\n");
// 这里可以输出一些相关信息,例如姓名,ID号,管理员等级,登录时间等
// insert code here..
LibrarianMenu(librarian);
}
else
printf("ID号或者密码不正确!\n");
}
else
printf("ID号或者密码不正确!\n"); // 这里的输出也可以替换成 ”此卡号不存在“ 之类的,随意
}
Reader.c
/**
读者管理模块
*/
#include "Reader.h"
#include "global.h"
#include<string.h>
#include "Reader.h"
int temp = 0;
int* nIndex = &temp;
/**
此函数用于输出登陆的读者信息(已借阅书籍除外,因为这是另外一个函数的功能)
外部会将登陆的读者结构体传递进此函数
*/
void OutputReaderInfo(Readers* reader)
{
printf("读者ID:%3d\n", reader->ReaderID);
printf("读者密码:%s\n", reader->ReaderPwd);
printf("读者状态:%d\n", reader->nDel);
}
/**
此函数用于输出已登陆读者的已借阅书目
*/
void OutputBorrowedInfo(Readers* reader)
{
int n = 0;
for (int i = 0; i < 6; i++)
if (reader->BorrowedBook[i].BookNum >= 0)
n++;
if (n == 0)
{printf("未借阅图书\n"); return;}
else
{for (int i = 0; i < n; i++)
{
printf("借阅书目:\n");
printf("图书名:%s\n", reader->BorrowedBook[i].BookName);
printf("作者:%s\n", reader->BorrowedBook[i].Author);
printf("图书编号:%d\n\n", reader->BorrowedBook[i].BookNum);
}
}
}
/**
删除读者函数
此函数由管理员模块调用
先进行管理员等级的判断,再进行读者的删除
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
需用到读者查询函数 void InquireReader(Librarians* librarian)
*/
void DeleteReader(Librarians* librarian)
{
int pId = 0;
int result = 0;
Readers* pReader = NULL;
int index = 0;
if (librarian->Level == 1)
{
printf("权限不够!\n");
return;
}
printf("欢迎您,亲爱的管理员!\n");
printf("请输入需要删除的读者ID:");
scanf_s("%d", &pId);
pReader = InquireReaderByID(pId);
if (pReader == NULL)
{
printf("此读者不存在!\n");
return;
}
pReader->nDel = 1;
checkReader(pReader->ReaderID, pReader->ReaderPwd);
result = updateReader(pReader, temp);
if (result == false)
{
printf("删除失败!\n");
return;
}
printf("删除成功!\n");
return;
}
/**
修改读者函数
此函数由管理员模块调用
先进行管理员等级的判断,再进行读者的修改
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
需用到读者查询函数 void InquireReader(Librarians* librarian)
*/
void ReviseReader(Librarians* librarian)
{
int pId = 0;
int result = 0;
char newpPwd[10];
char aPwd[10] = {0};
Readers* pReader = NULL;
if (librarian->Level == 1)
{
printf("权限不够!\n");
return;
}
printf("欢迎您,亲爱的管理员!\n");
printf("请输入需要修改的读者ID:");
scanf_s("%d", &pId);
pReader = InquireReaderByID(pId);
if (pReader == NULL)
{
printf("此读者不存在!\n");
return;
}
printf("现如今只能修改密码,是否继续?:");
printf("是:1 否:2\n");
scanf("%d", &result);
if (result == 2)
return;
else
result = 0;
printf("请输入新密码:");
scanf("%s", aPwd);
strcpy(pReader->ReaderPwd, aPwd);
checkToUpdate(pReader->ReaderID);
result = updateReader(pReader, temp);
if (result == 0)
{
printf("修改失败!\n");
return;
}
printf("修改成功!\n");
return;
}
/**
添加读者函数
此函数由管理员模块调用
先进行管理员等级的判断,再进行读者的添加
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
需用到读者查询函数 void InquireReader(Librarians* librarian) 判断是否有重复卡号
*/
void AddReader(Librarians* librarian)
{
if (librarian->Level > 1)
return;
else {
Readers reader;
char password[10] = { 0 };
printf("请输入读者ID:");
scanf("%d", &reader.ReaderID);
if (InquireReaderByID(reader.ReaderID) != NULL)
{
printf("ID 已存在\n");
return;
}
int flag = 1;
while (flag) {
printf("请输入读者密码:");
scanf("%s", &password);
if (strlen(password) > 10)
{
printf("密码过长,输入无效\n");
}
else flag = 0;
}
strcpy(reader.ReaderPwd, password);
memset(reader.BorrowedBook, 0, sizeof(Books) * 6);
reader.nDel = 0;
saveReader(reader);
}
}
/*
保存读者信息到二进制文件
*/
void saveReader(Readers reader)
{
FILE* fp = NULL;
fp = fopen(pPathReader, "ab");
if (fp == 0)
{
fp = fopen(pPathReader, "wb");
if (fp == 0)
{
printf("打开文件错误\n");
return;
}
}
fwrite(&reader, sizeof(reader), 1, fp);
printf("添加成功!!\n书上有路,学海无涯,养成读书习惯,加油加油再加油哦!!!\n");
OutputReaderInfo(&reader);
fclose(fp);
}
/*
查找二进制文件中读者信息所在位置
*/
int checkReader(const int id, const char* pPwd)
{
Readers* preader = (Readers*)malloc(sizeof(Readers));
FILE* fp = NULL;
fp = fopen(pPathReader, "rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
return 0;
}
temp = 0;
while (!feof(fp))
{
if (fread(preader, sizeof(Readers), 1, fp) != 0)
{
temp++;
if (preader->ReaderID == id)
{
if (strcmp(preader->ReaderPwd, pPwd) == 0)
return temp;
}
}
}
free(preader);
}
/*
修改二进制文件中读者信息
*/
int updateReader(const Readers* preader, int nIndex)
{
FILE* fp = NULL;
int nline = 0;
long position = 0;
Readers reader;
fp = fopen(pPathReader, "rb+");
if (fp == NULL)
return 0;
while (!feof(fp) && nline < nIndex)
{
if (fread(&reader, sizeof(Readers), 1, fp) != 0) {
position = ftell(fp);
nline++;
}
}
fseek(fp, position, 0);
fwrite(preader, sizeof(Readers), 1, fp);
fclose(fp);
return 1;
}
void checkToUpdate(const int id)
{
Readers* preader = (Readers*)malloc(sizeof(Readers));
FILE* fp = NULL;
fp = fopen(pPathReader, "rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
return;
}
temp = 0;
while (!feof(fp))
{
if (fread(preader, sizeof(Readers), 1, fp) != 0)
{
temp++;
if (preader->ReaderID == id)
{
return;
}
}
}
free(preader);
}
Manager.c
/**
图书管理模块
*/
#include "global.h"
#include "Manager.h"
#include"Librarian_file.h"
/**
借阅函数
底层代码由你们编写,可以新建底层函数完成相应功能
此函数或者你创建的底层函数可以调用 Inquire.c 中的查询书籍函数
借阅成功时需要修改 reader -> BorrowedBook 数组中的变量,相应书籍的 Books -> BookQuantity,以及借阅信息结构体
并修改文件以及链表中信息
*/
void BorrowBook(Readers* reader)
{
char bookname[20] = { 0 };
char bookauthor[20] = { 0 };
int booknum = 0;
int i,num=0;
Borrow borrow;
//输入要借阅的图书名字及编号
printf("-----读者归还模块----\n");
printf("请输入图书名字及编号\n");
printf("图书名字:");
scanf("%s", bookname);
printf("作者名字:");
scanf("%s", bookauthor);
printf("图书编号:");
scanf("%d", &booknum);
//判断该图书是否存在
if ((InquireBookByNameNum(bookname, booknum)) == NULL)
{
printf("该书不存在\n");
return;
}
//判断该用户借书数目
for ( i = 0; i < 6; i++)
{
if ((reader->BorrowedBook[i].BookNum) >= 0)
{
num++;
}
}
if (0<num < 6)
{
strcpy(reader->BorrowedBook[num].BookName, bookname);
strcpy(reader->BorrowedBook[num].Author, bookauthor);
reader->BorrowedBook[num].BookNum = booknum;
reader->BorrowedBook[num].nDel = 1;
num = checkReader(reader->ReaderID,reader->ReaderPwd);
updateReader(reader,i);
borrow.p = reader;
borrow.BorrowDate = time_t(NULL);
num = checkBorrow(reader->ReaderID,reader->ReaderPwd);
if (InquireBorrow(reader->ReaderID, &i) == false)
saveBorrow(borrow);
else updateBorrow(&borrow, num);
printf("借书成功\n");
}
else printf("达到借书上限,无法借阅");
}
/**
归还函数
底层代码由你们编写,可以新建底层函数完成相应功能
此函数或者你创建的底层函数可以调用 Inquire.c 中的查询书籍函数
归还成功时需要修改 reader -> BorrowedBook 数组中的变量,相应书籍的 Books -> BookQuantity,以及借阅信息结构体
并修改文件以及链表中的信息
*/
void ReturnBook(Readers* reader)
{
// insert code here...
char bookname[20] = { 0 };
int booknum = 0;
int num;
Borrow borrow;
//输入要归还的图书名字及编号
printf("-----读者归还模块----\n");
printf("请输入图书名字及编号\n");
printf("图书名字:");
scanf("%s", bookname);
printf("图书编号:");
scanf("%d", &booknum);
//判断此卡是否被借出,如果被借出,进行归还
for (int i = 0; i < 6; i++)
{
if ((reader->BorrowedBook[i].BookNum) == booknum && strcmp(reader->BorrowedBook[i].BookName, bookname) == 0)
{
if (reader->BorrowedBook[i].nDel != 1)
{
printf("该图书未被借出,还书失败\n");
return;
}
reader->BorrowedBook[i].nDel = 0;
num = checkReader(reader->ReaderID, reader->ReaderPwd);
updateReader(reader, i);
borrow.p = reader;
borrow.ReturnDate = time_t(NULL);
num = checkBorrow(reader->ReaderID, reader->ReaderPwd);
updateBorrow(&borrow, num);
printf("归还成功\n");
return;
}
}
printf("未借阅该书\n");
/*判断此卡是否被借出
Books* book = NULL;
book = (Books*)malloc(sizeof(Books));
book = InquireBookByNameNum(bookname, booknum,reader);
if (book == NULL)
{
printf("图书不存在,还书失败\n");
return ;
}
if (book->nDel != 1)
{
printf("该图书未被借出,还书失败\n");
return;
}*/
}
/**
删除书籍函数
需先判断管理员等级,再判断是否存在此书籍
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
此函数或者你创建的底层函数可以调用 Inquire.c 中的查询书籍函数
*/
void DeleteBook(Librarians* librarian)
{
// insert code here...
}
// 注意!我的框架中将添加书籍的书目功能放在了修改书籍函数中
// 虽然有一个叫做 添加书籍 的函数,但我的理解为那个函数的功能是添加书籍名称,与 添加读者 类似,而不是改变某书籍的书目
/**
修改书籍函数
需先判断管理员等级,再判断是否存在此书籍
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
此函数或者你创建的底层函数可以调用 Inquire.c 中的查询书籍函数
*/
void ReviseBook(Librarians* librarian)
{
// insert code here...
}
/**
添加书籍函数
需先判断管理员等级,再判断是否存在相同书籍
注意,若两个书籍相同,需要书籍的书名,作者,以及出版社均相同
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
此函数或者你创建的底层函数可以调用 Inquire.c 中的查询书籍函数
*/
void AddBook(Librarians* librarian)
{
if (librarian->Level > 2)
{
printf("宁都不是管理员,在想什么?\n");
return;
}
Books* newbook = NULL;
int aBookNum = 0;
char aBookName[40] = {};
char aAuthor[10] = {};
int nDel = 0;
printf("请输入图书编号:");
scanf("%d",&aBookNum);
printf("请输入图书名:");
scanf("%s", aBookName);
printf("请输入作者:");
scanf("%s", aAuthor);
newbook = NumInquireBook(aBookNum);
if (newbook!=NULL)
{
printf("编号已存在\n");
return;
}
newbook = (Books*)malloc(sizeof(Books));
strcpy(newbook->Author, aAuthor);
newbook->BookNum = aBookNum;
newbook->nDel = nDel;
strcpy(newbook->BookName,aBookName);
if (saveBooks(newbook) == 0)
{
printf("添加失败\n");
return;
}
printf("添加成功!\n图书编号为:%d",aBookNum);
}
Librarian.c
/**
管理员管理模块
由于所有的管理员操作都要涉及管理员等级,所以所有管理员函数我都传入了登录的管理员结构体,方便等级的查询
*/
#include "Librarian.h"
#include "Librarian_file.h"
#include "global.h"
/**
此函数用于输出登陆的管理员信息
外部会将登陆的管理员结构体传递进此函数
*/
void OutputLibInfo(Librarians* librarian)
{
printf("登陆成功");
printf("your ID is:%d\nyou level is:%d\n", librarian->LibrarianID, librarian->Level);
// insert code here...
}
/**
此函数为管理读者的上层函数
会在此选择对读者的操作
外部会将登陆的管理员结构体传递进此函数
*/
void ManageReader(Librarians* librarian)
{
int menuNum;
ManageReaderMenu();
do
{
puts("请输入菜单编号");
printf(">");
scanf("%d", &menuNum);
switch (menuNum)
{
case 1:
// insert code here...
// 读者查询
InquireReader(librarian);
break;
case 2:
// insert code here...
// 读者删除
DeleteReader(librarian);
break;
case 3:
// insert code here...
// 读者修改
ReviseReader(librarian);
break;
case 4:
// insert code here...
// 读者添加
AddReader(librarian);
break;
case 0:
// insert code here...
// 返回上一级目录
OutputLibMenu();
break;
default:
// insert code here...
puts("非法输入!");
break;
}
} while (menuNum);
}
/**
此函数为管理书籍的上层函数
会在此选择对书籍的操作
外部会将登陆的管理员结构体传递进此函数
*/
void ManageBook(Librarians* librarian)
{
int menuNum;
ManageBookMenu();
do
{
puts("请输入菜单编号");
printf(">");
scanf("%d", &menuNum);
switch (menuNum)
{
case 1:
// insert code here...
// 图书查询
// 此处直接调用通用的 void InquireBook(void) 函数
// 这里就无需判断管理员等级了,随便来个读者都能干这事儿
InquireBook();
break;
case 2:
// insert code here...
// 图书删除
DeleteBook(librarian);
break;
case 3:
// insert code here...
// 图书修改
ReviseBook(librarian);
break;
case 4:
// insert code here...
// 图书添加
AddBook(librarian);
break;
case 0:
// insert code here...
// 返回上一级目录
OutputLibMenu();
break;
default:
// insert code here...
puts("非法输入!");
break;
}
} while (menuNum);
}
/**
此函数为管理管理员的上层函数
会在此选择对管理员的操作
外部会将登陆的管理员结构体传递进此函数
*/
void ManageLib(Librarians* librarian)
{
int menuNum;
ManageLibMenu();
do
{
puts("请输入菜单编号");
printf(">");
scanf("%d", &menuNum);
switch (menuNum)
{
case 1:
// insert code here...
// 管理员查询
InquireLibrarian(librarian);
break;
case 2:
// insert code here...
// 管理员删除
DeleteLibrarian(librarian);
break;
case 3:
// insert code here...
// 管理员修改
ReviseLibrarian(librarian);
break;
case 4:
// insert code here...
// 管理员添加
AddLibrarian(librarian);
break;
case 0:
// insert code here...
// 返回上一级目录
OutputLibMenu();
break;
default:
// insert code here...
puts("非法输入!");
break;
}
} while (menuNum);
}
/**
删除管理员函数
此函数由管理员模块调用
先进行管理员等级的判断,再进行管理员的删除
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
需用到管理员查询函数 void InquireLibrarian(Librarians* librarian)
*/
void DeleteLibrarian(Librarians* librarian)
{
// insert code here...
}
/**
修改管理员函数
此函数由管理员模块调用
先进行管理员等级的判断,再进行管理员的修改
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
需用到管理员查询函数 void InquireLibrarian(Librarians* librarian)
*/
void ReviseLibrarian(Librarians* librarian)
{
// insert code here...
}
/**
添加管理员函数
此函数由管理员模块调用
先进行管理员等级的判断,再进行管理员的添加
需修改相应的链表以及文件
底层代码由你们编写,可以新建底层函数完成相应功能
需用到管理员查询函数 void InquireLibrarian(Librarians* librarian) 判断是否有相同管理员
*/
void AddLibrarian(Librarians* librarian)
{
if (librarian->Level > 0)
{
printf("您的权限不够,努力升职吧!!!\n");
return;
}
Librarians* newLib = NULL;
int aID = 0;
//char aName[18] = {};
char aPwd[8] = {};
//int phoneNumber = 0;
printf("请输入需要添加的管理员的ID:");
scanf("%d", &aID);
//printf("请输入您的姓名");
//scanf("%s", aName);
printf("请输入新密码");
scanf("%s", aPwd);
//printf("请输入您的联系电话");
//scanf("%d", &phoneNumber);
newLib = InquireLibByID(aID);
if (newLib!= NULL)
{
printf("ID 已存在!");
return;
}
/* newLib = InquireLibByName(aName);
if (newLib != NULL)
{
printf("姓名已存在!");
return;
}*/
newLib=(Librarians*)malloc(sizeof(Librarians));//新的管理员
newLib->Level = 1;
newLib->LibrarianID = aID;
//strcpy(newLib->LibrarianName, aName);
strcpy(newLib->LibrarianPwd, aPwd);
newLib->nDel = 0;
//newLib->LibrarianPhoneNum = phoneNumber;
if (saveLibrarian(newLib) == 0)
{
printf("添加失败!");
return;
}
printf("添加成功!\n您的ID为:%3d\n您的等级为:1\n",aID);
// insert code here...
}
Librarian_file.c
#include"Librarian_file.h"
#include "global.h"
int saveLibrarian(const Librarians* lib)
{
FILE* fp = NULL;
fp = fopen(ppPathReaderLib, "ab");
if (fp == 0)
{
fp = fopen(ppPathReaderLib, "wb");
if (fp == 0)
{
printf("打开文件错误\n");
return 0;
}
}
fwrite(lib, sizeof(Librarians), 1, fp);
fclose(fp);
return 1;
}
int saveBooks(const Books* book)
{
FILE* fp = NULL;
fp = fopen(ppPathReaderBook, "ab");
if (fp == 0)
{
fp = fopen(ppPathReaderBook, "wb");
if (fp == 0)
{
printf("打开文件错误\n");
return 0;
}
}
fwrite(book, sizeof(Books), 1, fp);
fclose(fp);
return 1;
}
Borrow.c
/**
借阅模块
*/
#include "Borrow.h"
#include "global.h"
/**
借阅 / 归还上层函数
在此函数中选择借阅或者f归还
将已登陆读者结构体传入此函数,以便于对读者的已借阅书籍进行修改
*/
void Borrow_ReturnBook(Readers* reader)
{
int menu;
ReaderBorrowMenu();
do
{
printf(">");
scanf("%d", &menu);
switch (menu)
{
case 1:
// 借阅
BorrowBook(reader);
break;
case 2:
// 归还
ReturnBook(reader);
break;
case 0:
// 返回上一级目录
OutputReaderMenu();
break;
default:
puts("非法输入!");
break;
}
} while (menu);
}
/**
借阅函数
底层代码由你们编写,可以新建底层函数完成相应功能
此函数或者你创建的底层函数可以调用 Inquire.c 中的查询书籍函数
借阅成功时需要修改 reader -> BorrowedBook 数组中的变量,相应书籍的 Books -> BookQuantity,以及借阅信息结构体
并修改文件以及链表中信息
*/
/*void BorrowBook(Readers* reader)
{
// insert code here...
}*/
/**
归还函数
底层代码由你们编写,可以新建底层函数完成相应功能
此函数或者你创建的底层函数可以调用 Inquire.c 中的查询书籍函数
归还成功时需要修改 reader -> BorrowedBook 数组中的变量,相应书籍的 Books -> BookQuantity,以及借阅信息结构体
并修改文件以及链表中的信息
*/
/*void ReturnBook(Readers* reader)
{
// insert code here...
}*/
/*
保存读者信息到二进制文件
*/
void saveBorrow(Borrow borrow)
{
FILE* fp = NULL;
fp = fopen(BORROWPATH, "ab");
if (fp == 0)
{
fp = fopen(BORROWPATH, "wb");
if (fp == 0)
{
printf("打开文件错误\n");
return ;
}
}
fwrite(&borrow, sizeof(borrow), 1, fp);
fclose(fp);
}
/*
查找二进制文件中读者信息所在位置
*/
int checkBorrow(const int id, const char* pPwd)
{
Borrow* borrow = (Borrow*)malloc(sizeof(Borrow));
FILE* fp = NULL;
fp = fopen(BORROWPATH, "rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
return 0;
}
int temp = 0;
while (!feof(fp))
{
if (fread(borrow, sizeof(Borrow), 1, fp) != 0)
{
temp++;
if (borrow->p->ReaderID == id)
{
if (strcmp(borrow->p->ReaderPwd, pPwd) == 0)
return temp;
}
}
free(borrow);
}
}
int updateBorrow(const Borrow* pborrow, int nIndex)
{
FILE* fp = NULL;
int nline = 0;
long position = 0;
Borrow borrow;
fp = fopen(BORROWPATH, "rb+");
if (fp == NULL)
return 0;
while (!feof(fp) && nline < nIndex)
{
if (fread(&pborrow, sizeof(Borrow), 1, fp) != 0) {
position = ftell(fp);
nline++;
}
}
fseek(fp, position, 0);
fwrite(&pborrow, sizeof(borrow), 1, fp);
fclose(fp);
return 1;
}
Inquire.c
/**
查询模块
这个模块是一个偏底层的模块,因为其它所有功能几乎都需要进行查询
*/
#include"Inquire.h"
#include "global.h"
/**
读者查询上层函数
在此函数中进行判断,先判断管理员等级
然后判断是按ID查询还是按姓名查询,并调用相关函数
*/
void InquireReader(Librarians* librarian)
{
int readerID = 0;
Readers* theReader = NULL;
theReader = (Readers*)malloc(sizeof(Readers));
printf("请输入想要查找的读者ID:");
scanf("%d", &readerID);
theReader=InquireReaderByID(readerID);
if (theReader == NULL||theReader->nDel==1)
{
printf("查无此人\n");
free(theReader);
return;
}
printf("查找成功!\n");
OutputReaderInfo(theReader);
}
/**
管理查询上层函数
在此函数中进行判断,先判断管理员等级
然后判断是按ID查询还是按姓名查询,并调用相关函数
*/
void InquireLibrarian(Librarians* librarian)
{
// 内部逻辑我懒得写了,你自己写吧
// 我搭框架搭了一天了
// insert code here...
}
/**
按读者ID号对读者进行查询,若查询到相应读者,返回对应结构体指针;若未查询到,返回NULL
此处应在读者信息链表中进行查询
*/
Readers* InquireReaderByID(int readerID)
{
Readers* reader = NULL;
reader = (Readers*)malloc(sizeof(Readers));
if (reader == NULL)
{
printf("储存空间不足,查询失败(位置1)");
free(reader);
return NULL;
}
FILE* fp = NULL;
fp = fopen(pPathReader, "rb");
if (fp == NULL)
{
fp = fopen(pPathReader, "ab+");
if (fp == NULL) {
printf("打开文件失败!\n");
free(reader);
return NULL;
}
}
while (!feof(fp))
{
if (fread(reader, sizeof(Readers), 1, fp) != 0)
{
if (reader->ReaderID == readerID)
{
if (reader->nDel == 0)
return reader;
}
}
}
free(reader);
return NULL;
}
/**
按读者姓名对读者进行查询,若查询到相应读者,返回对应结构体指针;若未查询到,返回NULL
此处应在读者信息链表中进行查询
*/
Readers* InquireReaderByName(int readerName)
{
Readers* reader = NULL;
//insert code here...
return reader;
}
/**
按管理员ID对管理员进行查询
此函数要求与 Readers* InquireReaderByID(int readerID) 函数类似
*/
Librarians* InquireLibByID(const int libID)
{
Librarians* librarian =(Librarians*)malloc(sizeof(Librarians));
FILE* fp = NULL;
fp = fopen(ppPathReaderLib, "rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
return NULL;
}
while (!feof(fp))
{
if (fread(librarian, sizeof(Librarians), 1, fp) != 0)
{
if (librarian->LibrarianID == libID)
{
if (librarian->nDel == 0)
return librarian;
}
}
}
//insert code here...
free(librarian);
return NULL;
}
/**
按管理员姓名对管理员进行查询
此函数要求与 Readers* InquireReaderByName(int readerID) 函数类似
*/
/*Librarians* InquireLibByName(const char* libName)
{
Librarians* librarian = (Librarians*)malloc(sizeof(Librarians));
FILE* fp = NULL;
fp = fopen(ppPathReaderLib, "rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
free(librarian);
return NULL;
}
while (!feof(fp))
{
if (fread(librarian, sizeof(Librarians), 1, fp) != 0)
{
if (strcmp(librarian->LibrarianName, libName) == 0)
{
return librarian;
}
}
}
free(librarian);
return NULL;
}*/
/**
查询图书顶层函数
*/
void InquireBook(void)
{
int menu,num;
char bookname[10] = {};
Books* abook=(Books*)malloc(sizeof(Books));
InquireBookMenu();
do
{
printf(">");
scanf("%d", &menu);
switch (menu)
{
case 1:
//按图书名查询
printf("请输入查询书名:");
scanf("%s", &bookname);
abook = NameInquireBook(bookname);
if (abook != NULL)
{
printf("查找成功");
printf("\n编号%d\n书名%s\n作者%s\n状态%d\n", abook->BookNum, abook->BookName, abook->Author, abook->nDel);
}
else printf("查找失败\n");
break;
/* 普通查询
SimpleInquireBook();
*/
case 2:
//按图书编号查询
printf("请输入查询书编号:");
scanf("%d", &num);
abook = NumInquireBook(num);
if (abook != NULL)
{
printf("查找成功");
printf("\n编号%d\n书名%s\n作者%s\n状态%d\n", abook->BookNum, abook->BookName, abook->Author, abook->nDel);
}
else printf("查找失败\n");
break;
/* 高级查询
AdvanceInquireBook();
*/
case 0:
// 返回上一级目录
OutputReaderMenu();
break;
default:
puts("非法输入!");
break;
}
} while (menu);
}
/**
普通查询书籍
底层代码由你们编写,可以新建底层函数完成相应功能
*/
void SimpleInquireBook()
{
int menu1;
int num = 0;
Books* tbook;
InquireBookMENU();
do {
printf(">");
scanf("%d",&menu1);
switch (menu1)
{
case 1:
AuthorInquireBook();
break;
case 2:
printf("请输入查询书编号:");
scanf("%d", &num);
tbook = NumInquireBook(num);
if(tbook!=NULL)
printf("查找成功");
printf("\n编号%d\n书名%s\n作者%s\n状态%d\n",tbook->BookNum,tbook->BookName,tbook->Author,tbook->nDel);
break;
case 0:
InquireBookMenu();
break;
}
} while (menu1);
}
/**
高级查询书籍
底层代码由你们编写,可以新建底层函数完成相应功能
*/
void AdvanceInquireBook()
{
// insert code here...
}
Books* AuthorInquireBook()
{
Books* abook = (Books*)malloc(sizeof(Books));
char bookauthor[10] = {};
printf("请输入查询书作者名:");
scanf("%s",bookauthor);
FILE* fp = NULL;
fp = fopen(ppPathReaderBook,"rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
free(abook);
return NULL;
}
while (!feof(fp))
{
if (fread(abook, sizeof(Books), 1, fp) != 0)
{
if (strcmp(abook->Author, bookauthor) == 0)
{
return abook;
}
}
free(abook);
return NULL;
}
return NULL;
}
Books* NumInquireBook(int num)
{
Books* abook = (Books*)malloc(sizeof(Books));
/*int num = 0;
printf("请输入查询书编号:");
scanf("%d", &num);*/
FILE* fp = NULL;
fp = fopen(ppPathReaderBook, "rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
free(abook);
return NULL;
}
while (!feof(fp))
{
if (fread(abook, sizeof(Books), 1, fp) != 0)
{
if ((abook->BookNum) == num)
{
return abook;
}
}
free(abook);
return NULL;
}
return NULL;
}
Books* NameInquireBook(char bookname[10])
{
Books* abook = (Books*)malloc(sizeof(Books));
FILE* fp = NULL;
fp = fopen(ppPathReaderBook, "rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
free(abook);
return NULL;
}
while (!feof(fp))
{
if (fread(abook, sizeof(Books), 1, fp) != 0)
{
if (strcmp(abook->Author, bookname) == 0)
{
return abook;
}
}
free(abook);
return NULL;
}
return NULL;
}
//根据编号和书名查询书籍
Books* InquireBookByNameNum(char* pbookname, int booknum)
{
Books* abook = (Books*)malloc(sizeof(Books));
FILE* fp = NULL;
fp = fopen(ppPathReaderBook, "rb");
if (fp == NULL)
{
printf("打开文件失败!\n");
free(abook);
return NULL;
}
while (!feof(fp))
{
if (fread(abook, sizeof(Books), 1, fp) != 0)
{
if ((abook->BookNum) == booknum && strcmp(abook->BookName, pbookname) == 0)
{
return abook;
}
}
free(abook);
return NULL;
}
}
//根据给出的借阅人编号查询是否第一次借阅
//是的话返回true
//不是的话获得文件中的位置
int InquireBorrow(int borrowernum, int* index)
{
Borrow* pBorrow = NULL;
FILE* fp = NULL;
pBorrow = (Borrow*)malloc(sizeof(Borrow));
fp = fopen(BORROWPATH, "rb");
if (fp == NULL)
{
return false;
}
while (!feof(fp))
{
if (fread(pBorrow, sizeof(Borrow), 1, fp) != 0)
{
if (pBorrow->p->ReaderID == borrowernum)
{
return true;
}
index++;
}
free(pBorrow);
return false;
}
}
头文件
头文件基本上都是函数的声明以及文件的引用,这里我只列出两个具有其它功能的头文件。
model.h
#ifndef model_h
#define model_h
/**
图书信息结构体
*/
typedef struct Books
{
int BookNum=0;
char BookName[40]; // 图书名
char Author[10]; // 作者
int nDel; //借阅状态:0未借出,1已借出,2已删除
}Books;
/**
借阅信息结构体
*/
typedef struct Borrow
{
struct Readers* p; // 借阅人信息
int BorrowDate; // 借阅日期 按视频要求,这里使用 int 型, 应该是按年/月/日的方式保存
int ReturnDate; // 归还日期
}Borrow;
/**
读者信息结构体
*/
typedef struct Readers
{
int nDel; //0未删除,1已删除
int ReaderID; // 读者ID
//char ReaderName[18]; // 读者姓名
char ReaderPwd[10]; // 密码
Books BorrowedBook[6]; // 已借书目, 这里用结构体表示, 同时借阅书目不能超过6本
//long int ReaderPhoneNum; // 读者联系电话
}Readers;
/**
管理员信息结构体
*/
typedef struct Librarians
{
int nDel; //0未删除,1已删除
int LibrarianID; // 管理员ID
//char LibrarianName[18]; // 管理员姓名/卡号
char LibrarianPwd[10]; // 密码
int Level; // 管理员等级
//long int LibrarianPhoneNum; // 管理员联系电话
}Librarians;
#endif /* model_h */
global.h
这个文件用于保存路径。
一定要记得改这个文件中的路径!
#define ppPathReaderLib "C:\\Users\\29799\\Desktop\\Library\\Library\\Library\\data\\Librarian.ams"
#define ppPathReaderBook "C:\\Users\\29799\\Desktop\\Library\\Library\\Library\\data\\Book.ams"
#define pPathReader "C:\\Users\\29799\\Desktop\\Library\\Library\\Library\\data\\Reader.ams"
#define BORROWPATH "C:\\Users\\29799\\Desktop\\Library\\Library\\Library\\data\\Borrow.ams"