表驱动法举例

使用表驱动法要面临的两个问题:

1. 如何访问表?可选的方式有直接访问、索引访问和阶梯访问。

2. 表中存什么?如果要得到的是数据,则将数据放进表中;如果要得到的是某个动作,则将函数指针放进表中。

例1:给定分数评出等级,保证分数范围在0-100内,规定90-100分等级为A,80-89为B,70-79为C,60-69为D,0-59为E。

函数原型为:char GetGrade(int score);

一般做法

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 }
View Code

使用表驱动法

 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 }
View Code

上面查表时采用的线性查找,如果表数据比较多,可考虑用二分查找,但前提是表有序。

例2:下表是目前个人所得税税率表,现要求根据月薪和保险,计算个人所得税。

个人所得税的计算公式为:(月薪 - 保险 - 起征点) * 税率 - 速算扣除数,其中起征点为3500。

 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 }
View Code

例3:某系统在校验用户身份有效性时提供多种认证方式,如静态密码、指纹、动态令牌、LDAP、Radius等。现在为了提高系统安全,需要在原认证基础上扩展出双重认证,即任选两种不同的认证方式组合,当且仅当两种认证方式都校验通过才认为身份有效。

说明:认证类型authType为int类型,从低位到高位分别代表静态密码、指纹、动态令牌、LDAP、Radius认证方式,如4代表动态令牌认证,9代表LDAP和静态密码双重认证。

输入数据格式为:

普通认证:username password

双重认证:username password1 password2,其中password1与password2顺序不做要求。

各种认证的函数原型列出如下,具体认证过程略。

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);
View Code

使用表驱动法实现双重认证

 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 }
View Code
posted @ 2015-06-29 16:32  boyfaceone  阅读(480)  评论(0编辑  收藏  举报