C语言单链表实现图书管理系统源码解析

Felix
Felix
发布时间:2026-10-13| 4人浏览过
原创

本教程通过C语言中的单链表和结构体,构建一个具备增删改查功能的图书管理系统。核心在于利用链表动态管理书籍信息,并通过文件读写(fopen/fprintf/fscanf)实现数据的本地保存,确保程序重启后记录不丢失。

系统架构与基础设计

图书管理系统需要处理多个书籍对象,每个对象包含书名、价格和库存数量。采用单链表作为底层数据结构,相比静态数组,它可以动态分配内存,便于在运行时灵活增加或移除书籍节点。

第1步:定义数据结构

目的:明确数据存储格式和链表节点形态。

  • struct book:容器结构体,包含name(书名)、price(价格)和num(数量)。
  • struct Node:链表节点,包含上述数据域data和指向下一个节点的指针next。
struct book {
    char name[20];
    float price;
    int num;          //书的数量
};
//3 数据容器——链表
struct Node {
    struct book data;
    struct Node* next;
};

struct Node* headnode = NULL; //全局头指针

第2步:初始化与节点操作

目的:建立空链表并支持插入新节点。

创建表头:使用malloc动态申请空间,将next置为NULL,返回头结点指针。

struct Node* createlisthead() {
    struct Node* headnode = (struct Node*)malloc(sizeof(struct Node));
    if(headnode == NULL) return NULL;
    headnode->next = NULL;
    return headnode;
}

头插法新增节点:先创建新节点存放数据,调整指针方向(先连新节点后继,再连头节点),完成插入。

void insertbyhead(struct Node* headnode, struct book data) {
    struct Node* newnode = createnewnode(data);
    //必须先连后断,防止链表断裂
    newnode->next = headnode->next;
    headnode->next = newnode;
}

struct Node* createnewnode(struct book data) {
    struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
    newnode->data = data;
    newnode->next = NULL;
    return newnode;
}

核心功能实现

第3步:遍历与打印链表

目的:展示当前所有书籍信息。

从表头的next开始遍历,直到指针为NULL。注意格式化输出以对齐显示。

void printflist(struct Node* headnode) {
    struct Node* pmove = headnode->next;
    printf("书名\t价格\t数量\n");
    while (pmove != NULL) {
        printf("%s\t%.1f\t%d\n", pmove->data.name,
               pmove->data.price, pmove->data.num);
        pmove = pmove->next;
    }
    printf("\n");
}

第4步:查找与删除节点

目的:根据书名定位并移除特定书籍。

查找逻辑:遍历链表,若找到名称匹配节点则返回指针,否则返回NULL。

删除逻辑:需保留前驱节点(posleftnode)以便修改其next指针指向目标的后继节点,最后释放目标节点内存并置空,防止悬空指针。

void deletenodebyname(struct Node* headnode, char *bookname) {
    struct Node* posleftnode = headnode;
    struct Node* posnode = headnode->next;
    
    while (posnode != NULL && strcmp(posnode->data.name, bookname)) {
        posleftnode = posnode;
        posnode = posnode->next;
    }
    
    if (posnode == NULL) {
        printf("未找到数据\n");
        return;
    } else {
        posleftnode->next = posnode->next; //断开链接
        free(posnode);
        posnode = NULL;
        printflist(headnode); //删除后刷新界面
    }
}');

第5步:冒泡排序(按价格)

目的:对书籍列表进行降序或升序排列。

采用交换数据域的方式而非交换节点位置,因为本题结构中数据较小,交换内容效率更高且逻辑更简单。外层循环控制趟数,内层循环比较相邻元素。

void bubblesortlist(struct Node* headnode) {
    for (struct Node* p = headnode->next; p != NULL; p = p->next) {
        for (struct Node* q = headnode->next; q->next != NULL; q = q->next) {
            if (q->data.price > q->next->data.price) {
                // 交换数据而不是指针
                struct book tempdata = q->data;
                q->data = q->next->data;
                q->next->data = tempdata;
            }
        }
    }
    printflist(headnode);
}

数据持久化(文件存储)

若不保存数据,每次关闭控制台程序输入的信息将丢失。通过文件操作可以实现数据持久化。

第6步:文件写入操作

目的:将链表中的数据保存到book.txt文件中。

打开文件模式为"w"(覆盖写),遍历链表并使用fprintf逐个写入字段,保持制表符分隔以便后续读取。

