fork download
  1. /* ============================================================
  2.  * 图书管理系统(链表 + 结构体)
  3.  * 功能:增加 / 按书名查询 / 按出版社查询 / 按书名删除 /
  4.  * 按出版社删除 / 显示全部 / 借还登记
  5.  * 编译:gcc book.c -o book
  6.  * ============================================================ */
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. /* ---------- 状态枚举 ---------- */
  13. typedef enum {
  14. STATUS_RETURNED = 0, // 已归还(在馆)
  15. STATUS_BORROWED = 1 // 已借出
  16. } BookStatus;
  17.  
  18. /* ---------- 图书结构体(链表节点) ---------- */
  19. typedef struct Book {
  20. char title[50]; // 书名
  21. char publisher[50]; // 出版社
  22. char borrow_date[20]; // 借出时间
  23. char return_date[20]; // 归还时间
  24. BookStatus status; // 当前状态
  25. struct Book *next; // 下一节点
  26. } Book;
  27.  
  28. Book *head = NULL; // 链表头指针
  29.  
  30. /* ============================================================
  31.  * 输入工具:读一整行并去掉换行
  32.  * ============================================================ */
  33. void read_line(char *buf, size_t size) {
  34. if (fgets(buf, (int)size, stdin) == NULL) {
  35. buf[0] = '\0';
  36. return;
  37. }
  38. if (strchr(buf, '\n') == NULL) { // 输入超长,清掉残留
  39. int c;
  40. while ((c = getchar()) != '\n' && c != EOF) { }
  41. } else {
  42. buf[strcspn(buf, "\n")] = '\0'; // 去掉换行
  43. }
  44. }
  45.  
  46. /* 状态转中文 */
  47. const char *status_text(BookStatus s) {
  48. return (s == STATUS_BORROWED) ? "借出" : "归还";
  49. }
  50.  
  51. /* 表头 */
  52. void print_header(void) {
  53. printf("%-16s %-18s %-12s %-12s %-4s\n",
  54. "书名", "出版社", "借出时间", "归还时间", "状态");
  55. printf("--------------------------------------------------------------------\n");
  56. }
  57.  
  58. /* 打印一行图书信息 */
  59. void print_book(Book *b) {
  60. printf("%-16s %-18s %-12s %-12s %-4s\n",
  61. b->title, b->publisher,
  62. b->borrow_date, b->return_date,
  63. status_text(b->status));
  64. }
  65.  
  66. /* ============================================================
  67.  * 1. 增加图书(尾插,保持添加顺序)
  68.  * ============================================================ */
  69. void add_book(void) {
  70. Book *b = (Book *)malloc(sizeof(Book));
  71. if (b == NULL) {
  72. printf("内存分配失败!\n");
  73. return;
  74. }
  75.  
  76. printf("书名: ");
  77. read_line(b->title, sizeof(b->title));
  78. if (b->title[0] == '\0') {
  79. printf("书名不能为空!\n");
  80. free(b);
  81. return;
  82. }
  83.  
  84. printf("出版社: ");
  85. read_line(b->publisher, sizeof(b->publisher));
  86.  
  87. printf("借出时间(如 2024-05-01,可为 -): ");
  88. read_line(b->borrow_date, sizeof(b->borrow_date));
  89.  
  90. printf("归还时间(如 2024-06-01,可为 -): ");
  91. read_line(b->return_date, sizeof(b->return_date));
  92.  
  93. char line[16];
  94. printf("状态(0=归还/在馆, 1=借出): ");
  95. read_line(line, sizeof(line));
  96. b->status = (atoi(line) == 1) ? STATUS_BORROWED : STATUS_RETURNED;
  97.  
  98. /* 尾插 */
  99. b->next = NULL;
  100. if (head == NULL) {
  101. head = b;
  102. } else {
  103. Book *p = head;
  104. while (p->next != NULL) p = p->next;
  105. p->next = b;
  106. }
  107. printf("添加成功!\n");
  108. }
  109.  
  110. /* ============================================================
  111.  * 2. 按书名查询(模糊匹配)
  112.  * ============================================================ */
  113. void search_by_title(void) {
  114. char key[50];
  115. printf("输入书名关键字: ");
  116. read_line(key, sizeof(key));
  117.  
  118. int count = 0;
  119. print_header();
  120. for (Book *p = head; p != NULL; p = p->next) {
  121. if (strstr(p->title, key) != NULL) { // 子串匹配
  122. print_book(p);
  123. count++;
  124. }
  125. }
  126. printf("共找到 %d 本图书\n", count);
  127. }
  128.  
  129. /* ============================================================
  130.  * 3. 按出版社查询(模糊匹配)
  131.  * ============================================================ */
  132. void search_by_publisher(void) {
  133. char key[50];
  134. printf("输入出版社关键字: ");
  135. read_line(key, sizeof(key));
  136.  
  137. int count = 0;
  138. print_header();
  139. for (Book *p = head; p != NULL; p = p->next) {
  140. if (strstr(p->publisher, key) != NULL) {
  141. print_book(p);
  142. count++;
  143. }
  144. }
  145. printf("共找到 %d 本图书\n", count);
  146. }
  147.  
  148. /* ============================================================
  149.  * 4. 删除:通用逻辑 + 匹配函数
  150.  * 删除所有匹配节点,返回删除数量
  151.  * ============================================================ */
  152.  
  153. /* 按书名精确匹配 */
  154. int match_title(Book *b, const char *key) {
  155. return strcmp(b->title, key) == 0;
  156. }
  157.  
  158. /* 按出版社精确匹配 */
  159. int match_publisher(Book *b, const char *key) {
  160. return strcmp(b->publisher, key) == 0;
  161. }
  162.  
  163. /* 通用删除:遍历链表删除所有匹配项
  164.  * match 是函数指针,决定按书名还是按出版社匹配 */
  165. int delete_books(int (*match)(Book *, const char *), const char *key) {
  166. Book *prev = NULL; // 前驱
  167. Book *cur = head; // 当前
  168. int count = 0;
  169.  
  170. while (cur != NULL) {
  171. if (match(cur, key)) {
  172. Book *del = cur;
  173. if (prev == NULL) { // 删头节点
  174. head = cur->next;
  175. } else { // 删中间/尾节点
  176. prev->next = cur->next;
  177. }
  178. cur = cur->next; // 前进
  179. free(del); // 释放
  180. count++;
  181. } else { // 不匹配才移动 prev
  182. prev = cur;
  183. cur = cur->next;
  184. }
  185. }
  186. return count;
  187. }
  188.  
  189. /* 按书名删除 */
  190. void delete_by_title(void) {
  191. char key[50];
  192. printf("输入要删除的书名(需完整): ");
  193. read_line(key, sizeof(key));
  194.  
  195. int n = delete_books(match_title, key);
  196. if (n > 0) printf("已删除 %d 本图书\n", n);
  197. else printf("未找到该书\n");
  198. }
  199.  
  200. /* 按出版社删除 */
  201. void delete_by_publisher(void) {
  202. char key[50];
  203. printf("输入要删除的出版社(需完整): ");
  204. read_line(key, sizeof(key));
  205.  
  206. int n = delete_books(match_publisher, key);
  207. if (n > 0) printf("已删除 %d 本图书\n", n);
  208. else printf("未找到该出版社的图书\n");
  209. }
  210.  
  211. /* ============================================================
  212.  * 5. 显示全部
  213.  * ============================================================ */
  214. void list_books(void) {
  215. if (head == NULL) {
  216. printf("暂无图书\n");
  217. return;
  218. }
  219. print_header();
  220. for (Book *p = head; p != NULL; p = p->next) {
  221. print_book(p);
  222. }
  223. }
  224.  
  225. /* ============================================================
  226.  * 6. 借出 / 归还登记
  227.  * ============================================================ */
  228. void change_status(void) {
  229. char title[50];
  230. printf("输入书名: ");
  231. read_line(title, sizeof(title));
  232.  
  233. /* 按书名精确查找 */
  234. Book *p = head;
  235. while (p != NULL && strcmp(p->title, title) != 0) p = p->next;
  236. if (p == NULL) {
  237. printf("未找到该书\n");
  238. return;
  239. }
  240.  
  241. char line[16];
  242. printf("1=借出 0=归还: ");
  243. read_line(line, sizeof(line));
  244.  
  245. if (atoi(line) == 1) {
  246. p->status = STATUS_BORROWED;
  247. printf("借出时间: ");
  248. read_line(p->borrow_date, sizeof(p->borrow_date));
  249. } else {
  250. p->status = STATUS_RETURNED;
  251. printf("归还时间: ");
  252. read_line(p->return_date, sizeof(p->return_date));
  253. }
  254. printf("状态已更新\n");
  255. }
  256.  
  257. /* ============================================================
  258.  * 7. 释放链表
  259.  * ============================================================ */
  260. void free_all(void) {
  261. Book *p = head;
  262. while (p != NULL) {
  263. Book *next = p->next; // 先存 next,再 free
  264. free(p);
  265. p = next;
  266. }
  267. head = NULL;
  268. }
  269.  
  270. /* ============================================================
  271.  * 主菜单 & main
  272.  * ============================================================ */
  273. void menu(void) {
  274. printf("\n========== 图书管理系统 ==========\n");
  275. printf(" 1. 增加图书\n");
  276. printf(" 2. 按书名查询\n");
  277. printf(" 3. 按出版社查询\n");
  278. printf(" 4. 按书名删除\n");
  279. printf(" 5. 按出版社删除\n");
  280. printf(" 6. 显示全部\n");
  281. printf(" 7. 借出/归还登记\n");
  282. printf(" 0. 退出\n");
  283. printf("==================================\n");
  284. printf("请选择: ");
  285. }
  286.  
  287. int main(void) {
  288. char line[32];
  289. while (1) {
  290. menu();
  291. read_line(line, sizeof(line)); // 统一按行读
  292. int choice = atoi(line);
  293.  
  294. switch (choice) {
  295. case 1: add_book(); break;
  296. case 2: search_by_title(); break;
  297. case 3: search_by_publisher(); break;
  298. case 4: delete_by_title(); break;
  299. case 5: delete_by_publisher(); break;
  300. case 6: list_books(); break;
  301. case 7: change_status(); break;
  302. case 0:
  303. free_all();
  304. printf("再见!\n");
  305. return 0;
  306. default:
  307. printf("无效选项,请重新输入\n");
  308. }
  309. }
  310. return 0;
  311. }
Success #stdin #stdout 0s 5344KB
stdin
Standard input is empty
stdout
========== 图书管理系统 ==========
 1. 增加图书
 2. 按书名查询
 3. 按出版社查询
 4. 按书名删除
 5. 按出版社删除
 6. 显示全部
 7. 借出/归还登记
 0. 退出
==================================
请选择: 再见!