- 系统功能分析
- 数据结构设计
- 模块化设计
- 完整源代码
- 代码编译与运行
- 系统扩展与优化建议
系统功能分析
一个基础的图书管理系统应具备以下核心功能:

(图片来源网络,侵删)
- 添加图书: 将新图书的信息(如ISBN、书名、作者、库存数量)录入系统。
- 删除图书: 根据ISBN号从系统中移除一本图书。
- 查找图书: 提供多种查找方式,例如按ISBN、按书名、按作者查找。
- 显示所有图书: 以列表形式展示系统中所有图书的信息。
- 借阅图书: 减少指定图书的库存数量。
- 归还图书: 增加指定图书的库存数量。
- 保存数据: 将图书信息保存到文件中,以便程序关闭后数据不丢失。
- 加载数据: 从文件中加载之前保存的图书信息。
数据结构设计
为了存储图书信息,我们需要一个自定义的结构体 Book。
// 图书结构体
typedef struct {
char isbn[20]; // ISBN号,作为唯一标识
char title[100]; // 书名
char author[50]; // 作者
int quantity; // 库存数量
} Book;
为了管理所有图书,我们将使用一个动态数组,动态数组的好处是可以在运行时根据需要调整大小,以容纳任意数量的图书。
// 图书管理系统结构体
typedef struct {
Book *books; // 指向图书动态数组的指针
int count; // 当前图书的数量
int capacity; // 当前动态数组的总容量
} LibrarySystem;
模块化设计
为了使代码结构清晰、易于维护,我们将把不同的功能封装成独立的函数。
| 函数模块 | 功能描述 |
|---|---|
| 初始化与销毁 | initSystem(): 初始化系统,分配内存。 freeSystem(): 释放系统内存,防止内存泄漏。 |
| 文件操作 | saveToFile(): 将所有图书数据保存到文件。 loadFromFile(): 从文件加载图书数据。 |
| 核心功能 | addBook(), deleteBook(), findBook(), displayAllBooks(), borrowBook(), returnBook() |
| 菜单与交互 | showMenu(): 显示主菜单。 main(): 程序入口,控制程序流程。 |
完整源代码
下面是完整的C语言源代码,您可以直接将其复制到 .c 文件(library.c)中编译运行。

