015_表驱动编程思想(c实现)

【背景】

数据压倒一切。如果选择了正确的数据结构并把一切组织的井井有条,正确的算法就不言自明。编程的核心是数据结构,而不是算法。

——Rob Pike

上面是这个名人说过的话,那么c语言之父 丹尼斯·麦卡利斯泰尔·里奇 的《c程序设计》里曾经也有这样一句话: 程序 = 算法 + 数据(原文是:program = algorithm + data structure)

从以上两个人的思想当中我们可以知道:算法和数据对于程序来说是至关重要的,如果把程序比作一个人的话,算法就是他的灵魂,数据结构就是他的肉体(个人理解,不喜勿喷),我们在普遍的编程里,一直追求的是算法的高效性和安全性,往往忽略了数据结构的重要性和编程用途,其实,数据结构也可以作为编程的一种思想,这便是:表驱动编程!

所谓表驱动法(Table-Driven Approach)简而言之就是用查表的方法获取数据。此处的“表”通常为数组,但可视为数据库的一种体现。

根据字典中的部首检字表查找读音未知的汉字就是典型的表驱动法,即以每个字的字形为依据,计算出一个索引值,并映射到对应的页数。相比一页一页地顺序翻字典查字,部首检字法效率极高。

具体到编程方面,在数据不多时可用逻辑判断语句(if…else或switch…case)来获取值;但随着数据的增多,逻辑语句会越来越长,此时表驱动法的优势就开始显现

表驱动是一种在C语言里常见的编程模式,从表里面查找信息而不使用逻辑语句(if和case)。核心操作是将输入因素作为直接或者间接的索引,到数组里找到直接的结果或者对应的处理(通常是函数指针)。

在传统的23种面向对象设计模式里,并没有表驱动这种模式。这种模式是强烈依赖数组或者多维数组的一种设计模式,不涉及类,继承等关系,所以在C语言等非面向对象编程里得到了广泛的应用。

表驱动是一种在C语言里常见的编程模式,从表里面查找信息而不使用逻辑语句(if和case)。核心操作是将输入因素作为直接或者间接的索引,到数组里找到直接的结果或者对应的处理(通常是函数指针)。

表驱动实质上把逻辑和数据进行了分离。因素和结果之间的映射关系能够全部存放到数组里,而不是混杂在if,else的流程代码里。当映射关系发生改变的时候,只需要改变数组就可以,不需要修改代码。管理和维护起来非常方便。甚至可以把数据作为配置文件存放到硬盘上,需要的时候读取进来,避免了代码重新编译

看完上面这写内容,可能你对表驱动编程思想有些粗略的认识,脑袋也许会懵,很正常,我们举个现实生活中的例子看看,如下:

一家水果超市有苹果,香蕉,橘子这三种水果售卖,你要去买之前,想要在app上查下苹果还有没有?价格多少?人们的评价如何?这时你输入apple,就会出现对应的这些问题的答案,这个怎么实现呢?

【分析】

看了上面这个问题后,我相信大多数人都会想到if...else...结构或者switch...case...结构来实现此功能,完全可以,但是我们不妨再往深想一层,目前只是三类水果,当然可以这么做,而且也不费力,但是如果要实现100个水果类别呢?是不是脑袋瞬间嗡嗡的了?那么我们就可以用表驱动编程思想,去处理这100个不同的数据,注意:我们把重心放在了让数据去选择程序,就是把数据和程序对应起来,这次数据作为主导,去搞事情,而不是逻辑作为主导!是不是有点懵或者一时半会儿转不过这个弯儿?没事,你不妨用笔画画,试试看,再分析分析哦,这个想通了,你就知道在大型结构数据面前,表驱动编程是多么的666了,接下来,我们看看具体的testcode的实现

【实现_TestCode】

/****************************
*表驱动编程(数据结构思想)
****************************/

