表驱动法举例
使用表驱动法要面临的两个问题:
1. 如何访问表?可选的方式有直接访问、索引访问和阶梯访问。
2. 表中存什么?如果要得到的是数据,则将数据放进表中;如果要得到的是某个动作,则将函数指针放进表中。
例1:给定分数评出等级,保证分数范围在0-100内,规定90-100分等级为A,80-89为B,70-79为C,60-69为D,0-59为E。
函数原型为:char GetGrade(int score);
一般做法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 char GetGrade(int score) 2 { 3 if (score >= 90) return 'A'; 4 if (score >= 80) return 'B'; 5 if (score >= 70) return 'C'; 6 if (score >= 60) return 'D'; 7 return 'E'; 8 }
使用表驱动法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 struct mark 2 { 3 int lower; // 分数区间下界 4 int grade; // 分数对应等级 5 }; 6 const struct markTable[] = { {90, 'A'}, {80, 'B'}, {70, 'C'}, {60, 'D'}, {0, 'E'}}; 7 int GetIndex(int score) 8 { 9 int idx = 0; 10 while (score < markTable[idx].lower) 11 idx++; 12 return idx; 13 } 14 char GetGrade(int score) 15 { 16 int idx = GetIndex(score); 17 return markTable[idx].grade; 18 }
上面查表时采用的线性查找,如果表数据比较多,可考虑用二分查找,但前提是表有序。
例2:下表是目前个人所得税税率表,现要求根据月薪和保险,计算个人所得税。
个人所得税的计算公式为:(月薪 - 保险 - 起征点) * 税率 - 速算扣除数,其中起征点为3500。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #define INT_MAX ~(1 << 31) 3 #define TAX_LOWER_BOUND 3500 4 typedef struct { int lower, upper, rate, deduction; }Tax; 5 const Tax taxTable[] = { 6 { 0, 1500, 3, 0}, 7 { 1500, 4500, 10, 105}, 8 { 4500, 9000, 20, 555}, 9 { 9000, 35000, 25, 1005}, 10 {35000, 55000, 30, 2755}, 11 {55000, 80000, 35, 5505}, 12 {80000, INT_MAX, 45, 13505}, 13 }; 14 double GetTax(double amountForTax) { 15 int i; 16 double tax; 17 if (amountForTax <= 0) return 0; 18 for (i = 0; taxTable[i].upper < (int)amountForTax; i++); 19 tax = amountForTax * taxTable[i].rate / 100 - taxTable[i].deduction; 20 return tax; 21 } 22 int main() 23 { 24 double income, insurance; 25 while (~scanf("%lf%lf", &income, &insurance)) 26 printf("%.2lf\n", GetTax(income - insurance - TAX_LOWER_BOUND)); 27 return 0; 28 }
例3:某系统在校验用户身份有效性时提供多种认证方式,如静态密码、指纹、动态令牌、LDAP、Radius等。现在为了提高系统安全,需要在原认证基础上扩展出双重认证,即任选两种不同的认证方式组合,当且仅当两种认证方式都校验通过才认为身份有效。
说明:认证类型authType为int类型,从低位到高位分别代表静态密码、指纹、动态令牌、LDAP、Radius认证方式,如4代表动态令牌认证,9代表LDAP和静态密码双重认证。
输入数据格式为:
普通认证:username password
双重认证:username password1 password2,其中password1与password2顺序不做要求。
各种认证的函数原型列出如下,具体认证过程略。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int AuthByPwd(const char *user, const char *pass); 2 int AuthByFingerprint(const char *user, const char *pass); 3 int AuthByToken(const char *user, const char *pass); 4 int AuthByLdap(const char *user, const char *pass); 5 int AuthByRadius(const char *user, const char *pass);
使用表驱动法实现双重认证
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 typedef int (*AuthFunc)(const char *, const char*); 2 3 int Offset(unsigned n) 4 { 5 int offset; 6 7 for (offset = 0; n; n >>= 1, offset++); 8 return offset; 9 } 10 11 int main() 12 { 13 const static AuthFunc authFunc[] = { 14 NULL, 15 AuthByPwd, 16 AuthByFingerprint, 17 AuthByToken, 18 AuthByLdap, 19 AuthByRadius, 20 }; 21 int authType, ret, idx[2] = {0}; 22 char user[32], pass1[32], pass2[32]; 23 24 while (~scanf("%d", &authType)) { 25 if (authType & (authType - 1)) { 26 scanf("%s%s%s", user, pass1, pass2); 27 idx[0] = Offset(authType & -authType); 28 authType &= authType - 1; 29 idx[1] = Offset(authType & -authType); 30 ret = (authFunc[idx[0]](user, pass1) && authFunc[idx[1]](user, pass2)) 31 || (authFunc[idx[0]](user, pass2) && authFunc[idx[1]](user, pass1)); 32 } else { 33 scanf("%s%s", user, pass1); 34 idx[0] = Offset(authType & -authType); 35 ret = authFunc[idx[0]](user, pass1); 36 } 37 printf("auth %s\n", ret ? "success" : "fail"); 38 } 39 return 0; 40 }