利用C语言创建图书管理系统

news2024/11/27 1:22:18

不仅仅是图书信息管理系统

基于双链表,采用面向对象编程方法制作的图书管理系统

效果演示

root用户:账号:0,密码:0

普通用户:账号:1001,密码:666666

图书信息

没有完全演示,只是个大概,微信gif只能300帧以内


框架结构

数据层:双链表管理

核心层:用户管理、图书管理

用户管理:

用户分三种:readonly、write、root(可删除数据)

功能:Exit(退出), Add(添加), Show(显示), Change(修改), Delete(删除), Search(查找)

图书管理:

权限分级:暂未实现(可自行实现)

功能:EXIT(退出), ADD(添加), SHOW(显示), CHANGE(修改), DELETE(删除), SEARCH(查找)

ps:用这个双链表框架可以解决99.9%的各种信息管理系统(增删改查)问题,那%0.1就是给自己留的后路,毕竟没有什么问题可以100%解决

以后再跟我提xxx管理系统我就给你扔过去这对代码,自己去实现

核心部分:双链表的实现

双链表

typedefstruct deroy_node
{
    void* data;
    struct deroy_node* prev;
    struct deroy_node* next;
}deroy_node_t;
typedefderoy_node_t* deroy_node_pt;


typedefstruct deroy_list
{
    int  limit_size;
    deroy_node_pt head;
    deroy_node_pt tail;
}deroy_list_t;
typedefderoy_list_t* deroy_list_pt;

为什么链表里面的data是void*呢,谭浩强的C语言不是这样教的啊

void类型是空类型,可以转成任意一种类型,你不知道你插入的数据的结构体是什么,或者说你要插入多种数据的结构体,确定的结构体已经不能够满足需求了,需要定义void*类型来指向你要添加进链表的结构体数据

我们需要实现一些函数来管理链表,注意o,前方高能,小白勿看

功能函数

/*初始化链表*/
deroy_list_pt deroy_list_create(void);
/*插入节点*/
int deroy_list_insert_before(deroy_list_t** list_head, int num, void* new_node_data);
/*删除节点*/
int deroy_list_delete(deroy_list_t** list_head, int num);
/*修改节点*/
int deroy_list_modify(deroy_list_t** list_head, int num, void* new_node_data);
/*遍历节点*/
void deroy_list_cuid(deroy_list_t* list_head, void (*do_function)(void*));
/*查询数据 返回 数据的位置*/
int deroy_list_search(deroy_list_t** list_head, void* find_data, int(*compare)(void*, void*));
/*查询数据 返回 数据的指针*/
void* deroy_list_find(deroy_list_t** list_head, void* find_data, int(*compare)(void*, void*))

为什么我要先把功能函数的原型给列举出来,因为你仔细看参数,双链表功能实现多次用到回调函数

什么是回调函数呢?

回调函数就是一个通过函数指针调用的函数。❞

怎么说呢,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数能够干什么?

你学过C++知道多肽吧,就是一个方法实现多个功能,回调函数就是C里面实现多肽的方式

举个栗子:

功能函数里面有个遍历所有节点的功能函数

/*遍历节点*/
void deroy_list_cuid(deroy_list_t* list_head, void (*do_function)(void*))
{
    int i = 0;
    if (list_head == NULL || list_head->limit_size < 0)
    {
        errno = EINVAL;
        exit(errno);
    }
    for (i = 0; i < list_head->limit_size; i++)
    {
        (*do_function)(__deroy_list_visit(&list_head, i));
    }
}

前面那个判断没啥可看的,直接看(*do_function)(__deroy_list_visit(&list_head, i));

__deroy_list_visit是个内联函数,它的功能就是返回list_head里面的第i个节点数据(void *data)

然后将数据给传入的do_function,让dofunction去处理data数据,核心层用户管理区实现dofunction

/*回调函数 打印所以学生信息*/
static void proxy_find_stu(deroy_data_pt pdata)
{
    /*遍历学生信息*/
    if (pdata->type == STU)
    {
        printf(" %d\t%d\t%s\t%d\t%d\n", pdata->type, pdata->id, pdata->name, pdata->sex, pdata->rank);
    }
}

