图书管理系统(纯C语言)

  • 项目简介
    • 实现的功能
    • 后续
  • 开发环境和工具
  • 主要知识
    • 结构体
    • 链表
      • 创建链表
      • 链表的基本操作
        • 增(链表的插入)
        • 删(制定结点删除)
    • 冒泡排序
    • 文件操作
    • gdb调试
      • 调试过程
  • 源代码

项目简介

实现的功能

基本功能为增删查改,目前已实现的功能为:
0.退出系统
1.登记书籍
2.浏览书籍
3.借阅书籍
4.归还书籍
5.书籍排序
6.删除书籍
7.查找书籍

后续

用户管理,代码测试。

开发环境和工具

Ubuntu 20.04.4 LTS
VS Code

主要知识

结构体

在本项目中,创建了两个结构体,用于存放书籍信息和链表结点信息。
书籍信息

struct bookInfo
{int ISBN;char name[20];float price;int num;
};

链表结点信息

struct Node
{struct bookInfo data; // 数据域struct Node* Next;  //指针域,指向直接后继元素
};

链表

创建链表

链表基本知识
创建链表表头

struct Node* createHead()
{// 动态内存申请struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));// 初始化表头// headNode->data = 1; //头结点不存数据headNode->Next = NULL;return headNode;
}

创建结点,存储用户数据。

// 创建节点,为插入作准备
// 把用户的数据变为结构体变量
struct Node* createNode(struct bookInfo data)
{struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));newNode->data = data;newNode->Next = NULL;return newNode;
}

链表的基本操作

增(链表的插入)

选择一种插入方式即可。
表头法插入基本流程示意图。

void insertNodeByHead(struct Node* headNode, struct bookInfo data)
{struct Node *newNode = createNode(data);newNode->Next = headNode->Next;headNode->Next = newNode;
}

表尾法插入基本流程示意图。

// 表尾插入法,找表尾(pMove->Next = NULL时)
void insertNodeByTail(struct Node* headNode, struct bookInfo data)
{struct Node* pMove = headNode;while(pMove->Next != NULL){pMove = pMove->Next;}struct Node* newNode = createNode(data);pMove->Next = newNode;
}

删(制定结点删除)

按照书籍名进行删除。

// 找要删除的结点和前一个结点;posNode -->指的是要删除的目标节点
// posLeftNode->Next = posNode->Next;posNode->Next-->指的是删除结点的下一个结点
// free(posNode);
void deleteNodeByName(struct Node* headNode, char *bookName)
{struct Node* posLeftNode = headNode; //前一个结点struct Node* posNode = headNode->Next; //删除的结点//如果在当前结点没找到,两个指针都要往下走,此时的左节点即为当前结点,此时的当前结点就变为左结点的Nextwhile(posNode != NULL && strcmp(posNode->data.name,bookName)) {posLeftNode = posNode; //此时的左节点即为当前结点posNode = posLeftNode->Next; //此时的当前结点就变为左结点的Next}// 讨论查找的结果if(posNode == NULL){// printf("未找到");return;}else{posLeftNode->Next = posNode->Next;  //把删除结点的前一个结点和后一个结点连接起来。free(posNode);posNode = NULL;printf("删除成功!\n");}
}

按书籍名进行查找。

struct Node* searchByName(struct Node* headNode,char* bookName)
{struct Node* posNode = headNode->Next; //查找的结点while(posNode != NULL && strcmp(posNode->data.name,bookName)) {posNode =posNode->Next;}return posNode;
}

用户交互处进行查找的判断。

case 7:printf("【 查找 】\n");printf("请输入需要查找的书名:");scanf("%s",bookTemp.name);result = searchByName(list,bookTemp.name);if(result == NULL){printf("未找到相关信息!\n");}else{printf("ISBN\tname\tprice\tnum\n");printf("%d\t%s\t%.1f\t%d\n",result->data.ISBN,result->data.name,result->data.price,result->data.num);result = NULL;printf("查找成功!\n");}break;

这部分的代码,主要体现在借阅归还处。创建一个临时的结构体指针result用于存放查找的结果(struct Node* result = NULL;)。

case 3:printf("【 借阅 】\n");  // 书籍存在且数量不为0,可以借阅,数量-1;书籍不存在,借阅失败。printf("请输入借阅书籍的名字:\n");scanf("%s",bookTemp.name);result = searchByName(list,bookTemp.name);if(result == NULL){printf("没有书籍相关信息,无法借阅\n");}else{if(result->data.num == 0){printf("当前书籍数量为0,无法借阅\n");}else{printf("可以借阅\n");result->data.num--;}}saveInfoToFile("bookinfo.txt",list);break;case 4:printf("【 归还 】\n");  // 书籍数量+1。printf("请输入归还书籍的名字:\n");scanf("%s",bookTemp.name);result = searchByName(list,bookTemp.name);if(result == NULL){printf("该书籍来源非法\n");}else{printf("归还成功\n");result->data.num++;}saveInfoToFile("bookinfo.txt",list);break;

