/* ============================================================
* 图书管理系统(链表 + 结构体)
* 功能:增加 / 按书名查询 / 按出版社查询 / 按书名删除 /
* 按出版社删除 / 显示全部 / 借还登记
* 编译:gcc book.c -o book
* ============================================================ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ---------- 状态枚举 ---------- */
typedef enum {
STATUS_RETURNED = 0, // 已归还(在馆)
STATUS_BORROWED = 1 // 已借出
} BookStatus;
/* ---------- 图书结构体(链表节点) ---------- */
typedef struct Book {
char title[50]; // 书名
char publisher[50]; // 出版社
char borrow_date[20]; // 借出时间
char return_date[20]; // 归还时间
BookStatus status; // 当前状态
struct Book *next; // 下一节点
} Book;
Book *head = NULL; // 链表头指针
/* ============================================================
* 输入工具:读一整行并去掉换行
* ============================================================ */
void read_line(char *buf, size_t size) {
if (fgets(buf, (int)size, stdin) == NULL) {
buf[0] = '\0';
return;
}
if (strchr(buf, '\n') == NULL) { // 输入超长,清掉残留
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
} else {
buf[strcspn(buf, "\n")] = '\0'; // 去掉换行
}
}
/* 状态转中文 */
const char *status_text(BookStatus s) {
return (s == STATUS_BORROWED) ? "借出" : "归还";
}
/* 表头 */
void print_header(void) {
printf("%-16s %-18s %-12s %-12s %-4s\n",
"书名", "出版社", "借出时间", "归还时间", "状态");
printf("--------------------------------------------------------------------\n");
}
/* 打印一行图书信息 */
void print_book(Book *b) {
printf("%-16s %-18s %-12s %-12s %-4s\n",
b->title, b->publisher,
b->borrow_date, b->return_date,
status_text(b->status));
}
/* ============================================================
* 1. 增加图书(尾插,保持添加顺序)
* ============================================================ */
void add_book(void) {
Book *b = (Book *)malloc(sizeof(Book));
if (b == NULL) {
printf("内存分配失败!\n");
return;
}
printf("书名: ");
read_line(b->title, sizeof(b->title));
if (b->title[0] == '\0') {
printf("书名不能为空!\n");
free(b);
return;
}
printf("出版社: ");
read_line(b->publisher, sizeof(b->publisher));
printf("借出时间(如 2024-05-01,可为 -): ");
read_line(b->borrow_date, sizeof(b->borrow_date));
printf("归还时间(如 2024-06-01,可为 -): ");
read_line(b->return_date, sizeof(b->return_date));
char line[16];
printf("状态(0=归还/在馆, 1=借出): ");
read_line(line, sizeof(line));
b->status = (atoi(line) == 1) ? STATUS_BORROWED : STATUS_RETURNED;
/* 尾插 */
b->next = NULL;
if (head == NULL) {
head = b;
} else {
Book *p = head;
while (p->next != NULL) p = p->next;
p->next = b;
}
printf("添加成功!\n");
}
/* ============================================================
* 2. 按书名查询(模糊匹配)
* ============================================================ */
void search_by_title(void) {
char key[50];
printf("输入书名关键字: ");
read_line(key, sizeof(key));
int count = 0;
print_header();
for (Book *p = head; p != NULL; p = p->next) {
if (strstr(p->title, key) != NULL) { // 子串匹配
print_book(p);
count++;
}
}
printf("共找到 %d 本图书\n", count);
}
/* ============================================================
* 3. 按出版社查询(模糊匹配)
* ============================================================ */
void search_by_publisher(void) {
char key[50];
printf("输入出版社关键字: ");
read_line(key, sizeof(key));
int count = 0;
print_header();
for (Book *p = head; p != NULL; p = p->next) {
if (strstr(p->publisher, key) != NULL) {
print_book(p);
count++;
}
}
printf("共找到 %d 本图书\n", count);
}
/* ============================================================
* 4. 删除:通用逻辑 + 匹配函数
* 删除所有匹配节点,返回删除数量
* ============================================================ */
/* 按书名精确匹配 */
int match_title(Book *b, const char *key) {
return strcmp(b->title, key) == 0;
}
/* 按出版社精确匹配 */
int match_publisher(Book *b, const char *key) {
return strcmp(b->publisher, key) == 0;
}
/* 通用删除:遍历链表删除所有匹配项
* match 是函数指针,决定按书名还是按出版社匹配 */
int delete_books(int (*match)(Book *, const char *), const char *key) {
Book *prev = NULL; // 前驱
Book *cur = head; // 当前
int count = 0;
while (cur != NULL) {
if (match(cur, key)) {
Book *del = cur;
if (prev == NULL) { // 删头节点
head = cur->next;
} else { // 删中间/尾节点
prev->next = cur->next;
}
cur = cur->next; // 前进
free(del); // 释放
count++;
} else { // 不匹配才移动 prev
prev = cur;
cur = cur->next;
}
}
return count;
}
/* 按书名删除 */
void delete_by_title(void) {
char key[50];
printf("输入要删除的书名(需完整): ");
read_line(key, sizeof(key));
int n = delete_books(match_title, key);
if (n > 0) printf("已删除 %d 本图书\n", n);
else printf("未找到该书\n");
}
/* 按出版社删除 */
void delete_by_publisher(void) {
char key[50];
printf("输入要删除的出版社(需完整): ");
read_line(key, sizeof(key));
int n = delete_books(match_publisher, key);
if (n > 0) printf("已删除 %d 本图书\n", n);
else printf("未找到该出版社的图书\n");
}
/* ============================================================
* 5. 显示全部
* ============================================================ */
void list_books(void) {
if (head == NULL) {
printf("暂无图书\n");
return;
}
print_header();
for (Book *p = head; p != NULL; p = p->next) {
print_book(p);
}
}
/* ============================================================
* 6. 借出 / 归还登记
* ============================================================ */
void change_status(void) {
char title[50];
printf("输入书名: ");
read_line(title, sizeof(title));
/* 按书名精确查找 */
Book *p = head;
while (p != NULL && strcmp(p->title, title) != 0) p = p->next;
if (p == NULL) {
printf("未找到该书\n");
return;
}
char line[16];
printf("1=借出 0=归还: ");
read_line(line, sizeof(line));
if (atoi(line) == 1) {
p->status = STATUS_BORROWED;
printf("借出时间: ");
read_line(p->borrow_date, sizeof(p->borrow_date));
} else {
p->status = STATUS_RETURNED;
printf("归还时间: ");
read_line(p->return_date, sizeof(p->return_date));
}
printf("状态已更新\n");
}
/* ============================================================
* 7. 释放链表
* ============================================================ */
void free_all(void) {
Book *p = head;
while (p != NULL) {
Book *next = p->next; // 先存 next,再 free
free(p);
p = next;
}
head = NULL;
}
/* ============================================================
* 主菜单 & main
* ============================================================ */
void menu(void) {
printf("\n========== 图书管理系统 ==========\n");
printf(" 1. 增加图书\n");
printf(" 2. 按书名查询\n");
printf(" 3. 按出版社查询\n");
printf(" 4. 按书名删除\n");
printf(" 5. 按出版社删除\n");
printf(" 6. 显示全部\n");
printf(" 7. 借出/归还登记\n");
printf(" 0. 退出\n");
printf("==================================\n");
printf("请选择: ");
}
int main(void) {
char line[32];
while (1) {
menu();
read_line(line, sizeof(line)); // 统一按行读
int choice = atoi(line);
switch (choice) {
case 1: add_book(); break;
case 2: search_by_title(); break;
case 3: search_by_publisher(); break;
case 4: delete_by_title(); break;
case 5: delete_by_publisher(); break;
case 6: list_books(); break;
case 7: change_status(); break;
case 0:
free_all();
printf("再见!\n");
return 0;
default:
printf("无效选项,请重新输入\n");
}
}
return 0;
}