其实这个题目要实现的功能比较清晰,主要就是文件和链表的操作以及基于这两个基础上的填删改查等功能,当然也可以添加一些个性化的功能,比如按照图书的检索量来对库存的图书进行热度的排序。
以下是我的这个图书管理系统的功能图以及菜单之间的调用情况(两张图基本一样,第二张图显示了菜单的调用信息)
附上源码,有好的建议欢迎各位指正!
第二部分的代码是一个头文件,里边包含了我需要用的的头文件以及三大部分关键函数的函数体,第一个是创建链表存入数据并返回头指针,第二个是将链表放入相应的文件,第三个是将数据从文件中取出并形成新的链表。(Book,Administrator,Reader三个结构体各有一套函数)
在实际编程的过程中碰到一些问题,和大家分享一下:
1、读者,管理员,书籍三者基础数据(至少100条)的录入,最初我采用的方法是只用一个函数将创建链表节点以及将节点数据存入文件,后来在编写其他功能时由于多次用到将链表数据从文件取出建立链表以及将修改后的链表数据存回文件的操作,我就将原来的一个函数拆分成三个相对独立的函数,分别是Create创建基础数据的链表并返回头指针,Save将链表数据存入相应文件(参数为链表头指针),List将数据从文件中取出放在新建立的链表并返回链表的头指针;
2、在写到读者借书还书的功能时,由于牵涉到要修改读者的相关信息,你们就会涉及到登录操作,当因为我的登录函数没有返回值(void),因此如果要完整的实现整个功能的话就需要将登录程序原封不动的再写一遍,因此我直接将登录程序的返回值写成struct Reader/Administrator *p类型,将登录者本人的节点的头指针返回,这样可以再借书还书程序中直接调用。这样还有一个好处,就是模拟了登录的真实过程:登陆后可以直接对个人的数据进行操作和保存,不用每次都要输入用户名和密码进行匹配,使程序逻辑更流畅;
3、我在遍历链表打印不管是读者亦或是书籍信息的时候会多输出一行乱码数据,然后我就在List函数的while循环那里设置断点查看循环的情况,后来发现循环比我预想的多进行了一次,导致在文件数据已经全部储存到链表之后又多创建了一个节点,然而该节点李并未存入任何实质性的数据。在深究为什么会多出一次循环的时候我发现自己似乎对文件位置标记的理解并不是很清楚,我的while循环的条件是(!feof(fp)),我最初认为当我创建完最后一个节点并将文件数据存进去之后由于此时文件位置标记已经移到了最后所以会少执行一次“将最后两个节点链起来”的操作,因此我在循环中加了一个if语句,即if(feof(fp)),之后将执行那个被跳过的操作。由于前面已经证实循环在文件到达末尾之后似乎还会在进行一次循环,所以if语句就显得没有必要,因此我在去掉if语句之后果然输出正常。但这不禁让我更加疑问,文件位置标记在执行完一次fread后到底如何移动?
4、我在输出的过程中也遇到了segmentation fault也就是段错误,在查找了相关博客之后我发现自己段错误的原因是指针访问了非法内存,具体到我的程序中就是我在遍历链表的过程中让指针多向后移动了一个位置,但那个位置指向的内容是不可预知的,因此就出错了。后来我发现在遍历链表的过程中用一个指针反而比两个指针更简洁有效,因此我就将遍历链表的那个循环改成了while(p!=NULL){…p = p->next};修改完之后没有再出现段错误;
5、在打印读者、管理员、和书籍相关信息时的排版问题,由于这些字符串的长度各不相同,因此在打印时容易出现错位的现象;解决办法:对于长度较短的读者和管理员的相关数据采用\t进行修正,对于书名和作者名比较长的书籍数据来说采用指定域宽的方式进行对齐,如%25s。
#include"Create & Save.h"
void menu1();
void menu2();
void menu3();
void menu4();
void menu5(struct Administrator *p);
void menu6();
void menu7(struct Reader *p);
void menu8();
void menu9();
void menu10();
void reader_Register(); //读者注册
void administrator_Register(); //管理员注册
struct Reader *reader_Log(); //读者登录
struct Administrator *administrator_Log(); //管理员登录
void reader_Change(struct Reader *p); //读者信息修改
void administrator_Change(struct Administrator *p); //管理员信息修改
void book_Research(); //图书查询
void book_Add(); //图书添加
void book_Delete(); //图书删除
void book_Change(); //图书信息修改
void reader_Print(); //读者信息一览表
void administrator_Print(); //管理员信息一览表
void book_TopN(int N); //图书Top(按照检索量排名)
void reader_bPrint(struct Reader *p); //读者借阅信息一览表
void reader_Borrow(struct Reader *p); //借阅功能
void reader_Return(struct Reader *p); //还书功能
int N1=125; //图书数量
int N2=125; //读者数量
int N3=20; //管理员数量
int main()
{
// printf("录入书籍数据(书名 ISBN号 作者 库存量 余量 检索量)\n");
// struct Book *head3;
// head3 = book_Create(N1);
// book_Save(head3);
// printf("录入管理员数据(用户名 密码)\n");
// struct Administrator *head2;
// head2 = administrator_Create(N3);
// administrator_Save(head2);
// printf("录入读者数据(用户名 密码 借阅本数 书名 ISBN 作者 库存 余量 检索量)\n");
// struct Reader *head1;
// head1 = reader_Create(N2);
// reader_Save(head1);
// printf("\n3s后跳转至主菜单\n");
// Sleep(3000);
menu1();
system("pause");
return 0;
}
void menu1()
{
system("cls");
int i;
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.登录系统\t\t\t**\n");
printf("\n**\t\t\t2.图书系统\t\t\t**\n");
printf("\n**\t\t\t3.退出系统\t\t\t**\n");
printf("\n**********************************************************\n\n");
printf("请选择功能:");
scanf("%d",&i);
switch(i) {
case 1: menu2();//登陆系统
break;
case 2: menu8();//图书信息
break;
case 3: //退出系统
default: {
printf("\n退出成功!\n");
} break;
}
}
void menu2()
{
system("cls");
int i;
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.用户登录\t\t\t**\n");
printf("\n**\t\t\t2.用户注册\t\t\t**\n");
printf("\n**\t\t\t3.读者信息一览表\t\t**\n");
printf("\n**\t\t\t4.管理员信息一览表\t\t**\n");
printf("\n**\t\t\t5.返回上一级\t\t\t**\n");
printf("\n**\t\t\t6.退出系统\t\t\t**\n");
printf("\n**********************************************************\n\n");
printf("请选择功能:");
scanf("%d",&i);
switch(i){
case 1: menu3();//用户登录
break;
case 2: menu4();//用户注册
break;
case 3: {
system("cls");
reader_Print();
printf("\n按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu2();
}
} //读者信息一览表
break;
case 4: {
system("cls");
administrator_Print();
printf("\n按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu2();
}
} //管理员信息一览表
break;
case 5: menu1();//返回上一级
break;
case 6: //退出系统
default: {
printf("\n退出成功!\n");
}break;
}
}
void menu3()
{
system("cls");
int i;
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.读者登录\t\t\t**\n");
printf("\n**\t\t\t2.管理员登录\t\t\t**\n");
printf("\n**\t\t\t3.返回上一级\t\t\t**\n");
printf("\n**\t\t\t4.退出系统\t\t\t**\n");
printf("\n**********************************************************\n\n");
printf("请选择功能:");
scanf("%d",&i);
switch(i) {
case 1: {
struct Reader *p = reader_Log();
printf("3s后将自动跳转至读者功能页面...\n");
Sleep(3000);
menu7(p);
}
break;
case 2: {
struct Administrator *p1 = administrator_Log();
printf("3s后将自动跳转至管理员功能页面...\n");
Sleep(3000);
menu5(p1);
}//管理员相关
break;
case 3: menu2();//返回上一级
break;
case 4: //退出系统
default: {
printf("\n退出成功!\n");
}break;
}
}
void menu4()
{
system("cls");
int i;
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.读者注册\t\t\t**\n");
printf("\n**\t\t\t2.管理员注册\t\t\t**\n");
printf("\n**\t\t\t3.返回上一级\t\t\t**\n");
printf("\n**\t\t\t4.退出系统\t\t\t**\n");
printf("\n**********************************************************\n");
printf("\n请选择功能:");
scanf("%d",&i);
switch(i) {
case 1: {
reader_Register();
printf("3s后将自动跳转至登录页面...\n");
Sleep(3000);
struct Reader *p = reader_Log();
menu7(p);
}//读者相关
break;
case 2: {
administrator_Register();
printf("3s后将自动跳转至登录页面...\n");
Sleep(3000);
struct Administrator *p1 = administrator_Log();
menu5(p1);
}//管理员相关
break;
case 3: menu2();//返回上一级
break;
case 4: //退出系统
default:{
printf("\n退出成功!\n");
} break;
}
}
void menu5(struct Administrator *p)
{
system("cls");
int i;
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.图书添加\t\t\t**\n");
printf("\n**\t\t\t2.图书删除\t\t\t**\n");
printf("\n**\t\t\t3.图书信息修改\t\t\t**\n");
printf("\n**\t\t\t4.修改个人信息\t\t\t**\n");
printf("\n**\t\t\t5.返回上一级\t\t\t**\n");
printf("\n**\t\t\t6.退出系统\t\t\t**\n");
printf("\n**********************************************************\n");
printf("\n请选择功能:");
scanf("%d",&i);
switch(i) {
case 1: { //图书添加
book_Add();
printf("\n请按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu5(p);
}
}
break;
case 2: {
book_Delete();
printf("\n请按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu5(p);
}
} //图书删除
break;
case 3: {
menu6();
book_Change(p);
printf("\n请按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu5(p);
}
} //图书信息修改
break;
case 4: {
menu10();
administrator_Change(p);
printf("3s后将自动跳转至登录页面,请重新登录...\n");
Sleep(3000);
struct Administrator *p1 = administrator_Log();
menu5(p1);
} //修改个人信息
break;
case 5: menu3(); //返回上一级
break;
case 6:
default: printf("退出成功!\n");
break;
}
}
void menu6()
{
system("cls");
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.ISBN号修改\t\t\t**\n");
printf("\n**\t\t\t2.作者修改\t\t\t**\n");
printf("\n**\t\t\t3.库存量修改\t\t\t**\n");
printf("\n**\t\t\t4.余量修改\t\t\t**\n");
printf("\n**\t\t\t5.返回上一级\t\t\t**\n");
printf("\n**\t\t\t6.退出系统\t\t\t**\n");
printf("**********************************************************\n");
}
void menu7(struct Reader *p) //读者功能菜单
{
system("cls");
int i;
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.图书借阅\t\t\t**\n");
printf("\n**\t\t\t2.图书归还\t\t\t**\n");
printf("\n**\t\t\t3.查看借阅信息\t\t\t**\n");
printf("\n**\t\t\t4.修改个人信息\t\t\t**\n");
printf("\n**\t\t\t5.返回上一级\t\t\t**\n");
printf("\n**\t\t\t6.退出系统\t\t\t**\n");
printf("\n**********************************************************\n");
printf("\n请选择功能:\n");
scanf("%d",&i);
switch(i){
case 1: {
reader_Borrow(p);
printf("\n请按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu3(); //返回登录界面借书信息才会更新
}
} //图书借阅
break;
case 2: {
reader_Return(p);
printf("请按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu3(); //返回登录界面借书信息才会更新
}
} //图书归还
break;
case 3: {
system("cls");
reader_bPrint(p);
printf("\n请按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu7(p);
}
} //查看个人信息
case 4: {
menu9();
reader_Change(p);
} //修改个人信息
break;
case 5: menu3(); //返回上一级
break;
case 6: //退出系统
default: printf("\n退出成功!\n");
break;
}
}
void menu8() //图书系统功能菜单
{
system("cls");
int i;
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.图书查询\t\t\t**\n");
printf("\n**\t\t\t2.图书Top_N\t\t\t**\n");
printf("\n**\t\t\t3.返回上一级\t\t\t**\n");
printf("\n**\t\t\t4.退出系统\t\t\t**\n");
printf("\n**********************************************************\n");
printf("\n请选择功能:\n");
scanf("%d",&i);
switch(i){
case 1: {
system("cls");
book_Research();
printf("\n请按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu8();
}
} //图书查询
break;
case 2: {
system("cls");
book_TopN(N1);
printf("\n请按ESC键返回上一级!\n");
char ch;
if((ch=getch())==27){
menu8();
}
} //图书Top
break;
case 3: menu1();
break;
case 4:
default: {
printf("\n退出成功!\n");
} break;
}
}
void menu9()
{
system("cls");
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.用户名修改\t\t\t**\n");
printf("\n**\t\t\t2.用户密码修改\t\t\t**\n");
printf("\n**\t\t\t3.借阅数量修改\t\t\t**\n");
printf("\n**\t\t\t4.返回上一级\t\t\t**\n");
printf("**********************************************************\n");
}
void menu10()
{
system("cls");
printf("**********************************************************\n");
printf("**\t\t欢迎使用图书管理系统V1.1\t\t**\n");
printf("**********************************************************\n");
printf("\n**\t\t\t1.用户名修改\t\t\t**\n");
printf("\n**\t\t\t2.用户密码修改\t\t\t**\n");
printf("\n**\t\t\t3.返回上一级\t\t\t**\n");
printf("**********************************************************\n");
}
void reader_Register() //读者注册
{
FILE *fp;
fp = file_Open("Reader.dat","ab");
char password[20];
struct Reader reader;
printf("请输入用户名(长度不超过20个字符):\n");
scanf("%s",reader.name);
while(1){
printf("请输入用户密码(长度不超过20个字符):\n");
scanf("%s",reader.password);
printf("请确认用户密码(长度不超过20个字符):\n");
scanf("%s",password);
if(strcmp(reader.password,password)!=0){
printf("两次密码不一致,请重新输入(长度不超过20个字符):\n");
}else break;
}
reader.count = 0; //首次注册只用收集用户名和密码信息,关于书的信息全是空
if(fwrite(&reader,len1,1,fp)!=1){
printf("file write error\n");
return ;
}
fclose(fp);
N2++;
printf("恭喜你,注册成功!\n"); //开始登录
}
void administrator_Register() //管理员注册
{
FILE *fp;
fp = file_Open("Administrator.dat","ab");
char password[20];
struct Administrator administrator;
printf("请输入用户名(长度不超过20个字符):\n");
scanf("%s",administrator.name);
while(1){
printf("请输入用户密码(长度不超过20个字符):\n");
scanf("%s",administrator.password);
printf("请确认用户密码(长度不超过20个字符):\n");
scanf("%s",password);
if(strcmp(administrator.password,password)!=0){
printf("两次密码不一致,请重新输入(长度不超过20个字符):\n");
}else break;
}
if(fwrite(&administrator,len2,1,fp)!=1){
printf("file write error\n");
}
fclose(fp); //开始登录
N3++;
printf("恭喜你,注册成功!\n");
}
struct Reader *reader_Log() //读者登录 需要返回一个Reader结构体指针,以便我接下来借书还书时使用
{
struct Reader *head=reader_List("rb"); //将文件数据取出来重新构建链表
struct Reader *p;
struct Reader reader;
while(1){
int flag=1;
printf("请输入用户名:\n");
scanf("%s",reader.name);
printf("请输入用户密码:\n");
scanf("%s",reader.password);
p = head;
while(p!=NULL){
if(strcmp(p->name,reader.name)==0){
if(strcmp(p->password,reader.password)==0){
printf("登录成功!\n");
break;
}
}
if(p !=NULL){
p = p->next;
}
}
if(p==NULL){
printf("用户名或密码错误,请重新输入!\n");
flag = 0;
}
if(flag) break;
}
return p;
}
void reader_Change(struct Reader *p) //读者信息修改
{
struct Reader *head = reader_List("rb");
struct Reader *p1;
p1 = head;
while(p1!=NULL){
if(strcmp(p1->name,p->name)==0){
int i;
printf("请选择相应的修改项:\n");
scanf("%d",&i);
switch(i){
case 1: {
printf("请输入修改后的用户名:\n");
scanf("%s",p1->name);
} break;
case 2: {
printf("请输入修改后的用户密码:\n");
scanf("%s",p1->password);
} break;
case 3: {
printf("请输入修改后的借阅数量:\n");
scanf("%d",&p1->count);
} break;
case 4: menu7(p);//返回上一级 这里在返回时有bug,明天改
break;
default: break;
}
reader_Save(head);
if(i==1||i==2||i==3){
printf("读者信息修改成功!\n");
printf("3s后将自动跳转至登录页面,请重新登录...\n");
Sleep(3000);
struct Reader *p2 = reader_Log();
menu7(p2);
}
break;
}
p1 = p1->next; //简化遍历过程,不要用p2指针,容易乱
}
if(p1==NULL){
printf("读者信息不存在!\n");
}
}
struct Administrator *administrator_Log() //管理员登录
{
struct Administrator *head=administrator_List("rb"); //将文件数据取出来重新构建链表
struct Administrator *p;
struct Administrator administrator;
while(1){
int flag=1;
printf("请输入用户名:\n");
scanf("%s",administrator.name);
printf("请输入用户密码:\n");
scanf("%s",administrator.password);
p = head;
while(p!=NULL){
if(strcmp(p->name,administrator.name)==0){
if(strcmp(p->password,administrator.password)==0){
printf("登录成功!\n"); //注意break的位置,语句别放错了
break;
}
}
if(p != NULL){
p = p->next;
}
}
if(p==NULL){
printf("用户名或密码错误,请重新输入!\n");
flag = 0;
}
if(flag) break;
}
return p;
}
void administrator_Change(struct Administrator *p) //管理员信息修改
{
struct Administrator *head = administrator_List("rb");
struct Administrator *p1;
p1 = head;
while(p1!=NULL){
if(strcmp(p1->name,p->name)==0){
int i;
printf("请选择相应的修改项:\n");
scanf("%d",&i);
switch(i){
case 1: {
printf("请输入修改后的用户名:\n");
scanf("%s",p1->name);
} break;
case 2: {
printf("请输入修改后的用户密码:\n");
scanf("%s",p1->password);
} break;
case 3: menu5(p);
break; //返回上一级
default: break;
} printf("管理员信息修改成功!\n");
break;
}
p1 = p1->next; //简化遍历过程,不要用p2指针,容易乱
}
if(p1==NULL){
printf("管理员信息不存在!\n");
}
administrator_Save(head);
}
void book_Add() //图书添加函数
{
FILE *fp;
fp = file_Open("Book.dat","ab");
struct Book book;
printf("请输入图书名称:\n");
scanf("%s",book.name);
printf("请输入ISBN号:\n");
scanf("%s",book.ISBN);
printf("请输入作者:\n");
scanf("%s",book.author);
printf("请输入库存量:\n");
scanf("%d",&book.count1);
book.count2 = book.count1; //刚添加的书余量等于库存
book.search_Num = 0; //新添加的书检索量为0
N1++;
printf("该书已入库!\n");
if(fwrite(&book,len3,1,fp)!=1){
printf("file write error!\n");
exit(0);
}
fclose(fp);
}
void book_Research() //图书信息查询函数
{
struct Book *head = book_List("rb"); //将文件数据取出来重新构建链表
struct Book *p;
p = head;
struct Book book;
printf("请输入ISBN号:\n");
scanf("%s",book.ISBN);
while(p!=NULL){
if(strcmp(p->ISBN,book.ISBN)==0){
printf("**************************************************************************************************\n");
printf("**\t书名\t\tISBN号\t\t作者\t\t库存\t\t余量\t\t检索量\t**\n");
printf("**%12s%14s%16s%13d%16d%17d\t**\n",p->name,p->ISBN,p->author,
p->count1,p->count2,p->search_Num);//不能用book来输出,因为book里边只有书名和ISBN号
printf("***************************************************************************************************\n");
p->search_Num++;
break;
}
p = p->next;
}
book_Save(head); //因为检索量信息有改动,需要重新存储
if(p==NULL){
printf("图书信息不存在!\n");
}
}
void book_Delete() //删除函数
{
struct Book *head = book_List("rb");
struct Book *p1,*p2;
struct Book book;
printf("请输入要删除的书籍ISBN号:\n");
scanf("%s",book.ISBN);
p1 = p2 = head;
while(strcmp(book.ISBN,p1->ISBN)!=0 && p1->next!=NULL){
p2 = p1;
p1 = p1->next;
}
if(strcmp(book.ISBN,p1->ISBN)==0){
if(p1==head){
head = p1->next;
}else {
p2->next = p1->next;
free(p1);
}
} else{
printf("输入信息有误!\n");
}
printf("书籍删除成功!\n");
N1--;
book_Save(head);
}
void book_Change(struct Administrator *p1) //书籍信息修改
{
struct Book *head = book_List("rb");
struct Book *p;
struct Book book;
printf("请输入ISBN号:\n");
scanf("%s",book.ISBN);
p = head;
while(p!=NULL){
if(strcmp(p->ISBN,book.ISBN)==0){
int i;
printf("请选择相应的修改项:\n");
scanf("%d",&i);
switch(i){
case 1: {
printf("请输入修改后的ISBN号:\n");
scanf("%s",p->ISBN);
} break;
case 2: {
printf("请输入修改后的作者名:\n");
scanf("%s",p->author);
} break;
case 3: {
printf("请输入修改后的库存量:\n");
scanf("%d",&p->count1);
} break;
case 4: {
printf("请输入修改后的余量:\n");
scanf("%d",&p->count2);
} break;
case 5: menu5(p1);
break;
case 6:
default: printf("\n退出成功!\n");
break;
} printf("图书信息修改成功!\n");
break;
}
p = p->next; //简化遍历过程,不要用p2指针,容易乱
}
if(p==NULL){
printf("图书信息不存在!\n");
}
book_Save(head);
}
void reader_Print() //读者信息一览表
{
struct Reader *head = reader_List("rb");
struct Reader *p;
p = head;
printf("******************************************************************\n");
printf("**\t\t 读 者 信 息 一 览 表 \t\t\t**\n");
printf("******************************************************************\n");
printf("**\t用户名\t\t密码\t\t\t借阅数量\t**\n");
while(p!=NULL){
printf("\n**\t%s\t\t%s\t\t%d\t\t**\n",p->name,p->password,p->count);
p = p->next;
}
printf("******************************************************************\n");
}
void administrator_Print() //管理员信息一览表
{
struct Administrator *head = administrator_List("rb");
struct Administrator *p;
p = head;
printf("******************************************************************\n");
printf("**\t\t管 理 员 信 息 一 览 表\t\t\t**\n");
printf("******************************************************************\n");
printf("\n**\t\t用户名\t\t\t密码\t\t\t**\n");
while(p!=NULL){
printf("\n**\t\t%s\t\t\t%s\t\t**\n",p->name,p->password);
p = p->next;
}
printf("\n******************************************************************\n");
}
void book_TopN(int N) //N<=150 但是要把数据全部拿出来,但只输出前N个
{
struct Book *p1,*p2,temp;
p1 = p2 = (struct Book*)malloc(len3*N);
FILE *fp;
fp = file_Open("Book.dat","rb");
for(int i=0;i<N;i++){
if(fread(p1,len3,1,fp)!=1){
printf("file read error!\n");
return ;
}
p1++;
}
for(int i=0;i<N;i++){ //冒泡排序
for(int j=i+1;j<N;j++){
if(p2[j].search_Num>p2[i].search_Num){
temp = p2[i];
p2[i] = p2[j];
p2[j] = temp;
}
}
}
int n;
printf("请输入Top_n:\n");
scanf("%d",&n);
printf("******************************************************************************************\n");
printf("**\t\t\t\t图 书 热 搜 排 名 Top%d\t\t\t\t**\n",n);
printf("******************************************************************************************\n");
printf("**\t\t书 名\t\t\t\t作 者\t\t\t检 索 量\t**\n");
for(int i=0;i<n;i++){
printf("**%23s%27s%25d\t\t**\n",p2[i].name,p2[i].author,p2[i].search_Num);
}
printf("******************************************************************************************\n");
free(p2);
}
void reader_bPrint(struct Reader *p) //读者借阅信息一览
{
int count = p->count;
struct Book *head = book_List("rb");
struct Book *p1;
printf("\n***************************************************************************************************\n");
printf("**\t\t\t\t读 者 借 阅 信 息 信 息 一 览 表\t\t\t\t**\n");
printf("***************************************************************************************************\n");
printf("**\t书名\t\tISBN号\t\t作者\t\t库存\t\t余量\t\t检索量\t**\n\n");
for(int i=0;i<count;i++){
p1 = head; //还需要重新找出这本书,然后输出信息
while(p1!=NULL){
if(strcmp(p1->ISBN,p->books[i].ISBN)==0){
printf("**%12s%14s%16s%13d%16d%17d\t**\n",p1->name,p1->ISBN,p1->author,
p1->count1,p1->count2,p1->search_Num);
break;
}
p1 = p1->next;
}
}
printf("\n***************************************************************************************************\n");
}
void reader_Borrow(struct Reader *p)
{
struct Book *head = book_List("rb");
struct Book *p1;
struct Book book;
printf("请输入图书名称:\n");
scanf("%s",book.name);
p1 = head;
while(p1!=NULL){
if(strcmp(p1->name,book.name)==0){
if(p->count==10){
printf("借书已达上限!\n");break;
}else if (p1->count2==0){
printf("该书已全部被借出!\n");break;
}else { // 先修改书的信息
p1->search_Num++;
p1->count2--;
break;
}
}
p1 = p1->next;
}
book_Save(head);
//再修改读者中关于所借书籍的信息
struct Reader *head1 = reader_List("rb");
struct Reader *p2;
p2 = head1;
while(p2!=NULL){
if(strcmp(p2->name,p->name)==0){
strcpy(p2->books[p2->count].name,p1->name);
strcpy(p2->books[p2->count].ISBN,p1->ISBN);
strcpy(p2->books[p2->count].author,p1->author);
p2->books[p2->count].count1=p1->count1;
p->books[p->count].count2=p1->count2;
p->books[p->count].search_Num=p1->search_Num;
p2->count++;
break;
}
p2 = p2->next;
}
reader_Save(head1); //要把修改后的读者信息存回文件里边
printf("借书成功\n");
}
void reader_Return(struct Reader *p) //还书
{
struct Book *head = book_List("rb");
struct Book *p1;
struct Book book;
printf("请输入图书名称:\n");
scanf("%s",book.name);
p1 = head;
while(p1!=NULL){
if(strcmp(p1->name,book.name)==0){
// 先修改书的信息
p1->count2++;
break;
}
p1 = p1->next;
}
book_Save(head);
//再修改人的信息
struct Reader *head1 = reader_List("rb"); //要把修改后的读者信息存回文件里边
struct Reader *p2;
p2 = head1;
while(p2!=NULL){
if(strcmp(p2->name,p->name)==0){
p2->count--;
break;
}
p2 = p2->next;
}
reader_Save(head1);
printf("还书成功!\n");
}
//v1.0结束基本功能的代码
//v1.1菜单功能完善,各项功能检查
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<windows.h>
#include<conio.h>
#define len1 sizeof(struct Reader)
#define len2 sizeof(struct Administrator)
#define len3 sizeof(struct Book)
struct Reader *reader_Create(int N);
void reader_Save(struct Reader *head);
struct Administrator *administrator_Create(int N);
void administrator_Save(struct Administrator *head);
struct Book *book_Create(int N);
void book_Save(struct Book *head);
FILE *file_Open(char fname[],char fopenWay[]);
struct Book *book_List(char fopenWay[]);
struct Reader *reader_List(char fopenWay[]);
struct Administrator *administrator_List(char fopenWay[]);
struct Administrator { //管理员
char name[20]; //用户名
char password[20]; //登陆密码
struct Administrator *next; //一定要注意administrator的拼写
};
struct Book { //图书
char name[30];
char ISBN[20];
char author[30];
int count1; //库存总量
int count2; //库存余量
int search_Num; //检索量
struct Book *next;
};
struct Reader { //读者
char name[20]; //用户名
char password[20]; //登陆密码
int count; //已借数量
struct Book books[10]; //借书信息,上限是10本 //如果把Book结构体声明放在Reader后面,程序会报错
struct Reader *next;
};
struct Reader *reader_Create(int N)
{
struct Reader *head;
struct Reader *p1,*p2;
int n=1;
p1 = p2 = (struct Reader*)malloc(len1);
scanf("%s%s%d",p1->name,p1->password,&p1->count);
for(int i=0;i<p1->count;i++){
scanf("%s%s%s%d%d%d",p1->books[i].name,p1->books[i].ISBN,p1->books[i].author,
&p1->books[i].count1,&p1->books[i].count2,&p1->books[i].search_Num);
}
head = NULL;
while(n<=N){
if(n==1){
head = p1;
}else {
p2->next = p1;
}
p2 = p1;
if(n<N){
p1 = (struct Reader *)malloc(len1);
scanf("%s%s%d",p1->name,p1->password,&p1->count);
for(int i=0;i<p1->count;i++){
scanf("%s%s%s%d%d%d",p1->books[i].name,p1->books[i].ISBN,p1->books[i].author,
&p1->books[i].count1,&p1->books[i].count2,&p1->books[i].search_Num);
}
}
n++;
}
p2->next = NULL;
printf("数据录入成功!\n");
return head;
}
void reader_Save(struct Reader *head)
{
FILE *fp;
fp = file_Open("Reader.dat","wb");
struct Reader *p = head;
while(p!=NULL){
if(fwrite(p,len1,1,fp)!=1){
printf("file write error!\n");
return ;
}
p = p->next;
}
fclose(fp);
printf("恭喜你!读者数据保存成功!\n");
}
struct Administrator *administrator_Create(int N)
{
struct Administrator *head;
struct Administrator *p1,*p2;
int n=1;
head = NULL;
p1 = p2 = (struct Administrator *)malloc(len2);
scanf("%s%s",p1->name,p1->password);
while(n<=N){
if(n==1){
head = p1;
}else {
p2->next = p1;
}
p2 = p1;
if(n<N){
p1 = (struct Administrator *)malloc(len2);
scanf("%s%s",p1->name,p1->password);
}
n++; //注意这个n的位置,不能放在上面的if里边,会引起死循环
}
p2->next = NULL;
printf("数据录入成功!\n");
return head;
}
void administrator_Save(struct Administrator *head)
{
FILE *fp;
fp = file_Open("Administrator.dat","wb");
struct Administrator *p = head;
while(p!=NULL){
if(fwrite(p,len2,1,fp)!=1){
printf("file write error!\n");
return ;
}
p = p->next;
}
fclose(fp);
printf("恭喜你!管理员信息保存成功!\n");
}
struct Book *book_Create(int N)
{
struct Book *head;
struct Book *p1,*p2;
head = NULL;
p1 = (struct Book*)malloc(len3);
scanf("%s%s%s%d%d%d",p1->name,p1->ISBN,p1->author,&p1->count1,&p1->count2,&p1->search_Num);
int n=1;
while(n<=N){
if(n==1){
head = p1;
}else {
p2->next = p1;
}
p2 = p1;
if(n<N){
p1 = (struct Book*)malloc(len3);
scanf("%s%s%s%d%d%d",p1->name,p1->ISBN,p1->author,&p1->count1,&p1->count2,&p1->search_Num);
}
n++;
}
p2->next = NULL;
printf("数据录入成功!\n");
return head;
}
void book_Save(struct Book *head)
{
FILE *fp;
fp = file_Open("Book.dat","wb");
struct Book *p;
p = head;
while(p!=NULL){
if(fwrite(p,len3,1,fp)!=1){
printf("file write error!\n");
return ;
}
p = p->next;
}
fclose(fp);
printf("恭喜你!书籍信息保存成功!\n");
}
//汉字无法在cmd终端显示,但在dev弹出终端中可以显示
FILE *file_Open(char fname[],char fopenWay[])//文件打开函数,相当有用
{
FILE *fp;
if((fp=fopen(fname,fopenWay))==NULL){
printf("cannot open file!\n");
return ;
}
return fp;
}
struct Book *book_List(char fopenWay[])
{
struct Book *head=NULL;
struct Book *p1,*p2;
FILE *fp;
fp = file_Open("Book.dat",fopenWay);
p1 = p2 = (struct Book*)malloc(len3);
int n=1;
fread(p1,len3,1,fp);
while(!feof(fp)){ //这里有一个关于文件位置标记的bug
if(n==1){
head = p1;
}else {
p2->next = p1;
}
p2 = p1;
p1 = (struct Book*)malloc(len3);
fread(p1,len3,1,fp);
n++;
}
fclose(fp);
p2->next = NULL;
free(p1);
return head;
}
struct Reader *reader_List(char fopenWay[])
{
struct Reader *head=NULL;
struct Reader *p1,*p2;
FILE *fp;
fp = file_Open("Reader.dat",fopenWay);
p1 = p2 = (struct Reader*)malloc(len1);
int n=1;
fread(p1,len1,1,fp);
while(!feof(fp)){
if(n==1){
head = p1;
}else {
p2->next = p1;
}
p2 = p1;
p1 = (struct Reader*)malloc(len1);
fread(p1,len1,1,fp);
n++;
}
fclose(fp);
p2->next = NULL;
free(p1);
return head;
}
struct Administrator *administrator_List(char fopenWay[])
{
struct Administrator *head=NULL;
struct Administrator *p1,*p2;
FILE *fp;
fp = file_Open("Administrator.dat",fopenWay);
p1 = p2 = (struct Administrator*)malloc(len2);
int n=1;
fread(p1,len2,1,fp);
while(!feof(fp)){
if(n==1){
head = p1;
}else {
p2->next = p1;
}
p2 = p1;
p1 = (struct Administrator*)malloc(len2);
fread(p1,len2,1,fp);
n++;
}
fclose(fp);
p2->next = NULL;
free(p1);
return head;
}