冒泡排序

// 冒泡排序
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 bookInfo tempData;tempData = q->data;q->data = q->Next->data;q->Next->data = tempData;}            }}
}

文件操作

// 文件操作
// 写操作
void saveInfoToFile(const char* fileName,struct Node* headNode)
{FILE* fp = fopen(fileName,"w");struct Node* pMove = headNode->Next;while(pMove != NULL){fprintf(fp,"%d\t%s\t%f\t%d\n",pMove->data.ISBN,pMove->data.name,pMove->data.price,pMove->data.num);pMove =pMove->Next;}fclose(fp);
}
// 读操作
void readInfoFromFile(const char* fileName,struct Node* headNode)
{FILE* fp = fopen(fileName,"r");  // 文件第一次打开不存在,就创建if(fp == NULL){fp = fopen(fileName,"w+");}// 创建一个临时变量储存从文件中读的信息,再插入到链表中struct bookInfo tempData;while(fscanf(fp,"%d\t%s\t%f\t%d\n",&tempData.ISBN,tempData.name,&tempData.price,&tempData.num) != EOF){insertNodeByHead(list,tempData);}fclose(fp);
}

gdb调试

在程序运行过程在出现里段错误(核心已转储)
最后发现是在动态内存申请时多打了一个sizeof导致的。
正确形式:

struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));

错误形式:

struct Node* headNode = (struct Node*)malloc(sizeof(sizeof(struct Node)));

调试过程

错误信息。

解决方法:输入以下命令查看程序core文件的大小。可以看到core文件的大小为0,这表明错误信息无法存入core文件。

ulimit -a

输入下列命令,修改core文件的大小为无限制。

ulimit -c unlimited

再次查看core文件大小,发现文件大小修改为unlimited
调用gdb进行调试。(我的core文件名就是core)
输入q退出gdb。

gcc -g ./图书管理系统.c -o ./图书管理系统
gdb 图书管理系统
core-file core
bt