/*回调函数 root用户打印所有信息*/
static void proxy_find_all(deroy_data_pt pdata)
{
    /*遍历所有信息*/
    printf(" %d\t%d\t%s\t%d\t%d\t%d:\t%s\n", pdata->type, pdata->id, pdata->name, pdata->sex, pdata->rank, pdata->acount,pdata->password);
}

    通过对dofunction的实现,我们一个deroy_list_cuid函数可以遍历所有data的id段,还是不管什么数据都打印,这样就实现了root用户查看的权限更大

    如果觉得这个直接两个函数实现不是更好吗,如果你想到这里,证明你还在思考,对,两个函数实现更方便,但是,那是核心层(自己写回调函数)去重新解释这个功能,达到了分层的概念

或许这里的回调函数应用的不明显,这里还有个明显的

/*查询数据 返回 数据的位置*/
int deroy_list_search(deroy_list_t** list_head, void* find_data, int(*compare)(void*, void*))
{
    int counter = 1;
    deroy_node_pt current = NULL;
    if (list_head == NULL || *list_head == NULL)
    {
        errno = EINVAL;
        exit(errno);
    }
    if ((*list_head)->limit_size == 0)
    {
        return-1;  //无数据可查询
    }
    current = (*list_head)->head;
    /*通过传入的comper函数进行比较*/
    while (compare(current->data, find_data) == 0 && current->next != NULL)
    {
        current = current->next;
        counter++;
    }
    if (current->next == NULL && compare(current->data, find_data) == 0)
        return0;
    return counter;
}

这里的的回调函数要求判断两个数据,返回真假

/*回调函数 比较db_data_pt数据段的id是否相同*/
static int proxy_compare_id(deroy_data_pt pdata, deroy_data_pt other)
{
    if (pdata->id == other->id)
        return1;
    return0;
}

通过核心层的用户管理去实现按id查找,还是其他查找方式,这里你总不能两个函数解决吧,必须要分层

不能扯太远,咱说的是链表,继续..

双链表的实现,我之前发过一篇循环双链表,有图解,还算详细

循环双链表

这个双链表还算可以,没有内存泄漏(如果有请告诉我,反正我也不会去改),各种判断安全系数高,功能完善,能处理各种增删改查功能的系统设计

核心层:用户管理

啊~当时想着用双链表实现学生信息管理系统来着,码着码着就想把图书信息管理系统也码下来,比较学生信息管理系统已经烂大街了,我上个学生信息管理系统在知乎都有2000赞了

#define STU 0
#define TEACHER 1

typedefenum Menu
{
    Exit, Add, Show, Change, Delete, Search
}MENU;

typedefenum Sex
{
    MAN, WOMAN
}SEX;

/*权限*/
enum RANK
{
    READ_ONLY   /*只读*/
    , WRITE     /*读写*/
    , ROOT      /*root可删除*/
};

/*学号、专业、姓名、年龄、性别属性。*/

typedefstruct deroy_data
{
    char   type;    /*类型*/
    char   rank;    /*级别*/
    int    id;      /*编号*/
    char   name[10];    /*姓名*/
    char   sex;         /*性别*/
    int    acount;      /*账号*/
    char   password[20];    /*密码*/
    void*  data;        /*其他*/
    int(*Init)(struct deroy_data* pdata);
}deroy_data_t;
typedefderoy_data_t* deroy_data_pt;

没什么特殊的,甚至用户信息少的可怜,有点用处的就是权限了,然后看到deroy_data里面的void* data段了吗,没错,我就是想告诉你们,这个是扩展功能,可扩展用户的其他信息,这个我就不实现了,比较代码多了,你们看着挺烦的

然后这个结构体里面的函数指针,就相当于C++里面的方法,可以指向一个功能函数

然后就和之前的学生信息管理系统差不多了~

/*学生信息管理系统*/
int system_proxy_stu(deroy_list_pt ptlist,int user_rank)
{
    rank = user_rank;
    while (1)
    {
        switch (menu_proxy_stu())	//菜单选择
        {
        case Exit:		//退出程序
            system("cls");
            printf("退出程序\n");
            Quit();
            return1;
            break;
        case Show:		//显示所有学生信息
            system("cls");
            if (rank == READ_ONLY)
            {
                printf(" 类型\t学号\t姓名\t性别\t权限\n\n");
                deroy_list_cuid(ptlist, proxy_find_stu);
            }
            elseif(rank == ROOT)
            {
                printf(" 类型\t学号\t姓名\t性别\t权限\t账号:\t密码\n\n");
                deroy_list_cuid(ptlist, proxy_find_all);
            }
            Quit();
            break;
        case Add:		//添加学生信息
            init_proxy_stu(ptlist);
            Quit();
            break;
        case Change:	//修改学生信息
            proxy_stu_modify(ptlist);
            Quit();
            break;
        case Delete:	//删除学生信息
            proxy_stu_delete(ptlist);
            Quit();
            break;
        case Search:	//查询学生信息
            proxy_stu_find(ptlist);
            Quit();
            break;
        }
        system("cls");
    }
}

把所有功能函数都实现了,并且功能函数都有权限设置,普通用户只能查看普通用户的信息

核心层:图书管理

这个图书管理实现的比用户管理还简单,我都没去设置权限问题,可自行设计

typedefenum BookMenu
{
    EXIT, ADD, SHOW, CHANGE, DELETE, SEARCH
}BOOKMENU;

/*图书编号、书名、图书分类、数量、出版日期、登记日期*/
typedefstruct deroy_book
{
    int  iID;            /*序号*/
    char cId[4];         /*编号*/
    char cName[20];      /*书名*/
    char cSubject[20];   /*图书分类*/
    int  iNums;           /*数量*/
    char cPublish_data[20];/*出版日期*/
    char cData[20];        /*登记日期*/
    int(*Init)(struct deroy_book* pdata);   /*初始化函数*/
}deroy_book_t;
typedefderoy_book_t* deroy_book_pt;

简简单单的把基本的图书信息给列举出来,只需要实现功能函数即可

/*初始化图书数据*/
static void init_book_proxy_node(deroy_book_pt self)
/*注册图书*/
static void register_book_proxy_method(deroy_list_pt ptlist, void* pdata)
/*初始化图书信息*/
static void init_proxy_book(deroy_list_pt ptlist)
/*菜单选择*/
static int menu_proxy_book()
/*修改图书信息*/
static void proxy_book_modify(deroy_list_pt ptlist)
/*删除图书信息*/
static void proxy_book_delete(deroy_list_pt ptlist)
/*查找图书信息*/
static void proxy_book_find(deroy_list_pt ptlist)
/*图书信息管理系统*/
int system_proxy_book(deroy_list_pt ptlist)

这些个功能函数都挺简单的,都是围绕着之前设计的链表来实现的,详情可以看原码

这其实就是我将用户管理的代码复制过来,改void *data所指向的结构体deroy_book,几乎是一模一样的,所以说这是个模板,是个框架,框架定死了,你围绕着这个框架去实现功能就行

这里提个有趣的:就是图书注册日期,这里不用管理员去实现,直接sprintf(self->cData, "%s", __DATE__);__DATE__是一个宏,打印的是当前日期,打印的是年月日例如Jul 11 2020,这个宏我在C语言预处理那里提过,可惜看的人不多,

预处理

用户登录

首先主函数里面把两个核心层给创建咯,

	deroy_list_pt pStu_Head = deroy_list_create();	//创建用户
	deroy_list_pt pBook_Head = deroy_list_create();	//创建书籍

在创建用户的时候会创建两个用户对象,一个root、一个普通read_only,用于初始登录

登录就是去调用函数,接收函数的返回值

int user_rank = load(pStu_Head);
	if (user_rank < 0)
	{
		printf("登录失败");
		return0;
	}

这个返回值是用户的权限,用来层级之间交互

int load(deroy_list_pt phead)
{
	char account[20],password[20];	//账号密码
	printf("input acount:");
	scanf("%s", account);
	printf("password:");
	scanf("%s", password);
	deroy_data_t temp;
	temp.id = atoi(account);
	deroy_data_pt find_data = deroy_list_find(&phead, &temp, proxy_compare_load);
	if (find_data >= 0)
	{
		if (strcmp(password, find_data->password) == 0)
		{
			return find_data->rank;
		}
	}
	return-1;
}

之而立直接调用链表提供的方法deroy_list_find,自己实现回调函数