/*定义打印宏函数*/
#define PFS(a, b, c) printf("state: %s --- price: %.1lf --- \
evaluate: %s \n", a, b, c )
/*1.基本数据结构*/                                    
typedef struct Bs                   /*水果属性数据结构*/
{
    char* state;                    /*状态:是否还有该水果*/
    double price;                   /*价格:该水果多钱一斤*/
    char* evaluate;                 /*评价:受到的顾客评价good, general, bad*/
}base;                                    
typedef struct fruit                /*水果类别数据结构*/
{
    base apple;
    base banana;
    base orange;
}fs;
/*2.函数指针类型声明*/
typedef fs* (*funcp)(fs* tp);
/*3.函数指针具体实现*/
fs* apples(fs *tmp)                    /*苹果函数实现*/
{
    char* state = "have";
    double price = 2.1;
    char* evaluate = "good";
    
    LOGS("welcome to zll fruit shop...");
    LOGS("I am is apples");
    tmp->apple.state = state;
    //tmp.apple.state = state;
    tmp->apple.price = price;
    tmp->apple.evaluate = evaluate;
    return tmp;
};
fs* bananas(fs* tmp)                    /*香蕉函数实现*/
{
    char* state = "have";
    double price = 3.0;
    char* evaluate = "general";

    LOGS("welcome to zll fruit shop...");
    LOGS("I am is banana");
    tmp->banana.state = state;
    tmp->banana.price = price;
    tmp->banana.evaluate = evaluate;
    return tmp;
};
fs* oranges(fs* tmp)                    /*橘子函数实现*/
{
    char* state = "have";
    double price = 1.2;
    char* evaluate = "bad";

    LOGS("welcome to zll fruit shop...");
    LOGS("I am is orange");
    tmp->orange.state = state;
    tmp->orange.price = price;
    tmp->orange.evaluate = evaluate;
    return tmp;
};
/*4.数据结构组合*/
typedef struct map                      /*表驱动结构:名字+对应函数指针*/
{
    char* name;
    funcp handle;
}Map_node;
/*5.表编程实现*/
static const Map_node g_fruit_handle[] = {
                                        /*对应的数组结构:根据名字回调对应的函数*/
    {"apple", apples},
    {"banana", bananas},
    {"orange", oranges}
};
/*6.回调函数实现*/
fs mycallback(char* name, int len)
{
    int i;
    fs ttm = {0};

    for (i = 0; i < len; i++) {
        if (!strcmp(g_fruit_handle[i].name, name)) {
            if (g_fruit_handle[i].handle) {
                (*(g_fruit_handle[i].handle))(&ttm);
                return ttm;
            }
        }
    }
};
/*7.调用*/
void test_38_biaoprogram()
{
    char* name = "apple";
    int len = sizeof(Map_node);
    fs gtm = {0};

    gtm = mycallback(name, len);
    PFS(gtm.apple.state, gtm.apple.price, gtm.apple.evaluate);
};

我们测试的是apple,结果如下:

那么,以后只要有新的水果需要添加,我们只需要实现本水果函数并把name和handle添加到g_fruit_handle数组中便可,是不是有种焕然一新的感觉?完全和if...else..以及switch...case...的编程思想是两种感觉,一起加油,伙伴们^-^

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux取经路】基于信号量和环形队列的生产消费者模型

文章目录 一、POSIX 信号量二、POSIX 信号量的接口2.1 sem_init——初始化信号量2.2 sem_destroy——销毁信号量2.3 sem_wait——等待信号量2.4 sem_post——发布信号量 三、基于环形队列的生产消费者模型3.1 单生产单消费模型3.2 多生产多消费模型3.3 基于任务的多生产多消费模…

C# 利用Xejen框架源码,我们来开发一个基于Dapper技术的数据库通用的帮助访问类,通过Dapper的增删改查,可以访问Sqlite数据库

Dapper 是一个轻量级的对象关系映射&#xff08;ORM&#xff09;工具&#xff0c;适用于 .NET 平台。它由 Stack Overflow 团队开发&#xff0c;旨在提供简单、高效的数据访问功能。与其他重量级 ORM&#xff08;如 Entity Framework&#xff09;相比&#xff0c;Dapper 更加轻…

用这8种方法在海外媒体推广发稿平台上获得突破-华媒舍

在今天的数字时代&#xff0c;海外媒体推广发稿平台已经成为了许多机构和个人宣传和推广的有效途径。如何在这些平台上获得突破并吸引更多的关注是一个关键问题。本文将介绍8种方法&#xff0c;帮助您在海外媒体推广发稿平台上实现突破。 1. 确定目标受众 在开始使用海外媒体推…

C++语法|虚函数与多态详细讲解(六)|如何解释多态?(面试向)

系列汇总讲解&#xff0c;请移步&#xff1a; C语法&#xff5c;虚函数与多态详细讲解系列&#xff08;包含多重继承内容&#xff09; 多态分为了两种&#xff0c;一种是静态的多态&#xff0c;一种是动态的多态。 静态&#xff08;编译时期&#xff09;的多态 函数重载 boo…

pands使用openpyxl引擎实现EXCEL条件格式

通过python的openpyxl库&#xff0c;实现公式条件格式。 实现内容&#xff1a;D列单元格不等于E列同行单元格时标红。 #重点是formula后面的公式不需要“”号。 from openpyxl.styles import Color, PatternFill, Font, Border from openpyxl.styles.differential import Dif…

【设计模式】JAVA Design Patterns——Bytecode(字节码模式)

&#x1f50d;目的 允许编码行为作为虚拟机的指令 &#x1f50d;解释 真实世界例子 一个团队正在开发一款新的巫师对战游戏。巫师的行为需要经过精心的调整和上百次的游玩测试。每次当游戏设计师想改变巫师行为时都让程序员去修改代码这是不妥的&#xff0c;所以巫师行为以数据…

git push后一直卡在在Writing objects:问题

git push后一直卡在Writing objects: 解决&#xff1a;设置 git config --global http.postBuffer 5242880000在执行git push。 一般设置后就可以成功了&#xff0c;后面不用看。 2. 我这里结果又报错&#xff1a; fatal: protocol error: bad line length 8192 MiB | 107.46 …

【C++】d1

关键字&#xff1a; 运行、前缀、输入输出、换行 运行f10 前缀必须项&#xff1a; #include <iostream> using namespace std; 输入/输出&#xff1a; cin >> 输入 cout << 输出 语句通过>>或<<分开 换行 endl或者"\n"

想当安卓开发工程师?学习路线分享!

安卓开发学习路线 在前几篇文章中,对安卓开发岗位的岗位要求做了一些科普,本节文章将介绍安卓开发岗位的学习路线。 目前,网络上有很多面经、算法题解、算法课等学习资料,如何合理利用这些资料成为技术求职者的一大困惑。笔者整理了一份安卓开发岗位学习路线供大家参考,…

第四课 communcation服务-can配置第二弹

Davinci配置目标: 介绍DBC基本属性,并且配置出一个DBC。 将DBC导入到vector的davinci工具,生成我们想要的代码。 Davinci配置步骤: 1. 编辑DBC文件 DBC文件是一种非常重要的工具,所谓DBC就是Database CAN,CAN网络的数据库文件,定义了CAN网络的节点、消息、信号的所有…

网络安全知识核心20要点

1、什么是SQL注入攻击 概述 攻击者在 HTTP 请求中注入恶意的 SQL 代码&#xff0c;服务器使用参数构建数据库 SQL 命令时&#xff0c;恶意SQL 被一起构造&#xff0c;并在数据库中执行。 注入方法 用户登录&#xff0c;输入用户名 lianggzone&#xff0c;密码‘ or ‘1’’…

axios如何传递数组作为参数,后端又如何接收呢????

前端的参数是一个数组。 前端编写&#xff1a; 后端接收&#xff1a;

git解决版本冲突 -git pull

当在Git中遇到版本冲突时&#xff0c;通常是因为两个或更多的开发者在同一时间修改了同一个文件的相同部分&#xff0c;并将这些修改推送到远程仓库。Git无法自动合并这些修改&#xff0c;因此会产生冲突。以下是解决Git版本冲突的基本步骤&#xff1a; 拉取最新代码&#xff…

mybatis-plus 优雅的写service接口中方法(3)

多表联查 上文讲过了自定义sql &#xff0c;和wrapper的使用&#xff0c;但是我们可以发现 我们查询的都是数据库中的一张表&#xff0c;那么怎么进行多表联查呢&#xff0c;当然也是用自定义sql来进行实现 比如说 查询 id 为 1 2 4 的用户 并且 地址在北京 的 用户名称 普…

AI崛起,掌握它,开启智能新生活!

AI崛起&#xff0c;掌握它&#xff0c;开启智能新生活&#xff01; &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &…

LDAP: error code 32 - No Such Object

目前我的项目版本&#xff1a; Spring版本:5.3.15SpringBoot版本:2.6.3 完整错误 org.springframework.ldap.NameNotFoundException: [LDAP: error code 32 - No Such Object]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - No Such Objec…

Java进阶学习笔记9——子类中访问其他成员遵循就近原则

正确访问成员的方法。 在子类方法中访问其他成员&#xff08;成员变量、成员方法&#xff09;&#xff0c;是依照就近原则的。 F类&#xff1a; package cn.ensource.d13_extends_visit;public class F {String name "父类名字";public void print() {System.out.p…

[算法][前缀和] [leetcode]724. 寻找数组的中心下标

题目地址 https://leetcode.cn/problems/find-pivot-index/description/ 题目描述 代码 class Solution {public int pivotIndex(int[] nums) {int total Arrays.stream(nums).sum();//前缀和int prefixSum 0;int len nums.length;for(int i 0;i<len;i){if (i-1>0){p…

【已解决】C#设置Halcon显示区域Region的颜色

前言 在开发过程中&#xff0c;突然发现我需要显示的筛选区域的颜色是白色的&#xff0c;如下图示&#xff0c;这对我们来说不明显会导致我的二值化筛选的时候存在误差&#xff0c;因此我们需要更换成红色显示这样的话就可以更加的明显&#xff0c;二值化筛选更加的准确。 解…