c语言实现图书管理系统,未成熟版
一、目的
创建一个图书管理系统,进行添加、删除,查询,借书,还书,退出,等等操作;使用菜单以实现功能选择模块。
二、C语言图书管理系统包括以下功能:
0. 退出信息系统
1. 登记书籍信息
2. 浏览书籍查询
3. 借阅书籍
4. 归还书籍
5.删除书籍
6.查找书籍
三、流程图
四、代码块
/*定义#define _CRT_SECURE_NO_WARNINGS,
我们在编译老的用C语言的开源项目如lua源包的时候,
可能因为一些老的.c文件使用了strcpy,scanf等不安全的函数,
而报警告和错误,而导致无法编译通过。*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h> //数据的设计
#include <string.h>
//3.数据的设计
//3.1程序用什么东西处理数据(数组或链表)--->选择链表
//3.2数据的结构(图书的信息)
//图书信息
struct bookInfo
{
char name[20]; //名字
float price; //价格
int num; //数量
};
struct Node //Node节点
{
struct bookInfo data; //链表里存的struct bookInfo类型
struct Node* next;
};
struct Node* list = NULL; //更改为全局的列表为空,然后在主函数那初始化
//创建表头:表头就是一个结构体变量
struct Node* createHead()
{
/*动态内存申请
sizeof(struct node)就是求 struct node 这个结构体占用的字节数。
malloc(sizeof(struct node))申请 struct node 这个结构体占用字节数大小的空间
(struct node *) malloc(sizeof(struct node))将申请的空间的地址强制转化为 struct node * 指针类型
headNade=(struct node *) malloc(sizeof(struct node))将那个强制转化的地址赋值给 headNade.
*/
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//变量的基本规则:使用前必须初始化,在这里只需要给next指针初始化,表头不需要存储数据,所以不用初始化
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的指针域指向下一个结点(地址)
headNode->next = newNode; // 原表头指向新建的结点(地址)
}
//指定位置删除
//posLeftNode->next=posNode->next;相邻指针
//free(posNode);指定删除的代码,删除完后要把posNode=NULL
void deleteNodeByName(struct Node* headNode,char *bookName) //通过书籍名字进行删除
{
/*需要两个指针进行删除,先删除节点指针的Left左边,其次再删除节点指针的右边,一前一后*/
struct Node* posLeftNode = headNode;
struct Node* posNode = headNode->next;
/*书籍名字是字符串,所以要使用字符串比较函数处理
当我们删除节点不等于空,
并且使用strcmp()比较,
使用posNode->data.name和我们传过来的参数bookName进行比较*/
while(posNode != NULL && strcmp(posNode->data.name,bookName))
{
/*让节点并排往下走*/
posLeftNode = posNode;
posNode = posLeftNode->next;
}
//讨论查找结果,如果posNode为空,那就是没有找到,无法删除,找到就删除
if(posNode == NULL)
return;
else
{
printf("删除成功!\n");
posLeftNode->next = posNode->next;
free(posNode);
posNode = NULL;
}
}
//添加链表的查找函数,把找到的节点给它返回
struct Node* searchByName(struct Node* headNode,char *bookName)
{
//只需要找到那个节点即可,不需要两个指针
struct Node* posNode = headNode->next;
while(posNode != NULL && strcmp(posNode->data.name,bookName)) //strcmp()比较括号里面的,如果相等,就退出循环,如果不等,那就执行循环
{
posNode = posNode->next;
}
return posNode;
}
//打印链表
void printList(struct Node* headNode)
{
/*定义一个移动的指针pMove从第二个节点headNode->next开始打印*/
struct Node* pMove = headNode->next;
printf("书名\t价格\t数量\n"); //表头
while(pMove != NULL) // pMove不等于空的时候,打印节点的数据
{
//剥洋葱,一层一层
printf("%s\t%0.1f\t%d\n", pMove->data.name, pMove->data.price, pMove->data.num); //让pMove往下一个节点走
pMove = pMove->next;
}
}
//1.写界面--->菜单--->模块
void makeMenu()
{
printf("\t \n");
printf("\t┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n");
printf("\t┃ ╔══════════════════════════════════════════════════════════╗ ┃\n");
printf("\t┃ ║ 欢 迎 使 用 图 书 管 理 信 息 系 统 ║ ┃\n");
printf("\t┃ ╚══════════════════════════════════════════════════════════╝ ┃\n");
printf("\t┃ *********************************************************** ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ * 0.退出信息系统 * 1.登记书籍信息 * ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ *********************************************************** ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ * 2.浏览书籍查询 * 3.借阅书籍 * ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ *********************************************************** ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ * 4.归还书籍 * 5.删除书籍 * ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ *********************************************************** ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ * 6.查找书籍 * * ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ * * * ┃\n");
printf("\t┃ *********************************************************** ┃\n");
printf("\t┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n");
printf("请输入0-8:");
}
//文件存操作
void saveInfoToFile(const char *fileName,struct Node* headNode) //将链表里的信息打印到文件里去
{
FILE *fp = fopen(fileName, "w"); //第一个指针使用写的方式打开文件
struct Node* pMove = headNode->next;
//当第二个节点不等于空时,就将链表里的信息打印到文件里去
while(pMove)
{
fprintf(fp,"%s\t%.1f\t%d\n", pMove->data.name, pMove->data.price, pMove->data.num); //打印到指针文件指向的文件,打印的是pMove
pMove = pMove->next;
}
fclose(fp); //关闭文件
}
//文件读操作
void readInfoFromFile(const char* fileName, struct Node* headNode) //需要从文件里将内容读出
{
//把文件当作是一个输入键盘,定义临时变量tempData,把数据读到变量(如:%s)里
struct bookInfo tempData;
FILE* fp = fopen(fileName, "r"); //第一个指针使用读的方式打开文件
/*文件开始的时候是不存在的,不存在的时候,使用创建(w+)的读写方式打开文件*/
if (fp == NULL)
{
fp = fopen(fileName, "w+");
}
while (fscanf(fp,"%s\t%.1f\t%d\n", tempData.name, &tempData.price, &tempData.num) != EOF) //加上" != EOF"后该程序就不是死循环了
{
/*做链表的插入,读一个信息就插入到链表中*/
insertNodeByHead(list, tempData);
}
fclose(fp); //关闭文件
}
//按键处理,做交互
void keyDown()
{
int userKey = 0;
//准备一个临时变量去存放书籍的临时信息
struct bookInfo tempBook;
//写个临时的指针用于查询
struct Node* result = NULL;
scanf("%d",&userKey);
switch (userKey)
{
case 0:
printf("【退出】\n");
printf("退出成功!欢迎下次使用~\n");
system("pause"); //防止闪屏
exit(0); //关闭掉整个程序
break;
case 1:
printf("【登记】\n");
printf("请输入书籍的信息(name,price,num):");
scanf("%s%f%d",tempBook.name,&tempBook.price,&tempBook.num); //tempBook.name不需要加&取地址,因为是字符串
insertNodeByHead(list, tempBook); // 插入链表
saveInfoToFile("bookinfo.txt", list); //当做了数据修改,就将信息保存到bookinfo.txt文件中,读到链表中
break;
case 2:
printf("【浏览】\n");
printList(list); //打印链表
break;
case 3:
printf("【借阅】\n"); //是把书的数量减少,书籍存在可以借,书的数量-1,不存在则提示借书失败
//通过书籍名去借阅
printf("请输入需要借阅的书名:");
scanf("%s", tempBook.name);
result = searchByName(list, tempBook.name);
if(result == NULL)
{
printf("没有此书籍,无法借阅!");
}
else
{
if(result->data.num > 0) //大于0说明有书籍可借阅
{
result->data.num--; //书的数量-1
printf("【0v0】恭喜你,借阅成功!");
}
else
{
printf("【TAT】当前书籍无库存,借阅失败");
}
}
break;
case 4:
printf("【归还】\n"); //是把当前书的数量增加+1
printf("请输入需要归还的书名:");
scanf("%s", tempBook.name);
result = searchByName(list, tempBook.name);
if(result == NULL)
{
printf("没有此书籍借阅记录,无法归还!");
}
else
{
result->data.num++; //书的数量+1
printf("【0v0】恭喜你,归还成功!");
}
break;
case 5:
printf("【删除】\n");
printf("请输入要删除书籍的名字:");
scanf("%s",tempBook.name);
deleteNodeByName(list, tempBook.name);
saveInfoToFile("bookinfo.txt", list); //删除之后需要同步到文件,因为涉及到数据的修改
break;
case 6:
printf("【查找】\n");
printf("请输入要查询书籍的名字:");
scanf("%s",tempBook.name);
result = searchByName(list, tempBook.name);
//查找等效于链表的查找
//判断如果result等于NULL,就表示未找到
if(result == NULL)
{
printf("未找到该书籍!");
}
else
{
printf("书名\t价格\t数量\n");
printf("%s\t%.1f\t%d\n",result->data.name,result->data.price,result->data.num);
}
break;
default:
printf("【错误】\n"); //在switch语句中,如果表达式的值与每一中情况都不同,则执行default:后面的语句
break;
}
}
//调用测试实现
int main()
{
list = createHead();
readInfoFromFile("bookinfo.txt", list); //当系统运行的时候,就将文件的东西读到列表里
/*while(1)其中1代表一个常量表达式,
它永远不会等于0。循环会一直执行下去。
除非你设置break等类似的跳出循环语句循环才会中止。*/
while (1)
{
makeMenu();
keyDown();
system("pause");
system("cls"); //清屏代码:
}
system("pause"); //就是暂停程序的执行,等待任意健继续执行。
return 0;
}
编辑于 2021-12-03 12:59