源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>// 3.写数据// 3.1 程序怎样处理数据  --->链表// 3.2 数据的结构  --->图书信息struct bookInfo
{int ISBN;char name[20];float price;int num;
};struct Node
{struct bookInfo data; // 数据域struct Node* Next;  //指针域,指向直接后继元素
};
struct Node* list = NULL; //全局链表
// 创建表头,-->结构体变量
struct Node* createHead()
{// 动态内存申请struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));// 初始化表头// headNode->data = 1; //头结点不存数据headNode->Next = NULL;return headNode;
}// 创建节点,为插入作准备
// 把用户的数据变为结构体变量
struct Node* createNode(struct bookInfo data)
{struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));newNode->data = data;newNode->Next = NULL;return newNode;
}// 插入,只需要一种方式,这里是表头法插入,必须先连接后断开
void insertNodeByHead(struct Node* headNode, struct bookInfo data)
{struct Node *newNode = createNode(data);newNode->Next = headNode->Next;headNode->Next = newNode;
}
// 表尾插入法,找表尾(pMove->Next = NULL时)
// void insertNodeByTail(struct Node* headNode, struct bookInfo data)
// {//     struct Node* pMove = headNode;
//     while(pMove->Next != NULL)
//     {//         pMove = pMove->Next;
//     }
//     struct Node* newNode = createNode(data);
//     pMove->Next = newNode;
// }// 指定位置删除
// 找要删除的结点和前一个结点;posNode -->指的是要删除的目标节点
// posLeftNode->Next = posNode->Next;posNode->Next-->指的是删除结点的下一个结点
// free(posNode);
void deleteNodeByName(struct Node* headNode, char *bookName)
{struct Node* posLeftNode = headNode; //前一个结点struct Node* posNode = headNode->Next; //删除的结点//如果在当前结点没找到,两个指针都要往下走,此时的左节点即为当前结点,此时的当前结点就变为左结点的Nextwhile(posNode != NULL && strcmp(posNode->data.name,bookName)) {posLeftNode = posNode; //此时的左节点即为当前结点posNode = posLeftNode->Next; //此时的当前结点就变为左结点的Next}// 讨论查找的结果if(posNode == NULL){// printf("未找到");return;}else{posLeftNode->Next = posNode->Next;  //把删除结点的前一个结点和后一个结点连接起来。free(posNode);posNode = NULL;printf("删除成功!\n");}
}
// 查找
struct Node* searchByName(struct Node* headNode,char* bookName)
{struct Node* posNode = headNode->Next; //查找的结点while(posNode != NULL && strcmp(posNode->data.name,bookName)) {posNode =posNode->Next;}return posNode;
}// 打印
void printList(struct Node* headNode)
{struct Node* pMove = headNode->Next; //头结点不存数据printf("ISBN\tname\tprice\tnum\n");while(pMove != NULL) //链表地址不为空时打印数据,为空时,表示链表打印结束{printf("%d\t%s\t%.1f\t%d\n", pMove->data.ISBN,pMove->data.name,pMove->data.price,pMove->data.num);pMove = pMove->Next;}}// 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");
}// 文件操作
// 写操作
void saveInfoToFile(const char* fileName,struct Node* headNode)
{FILE* fp = fopen(fileName,"w");struct Node* pMove = headNode->Next;while(pMove != NULL){fprintf(fp,"%d\t%s\t%f\t%d\n",pMove->data.ISBN,pMove->data.name,pMove->data.price,pMove->data.num);pMove =pMove->Next;}fclose(fp);
}
// 读操作
void readInfoFromFile(const char* fileName,struct Node* headNode)
{FILE* fp = fopen(fileName,"r");  // 文件第一次打开不存在,就创建if(fp == NULL){fp = fopen(fileName,"w+");}// 创建一个临时变量储存从文件中读的信息,再插入到链表中struct bookInfo tempData;while(fscanf(fp,"%d\t%s\t%f\t%d\n",&tempData.ISBN,tempData.name,&tempData.price,&tempData.num) != EOF){insertNodeByHead(list,tempData);}fclose(fp);
}// 冒泡排序
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 bookInfo tempData;tempData = q->data;q->data = q->Next->data;q->Next->data = tempData;}            }}
}// 2.交互
void Key()
{int userKey =0;struct bookInfo bookTemp; //创建一个临时变量存储书籍信息。struct Node* result = NULL;scanf("%d", &userKey);switch (userKey){case 0:printf("【 退出 】\n");printf("退出成功\n");// getchar(); exit(0);  //关闭程序break;case 1:printf("【 登记 】\n");printf("输入书籍的信息(ISBN,name,price,num):");scanf("%d\t%s\t%f\t%d\n",&bookTemp.ISBN,bookTemp.name,&bookTemp.price,&bookTemp.num);insertNodeByHead(list,bookTemp);saveInfoToFile("bookinfo.txt",list); //每次登记完,将链表里的数据写到文件中break;case 2:printf("【 浏览 】\n");  //打印链表printList(list);break;case 3:printf("【 借阅 】\n");  // 书籍存在且数量不为0,可以借阅,数量-1;书籍不存在,借阅失败。printf("请输入借阅书籍的名字:\n");scanf("%s",bookTemp.name);result = searchByName(list,bookTemp.name);if(result == NULL){printf("没有书籍相关信息,无法借阅\n");}else{if(result->data.num == 0){printf("当前书籍数量为0,无法借阅\n");}else{printf("可以借阅\n");result->data.num--;}}saveInfoToFile("bookinfo.txt",list);break;case 4:printf("【 归还 】\n");  // 书籍数量+1。printf("请输入归还书籍的名字:\n");scanf("%s",bookTemp.name);result = searchByName(list,bookTemp.name);if(result == NULL){printf("该书籍来源非法\n");}else{printf("归还成功\n");result->data.num++;}saveInfoToFile("bookinfo.txt",list);break;case 5:printf("【 排序 】\n");bubbleSortList(list);printList(list);break;case 6:printf("【 删除 】\n");printf("请输入删除书籍的名字:");scanf("%s",bookTemp.name);deleteNodeByName(list,bookTemp.name);// 删除完成后,需要同步到文件(写操作)saveInfoToFile("bookinfo.txt",list);break;case 7:printf("【 查找 】\n");printf("请输入需要查找的书名:");scanf("%s",bookTemp.name);result = searchByName(list,bookTemp.name);if(result == NULL){printf("未找到相关信息!\n");}else{printf("ISBN\tname\tprice\tnum\n");printf("%d\t%s\t%.1f\t%d\n",result->data.ISBN,result->data.name,result->data.price,result->data.num);result = NULL;printf("查找成功!\n");}break;default:printf("【 ERROR 】\n");break;}
}int main()
{list =createHead();readInfoFromFile("bookinfo.txt", list); // 当系统运行时,将文件中的数据读到链表当中while (1){Menu();Key();//getchar();system("read");}getchar();return 0;}

图书管理系统(纯C语言)相关推荐

  1. 【C语言】以通讯录为例理解宿舍管理系统,图书管理系统完成C语言期末作业。源代码见文章末尾

    学完结构体来尝试写一个通讯录吧,以通讯录为例带你理解图书管理系统,宿舍管理系统解决C语言期末作业,需要基础的结构体与指针知识,基础的动态内存知识以及基础的文件操作知识. 源代码见文章末尾 1.理清思路 ...

  2. 基于B树的图书管理系统(C语言)(含完整代码)

    目录: 一.实现的设计要求 1.基本要求 2.额外选做要求 二.项目文件管理 三.完整代码 1.实现的接口 2.头文件 BTreeBook.h 全部代码 3.源文件 BTreeBook.cpp 全部代 ...

  3. 学校图书管理系统基于c语言源代码,基于C语言的学校图书管理系统参考.doc

    基于C语言的学校图书管理系统参考 本科学生毕业论文(设计) 题目(中 文):基于C语言的学校图书管理系统(英 文):School Library Management System Based on ...

  4. c语言课程设计图书管理系统报告,C语言图书管理系统课程设计报告[1]

    C语言图书管理系统课程设计报告[1] 第三章 图书管理系统的设计与实现3.1 系统的需求分析图书登记管理系统作为一个应用软件将为学校的老师和学生提供一个对学校图书馆深入了解并借阅.还书的平台.根据系统 ...

  5. 图书管理系统(Java语言)

    图书管理系统 程序介绍 实现思路和内容概括 代码实现 顺序表--bookList(书架)和book(书) book类: bookList类 操作--各种的操作类 IOperation接口 AddOpe ...

  6. 数据结构课程设计图书管理系统,C语言版。

    目录 一.功能描述 二.设计要求 三.实现的功能 四.代码 一.功能描述 设计一个图书管理程序满足图书馆基本业务需求. 二.设计要求 每种书的登记内容包括书号.书名.著作者.现存量和库存量等: 对书号 ...

  7. 图书管理系统(C语言)

    最近闲来无事,想着做出一个好看且互动性高的图书管理系统. 先上最后源码: #include<stdio.h> #include<string.h> #include<st ...

  8. 图书管理系统(c语言)功能比较全

    前提:最近看到蛮多链表的课设,然后发现其实都差不多,图书管理系统,学生信息等,然后把去年的学生信息管理系统改了改,改成图书管理系统 效果如下: ①界面 ②输入,不一定5个,最后####结尾就好,这里本 ...

  9. C语言图书管理系统注册功能,图书管理系统的c语言源程序

    /*****************************************************************************************/#include ...

  10. C语言图书管理系统验证码,C语言的图书管理系统

    #include #include #include #define SIZE 100 typedef struct { int isbn; //书号 char name[100];//书名 floa ...

最新文章

  1. 关于更清楚地了解.net的垃圾回收机制
  2. 会计的思考(38):会计--让业务做到心中有数,有真数
  3. REDIS的几个测试结果
  4. Oh-My-Zsh 操作 Git 的快捷键
  5. 【STM32】FreeRTOS创建和删除任务示例(静态方法)(了解)
  6. C# 运行控制台程序中文乱码
  7. 中科大计算机竞赛夺冠,中科大斩获全国唯一特等奖,力压清华捧得华为毕昇杯...
  8. ubuntu18常用软件安装设置
  9. php源码 乱码 通达oa_php中文乱码问题的终极解决方案汇总
  10. POJ 2942Knights of the Round Table(二分图判定+双连通分量)
  11. Informatic学习总结_day02_增量抽取
  12. 校园网\中心机房\拓扑图 思科模拟器(cisco)
  13. 菲尼克斯馈电隔离器 - MINI MCR-SL-RPS-I-I
  14. 五星大饭店续集剧情大放送(最新更新)
  15. 今天分享固态硬盘安装以及Win7系统安装流程
  16. MySQL8.0局域网共享
  17. 2020进博会霍尼韦尔特性材料和技术集团与七家企业签约项目
  18. IC卡和ID卡的区别
  19. Android开发之使用createFromStream加载图片发现图片变小
  20. 本地html文件显示不全,网页显示不全,详细教您网页显示不全怎么办

热门文章

  1. 伪漫迷用数据假装看了一遍《复联4》
  2. 【蓝桥杯省赛】冲刺练习题【枚举】倒计时【12】天
  3. php数独,php数独求解
  4. 卡塔尔是一个什么样的国家?
  5. 91、储存物品的火灾危险性分类
  6. python读excel中的sheet
  7. 统计字符串中汉字数目C++
  8. PHP DES加密解密类
  9. Android全面屏状态栏适配
  10. 【嵌入式系统】二、初识 Tiva TM4C123G系列开发板