图书馆管理系统

非图形界面
使用了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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值