目录
一、需求分析
本次课程设计为图书管理系统,分为管理员处理系统和普通读者管理系统。管理员系统能对读者账号进行增删改查,能对书籍进行增删改查,能对账号进行用户名与密码的修改,能对读者借阅信息进行增删改查。普通读者管理系统能对借阅信息进行查询,能够进行还书和借书操作。
二、 概要设计
1、程序设计框架
(如图1所示)
图1-系统程序框图
2、数据结构
//图书管理系统结构体
typedef struct timeInfo{ int year; int mouth; int day; int hour; int min; int sec; }TIME; |
//读者信息
typedef struct readerInfo{ char name[30];//姓名 char no[20];//学号 char password[16];//密码 int maxnum;//最大借阅额度 struct readerInfo * next; }READ; |
//图书信息
typedef struct book{ char no[20];//图书编号 char bookName[50];//图书名 char author[20];//作者名 char type[10];//图书类型 char unit[30];//出版单位 float price;//图书单价 int num;//库存数量 struct book * next; }BOOK; |
//图书借阅信息
typedef struct bookLend{ char no[20];//借书学生学号 char bookno[20];//图书编号 TIME * remand;//借/还日期 char condition[10];//借阅状态 struct bookLend * next; }LEND; |
//管理员登录信息结构体
typedef struct loginInfo{ int times;//次数 char username[20];//用户名 char password[16];//密码 TIME * logintime;//登录时间 struct loginInfo * next; }LOGIN; |
3、模块函数划分
//管理员登陆图书管理系统
void login_system();
void login_registered();
void login_enter(char user[], char password[]);
void output_login(LOGIN * head);
TIME * getTime();
//窗口
void account_windows();
void login_windows();
void administrator_windows();
void menu_windows();
void book_windows();
void windows();
void reader_windows(char no[]);
//找回密码
LOGIN * login_read();
void password_asked(int num);
void password_setquestion();
void password_answers(int num);
void password_change();
void reset_system();
void change_adminname();
void change_adminpassword();
//图书管理
//图书录入
void onebookLoad(BOOK * head);
void bookLoad_system(BOOK * head);
BOOK* getNode();
void book_output(BOOK* info);
void book_save(BOOK * head);
void book_read(BOOK *head);
//图书查询
void onebook_output(BOOK * p);
void book_inquire(BOOK *head);
void inquire_no(BOOK * head);
void inquire_name(BOOK * head);
void inquire_author(BOOK * head);
void book_change(BOOK * head);
void book_delete(BOOK * head);
//图书借阅
void book_lend(char no[]);
void lend_inquire(char no[]);
TIME * count_remand();
void lend_read(LEND *head);
void lend_save(LEND * temp);
void lend_output(char no[], LEND * head);
void lendsum_change(char no[], READ * head, int n);
void booksum_change(BOOK * head, char no[], int n);
int lend_credit(char no[], READ * head);
void reader_save(READ * head);
//图书归还
void return_book(char no[]);
void onebook_return(char no[], char bookno[]);
//读者登录
void reader_registered();
void reader_read(READ * head);
void onereader_save(READ * temp);
int reader_enter(char no[], char password[]);
void reader_login();
void reader_loginwindows();
//读者信息管理
void reader_mgm();
void add_reader();
void change_readerinfo(READ * head);
void delete_reader(READ * head);
void inquire_reader(READ * head);
void inquire_reader_no(READ * head);
void inquire_reader_name(READ * head);
void inquire_reader_all(READ * head);
void CreateFolder();
三、 详细设计
1、main主函数
函数的主入口,先规定颜色、窗体大小和标题,再创建文件夹存储信息后调用主菜单。
int main() { system("title 图书管理系统"); CreateFolder();//创建文件夹储存信息 menu_windows(); return 0; } |
2、主菜单函数
void menu_windows(){ int n; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ printf("***********************[图书管理系统]***********************\n"); printf("\n [1.管理员入口] \n"); printf("\n [2.读者入口] \n"); printf("\n [3.退出系统] \n\n"); printf("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("\n\t[请选择]\t·"); scanf("%d", &n); switch (n) { case 1:login_windows(); break; case 2:reader_loginwindows(); break; case 3:exit(0); break; default:printf("\t\t输入有误!\n"); Sleep(1000); menu_windows(); break; } } |
打印图书管理系统的界面后,利用switch case 语句进行选择是管理员入口还是读者入口还是退出系统。
3、密保
利用fopen函数对于FindPassword_Question.txt进行数据的下入,如果选择编号小于0并且大于13时候输出选择有误,利用switch case 语句进行选择密保后写入文件。
//选择密保问题 void password_asked(int num) { int n; if (num == 1) fp1 = fopen("Data\\FindPassword_Qusetion.txt", "w"); else fp1 = fopen("Data\\FindPassword_Qusetion.txt", "a"); printf("\n请选择第%d个密保问题:>>\t", num); scanf("%d", &n); while (n<0||n>13) { printf("选择有误!请重新输入\n"); scanf("%d", &n); } switch (n) { case 1:fprintf(fp1, "%s", "您目前的姓名是?\t"); break; case 2:fprintf(fp1, "%s", "您配偶的生日是?\t"); break; case 3:fprintf(fp1, "%s", "您的学号(或工号)是\t"); break; case 4:fprintf(fp1, "%s", "您母亲的生日是?\t"); break; case 5:fprintf(fp1, "%s", "您高中班主任的名字是?\t"); break; case 6:fprintf(fp1, "%s", "您父亲的姓名是?\t"); break; case 7:fprintf(fp1, "%s", "您小学班主任的名字是?\t"); break; case 8:fprintf(fp1, "%s", "您父亲的生日是?\t"); break; case 9:fprintf(fp1, "%s", "您配偶的姓名是?\t"); break; case 10:fprintf(fp1, "%s", "您初中班主任的名字是?\t"); break; case 11:fprintf(fp1, "%s", "您最熟悉的童年好友名字是?\t"); break; case 12:fprintf(fp1, "%s", "您最熟悉的学校宿舍舍友名字是?\t"); break; case 13:fprintf(fp1, "%s", "对您影响最大的人名字是?\t"); break; } fclose(fp1); } |
4、管理员登录
对LoginInfo_Administrator.txt进行缓存管理员登录信息后,读取管理员的登录信息。
/缓存管理员登录信息 //(输出管理员的登录信息到文件中) void output_login(LOGIN * info) { fp1 = fopen("Data\\LoginInfo_Administrator.txt", "w"); fprintf(fp1, "%d\t%s\t%s\t", info->times, info->username, info->password); fprintf(fp1, "%d\t%d\t%d\t", info->logintime->year, info->logintime->mouth, info->logintime->day); fprintf(fp1, "%d\t%d\t%d\t\n", info->logintime->hour, info->logintime->min, info->logintime->sec); fclose(fp1); } //读取管理员的登录信息 LOGIN * login_read() { LOGIN * temp=(LOGIN *)malloc(sizeof(LOGIN)); memset(temp,0,sizeof(temp)); if(!access("Data\\LoginInfo_Administrator.txt",0))//如果文件存在 { fp1 = fopen("Data\\LoginInfo_Administrator.txt", "r"); fscanf(fp1, "%d%s%s", &temp->times, temp->username, temp->password); } else fp1=fopen("Data\\LoginInfo_Administrator.txt", "w"); return temp; } |
5、修改管理员账号和密码
在LoginInfo_Administrator.txt文本中对管理员信息进行修改,流程图如图2所示。
/修改管理员用户名 void change_adminname(){ LOGIN * temp = login_read(); temp->logintime = getTime(); system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("**********************[用户名修改]******************"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"); |
图2-修改管理员账号和密码
printf("[请输入修改后的用户名]\n"); printf("\n\t\t用户名:\t·"); scanf("%s", temp->username); printf("\n-------------------------[修改成功]-------------------------\n"); Sleep(1000); output_login(temp); account_windows(); } //修改管理员密码 void change_adminpassword() { LOGIN * temp = login_read(); temp->logintime = getTime(); system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("**************************[密码修改]****************"); printf("━━━━━━━━━━━━━━━━━━━━━━━\n\n\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━\n"); printf("[请输入修改后的密码]\n"); printf("\n\t\t密码:\t·"); scanf("%s", temp->password); printf("\n-------------------------[修改成功]-------------------------\n"); Sleep(1000); output_login(temp); account_windows(); } |
6、录入图书
创建newbook结点,利用链表进行数据的插入.流程图如图3所示。
图3录入图书
//有序录入图书 void onebookLoad(BOOK * head) { BOOK * p = head; BOOK * newbook = getNode(); system("cls"); printf("\n请输入图书信息\n"); printf("[图书编号]·"); scanf("%s", newbook->no); printf("[图书类型]·"); scanf("%s", newbook->type); printf("[图书名] ·"); scanf("%s", newbook->bookName); printf("[作者名] ·"); scanf("%s", newbook->author); printf("[出版单位]·"); scanf("%s", newbook->unit); printf("[图书单价]·"); scanf("%f", &newbook->price); printf("[库存数量]·"); scanf("%d", &newbook->num); while (p->next != NULL&&strcmp(p->next->no, newbook->no)<0) p = p->next; newbook->next = p->next; p->next =newbook; printf("图书录入成功!"); } |
7、输出图书
/输出所有的图书信息 void book_output(BOOK* head) { BOOK* p = head->next; system("cls"); windows(); printf("\n[图书信息如下]\n"); while (p != NULL) { onebook_output(p); p = p->next; } printf("\n按回车键返回···\n"); fflush(stdin); getchar(); book_inquire(head); } |
8、修改图书
通过图书编号与txt文本信息进行比较,查询到后覆盖链表信息。
//图书信息修改 void book_change(BOOK * head) { BOOK * p = head->next; char no[20]; int flag = 0; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━"); printf("************************[图书信息修改]***************"); printf("━━━━━━━━━━━━━━━━━━━━━━━\n\n\n"); printf("\n[输入修改图书的编号]·"); scanf("%s", no); for (; p != NULL; p = p->next) { if ((strcmp(no, p->no)) == 0) { printf("\n请输入修改后的图书信息\n"); printf("\n[图书编号]·"); scanf("%s", p->no); printf("[图书类型]·"); scanf("%s", p->type); printf("[图书名] ·"); scanf("%s", p->bookName); printf("[作者名] · "); scanf("%s", p->author); printf("[出版单位]·"); scanf("%s", p->unit); printf("[图书单价]·"); scanf("%f", &p->price); printf("[库存数量]·"); scanf("%d", &p->num); book_save(head); printf("\n-------------------------[修改成功]-----------------------\n"); flag = 1; break; } } if (flag == 0) printf("没有找到!\n"); printf("\n按回车键返回···\n"); fflush(stdin); getchar(); } |
9、删除图书
通过图书编号进行查询,查询到后释放节点。
//图书信息删除 void book_delete(BOOK * head) { BOOK * p = head; BOOK * temp = NULL; char no[20],ch; int flag = 0; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━"); printf("*******************[图书信息删除]***********"); printf("━━━━━━━━━━━━━━━━━━━━━━━━\n\n\n"); printf("\n[输入删除图书的编号]·"); scanf("%s", no); while (p->next != NULL) { if ((strcmp(no, p->next->no)) == 0){ fflush(stdin); onebook_output(p->next); printf("确定删除该图书\nY、确认\tN、取消\n"); scanf("%c", &ch); if (ch == 'y' || ch == 'Y') { temp = p->next; p->next = temp->next; free(temp); printf("\n-------------------------[删除成功]---------------------\n"); book_save(head); flag++; } else { printf("\n按回车键返回···\n"); fflush(stdin); getchar(); book_inquire(head); } } else p = p->next; } if (flag == 0) printf("\n-------------------------[没有找到]-------------------------\n"); printf("\n按回车键返回···\n"); fflush(stdin); getchar(); book_inquire(head); } |
10、增加读者
创建newhead节点,插入读者信息链表。
/增加读者信息 void add_reader() { READ * newhead = (READ *)malloc(sizeof(READ)); READ * head = (READ *)malloc(sizeof(READ)); READ * p = head; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━━"); printf("********************[增加读者信息]********************"); printf("━━━━━━━━━━━━━━━━━━━━━━━━\n\n\n"); memset(head, 0, sizeof(READ)); reader_read(head); memset(newhead, 0, sizeof(READ)); newhead->maxnum = 10; printf("[请填写以下信息]\n\n"); printf("[姓名]:"); scanf("%s", newhead->name); printf("[学号]:"); scanf("%s", newhead->no); printf("[密码(少于16位)]:"); scanf("%s", newhead->password); for (; p != NULL; p = p->next) { if ((strcmp(newhead->no, p->no)) == 0) { printf("\n\n---------------------[该用户已存在]----------------------\n"); Sleep(1000); add_reader(); } } onereader_save(newhead); printf("\n\n----------------------[读者添加成功]------------------------\n"); Sleep(1000); reader_mgm(); } |
11、删除读者
利用读者编号查询到读者后,释放相关读者信息。
//删除读者信息 void delete_reader(READ * head) { READ * p = head; READ * temp = NULL; char no[20], ch; int flag = 0; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━"); printf("**********************[删除读者信息]**************"); printf("━━━━━━━━━━━━━━━━\n\n\n"); printf("\n[输入删除读者的编号]·"); scanf("%s", no); while (p->next != NULL) { if ((strcmp(no, p->next->no)) == 0) { fflush(stdin); printf("[姓名]:%s\n", p->next->name); printf("[学号]:%s\n", p->next->no); printf("[密码]:%s\n", p->next->password); printf("[最大借阅额度]:%d\n\n", p->maxnum); printf("确定删除该读者\nY、确认\tN、取消\n"); scanf("%c", &ch); if (ch == 'y' || ch == 'Y') { temp = p->next; p->next = temp->next; free(temp); printf("\n----------------------[删除成功]-------------------------\n"); reader_save(head); flag++; } } else p = p->next; } if (flag == 0) printf("\n-------------------------[没有找到]-------------------------\n"); printf("\n按回车键返回···\n"); fflush(stdin); getchar(); reader_mgm(); } |
12、查询读者
利用学生编号,在链表中进行逐一查找。
//编号查询 void inquire_reader_no(READ * head) { READ * p = head->next; char no[20]; int flag = 0; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━"); printf("********************[编号查询]************************"); printf("━━━━━━━━━━━━━━━━━━━━\n\n\n"); printf("请输入想要查询的学生编号\n"); scanf("%s", no); for (; p != NULL; p = p->next) { if (strcmp(no, p->no) == 0) { flag = 1; printf("[姓名]:%s\n", p->name); printf("[学号]:%s\n", p->no); printf("[密码]:%s\n", p->password); printf("[最大借阅额度]:%d\n\n", p->maxnum); } } if (flag == 0) printf("没有找到!\n"); printf("\n按回车键返回···\n"); fflush(stdin); getchar(); reader_mgm(); } //姓名查询 void inquire_reader_name(READ * head) { READ * p = head->next; char name[30]; int flag = 0; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━"); printf("**********************[姓名查询]************************"); printf("━━━━━━━━━━━━━━━━━━━━━━━━━\n\n\n"); printf("请输入想要查询的学生姓名\n"); scanf("%s", name); for (; p != NULL; p = p->next) { if (strcmp(name, p->name) == 0) { flag = 1; printf("[姓名]:%s\n", p->name); printf("[学号]:%s\n", p->no); printf("[密码]:%s\n", p->password); printf("[最大借阅额度]:%d\n\n", p->maxnum); } } if (flag == 0) printf("没有找到!\n"); printf("\n按回车键返回···\n"); fflush(stdin); getchar(); reader_mgm(); } //查看所有读者 void inquire_reader_all(READ * head) { READ * p = head->next; windows(); system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━"); printf("**************[浏览图书信息]*******************"); printf("━━━━━━━━━━━━━━━━━━━━\n\n\n"); for (; p != NULL; p = p->next) { printf("[姓名]:%s\n", p->name); printf("[学号]:%s\n", p->no); printf("[密码]:%s\n", p->password); printf("[最大借阅额度]:%d\n\n", p->maxnum); printf("━━━━━━━━━━━━━━━━━━━━\n"); } printf("\n按回车键返回···\n"); fflush(stdin); getchar(); reader_mgm(); } |
13、读者登录和注册
//读者登录 void reader_login() { char no[20], password[16]; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━━━━━━━"); printf("****************[欢迎来到登录界面]******************"); printf("━━━━━━━━━━━━━━━━━━━━━━\n\n\n"); printf("━━━━━━━━━━━━━━━━━━━━━\n"); printf("\n\n [ 学号 ]:"); scanf("%s",no); printf("\n [ 密码 ]:"); scanf("%s", password); if (reader_enter(no, password)) { printf("\n\n------------------------[登录成功]--------------------------\n"); printf("\n\n 正在跳转请稍后······\n"); Sleep(1000); reader_windows(no); } else { printf("\n\n 正在跳转请稍后······\n"); Sleep(1000); menu_windows(); } } //检查登录信息是否正确 int reader_enter(char no[],char password[]) { READ * head = (READ *)malloc(sizeof(READ)); READ * p = NULL; memset(head, 0, sizeof(READ)); p = head; reader_read(head); for (; p != NULL; p = p->next) { if ((strcmp(no, p->no)) == 0 && strcmp(password, p->password) == 0) { return 1; } } printf("\n\n--------------------[用户名或密码错误]----------------------\n\n"); return 0; } //读者注册 void reader_registered(){ READ * newhead = (READ *)malloc(sizeof(READ)); READ * head = (READ *)malloc(sizeof(READ)); READ * p = head; memset(head, 0, sizeof(READ)); reader_read(head); memset(newhead, 0, sizeof(READ)); newhead->maxnum = 10; system("cls"); printf("\n"); printf("━━━━━━━━━━━━━━━━━━"); printf("****************[读者注册]*************************"); printf("━━━━━━━━━━━━\n\n\n"); printf("[请填写以下信息]\n\n"); printf("[姓名]:"); scanf("%s", newhead->name); printf("[学号]:"); scanf("%s", newhead->no); printf("[密码(少于16位)]:"); scanf("%s", newhead->password); for (; p != NULL; p = p->next) { if ((strcmp(newhead->no, p->no)) == 0 ) { printf("\n\n------------------[该用户已存在]------------------------\n"); Sleep(1000); reader_registered(); } } onereader_save(newhead); reader_login(); } |
四、调试分析
问题:
(1)管理员
1补办读书卡
2对图书借读日期进行管理
(2)读者
1图书丢失
2图书卡丢失
解决办法:
应该在结构体中增加新的属性,对其读书卡是否挂失和借读日期进行管理。
五、测试结果
(1)主菜单界面,结果如图5.1所示。
图5.1主菜单界面
按1则会出现管理员账户密码登录界面,结果如图5.2所示。
图5.2管理员账户密码登录界面
按2则会出现普通用户账户密码登录界面,结果如图5.3所示。
图5.3普通用户账户密码登录界面
输入3则会退出系统,结果如图5.4所示。
图5.4退出界面
- 管理员操作界面,结果如图5.5所示。
图5.5管理员操作界面
若输入1则会进入账号信息管理界面,结果如图5.6所示。
图5.6用户管理菜单界面
输入2则会进入图书管理界面,结果如图5.7所示。
图5.7图书信息管理菜单界面
输入3则进入读者管理界面,结果如图5.8所示。
图5.8读者信息管理饥饿面
(3)普通用户操作界面,结果如图5.9所示。
图5.9普通用户操作菜单界面
输入1借阅查询界面,结果如图5.10所示。
图5.10借阅查询界面
输入2则会进入图书借阅界面,结果如图5.11所示。
图5.11图书借阅界面
输入3则进入图书归还界面,结果如图5.12所示。
图5.12图书归还界面
六、课程心得总结
5天基本完成了图书信息管理系统,任务很紧,还好坚持了下来。虽然现在依然功能未能完善,逻辑上还有问题。但是总体的感受是,并没有想象中那样,困难到无法实现,收获真的很大。每一个小的功能可能都需要整个系统的逻辑来支撑,在完善过程中学习到了很多方法和知识。实现比较好看的界面设计和功能时,发觉枯燥中还是有很有趣的东西。一个系统不能只是随便添加功能,所有的限制条件都是考虑了用户操作时的各种可能性。这一点还体现在设计功能时需注重用户体验。操作方便简单易懂很重要,也要考虑到用户可能需要的各种功能以及安全性,比如密码最好不要明文。
这次实践使我更加熟练了链表的操作,链表的增删改查从逻辑上理解并不难,实践的时候有很多小细节需要注意。使用链表这种数据结构,其实也存在很多不足,遍历的效率有点低,这学期学了很多算法,其实都可以应用到这个系统上的,但是时间紧迫,任务很重,都没来得及,这是这个系统的一大遗憾。还有就是本来想学学c语言的图形化界面的,让界面更好看,但是时间有点赶,没来得及,这个暑假我学学c语言图形化界面,让这个系统更加完善。
期待系统的后续优化,使系统趋近于完美。
七、参考文献
[1] 甘勇,李晔,C语言程序设计(第二版),中国铁道出版社,2020.
[2] 何钦铭、颜辉,C语言程序设计(第4版),高等教育出版社,2020.
[3] 邹欣,构建之法(第三版)[M]. 北京:人民邮电出版社,2017.
[4] 严蔚敏,数据结构(C语言版),清华大学出版社,2021.
[5] 王珊、萨师煊,数据库系统概论(第5版),高等教育出版社,2014.
想要源码,点个关注,私信摸鱼哥即可(doge/手动狗头)