了解更多知识请点我:学习C语言之路(汇总篇)
手把手教你写一个校验器
使用场景
其实就相当于一个工具,比如范围校验器:对某范围(x,y)的范围内进行数据校验,比如奇偶校验器 对该数值进行奇偶判断
要求是分层思想,可扩展。代入参数为void *。
代码构思思路(复习用)
第一步:定义结构体变量(包含函数指针,变量)
第二步:书写奇偶校验器,范围校验器(必须要能处理结构体数据)
第三步:#define初始值赋值。
第四步:运行
青铜版
bool rangeCheck(int min, int max, int value)
{
if(value < min || value > max)
return false;
else
return true;
}
详解
范围校验器,核心参数为最大值、最小值,比较值。问题来了,对于优秀的程序员来说看到参数这么多不免想要优化的打算,请看黄金版。
运行结果
黄金版
#include "stdio.h"
#include <stdbool.h>
struct _Range{
const int min;
const int max;
}range = {0,9}; //相比升级版直接赋初值
bool rangeCheck(struct _Range rangeValidator, int value)
{
return (rangeValidator.min <= value) && (value <= rangeValidator.max);
}
int main()
{
bool result = rangeCheck(range, 11);
printf("result = %d\n",result);
return 0;
}
改进点
相比于青铜版,黄金版我们这边定义了一个结构体,变量为range,顺便给结构体赋了初值0~9。
但是还是有改进的空间,比如假如代入的参数的结构体,
注意:C语言的参数传址调用要求将参数 的一份拷贝传递给函数,假如结构体成员有128个呢 妈的贼大!!快给我升级!!!!
解决方法:传递结构体的指针!!
改进见钻石版
运行结果
钻石版
#include "stdio.h"
#include <stdbool.h>
#define newRangeCheck(min,max) {(min),(max)} //初始化引用define
typedef struct _Range{
const int min;
const int max;
}Range;
bool rangeCheck(Range *rangeValidator, int value) //改进版 指针结构体带入
{
return (rangeValidator->min <= value) && (value <= rangeValidator->max);
}
int main()
{
Range range = newRangeCheck(0,9); //初始化程序
bool result = rangeCheck(&range, 11);//改进加&
printf("result = %d\n",result);
return 0;
}
改进点
- 引入typedef:有什么好处呢
typedef struct _Range{
const int min;
const int max;
}Range;
注意:该结构体有重要的含义1、“结构体布局”,相当于告诉编译器怎么表示数据但是它没有让编译器分配实际的地址
bool rangeCheck(Range *rangeValidator, int value)
- Range *rangeValidator: 定义了一个数据类型为指向结构体的指针变量Range(注意这个时候代入的地址大小才为4)。
来来来!这时候又来了一个新需求,比如我这边还有加一个奇偶校验器怎么办??
所以我们这边要有一个核心的思想:如何把程序写成通用版本。 哈哈哈,把媳妇介绍给你 “void *”。 请看王者版
王者版
#include "stdio.h"
#include <stdbool.h>
#define newRangeCheck(min,max) {(min),(max)} //初始化引用define
typedef struct _Range{
const int min;
const int max;
}Range;
typedef struct _OddEven{ //加了奇偶校验器
bool isEven;
}OddEven;
typedef bool(*Validate)(void *pDate,int value); //应该是回调函数 void 变量
bool rangeCheck(void *pthis, int value) //Range rangeValidator 你要改变!!!
{ //void *pthis
Range *pRange = (Range *)pthis; //强制转化 来适应参数void
return (pRange->min <= value) && (value <= pRange->max);
}
bool oddEvenCheck(void *pthis, int value) //范围校验器
{
OddEven *pOddEven = (OddEven *)pthis;
return (!pOddEven->isEven && (value % 2)) || (pOddEven->isEven && !(value % 2));
}
int main()
{
Range range = newRangeCheck(0, 9); //初始化变量参数
Validate ValidateRange = rangeCheck; //把要运行的函数指针给ValidateRange
printf("result = %d\n", ValidateRange(&range,3));
ValidateRange = oddEvenCheck;
printf("result = %d\n", ValidateRange(&range,5));
return 0;
}
改进点
- 增加了奇偶校验器,核心思想和范围校验器一样。
// An highlighted block
bool oddEvenCheck(void *pthis, int value) //范围校验器
{
OddEven *pOddEven = (OddEven *)pthis;
return (!pOddEven->isEven && (value % 2)) || (pOddEven->isEven && !(value % 2));
}
- 各种校验器参数变成了 void 输入–还有增加typedef
typedef bool(*const Validate)(void *pDate,int value); //应该是回调函数 void 变量
- bool rangeCheck(void *pthis, int value) //Range rangeValidator 你要改变!!!
{ //void *pthis
Range *pRange = (Range *)pthis; //强制转化 来适应参数void
return (pRange->min <= value) && (value <= pRange->max);
}
但你以为这就结束了??? 请看最终版。
运行结果
最终版
#include "stdio.h"
#include <stdbool.h>
// 初始化数据结构---初值赋值
#define newRangeValidator(min, max) {{validateRange}, (min), (max)}
#define newOddEvenValidator(isEven) {{validateOddEven}, (isEven)}
// 定义了一个函数指针
// 相当于函数类型重定义 bool validateOddEven(void *pThis, int value)
// bool validateRange(void *pThis, int value)
typedef bool(*const Validate)(void *pThis, int value);
//范围校验器--变量
typedef struct{
Validate isa;
const int min;
const int max;
} RangeValidator;
//奇偶校验器 --变量
typedef struct{
Validate isa;
bool isEven;
}OddEvenValidator;
// 数据结构类型处理函数
bool validateRange(void *pThis, int value)
{
RangeValidator *pRangeValidator = (RangeValidator *)pThis;
return pRangeValidator -> min <= value && value <= pRangeValidator -> max;
}
// 数据结构类型处理函数
bool validateOddEven(void *pThis, int value)
{
OddEvenValidator *pOddEvenValidator = (OddEvenValidator *)pThis;
return (!pOddEvenValidator -> isEven && (value % 2)) ||
(pOddEvenValidator -> isEven && !(value % 2));
}
bool rangeCheck(void *pValidator, int value)
{
Validate validate = *((Validate *)pValidator);
return validate(pValidator, value);
}
int main()
{
RangeValidator rangevalidator = newRangeValidator(3,6);// 初始化变量参数
OddEvenValidator oddevenvalidator = newOddEvenValidator(3);
printf("result = %d\n", rangeCheck(&rangevalidator,3));
printf("result = %d\n", validateOddEven(&oddevenvalidator,3));
return 0;
}
最终版-编程思想说明
main()函数是怎么运行的
- 变量说明:RangeValidator rangevalidator = newRangeValidator(3,6);
相当于RangeValidator rangeValidator = {(validateRange), (0), (9) };
说明:该结构变量既有函数指针,还有变量。 - 如何运行:rangeCheck()函数首先将该结构体指针变为函数指针并将地址赋值给validate
-(**Validate validate = ((Validate )pValidator); ) - 然后再运行函数return validate(pValidator, value); 因为此时pValidator参数传入的validateRange函数,这是运行该函数。
- 进入validateRange函数,这个时候强制转化为结构体 OddEvenValidator *pOddEvenValidator = (OddEvenValidator *)pThis;
- return (!pOddEvenValidator -> isEven && (value % 2)) ||
(pOddEvenValidator -> isEven && !(value % 2)); - 然后这边将结果返回。
你有没发现,我这边时候写的rangeCheck()已经不依赖于任何任何具体的校验器的。
牛!
总结
总体老说各个函数围绕 结构体进行操作,每次都是对该地址进行进行强制转化