首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C语言实战项目--图书管理系统(附带全套源代码)

C语言实战项目--图书管理系统(附带全套源代码)

作者头像
@VON
发布2025-12-17 09:48:24
发布2025-12-17 09:48:24
1950
举报

一、项目简介

该项目适用于大一大二实训作业,所用到的知识全都是课堂中老师要求掌握的,该项目有运行截图可以直接进行应用。实现了对图书的增、删、改、查的操作。图书的信息包括名称、单价、数量。运用链表来保存图书信息,再对链表进行读取,保存至文件当中。

注:使用前要先在该项目下创建“booksave.txt”文本文件,如果不想应用文件操作可以删除对应函数及函数的调用操作。

二、项目应用技术

1、动态内存分配与释放

使用 malloc 分配内存来存储 BOOKINFO 结构体类型的数据。

在退出系统时通过 delinit 函数释放链表节点占用的内存。

2、结构体和指针

BOOKINFO 结构体用于存储图书的名称、价格和数量。

BOOKINFO* 类型的指针 p_info 用于动态创建新的图书信息。

3、链表操作

booklink* lnk 是一个指向图书链表头的指针,用于操作和管理图书的插入、删除、查找等操作。

函数 bookinsertbookdeletebooksearch 用于在链表中插入、删除和查找图书信息。

4、文件操作

savebook 函数可能用于将当前图书链表的信息保存到文件中,以便在程序重新运行时可以恢复数据。

5、用户交互

使用 scanf 函数接收用户输入的操作选择和相关参数。

通过 switch 语句根据用户输入执行相应的操作:登记新书、浏览书籍、借阅书籍、归还书籍、查找书籍、删除书籍、退出系统等。

6、错误处理

在内存分配失败时输出错误信息。

在未找到相关书籍或操作非法时,输出相应的提示信息。

7、功能实现细节

在插入图书时,允许用户指定插入位置,并保存修改后的链表状态。

借阅和归还书籍时,根据库存数量进行相应的操作,并保存更新后的信息。

三、项目运行展示

1、booksave.txt
2、books.cpp

四、项目构建思路及其代码展示

1.结构体和头文件的使用

预处理指令 (#define _CRT_SECURE_NO_WARNINGS)

这是针对使用 Visual Studio 编译器的预处理指令,用于忽略某些与标准C库函数相关的警告。

头文件包含 #include<stdio.h>:标准输入输出库,包含了输入输出函数的声明。 #include<stdlib.h>:标准库,包含了内存分配、类型转换、数学函数等。 #include<string.h>:标准字符串处理库,包含了字符串操作函数的声明。 #include<stdbool.h>:标准布尔类型库,包含了 bool 类型和 true/false 宏定义。 结构体定义 (typedef struct ...) typedef struct bookinfo:定义了名为 bookinfo 的结构体,用于存储图书的信息。 char name[20]:存储图书名称的字符数组,最大长度为 19 个字符(加上结尾的空字符 \0)。 float price:存储图书价格的浮点数。 int num:存储图书数量的整数。 struct bookinfo* next:指向下一个 bookinfo 结构体的指针,用于构建链表。 typedef struct link:定义了名为 link 的结构体,用于表示一个链表。 BOOKINFO head:链表的头部,存储一个 BOOKINFO 结构体,可能作为链表的起始点。 BOOKINFO tail:链表的尾部,存储一个 BOOKINFO 结构体,可能作为链表的结束点。

代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
//定义图书信息
typedef struct bookinfo
{
	char name[20];
	float price;
	int num;
	struct bookinfo* next;
}BOOKINFO;

//链表
typedef struct link
{
	BOOKINFO head;//头部
	BOOKINFO tail;//尾部
}booklink;
2.初始化链表

指针操作 p_link 是一个指向 booklink 结构的指针,用来操作传入的链表结构。 结构体成员访问 p_link->head 和 p_link->tail 分别访问了 booklink 结构体中的 head 和 tail 成员。 链表初始化 p_link->head.next = &(p_link->tail); 将 head 结构体中的 next 成员指向 tail 结构体的地址。这表示链表的头部的下一个节点是尾部,这是一个常见的初始化操作,使得链表在初始状态下只有头部一个节点。 p_link->tail.next = NULL; 将 tail 结构体中的 next 成员设置为 NULL,表示链表的尾部节点没有下一个节点,即链表结束。

代码语言:javascript
复制
//初始化
void linkinit(booklink* p_link)
{
	p_link->head.next = &(p_link->tail);
	p_link->tail.next = NULL;
}
3.释放结点空间

指针操作 BOOKINFO* p_first = &(p_link->head); 将 p_first 指针指向链表头部节点。 BOOKINFO* p_mid = p_first->next; p_mid 指向头部节点的下一个节点,即链表中的第一个实际节点。 BOOKINFO* p_last = p_mid->next; p_last 指向 p_mid 节点的下一个节点,即要删除的节点的下一个节点。 节点释放 p_first->next = p_last; 将头部节点的 next 指针指向要删除节点的下一个节点,从而维持链表的连续性。 free(p_mid); 释放 p_mid 指向的节点的内存空间,即删除链表中的一个节点。

代码语言:javascript
复制
//释放结点空间
void delinit(booklink* p_link)
{
	while (p_link->head.next != &(p_link->tail))
	{
		BOOKINFO* p_first = &(p_link->head);
		BOOKINFO* p_mid = p_first->next;
		BOOKINFO* p_last = p_mid->next;
		p_first->next = p_last;
		free(p_mid);
		p_mid = NULL;
	}
}
4.统计图书数量

指针操作 const BOOKINFO* p_first = p_node; 将 p_first 指针指向当前循环节点 p_node,表示当前节点。 const BOOKINFO* p_mid = p_first->next; p_mid 指向 p_first 节点的下一个节点,即链表中的第一个实际节点。 const BOOKINFO* p_last = p_mid->next; p_last 指向 p_mid 节点的下一个节点,用于检查是否到达链表的尾部。 条件判断 if (p_mid != &(p_link->tail)) cut++; 检查 p_mid 是否指向链表尾部节点。如果不是尾部节点,即 p_mid 是一个有效的书籍节点,那么增加 cut 计数器的值。 计数器 int cut = 0; cut 用来记录链表中实际书籍节点的数量,每次遇到一个有效节点时增加。

代码语言:javascript
复制
//统计图书数量
int booksize(const booklink*p_link)
{
	int cut = 0;
	for (const BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next)
	{
		const BOOKINFO* p_first = p_node;
		const BOOKINFO* p_mid = p_first->next;
		const BOOKINFO* p_last = p_mid->next;
		if (p_mid != &(p_link->tail))cut++;
	}
	return cut;
}
5.插入图书信息

BOOKINFO* p_first = p_node; 将 p_first 指针指向当前循环节点 p_node,表示当前节点。 BOOKINFO* p_mid = p_first->next; p_mid 指向 p_first 节点的下一个节点,即链表中的第一个实际节点。 BOOKINFO* p_last = p_mid->next; p_last 指向 p_mid 节点的下一个节点,用于插入新节点时的连接操作。 if (location == i) 检查当前迭代到的位置 i 是否与要插入的位置 location 相等。 p_info->next = p_mid; 将要插入的书籍节点 p_info 的 next 指针指向当前位置的节点 p_mid,使其成为链表中的下一个节点。 p_first->next = p_info; 将当前节点 p_first 的 next 指针指向要插入的书籍节点 p_info,完成插入操作。 *size += 1; 更新书籍链表的大小,即增加 size 指向的整数值,表示链表中书籍数量增加了一个。

代码语言:javascript
复制
void bookinsert(booklink* p_link, BOOKINFO* p_info, int location, int* size)
{
	int i = 0;
	for (BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next, i++)
	{
		BOOKINFO* p_first = p_node;
		BOOKINFO* p_mid = p_first->next;
		BOOKINFO* p_last = p_mid->next;
		if (location == i)
		{
			p_info->next = p_mid;
			p_first->next = p_info;
			*size += 1;
			break;
		}
	}
}
6.打印图书信息

const BOOKINFO* p_first = p_node; 将 p_first 指针指向当前循环节点 p_node,表示当前节点。 const BOOKINFO* p_mid = p_first->next; p_mid 指向 p_first 节点的下一个节点,即链表中的第一个实际节点。 const BOOKINFO* p_last = p_mid->next; p_last 指向 p_mid 节点的下一个节点,用于判断是否到达链表尾部。 打印图书信息 if (p_mid != &(p_link->tail)) 检查 p_mid 是否指向链表尾部节点,确保不打印尾部哨兵节点的信息。 printf("第%d本图书的信息为:\n", i + 1); 打印当前图书在链表中的位置。 printf("名字:%s,价格:%.2f,数量:%d\n", p_mid->name, p_mid->price, p_mid->num); 输出当前图书节点中存储的名称、价格和数量信息。

代码语言:javascript
复制
void bookprint(const booklink* p_link, int* size)
{
	int i = 0;
	if (*size == 0)
	{
		printf("当前没有图书信息,请先插入图书信息\n");
		return;
	}
	for (const BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next, i++)
	{
		const BOOKINFO* p_first = p_node;
		const BOOKINFO* p_mid = p_first->next;
		const BOOKINFO* p_last = p_mid->next;
		if (p_mid != &(p_link->tail))
		{
			printf("第%d本图书的信息为:\n", i + 1);
			printf("名字:%s,价格:%.2f,数量:%d\n", p_mid->name, p_mid->price, p_mid->num);
		}
	}
}
7.查询图书信息

for (BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next) 使用 for 循环遍历链表,从链表的头部节点开始 (&(p_link->head)),直到遇到尾部节点 (&(p_link->tail))。p_node 每次迭代指向当前节点的下一个节点 (p_node->next)。 BOOKINFO* p_first = p_node; 将 p_first 指针指向当前循环节点 p_node,表示当前节点。 BOOKINFO* p_mid = p_first->next; p_mid 指向 p_first 节点的下一个节点,即链表中的第一个实际节点。 BOOKINFO* p_last = p_mid->next; p_last 指向 p_mid 节点的下一个节点,用于判断是否到达链表尾部。 字符串比较 if (strcmp(bookName, p_mid->name) == 0) return p_mid; 使用 strcmp 函数比较参数 bookName 和当前节点 p_mid 的书名 (p_mid->name)。如果两者相等,表示找到了目标图书节点,直接返回该节点的指针 p_mid

代码语言:javascript
复制
BOOKINFO* booksearch(booklink* p_link, char* bookName)
{
	for (BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next)
	{
		BOOKINFO* p_first = p_node;
		BOOKINFO* p_mid = p_first->next;
		BOOKINFO* p_last = p_mid->next;
		if (strcmp(bookName, p_mid->name) == 0) return p_mid;
	}
	return NULL;
}
8.删除图书信息

for (BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next, i++) 使用 for 循环遍历链表,从链表的头部节点开始 (&(p_link->head)),直到遇到尾部节点 (&(p_link->tail))。p_node 每次迭代指向当前节点的下一个节点 (p_node->next),同时通过 i 计数器记录当前节点的位置。 BOOKINFO* p_first = p_node; 将 p_first 指针指向当前循环节点 p_node,表示当前节点。 BOOKINFO* p_mid = p_first->next; p_mid 指向 p_first 节点的下一个节点,即链表中的第一个实际节点。 BOOKINFO* p_last = p_mid->next; p_last 指向 p_mid 节点的下一个节点,用于删除操作时的重新连接。 删除操作 if (location == i) 判断当前节点的位置是否与目标删除位置 location 相同。 p_first->next = p_last; 将当前节点 p_first 的下一个节点指针 next 更新为 p_last,跳过了中间节点 p_mid,实现删除操作。 free(p_mid); 释放被删除的中间节点 p_mid 的内存空间,防止内存泄漏。 *size -= 1; 更新链表大小变量 size,减少一个节点的大小计数。

代码语言:javascript
复制
void bookdelete(booklink* p_link, int location, int* size)
{
	int i = 0;
	for (BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next, i++)
	{
		BOOKINFO* p_first = p_node;
		BOOKINFO* p_mid = p_first->next;
		BOOKINFO* p_last = p_mid->next;
		if (location == i)
		{
			p_first->next = p_last;
			free(p_mid);
			*size -= 1;
			break;
		}	
	}
}
9.保存文件

文件操作 FILE* fp = fopen("booksave.txt", "w"); 使用 fopen 函数以写入模式 ("w") 打开名为 "booksave.txt" 的文件。如果文件打开失败 (fp == NULL),则输出错误信息并返回,表示无法继续操作。 BOOKINFO* p_tem = p_link->head.next; 初始化 p_tem 指针,指向链表的第一个实际节点,即头节点的下一个节点。 循环写入文件 while (p_tem != &p_link->tail) 使用 while 循环遍历链表,条件是 p_tem 不等于尾部节点 (&p_link->tail)。这种尾部节点的设计常见于链表的哨兵节点或者尾节点。 文件写入 fprintf(fp, "%s %f %d\n", p_tem->name, p_tem->price, p_tem->num); 使用 fprintf 函数将每个节点的图书信息按指定格式写入文件中,包括图书名称 (name)、价格 (price) 和数量 (num)。 关闭文件 fclose(fp); 使用 fclose 函数关闭文件流,确保写入操作完成并释放文件资源。

代码语言:javascript
复制
//保存文件
void savebook(booklink* p_link)
{
	FILE* fp = fopen("booksave.txt", "w");
	if (fp == NULL)
	{
		printf("无法打开文件!\n");
		return;
	}
	BOOKINFO* p_tem = p_link->head.next;
	while (p_tem != &p_link->tail)
	{
		fprintf(fp, "%s %f %d\n", p_tem->name, p_tem->price, p_tem->num);
		p_tem = p_tem->next;
	}
	printf("保存图书信息成功!\n");
	fclose(fp);
}
10.读取文件

文件操作 FILE* fp = fopen("booksave.txt", "r"); 使用 fopen 函数以只读模式 ("r") 打开名为 "booksave.txt" 的文件。如果文件打开失败 (fp == NULL),则输出错误信息并返回,表示无法继续操作。 内存动态分配 BOOKINFO* p_info = (BOOKINFO*)malloc(sizeof(BOOKINFO)); 使用 malloc 函数动态分配内存来存储每个图书信息。这里假设 BOOKINFO 是一个结构体或者类型,用于存储图书的名称 (name)、价格 (price) 和数量 (num)。 循环读取文件 while (fscanf(fp, "%s%f%d", p_info->name, &p_info->price, &p_info->num) != EOF) 使用 while 循环结合 fscanf 函数从文件中逐行读取图书信息,直到文件结尾 (EOF)。每次成功读取一行数据后,将其打印出来以确认读取的正确性,并调用 bookinsert 函数将读取到的图书信息插入到链表中。 链表操作 bookinsert(p_link, p_info, location, size); 假设 bookinsert 是一个函数,用于将 p_info 指向的图书信息节点插入到链表 p_link 的指定位置 (location),并更新链表的大小 (size)。 内存释放 free(p_info); 在循环结束后,释放最后一次 malloc 分配的内存,避免内存泄漏。 关闭文件 fclose(fp); 使用 fclose 函数关闭文件流,确保读取操作完成并释放文件资源。

代码语言:javascript
复制
//读取文件
void readbook(booklink* p_link,int *size)
{
	FILE* fp = fopen("booksave.txt", "r");
	if (fp == NULL)
	{
		printf("无法打开文件!\n");
		return;
	}
	BOOKINFO* p_info = (BOOKINFO*)malloc(sizeof(BOOKINFO));
	int location = 0;
	while (fscanf(fp, "%s%f%d", p_info->name, &p_info->price, &p_info->num) != EOF)
	{
		printf("%s %f %d\n", p_info->name, p_info->price, p_info->num);
		bookinsert(p_link, p_info, location, size);
		p_info = (BOOKINFO*)malloc(sizeof(BOOKINFO));
	}
	free(p_info);
	p_info = NULL;
	printf("读取信息成功!\n");
	fclose(fp);
}
11.功能函数
代码语言:javascript
复制
//功能
void book_keydown(booklink*lnk,int *size)
{
	int userkey = 0;
	int location = 0;
	char bookname[20] = { 0 };
	BOOKINFO *result = NULL;
	BOOKINFO* p_info; // 将 p_info 的定义提前到 switch 之前
	scanf("%d", &userkey);
	switch (userkey)
	{
	case 0:
		printf("登记\n");
		p_info = (BOOKINFO*)malloc(sizeof(BOOKINFO));
		if (p_info == NULL) {
			printf("内存分配失败!\n");
			break;
		}
		printf("请输入要插入图书的信息(名称,价格,数量):\n");
		scanf("%s%f%d", p_info->name, &p_info->price, &p_info->num);
		printf("请输入要插入的位置:\n");
		scanf("%d", &location);
		if (location > *size || location==0) location = *size;
		bookinsert(lnk, p_info, location, size);
		savebook(lnk);
		break;
	case 1:
		printf("【浏览】\n");
		bookprint(lnk, size);
		break;
	case 2:
		printf("【借阅】\n");
		printf("请输入你要借阅的书名:");
		scanf("%20s", bookname);
		result = booksearch(lnk, bookname);
		if (result == NULL) printf("未找到相关结果!\n");
		else
		{
			if (result->num > 0)
			{
				result->num--;
				printf("借阅成功!\n");
				savebook(lnk);
			}
			else printf("当前书籍无库存,借阅失败!\n");
		}
		break;
	case 3:
		printf("【归还】\n");
		printf("请输入你要归还的书名:");
		scanf("%20s", bookname);
		result = booksearch(lnk, bookname);
		if (result == NULL) printf("书籍来源非法,归还失败!\n");
		else
		{
			if (result->num > 0)
			{
				result->num++;
				printf("归还成功!\n");
				savebook(lnk);
			}
		}
		break;
	case 4:
		printf("【查找】\n");
		printf("请输入你要查找的书名:");
		scanf("%20s", bookname);
		result = booksearch(lnk, bookname);
		if (result == NULL) printf("未找到相关结果!\n");
		else printf("书名:%s\t,价格:%.2f\t,数量:%d\t\n", result->name, result->price, result->num);
		break;
	case 5:
		printf("删除\n");
		printf("请输入要删除的位置:");
		scanf("%d", &location);
		if (location > *size) location = *size;
		bookdelete(lnk, location, size);
		savebook(lnk);
		break;
	case 6:
		delinit(lnk);
		printf("已退出系统\n");
		exit(0);
		break;
	default:
		printf("输入有误,请重新输入!!!\n");
		break;
	}
}
12.主函数
代码语言:javascript
复制
int main()
{
	booklink lnk = { 0 };
	linkinit(&lnk);
	int size = booksize(&lnk);
	readbook(&lnk, &size);
	while (1)
	{
		bookmenu();
		book_keydown(&lnk,&size);
	}
	return 0;
}

五、项目完整代码

代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
//定义图书信息
typedef struct bookinfo
{
	char name[20];
	float price;
	int num;
	struct bookinfo* next;
}BOOKINFO;

//链表
typedef struct link
{
	BOOKINFO head;//头部
	BOOKINFO tail;//尾部
}booklink;

//初始化
void linkinit(booklink* p_link)
{
	p_link->head.next = &(p_link->tail);
	p_link->tail.next = NULL;
}

//释放结点空间
void delinit(booklink* p_link)
{
	while (p_link->head.next != &(p_link->tail))
	{
		BOOKINFO* p_first = &(p_link->head);
		BOOKINFO* p_mid = p_first->next;
		BOOKINFO* p_last = p_mid->next;
		p_first->next = p_last;
		free(p_mid);
		p_mid = NULL;
	}
}

//统计图书数量
int booksize(const booklink*p_link)
{
	int cut = 0;
	for (const BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next)
	{
		const BOOKINFO* p_first = p_node;
		const BOOKINFO* p_mid = p_first->next;
		const BOOKINFO* p_last = p_mid->next;
		if (p_mid != &(p_link->tail))cut++;
	}
	return cut;
}

//菜单
void bookmenu()
{
	printf("----------图书管理系统V1.0----------\n\n");
	printf("------------0.登记新书--------------\n");
	printf("------------1.浏览全部书籍----------\n");
	printf("------------2.借阅书籍--------------\n");
	printf("------------3.归还书籍--------------\n");
	printf("------------4.查询书籍--------------\n");
	printf("------------5.删除书籍--------------\n");
	printf("------------6.退出系统--------------\n");
	printf("------------------------------------\n");
}

//功能函数
//0.插入
void bookinsert(booklink* p_link, BOOKINFO* p_info, int location, int* size)
{
	int i = 0;
	for (BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next, i++)
	{
		BOOKINFO* p_first = p_node;
		BOOKINFO* p_mid = p_first->next;
		BOOKINFO* p_last = p_mid->next;
		if (location == i)
		{
			p_info->next = p_mid;
			p_first->next = p_info;
			*size += 1;
			break;
		}
	}
}

//1.打印图书有效信息
void bookprint(const booklink* p_link, int* size)
{
	int i = 0;
	if (*size == 0)
	{
		printf("当前没有图书信息,请先插入图书信息\n");
		return;
	}
	for (const BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next, i++)
	{
		const BOOKINFO* p_first = p_node;
		const BOOKINFO* p_mid = p_first->next;
		const BOOKINFO* p_last = p_mid->next;
		if (p_mid != &(p_link->tail))
		{
			printf("第%d本图书的信息为:\n", i + 1);
			printf("名字:%s,价格:%.2f,数量:%d\n", p_mid->name, p_mid->price, p_mid->num);
		}
	}
}

//2.查询书籍
BOOKINFO* booksearch(booklink* p_link, char* bookName)
{
	for (BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next)
	{
		BOOKINFO* p_first = p_node;
		BOOKINFO* p_mid = p_first->next;
		BOOKINFO* p_last = p_mid->next;
		if (strcmp(bookName, p_mid->name) == 0) return p_mid;
	}
	return NULL;
}
//3.删除图书信息
void bookdelete(booklink* p_link, int location, int* size)
{
	int i = 0;
	for (BOOKINFO* p_node = &(p_link->head); p_node != &(p_link->tail); p_node = p_node->next, i++)
	{
		BOOKINFO* p_first = p_node;
		BOOKINFO* p_mid = p_first->next;
		BOOKINFO* p_last = p_mid->next;
		if (location == i)
		{
			p_first->next = p_last;
			free(p_mid);
			*size -= 1;
			break;
		}	
	}
}

//保存文件
void savebook(booklink* p_link)
{
	FILE* fp = fopen("booksave.txt", "w");
	if (fp == NULL)
	{
		printf("无法打开文件!\n");
		return;
	}
	BOOKINFO* p_tem = p_link->head.next;
	while (p_tem != &p_link->tail)
	{
		fprintf(fp, "%s %f %d\n", p_tem->name, p_tem->price, p_tem->num);
		p_tem = p_tem->next;
	}
	printf("保存图书信息成功!\n");
	fclose(fp);
}

//读取文件
void readbook(booklink* p_link,int *size)
{
	FILE* fp = fopen("booksave.txt", "r");
	if (fp == NULL)
	{
		printf("无法打开文件!\n");
		return;
	}
	BOOKINFO* p_info = (BOOKINFO*)malloc(sizeof(BOOKINFO));
	int location = 0;
	while (fscanf(fp, "%s%f%d", p_info->name, &p_info->price, &p_info->num) != EOF)
	{
		printf("%s %f %d\n", p_info->name, p_info->price, p_info->num);
		bookinsert(p_link, p_info, location, size);
		p_info = (BOOKINFO*)malloc(sizeof(BOOKINFO));
	}
	free(p_info);
	p_info = NULL;
	printf("读取信息成功!\n");
	fclose(fp);
}

//功能
void book_keydown(booklink*lnk,int *size)
{
	int userkey = 0;
	int location = 0;
	char bookname[20] = { 0 };
	BOOKINFO *result = NULL;
	BOOKINFO* p_info; // 将 p_info 的定义提前到 switch 之前
	scanf("%d", &userkey);
	switch (userkey)
	{
	case 0:
		printf("登记\n");
		p_info = (BOOKINFO*)malloc(sizeof(BOOKINFO));
		if (p_info == NULL) {
			printf("内存分配失败!\n");
			break;
		}
		printf("请输入要插入图书的信息(名称,价格,数量):\n");
		scanf("%s%f%d", p_info->name, &p_info->price, &p_info->num);
		printf("请输入要插入的位置:\n");
		scanf("%d", &location);
		if (location > *size || location==0) location = *size;
		bookinsert(lnk, p_info, location, size);
		savebook(lnk);
		break;
	case 1:
		printf("【浏览】\n");
		bookprint(lnk, size);
		break;
	case 2:
		printf("【借阅】\n");
		printf("请输入你要借阅的书名:");
		scanf("%20s", bookname);
		result = booksearch(lnk, bookname);
		if (result == NULL) printf("未找到相关结果!\n");
		else
		{
			if (result->num > 0)
			{
				result->num--;
				printf("借阅成功!\n");
				savebook(lnk);
			}
			else printf("当前书籍无库存,借阅失败!\n");
		}
		break;
	case 3:
		printf("【归还】\n");
		printf("请输入你要归还的书名:");
		scanf("%20s", bookname);
		result = booksearch(lnk, bookname);
		if (result == NULL) printf("书籍来源非法,归还失败!\n");
		else
		{
			if (result->num > 0)
			{
				result->num++;
				printf("归还成功!\n");
				savebook(lnk);
			}
		}
		break;
	case 4:
		printf("【查找】\n");
		printf("请输入你要查找的书名:");
		scanf("%20s", bookname);
		result = booksearch(lnk, bookname);
		if (result == NULL) printf("未找到相关结果!\n");
		else printf("书名:%s\t,价格:%.2f\t,数量:%d\t\n", result->name, result->price, result->num);
		break;
	case 5:
		printf("删除\n");
		printf("请输入要删除的位置:");
		scanf("%d", &location);
		if (location > *size) location = *size;
		bookdelete(lnk, location, size);
		savebook(lnk);
		break;
	case 6:
		delinit(lnk);
		printf("已退出系统\n");
		exit(0);
		break;
	default:
		printf("输入有误,请重新输入!!!\n");
		break;
	}
}

int main()
{
	booklink lnk = { 0 };
	linkinit(&lnk);
	int size = booksize(&lnk);
	readbook(&lnk, &size);
	while (1)
	{
		bookmenu();
		book_keydown(&lnk,&size);
	}
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、项目简介
  • 二、项目应用技术
    • 1、动态内存分配与释放
    • 2、结构体和指针
    • 3、链表操作
    • 4、文件操作
    • 5、用户交互
    • 6、错误处理
    • 7、功能实现细节
  • 三、项目运行展示
    • 1、booksave.txt
    • 2、books.cpp
  • 四、项目构建思路及其代码展示
    • 1.结构体和头文件的使用
    • 2.初始化链表
    • 3.释放结点空间
    • 4.统计图书数量
    • 5.插入图书信息
    • 6.打印图书信息
    • 7.查询图书信息
    • 8.删除图书信息
    • 9.保存文件
    • 10.读取文件
    • 11.功能函数
    • 12.主函数
  • 五、项目完整代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档