int proxy_compare_load(deroy_data_pt pdata, deroy_data_pt other)
{
	if (pdata->id == other->id)
		return1;
	return0;
}

为什么是找id而不是用户名呢,这里我懒了一下,直接将id赋值给account,整数方便,图个开心

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/665326.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring MVC各种参数进行封装

目录 一、简单数据类型 1.1 控制器方法 1.2 测试结果 二、对象类型 2.1 单个对象 2.1.1 控制器方法 2.1.2 测试结果 2.2 关联对象 2.2.1 控制器方法 2.2.2 测试结果 三、集合类型 3.1 简单数据类型集合 3.1.1 控制方法 3.1.2 测试结果 3.2 对象数据类型集合 3.…

KMP算法实现strStr(c++代码实现)

1 KMP算法简介 KMP算法是一个解决字符串匹配问题的算法&#xff0c;由D.E.Knuth&#xff0c;J.H.Morris和V.R.Pratt提出。当给你一个主串str和一个子串substr&#xff0c;如何确定substr在主串中出现的位置&#xff1f;如果没有学习KMP算法&#xff0c;我们可能会写出这样的代…

测试(三)——黑盒测试

一、测试用例的基本要素 测试环境、操作步骤、测试数据、预期结果 测试用例的好处&#xff1a; 1.能提高测试效率、节省测试时间 2.测试用例是自动化测试用例的前提 二、测试用例的设计方法 2.1基于需求进行测试用例设计 2.2具体的设计方法 2.2.1等价类 有效等价类&#x…

c++学生信息管理系统

前言 c课程作业–学生信息管理系统 在 原博客C通讯录管理系统 https://www.csdn.net/tags/OtDagg2sODU2Ni1ibG9n.html 的基础上进行了一点修改。 学生信息管理系统 基本功能要求&#xff1a; 能使用文件的打开&#xff0c;关闭&#xff0c;读写等操作&#xff0c;实现 1.连…

STM32单片机(六)TIM定时器 -> 第八节:TIM编码器练习(编码器接口测速)

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

Linux学习入门笔记

计算机硬件 计算机五大基本部件 控制器 -----> 协调各个部件运算器 -----> 算术、逻辑运算存储单元 ----->内存、外存输入单元输出单元 cup 由控制器、运算器组成 计算机操作系统 操作系统 OS 管理和控制计算机系统中的硬件和软件资源&#xff0c;用于在用户与系统…

gitLens插件简单使用

1.安装 在vscode中的插件管理输入如下后下载 GitLens — Git supercharged 2.配置 点击文件--首选项--设置 点击右上角设置小图标 3.github使用 首先仓库文件一定是要git init是git所管理的 1.在代码文件夹下使用git init创建仓库 2.打开vscode的git管理 3.点击添加暂存区…

Triton教程 --- 优化

Triton教程 — 优化 文章目录 Triton教程 --- 优化优化设置动态批处理程序模型实例 特定于框架的优化带有 TensorRT 优化的 ONNX (ORT-TRT)具有 OpenVINO 优化的 ONNXTensorFlow 与 TensorRT 优化 (TF-TRT)TensorFlow JIT 图优化TensorFlow 自动 FP16 优化 NUMA优化主机策略 Tr…

python找出所有重复数字的三位数(如110)注意重复数字(如111除外) ​要求打印所有满足条件的三位数及个数,每行打印五个

一、编程题目 python找出所有重复数字的三位数&#xff08;如110&#xff09;注意重复数字&#xff08;如111除外&#xff09; ​要求打印所有满足条件的三位数及个数&#xff0c;每行打印五个。 二、实现思路 要实现判断数字是否重复&#xff0c;脑袋里的第一反应就是使用循环…

在办公套件 ONLYOFFICE 中使用 AI 插件:自动生成文本/图片、单词释义、翻译等

想必大家多少都体验过各种人工智能应用&#xff0c;它们跟办公套件结合简直就是打工人和学生们的王炸。除了在Office全家桶中可以使用AI插件&#xff0c;在开源办公套件 ONLYOFFICE 中也能使用它。 什么是 ONLYOFFICE ONLYOFFICE 是一个开源办公套件&#xff0c;由总部位于总部…