void savefile(const char* filename, struct Node* headnode) {
    FILE* fp = fopen(filename, "w");
    if (fp == NULL) return; // 容错检查
    struct Node* pmove = headnode->next;
    while (pmove != NULL) {
        fprintf(fp, "%s\t%.1f\t%d\n", pmove->data.name, 
                pmove->data.price, pmove->data.num);
        pmove = pmove->next;
    }
    fclose(fp);
    fp = NULL;
}

第7步:文件读取操作

目的:启动时加载已有数据到链表。

尝试以"r"模式打开文件。如果文件不存在(返回NULL),则新建一个空文件"w+"。随后循环调用fscanf读取三元组,通过insertbyhead依次加入链表。注意读取时需用指针传递浮点数地址。

void readfile(const char *filename, struct Node* headnode) {
    FILE* fp = fopen(filename, "r");
    if (fp == NULL) {
        fp = fopen(filename, "w+"); // 无文件则创建
    }
    
    struct book tempdata;
    // fscanf 返回值等于字段数表示成功
    while (fscanf(fp, "%s\t%f\t%d\n", tempdata.name, 
                  &tempdata.price, &tempdata.num) != EOF) {
        insertbyhead(headnode, tempdata);
    }
    fclose(fp);
    fp = NULL;
}

交互逻辑整合

main函数流程:初始化链表头 -> 读取文件数据进入链表 -> 进入死循环等待菜单指令 -> 执行对应操作 -> 清屏。

借阅与归还逻辑细节

借阅时需判断是否存在该书籍且库存num > 0,成功后数量减1;归还需判断来源合法性(即书中是否真有此书),成功后数量加1。这两个操作不需要保存文件,仅在下次保存或退出时才落盘。

完整菜单控制代码

void menu() {
    printf("---------------------------------\n");
    printf("\t图书管理系统\n");
    printf("\t0.退出系统\n");
    printf("\t1.登记书籍\n");
    printf("\t2.浏览书籍\n");
    printf("\t3.借阅书籍\n");
    printf("\t4.归还书籍\n");
    printf("\t5.书籍排序\n");
    printf("\t6.删除书籍\n");
    printf("\t7.查找书籍\n");
    printf("---------------------------------\n");
    printf("请输入0~7\n");
}

int main() {
    headnode = createlisthead();
    readfile("book.txt", headnode); // 加载历史数据
    
    int input = 0;
    while (1) {
        system("cls"); // Windows下清屏
        menu();
        scanf("%d", &input);
        
        switch (input) {
            case 0:
                savefile("book.txt", headnode); // 退出前务必保存
                printf("【退出】\n退出成功\n");
                exit(0);
            case 1: { // 登记
                struct book tempbook;
                printf("输入书籍的信息(name,price,num): ");
                scanf("%s%f%d", tempbook.name, &tempbook.price, &tempbook.num);
                insertbyhead(headnode, tempbook);
                break;
            }
            case 2: printflist(headnode); break; // 浏览
            case 3: { // 借阅
                char name[20];
                printf("请输入要借阅的书名: ");
                scanf("%s", name);
                struct Node* res = searchbyname(headnode, name);
                if (!res || res->data.num <= 0) printf("无法借阅(无书或无库存)\n");
                else {
                    res->data.num--;
                    printf("借阅成功\n");
                }
                break;
            }
            case 4: { // 归还
                char name[20];
                printf("请输入要归还的书名: ");
                scanf("%s", name);
                struct Node* res = searchbyname(headnode, name);
                if (!res) printf("系统中无此书记录,来源非法\n");
                else {
                    res->data.num++;
                    printf("书籍归还成功!\n");
                }
                break;
            }
            case 5: bubblesortlist(headnode); break; // 排序
            case 6: { // 删除
                char name[20];
                printf("输入要删除的书名: ");
                scanf("%s", name);
                deletenodebyname(headnode, name);
                break;
            }
            case 7: { // 查找
                char name[20];
                printf("请输入要查找的书籍: ");
                scanf("%s", name);
                struct Node* res = searchbyname(headnode, name);
                if (!res) printf("未找到相关信息!\n");
                else {
                    printf("书名\t价格\t数量\n");
                    printf("%s\t%.1f\t%d\n", res->data.name, res->data.price, res->data.num);
                }
                break;
            }
            default: printf("选择错误\n");
        }
        system("pause");
    }
    return 0;
}

以上就是利用C语言单链表开发图书管理系统的详细内容,更多关于C语言链表编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。