图书馆管理系统(3)

这里写一个图书馆管理系统,也相当于写了多个类似的系统,通讯录管理系统,餐饮管理系统

例如学生成绩管理系统什么的,框架都一样

一进来先是显示界面,

然后是对成绩增删改查的功能,也可以再加一些求平均成绩之类的功能函数

模块

 

现在来写这个里面的显示图书信息

有新增加的图书信息我们就把它存到文件里面,所以图书信息我们就从文件里面去读

到时候我们这个项目底下就有一个book这个文件,那么我们就把图书信息存在这个文件里,

显示信息函数的思路就是:

1.先从文件里面去读(rb只读方式)(后面新增图书信息就是以写的方式打开了)(现在把这个模式传过去,后面就可以复用这个ReadBookFile函数了)图书信息(一会儿会把这些数据读到数组里面去)

2.接下来打印,就在数组里面打印BOOK_DATA


现在要写这个 ReadBookFile函数,之后才能2个函数一起测试

通常大小会定义成一个宏,不定直接写也行

测试

接下来写case2,新增图书信息

void AddBook()//新增图书信息
{
	//图书信息是往文件里面增加的,每次打开文件要往已有记录的后面新加,
	//所以要以追加的方式打开,不能以w打开,w打开会删除原有数据
	FILE* pfBook;//文件指针
	int iBookRecord;//图书记录条数
	int iFlagExist;//该图书是否存在,录入时要用
	int i;//结构体数组下标
	char cFlag;//是否继续输入的标志
	system("cls");//清屏
	iBookRecord = ReadBookFile("ab+");//ab+是以追加方式打开或新建二进制文件。
	//这里函数复用,pcMode==ab+
	if (iBookRecord == -1)
	{
		printf("文件打开失败\n");
		return ;
	}
	else if (iBookRecord == 0)
	{
		printf("文件为空,没有图书记录!\n");
	}
	else
	{
		ShowBook();//记录不为0则显示现有图书记录信息
	}
	//循环录入图书信息,一次录完所有图书信息
	//不想循环就要多次进入,录一本书进入一次
	printf("请选择是否输入信息(y/n)或(Y/N)\n");
	cFlag = getchar();//getchar将刚才从键盘读取的字符(y/n)丢给cFlag
	getchar();//去掉\n
	if (cFlag == 'n'|| cFlag == 'N')//选择否,一般没有提示,直接退出(到上一层)
	{
		return;
	}
	//打开pfBook文件信息,方便后面保存信息
	pfBook = fopen("Book.txt", "ab +");
	if (pfBook == NULL)
	{
		printf("文件打开失败\n");
		return;
	}

	while(cFlag == 'y'|| cFlag == 'Y')
	{
		printf("录入数据:\n");

		//录入数据,往内存中的结构体数组录入数据
		
		//定义录入的数组的大小,先判断录入的数据不能超过数组大小,这里宏定义是200,
		//即判断记录是否已满
		if (iBookRecord >= BOOK_NUM)
		{
			printf("记录已满!\n");
			fclose(pfBook);
			return;
		}
		// 要考虑图书编号是唯一的,不能重复;
		printf("请输入图书编号:\n");
		//不能输一个编号就退出,要循环录do while
		do
		{
			iFlagExist = 0;
			scanf("%d", &astBook[iBookRecord].iNum);
			getchar();//去掉编号的\n
			//循环挨个对比,编号是否重复
			for (int i = 0;i < iBookRecord; i++)
			{
				//iFlagExist= 0;//这里置0会出错
				if (astBook[i].iNum == astBook[iBookRecord].iNum)//重复,数组已存在==新输入
				{
					iFlagExist = 1;
					printf("该图书编号已经存在,请重新输入:");
					break;
				}
			}
		} while(iFlagExist == 1);//重复了重新进入do循环,输入新编号;
		//要是不为1为0,就是正常的,就不重复退出当前do循环

		//输入图书信息
		printf("请输入图书名称:");
		scanf("%s", astBook[iBookRecord].acName);
		getchar();

		printf("请输入图书作者:");
		scanf("%s", astBook[iBookRecord].acAuthor);
		getchar();

		printf("请输入图书出版社:");
		scanf("%s", astBook[iBookRecord].acPress);
		getchar();

		printf("请输入图书库存量:");
		scanf("%d", &astBook[iBookRecord].iAmout);
		getchar();
	
		//录完数据后保存信息,将信息保存在外存的文件中
		//从数组存到文件
		//这里不太好的地方是,它是一条一条保存的,即录完一条当即保存一条
		//这个保存也可以封装成一个函数,后面增删改查等所有操作执行完都需要保存,直接调用函数会更方便,不然会发现保存的代码会一直重复的写
		if (fwrite(&astBook[iBookRecord], LEN_BOOK, 1, pfBook) != 1)//把buffer里面的数据给他写,写到FILE*里面去
		{
			printf("无法保存该信息!\n");
			return;
		}
		else//fwrite返回1,即当前一个信息读完了
		{
			printf("%d号图书信息已经保存!\n", astBook[iBookRecord].iNum);
			iBookRecord++;
		}
		//给提示是否还录
		printf("还要继续输入信息吗?(y/n)或(Y/N)\n");
		cFlag = getchar();
		getchar();
		
	}
	fclose(pfBook);
	printf("添加图书信息执行完毕\n");
}


这三个的scanf输入加不加取地址符&都是可以的,上面代码框里的没加&,但还是加上比较好