(图片来源网络,侵删)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// --- 常量定义 ---
#define FILENAME "library.dat"
#define INITIAL_CAPACITY 10
#define ISBN_LEN 20
#define TITLE_LEN 100
#define AUTHOR_LEN 50
// --- 图书结构体 ---
typedef struct {
char isbn[ISBN_LEN];
char title[TITLE_LEN];
char author[AUTHOR_LEN];
int quantity;
} Book;
// --- 图书管理系统结构体 ---
typedef struct {
Book *books; // 指向图书动态数组的指针
int count; // 当前图书的数量
int capacity; // 当前动态数组的总容量
} LibrarySystem;
// --- 函数声明 ---
void initSystem(LibrarySystem *sys);
void freeSystem(LibrarySystem *sys);
void showMenu();
void addBook(LibrarySystem *sys);
void deleteBook(LibrarySystem *sys);
void findBook(const LibrarySystem *sys);
void displayAllBooks(const LibrarySystem *sys);
void borrowBook(LibrarySystem *sys);
void returnBook(LibrarySystem *sys);
void saveToFile(const LibrarySystem *sys);
void loadFromFile(LibrarySystem *sys);
void resizeLibrary(LibrarySystem *sys);
// --- 主函数 ---
int main() {
LibrarySystem sys;
initSystem(&sys);
// 尝试从文件加载数据
loadFromFile(&sys);
int choice;
do {
showMenu();
printf("请输入您的选择: ");
scanf("%d", &choice);
getchar(); // 清除输入缓冲区中的换行符
switch (choice) {
case 1: addBook(&sys); break;
case 2: deleteBook(&sys); break;
case 3: findBook(&sys); break;
case 4: displayAllBooks(&sys); break;
case 5: borrowBook(&sys); break;
case 6: returnBook(&sys); break;
case 7: saveToFile(&sys); printf("数据已保存!\n"); break;
case 0: printf("感谢使用,再见!\n"); break;
default: printf("无效的选择,请重新输入!\n");
}
} while (choice != 0);
// 退出前保存数据
saveToFile(&sys);
// 释放内存
freeSystem(&sys);
return 0;
}
// --- 函数实现 ---
/**
* @brief 初始化图书管理系统
* @param sys 指向图书管理系统的指针
*/
void initSystem(LibrarySystem *sys) {
sys->capacity = INITIAL_CAPACITY;
sys->count = 0;
// 为图书数组分配初始内存
sys->books = (Book *)malloc(sys->capacity * sizeof(Book));
if (sys->books == NULL) {
printf("内存分配失败!\n");
exit(1);
}
}
/**
* @brief 释放图书管理系统占用的内存
* @param sys 指向图书管理系统的指针
*/
void freeSystem(LibrarySystem *sys) {
free(sys->books);
sys->books = NULL;
sys->count = 0;
sys->capacity = 0;
}
/**
* @brief 显示系统菜单
*/
void showMenu() {
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");
}
/**
* @brief 添加图书
* @param sys 指向图书管理系统的指针
*/
void addBook(LibrarySystem *sys) {
// 检查是否需要扩容
if (sys->count >= sys->capacity) {
resizeLibrary(sys);
}
Book *newBook = &sys->books[sys->count];
printf("请输入图书ISBN: ");
scanf("%s", newBook->isbn);
getchar();
printf("请输入书名: ");
fgets(newBook->title, TITLE_LEN, stdin);
newBook->title[strcspn(newBook->title, "\n")] = 0; // 去除fgets读取的换行符
printf("请输入作者: ");
fgets(newBook->author, AUTHOR_LEN, stdin);
newBook->author[strcspn(newBook->author, "\n")] = 0;
printf("请输入库存数量: ");
scanf("%d", &newBook->quantity);
getchar();
sys->count++;
printf("图书添加成功!\n");
}
/**
* @brief 删除图书
* @param sys 指向图书管理系统的指针
*/
void deleteBook(LibrarySystem *sys) {
if (sys->count == 0) {
printf("图书馆中没有图书!\n");
return;
}
char isbn[ISBN_LEN];
printf("请输入要删除的图书ISBN: ");
scanf("%s", isbn);
getchar();
for (int i = 0; i < sys->count; i++) {
if (strcmp(sys->books[i].isbn, isbn) == 0) {
// 将最后一个元素移到被删除元素的位置
sys->books[i] = sys->books[sys->count - 1];
sys->count--;
printf("图书删除成功!\n");
return;
}
}
printf("未找到ISBN为 %s 的图书!\n", isbn);
}
/**
* @brief 查找图书
* @param sys 指向图书管理系统的指针
*/
void findBook(const LibrarySystem *sys) {
if (sys->count == 0) {
printf("图书馆中没有图书!\n");
return;
}
int choice;
printf("选择查找方式:\n");
printf(" 1. 按ISBN查找\n");
printf(" 2. 按书名查找\n");
printf(" 3. 按作者查找\n");
printf("请输入您的选择: ");
scanf("%d", &choice);
getchar();
char keyword[100];
printf("请输入关键词: ");
fgets(keyword, 100, stdin);
keyword[strcspn(keyword, "\n")] = 0;
int found = 0;
printf("\n--- 查找结果 ---\n");
for (int i = 0; i < sys->count; i++) {
int match = 0;
switch (choice) {
case 1: match = (strcmp(sys->books[i].isbn, keyword) == 0); break;
case 2: match = (strstr(sys->books[i].title, keyword) != NULL); break;
case 3: match = (strstr(sys->books[i].author, keyword) != NULL); break;
default: printf("无效的查找选项!\n"); return;
}
if (match) {
printf("ISBN: %s\n", sys->books[i].isbn);
printf("书名: %s\n", sys->books[i].title);
printf("作者: %s\n", sys->books[i].author);
printf("库存: %d\n", sys->books[i].quantity);
printf("-----------------\n");
found = 1;
}
}
if (!found) {
printf("未找到匹配的图书,\n");
}
}
/**
* @brief 显示所有图书
* @param sys 指向图书管理系统的指针
*/
void displayAllBooks(const LibrarySystem *sys) {
if (sys->count == 0) {
printf("图书馆中没有图书!\n");
return;
}
printf("\n--- 所有图书列表 (共 %d 本) ---\n", sys->count);
printf("%-15s %-30s %-20s %s\n", "ISBN", "书名", "作者", "库存");
printf("----------------------------------------------------------------\n");
for (int i = 0; i < sys->count; i++) {
printf("%-15s %-30s %-20s %d\n",
sys->books[i].isbn,
sys->books[i].title,
sys->books[i].author,
sys->books[i].quantity);
}
printf("----------------------------------------------------------------\n");
}
/**
* @brief 借阅图书
* @param sys 指向图书管理系统的指针
*/
void borrowBook(LibrarySystem *sys) {
if (sys->count == 0) {
printf("图书馆中没有图书!\n");
return;
}
char isbn[ISBN_LEN];
printf("请输入要借阅的图书ISBN: ");
scanf("%s", isbn);
getchar();
for (int i = 0; i < sys->count; i++) {
if (strcmp(sys->books[i].isbn, isbn) == 0) {
if (sys->books[i].quantity > 0) {
sys->books[i].quantity--;
printf("借阅成功! 当前库存: %d\n", sys->books[i].quantity);
} else {
printf("借阅失败! 该图书已无库存,\n");
}
return;
}
}
printf("未找到ISBN为 %s 的图书!\n", isbn);
}
/**
* @brief 归还图书
* @param sys 指向图书管理系统的指针
*/
void returnBook(LibrarySystem *sys) {
if (sys->count == 0) {
printf("图书馆中没有图书!\n");
return;
}
char isbn[ISBN_LEN];
printf("请输入要归还的图书ISBN: ");
scanf("%s", isbn);
getchar();
for (int i = 0; i < sys->count; i++) {
if (strcmp(sys->books[i].isbn, isbn) == 0) {
sys->books[i].quantity++;
printf("归还成功! 当前库存: %d\n", sys->books[i].quantity);
return;
}
}
printf("未找到ISBN为 %s 的图书!\n", isbn);
}
/**
* @brief 将数据保存到文件
* @param sys 指向图书管理系统的指针
*/
void saveToFile(const LibrarySystem *sys) {
FILE *fp = fopen(FILENAME, "wb"); // "wb" 表示以二进制写入模式
if (fp == NULL) {
printf("无法打开文件 %s 进行写入!\n", FILENAME);
return;
}
// 先写入图书的数量
fwrite(&sys->count, sizeof(int), 1, fp);
// 再写入所有图书数据
fwrite(sys->books, sizeof(Book), sys->count, fp);
fclose(fp);
}
/**
* @brief 从文件加载数据
* @param sys 指向图书管理系统的指针
*/
void loadFromFile(LibrarySystem *sys) {
FILE *fp = fopen(FILENAME, "rb"); // "rb" 表示以二进制读取模式
if (fp == NULL) {
// 文件不存在是正常情况(第一次运行)
return;
}
int count;
// 读取图书数量
fread(&count, sizeof(int), 1, fp);
// 根据数量调整系统容量
if (count > sys->capacity) {
sys->capacity = count;
resizeLibrary(sys);
}
// 读取所有图书数据
fread(sys->books, sizeof(Book), count, fp);
sys->count = count;
fclose(fp);
printf("成功从文件加载 %d 本图书,\n", count);
}
/**
* @brief 调整图书馆容量(扩容)
* @param sys 指向图书管理系统的指针
*/
void resizeLibrary(LibrarySystem *sys) {
int new_capacity = sys->capacity * 2;
Book *new_books = (Book *)realloc(sys->books, new_capacity * sizeof(Book));
if (new_books == NULL) {
printf("内存重新分配失败!\n");
exit(1);
}
sys->books = new_books;
sys->capacity = new_capacity;
printf("图书馆已扩容至 %d,\n", new_capacity);
}
代码编译与运行
- 保存代码: 将上述代码保存为
library.c文件。 - 打开终端/命令行:
- 在 Windows 上,可以使用 CMD 或 PowerShell。
- 在 macOS 或 Linux 上,可以使用 Terminal。
- 编译代码: 使用 GCC 编译器进行编译。
gcc library.c -o library
gcc: GCC 编译器的命令。library.c: 你的源文件名。-o library: 指定输出的可执行文件名为library(在 Windows 上会是library.exe)。
- 运行程序:
- Windows:
library.exe
- macOS / Linux:
./library
- Windows:
程序运行后,会生成一个名为 library.dat 的文件,用于持久化存储数据。
系统扩展与优化建议
这个基础版本已经可以很好地工作,但如果你想进一步学习和提升,可以考虑以下扩展:
-
用户管理:
- 创建一个
User结构体,包含用户ID、姓名、借阅的图书列表等。 - 实现用户注册、登录、查看借阅历史等功能。
- 借阅时需要关联到特定用户,并限制每个用户的最大借阅数量。
- 创建一个
-
更强大的数据持久化:
(图片来源网络,侵删)- 使用CSV/文本文件: 将数据保存为人类可读的文本格式(如CSV),方便用Excel等工具查看和编辑,这比二进制文件更灵活,但解析稍慢。
- 使用数据库: 对于更复杂的系统,可以考虑使用SQLite这样的嵌入式数据库,它提供了SQL查询、索引、事务等强大功能,能极大地提升数据管理的效率和可靠性。
-
改进用户界面:
- 使用
ncurses(Linux/macOS) 或conio.h(Windows, 非标准) 等库来创建更美观的基于终端的图形界面(TUI),如彩色文本、窗口、按钮等。
- 使用
-
代码健壮性:
- 输入验证: 对所有用户输入进行更严格的验证,确保库存数量是正整数,ISBN格式正确等。
- 错误处理: 增加更完善的错误处理机制,当文件读写失败或内存分配失败时,提供更友好的错误信息并尝试恢复。
-
功能增强:
- 图书分类: 为
Book结构体增加一个category(分类) 字段,如“文学”、“科学”、“计算机”等,并支持按分类查找和统计。 - 排序功能: 支持按书名、作者、入库时间等对图书列表进行排序。
- 统计报表: 实现功能,如“最受欢迎的图书”、“库存不足的图书”等统计报表。
- 图书分类: 为
这个项目是学习C语言指针、结构体、文件操作、动态内存管理的绝佳实践,希望这个详细的设计和代码对你有帮助!