OpenMMLab-AI实战营第二期-课程笔记-Class 4:深度学习预训练与MMPretrain

Class4&#xff1a;深度学习预训练与MMPretrain 课程链接&#xff1a;深度学习预训练与MMPretrain_哔哩哔哩_bilibili 相关repo&#xff1a;open-mmlab/mmpretrain: OpenMMLab Pre-training Toolbox and Benchmark (github.com) 文章目录 Class4&#xff1a;深度学习预训练与MM…

系统工程 - 记录一次调试USB设备低功耗应用的过程

系统工程 - 记录一次调试USB设备低功耗应用的过程 文章目录 系统工程 - 记录一次调试USB设备低功耗应用的过程需求功耗测量方法分析功耗来源LED功耗MCU功耗板子漏电 软件改善功耗调整tinyusb协议栈源码降低主频电脑唤醒usb设备退出低功耗进入STOP模式 总结 需求 最近在同客户做…

【Python 随练】寻找完数

题目&#xff1a; 一个数如果恰好等于它的因子之和&#xff0c;这个数就称为"完数"。例如 61&#xff0b;2&#xff0b;3.编程找出 1000 以内的所有完数。 简介&#xff1a; 在本篇博客中&#xff0c;我们将解决一个数学问题&#xff1a;如何找出 1000 以内的所有…

Stable diffusion WebUI txt2img使用教学

本篇文章将深入探讨如何在Stable Diffusion WebUI上进行各项参数的调整。将以txt2img为主要讨论对象&#xff0c;探讨诸如基本设定Sampling method以及CFG scale等参数的调整&#xff0c;以及这些参数之间的相互影响。 对于还未安装Stable Diffusion WebUI的小伙伴&#xff0c…

httpd的安装和mysql数据库的安装方法

目录 一 安装httpd 1.下载httpd包模块apr和apr-u到opt目录 2. 解包 3. 把apr和apr-u包放在http的第三方模块scrilb目录中 4.进入httpd包的安装目录并安装依赖环境和进行编译安装 5. make -j 2 && make install 编译并安装 6.优化配置文件 7. 把httpd服务放在sy…

智能文档图像处理技术:解决大数据时代文档图像处理难题

智能文档图像处理技术&#xff1a;解决大数据时代文档图像处理难题 0. 前言1. 智能文档处理1.1 智能文档处理简介1.2 智能文档处理应用 2. VALSE 视觉与学习青年学者研讨会2.1 VALSE 20232.2 合合信息亮相 VALSE 2023 3. 版面分析技术3.1 版面分析3.2 文档还原 4. 其他相关智能…

Gamma:强大的AI制作PPT神器,用完再也回不去了!

看过许多 AI 制作 PPT 软件&#xff0c;最终还是被 Gamma 惊艳到。 Gamma 是一款基于人工智能技术的 PPT 制作工具&#xff0c;可以帮助用户轻松制作高质量的 PPT 演示文稿。 痛点解决 相比传统制作 PPT 方式&#xff0c;Gamma 可以解决哪些如下 7 个痛点&#xff1a; 一句话…

2016年全国硕士研究生入学统一考试管理类专业学位联考写作试题

2016年1月真题&#xff1a; 四、写作&#xff1a;第56~57小题&#xff0c;共65 分。其中论证有效性分析30 分&#xff0c;论说文35分。 56、论证有效性分析&#xff1a; 分析下述论证中存在的缺陷和漏洞&#xff0c;选择若干要点&#xff0c;写一篇600字左右的文章&#xff0…

2013年全国硕士研究生入学统一考试管理类专业学位联考写作试题

2013年1月真题: 四、写作:第 56~57小题&#xff0c;共65分。其中论证有效性分析30 分&#xff0c;论说文35 分。 56、论证有效性分析: 分析下述论证中存在的缺陷和漏洞&#xff0c;选择若干要点&#xff0c;写一篇600 字左右的文章&#xff0c;对该论证的有效性进行分析和评论…

Golang每日一练(leetDay0102) 删除无效的括号、累加数

目录 301. 删除无效的括号 Remove Invalid Parentheses &#x1f31f;&#x1f31f;&#x1f31f; 306. 累加数 Additive Number &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏…