非图形界面
使用了Linux内核链表的部分。
将文件数据读出到链表进行操作。
构成文件:main.c, module.c, module.h, kernel_list.h(Linux内核链表), book.txt(存放图书数据)
注:部分操作无法做到检测任意错误输入。如果不是通过程序提供的退出操作,其他退出操作都不能将链表中已经修改好的数据保存进文件。文件中至少要存有一本书的数据。
文件中图书的数据格式(单个数据占一行):
12(图书索引号)
水浒传(图书名)
图书馆b区(馆藏地址)
小说(类别)
10(图书数量)
55.5(图书价格)
2000(入库年份)
12(入库月份)
22(入库日)
2023(归还年份)
10(归还月份)
1(归还日)
5(借阅次数)
1(借阅状态,1为可借阅,0为不可借阅)
以上括号内的内容以及括号在文件中不出现,在这仅作为数据信息注释,文件的末尾必须留一行空白行
功能:
- 显示文件中所有图书信息
- 根据图书名查询图书信息
- 向文件添加图书信息
- 根据搜索书名修改图书信息
- 根据搜索书名删除图书信息
- 将图书信息按借阅次数从大到小排序
- 显示所有即将到期的图书(三天及以内,已经到期的不算)
- 保存数据到文件(退出程序)
以下为源代码
main.c
#include <stdio.h>
#include <windows.h>
#include "module.h"
int main()
{
BOOK *head = ListInit(); // 初始化链表
char bookname[20] = ""; // 临时存放数据,书名
int n = GetBookNum(); // 临时变量,存放书本数量
if (n == 0) // 若文本中书本数量为零,直接结束程序
{
printf("文件中无图书数据。\n");
return 0;
}
fileread(head, n); // 从文件读取数据存放到链表
char flag = 1; // 控制循环标志
char select; // 操作选择
BOOK *temp = NULL; // 临时结构体指针变量
while (flag)
{
menu(); // 显示菜单
printf("请输入选择:(0-8)");
fflush(stdin);
if(scanf("%d", &select) && select < 9)
{
switch (select)
{
case 0: // 退出
system("cls");
printf("退出成功!");
flag = 0; // 标志为0,退出循环
filewrite(head); // 将链表数据写入文件
break;
case 1: // 显示所有图书信息
List_Traval(head); // 链表遍历显示图书
break;
case 2: // 查找图书
system("cls");
printf("请输入要查找的书名:\n");
fflush(stdin); // 清空输入缓冲区
fgets(bookname, 20, stdin);
temp = search(head, bookname); // 调用查找函数返回节点地址
if (temp)
{
show(temp); // 传入节点,显示节点信息
system("pause");
}
break;
case 3: // 添加图书信息
ListWrite(head);
break;
case 4: // 修改图书信息
system("cls");
printf("请输入要修改的图书名:\n");
fflush(stdin);
fgets(bookname, 20, stdin); // 从键盘获取图书名
temp = search(head, bookname); // 调用根据图书名查找图书函数
if (temp) // 若根据图书名查找函数返回不为NULL,则执行下面的修改函数
{
char n = 1; // 控制循环位
while (n)
{
*temp = set(*temp); // 调用修改图书信息函数
printf("是否继续修改:是(1),否(0)\n");
scanf("%d", &n);
}
printf("修改成功\n");
}
break;
case 5: // 删除图书信息
system("cls");
printf("请输入要删除的图书名。\n");
fflush(stdin);
fgets(bookname, 20, stdin);
temp = search(head, bookname);
if (temp) // 若根据图书名查找函数返回不为NULL,则执行下面的删除函数
{
DeleteNode(temp);
}
break;
case 6: // 按借阅次数排序
head = sort_times(head); // 调用按借阅次数排序函数,并将排好序的链表头节点返回
system("cls");
printf("排序成功!\n");
system("pause");
break;
case 7: // 显示所有即将到期的图书
show_BookB(head);
system("pause");
break;
}
}
else
{
system("cls");
printf("输入有误!请重新输入!\n");
system("pause");
}
}
}
module.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <windows.h>
#include <math.h>
#include "kernel_list.h"
#include "module.h"
/**
* @brief 链表初始化,双向循环链表
* @param 无
* @return head(struct book结构体类型指针)
*/
BOOK *ListInit(void)
{
// 为头节点申请空间
BOOK *head = (BOOK *)malloc(sizeof(BOOK));
if (head == NULL)
{
printf("内存申请失败");
}
// 处理空表头节点指针域
INIT_LIST_HEAD(&(head->nlist));
return head;
}
/**
* @brief 链表节点插入,尾插
* @param head 链表表头指针
* @param New 待插入的节点数据
* @return 0(成功) -1(失败)
*/
char ListInsert(BOOK *head, BOOK New)
{
// 判断传入头指针是否有效
if (head == NULL)
{
return -1;
}
// 为新节点申请空间
BOOK *NewNode = (BOOK *)malloc(sizeof(BOOK));
if (NewNode == NULL)
{
printf("待插入新节点内存申请失败");
return -1;
}
// 处理新节点的数据域
*NewNode = New;
// 处理新节点的指针域
list_add_tail(&(NewNode->nlist), &(head->nlist));
return 0;
}
/**
* @brief 显示图书信息
* @param head 待显示节点
* @return 无
*/
void show(BOOK *head)
{
// 判断传入节点是否有效
if (head == NULL)
{
return;
}
system("cls");
printf("图书编号:%d\n", (head->id));
printf("书名:%s", (head->name));
printf("馆藏地址:%s", (head->address));
printf("图书类别:%s", (head->Class));
printf("被借阅次数:%d\n", (head->number));
printf("价格:%.2lf\n", (head->price));
printf("入库日期:%d.%d.%d\n", (head->date[0]), (head->date[1]), (head->date[2]));
printf("归还日期:%d.%d.%d\n", (head->ReturnDate[0]), (head->ReturnDate[1]), (head->ReturnDate[2]));
printf("借阅次数:%d\n", (head->times));
printf("借阅状态:%s\n", ((head->state) ? "可借阅" : "不可借阅"));
}
/**
* @brief 链表遍历,打印所有图书信息
* @param head 待遍历链表的表头
* @return 无
*/
void List_Traval(BOOK *head)
{
// 判断传入节点是否有效
if (head == NULL)
{
return;
}
// 遍历输出
BOOK *p = NULL;
list_for_each_entry(p, &(head->nlist), nlist)
{
show(p);
system("pause");
}
}
/**
* @brief 根据图书名字查找图书
* @param head 链表头指针
* @param name 要查找的书名
* @return temp 找到的图书对应的指针
*/
BOOK *search(BOOK *head, char *name)
{
// 判断传入头节点是否有效
if (head == NULL)
{
return NULL;
}
char flag = 0; // 判断是否找到节点的标志位
BOOK *p = NULL;
// 遍历比对
list_for_each_entry(p, &(head->nlist), nlist)
{
if (!strcmp(p->name, name))
{
flag = 1;
break;
}
}
if (flag)
{
system("cls");
printf("已查询到此书。\n");
system("pause");
return p;
}
else
{
system("cls");
printf("未查询到此书。\n");
system("pause");
return NULL;
}
}
/**
* @brief 删除节点
* @param node 待删除节点
* @return 无
*/
void DeleteNode(BOOK *node)
{
list_del(&(node->nlist));
free(node); // 释放node节点
}
/**
* @brief 修改图书信息
* @param node 待修改图书结构体
* @return node 修改后的图书结构体
*/
BOOK set(BOOK node)
{
char num = 0; // 存放操作选择
system("cls");
printf("请输入要修改的部分:\n退出修改(0)\n \
图书索引号(1)\n \
图书名称(2)\n \
馆藏地址(3)\n \
类别(4)\n数量(5)\n \
价格(6)\n入库年份(7)\n \
入库月份(8)\n入库日(9)\n \
归还年份(10)\n归还月份(11)\n \
归还日(12)\n借阅次数(13)\n");
scanf("%d", &num);
switch (num)
{
case 0:
system("cls");
printf("确认退出?\n");
break;
case 1:
system("cls");
printf("索引号要修改为:\n");
setid(&(node.id)); // 调用设置图书索引号函数
break;
case 2:
system("cls");
printf("图书名称要修改为:\n");
setname(node.name); // 调用设置图书名函数
break;
case 3:
system("cls");
printf("馆藏地址修改为:\n");
setaddress(node.address); // 调用设置图书馆藏地址函数
break;
case 4:
system("cls");
printf("类别修改为:\n");
setClass(node.Class); // 调用设置图书类别函数
break;
case 5:
system("cls");
printf("数量修改为:\n");
setnumber(&(node.number)); // 调用设置图书数量函数
if (node.number == 0) // 书本数量为零,自动将借阅状态置为0(不可借阅)
{
node.state = 0;
}
else
{
node.state = 1;
}
break;
case 6:
system("cls");
printf("价格修改为:\n");
setprice(&(node.price)); // 调用设置图书价格函数
break;
case 7:
system("cls");
printf("请输入修改入库年份:(1999-2023)\n");
setyear(&(node.date[0])); // 调用设置图书入库(归还)年份函数
break;
case 8:
system("cls");
printf("请输入修改入库月份:\n");
setmonth(&(node.date[1])); // 调用设置图书入库(归还)月份函数
break;
case 9:
system("cls");
printf("请输入修改入库日:\n");
setdate(&(node.date[0]), &(node.date[1]), &(node.date[2])); // 调用设置图书入库(归还)日函数
break;
case 10:
system("cls");
printf("请输入修改归还年份:(1999-2023)\n");
setyear(&(node.ReturnDate[0])); // 调用设置图书入库(归还)年份函数
break;
case 11:
system("cls");
printf("请输入修改归还月份:\n");
setmonth(&(node.ReturnDate[1])); // 调用设置图书入库(归还)月份函数
break;
case 12:
system("cls");
printf("请输入修改归还日:\n");
setdate(&(node.ReturnDate[0]), &(node.ReturnDate[1]), &(node.ReturnDate[2])); // 调用设置图书入库(归还)日函数
break;
case 13:
system("cls");
printf("请输入修改借阅次数:\n");
settimes(&(node.times)); // 调用设置图书借阅次数函数
break;
default:
system("cls");
printf("输入有误!\n");
break;
}
return node; // 返回修改后的结构体
}
/**
* @brief 节点数据交换
* @param p1 待交换节点
* @param p2 待交换节点
* @return 无
*/
void swap(BOOK *p1, BOOK *p2)
{
BOOK *temp = (BOOK *)malloc(sizeof(BOOK));
if(temp == NULL)
{
printf("error\n");
}
*temp = *p1;
*p1 = *p2;
*p2 = *temp;
temp->nlist = p1->nlist;
p1->nlist = p2->nlist;
p2->nlist = temp->nlist;
}
/**
* @brief 按借阅次数由大到小排序,冒泡排序
* @param head 链表头节点
* @return head 排序完成后的头节点
*/
BOOK *sort_times(BOOK *head)
{
// 判断传入头节点是否有效
if (head == NULL)
{
return NULL;
}
BOOK *p1 = NULL, *p2 = NULL, *mark = NULL; // 创建三个指针变量,p1、p2负责比较,mark负责控制外循环排序
mark = p1 = list_entry((&(head->nlist))->next, typeof(*p1), nlist); // 跳过表头空节点
p2 = list_entry(p1->nlist.next, typeof(*p1), nlist); // p1在p2前
char flag = 1; // 循环终止位,若冒泡排序完成一趟比较后没有进行交换,则表示原链表已经有序
for (; &mark->nlist != ((head->nlist.prev)); \
mark = list_entry(mark->nlist.next, typeof(*mark), nlist), \
p1 = list_entry(mark->nlist.next, typeof(*mark), nlist), \
p2 = list_entry(p1->nlist.next, typeof(*p1), nlist)) // 外循环控制趟数
{
printf("1");
for (; &p1->nlist != ((head->nlist.prev)); \
p1 = list_entry(p1->nlist.next, typeof(*p1), nlist), \
p2 = list_entry(p2->nlist.next, typeof(*p2), nlist)) // 内层循环,进行比较
{
printf("2");
if (p1->times < p2->times)
{
swap(p1, p2);
printf("3");
flag = 0;
}
}
printf("4");
if (flag) // 若一趟比较后没有进行交换,flag还为1,表明链表已经有序,无需再继续比较,直接退出循环
{
break;
}
}
return head;
}
/**
* @brief 获取文件内图书数量
* @param 无
* @return 图书数量
*/
int GetBookNum(void)
{
char a[20] = ""; // 临时存放数据
FILE *fp = fopen("txt.txt", "r"); // 读取文件行数
if (fp == NULL)
{
printf("文件打开失败。\n");
return 0;
}
int n = 0;
while (fgets(a, 20, fp))
{
n++;
}
fclose(fp);
return (n / 14); // 每本书共14个数据(行),总行数除以单本图书数据得出图书数量
}
/**
* @brief 设置图书索引号
* @param id 图书索引号对应地址
* @return 无
*/
void setid(int *id)
{
// 循环判断输入是否有误
while (!(scanf("%d", id) && (*id >= 0)))
{
fflush(stdin);
printf("输入有误,请重新输入。\n");
}
fflush(stdin);
}
/**
* @brief 设置图书名
* @param name 图书名对应地址
* @return 无
*/
void setname(char *name)
{
fflush(stdin);
fgets(name, 20, stdin);
}
/**
* @brief 设置图书馆藏地址
* @param address 图书馆藏地址对应的地址
* @return 无
*/
void setaddress(char *address)
{
fflush(stdin);
fgets(address, 20, stdin);
}
/**
* @brief 设置图书类别
* @param Class 图书类别对应的地址
* @return 无
*/
void setClass(char *Class)
{
fflush(stdin);
fgets(Class, 20, stdin);
}
/**
* @brief 设置图书数量
* @param number 图书数量对应的地址
* @return 无
*/
void setnumber(int *number)
{
while (!(scanf("%d", number) && (*number) >= 0))
{
fflush(stdin);
printf("输入有误,请重新输入。\n");
}
fflush(stdin);
}
/**
* @brief 设置图书价格
* @param price 图书价格对应的地址
* @return 无
*/
void setprice(double *price)
{
while (!(scanf("%lf", price) && (*price) > 0))
{
fflush(stdin);
printf("输入有误,请重新输入。\n");
}
fflush(stdin);
}
/**
* @brief 设置图书入库(归还)年份
* @param year 图书入库(归还)年份对应的地址
* @return 无
*/
void setyear(int *year)
{
while (!(scanf("%d", year) && ((*year) >= 1999) && ((*year) <= 2023)))
{
system("cls");
fflush(stdin);
printf("输入有误,请重新输入,有效年份(1999-2023)\n");
}
fflush(stdin);
}
/**
* @brief 设置图书入库(归还)月份
* @param month 图书入库(归还)月份对应的地址
* @return 无
*/
void setmonth(int *month)
{
while (!(scanf("%d", month) && ((*month) >= 1) && ((*month) <= 12)))
{
fflush(stdin);
printf("输入有误,请重新输入。\n");
}
fflush(stdin);
}
/**
* @brief 设置图书入库(归还)日
* @param year 图书入库(归还)年份对应的地址
* @param month 图书入库(归还)月份对应的地址
* @param date 图书入库(归还)日对应的地址
* @return 无
*/
void setdate(int *year, int *month, int *date)
{
switch ((*month))
{
// 大月份
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
while (!(scanf("%d", date) && ((*date) >= 1) && ((*date) <= 31)))
{
system("cls");
fflush(stdin);
printf("输入有误,请重新输入,大月份(1-31)\n");
}
fflush(stdin);
break;
// 小月份
case 4:
case 6:
case 9:
case 11:
while (!(scanf("%d", date) && ((*date) >= 1) && ((*date) <= 30)))
{
system("cls");
fflush(stdin);
printf("输入有误,请重新输入,小月份(1-30)\n");
}
fflush(stdin);
break;
// 二月份再单独判断
case 2:
if ((((*year) % 100 != 0) && ((*year) % 4 == 0)) || ((*year) % 400 == 0)) // 闰年
{
while (!((scanf("%d", date)) && ((*date) >= 1) && ((*date) <= 29)))
{
system("cls");
fflush(stdin);
printf("输入有误,请重新输入,闰年二月(1-29)\n");
}
fflush(stdin);
}
else // 平年
{
while (!(scanf("%d", date) && ((*date) >= 1) && ((*date) <= 28)))
{
system("cls");
fflush(stdin);
printf("输入有误,请重新输入,平年二月(1-28)\n");
}
fflush(stdin);
}
break;
}
}
/**
* @brief 设置图书借阅次数
* @param times 图书借阅次数对应地址
* @return 无
*/
void settimes(int *times)
{
while (!(scanf("%d", times) && ((*times) >= 0)))
{
fflush(stdin);
printf("输入有误,请重新输入。\n");
}
fflush(stdin);
}
/**
* @brief 显示所有即将到期的图书
* @param head 链表头节点
* @return 无
*/
void show_BookB(BOOK *head)
{
// 判断传入头节点是否有效
if (head == NULL)
{
return;
}
// 获取当前时间用于对比
time_t nowtime;
struct tm *ptime;
time(&nowtime);
ptime = gmtime(&nowtime);
char flag = 1; // 判断是否有图书到期标志位
system("cls");
printf("正在检查即将到期的书......\n");
system("pause");
BOOK *p = NULL; // 创建临时指针变量,并跳过头节点
list_for_each_entry(p, &(head->nlist), nlist)
{
if (p->ReturnDate[0] == (ptime->tm_year + 1900))
{
if (p->ReturnDate[1] == (ptime->tm_mon + 1))
{
if ((ptime->tm_mday - p->ReturnDate[2]) <= 3 && (ptime->tm_mday - p->ReturnDate[2]) >= 0) // 判断图书是否即将到期,已经过期的不作判断
{
flag = 0;
show(p);
printf("以上为即将到期的书。\n");
}
}
}
}
if (flag)
{
system("cls");
printf("没有即将到期的图书。\n");
}
}
/**
* @brief 显示菜单
* @param 无
* @return 无
*/
void menu()
{
system("cls");
printf("---------------------------------------------\n");
printf("-------欢迎使用图书馆管理系统----------------\n");
printf("---菜单--------------------------------------\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 head 链表头节点
* @return 无
*/
void filewrite(BOOK *head)
{
// head = head->next; //跳过空表头,指向下一个结点
BOOK *temp = list_entry((&(head->nlist))->next, typeof(*temp), nlist);
FILE *fp;
char tmp[20]; // 临时数组
fp = fopen("txt.txt", "w");
if (fp != NULL)
{
while (temp != head)
{
itoa(temp->id, tmp, 10); // 整型转字符串
fputs(tmp, fp);
fputs("\n", fp);
fputs(temp->name, fp);
fputs(temp->address, fp);
fputs(temp->Class, fp);
itoa(temp->number, tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
gcvt(temp->price, 6, tmp); // 浮点数转字符串
fputs(tmp, fp);
fputs("\n", fp);
itoa(temp->date[0], tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
itoa(temp->date[1], tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
itoa(temp->date[2], tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
itoa(temp->ReturnDate[0], tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
itoa(temp->ReturnDate[1], tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
itoa(temp->ReturnDate[2], tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
itoa(temp->times, tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
itoa(temp->state, tmp, 10);
fputs(tmp, fp);
fputs("\n", fp);
temp = list_entry((&(temp->nlist))->next, typeof(*temp), nlist);
}
}
else
printf("文件打开失败!\n");
fclose(fp);
}
/**
* @brief 文件读出
* @param head 链表头节点
* @param num 书本数量
* @return 无
* */
void fileread(BOOK *head, int num)
{
BOOK temp; // 图书信息
FILE *fp;
char tmp[20]; // 临时数组
fp = fopen("txt.txt", "r");
if (fp != NULL)
{
for (int i = 0; i < num; i++)
{
fgets(tmp, 20, fp);
temp.id = atoi(tmp); // 字符串转整型
fgets(temp.name, 20, fp);
fgets(temp.address, 20, fp);
fgets(temp.Class, 20, fp);
fgets(tmp, 20, fp);
temp.number = atoi(tmp);
fgets(tmp, 20, fp);
temp.price = atof(tmp); // 字符串转浮点数
fgets(tmp, 20, fp);
temp.date[0] = atoi(tmp);
fgets(tmp, 20, fp);
temp.date[1] = atoi(tmp);
fgets(tmp, 20, fp);
temp.date[2] = atoi(tmp);
fgets(tmp, 20, fp);
temp.ReturnDate[0] = atoi(tmp);
fgets(tmp, 20, fp);
temp.ReturnDate[1] = atoi(tmp);
fgets(tmp, 20, fp);
temp.ReturnDate[2] = atoi(tmp);
fgets(tmp, 20, fp);
temp.times = atoi(tmp);
fgets(tmp, 20, fp);
temp.state = atoi(tmp);
int n = ListInsert(head, temp); // 插入图书信息
if (n == -1)
{
printf("文件读出函数调用插入图书信息函数失败\n");
}
}
}
else
printf("文件打开失败!\n");
fclose(fp);
}
/**
* @brief 添加图书信息
* @param head 链表头节点
* @return 无
*/
void ListWrite(BOOK *head)
{
BOOK temp; // 临时变量,存放添加的图书信息
system("cls");
printf("请输入图书索引号:\n");
setid(&(temp.id)); // 调用设置索引号函数
system("cls");
printf("请输入图书名:\n");
setname(temp.name); // 调用设置图书名函数
system("cls");
printf("请输入图书馆藏地址:\n");
setaddress(temp.address); // 调用设置馆藏地址函数
system("cls");
printf("请输入图书类别:\n");
setClass(temp.Class); // 调用设置图书类别函数
system("cls");
printf("请输入图书数量:\n");
setnumber(&(temp.number)); // 调用设置图书数量函数
system("cls");
printf("请输入图书价格:\n");
setprice(&(temp.price)); // 调用设置图书价格函数
system("cls");
printf("请输入图书入库年份:(1999-2023)\n");
setyear(&(temp.date[0])); // 调用设置图书入库年份函数
system("cls");
printf("请输入图书入库月份:\n");
setmonth(&(temp.date[1])); // 调用设置图书入库月份函数
system("cls");
printf("请输入图书入库日:\n");
setdate(&(temp.date[0]), &(temp.date[1]), &(temp.date[2])); // 调用设置图书入库日函数
system("cls");
printf("请输入图书归还年份:(1999-2023)\n");
setyear(&(temp.ReturnDate[0])); // 调用设置图书归还年份函数
system("cls");
printf("请输入图书归还月份:\n");
setmonth(&(temp.ReturnDate[1])); // 调用设置图书归还月份函数
system("cls");
printf("请输入图书归还日:\n");
setdate(&(temp.ReturnDate[0]), &(temp.ReturnDate[1]), &(temp.ReturnDate[2])); // 调用设置图书归还日函数
system("cls");
printf("请输入借阅次数:\n");
settimes(&(temp.times)); // 调用设置图书借阅次数函数
// 根据图书数量自动设置借阅状态
if (temp.number != 0)
{
temp.state = 1;
}
else
{
temp.state = 0;
}
int n = ListInsert(head, temp); // 调用插入函数将节点插入
if (n == -1)
{
printf("添加图书调用插入图书信息函数失败\n");
}
system("cls");
printf("添加成功!\n");
system("pause");
}
module.h
#ifndef __MODULE_H__
#define __MODULE_H__
#include "kernel_list.h"
typedef struct book
{
// 数据域
int id; // 索引号
char name[20]; // 名称
char address[20]; // 馆藏地址
char Class[5]; // 类别(人文、科技、等)
int number; // 数量
double price; // 价格
int date[3]; // 入库日期(年、月、日)
int ReturnDate[3]; // 归还日期(年、月、日)
int times; // 借阅次数
char state; // 借阅状态
// 指针域
// struct book *prev; // 前驱指针
// struct book *next; // 后驱指针
struct list_head nlist;
} BOOK;
BOOK *ListInit(void); // 链表初始化
char ListInsert(BOOK *head, BOOK New); // 链表节点插入,尾插
void List_Traval(BOOK *head); // 链表遍历,打印所有图书信息
void show(BOOK *head); // 显示图书信息
BOOK *search(BOOK *head, char *name); // 根据图书名字查找图书
void DeleteNode(BOOK *node); // 删除节点
BOOK *sort_times(BOOK *head); // 按借阅次数由大到小排序
BOOK set(BOOK node); // 修改图书信息
int GetBookNum(void); // 获取文件内图书数量
void setid(int *id); // 设置图书索引号
void setname(char *name); // 设置图书名
void setaddress(char *address); // 设置图书馆藏地址
void setClass(char *Class); // 设置图书类别
void setnumber(int *number); // 设置图书数量
void setprice(double *price); // 设置图书价格
void setyear(int *year); // 设置图书入库(归还)年份
void setmonth(int *month); // 设置图书入库(归还)月份
void setdate(int *year, int *month, int *date); // 设置图书入库(归还)日
void settimes(int *times); // 设置图书借阅次数
void show_BookB(BOOK *head); // 显示所有即将到期的图书
void menu(void); // 显示菜单函数
void fileread(BOOK *head, int num); // 文件读出函数
void filewrite(BOOK *head); // 文件写入函数
void ListWrite(BOOK *head); // 添加图书信息函数
#endif
kernel_list.h
#ifndef __DLIST_H
#define __DLIST_H
/* This file is from Linux Kernel (include/linux/list.h)
* and modified by simply removing hardware prefetching of list items.
* Here by copyright, credits attributed to wherever they belong.
* Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu)
*/
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions (“__xxx”) are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
/**
* container_of - cast a member of a structure out to the containing structure
*
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); })
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *)0x00100100)
#define LIST_POISON2 ((void *)0x00200)
struct list_head
{
struct list_head *prev;
struct list_head *next;
};
#define LIST_HEAD_INIT(name) \
{ \
&(name), &(name) \
}
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
// 宏定义语法规定只能有一条语句
// 如果需要多条语句,那就必须将多条语句放入一个do{}while(0)中使之成为一条复合语句
#define INIT_LIST_HEAD(ptr) \
do \
{ \
(ptr)->next = (ptr); \
(ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add – add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail – add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del – deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (void *)0;
entry->prev = (void *)0;
}
/**
* list_del_init – deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_move – delete from one list and add as another’s head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
/**
* list_move_tail – delete from one list and add as another’s tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* list_empty – tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(struct list_head *head)
{
return head->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/**
* list_splice – join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
/**
* list_splice_init – join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
{
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}
/**
* list_entry – get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); \
pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe – iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif