# 软件与编程大作业 **Repository Path**: BodanC/Soft_finalwork ## Basic Information - **Project Name**: 软件与编程大作业 - **Description**: No description available - **Primary Language**: C - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-01-15 - **Last Updated**: 2022-01-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 概述 * 开发环境:Visual studio code * 基本原理:C语言基础知识、数据结构中的链表、文件导入导出 * 需求说明:管理员账号:Admin,密码:AdminPassport ## 程序概要设计 本设计基本实现图书管理系统,可以为图书管理员和借阅者提供一定的管理和查询服务,具有很好的实际意义和用途,另外,**本程序具有较高的容错性,具体见程序细节设计**。 ### 已经实现的功能如下: * 图书数据信息导入和导出; * 图书管理员身份可以进行的操作: * * 录入:增加一本图书信息; * 删除:删除一本图书信息; * 修改:修改一本图书信息; * 查询:根据书名查询图书信息; * 借书:借出一本书,该书的借阅量增加一本; * 还书:还回一本书,该书的借阅量减少一本; * 统计:统计所有的借出的图书数目,即:所有图书借阅量之和; * 输出:输出所有图书的所有信息; * 读者身份可以进行的操作: * * 读者账号注册; * 查询:根据书名查询图书信息; * 借书:借出一本书,该书的借阅量增加一本; * 还书:还回一本书,该书的借阅量减少一本; * 输出:输出所有图书的所有信息; ### 未完成的操作及原因: * 排序:链表排序较复杂且实用性不高 ### 程序流程 1. 运行程序,导入图书数据信息,进入2; 2. 选择身份,选择图书管理员则进入3,选择读者进入6; 3. 输入管理员账号密码,正确进入4,错误进入3; 4. 选择图书管理员所要进行的操作,完成操作后进入5; 5. 是否继续?继续进入4,否则**退出程序**; 6. 选择读者所要进行的操作,完成操作后进入7; 7. 是否继续?继续进入6,否则**退出程序**; ## 程序细节设计 * 本设计采用有限状态机的思想,变量state表示当前状态,根据state的值进行相应操作,并将操作后的状态赋值给state,循环进行下一个操作,具体状态表示如下: ```C #define EXIT 0 #define INIT 1 #define ADMIN 2 #define READER 3 #define AD_ADD 4 #define AD_DELETE 5 #define AD_MODIFY 6 #define AD_ENQUIRE 7 #define AD_SORT 8 #define AD_BORROW 9 #define AD_RETURN 10 #define AD_COUNT 11 #define AD_PRINT 12 #define AD_COMFIRM 13 #define RE_ENQUIRE 14 #define RE_SORT 15 #define RE_BORROW 16 #define RE_RETURN 17 #define RE_COUNT 18 #define RE_PRINT 19 ``` * 在程序设计中利用宏定义以减少代码量 ```C #define PUTS1 \ { \ puts("\nAdmin Or Reader?"); \ puts("1:Admin"); \ puts("2:Reader"); \ puts("0:Exit"); \ } ``` * 图书信息和读者信息采用链表存储,结构体设计如下 ```C typedef struct _date //入库日期 { int year, month, day; } Date; typedef struct _book //图书信息 { char name[40], author[40], press[40]; Date intime; int stock, borrows; struct _book *next; } Book, *BookList; typedef struct _reader //读者信息 { char account[200], passport[200]; int all_borrows; struct _reader *next; } Reader, *ReaderList; ``` ### 图书信息导入和导出 使用文件指针和 `fscanf` 函数从文件 `book.dat` 中导入图书信息,在图书管理员选择打印操作时,先将所有的图书信息打印到屏幕上,再将新的图书信息导出到 `book.dat` 。在这个步骤中,用到了链表的遍历操作。 #### 导入操作如下 ```C while (1) { BookList p = (BookList)malloc(sizeof(Book)); if (fscanf(fp, "%s", p->name) == EOF) break; fscanf(fp, "%s%s%d-%d-%d%d%d", p->author, p->press, &p->intime.year, &p->intime.month, &p->intime.day, &p->stock, &p->borrows); p->next = NULL; if (q == NULL) //如果q是头节点 q = preq = p; else { preq->next = p; preq = p; } } puts("文件导入成功!\n\n"); ``` #### 导出操作如下 ```C FILE *fp; if (!(fp = fopen("book.dat", "w"))) puts("open error"); p = T; fprintf(fp, " Name Author Press Intime Stock Borrows\n"); while (p != NULL) { fprintf(fp, " %-10s %-10s %-10s %04d-%02d-%02d %-5d %-5d\n", p->name, p->author, p->press, p->intime.year, p->intime.month, p->intime.day, p->stock, p->borrows); p = p->next; } puts("成功导出到文件 book.dat! "); ``` 在导入导出操作中,利用格式化输出,导出文件清晰易懂,简洁大方,优雅美观 ### 欢迎界面 在运行本程序时,首先进入的是欢迎界面,用户将在欢迎界面选择图书管理员身份或者是读者身份,要求用户输入数字1或2或0,1表示图书管理员身份,2表示读者身份,0表示退出。 在这个过程中,我们增加了一定的容错性,当用户输入的不是数字或者非012的数字时,系统会提醒用户输入错误,这个过程通过如下判断实现 ```c while (scanf("%d", &op) != 1 || (op != 0 && op != 1 && op != 2)) { char laji[200]; fgets(laji, 200, stdin); puts("请输入数字!"); PUTS1 } ``` ### 录入 录入操作实际上是对链表增加一个节点的操作,将用户输入信息存储在一个结构体节点q中,然后判断链表T是否为空,是的话将q赋值给T,否则找到list的尾节点,将q加在T的后面 ```C if (p == NULL) return q; while (p->next != NULL) p = p->next; p->next = q; return T; ``` ### 删除 录入操作实际上是对链表删除一个节点的操作,输入需要删除的信息,遍历链表,找到该节点及其前继节点,实现删除操作 ```C if (p == T) //如果要删除的是头节点 return p->next; //返回头节点的下一个节点 q->next = p->next; //q是p的前继节点 free(p); return T; ``` ### 修改 录入操作实际上是对链表查找一个节点的操作,输入需要修改的信息,遍历链表,找到该节点,修改其信息 ### 查询 查询同样是对链表遍历的操作,从头节点出发,每次遍历一个节点后指针指向该节点的后一个节点,直到指向NULL ```C while (p != NULL) { if (strcmp(p->name, na) == 0) { flag = 1; break; } p = p->next; } ``` ### 借书、还书、统计 对链表的遍历操作,信息统计 ### 输出 遍历链表,对每一本图书的信息进行格式化输出,关键代码如下: ```C printf(" Name Author Press Intime Stock Borrows\n"); while (p != NULL) { printf(" %-10s %-10s %-10s %04d-%02d-%02d %-5d %-5d\n", p->name, p->author, p->press, p->intime.year, p->intime.month, p->intime.day, p->stock, p->borrows); p = p->next; } ``` ## 使用情况 ### 欢迎界面 ![1](img/1.png) ### 管理员登录 ![2](img/2.png) ### 读者登录 ![2](img/12.png) ### 登录错误提示 ![2](img/00.png) ### 操作错误提示 ![2](img/01.png) ### 录入图书信息 ![2](img/3.png) ### 删除图书信息 ![2](img/4.png) ### 修改图书信息 ![2](img/5.png) ### 查询图书信息 ![2](img/6.png) ### 借书 ![2](img/7.png) ### 还书 ![2](img/8.png) ### 统计 ![2](img/9.png) ### 输出 ![2](img/10.png) ![2](img/11.png) ## 总结 * 程序的优点:基本完成图书管理系统所要求的功能,基本没有代码错误,能够正常运行并实现相关功能、代码简洁易懂、程序运行界面大方;加入了一定的容错性考虑,加入了文件导入导出的功能,方便用户更好的查看数据; * 程序的缺点:未能实现排序的功能;由于链表不同于顺序表(中间位置节点的地址可以通过首位两个地址计算出来),因此只能进行顺序查找而不能进行二分查找,故对链表的排序并不能很大程度上提高查找的效率,而且排序的时间复杂度是O(n^2),并不适合多次调用此功能,因此省去了排序功能的实现; * 开发时遇到的困难:对于系统逻辑的处理,对于非规范输入的处理; * 解决方法:对于前一个困难,我们采取了有限状态机的思想,将系统划分为若干个状态,更加系统、逻辑地去处理每一个小问题;对于后者,我们增加了对于非规范输入的判断以及处理,使得程序的实用性更强。 * 总结:本次作业我们充分利用软件与编程所学知识实现了一个简单的图书管理系统,在编写的过程中难免遇到了一些问题,但是我们积极面对,迎难而上,查阅相关资料,请教学长,最后还是将问题一个个解决了。通过本次作业,大大增强了我们的程序设计、编码、调试和实践动手能力,大大提高了我们的编程水平。 ## 参考文献 无