————因为数组名本来就表示地址的意思了

而这里的不能去掉&是因为这是%d,不是%s

分不清的情况下就全加上&

测试一下

改成一进do就置0

这里1001号图书就好了

继续

输入一个重复的1001试试

显示图书信息

再新增

打开当前所在文件夹,可以看到这还是一个二进制文件,所以有些字符都不对


查找查询图书信息

//查找查询图书信息
int SearchBook()
{
	//将文件以只读的方式打开,在里面一个个找就是查询了
	//按编号找,因为编号是唯一不重复的
	int iBookNum;//图书编号
	int iBookReacord;//图书记录条数
	int iBookId;//返回值,查到该书了就返回其返回值
	int i;
	system("cls");
	iBookReacord = ReadBookFile("rb");
		//ReadBookFile读文件函数,每回将以什么方式读的参数传进去就可以了
	if (iBookReacord == -1)
	{
		printf("文件打开失败!\n");
		printf("按任意键返回到子菜单");
		getchar();
		return -2;//文件打开失败,返回-2,
		//这里有很多种返回情况,每种情况的返回值不一样好区分,都写return难排错
		//方便后面排错,类似于一张表上-1对应的错,-2的,-3的错误分类
	}
	else if (iBookReacord == 0)
	{
		printf("没有图书记录!\n");
		printf("按任意键返回到子菜单");
		getchar();
		return -3;//没有图书记录,返回-3
	}

	//进入查找程序
	printf("请输入想要查找的图书编号:");
	scanf("%d", &iBookNum);
	getchar();
	//在文件里循环,挨个查找有没有该图书编号
	for (i = 0; i < iBookReacord; i++)//一共三种编号种类的书,循环到2下标
	{
		if (iBookNum == astBook[i].iNum)//编号相等
		{
			iBookId = i;//图书返回值为该书在数组中的下标位置
			printf("\t\t%d号图书信息如下:", iBookNum);
			printf("\t\t------------------------------\n");
			printf("\t\t%-6s%-16s%-10s%-20s%-4s\n", "编号", "书名", "作者", "出版社", "库存量");//数字前面加负号为左对齐,都是%s是因为刚开始打印的是抬头汉字
			printf("\t\t%-6d%-16s%-10s%-20s%-4d\n", BOOK_DATA);
			printf("\t\t------------------------------\n");
			break;
		}
	}

	if (i == iBookReacord)//出for循环未进入if
	{
		printf("找不到%d号图书信息!\n",iBookNum);
		iBookId = -1;//找不到记录,返回-1
	}
	return iBookId;
}


测试一下

接下来写case 4:DeleteBook();//删除图书信息

删除思路

我们定义了图书长度为200,即最多只能输入200个,200种编号的图书(图中黑色的)

我们现在现有保存的图书长度为astBook(图中红色的)(3本)

所以我们找图书信息是在红色区域找的

假设图中红色有50本,那么iBookRecord就为0~49

假设找到了,要删除的图书编号为1005的位置在图中绿色框部分

那么现在要怎么删除——穿透删除,将后面的数据依次往前移动

代码如图

现在删完后1002号信息已经不存在了,那么被删除覆盖掉的,1002号怎么表示

——所以在删除覆盖之前,应该先把1002号保存一下

//删除图书信息
void DeleteBook()
{
	FILE* pfBook;
	int iBookId;//要删除的图书编号
	int iBookRecord;//图书记录
	int i;
	char cFlag;//是否删除标志

	system("cls");
	iBookId = SearchBook();//找到该图书id
	if (iBookId == -1)//没找到信息
	{
		return;
	}
	iBookRecord = ReadBookFile("rb");//只读打开看文件里的图书记录条数
	printf("已经找到该图书,是否删除?[y(Y)/n(N)]");
	cFlag = getchar();//读y/n
	getchar();//丢\n

	//删除之前先保存删除之前的图书编号,因为删除之后图书信息会被覆盖
	int index = astBook[iBookId].iNum;//绿色位置id的号码num


	if (cFlag == 'n' || cFlag == 'N')//选择否,一般没有提示,直接退出(到上一层)
	{
		return;
	}
	else if (cFlag == 'y' || cFlag == 'Y')
	{
		//删除找到的书(将后面的书依次往前移动,穿透删除)
		for (i = iBookId; i < iBookRecord-1; i++)//i=iBookId找到的绿色位置,i < iBookRecord,i<红色末尾
		{
			astBook[i] = astBook[i + 1];//,数组依次前移,后面值覆盖前面值
			//i+1可能越界,所以 iBookRecord-1,或者i+1< iBookRecord
		}
		//删除完记录条数(红色)减1
		iBookRecord--;
	}
	//删除完成保存现有修改后的信息
	//现在删掉的是数组里面的信息(在数组里操作),文件里面的还未删除
	//数组里删完之后整体复制到文件中,保存到文件
	pfBook = fopen("book.txt", "wb");//wb删除原有打开新空白
	if (pfBook != NULL)//指针不空复制写进文件去,写完关文件
	{
		for (i = 0; i < iBookRecord; i++)
		{
			if (fwrite(&astBook[i], LEN_BOOK, 1, pfBook) != 1)//写成功完返回写的条数1
			{
				printf("无法保存该信息!\n");
				return;
			}
		}
		fclose(pfBook);
		printf("%d号图书已经删除!\n",index);
	}


}

测试

不存在的编号

找到但不删,还在

删除——最终每种可能性都要测试

删完显示图书信息里面就没有了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值