马房山实验报告大学C语言实验 图书管理系统(一)——追求卓越

  • 时间:
  • 来源:互联网
  • 文章标签:

马房山实验报告大学C语言实验图书馆系统——追求卓越

  • 实验内容
  • 开发环境
  • 说明
  • 代码
    • 源文件
      • main.c
      • Welcome.c
      • Login.c
      • Reader.c
      • Manager.c
      • Librarian.c
      • Librarian_file.c
      • Borrow.c
      • Inquire.c
    • 头文件
      • model.h
      • global.h

实验内容

实验要求我就不说了老师应该都给你们说的很清楚了(其实是我忘了)

由于本次实验是组队编程,所以你们要cv也记得考虑接口的问题。

开发环境

macOS 10.14 Xcode
使用bug 10的各位同学直接运行可能会出一点小问题。
建议将代码导入工程阅读,体现代码结构

说明

以下代码均由我一人完成,代码基本上没有实现任何功能,只是设计出了整个系统的整体框架,以及所有接口的预留;接口的统一便于团队后续的功能实现。这篇文章的目的是给不知道从何开始编写的同学们一个参考(所以说为什么叫追求卓越了)(这个工程绝对是我这辈子写过的注释最多的一个工程)

代码

源文件

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"

本文链接http://www.taodudu.cc/news/show-1944764.html